@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.
Files changed (66) hide show
  1. package/.claude/agents/lead-builder.md +55 -0
  2. package/.claude/agents/lead-reviewer.md +39 -0
  3. package/README.md +276 -0
  4. package/assets/readme-hero.png +0 -0
  5. package/assets/skill-cards/async-learning-teacher.svg +7 -0
  6. package/assets/skill-cards/code-standards.svg +7 -0
  7. package/assets/skill-cards/lead-research.svg +7 -0
  8. package/assets/skill-cards/lead.svg +7 -0
  9. package/assets/skill-cards/orwell-writing.svg +7 -0
  10. package/assets/skill-cards/session-profiler.svg +7 -0
  11. package/assets/skill-cards/validate-market.svg +7 -0
  12. package/assets/skill-cards/write-blog.svg +7 -0
  13. package/bin/builder-essential-skills.js +134 -0
  14. package/install.ps1 +58 -0
  15. package/install.sh +63 -0
  16. package/package.json +24 -0
  17. package/skills/async-learning-teacher/README.md +50 -0
  18. package/skills/async-learning-teacher/SKILL.md +192 -0
  19. package/skills/async-learning-teacher/agents/openai.yaml +4 -0
  20. package/skills/code-standards/README.md +27 -0
  21. package/skills/code-standards/SKILL.md +51 -0
  22. package/skills/lead/README.md +29 -0
  23. package/skills/lead/SKILL.md +222 -0
  24. package/skills/lead/config.py +359 -0
  25. package/skills/lead/dispatch.md +342 -0
  26. package/skills/lead/loop.md +103 -0
  27. package/skills/lead/models.json +34 -0
  28. package/skills/lead/research.md +76 -0
  29. package/skills/lead/status.ps1 +114 -0
  30. package/skills/lead/status.sh +110 -0
  31. package/skills/lead/watchdog.ps1 +90 -0
  32. package/skills/lead/watchdog.sh +88 -0
  33. package/skills/lead-research/README.md +27 -0
  34. package/skills/lead-research/SKILL.md +157 -0
  35. package/skills/lead-research/tactics.md +150 -0
  36. package/skills/orwell-writing/README.md +27 -0
  37. package/skills/orwell-writing/SKILL.md +44 -0
  38. package/skills/orwell-writing/agents/openai.yaml +4 -0
  39. package/skills/session-profiler/README.md +25 -0
  40. package/skills/session-profiler/SKILL.md +103 -0
  41. package/skills/session-profiler/agents/openai.yaml +4 -0
  42. package/skills/session-profiler/scripts/requirements.txt +2 -0
  43. package/skills/session-profiler/scripts/session_profiler/__init__.py +5 -0
  44. package/skills/session-profiler/scripts/session_profiler/analyses.py +246 -0
  45. package/skills/session-profiler/scripts/session_profiler/cli.py +77 -0
  46. package/skills/session-profiler/scripts/session_profiler/dataset.py +369 -0
  47. package/skills/session-profiler/scripts/session_profiler/discover.py +191 -0
  48. package/skills/session-profiler/scripts/session_profiler/toc.py +74 -0
  49. package/skills/session-profiler/scripts/session_profiler/trace.py +146 -0
  50. package/skills/session-profiler/scripts/sp +20 -0
  51. package/skills/session-profiler/scripts/tests/codex_home/sessions/2026/01/01/rollout-child.jsonl +7 -0
  52. package/skills/session-profiler/scripts/tests/codex_home/sessions/2026/01/01/rollout-root.jsonl +10 -0
  53. package/skills/session-profiler/scripts/tests/fixture/main/subagents/agent-abc.jsonl +2 -0
  54. package/skills/session-profiler/scripts/tests/fixture/main/subagents/agent-abc.meta.json +1 -0
  55. package/skills/session-profiler/scripts/tests/fixture/main.jsonl +7 -0
  56. package/skills/session-profiler/scripts/tests/test_fixture.py +58 -0
  57. package/skills/validate-market/README.md +27 -0
  58. package/skills/validate-market/SKILL.md +202 -0
  59. package/skills/write-blog/README.md +27 -0
  60. package/skills/write-blog/SKILL.md +142 -0
  61. package/skills/write-blog/check.sh +52 -0
  62. package/skills/write-blog/reference/angles.md +51 -0
  63. package/skills/write-blog/reference/craft.md +94 -0
  64. package/skills/write-blog/reference/seo.md +116 -0
  65. package/skills/write-blog/reference/voice.md +64 -0
  66. 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).