@tamng0905/builder-essential-skills 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/lead-builder.md +55 -0
- package/.claude/agents/lead-reviewer.md +39 -0
- package/README.md +276 -0
- package/assets/readme-hero.png +0 -0
- package/assets/skill-cards/async-learning-teacher.svg +7 -0
- package/assets/skill-cards/code-standards.svg +7 -0
- package/assets/skill-cards/lead-research.svg +7 -0
- package/assets/skill-cards/lead.svg +7 -0
- package/assets/skill-cards/orwell-writing.svg +7 -0
- package/assets/skill-cards/session-profiler.svg +7 -0
- package/assets/skill-cards/validate-market.svg +7 -0
- package/assets/skill-cards/write-blog.svg +7 -0
- package/bin/builder-essential-skills.js +134 -0
- package/install.ps1 +58 -0
- package/install.sh +63 -0
- package/package.json +24 -0
- package/skills/async-learning-teacher/README.md +50 -0
- package/skills/async-learning-teacher/SKILL.md +192 -0
- package/skills/async-learning-teacher/agents/openai.yaml +4 -0
- package/skills/code-standards/README.md +27 -0
- package/skills/code-standards/SKILL.md +51 -0
- package/skills/lead/README.md +29 -0
- package/skills/lead/SKILL.md +222 -0
- package/skills/lead/config.py +359 -0
- package/skills/lead/dispatch.md +342 -0
- package/skills/lead/loop.md +103 -0
- package/skills/lead/models.json +34 -0
- package/skills/lead/research.md +76 -0
- package/skills/lead/status.ps1 +114 -0
- package/skills/lead/status.sh +110 -0
- package/skills/lead/watchdog.ps1 +90 -0
- package/skills/lead/watchdog.sh +88 -0
- package/skills/lead-research/README.md +27 -0
- package/skills/lead-research/SKILL.md +157 -0
- package/skills/lead-research/tactics.md +150 -0
- package/skills/orwell-writing/README.md +27 -0
- package/skills/orwell-writing/SKILL.md +44 -0
- package/skills/orwell-writing/agents/openai.yaml +4 -0
- package/skills/session-profiler/README.md +25 -0
- package/skills/session-profiler/SKILL.md +103 -0
- package/skills/session-profiler/agents/openai.yaml +4 -0
- package/skills/session-profiler/scripts/requirements.txt +2 -0
- package/skills/session-profiler/scripts/session_profiler/__init__.py +5 -0
- package/skills/session-profiler/scripts/session_profiler/analyses.py +246 -0
- package/skills/session-profiler/scripts/session_profiler/cli.py +77 -0
- package/skills/session-profiler/scripts/session_profiler/dataset.py +369 -0
- package/skills/session-profiler/scripts/session_profiler/discover.py +191 -0
- package/skills/session-profiler/scripts/session_profiler/toc.py +74 -0
- package/skills/session-profiler/scripts/session_profiler/trace.py +146 -0
- package/skills/session-profiler/scripts/sp +20 -0
- package/skills/session-profiler/scripts/tests/codex_home/sessions/2026/01/01/rollout-child.jsonl +7 -0
- package/skills/session-profiler/scripts/tests/codex_home/sessions/2026/01/01/rollout-root.jsonl +10 -0
- package/skills/session-profiler/scripts/tests/fixture/main/subagents/agent-abc.jsonl +2 -0
- package/skills/session-profiler/scripts/tests/fixture/main/subagents/agent-abc.meta.json +1 -0
- package/skills/session-profiler/scripts/tests/fixture/main.jsonl +7 -0
- package/skills/session-profiler/scripts/tests/test_fixture.py +58 -0
- package/skills/validate-market/README.md +27 -0
- package/skills/validate-market/SKILL.md +202 -0
- package/skills/write-blog/README.md +27 -0
- package/skills/write-blog/SKILL.md +142 -0
- package/skills/write-blog/check.sh +52 -0
- package/skills/write-blog/reference/angles.md +51 -0
- package/skills/write-blog/reference/craft.md +94 -0
- package/skills/write-blog/reference/seo.md +116 -0
- package/skills/write-blog/reference/voice.md +64 -0
- package/skills/write-blog/reference/wiring.md +113 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Read-only status tree for a techlead-loop run. Reads run artifacts plus `gh`;
|
|
3
|
+
# never a new state store. Piped output is plain text; color follows isatty and
|
|
4
|
+
# NO_COLOR. Callers print it verbatim instead of hand-composing status.
|
|
5
|
+
set -u
|
|
6
|
+
|
|
7
|
+
root=$(pwd)
|
|
8
|
+
while [ "$#" -gt 0 ]; do
|
|
9
|
+
case "$1" in --repo-root) root=$2; shift 2;; *) shift;; esac
|
|
10
|
+
done
|
|
11
|
+
case "$root" in /*) ;; *) root="$(pwd)/$root";; esac
|
|
12
|
+
[ -d "$root" ] || { printf 'unreadable repo: %s\n' "$root"; exit 1; }
|
|
13
|
+
|
|
14
|
+
color_glyph(){ if [ -t 1 ] && [ -z "${NO_COLOR:-}" ]; then printf '\033[%sm%s\033[0m' "$2" "$1"; else printf '%s' "$1"; fi; }
|
|
15
|
+
g_merged=$(color_glyph '✓' 32); g_review=$(color_glyph '◐' 36); g_blocked=$(color_glyph '!' 31)
|
|
16
|
+
g_reported=$(color_glyph '▣' 35); g_building=$(color_glyph '●' 34); g_queued=$(color_glyph '⊘' 33); g_ready=$(color_glyph '○' 37)
|
|
17
|
+
|
|
18
|
+
newest_spec(){
|
|
19
|
+
spec_dir="$root/docs/spec"
|
|
20
|
+
newest=; newest_mtime=
|
|
21
|
+
[ -d "$spec_dir" ] || { printf unknown; return; }
|
|
22
|
+
for spec in "$spec_dir"/*.md; do
|
|
23
|
+
[ -f "$spec" ] || continue
|
|
24
|
+
mtime=$(stat -c %Y "$spec" 2>/dev/null || stat -f %m "$spec" 2>/dev/null || printf 0)
|
|
25
|
+
case "$mtime" in ''|*[!0-9]*) mtime=0;; esac
|
|
26
|
+
if [ -z "$newest" ] || [ "$mtime" -gt "$newest_mtime" ]; then newest=$spec; newest_mtime=$mtime; fi
|
|
27
|
+
done
|
|
28
|
+
[ -n "$newest" ] && basename "$newest" || printf unknown
|
|
29
|
+
}
|
|
30
|
+
tail_text(){ [ -f "$1" ] && tail -c 4096 "$1" | tr -d '\000'; }
|
|
31
|
+
status_line(){ tail_text "$1" | sed 's/^\xEF\xBB\xBF//' | awk '/^STATUS:/{sub(/^STATUS:[[:space:]]*/,""); s=$0} END{print s}'; }
|
|
32
|
+
last_command(){
|
|
33
|
+
ev="$root/.lead/wt/$1-01.events.jsonl"
|
|
34
|
+
cmd=$(tail_text "$ev" | sed -n 's/.*"command"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | tail -n 1)
|
|
35
|
+
[ -n "$cmd" ] && printf ' last: %s age: unknown\n' "$cmd"
|
|
36
|
+
}
|
|
37
|
+
report_path(){
|
|
38
|
+
in_wt="$root/.lead/wt/$1-01/docs/jobs/$1-01.md"
|
|
39
|
+
in_repo="$root/docs/jobs/$1-01.md"
|
|
40
|
+
[ -f "$in_wt" ] && { printf '%s' "$in_wt"; return; }
|
|
41
|
+
printf '%s' "$in_repo"
|
|
42
|
+
}
|
|
43
|
+
slugify(){ printf '%s' "$1" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g;s/--*/-/g;s/^-//;s/-$//'; }
|
|
44
|
+
artifact_slugs(){ find "$root/.lead/wt" -maxdepth 1 -type d -name '*-01' 2>/dev/null | sed 's|.*/||;s/-01$//' | sort -u; }
|
|
45
|
+
phase(){
|
|
46
|
+
slug=$1; state=${2:-}; blockers=${3:-}
|
|
47
|
+
[ "$state" = CLOSED ] && { printf '%s MERGED' "$g_merged"; return; }
|
|
48
|
+
[ "$state" = OPEN ] && [ -n "$blockers" ] && { printf '%s QUEUED' "$g_queued"; return; }
|
|
49
|
+
rep=$(report_path "$slug")
|
|
50
|
+
review=$(find "$root/.lead/wt" -maxdepth 1 -type f -name "$slug-01.review*.md" 2>/dev/null | head -n 1)
|
|
51
|
+
[ -f "$rep" ] && [ -n "$review" ] && { printf '%s REVIEWING' "$g_review"; return; }
|
|
52
|
+
st=$(status_line "$rep")
|
|
53
|
+
case "$st" in BLOCKED*) printf '%s BLOCKED' "$g_blocked"; return;; esac
|
|
54
|
+
[ -f "$rep" ] && { printf '%s REPORTED' "$g_reported"; return; }
|
|
55
|
+
[ -d "$root/.lead/wt/$slug-01" ] && { printf '%s BUILDING' "$g_building"; return; }
|
|
56
|
+
printf '%s READY' "$g_ready"
|
|
57
|
+
}
|
|
58
|
+
tracker_lines(){
|
|
59
|
+
jq_expr='. as $all | ([ $all[] | select(.parent != null) | .parent.number ] | unique) as $pnums | ([ $all[] | select(.state == "OPEN") | select(.number as $n | $pnums | index($n)) ] | map(.number) | max) as $t | if $t == null then "NOOPENRUN" else ("TRACK\t\($t)", ($all[] | select(.parent != null and .parent.number == $t) | [ "SUB", (.number|tostring), .state, ((.blockedBy.nodes // []) | map(select(.state == "OPEN") | (.number|tostring)) | join(",")), .title ] | @tsv)) end'
|
|
60
|
+
if [ -n "${STATUS_GH_STUB:-}" ] && [ -r "$STATUS_GH_STUB" ]; then cat "$STATUS_GH_STUB"; return 0; fi
|
|
61
|
+
command -v gh >/dev/null 2>&1 || return 1
|
|
62
|
+
(cd "$root" && gh issue list --state all --limit 200 --json number,title,state,parent,blockedBy --jq "$jq_expr")
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
branch=
|
|
66
|
+
[ -e "$root/.git" ] && branch=$(git -C "$root" branch --show-current 2>/dev/null || true)
|
|
67
|
+
[ -n "$branch" ] || branch=unknown
|
|
68
|
+
tracker=0; tracker_tsv=
|
|
69
|
+
if tracker_tsv=$(tracker_lines 2>/dev/null); then tracker=1; fi
|
|
70
|
+
tracking=
|
|
71
|
+
if [ "$tracker" -eq 1 ]; then
|
|
72
|
+
# Tab is IFS whitespace to bash: empty TSV fields shift columns. Use unit separators.
|
|
73
|
+
while IFS="$(printf '\037')" read -r kind num state blockers title; do
|
|
74
|
+
[ "$kind" = TRACK ] && tracking=$num
|
|
75
|
+
done <<< "$(printf '%s\n' "$tracker_tsv" | tr '\t' '\037')"
|
|
76
|
+
fi
|
|
77
|
+
slugs=$(artifact_slugs)
|
|
78
|
+
if { [ "$tracker" -eq 0 ] || [ -z "$tracking" ]; } && [ -z "$slugs" ]; then
|
|
79
|
+
printf 'NO ACTIVE FACTORY RUN\nspec: %s\n' "$(newest_spec)"
|
|
80
|
+
exit 0
|
|
81
|
+
fi
|
|
82
|
+
printf 'STATUS TREE spec: %s branch: %s\n' "$(newest_spec)" "$branch"
|
|
83
|
+
if [ "$tracker" -eq 1 ] && [ -n "$tracking" ]; then
|
|
84
|
+
printf 'tracker: #%s\n' "$tracking"
|
|
85
|
+
elif [ "$tracker" -eq 1 ]; then
|
|
86
|
+
printf 'tracker: no open run\n'
|
|
87
|
+
else
|
|
88
|
+
printf 'tracker: unavailable (local view)\n'
|
|
89
|
+
fi
|
|
90
|
+
printf 'LEAD: local view\n'
|
|
91
|
+
cfg=$(find "$root/.lead/tmp" -maxdepth 1 -type f -name 'wd-*.json' 2>/dev/null | wc -l | tr -d ' ')
|
|
92
|
+
ps -eo args= 2>/dev/null | grep 'watchdog\.\(ps1\|sh\)' >/dev/null && proc=True || proc=False
|
|
93
|
+
printf 'WATCHDOG: process=%s config=%s\n' "$proc" "$cfg"
|
|
94
|
+
if [ "$tracker" -eq 1 ] && [ -n "$tracking" ]; then
|
|
95
|
+
while IFS="$(printf '\037')" read -r kind num state blockers title; do
|
|
96
|
+
[ "$kind" = SUB ] || continue
|
|
97
|
+
slug=$(slugify "$title"); set -- $(phase "$slug" "$state" "$blockers")
|
|
98
|
+
extra=; [ "$2" = QUEUED ] && extra=" blocked-by: $blockers"
|
|
99
|
+
printf '%s #%s %s .lead/wt/%s-01%s\n' "$1" "$num" "$title" "$slug" "$extra"
|
|
100
|
+
[ "$2" = BUILDING ] && last_command "$slug"
|
|
101
|
+
done <<< "$(printf '%s\n' "$tracker_tsv" | tr '\t' '\037')"
|
|
102
|
+
else
|
|
103
|
+
for slug in $slugs; do
|
|
104
|
+
set -- $(phase "$slug")
|
|
105
|
+
case "$2" in BUILDING|BLOCKED|REVIEWING|REPORTED)
|
|
106
|
+
printf '%s %s .lead/wt/%s-01\n' "$1" "$slug" "$slug"
|
|
107
|
+
[ "$2" = BUILDING ] && last_command "$slug"
|
|
108
|
+
esac
|
|
109
|
+
done
|
|
110
|
+
fi
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
param([Parameter(Mandatory=$true)][string]$Config)
|
|
2
|
+
|
|
3
|
+
# Deterministic stall watchdog for techlead-loop (Windows). Detects mechanically
|
|
4
|
+
# and exits with typed evidence; never kills, nudges, or judges. A job is done
|
|
5
|
+
# only when its report's last non-blank line starts with STATUS:.
|
|
6
|
+
|
|
7
|
+
function DecodeBytes($Buf) {
|
|
8
|
+
if ($Buf.Length -ge 2 -and $Buf[0] -eq 255 -and $Buf[1] -eq 254) { return [System.Text.Encoding]::Unicode.GetString($Buf) }
|
|
9
|
+
if ($Buf.Length -ge 2 -and $Buf[0] -eq 254 -and $Buf[1] -eq 255) { return [System.Text.Encoding]::BigEndianUnicode.GetString($Buf) }
|
|
10
|
+
$utf8 = New-Object System.Text.UTF8Encoding($false, $true)
|
|
11
|
+
try { return $utf8.GetString($Buf) } catch { return [System.Text.Encoding]::Unicode.GetString($Buf) }
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function TailText($Path) {
|
|
15
|
+
if (-not (Test-Path -LiteralPath $Path)) { return "" }
|
|
16
|
+
$fs = [System.IO.File]::Open($Path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::ReadWrite)
|
|
17
|
+
try { $len = [Math]::Min([int64]4096, $fs.Length); [void]$fs.Seek(-$len, [System.IO.SeekOrigin]::End); $buf = New-Object byte[] $len; [void]$fs.Read($buf, 0, $len) }
|
|
18
|
+
finally { $fs.Close() }
|
|
19
|
+
return DecodeBytes $buf
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function HasTerminalStatus($Path) {
|
|
23
|
+
$lines = (TailText $Path) -split "`r?`n"
|
|
24
|
+
for ($i = $lines.Count - 1; $i -ge 0; $i--) {
|
|
25
|
+
$t = $lines[$i].Trim()
|
|
26
|
+
if ($t.Length -gt 0) { return $t.StartsWith("STATUS:", [StringComparison]::Ordinal) }
|
|
27
|
+
}
|
|
28
|
+
return $false
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function FileSize($Path) { if (Test-Path -LiteralPath $Path) { return (Get-Item -LiteralPath $Path).Length }; return 0 }
|
|
32
|
+
|
|
33
|
+
function CpuTotal($Needle) {
|
|
34
|
+
$sum = [int64]0
|
|
35
|
+
foreach ($p in (Get-CimInstance Win32_Process -ErrorAction SilentlyContinue)) {
|
|
36
|
+
if ($p.CommandLine -and $p.CommandLine.IndexOf($Needle, [StringComparison]::OrdinalIgnoreCase) -ge 0) {
|
|
37
|
+
$sum += [int64]$p.KernelModeTime + [int64]$p.UserModeTime
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return $sum
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
$cfg = Get-Content -LiteralPath $Config -Raw | ConvertFrom-Json
|
|
44
|
+
$sweep = if ($cfg.sweep_sec) { [int]$cfg.sweep_sec } else { 120 }
|
|
45
|
+
$stall = if ($cfg.stall_after_min) { [double]$cfg.stall_after_min } else { 10 }
|
|
46
|
+
$state = @{}
|
|
47
|
+
foreach ($j in $cfg.jobs) {
|
|
48
|
+
$state[$j.id] = @{ Done = $false; Size = ((FileSize $j.events_file) + (FileSize $j.report_path)); Growth = (Get-Date); Cpu = (CpuTotal $j.worktree) }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
while ($true) {
|
|
52
|
+
foreach ($j in $cfg.jobs) {
|
|
53
|
+
$id = [string]$j.id
|
|
54
|
+
$s = $state[$id]
|
|
55
|
+
if ($s.Done) { continue }
|
|
56
|
+
if (HasTerminalStatus $j.report_path) { $s.Done = $true; continue }
|
|
57
|
+
if ((-not (Test-Path -LiteralPath $j.events_file)) -and (-not (Test-Path -LiteralPath $j.worktree))) {
|
|
58
|
+
Write-Output "WATCHDOG: INTEGRATED $id"
|
|
59
|
+
exit 2
|
|
60
|
+
}
|
|
61
|
+
$size = (FileSize $j.events_file) + (FileSize $j.report_path)
|
|
62
|
+
$cpu = CpuTotal $j.worktree
|
|
63
|
+
if ($size -gt $s.Size) { $s.Size = $size; $s.Growth = Get-Date }
|
|
64
|
+
$mins = ((Get-Date) - $s.Growth).TotalMinutes
|
|
65
|
+
$cpuDelta = $cpu - $s.Cpu
|
|
66
|
+
$s.Cpu = $cpu
|
|
67
|
+
$grace = $stall + [double]$j.duration_hint_min
|
|
68
|
+
if ($mins -gt $grace -and $cpuDelta -eq 0) {
|
|
69
|
+
Write-Output "WATCHDOG: STALL $id minutes_since_growth=$([Math]::Round($mins, 3)) cpu_delta=$cpuDelta"
|
|
70
|
+
foreach ($line in ((TailText $j.events_file) -split "`r?`n" | Select-Object -Last 5)) { Write-Output $line }
|
|
71
|
+
exit 3
|
|
72
|
+
}
|
|
73
|
+
$cmds = @()
|
|
74
|
+
foreach ($m in [regex]::Matches((TailText $j.events_file), '"command"\s*:\s*"((?:\\.|[^"\\])*)"')) { $cmds += $m.Groups[1].Value }
|
|
75
|
+
if ($cmds.Count -ge 4) {
|
|
76
|
+
$last = $cmds | Select-Object -Last 4
|
|
77
|
+
if (($last | Select-Object -Unique).Count -eq 1) {
|
|
78
|
+
Write-Output "WATCHDOG: REPEAT $id command=$($last[0]) count=4"
|
|
79
|
+
exit 4
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
$open = @($state.Values | Where-Object { -not $_.Done })
|
|
84
|
+
if ($open.Count -eq 0) {
|
|
85
|
+
Write-Output "WATCHDOG: ALL_DONE"
|
|
86
|
+
foreach ($j in $cfg.jobs) { Write-Output "$($j.id) $($j.report_path) $(FileSize $j.report_path) bytes" }
|
|
87
|
+
exit 0
|
|
88
|
+
}
|
|
89
|
+
Start-Sleep -Seconds $sweep
|
|
90
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Deterministic stall watchdog for techlead-loop. It detects mechanically and
|
|
3
|
+
# never kills, nudges, or judges - it exits with typed evidence and the Lead
|
|
4
|
+
# rules on it. A job is done only when its report's last non-blank line starts
|
|
5
|
+
# with STATUS:.
|
|
6
|
+
set -u
|
|
7
|
+
|
|
8
|
+
cfg=
|
|
9
|
+
while [ "$#" -gt 0 ]; do
|
|
10
|
+
case "$1" in --config) cfg=$2; shift 2;; *) shift;; esac
|
|
11
|
+
done
|
|
12
|
+
[ -n "$cfg" ] || { printf 'usage: watchdog.sh --config <wd.json>\n' >&2; exit 1; }
|
|
13
|
+
|
|
14
|
+
json=$(tr -d '\r\n' < "$cfg")
|
|
15
|
+
sweep=$(printf '%s' "$json" | sed -n 's/.*"sweep_sec"[[:space:]]*:[[:space:]]*\([0-9.]*\).*/\1/p')
|
|
16
|
+
stall=$(printf '%s' "$json" | sed -n 's/.*"stall_after_min"[[:space:]]*:[[:space:]]*\([0-9.]*\).*/\1/p')
|
|
17
|
+
[ -n "$sweep" ] || sweep=120
|
|
18
|
+
[ -n "$stall" ] || stall=10
|
|
19
|
+
jobs=$(printf '%s' "$json" | sed 's/.*"jobs"[[:space:]]*:[[:space:]]*\[//;s/\][^]]*$//;s/}[[:space:]]*,[[:space:]]*{/\}\n\{/g')
|
|
20
|
+
|
|
21
|
+
field(){ printf '%s' "$1" | sed -n "s/.*\"$2\"[[:space:]]*:[[:space:]]*\"\([^\"]*\)\".*/\1/p"; }
|
|
22
|
+
numfield(){ printf '%s' "$1" | sed -n "s/.*\"$2\"[[:space:]]*:[[:space:]]*\([0-9.]*\).*/\1/p"; }
|
|
23
|
+
fsize(){ stat -c %s "$1" 2>/dev/null || stat -f %z "$1" 2>/dev/null || printf 0; }
|
|
24
|
+
now(){ date +%s; }
|
|
25
|
+
tail_text(){ [ -f "$1" ] && tail -c 4096 "$1" | tr -d '\000\377\376'; }
|
|
26
|
+
report_done(){
|
|
27
|
+
[ -f "$1" ] || return 1
|
|
28
|
+
last=$(tail_text "$1" | awk 'NF{line=$0} END{gsub(/^[[:space:]]+|[[:space:]]+$/,"",line); print line}')
|
|
29
|
+
case "$last" in STATUS:*) return 0;; *) return 1;; esac
|
|
30
|
+
}
|
|
31
|
+
cpu_sum(){
|
|
32
|
+
w=$1
|
|
33
|
+
if [ -d /proc ]; then
|
|
34
|
+
total=0
|
|
35
|
+
for p in /proc/[0-9]*; do
|
|
36
|
+
[ -r "$p/cmdline" ] || continue
|
|
37
|
+
cmd=$(tr '\000' ' ' < "$p/cmdline")
|
|
38
|
+
case "$cmd" in *"$w"*) v=$(awk '{print $14+$15}' "$p/stat" 2>/dev/null); total=$((total+${v:-0}));; esac
|
|
39
|
+
done
|
|
40
|
+
printf '%s' "$total"
|
|
41
|
+
else
|
|
42
|
+
ps -eo time=,args= | awk -v w="$w" 'index($0,w){split($1,a,"-"); n=split($1,b,"-"); t=(n==2?b[2]:$1); split(t,c,":"); if(length(c)==3)s+=c[1]*3600+c[2]*60+c[3]; else s+=c[1]*60+c[2]} END{print s+0}'
|
|
43
|
+
fi
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
declare -a ids events reports trees hints done_ sizes growth cpus
|
|
47
|
+
i=0
|
|
48
|
+
while IFS= read -r job; do
|
|
49
|
+
[ -n "$job" ] || continue
|
|
50
|
+
ids[$i]=$(field "$job" id); events[$i]=$(field "$job" events_file)
|
|
51
|
+
reports[$i]=$(field "$job" report_path); trees[$i]=$(field "$job" worktree)
|
|
52
|
+
hints[$i]=$(numfield "$job" duration_hint_min); done_[$i]=0
|
|
53
|
+
ev=$(fsize "${events[$i]}"); rp=$(fsize "${reports[$i]}"); sizes[$i]=$((ev+rp)); growth[$i]=$(now); cpus[$i]=$(cpu_sum "${trees[$i]}")
|
|
54
|
+
i=$((i+1))
|
|
55
|
+
done <<EOF
|
|
56
|
+
$jobs
|
|
57
|
+
EOF
|
|
58
|
+
|
|
59
|
+
while :; do
|
|
60
|
+
all=1
|
|
61
|
+
for i in "${!ids[@]}"; do
|
|
62
|
+
[ "${done_[$i]}" = 1 ] && continue
|
|
63
|
+
report_done "${reports[$i]}" && { done_[$i]=1; continue; }
|
|
64
|
+
all=0
|
|
65
|
+
if [ ! -e "${events[$i]}" ] && [ ! -e "${trees[$i]}" ]; then
|
|
66
|
+
printf 'WATCHDOG: INTEGRATED %s\n' "${ids[$i]}"; exit 2
|
|
67
|
+
fi
|
|
68
|
+
ev=$(fsize "${events[$i]}"); rp=$(fsize "${reports[$i]}"); sz=$((ev+rp)); cpu=$(cpu_sum "${trees[$i]}")
|
|
69
|
+
[ "$sz" -gt "${sizes[$i]}" ] && { sizes[$i]=$sz; growth[$i]=$(now); }
|
|
70
|
+
mins=$(awk -v a="$(now)" -v b="${growth[$i]}" 'BEGIN{printf "%.3f",(a-b)/60}')
|
|
71
|
+
delta=$((cpu-cpus[$i])); cpus[$i]=$cpu
|
|
72
|
+
grace=$(awk -v a="$stall" -v b="${hints[$i]:-0}" 'BEGIN{print a+b}')
|
|
73
|
+
if awk -v m="$mins" -v g="$grace" 'BEGIN{exit !(m>g)}' && [ "$delta" -eq 0 ]; then
|
|
74
|
+
printf 'WATCHDOG: STALL %s minutes_since_growth=%s cpu_delta=%s\n' "${ids[$i]}" "$mins" "$delta"
|
|
75
|
+
tail_text "${events[$i]}" | tail -n 5; exit 3
|
|
76
|
+
fi
|
|
77
|
+
last4=$(tail_text "${events[$i]}" | grep -o '"command"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"command"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/' | tail -n 4)
|
|
78
|
+
if [ "$(printf '%s\n' "$last4" | sed '/^$/d' | wc -l)" -eq 4 ] && [ "$(printf '%s\n' "$last4" | sort -u | wc -l)" -eq 1 ]; then
|
|
79
|
+
printf 'WATCHDOG: REPEAT %s command=%s count=4\n' "${ids[$i]}" "$(printf '%s\n' "$last4" | sed -n '1p')"; exit 4
|
|
80
|
+
fi
|
|
81
|
+
done
|
|
82
|
+
if [ "$all" -eq 1 ]; then
|
|
83
|
+
printf 'WATCHDOG: ALL_DONE\n'
|
|
84
|
+
for i in "${!ids[@]}"; do printf '%s %s %s bytes\n' "${ids[$i]}" "${reports[$i]}" "$(fsize "${reports[$i]}")"; done
|
|
85
|
+
exit 0
|
|
86
|
+
fi
|
|
87
|
+
sleep "$sweep"
|
|
88
|
+
done
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Lead Research
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="../../assets/skill-cards/lead-research.svg" alt="lead-research skill card" width="100%">
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
Map a topic cheaply, design parallel research assignments, verify claims
|
|
8
|
+
against sources, and produce a decision-oriented report.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
Install this skill for your user account:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx @tamng0905/builder-essential-skills --skill lead-research
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Install it into the current repository instead:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx @tamng0905/builder-essential-skills --skill lead-research --project
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Restart Claude Code or Codex, then ask it to research a topic, compare
|
|
25
|
+
technology choices, or investigate the state of the art.
|
|
26
|
+
|
|
27
|
+
See the full workflow in [SKILL.md](SKILL.md).
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lead-research
|
|
3
|
+
description: >
|
|
4
|
+
Discovery-scale research harness. A cheap scout maps the topic, the Lead designs
|
|
5
|
+
topic-specific parallel researcher assignments from the scout's map (drawing on a
|
|
6
|
+
source-class tactics library — academic, repos, production patterns, web,
|
|
7
|
+
experts), then verifies claims against sources and writes a decision-oriented
|
|
8
|
+
report. Use when brainstorming a project or feature, choosing a technology, or
|
|
9
|
+
asked to "research X", "state of the art", "deep research". For narrow
|
|
10
|
+
slice-level fact checks inside the build loop, /lead handles those inline.
|
|
11
|
+
effort: high
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Lead Research
|
|
15
|
+
|
|
16
|
+
You are the research Lead. Researchers gather; **you** design the decomposition,
|
|
17
|
+
verify, and write — judgment never delegates. The source-class tactics library
|
|
18
|
+
(search mechanics + verified endpoints per source class) is in `tactics.md`; read
|
|
19
|
+
it when you design researcher assignments. Resolve the `researcher` and `scout`
|
|
20
|
+
models with `python ../lead/config.py` (or the shipped defaults) exactly as the
|
|
21
|
+
build loop does — repo `.lead/config`, then `~/.lead/config`, then defaults.
|
|
22
|
+
|
|
23
|
+
## Scale before anything
|
|
24
|
+
|
|
25
|
+
A tool call is one search OR one page fetch.
|
|
26
|
+
|
|
27
|
+
- **Simple fact-find** → answer directly or 1 researcher, 3–10 tool calls. Don't
|
|
28
|
+
run a harness on a question one search answers.
|
|
29
|
+
- **Comparison / focused question** → 2–4 researchers on distinct perspectives,
|
|
30
|
+
10–15 tool calls each, no scout — you already know the terrain.
|
|
31
|
+
- **Brainstorm / SOTA survey / technology choice** → scout first, then a designed
|
|
32
|
+
fan-out of 4–6 researchers, 15–25 tool calls each.
|
|
33
|
+
|
|
34
|
+
## Procedure
|
|
35
|
+
|
|
36
|
+
### 1. Scope → brief
|
|
37
|
+
|
|
38
|
+
If the question is ambiguous, ask at most 2–3 clarifying questions, then compress
|
|
39
|
+
everything into a **research brief**: the question, the decision it informs,
|
|
40
|
+
constraints, and what "answered" looks like. The brief is the north star — every
|
|
41
|
+
later step is checked against it, and it is restated at the top of the final
|
|
42
|
+
report so the reader can audit scope drift.
|
|
43
|
+
|
|
44
|
+
### 2. Scout, then design the researchers
|
|
45
|
+
|
|
46
|
+
Production deep-research systems use LLM-designed, topic-specific decomposition
|
|
47
|
+
rather than a fixed taxonomy. Researcher assignments are designed per topic.
|
|
48
|
+
|
|
49
|
+
**Scout (brainstorm scale only):** dispatch ONE cheap researcher (the `scout`
|
|
50
|
+
role, ~10 searches) to map the terrain — canonical terminology; the 5–10
|
|
51
|
+
load-bearing systems/papers/repos; the named people; which source classes look
|
|
52
|
+
rich vs empty; the topic's natural fault lines. The scout returns a map, not
|
|
53
|
+
findings. Skip the scout when you already know the terrain (comparisons,
|
|
54
|
+
fact-finds) — an upfront pass that tells you nothing is pure latency.
|
|
55
|
+
|
|
56
|
+
**Design (you, from the scout map):** decompose into 3–6 sub-questions along the
|
|
57
|
+
topic's own fault lines — distinct perspectives, never keyword variants of one
|
|
58
|
+
query. For each researcher pick the source-class tactics it needs from
|
|
59
|
+
`tactics.md` (academic snowballing, dependents-not-stars repo evidence,
|
|
60
|
+
production-pattern mining, general web, expert tracking) — one researcher may mix
|
|
61
|
+
tactics; most topics do not need every class. Scope each researcher to ≤5
|
|
62
|
+
subjects and give it an explicit search budget. Reserve **expert opinion** for a
|
|
63
|
+
second-wave researcher, its roster seeded from the first wave. Review the set for
|
|
64
|
+
overlap AND gaps against the brief before dispatch.
|
|
65
|
+
|
|
66
|
+
### 3. Fan out
|
|
67
|
+
|
|
68
|
+
One fresh researcher per assignment, all parallel, in the background. Take the
|
|
69
|
+
command from `python ../lead/config.py --role researcher`; for Codex it is:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
codex exec --sandbox read-only -c web_search="live" \
|
|
73
|
+
-m <model-id> -c model_reasoning_effort="<effort>" \
|
|
74
|
+
-o .lead/research/<NN>-<researcher>.md \
|
|
75
|
+
- < .lead/research/<NN>-<researcher>.prompt.md
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Write each researcher block to a `.prompt.md` file and pass it via stdin (`-`) —
|
|
79
|
+
never as a shell argument; quote-mangling shells make the CLI hang. Launch ONE
|
|
80
|
+
canary and confirm it starts cleanly before fanning out. If the resolved
|
|
81
|
+
researcher is a Claude row or Codex is unavailable, run researchers as read-only
|
|
82
|
+
Claude subagents with web search — the blocks work verbatim.
|
|
83
|
+
|
|
84
|
+
Every researcher block carries the full contract (objective, output format,
|
|
85
|
+
source guidance, boundaries) plus:
|
|
86
|
+
|
|
87
|
+
- **Search budget** by tier: simple 5, standard 15, deep 25 searches.
|
|
88
|
+
- **Saturation rule**: two consecutive searches yielding no new load-bearing
|
|
89
|
+
facts → return what you have.
|
|
90
|
+
- **Findings discipline**: every finding has a source tag + date + exact figure
|
|
91
|
+
or short quote + confidence tag (high = primary / med = reputable secondary /
|
|
92
|
+
low = single blog or forum). NOT FOUND beats inference. Disagreements between
|
|
93
|
+
sources are reported, never resolved. No recommendations — judgment is yours.
|
|
94
|
+
The findings file is capped at ≤ ~2,500 tokens; every source URL appears
|
|
95
|
+
EXACTLY ONCE in a numbered list at the end, and findings cite by tag ([S3]).
|
|
96
|
+
|
|
97
|
+
### 4. Gap round (max 2 extra rounds, usually 1)
|
|
98
|
+
|
|
99
|
+
After reading wave-1 findings, write (or update) a skeleton draft at
|
|
100
|
+
`.lead/research/<topic>.draft.md` (gitignored working state) — an answer-first
|
|
101
|
+
outline where every section carries **SUPPORTED / THIN / EMPTY** against the
|
|
102
|
+
brief. Gap researchers are designed from the THIN/EMPTY sections. Every NOT FOUND
|
|
103
|
+
carries forward into a **do-not-rechase list** that every gap block includes. The
|
|
104
|
+
**expert-opinion researcher** dispatches here, seeded by the names wave one
|
|
105
|
+
surfaced. Hard stop after two refinement rounds.
|
|
106
|
+
|
|
107
|
+
### 5. Verify (your work, against raw sources)
|
|
108
|
+
|
|
109
|
+
- Extract the **load-bearing claims** — the facts the decision depends on.
|
|
110
|
+
- Require **≥2 independent-origin sources** per load-bearing claim (two articles
|
|
111
|
+
rewriting one press release are one source).
|
|
112
|
+
- Tag each: VERIFIED (≥2 independent agree) / UNVERIFIED (<2, no contradiction) /
|
|
113
|
+
DISPUTED (sources disagree — report both and why) / SUSPICIOUS (contradicts
|
|
114
|
+
available evidence).
|
|
115
|
+
- **Adversarial pass** on the top claims: search "<claim> criticism", "<X>
|
|
116
|
+
problems", "<X> vs <alternative>".
|
|
117
|
+
- **Citations are only URLs fetched this session.** Never cite from memory — even
|
|
118
|
+
search-grounded agents fabricate a nontrivial fraction of URLs. Spot-check the
|
|
119
|
+
load-bearing ones by fetching them yourself.
|
|
120
|
+
- **Recency discipline**: every quantitative or current-state claim carries a
|
|
121
|
+
source date; prefer the most recent authoritative treatment.
|
|
122
|
+
- **Source hierarchy**: primary (papers, official docs, changelogs, first-party
|
|
123
|
+
engineering blogs) > reputable secondary > SEO listicles (pointers, never
|
|
124
|
+
citations).
|
|
125
|
+
- **Opinion ≠ fact.** Expert opinions are positions — quoted, dated,
|
|
126
|
+
conflict-of-interest flagged — and never count toward the ≥2-source rule.
|
|
127
|
+
Expert *disagreements* are first-class findings: they mark the open questions.
|
|
128
|
+
|
|
129
|
+
### 6. Synthesize (one pass, one author — you)
|
|
130
|
+
|
|
131
|
+
Parallelize gathering, never synthesis. Write `docs/research/<topic>.md`:
|
|
132
|
+
|
|
133
|
+
- **Answer first** (BLUF), then evidence, then method.
|
|
134
|
+
- The brief, restated.
|
|
135
|
+
- Per major finding: the claim + confidence tag + what it implies for the
|
|
136
|
+
decision + what evidence would change this conclusion.
|
|
137
|
+
- Disputes surfaced with both positions — never silently averaged.
|
|
138
|
+
- **Expert positions map**: who believes what (quoted, dated, COI-flagged), and
|
|
139
|
+
where credible experts disagree.
|
|
140
|
+
- **Open questions**: each UNVERIFIED/DISPUTED item with the specific search or
|
|
141
|
+
experiment that would resolve it (this doubles as the next round's input).
|
|
142
|
+
- Citations dated and tier-labeled: `[primary, 2026-04]`.
|
|
143
|
+
|
|
144
|
+
Commit the report — this is the **research handoff**: its Open-questions section
|
|
145
|
+
is the next round's input, and the repo is the memory. Raw findings stay in
|
|
146
|
+
`.lead/research/` (gitignored).
|
|
147
|
+
|
|
148
|
+
### 7. Hand off
|
|
149
|
+
|
|
150
|
+
A later session resumes by reading the committed report and dispatching gap
|
|
151
|
+
researchers against its Open-questions section instead of restarting the harness.
|
|
152
|
+
If this feeds the build loop, distill the report into `docs/spec/<slice>.md` per
|
|
153
|
+
`/lead` and continue there. The builder's PHASE 0 will challenge the spec's
|
|
154
|
+
claims — that is a feature.
|
|
155
|
+
|
|
156
|
+
Research is a separate skill on purpose: fan-out costs many times chat-level
|
|
157
|
+
tokens, so it should be a deliberate act, not a side effect of building.
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Source-class tactics library
|
|
2
|
+
|
|
3
|
+
Researcher assignments are DESIGNED per topic by the Lead (SKILL.md step 2); the
|
|
4
|
+
sections below are search tactics and verified endpoints per source class — draw
|
|
5
|
+
on whichever a designed researcher needs, mix freely. Every researcher block
|
|
6
|
+
starts with this preamble, then the researcher-specific objective:
|
|
7
|
+
|
|
8
|
+
```text
|
|
9
|
+
You are a web research agent. Answer ONE assigned objective. Do not write code,
|
|
10
|
+
do not make recommendations - judgment belongs to the Lead reading your output.
|
|
11
|
+
Budget: <N> searches; if two consecutive searches yield no new load-bearing
|
|
12
|
+
facts, stop and return. HARD CONTEXT RULES: never open a full page when the
|
|
13
|
+
search snippet answers the question; quote at most 2 sentences per source; the
|
|
14
|
+
moment you can answer, STOP and write your findings - partial findings beat
|
|
15
|
+
context exhaustion (a researcher that fills its window dies without writing
|
|
16
|
+
anything). OUTPUT: markdown findings, <= ~2,500 tokens - every finding carries a
|
|
17
|
+
source tag (e.g. [S3]), source date, the exact figure or a short direct quote,
|
|
18
|
+
and a confidence tag (high = primary / med = reputable secondary / low = single
|
|
19
|
+
blog or forum). Prefer primary sources. Record exact version numbers and dates.
|
|
20
|
+
When sources disagree, report the disagreement - do not resolve it. If you cannot
|
|
21
|
+
find evidence, write NOT FOUND - never fill gaps from prior knowledge without
|
|
22
|
+
flagging it. End with a numbered source list - every source URL appears EXACTLY
|
|
23
|
+
ONCE, numbered [S1], [S2], ... - then the 2-3 findings most likely to change a
|
|
24
|
+
design decision.
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Researcher scoping rule:** cap each researcher at ~5 subjects (repos, vendors,
|
|
28
|
+
people). Doc-heavy assignments burn the context window on fetched pages. A
|
|
29
|
+
researcher that dies returns NOTHING (the `-o` output only materializes on a
|
|
30
|
+
clean finish). If a researcher dies this way, bisect the assignment into narrower
|
|
31
|
+
researchers and re-dispatch; do not re-run it as-is.
|
|
32
|
+
|
|
33
|
+
## Researcher 0 — Scout (brainstorm scale; runs before assignment design)
|
|
34
|
+
|
|
35
|
+
Objective template: map the terrain of <topic> — do NOT gather findings. Return:
|
|
36
|
+
(1) canonical terminology and the names the field itself uses; (2) the 5–10
|
|
37
|
+
load-bearing systems/papers/repos/vendors, one line each on why they matter;
|
|
38
|
+
(3) the named people whose positions recur; (4) which source classes look rich vs
|
|
39
|
+
empty (papers? repos? vendor blogs? forums?); (5) the topic's natural fault lines
|
|
40
|
+
— the 3–6 sub-questions an expert would split it into. Budget ~10 searches;
|
|
41
|
+
breadth over depth; snippet over page. Output is a MAP for the Lead to design
|
|
42
|
+
researchers from — structure matters more than completeness.
|
|
43
|
+
|
|
44
|
+
## Researcher 1 — Academic (latest papers)
|
|
45
|
+
|
|
46
|
+
Objective: the current academic state of <topic> — most recent survey, the latest
|
|
47
|
+
preprints, and which papers the field treats as load-bearing.
|
|
48
|
+
|
|
49
|
+
Pipeline: **survey first → latest sweep → snowball → score.**
|
|
50
|
+
|
|
51
|
+
- Recent survey: Semantic Scholar `publicationTypes=Review`, or arXiv
|
|
52
|
+
`ti:survey AND abs:<topic>` (last ~18 months). The survey supplies canonical
|
|
53
|
+
terminology and the seed bibliography.
|
|
54
|
+
- Latest sweep (newest first): the arXiv Atom API
|
|
55
|
+
`https://export.arxiv.org/api/query?search_query=cat:<cs.XX>+AND+abs:%22<topic>%22&sortBy=submittedDate&sortOrder=descending&max_results=25`
|
|
56
|
+
(uppercase AND/OR; wait ~3s between calls) and Semantic Scholar
|
|
57
|
+
`https://api.semanticscholar.org/graph/v1/paper/search?query=<topic>&fields=title,year,citationCount,tldr,venue&limit=20`
|
|
58
|
+
(expect 429s — back off and retry; the `tldr` field is gold for triage).
|
|
59
|
+
- Snowball from the 2–3 most relevant seeds — forward citations and semantic
|
|
60
|
+
neighbours via the Semantic Scholar graph API; fall back to OpenAlex
|
|
61
|
+
`https://api.openalex.org/works?search=<topic>&sort=publication_date:desc&per-page=25`
|
|
62
|
+
when S2 throttles.
|
|
63
|
+
- Score candidates by citations-per-month (not raw count — meaningless for 2026
|
|
64
|
+
papers), venue/review decision, code availability. Red flags: preprint-only
|
|
65
|
+
after 18+ months, self-citation-heavy.
|
|
66
|
+
|
|
67
|
+
## Researcher 2 — Popular repos (what the ecosystem actually uses)
|
|
68
|
+
|
|
69
|
+
Objective: the 5–10 repos/libraries the ecosystem has actually adopted for
|
|
70
|
+
<topic>, with adoption evidence beyond stars.
|
|
71
|
+
|
|
72
|
+
- Discovery: GitHub search — `topic:<topic> stars:>1000 archived:false sort:stars`,
|
|
73
|
+
`"<topic>" in:name,description,readme stars:>2000`, plus awesome-lists as recall
|
|
74
|
+
boosters — re-check `pushed:` on every list entry; lists go stale.
|
|
75
|
+
- **Adoption evidence beats stars**: dependents via `https://api.deps.dev` or
|
|
76
|
+
`https://packages.ecosyste.ms` (keyless); registry download trends
|
|
77
|
+
(`https://pypistats.org`, `https://api.npmjs.org/downloads`).
|
|
78
|
+
- **Fake-star check**: stars without proportional forks/issues/dependents = flag
|
|
79
|
+
it. Report stars AND dependents AND last release for every repo.
|
|
80
|
+
|
|
81
|
+
## Researcher 3 — Cutting-edge repos (emerging, not hype)
|
|
82
|
+
|
|
83
|
+
Objective: what's emerging in <topic> in the last ~6 months that practitioners are
|
|
84
|
+
actually adopting — and which hyped repos are already abandoned.
|
|
85
|
+
|
|
86
|
+
- Where bleeding-edge surfaces first: Hacker News via Algolia
|
|
87
|
+
`https://hn.algolia.com/api/v1/search_by_date?query=<topic>&tags=story&numericFilters=points>50`;
|
|
88
|
+
`https://lobste.rs/t/<tag>.json`; GitHub
|
|
89
|
+
`topic:<topic> created:>{90d ago} stars:>100 pushed:>{14d ago} sort:stars`.
|
|
90
|
+
- **Emerging-vs-hype test** (report which side each repo lands on): EMERGING =
|
|
91
|
+
created recently AND pushed <14d AND sustained star velocity AND maintainer
|
|
92
|
+
responses AND forks/issues growing in proportion to stars. HYPE = week-one
|
|
93
|
+
spike then stalled pushes, unanswered issues, README >> code, single
|
|
94
|
+
contributor, no tests/releases. Any single signal is gameable; the conjunction
|
|
95
|
+
is not.
|
|
96
|
+
|
|
97
|
+
## Researcher 4 — Production-grade design patterns
|
|
98
|
+
|
|
99
|
+
Objective: how 2–3 production libraries adjacent to <topic> design the thing we're
|
|
100
|
+
about to build — API ergonomics, error handling, extension points, testing
|
|
101
|
+
patterns — and where they differ.
|
|
102
|
+
|
|
103
|
+
- Select subjects with the production-grade test: pushed <6mo (or explicitly
|
|
104
|
+
stable + responsive issues), tagged releases + changelog in the last 12mo,
|
|
105
|
+
dependents >100 (ecosystem-adjusted), ≥2 active maintainers, CI runs tests on
|
|
106
|
+
PRs, OSI license. Ignore raw stars and commit counts.
|
|
107
|
+
- Reading order — never start at file #1: README + manifest (the deliberate
|
|
108
|
+
public surface) → trace ONE canonical happy-path call end to end → tests for the
|
|
109
|
+
relevant feature → 3 closed issues + 2 merged PRs in the area (the "why not").
|
|
110
|
+
- Extract four categories per library: API ergonomics, error handling, extension
|
|
111
|
+
points (grep for hook/adapter/middleware/plugin/register/Protocol), testing
|
|
112
|
+
patterns. Then the cross-library diff: shared patterns are load-bearing; where
|
|
113
|
+
they differ is a trade-off to document.
|
|
114
|
+
- Tools: GitHub code search (`symbol:`, `/regex/`, `repo:`, `path:`),
|
|
115
|
+
`https://grep.app`, `https://sourcegraph.com/search`.
|
|
116
|
+
|
|
117
|
+
## Researcher 5 — General web
|
|
118
|
+
|
|
119
|
+
Objective: everything the other researchers structurally miss on <topic> — expert
|
|
120
|
+
blog posts, postmortems and failure reports, comparisons, official vendor
|
|
121
|
+
docs/changelogs, pricing/operational constraints.
|
|
122
|
+
|
|
123
|
+
- Standard multi-angle sweep: official docs/changelogs; named-expert posts;
|
|
124
|
+
"<X> postmortem" / "<X> at scale" / "<X> problems"; "<X> vs <Y>". Date-restrict
|
|
125
|
+
queries on fast-moving topics.
|
|
126
|
+
- Source hierarchy applies hardest here: SEO listicles and AI-generated
|
|
127
|
+
aggregators are pointers, never citations — chase them to the primary source or
|
|
128
|
+
drop the claim.
|
|
129
|
+
|
|
130
|
+
## Researcher 6 — Expert opinion (second wave)
|
|
131
|
+
|
|
132
|
+
Objective: what the named experts in <topic> are saying right now — positions,
|
|
133
|
+
warnings, predictions, and especially disagreements — from their blogs, talks,
|
|
134
|
+
and social posts.
|
|
135
|
+
|
|
136
|
+
- **Build the roster first** (why this runs second): survey and top-paper authors
|
|
137
|
+
(researcher 1), maintainers of the leading repos (researchers 2–3), and names
|
|
138
|
+
that recur across researcher 5. Pick 5–8; record each expert's affiliation for
|
|
139
|
+
conflict-of-interest tagging.
|
|
140
|
+
- Where to find their voice, in reliability order: personal blogs / newsletters
|
|
141
|
+
(`"<name>" <topic>`, `site:<their-domain> <topic>`); HN comments
|
|
142
|
+
(`https://hn.algolia.com/api/v1/search?tags=comment,author_<username>&query=<topic>`);
|
|
143
|
+
conference talks / podcasts (prefer transcripts or the speaker's own writeup);
|
|
144
|
+
indexed social (`site:x.com "<name>" <topic>`); Reddit / lobste.rs threads.
|
|
145
|
+
- **Opinion is its own evidence class.** For every position report: the exact
|
|
146
|
+
quote or close paraphrase, where and when stated, and any conflict of interest.
|
|
147
|
+
An opinion NEVER counts toward the ≥2-source rule for factual claims.
|
|
148
|
+
- **The highest-value output is disagreement**: where credible experts contradict
|
|
149
|
+
each other is exactly where the genuinely open questions are. Map who stands
|
|
150
|
+
where and what evidence each side cites.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Orwell Writing
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="../../assets/skill-cards/orwell-writing.svg" alt="orwell-writing skill card" width="100%">
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
Draft, revise, and polish prose in plain English while preserving the intended
|
|
8
|
+
meaning, voice, audience, and genre.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
Install this skill for your user account:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx @tamng0905/builder-essential-skills --skill orwell-writing
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Install it into the current repository instead:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx @tamng0905/builder-essential-skills --skill orwell-writing --project
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Restart Claude Code or Codex, then ask it to draft, edit, simplify, or
|
|
25
|
+
humanize a piece of writing.
|
|
26
|
+
|
|
27
|
+
See the full workflow in [SKILL.md](SKILL.md).
|