@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,342 @@
|
|
|
1
|
+
# Dispatch reference
|
|
2
|
+
|
|
3
|
+
Dispatch turns a frozen slice into fresh builder, reviewer, or critic work. The
|
|
4
|
+
Lead chooses the job shape, the model tier, the worktree, and the report path;
|
|
5
|
+
the subagent receives a self-contained task and returns raw evidence only.
|
|
6
|
+
|
|
7
|
+
## Model routing
|
|
8
|
+
|
|
9
|
+
Every role — `lead`, `builder`, `reviewer`, `researcher`, `scout`, `critic` — is
|
|
10
|
+
an independent slot resolved by `skills/lead/config.py`. The "submodel" of a role
|
|
11
|
+
is its reasoning effort. Do not hand-parse config; run the resolver and use what
|
|
12
|
+
it prints:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
python skills/lead/config.py # table of the effective routing
|
|
16
|
+
python skills/lead/config.py --role builder # one role, with its command
|
|
17
|
+
python skills/lead/config.py --check # verify each provider CLI is on PATH
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Resolution order per role: repo `.lead/config`, then `~/.lead/config`, then the
|
|
21
|
+
shipped defaults in `config.py`. A role value is `<provider>/<model>[:<effort>]`,
|
|
22
|
+
a user-defined `alias`, or the sentinel `inherit-lead`. The provider registry
|
|
23
|
+
(`skills/lead/models.json`, extendable via `.lead/models.json`) maps a provider's
|
|
24
|
+
model aliases to real model ids and prints the exact CLI command — this is the
|
|
25
|
+
single place a model-generation change is reviewed. Full grammar: `MODELS.md`.
|
|
26
|
+
|
|
27
|
+
Defaults (see `config.py`): `lead = claude/fable:xhigh` (the leading model),
|
|
28
|
+
`reviewer = inherit-lead`, `builder = codex/best:xhigh`, `researcher =
|
|
29
|
+
codex/best:high`, `scout = codex/best:low`, `critic = claude/fable:high`.
|
|
30
|
+
|
|
31
|
+
Rules that always hold:
|
|
32
|
+
|
|
33
|
+
- **Tier is fixed at decomposition** by config plus dispatch rules; a job failure
|
|
34
|
+
never moves it. A failure is a diagnosis task, not a retry-at-a-stronger-model
|
|
35
|
+
task (see `loop.md` "## Failure ladder").
|
|
36
|
+
- **Codex-first builder fallback.** If the resolved builder's Codex CLI is not on
|
|
37
|
+
PATH at preflight (`config.py --check` flags this), fall back to
|
|
38
|
+
`claude/sonnet:high` and write one tracking-issue comment naming requested vs
|
|
39
|
+
substituted. Never hard-fail on model availability alone.
|
|
40
|
+
- **Dispatch rules** (`when <task-class> -> <spec>`) route recipe-like work to a
|
|
41
|
+
cheaper tier or ambiguous work to a deeper one; the resolver lists them. A
|
|
42
|
+
matching rule is a judgment aid — record which rule you used and override with a
|
|
43
|
+
reason on the issue when needed.
|
|
44
|
+
- **Cross-family review** for high-stakes slices reduces shared blind spots. When
|
|
45
|
+
both CLIs are installed, prefer the reviewer be a different family than the
|
|
46
|
+
builder, and record the direction in the verdict comment.
|
|
47
|
+
|
|
48
|
+
## Per-harness delegation
|
|
49
|
+
|
|
50
|
+
| | Claude Code | Codex |
|
|
51
|
+
|---|---|---|
|
|
52
|
+
| Builder | Agent tool with `.claude/agents/lead-builder.md`; `disallowedTools` denies git commit/push; `isolation: worktree`; run in background; model passed per invocation from the resolver. Verify `git worktree list` after each spawn; never run two Claude-backend builders concurrently without verified separate worktrees. Never pre-create a worktree for a Claude-backend job. | `codex exec` per the resolver's builder command; the Lead owns worktree creation via git. |
|
|
53
|
+
| Reviewer | Agent tool with `.claude/agents/lead-reviewer.md`; read-only tools plus a shell for check commands; lead tier via `model: inherit` or a per-invocation model. | Fresh `codex exec --sandbox read-only` with the fixed reviewer template. |
|
|
54
|
+
| Watchdog | Background `watchdog.sh` / `watchdog.ps1` whose exit wakes the Lead; the LLM fallback template only when the harness cannot wake on a process exit. | Same script watchdog. |
|
|
55
|
+
| Critic | One fresh read-only subagent over the whole decomposition, pre-freeze. | Same. |
|
|
56
|
+
|
|
57
|
+
Job and reviewer reports must name which executor (Bash or PowerShell) ran each
|
|
58
|
+
check command; some sandboxes strip one shell.
|
|
59
|
+
|
|
60
|
+
## Codex backend from a Claude Lead
|
|
61
|
+
|
|
62
|
+
When the Lead is Claude Code and the builder backend is Codex, write the builder
|
|
63
|
+
block to a file first, then pass it via stdin (`-`) — big prompt blocks contain
|
|
64
|
+
quotes that shells can mangle. Take the exact per-role command from
|
|
65
|
+
`config.py --role builder`; the effort pin is the only thing that changes for a
|
|
66
|
+
tier-down.
|
|
67
|
+
|
|
68
|
+
Single job in the current checkout:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
codex exec -C <repo-root> --sandbox workspace-write \
|
|
72
|
+
-m <model-id> -c model_reasoning_effort="<effort>" \
|
|
73
|
+
--json -o .lead/last-run.md \
|
|
74
|
+
- < .lead/dispatch-block.md
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
For 2–5 jobs, the Lead owns the worktree and runs them in parallel:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
git -C <repo-root> worktree add .lead/wt/<slice>-<NN> -b job/<slice>-<NN> <freeze-sha>
|
|
81
|
+
|
|
82
|
+
codex exec -C <repo-root>/.lead/wt/<slice>-<NN> --sandbox workspace-write \
|
|
83
|
+
-m <model-id> -c model_reasoning_effort="<effort>" \
|
|
84
|
+
--json -o .lead/wt/<slice>-<NN>.last-run.md \
|
|
85
|
+
- < .lead/wt/<slice>-<NN>.block.md
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
A worktree's `.git` is sandbox-protected; builders cannot commit or touch shared
|
|
89
|
+
history from any job.
|
|
90
|
+
|
|
91
|
+
## Integration commands
|
|
92
|
+
|
|
93
|
+
Integration is Lead-only, after per-job post-flight passes. For Claude-backend
|
|
94
|
+
jobs, commit inside the harness's auto-created worktree, then merge that branch:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
git -C <repo-root> checkout -b slice/<name> <freeze-sha>
|
|
98
|
+
git -C <repo-root>/.lead/wt/<slice>-<NN> add -A
|
|
99
|
+
git -C <repo-root>/.lead/wt/<slice>-<NN> commit -m "job <NN>: <what>"
|
|
100
|
+
git -C <repo-root> merge --no-ff job/<slice>-<NN>
|
|
101
|
+
<rerun the check commands>
|
|
102
|
+
git -C <repo-root> worktree remove .lead/wt/<slice>-<NN>
|
|
103
|
+
git -C <repo-root> branch -d job/<slice>-<NN>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
A merge conflict means the plan was not disjoint. Kill the conflicting job and
|
|
107
|
+
re-slice; never hand-resolve builder conflicts.
|
|
108
|
+
|
|
109
|
+
## Reviewer template
|
|
110
|
+
|
|
111
|
+
Send this as-is except for the placeholders. Add no slice-specific prose,
|
|
112
|
+
encouragement, summaries, or interpretation. Intent context is pointer-only.
|
|
113
|
+
|
|
114
|
+
<!-- lead-reviewer-template:start -->
|
|
115
|
+
```text
|
|
116
|
+
Frozen check file path: docs/checks/<slice>.md
|
|
117
|
+
Freeze commit SHA: <freeze-sha>
|
|
118
|
+
Branch to review: <branch>
|
|
119
|
+
Spec pointer: <spec path named by the frozen check>
|
|
120
|
+
Job report: docs/jobs/<issue-slug>-01.md
|
|
121
|
+
Rulings file: docs/jobs/<issue-slug>-rulings.md (absent = no post-freeze rulings)
|
|
122
|
+
|
|
123
|
+
You are a fresh, read-only reviewer. You did not build this job. Flag only gaps
|
|
124
|
+
that affect correctness, the stated requirements, or documented project
|
|
125
|
+
invariants -- cite file:line evidence for every finding. No stylistic preferences.
|
|
126
|
+
|
|
127
|
+
Tree audit: any tracked-file modification during review discards the verdict as
|
|
128
|
+
INVALID.
|
|
129
|
+
|
|
130
|
+
Verdict format:
|
|
131
|
+
- Checks integrity: PASS | FAIL | INVALID
|
|
132
|
+
Raw evidence: git diff <freeze-sha>..HEAD -- docs/checks/
|
|
133
|
+
- Diff vs intent: PASS | FAIL | INVALID
|
|
134
|
+
Raw evidence: file:line evidence from the diff and the frozen check/spec text
|
|
135
|
+
- Per check:
|
|
136
|
+
- <check id>: PASS | FAIL | INVALID
|
|
137
|
+
Command: <exact command from the frozen check>
|
|
138
|
+
Executor: <Bash | PowerShell>
|
|
139
|
+
Raw evidence: verbatim stdout/stderr and exit code
|
|
140
|
+
- Slice verdict: PASS | FAIL | INVALID
|
|
141
|
+
Decisive reason: <one sentence tied to raw evidence>
|
|
142
|
+
```
|
|
143
|
+
<!-- lead-reviewer-template:end -->
|
|
144
|
+
|
|
145
|
+
Passing checks with wrong code still fails: the diff-vs-intent verdict is not
|
|
146
|
+
optional. INVALID means "not measured the way the check specifies" — unmeasured
|
|
147
|
+
never equals passed.
|
|
148
|
+
|
|
149
|
+
## Critic template
|
|
150
|
+
|
|
151
|
+
One pre-freeze pass over the whole decomposition. Send as-is except placeholders.
|
|
152
|
+
|
|
153
|
+
<!-- lead-critic-template:start -->
|
|
154
|
+
```text
|
|
155
|
+
Draft check file path: docs/checks/<slice>.md
|
|
156
|
+
Branch: <branch>
|
|
157
|
+
Issue bodies: <pasted issue bodies for this plan>
|
|
158
|
+
|
|
159
|
+
Task: try to falsify this plan. Execute each check command against the current
|
|
160
|
+
tree, verify every referenced path/SHA/pointer resolves, and attack each
|
|
161
|
+
acceptance criterion and issue body for contradictions and non-falsifiability --
|
|
162
|
+
including patterns that collide with repo realities (e.g. a grep pattern matching
|
|
163
|
+
the repo's own name). For every file a job deletes or renames, grep the repo for
|
|
164
|
+
references and confirm the owning job's boundary covers them or a dependency edge
|
|
165
|
+
orders the fix. For every NEW artifact path a job will create, run
|
|
166
|
+
`git check-ignore <path>` and flag the plan if it is ignored.
|
|
167
|
+
|
|
168
|
+
Defect report format:
|
|
169
|
+
- <check id or clause>: FALSIFIED | HOLDS
|
|
170
|
+
Evidence: <command run and verbatim output, or file:line>
|
|
171
|
+
- Plan findings: <delete/rename reference and ignored-new-path findings, or none>
|
|
172
|
+
- Assumptions not evidenced in the repo: <list or none>
|
|
173
|
+
```
|
|
174
|
+
<!-- lead-critic-template:end -->
|
|
175
|
+
|
|
176
|
+
## Issue conventions
|
|
177
|
+
|
|
178
|
+
Claim is a Lead action, never a builder action: the Lead is the single
|
|
179
|
+
dispatcher and assigns exactly one issue per job immediately before spawning its
|
|
180
|
+
builder. On current backends, builders usually cannot post to issues (Codex has
|
|
181
|
+
no network; a Claude subagent may lose its shell), so `MIRROR: LEAD` is the
|
|
182
|
+
normal mode — the Lead mirrors status at event boundaries it already occupies.
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
gh issue edit <n> --add-assignee "@me" # Lead claims, before dispatch
|
|
186
|
+
gh issue comment <n> --body "PHASE 0: <disagreements, or what I checked>"
|
|
187
|
+
gh issue comment <n> --body "BLOCKED: <exact blocker> + <what I tried>"
|
|
188
|
+
gh issue comment <n> --body "STATUS: <the report's exact status line>"
|
|
189
|
+
gh issue comment <n> --body "RULING: <decision> - <one line why>"
|
|
190
|
+
gh issue comment <n> --body "ANSWER: <blocker answer>"
|
|
191
|
+
gh issue comment <n> --body "VERDICT: PASS|FAIL|INVALID - <decisive reason>"
|
|
192
|
+
gh issue comment <tracking-issue-n> --body "DIGEST: <batched escalations + run summary>"
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Comments land at least 1 minute apart, each under 65,000 characters, never one
|
|
196
|
+
per commit (GitHub secondary rate limits). A running builder does NOT re-read
|
|
197
|
+
issue comments mid-job — the issue is the durable log, not a channel it polls; an
|
|
198
|
+
answer reaches a builder only through a fresh respawn's spawn context.
|
|
199
|
+
|
|
200
|
+
## Watchdog dispatch
|
|
201
|
+
|
|
202
|
+
The Lead writes one watchdog config JSON per wave, then launches the platform
|
|
203
|
+
script as a background process (`watchdog.sh` on POSIX, `watchdog.ps1` on
|
|
204
|
+
Windows):
|
|
205
|
+
|
|
206
|
+
```json
|
|
207
|
+
{
|
|
208
|
+
"sweep_sec": 120,
|
|
209
|
+
"stall_after_min": 10,
|
|
210
|
+
"jobs": [
|
|
211
|
+
{ "id": "issue-31", "events_file": "<path>", "report_path": "<path>",
|
|
212
|
+
"worktree": "<path>", "duration_hint_min": 0 }
|
|
213
|
+
]
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
The watchdog detects mechanically and never kills, nudges, or judges. It exits
|
|
218
|
+
with typed evidence; the Lead rules on it:
|
|
219
|
+
|
|
220
|
+
| Exit | Prefix | Meaning |
|
|
221
|
+
|---|---|---|
|
|
222
|
+
| 0 | `WATCHDOG: ALL_DONE` | every job report exists, with path + byte-size evidence |
|
|
223
|
+
| 2 | `WATCHDOG: INTEGRATED` | a worktree or events file vanished because the Lead integrated it mid-sweep |
|
|
224
|
+
| 3 | `WATCHDOG: STALL` | file growth and process activity both stopped past `stall_after_min` plus any duration hint |
|
|
225
|
+
| 4 | `WATCHDOG: REPEAT` | the last four parsed command events were identical and need an intentional-vs-stuck ruling |
|
|
226
|
+
|
|
227
|
+
A job is DONE only when its report's final non-blank line starts with `STATUS:`.
|
|
228
|
+
Report existence alone is not done. Liveness is output-file growth plus
|
|
229
|
+
process-tree activity, weighed against any duration hint — never wall-clock alone.
|
|
230
|
+
|
|
231
|
+
## Monitor fallback template
|
|
232
|
+
|
|
233
|
+
Use only when the backend cannot wake the Lead from a background process exit; it
|
|
234
|
+
counts against the concurrency cap while running.
|
|
235
|
+
|
|
236
|
+
<!-- lead-monitor-fallback-template:start -->
|
|
237
|
+
```text
|
|
238
|
+
You are the detection-only fallback monitor for this dispatch wave. You never
|
|
239
|
+
kill, nudge, or decide -- you only observe and report evidence.
|
|
240
|
+
|
|
241
|
+
In-flight jobs:
|
|
242
|
+
- Issue #<n>, events <path>, report docs/jobs/<issue-slug>-01.md,
|
|
243
|
+
worktree <path>, duration hint <hint or none>. (one line per job)
|
|
244
|
+
|
|
245
|
+
Sweep every ~10 minutes. For each job, check events/report byte growth, process
|
|
246
|
+
activity by command-line/worktree match, and repeated identical commands in the
|
|
247
|
+
tail. A quiet events file on a single sweep is normal model thinking.
|
|
248
|
+
|
|
249
|
+
Quiet exit is allowed ONLY when, for every job, you list the report path and byte
|
|
250
|
+
size as evidence. If a worktree or events file vanished because the Lead
|
|
251
|
+
integrated the job mid-sweep, exit INTEGRATED and list the vanished path. If you
|
|
252
|
+
cannot verify something from this sandbox, state what you cannot verify rather
|
|
253
|
+
than assuming the job is done. Any stall or repeat concern exits immediately with
|
|
254
|
+
the job id, minutes since last growth, process evidence, and a tail excerpt.
|
|
255
|
+
```
|
|
256
|
+
<!-- lead-monitor-fallback-template:end -->
|
|
257
|
+
|
|
258
|
+
## Respawn-with-answer template
|
|
259
|
+
|
|
260
|
+
Respawn-over-resume is the default recovery: a fresh builder spawns into the same
|
|
261
|
+
issue's job. The respawn block is built from four pieces — the original issue
|
|
262
|
+
body (unchanged), the Lead's answer or ruling (posted as an issue comment first,
|
|
263
|
+
copied verbatim into the spawn context), what the previous session completed
|
|
264
|
+
(read from its job report and the worktree's actual `git status`/`git diff`,
|
|
265
|
+
never assumed), and the unchanged boundaries.
|
|
266
|
+
|
|
267
|
+
```text
|
|
268
|
+
You are resuming issue #<n>. Do not redo completed edits; working-tree edits
|
|
269
|
+
survived unless the command output below proves otherwise.
|
|
270
|
+
|
|
271
|
+
Previous session completed (from docs/jobs/<issue-slug>-01.md and worktree state):
|
|
272
|
+
<summary of file:line evidence>.
|
|
273
|
+
|
|
274
|
+
Lead's answer/ruling (also posted on issue #<n>):
|
|
275
|
+
<answer, diagnosis, or rescue root cause>.
|
|
276
|
+
|
|
277
|
+
Required route-around (sandbox-hang cases only):
|
|
278
|
+
- Run exactly: <command with in-workspace temp/cache paths>.
|
|
279
|
+
- Run check commands sequentially only.
|
|
280
|
+
|
|
281
|
+
Boundaries remain:
|
|
282
|
+
- MAY TOUCH: <files>
|
|
283
|
+
- MUST NOT TOUCH: <files>
|
|
284
|
+
- Report path: docs/jobs/<issue-slug>-01.md
|
|
285
|
+
- End with exactly one STATUS line.
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## Builder block template
|
|
289
|
+
|
|
290
|
+
```text
|
|
291
|
+
Execute the spec below. Operating rules:
|
|
292
|
+
|
|
293
|
+
PHASE 0 - Before any code: reply with your plan and EVERY disagreement you have
|
|
294
|
+
with this spec, with reasons, citing real files in this repo. Silent compliance
|
|
295
|
+
is a failure. Silent scope additions are a failure. If you have no disagreements,
|
|
296
|
+
state what you checked before concluding the spec is sound. Verify the named
|
|
297
|
+
APIs/formats/versions against the live dependencies before planning around them.
|
|
298
|
+
|
|
299
|
+
PHASE 1 - The files under docs/checks/ are read-only at all times; editing them
|
|
300
|
+
fails the slice regardless of results.
|
|
301
|
+
|
|
302
|
+
PHASE 2 - Build YOUR JOB ONLY: exactly the files listed in BOUNDARIES. Files
|
|
303
|
+
outside your job belong outside your authority - touching them fails your job. No
|
|
304
|
+
placeholder implementations - search the codebase before implementing; full
|
|
305
|
+
implementations only. No silent fallbacks or success-shaped defaults - never
|
|
306
|
+
swallow an error to make output look right. No unrequested backwards-
|
|
307
|
+
compatibility shims. Fail loudly, with context. Exception: fallbacks or compat
|
|
308
|
+
code are allowed only when the spec explicitly requests them. Verify your work by
|
|
309
|
+
running the job's check commands and record the verbatim output. Do NOT commit -
|
|
310
|
+
the Lead commits and merges after verification. Do NOT delete lock files or
|
|
311
|
+
escalate privileges if a git command fails; record the exact error and continue.
|
|
312
|
+
|
|
313
|
+
SANDBOX POLICY - All temp/basetemp/cache paths MUST be inside the workspace
|
|
314
|
+
(.lead/tmp/<purpose>); never system temp. Run check commands SEQUENTIALLY. The
|
|
315
|
+
spec may declare duration hints for known-long commands; they are context, not
|
|
316
|
+
kill ceilings. If a command appears stalled - no output growth and no process
|
|
317
|
+
activity well past its hint - record the exact command and stop the job; the
|
|
318
|
+
watchdog and Lead own stall handling. A filesystem/sandbox error on a path is
|
|
319
|
+
environmental: record it and route around it - never retry the same path.
|
|
320
|
+
|
|
321
|
+
When done, write your job report to docs/jobs/<issue-slug>-01.md with RAW results
|
|
322
|
+
only - tables, numbers, command output - no interpretation. Every status claim
|
|
323
|
+
must be backed by a command result from this run. Mirror your final STATUS line
|
|
324
|
+
as a comment on your issue when gh is available; otherwise write "MIRROR: LEAD"
|
|
325
|
+
in the report and continue. End the report with exactly one status line:
|
|
326
|
+
STATUS: COMPLETE | COMPLETE_WITH_CONCERNS (list them) | BLOCKED (exact blocker + what you tried).
|
|
327
|
+
Verdicts belong to the reviewer and the human. Persist until your job is handled
|
|
328
|
+
end to end.
|
|
329
|
+
|
|
330
|
+
=== OBJECTIVE (and why) ===
|
|
331
|
+
...
|
|
332
|
+
=== OUTPUT FORMAT ===
|
|
333
|
+
...
|
|
334
|
+
=== TOOL GUIDANCE (verification commands; verify-against-reality list) ===
|
|
335
|
+
...
|
|
336
|
+
=== BOUNDARIES (may touch / must not touch / out of scope) ===
|
|
337
|
+
...
|
|
338
|
+
=== DISAGREEMENT RULINGS (from last session) ===
|
|
339
|
+
...
|
|
340
|
+
=== ACCEPTANCE CHECKS (frozen at docs/checks/<slice>.md - read-only) ===
|
|
341
|
+
...
|
|
342
|
+
```
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Factory-loop reference
|
|
2
|
+
|
|
3
|
+
The loop is one Lead session that runs the factory to completion after approval.
|
|
4
|
+
GitHub issues carry coordination state; git carries specs and frozen checks. The
|
|
5
|
+
Lead dispatches the ready issues, sleeps, and wakes only on an event.
|
|
6
|
+
|
|
7
|
+
Parallel rules: reviewers dispatch immediately and run concurrently for every
|
|
8
|
+
DONE, never queued behind another review; the ready-issue frontier recomputes on
|
|
9
|
+
every merge, not at wave boundaries; independent bookkeeping batches into
|
|
10
|
+
parallel calls; merges, synthesis, and the critic pass stay serial by design.
|
|
11
|
+
|
|
12
|
+
## Factory block procedure
|
|
13
|
+
|
|
14
|
+
1. **Dispatch the ready issues.** Compute the ready set (every issue whose
|
|
15
|
+
blockers are closed), up to 5 builder jobs plus one watchdog (see `dispatch.md`
|
|
16
|
+
"## Watchdog dispatch"). Check `docs/STOP` and `docs/PAUSE` before every wave.
|
|
17
|
+
2. **Sleep.** Zero Lead work between dispatch and the next event — no polling.
|
|
18
|
+
3. **Wake on exactly one event:**
|
|
19
|
+
- **Job DONE.** Send the fixed reviewer template to one fresh reviewer; record
|
|
20
|
+
the verdict as an issue comment; merge on PASS, diagnose on FAIL.
|
|
21
|
+
- **Job BLOCKED.** A blocker comment is a completion event. Read it, rule an
|
|
22
|
+
answer, and respawn a fresh builder with the answer in its spawn context
|
|
23
|
+
(`dispatch.md` "## Respawn-with-answer template"). A running job never
|
|
24
|
+
re-reads its own comments — the spawn context is the only delivery channel.
|
|
25
|
+
- **Watchdog ANOMALY.** Read the evidence and rule one of: healthy-long-run
|
|
26
|
+
(relaunch the watchdog, sleep again), needs a nudge or answer, or wedged
|
|
27
|
+
(kill the job, discard its worktree, respawn from the frozen check with a
|
|
28
|
+
route-around).
|
|
29
|
+
4. **Recompute the ready set.** Closing an issue may unblock others.
|
|
30
|
+
5. **Repeat** until no issues remain open, then post the end-of-run digest.
|
|
31
|
+
|
|
32
|
+
## Watchdog protocol
|
|
33
|
+
|
|
34
|
+
Launch the script watchdog at wave dispatch; its typed exit wakes the Lead.
|
|
35
|
+
|
|
36
|
+
- Exit 0 `ALL_DONE` -> proceed to the review backlog for every report listed by
|
|
37
|
+
path and byte size.
|
|
38
|
+
- Exit 2 `INTEGRATED` -> benign mid-sweep integration; relaunch if jobs remain.
|
|
39
|
+
- Exit 3 `STALL` -> run the rescue ladder: inspect the named job, kill stuck
|
|
40
|
+
children if needed, discard a wedged worktree, and respawn from the frozen
|
|
41
|
+
check with a route-around.
|
|
42
|
+
- Exit 4 `REPEAT` -> rule intentional-vs-stuck before acting; deliberate polling
|
|
43
|
+
loops are a known false positive.
|
|
44
|
+
|
|
45
|
+
Backends without background-exit notifications use the LLM fallback template in
|
|
46
|
+
`dispatch.md`; it keeps the same detection-only boundary and per-job evidence.
|
|
47
|
+
|
|
48
|
+
## Verdict comments
|
|
49
|
+
|
|
50
|
+
Judgment is recorded on the issue, not in a file. One comment per reviewed job
|
|
51
|
+
carries: per-check PASS/FAIL/INVALID, a checks-integrity verdict, a
|
|
52
|
+
diff-vs-intent verdict, the slice call, and the decisive reason tied to raw
|
|
53
|
+
evidence (exact `gh` command in `dispatch.md` "## Issue conventions"). The
|
|
54
|
+
reviewer's intent context is exactly the frozen check file, the spec, the job
|
|
55
|
+
report, and `docs/jobs/<issue-slug>-rulings.md`. That rulings file is Lead-owned,
|
|
56
|
+
append-only, and committed before reviewer dispatch. No verdict comment on an
|
|
57
|
+
issue means the next block must not build on it as accepted; you may re-run review
|
|
58
|
+
with a fresh reviewer if evidence is missing, but may not fill in a verdict from
|
|
59
|
+
memory. The issue closes on merge.
|
|
60
|
+
|
|
61
|
+
## Failure ladder
|
|
62
|
+
|
|
63
|
+
First FAIL on an issue: diagnose from the reviewer's evidence (not the full
|
|
64
|
+
diff), optionally fan out researchers (`research.md`) to inform the diagnosis,
|
|
65
|
+
fix the input — issue text, missing context, or a forbidden-pattern note — and
|
|
66
|
+
respawn a fresh builder at the same tier. Tier is set once, at decomposition, and
|
|
67
|
+
never changes because a job failed. Second FAIL on the same issue after an
|
|
68
|
+
intervention: re-decompose the issue or escalate to the digest. A merge conflict
|
|
69
|
+
is a decomposition failure, not a build failure: kill the conflicting job and
|
|
70
|
+
re-slice; never hand-resolve builder conflicts.
|
|
71
|
+
|
|
72
|
+
## Escalation digest
|
|
73
|
+
|
|
74
|
+
Batched on the tracking issue instead of interleaved per-job noise: completed and
|
|
75
|
+
failed jobs with verdicts; open blockers and the answers given; decisions the
|
|
76
|
+
approved spec genuinely does not answer. Ask-the-human items are batched here
|
|
77
|
+
unless a hard stop requires an immediate stop.
|
|
78
|
+
|
|
79
|
+
## Hard stops
|
|
80
|
+
|
|
81
|
+
| Situation | Hard stop |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `docs/STOP` exists | Stop before dispatching the next wave. |
|
|
84
|
+
| `docs/PAUSE` exists | Finish in-flight jobs; dispatch nothing new; ask the human. |
|
|
85
|
+
| No verdict comment for completed work | Do not build on it as accepted. |
|
|
86
|
+
| Builder touched `docs/checks/` | Automatic FAIL for that job. |
|
|
87
|
+
| Merge conflict | Decomposition failure: kill the job, re-slice. |
|
|
88
|
+
| Second FAIL on the same issue | Re-decompose or escalate to the digest. |
|
|
89
|
+
| Two consecutive KILLs | Stop the factory and ask the human. |
|
|
90
|
+
| Watchdog reports an anomaly | Rule on it before any further dispatch on that job. |
|
|
91
|
+
| Blocker collides with a recorded assumption | Ask the human; a spec decision surfacing late. |
|
|
92
|
+
| Session context degrades | End the session; the next session grounds from the tracker and git. |
|
|
93
|
+
| Scope grows beyond the approved spec | Stop the factory. |
|
|
94
|
+
| High-stakes issue | Add cross-model review before CONTINUE. |
|
|
95
|
+
|
|
96
|
+
## Context discipline
|
|
97
|
+
|
|
98
|
+
- Delegate heavy reading to reviewer, watchdog, or builder subagents; the Lead
|
|
99
|
+
stays thin and never reads a full diff directly.
|
|
100
|
+
- The tracker and git are the memory: specs, frozen checks, verdict comments, and
|
|
101
|
+
job reports carry state across sessions, not the conversation.
|
|
102
|
+
- Compact proactively when the harness supports it. Ending a degraded session is
|
|
103
|
+
free because the tracker and git are the memory.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"//": "Provider registry for techlead-loop model routing. Edit this ONE file when a model generation ships or a CLI flag changes. `.lead/models.json` (repo) or `~/.lead/models.json` (user) can add or override providers without touching the skill.",
|
|
3
|
+
"providers": {
|
|
4
|
+
"claude": {
|
|
5
|
+
"cli": "claude",
|
|
6
|
+
"kind": "claude",
|
|
7
|
+
"default_model": "fable",
|
|
8
|
+
"default_effort": "xhigh",
|
|
9
|
+
"efforts": ["low", "medium", "high", "xhigh", "max"],
|
|
10
|
+
"models": {
|
|
11
|
+
"fable": "claude-fable-5",
|
|
12
|
+
"opus": "claude-opus-4-8",
|
|
13
|
+
"sonnet": "claude-sonnet-5",
|
|
14
|
+
"haiku": "claude-haiku-4-5"
|
|
15
|
+
},
|
|
16
|
+
"tier_down": {
|
|
17
|
+
"fable": "sonnet",
|
|
18
|
+
"opus": "sonnet",
|
|
19
|
+
"sonnet": "haiku"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"codex": {
|
|
23
|
+
"cli": "codex",
|
|
24
|
+
"kind": "codex",
|
|
25
|
+
"default_model": "best",
|
|
26
|
+
"default_effort": "xhigh",
|
|
27
|
+
"efforts": ["low", "medium", "high", "xhigh"],
|
|
28
|
+
"models": {
|
|
29
|
+
"best": "gpt-5.5"
|
|
30
|
+
},
|
|
31
|
+
"tier_down": {}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Inline research fan-out (for the build loop)
|
|
2
|
+
|
|
3
|
+
Read this only when a research trigger fires inside the factory (an oddity, a
|
|
4
|
+
failure diagnosis, a load-bearing fact the spec depends on). The fan-out uses the
|
|
5
|
+
`researcher` role as parallel web-research subagents — read-only, live search, on
|
|
6
|
+
the flat-rate subscription — and the Lead keeps all judgment: it verifies the
|
|
7
|
+
load-bearing claims and writes the spec itself. For discovery-scale research, use
|
|
8
|
+
the separate `/lead-research` skill; this is the slice-scale version.
|
|
9
|
+
|
|
10
|
+
## Fan out
|
|
11
|
+
|
|
12
|
+
Resolve the researcher model with `python skills/lead/config.py --role
|
|
13
|
+
researcher`. Decompose the question into 3–5 narrow, NON-OVERLAPPING questions —
|
|
14
|
+
cover different angles, not one angle five times. Typical split: official
|
|
15
|
+
docs/reference; changelog / breaking changes; community failure reports;
|
|
16
|
+
alternatives/comparisons; security/operational constraints.
|
|
17
|
+
|
|
18
|
+
One fresh researcher per question, all launched in parallel in the background.
|
|
19
|
+
Take the exact command from the resolver; for Codex it looks like:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
codex exec -C <repo-root> --sandbox read-only -c web_search="live" \
|
|
23
|
+
-m <model-id> -c model_reasoning_effort="<effort>" \
|
|
24
|
+
-o .lead/research/<NN>-<topic>.md \
|
|
25
|
+
- < .lead/research/<NN>-<topic>.prompt.md
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Write each research block to a `.prompt.md` file and pass it via stdin (`-`),
|
|
29
|
+
never as a shell argument — quote-mangling shells make the CLI hang on stdin.
|
|
30
|
+
Launch ONE canary researcher and confirm it starts cleanly before fanning out. If
|
|
31
|
+
the resolved researcher is a Claude row or Codex is unavailable, run the fan-out
|
|
32
|
+
as read-only Claude subagents with web search — the block below works verbatim.
|
|
33
|
+
|
|
34
|
+
- `--sandbox read-only`: researchers never write to the repo.
|
|
35
|
+
- Effort is coverage-tier (`high`, not `xhigh`); synthesis happens on the Lead's
|
|
36
|
+
side.
|
|
37
|
+
- Scope each researcher to ≤5 subjects and put hard context rules in the block
|
|
38
|
+
(snippet over page; quote ≤2 sentences; stop the moment you can answer) — a
|
|
39
|
+
researcher that fills its context window dies without writing its output.
|
|
40
|
+
Bisect and re-dispatch a dead researcher; do not re-run it as-is.
|
|
41
|
+
|
|
42
|
+
## Research block template
|
|
43
|
+
|
|
44
|
+
```text
|
|
45
|
+
You are a web research agent. Answer ONE question. Do not write code, do not make
|
|
46
|
+
recommendations - judgment belongs to the Lead who reads your output.
|
|
47
|
+
|
|
48
|
+
QUESTION: <one narrow question>
|
|
49
|
+
|
|
50
|
+
OUTPUT FORMAT - a markdown report, <= ~2,500 tokens total:
|
|
51
|
+
- Findings as bullets. EVERY finding carries: a source tag (e.g. [S3]), source
|
|
52
|
+
date (if shown), the exact figure or a short direct quote, and a confidence tag
|
|
53
|
+
(high = primary source / med = reputable secondary / low = single blog or forum).
|
|
54
|
+
- Prefer primary sources (official docs, changelogs, release notes, source code)
|
|
55
|
+
over blog posts. Record exact version numbers and dates.
|
|
56
|
+
- When sources disagree, report the disagreement - do not resolve it.
|
|
57
|
+
- If you cannot find evidence, write NOT FOUND - never infer or fill gaps from
|
|
58
|
+
prior knowledge without flagging it.
|
|
59
|
+
- End with a numbered source list - every source URL appears EXACTLY ONCE - then
|
|
60
|
+
the 2-3 findings most likely to change an implementation decision.
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Gather (Lead — your work, not a subagent's)
|
|
64
|
+
|
|
65
|
+
1. Read every findings file in `.lead/research/`.
|
|
66
|
+
2. Identify the **load-bearing claims** — the facts the spec will depend on (an
|
|
67
|
+
API shape, a version constraint, a limit, a deprecation). Adversarially verify
|
|
68
|
+
each against a second independent source or the live dependency itself.
|
|
69
|
+
Discard single-source low-confidence claims or mark them as open questions.
|
|
70
|
+
3. Write `docs/spec/<slice>.md`: problem, decision + why, requirements, non-goals,
|
|
71
|
+
verified facts **with citations**, open questions for the human. You write it;
|
|
72
|
+
researchers gather, you judge.
|
|
73
|
+
4. Commit the spec. Raw findings stay in `.lead/research/` (gitignored) — only the
|
|
74
|
+
distilled, cited spec is repo memory.
|
|
75
|
+
5. The slice spec references this spec instead of restating it; the builder's
|
|
76
|
+
PHASE 0 is expected to challenge the spec's claims.
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
param([string]$RepoRoot = ".")
|
|
2
|
+
|
|
3
|
+
# Read-only status tree for a techlead-loop run (Windows). Reads run artifacts
|
|
4
|
+
# plus `gh`; never a new state store. Callers print the output verbatim.
|
|
5
|
+
|
|
6
|
+
$root = (Resolve-Path -LiteralPath $RepoRoot).Path
|
|
7
|
+
if (-not (Test-Path -LiteralPath $root)) { Write-Output "unreadable repo: $RepoRoot"; exit 1 }
|
|
8
|
+
|
|
9
|
+
$useColor = ($Host.UI.RawUI -ne $null) -and (-not $env:NO_COLOR)
|
|
10
|
+
function Glyph($ch, $code) { if ($useColor) { "`e[$($code)m$ch`e[0m" } else { $ch } }
|
|
11
|
+
$gMerged = Glyph ([char]0x2713) 32
|
|
12
|
+
$gReview = Glyph ([char]0x25D0) 36
|
|
13
|
+
$gBlocked = Glyph "!" 31
|
|
14
|
+
$gReported = Glyph ([char]0x25A3) 35
|
|
15
|
+
$gBuilding = Glyph ([char]0x25CF) 34
|
|
16
|
+
$gQueued = Glyph ([char]0x2298) 33
|
|
17
|
+
$gReady = Glyph ([char]0x25CB) 37
|
|
18
|
+
|
|
19
|
+
function NewestSpec {
|
|
20
|
+
$specDir = Join-Path $root "docs/spec"
|
|
21
|
+
if (-not (Test-Path -LiteralPath $specDir)) { return "unknown" }
|
|
22
|
+
$newest = Get-ChildItem -LiteralPath $specDir -Filter *.md -File -ErrorAction SilentlyContinue |
|
|
23
|
+
Sort-Object LastWriteTimeUtc -Descending | Select-Object -First 1
|
|
24
|
+
if ($newest) { return $newest.Name } else { return "unknown" }
|
|
25
|
+
}
|
|
26
|
+
function TailText($Path) {
|
|
27
|
+
if (-not (Test-Path -LiteralPath $Path)) { return "" }
|
|
28
|
+
$bytes = [System.IO.File]::ReadAllBytes($Path)
|
|
29
|
+
$len = [Math]::Min(4096, $bytes.Length)
|
|
30
|
+
$tail = $bytes[($bytes.Length - $len)..($bytes.Length - 1)]
|
|
31
|
+
return [System.Text.Encoding]::UTF8.GetString($tail)
|
|
32
|
+
}
|
|
33
|
+
function StatusLine($Path) {
|
|
34
|
+
$s = ""
|
|
35
|
+
foreach ($line in ((TailText $Path) -split "`r?`n")) {
|
|
36
|
+
if ($line -match '^\xEF\xBB\xBF?STATUS:') { $s = ($line -replace '^\xEF\xBB\xBF?STATUS:\s*', '') }
|
|
37
|
+
elseif ($line -match '^STATUS:') { $s = ($line -replace '^STATUS:\s*', '') }
|
|
38
|
+
}
|
|
39
|
+
return $s
|
|
40
|
+
}
|
|
41
|
+
function Slugify($s) { (($s.ToLower() -replace '[^a-z0-9]', '-') -replace '-+', '-').Trim('-') }
|
|
42
|
+
function ReportPath($slug) {
|
|
43
|
+
$inWt = Join-Path $root ".lead/wt/$slug-01/docs/jobs/$slug-01.md"
|
|
44
|
+
if (Test-Path -LiteralPath $inWt) { return $inWt }
|
|
45
|
+
return (Join-Path $root "docs/jobs/$slug-01.md")
|
|
46
|
+
}
|
|
47
|
+
function Phase($slug, $state, $blockers) {
|
|
48
|
+
if ($state -eq "CLOSED") { return "$gMerged MERGED" }
|
|
49
|
+
if ($state -eq "OPEN" -and $blockers) { return "$gQueued QUEUED" }
|
|
50
|
+
$rep = ReportPath $slug
|
|
51
|
+
$review = Get-ChildItem -LiteralPath (Join-Path $root ".lead/wt") -Filter "$slug-01.review*.md" -File -ErrorAction SilentlyContinue | Select-Object -First 1
|
|
52
|
+
if ((Test-Path -LiteralPath $rep) -and $review) { return "$gReview REVIEWING" }
|
|
53
|
+
if ((StatusLine $rep) -like "BLOCKED*") { return "$gBlocked BLOCKED" }
|
|
54
|
+
if (Test-Path -LiteralPath $rep) { return "$gReported REPORTED" }
|
|
55
|
+
if (Test-Path -LiteralPath (Join-Path $root ".lead/wt/$slug-01")) { return "$gBuilding BUILDING" }
|
|
56
|
+
return "$gReady READY"
|
|
57
|
+
}
|
|
58
|
+
function TrackerLines {
|
|
59
|
+
$jq = '. 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 ($env:STATUS_GH_STUB -and (Test-Path -LiteralPath $env:STATUS_GH_STUB)) { return Get-Content -LiteralPath $env:STATUS_GH_STUB }
|
|
61
|
+
if (-not (Get-Command gh -ErrorAction SilentlyContinue)) { return $null }
|
|
62
|
+
Push-Location $root
|
|
63
|
+
try { gh issue list --state all --limit 200 --json number,title,state,parent,blockedBy --jq $jq } finally { Pop-Location }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
$branch = "unknown"
|
|
67
|
+
if (Test-Path -LiteralPath (Join-Path $root ".git")) {
|
|
68
|
+
$b = git -C $root branch --show-current 2>$null
|
|
69
|
+
if ($b) { $branch = $b.Trim() }
|
|
70
|
+
}
|
|
71
|
+
$trackerTsv = TrackerLines
|
|
72
|
+
$tracker = ($null -ne $trackerTsv)
|
|
73
|
+
$tracking = $null
|
|
74
|
+
if ($tracker) {
|
|
75
|
+
foreach ($row in $trackerTsv) {
|
|
76
|
+
$cols = $row -split "`t"
|
|
77
|
+
if ($cols[0] -eq "TRACK") { $tracking = $cols[1] }
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
$slugDirs = Get-ChildItem -LiteralPath (Join-Path $root ".lead/wt") -Directory -Filter "*-01" -ErrorAction SilentlyContinue |
|
|
81
|
+
ForEach-Object { $_.Name -replace '-01$', '' } | Sort-Object -Unique
|
|
82
|
+
|
|
83
|
+
if ((-not $tracker -or -not $tracking) -and -not $slugDirs) {
|
|
84
|
+
Write-Output "NO ACTIVE FACTORY RUN"
|
|
85
|
+
Write-Output "spec: $(NewestSpec)"
|
|
86
|
+
exit 0
|
|
87
|
+
}
|
|
88
|
+
Write-Output "STATUS TREE spec: $(NewestSpec) branch: $branch"
|
|
89
|
+
if ($tracker -and $tracking) { Write-Output "tracker: #$tracking" }
|
|
90
|
+
elseif ($tracker) { Write-Output "tracker: no open run" }
|
|
91
|
+
else { Write-Output "tracker: unavailable (local view)" }
|
|
92
|
+
Write-Output "LEAD: local view"
|
|
93
|
+
$cfg = (Get-ChildItem -LiteralPath (Join-Path $root ".lead/tmp") -Filter "wd-*.json" -File -ErrorAction SilentlyContinue | Measure-Object).Count
|
|
94
|
+
$proc = if (Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object { $_.CommandLine -match 'watchdog\.(ps1|sh)' }) { "True" } else { "False" }
|
|
95
|
+
Write-Output "WATCHDOG: process=$proc config=$cfg"
|
|
96
|
+
|
|
97
|
+
if ($tracker -and $tracking) {
|
|
98
|
+
foreach ($row in $trackerTsv) {
|
|
99
|
+
$cols = $row -split "`t"
|
|
100
|
+
if ($cols[0] -ne "SUB") { continue }
|
|
101
|
+
$num = $cols[1]; $state = $cols[2]; $blockers = $cols[3]; $title = $cols[4]
|
|
102
|
+
$slug = Slugify $title
|
|
103
|
+
$p = (Phase $slug $state $blockers) -split ' ', 2
|
|
104
|
+
$extra = if ($p[1] -eq "QUEUED") { " blocked-by: $blockers" } else { "" }
|
|
105
|
+
Write-Output "$($p[0]) #$num $title .lead/wt/$slug-01$extra"
|
|
106
|
+
}
|
|
107
|
+
} else {
|
|
108
|
+
foreach ($slug in $slugDirs) {
|
|
109
|
+
$p = (Phase $slug "" "") -split ' ', 2
|
|
110
|
+
if ($p[1] -in @("BUILDING", "BLOCKED", "REVIEWING", "REPORTED")) {
|
|
111
|
+
Write-Output "$($p[0]) $slug .lead/wt/$slug-01"
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|