archgen-skill 0.0.4 → 0.0.5
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/README.md +31 -43
- package/bin/archgen.mjs +8 -1
- package/lib/block.js +54 -8
- package/lib/doctor.js +23 -4
- package/lib/init.js +11 -1
- package/lib/install.js +20 -3
- package/lib/store.js +99 -4
- package/lib/version-stamp.js +3 -1
- package/package.json +3 -2
- package/vendor/skills/archgen/SKILL.md +183 -278
- package/vendor/skills/archgen/archgen.config.json +1 -1
- package/vendor/skills/archgen/assets/skill-registry.json +1 -1
- package/vendor/skills/archgen/references/artifact-templates.md +57 -0
- package/vendor/skills/archgen/references/interview.md +51 -6
- package/vendor/skills/archgen/references/orchestration.md +136 -13
- package/vendor/skills/archgen/references/platforms.md +55 -0
- package/vendor/skills/archgen/scripts/lib/graph.mjs +18 -3
- package/vendor/skills/archgen/scripts/set-status.mjs +27 -5
- package/vendor/skills/archgen/scripts/update-agents.mjs +12 -3
|
@@ -96,6 +96,63 @@ shrinking LARGE hallucinates.
|
|
|
96
96
|
per-task edge-case matrices + per-module diagrams + MEDIUM-grade plan
|
|
97
97
|
sections. Every diagram ≤15 nodes.
|
|
98
98
|
|
|
99
|
+
## Structural correctness — verifier-enforced authoring rules
|
|
100
|
+
|
|
101
|
+
- **Waves derive from `depends_on`.** Declared wave / `parallel_group` labels
|
|
102
|
+
MUST match the dependency-derived topological order — never hand-label a
|
|
103
|
+
task into a wave that contradicts its `depends_on`. A dependent task may not
|
|
104
|
+
sit in an earlier (or parallel) wave than its prerequisite.
|
|
105
|
+
`plan-graph.mjs --mermaid` is the ground truth for wave order.
|
|
106
|
+
- **artifacts ⊆ file_ownership.** Every path a task lists in `artifacts` must
|
|
107
|
+
fall inside that task's `file_ownership` globs — workers can write ONLY
|
|
108
|
+
owned paths. Listing a doc the task doesn't own is a verifier-blocking
|
|
109
|
+
defect.
|
|
110
|
+
- **Verification commands**: repo-root-relative (no `../`, no `--plan .`),
|
|
111
|
+
fully specific — exact commands, versions, sample sizes, thresholds — the
|
|
112
|
+
same form a worker would actually run. Generic "run the tests" or
|
|
113
|
+
wrong-root-resolved paths fail.
|
|
114
|
+
- **YAML subset**: emit only the parser's supported subset — block mappings
|
|
115
|
+
and block sequences only. Avoid flow mappings (`{...}`), block scalars
|
|
116
|
+
(`|` / `>`), duplicate keys, and comma-heavy inline values, which the
|
|
117
|
+
strict parser rejects (these caused format-repair loops).
|
|
118
|
+
- **tasks.yaml edits**: make small targeted edits or one clean full
|
|
119
|
+
regeneration — never large multi-region patches (they corrupted tasks.yaml
|
|
120
|
+
in the field).
|
|
121
|
+
|
|
122
|
+
## Agent workspace & artifact location — the two-tier rule
|
|
123
|
+
|
|
124
|
+
Location follows LIFETIME + AUDIENCE: the plan (and its rationale) travels as
|
|
125
|
+
ONE self-contained, reviewable, git-versioned unit; the product's deliverables
|
|
126
|
+
travel with the product.
|
|
127
|
+
|
|
128
|
+
INSIDE `.archgen/<slug>/` — the plan + everything needed to execute/review it:
|
|
129
|
+
- tasks.yaml, plans/, architecture.yaml, answers.yaml, codebase-map.md.
|
|
130
|
+
- `docs/prd.md` — a PLANNING artifact (defines the FR-ids tasks cite), not a
|
|
131
|
+
shipped doc — stays inside so doc-index can validate FR references.
|
|
132
|
+
- `decisions/NNNN-title.md` — the plan's formal ADRs (its rationale). Inside
|
|
133
|
+
keeps the feature folder self-contained and ADR↔task↔plan references valid.
|
|
134
|
+
- `.agent/` — ALL agent/sub-agent working state. The leading dot keeps it out
|
|
135
|
+
of doc-index scans (process state, not a validated artifact):
|
|
136
|
+
- `.agent/decisions/NNNN-<slug>.md` — EXECUTION-time decisions a sub-agent
|
|
137
|
+
takes while working (distinct from the plan's formal ADRs in `decisions/`).
|
|
138
|
+
- `.agent/learnings.md` — conventions/patterns discovered (append-only).
|
|
139
|
+
- `.agent/notes/<task-id-or-topic>.md` — worker/survey/investigator notes.
|
|
140
|
+
- `.agent/reports/<verifier|reviewer|investigate>-<round>.md` — persisted
|
|
141
|
+
verifier/reviewer/investigation findings.
|
|
142
|
+
|
|
143
|
+
OUTSIDE `.archgen/` — project DELIVERABLES an approved task produces, written
|
|
144
|
+
to the task's `file_ownership` paths at the repo root (never into `.archgen/`):
|
|
145
|
+
- source code (`src/...`), and
|
|
146
|
+
- shipped documentation: README, API reference, deployment/runbooks, user
|
|
147
|
+
guides — the docs the running software ships to users/operators.
|
|
148
|
+
|
|
149
|
+
Enterprise refinement — durable ADRs: a decision that outlives this feature
|
|
150
|
+
(project-wide, e.g. "Postgres over MongoDB") SHOULD also be promoted to the
|
|
151
|
+
project's canonical ADR register (`docs/adr/` or the team's equivalent) so
|
|
152
|
+
future features discover it. `.archgen/<slug>/decisions/` is the working
|
|
153
|
+
record; the register is the durable project-wide copy. Never delete or
|
|
154
|
+
re-number an accepted ADR — supersede it.
|
|
155
|
+
|
|
99
156
|
## architecture.yaml (LARGE scope)
|
|
100
157
|
|
|
101
158
|
The four contract blocks below (`naming_conventions`, `data_contracts`,
|
|
@@ -1,20 +1,53 @@
|
|
|
1
1
|
# Interview playbook — requirement elicitation
|
|
2
2
|
|
|
3
3
|
Goal: complete, conflict-free requirements in the FEWEST round-trips.
|
|
4
|
-
Batch 3–5 questions per message. Never ask what you can infer
|
|
4
|
+
Batch 3–5 questions per message. Never ask what you can infer — ask only
|
|
5
|
+
decision-forks, state everything else as a veto-able decision (§ How to ask).
|
|
6
|
+
|
|
7
|
+
## How to ask
|
|
8
|
+
|
|
9
|
+
- **Tool-first, options-fallback.** Use your harness's ask-question /
|
|
10
|
+
interactive multiple-choice tool when one exists; no such tool → ask inline
|
|
11
|
+
with labeled options. Same content either way.
|
|
12
|
+
- **Recommendation-first.** Every option set leads with YOUR best judgment
|
|
13
|
+
tagged `(recommended)`, then alternatives. The user accepts the
|
|
14
|
+
recommendation by default and may override — never present bare options
|
|
15
|
+
without a recommendation.
|
|
16
|
+
- **Ask forks, state decisions.** Ask ONLY the few decision-forks that
|
|
17
|
+
materially branch the plan. Everything derivative: DECIDE autonomously and
|
|
18
|
+
announce — "I'll use X because Y — say so if you'd rather Z" — so the user
|
|
19
|
+
can veto without being interrogated.
|
|
20
|
+
- **Volume scales with scope.** Round caps (§ Step 1) are MAXIMA, not targets:
|
|
21
|
+
SMALL/simple prompt → at most 1–2 core questions, decide the rest; MEDIUM →
|
|
22
|
+
the targeted set; LARGE — or an experienced engineer signaling they want
|
|
23
|
+
control → the fuller discovery set.
|
|
24
|
+
|
|
25
|
+
Worked example (recommendation-first, inline fallback form):
|
|
26
|
+
|
|
27
|
+
> Rollout strategy?
|
|
28
|
+
> 1. Feature flag + staged rollout **(recommended)** — existing users unaffected
|
|
29
|
+
> 2. Immediate cutover — simpler, riskier
|
|
30
|
+
> 3. Versioned API alongside — only if existing clients break
|
|
31
|
+
> Reply 1–3, or just "ok" to accept the recommendation.
|
|
5
32
|
|
|
6
33
|
## Round 0 — calibration exchange (skippable)
|
|
7
34
|
|
|
8
|
-
Two or three rapid
|
|
35
|
+
Two or three rapid items, asked once at the very start — each INFERRED first
|
|
36
|
+
(§ How to ask), asked only when genuinely ambiguous:
|
|
9
37
|
|
|
10
|
-
1. Rough scale: prototype, MVP, or production-bound?
|
|
38
|
+
1. Rough scale: prototype, MVP, or production-bound? INFER from the opening
|
|
39
|
+
message + repo context; state the inference + one line of reasoning and
|
|
40
|
+
let the user confirm or correct. Ask open-ended ONLY when genuinely
|
|
41
|
+
ambiguous.
|
|
11
42
|
2. Team size + convention constraints? (solo? existing lint/CI/style guides?)
|
|
12
43
|
3. Deadline pressure: none, moderate, crunch?
|
|
13
44
|
|
|
14
45
|
Purpose is ONLY to pick question-set depth and right-size later verification
|
|
15
46
|
rigor — never to collect requirements. SKIP the whole exchange when the user's
|
|
16
|
-
opening message already answers these items (e.g. "quick prototype by
|
|
17
|
-
|
|
47
|
+
opening message already answers these items (e.g. "quick prototype by
|
|
48
|
+
Friday"); SMALL/simple prompts skip calibration entirely and go straight to
|
|
49
|
+
their 1–2 core forks (§ How to ask). Record whatever was captured under
|
|
50
|
+
`calibration:` in answers.yaml.
|
|
18
51
|
|
|
19
52
|
## Step 1 — classify intent (decide during round 1)
|
|
20
53
|
|
|
@@ -31,6 +64,17 @@ the user in one sentence, and record it as `intent_class` in answers.yaml:
|
|
|
31
64
|
Never interrogate a BROWNFIELD-FEATURE with PRD-grade questions — token waste,
|
|
32
65
|
user annoyance. Round caps INCLUDE round 0 when it runs.
|
|
33
66
|
|
|
67
|
+
Default `scope_class` from the intent class (user's choice wins — scope_class
|
|
68
|
+
is agreed in GENERATE step 1 and recorded in answers.yaml):
|
|
69
|
+
GREENFIELD-SYSTEM→LARGE, GREENFIELD-MODULE→MEDIUM,
|
|
70
|
+
BROWNFIELD-FEATURE→MEDIUM/SMALL, BROWNFIELD-CHANGE→SMALL.
|
|
71
|
+
|
|
72
|
+
Scale is INFERRED, not asked: derive scope_class from the opening message +
|
|
73
|
+
repo context + the class above, state it with one line of reasoning, and let
|
|
74
|
+
the user confirm or correct. Ask about scale ONLY when genuinely
|
|
75
|
+
ambiguous/confused. Small/simple prompts: skip heavy calibration, ask only
|
|
76
|
+
the 1–2 core forks (§ How to ask), decide the rest.
|
|
77
|
+
|
|
34
78
|
## GREENFIELD-SYSTEM — professional discovery (≤6 rounds)
|
|
35
79
|
|
|
36
80
|
Creating a system from scratch demands PRD-grade inputs. Each round below
|
|
@@ -158,7 +202,8 @@ resolve before proceeding. [wait for user]
|
|
|
158
202
|
## Token discipline
|
|
159
203
|
|
|
160
204
|
- Batch 3–5 questions per message; never ping-pong one-per-message.
|
|
161
|
-
- Hard round caps
|
|
205
|
+
- Hard round caps — MAXIMA, not targets (small prompts ask far fewer;
|
|
206
|
+
§ How to ask): GREENFIELD-SYSTEM ≤6 rounds, every other class ≤3
|
|
162
207
|
(round 0 counts when it runs).
|
|
163
208
|
- Skip any question already answered by the opening message, calibration, or
|
|
164
209
|
survey artifacts.
|
|
@@ -24,29 +24,127 @@ Accept the map only if every section is present and non-empty.
|
|
|
24
24
|
|
|
25
25
|
## §verifier — plan review brief
|
|
26
26
|
|
|
27
|
-
Dispatch AFTER artifacts exist and validate.mjs passes.
|
|
27
|
+
Dispatch AFTER artifacts exist and validate.mjs passes.
|
|
28
|
+
|
|
29
|
+
### Agent tier — EVERY verifier dispatch
|
|
30
|
+
|
|
31
|
+
Verification is judgment-heavy: a weak verifier misses real defects AND raises
|
|
32
|
+
false positives — costing MORE rounds, not fewer. Dispatch on the strongest
|
|
33
|
+
reasoning agent the harness offers (best agent present), or a mid/high-tier
|
|
34
|
+
sub-agent scaled to plan complexity:
|
|
35
|
+
|
|
36
|
+
- SMALL/MEDIUM plan → one strong (mid/high-tier) agent.
|
|
37
|
+
- LARGE plan → the stronger/highest tier available.
|
|
38
|
+
- NEVER an explore / research / quick / small / cheap / fast sub-agent,
|
|
39
|
+
whatever the harness calls its low-end tiers.
|
|
40
|
+
|
|
41
|
+
### Verification pass — FULL-DEPTH, every run
|
|
42
|
+
|
|
43
|
+
Each verifier run executes ALL four steps:
|
|
28
44
|
|
|
29
45
|
1. Runs `node <skill>/scripts/verify-plan.mjs .archgen/<slug>/tasks.yaml --plan .archgen/<slug>/plans`
|
|
30
46
|
— deterministic floor: cycles, dangling refs, same-wave ownership overlap,
|
|
31
47
|
missing acceptance criteria, plan↔task coverage.
|
|
32
|
-
2.
|
|
48
|
+
2. When markdown artifacts exist under `.archgen/<slug>/`, runs
|
|
49
|
+
`node <skill>/scripts/doc-index.mjs .archgen/<slug> --validate` — must be
|
|
50
|
+
clean (zero broken references, exit 0) alongside verify-plan APPROVE;
|
|
51
|
+
broken references block APPROVAL.
|
|
52
|
+
3. Reads plans + tasks.yaml and judges what scripts cannot:
|
|
33
53
|
- Are wave boundaries sensible (no artificial serialization)?
|
|
34
54
|
- Do acceptance criteria objectively verify (command or observable)?
|
|
35
55
|
- Edge cases covered per SKILL.md right-sizing class?
|
|
36
56
|
- Code-standards compliance plausible for the planned structure?
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
57
|
+
- CONTRACT-COMPLETENESS sweep — round 1 must confirm OR flag-as-missing
|
|
58
|
+
every APPLICABLE dimension (later discovery = the round-1 sweep failed,
|
|
59
|
+
not a gap). Apply a dimension only where the system actually has that
|
|
60
|
+
concern — skip what genuinely doesn't apply, but NEVER skip a dimension
|
|
61
|
+
the system touches:
|
|
62
|
+
- **Functional coverage**: every stated requirement/feature has tasks +
|
|
63
|
+
objectively verifiable acceptance.
|
|
64
|
+
- **Security & data protection** (if it authenticates, authorizes,
|
|
65
|
+
encrypts, or handles sensitive data): authn/authz flows, session &
|
|
66
|
+
credential lifecycle, replay/CSRF protection, encryption & privacy
|
|
67
|
+
boundaries, input validation — each fully specified, not named-and-
|
|
68
|
+
skipped.
|
|
69
|
+
- **Data integrity**: schemas, relationships, validation, and migration /
|
|
70
|
+
back-compat for any persisted state.
|
|
71
|
+
- **State, lifecycle & recovery** (if any operation is stateful,
|
|
72
|
+
long-running, or multi-step): checkpointing/resume, idempotency,
|
|
73
|
+
cleanup, expiry, compensation/rollback semantics.
|
|
74
|
+
- **Resource limits & abuse** (if it exposes shared or anonymous
|
|
75
|
+
resources): quotas, rate limits, retention/deletion, anonymous-abuse
|
|
76
|
+
controls.
|
|
77
|
+
- **Operational entrypoints**: every stack-required build/deploy/test/
|
|
78
|
+
bootstrap entrypoint is OWNED by some task (no orphan entrypoint).
|
|
79
|
+
- **Metric traceability**: every PRD success metric maps to a task
|
|
80
|
+
acceptance criterion with a reproducible command / sample size / data
|
|
81
|
+
source.
|
|
82
|
+
- **Consistency**: actively check cross-contract claims for internal
|
|
83
|
+
contradiction (a claim in one artifact that another artifact violates).
|
|
84
|
+
These failure classes are the TOP cause of multi-round loops — round 1
|
|
85
|
+
MUST sweep the applicable dimensions exhaustively.
|
|
86
|
+
4. Returns EXACTLY one line verdict: `APPROVE` or `ISSUES:` + numbered list.
|
|
87
|
+
|
|
88
|
+
### Efficiency — fewer rounds + zero duplicate work, NEVER shallower checks
|
|
89
|
+
|
|
90
|
+
Every run stays FULL-DEPTH: both scripts run to completion and the full
|
|
91
|
+
judgment checklist applies each time. Efficiency comes ONLY from:
|
|
92
|
+
|
|
93
|
+
- capping automatic rounds at 2 (gate protocol below);
|
|
94
|
+
- batching fixes per file (fix discipline below);
|
|
95
|
+
- never re-fixing an already-resolved finding.
|
|
96
|
+
|
|
97
|
+
"Efficient" NEVER means skipping or lightening verify-plan.mjs, doc-index.mjs,
|
|
98
|
+
or any judgment-checklist item.
|
|
99
|
+
|
|
100
|
+
### Fix discipline — batch per file, dedupe repeats
|
|
101
|
+
|
|
102
|
+
On `ISSUES:` the orchestrator fixes ALL findings before re-dispatching:
|
|
103
|
+
|
|
104
|
+
- Group findings BY FILE; apply each file's fixes in ONE edit pass — open
|
|
105
|
+
each file once per round, not once per finding.
|
|
106
|
+
- Round N reports the SAME finding as round N-1 (same file + same issue) →
|
|
107
|
+
the prior fix did not land: re-read the file and fix it properly — never
|
|
108
|
+
re-apply the identical edit.
|
|
109
|
+
|
|
110
|
+
### Gate protocol — 2 automatic rounds, then ask the user
|
|
111
|
+
|
|
112
|
+
The initial VERIFIER GATE flow (GENERATE step 5). Rounds 1–2 run
|
|
113
|
+
automatically; fix ALL findings between rounds (fix discipline above):
|
|
114
|
+
|
|
115
|
+
1. Round 1: dispatch verifier. `APPROVE` → gate passed → §plan-review.
|
|
116
|
+
`ISSUES:` → fix ALL findings → round 2.
|
|
117
|
+
2. Round 2: dispatch verifier.
|
|
118
|
+
- Clean `APPROVE` → ask the user once more, recommending NO, proceed.
|
|
119
|
+
- `ISSUES:` → fix ALL findings → ask the user once more, recommending
|
|
120
|
+
YES, one more pass.
|
|
121
|
+
Ask recommendation-first per interview.md § How to ask: "Run the verifier
|
|
122
|
+
once more to make sure everything passes?"
|
|
123
|
+
3. On YES → run another round; if it returns `ISSUES:`, fix all and ask again
|
|
124
|
+
— every round beyond 2 is user-approved. On NO → proceed to §plan-review.
|
|
125
|
+
4. On NO with findings still outstanding and no verifier `APPROVE` on record:
|
|
126
|
+
surface every outstanding finding verbatim and require an EXPLICIT user
|
|
127
|
+
waiver — never proceed silently. Hard rule 2 stands: the plan MUST NOT
|
|
128
|
+
reach the USER GATE without at least one verifier `APPROVE` (or that
|
|
129
|
+
explicit waiver on the record). An earlier `APPROVE` on record → proceed
|
|
130
|
+
to §plan-review, noting the latest unverified fixes.
|
|
41
131
|
|
|
42
132
|
## §plan-review — post-plan review stage
|
|
43
133
|
|
|
44
|
-
Run AFTER verify-plan returns APPROVE and BEFORE the user gate. Dispatch
|
|
45
|
-
|
|
134
|
+
Run AFTER verify-plan returns APPROVE and BEFORE the user gate. Dispatch
|
|
135
|
+
REVIEWER sub-agents sized by the right-sizing class — always ONE holistic
|
|
136
|
+
review of the WHOLE plan, never per-concern splits:
|
|
46
137
|
|
|
47
138
|
- SMALL: main-agent self-review acceptable if no reviewer mechanism exists.
|
|
48
139
|
- MEDIUM: 1 reviewer.
|
|
49
|
-
- LARGE:
|
|
140
|
+
- LARGE: 1 holistic reviewer on the strongest reasoning tier. A 2nd reviewer
|
|
141
|
+
ONLY if the plan is genuinely too large for one reviewer's context — split
|
|
142
|
+
by ARTIFACT/VOLUME then (e.g. plans vs docs), never by concern.
|
|
143
|
+
|
|
144
|
+
One holistic reviewer analyzes ALL issues together: cross-issue reasoning
|
|
145
|
+
catches contradictions a narrow per-concern slice misses, and one reviewer
|
|
146
|
+
costs far fewer tokens than several. NEVER dispatch one sub-agent per
|
|
147
|
+
individual issue/concern.
|
|
50
148
|
|
|
51
149
|
```
|
|
52
150
|
TASK: Review the plan in .archgen/<slug>/ READ-ONLY.
|
|
@@ -61,9 +159,29 @@ You NEVER edit files. Report only.
|
|
|
61
159
|
```
|
|
62
160
|
|
|
63
161
|
Reviewers are read-only and report-only — they never edit artifacts or code.
|
|
64
|
-
The orchestrator fixes the artifacts itself, re-runs validate.mjs +
|
|
65
|
-
the verifier gate after every change
|
|
66
|
-
|
|
162
|
+
The orchestrator fixes the artifacts itself, re-runs validate.mjs +
|
|
163
|
+
re-dispatches the verifier gate after every change.
|
|
164
|
+
|
|
165
|
+
### Review loop — bounded passes, then ask
|
|
166
|
+
|
|
167
|
+
The fix→re-verify cycle stays, but reviewer passes are countable and bounded:
|
|
168
|
+
|
|
169
|
+
1. Pass 1: holistic review. Zero findings → stage done.
|
|
170
|
+
2. Findings → fix ALL (batched per file), re-run validate.mjs + the verifier
|
|
171
|
+
gate → pass 2.
|
|
172
|
+
3. Pass 2 still yields findings → do NOT spawn more reviewers. Consolidate
|
|
173
|
+
the outstanding findings and ask the user once, recommendation-first per
|
|
174
|
+
interview.md § How to ask: "Run one more targeted review pass on the N
|
|
175
|
+
open findings? 1. One more pass (recommended) 2. Waive these findings and
|
|
176
|
+
proceed."
|
|
177
|
+
4. On YES → run EXACTLY ONE more pass, then consolidate and STOP. Zero
|
|
178
|
+
findings → stage done; findings remain → surface them and require an
|
|
179
|
+
explicit user waiver before the user gate. On NO → record the explicit
|
|
180
|
+
waiver, proceed.
|
|
181
|
+
|
|
182
|
+
A "more review" approval authorizes EXACTLY ONE additional pass — never a
|
|
183
|
+
fresh loop, never more reviewers. The stage ends ONLY at zero findings or an
|
|
184
|
+
explicit user waiver on record.
|
|
67
185
|
|
|
68
186
|
## §investigate — root-cause protocol
|
|
69
187
|
|
|
@@ -150,10 +268,15 @@ Every worker receives ALL of:
|
|
|
150
268
|
`node <skill>/scripts/set-status.mjs .archgen/<slug>/tasks.yaml <id> done|failed`;
|
|
151
269
|
- commit guidance: commit completed work scoped to the owned files;
|
|
152
270
|
- BEFORE writing code run
|
|
153
|
-
`node <skill>/scripts/plan-graph.mjs --node <task-id
|
|
271
|
+
`node <skill>/scripts/plan-graph.mjs <slug-dir-or-tasks.yaml> --node <task-id>`
|
|
154
272
|
and honor every connected dependency shown;
|
|
155
273
|
- all file paths come from tasks.yaml/architecture.yaml VERBATIM — never
|
|
156
274
|
reconstruct paths from memory.
|
|
275
|
+
- working state goes under `.archgen/<slug>/.agent/` — execution decisions to
|
|
276
|
+
`.agent/decisions/`, notes to `.agent/notes/<id>.md` (see
|
|
277
|
+
references/artifact-templates.md § Agent workspace & artifact location).
|
|
278
|
+
NEVER create ad-hoc note/context/decision folders at the repo root or
|
|
279
|
+
anywhere outside `.archgen/`.
|
|
157
280
|
|
|
158
281
|
Workers do NOT talk to each other; coordination happens only through
|
|
159
282
|
tasks.yaml state.
|
|
@@ -81,3 +81,58 @@ Claude Code project-scope servers.
|
|
|
81
81
|
2. Prefer official vendor domains over blog posts; note the date of sources.
|
|
82
82
|
3. Present findings + proposed config diff to the user. [approval gate]
|
|
83
83
|
4. Apply, verify, and offer to append findings to this table upstream.
|
|
84
|
+
|
|
85
|
+
## Codegraph indexing scope
|
|
86
|
+
|
|
87
|
+
Current mainstream codegraph indexers extract SOURCE symbols only
|
|
88
|
+
(functions/classes/imports) — they do not index markdown headings, and YAML
|
|
89
|
+
support ranges from absent to file-level config tracking; none can graph
|
|
90
|
+
tasks.yaml dependencies (audited 8 codegraph-family tools Aug 2026; local
|
|
91
|
+
binary v1.0.1 empirically confirms). Generic code indexers verifiably do not
|
|
92
|
+
extract markdown headings or YAML task semantics, so archgen ships its own
|
|
93
|
+
deterministic graph tools:
|
|
94
|
+
|
|
95
|
+
- Source navigation → codegraph MCP when configured (offered at Step 0).
|
|
96
|
+
- YAML plan graphs → exclusively `scripts/plan-graph.mjs`.
|
|
97
|
+
- Markdown artifact navigation → `scripts/doc-index.mjs`.
|
|
98
|
+
|
|
99
|
+
If the harness exposes a markdown-heading indexer (e.g. a
|
|
100
|
+
`codegraph_index_markdown`-style tool), prefer it for general repo docs but
|
|
101
|
+
still use `doc-index.mjs` inside `.archgen/` — it understands TASK/FR
|
|
102
|
+
reference semantics. Brownfield surveys prefer codegraph once present.
|
|
103
|
+
|
|
104
|
+
### Codegraph install & index (concrete — researched Aug 2026, v1.0.1)
|
|
105
|
+
|
|
106
|
+
CodeGraph = `@colbymchenry/codegraph` (npm), CLI `codegraph`, MIT, 100% local.
|
|
107
|
+
It persists a SQLite symbol graph in `.codegraph/` and serves it over MCP. It
|
|
108
|
+
indexes SOURCE symbols only (scope above) — pair with `doc-index.mjs` /
|
|
109
|
+
`plan-graph.mjs` for markdown/YAML. Requires Node 22 or 24 (native SQLite
|
|
110
|
+
bindings; other versions fall back to a 5–10x-slower WASM backend).
|
|
111
|
+
|
|
112
|
+
Install the CLI (one-time, global):
|
|
113
|
+
- `npm i -g @colbymchenry/codegraph` (any OS with Node), or
|
|
114
|
+
- `curl -fsSL https://raw.githubusercontent.com/colbymchenry/codegraph/main/install.sh | sh` (macOS/Linux), or
|
|
115
|
+
- zero-install: `npx @colbymchenry/codegraph`.
|
|
116
|
+
|
|
117
|
+
Wire the harness (writes MCP config + instructions — INSTALL-MCP approval gate):
|
|
118
|
+
- `codegraph install --yes` (auto-detect agents, global)
|
|
119
|
+
- `codegraph install --target=<agent> --yes` (explicit harness)
|
|
120
|
+
- `codegraph install --target=auto --location=local --yes` (project-local)
|
|
121
|
+
- `codegraph install --print-config <agent>` (preview snippet, no writes)
|
|
122
|
+
- Manual config shape: assets/mcp-template.json (stdio `codegraph serve --mcp`
|
|
123
|
+
or npx `-y @colbymchenry/codegraph mcp`).
|
|
124
|
+
|
|
125
|
+
Index the project (per project; creates `.codegraph/` + builds the graph):
|
|
126
|
+
- `codegraph init` (add `--yes` to skip prompts); one-shot bootstrap:
|
|
127
|
+
`codegraph install --yes --init`. Auto-syncs on file change thereafter.
|
|
128
|
+
- `codegraph status` to verify; `codegraph uninit` removes the index;
|
|
129
|
+
`codegraph uninstall` de-wires the agents; `codegraph upgrade` updates.
|
|
130
|
+
|
|
131
|
+
`.codegraph/` is deterministic and small — committing it gives teammates the
|
|
132
|
+
index on first checkout (team recommendation); git-ignore it for solo repos.
|
|
133
|
+
Never point two OSes (Windows + WSL) at one `.codegraph/`.
|
|
134
|
+
|
|
135
|
+
Agent flow: detect `.codegraph/` at repo root. Present → use `codegraph_explore`
|
|
136
|
+
for source navigation. Absent → offer once (INSTALL-MCP approval pattern,
|
|
137
|
+
recommendation-first), run the commands above on approval; on decline use
|
|
138
|
+
Glob+Grep.
|
|
@@ -2,16 +2,26 @@
|
|
|
2
2
|
// WHY a lib: validate.mjs, next-tasks.mjs and verify-plan.mjs must agree on
|
|
3
3
|
// cycle detection and wave semantics; three copies would drift (Metis finding).
|
|
4
4
|
|
|
5
|
+
/** True iff `t` is a mapping object (not null, not an array, not a scalar). */
|
|
6
|
+
function isTaskMapping(t) {
|
|
7
|
+
return t !== null && typeof t === 'object' && !Array.isArray(t);
|
|
8
|
+
}
|
|
9
|
+
|
|
5
10
|
/** Build adjacency (prerequisite → dependents) + reverse maps from tasks.
|
|
6
11
|
* Normative semantics: depends_on lists PREREQUISITE ids; a task is ready iff
|
|
7
|
-
* every prerequisite is done; wave 1 = empty depends_on.
|
|
12
|
+
* every prerequisite is done; wave 1 = empty depends_on.
|
|
13
|
+
* Entries must be mappings with a non-empty string id — anything else is a
|
|
14
|
+
* GraphError naming the index, so consumers exit with a clean contract code
|
|
15
|
+
* instead of an uncaught TypeError on malformed tasks.yaml shapes. */
|
|
8
16
|
export function buildGraph(tasks) {
|
|
9
17
|
/** @type {Map<string, string[]>} prereq -> [dependent ids] */
|
|
10
18
|
const dependents = new Map();
|
|
11
19
|
/** @type {Map<string, string[]>} id -> prerequisite ids */
|
|
12
20
|
const prerequisites = new Map();
|
|
13
21
|
const byId = new Map();
|
|
14
|
-
for (const t of tasks) {
|
|
22
|
+
for (const [i, t] of tasks.entries()) {
|
|
23
|
+
if (!isTaskMapping(t)) throw new GraphError(`tasks[${i}]: not a mapping (task entries must be 'key: value' mappings)`);
|
|
24
|
+
if (typeof t.id !== 'string' || t.id.length === 0) throw new GraphError(`tasks[${i}]: missing string 'id' (every task needs a non-empty string id)`);
|
|
15
25
|
if (byId.has(t.id)) throw new GraphError(`duplicate task id: ${t.id}`);
|
|
16
26
|
byId.set(t.id, t);
|
|
17
27
|
prerequisites.set(t.id, Array.isArray(t.depends_on) ? t.depends_on : []);
|
|
@@ -169,7 +179,9 @@ function globsMayOverlap(a, b) {
|
|
|
169
179
|
export function dedupeDependencies(tasks) {
|
|
170
180
|
let duplicatesCollapsed = 0;
|
|
171
181
|
const normalized = tasks.map((t) => {
|
|
172
|
-
|
|
182
|
+
// Malformed entries pass through untouched; buildGraph owns reporting them
|
|
183
|
+
// (touching t.depends_on here would throw before the contract check runs).
|
|
184
|
+
if (!isTaskMapping(t) || !Array.isArray(t.depends_on)) return t;
|
|
173
185
|
const seen = new Set();
|
|
174
186
|
const deps = [];
|
|
175
187
|
for (const d of t.depends_on) {
|
|
@@ -197,6 +209,9 @@ export function computeQualityStats(tasks) {
|
|
|
197
209
|
let emptyOwnership = 0;
|
|
198
210
|
let blankAcceptance = 0;
|
|
199
211
|
for (const t of tasks) {
|
|
212
|
+
// Malformed entries are buildGraph's to report; counting them here would
|
|
213
|
+
// throw on property access before any consumer sees a contract error.
|
|
214
|
+
if (!isTaskMapping(t)) continue;
|
|
200
215
|
if (Array.isArray(t.depends_on) && t.depends_on.includes(t.id)) selfDeps++;
|
|
201
216
|
const own = t.file_ownership;
|
|
202
217
|
if (!Array.isArray(own) || own.length === 0) emptyOwnership++;
|
|
@@ -3,9 +3,13 @@
|
|
|
3
3
|
// Usage: node set-status.mjs <tasks.yaml> <taskId> <status> [--force]
|
|
4
4
|
// ANY transition out of 'done' requires --force (reopening completed work —
|
|
5
5
|
// directly or via a failed/blocked hop — needs explicit intent). Exit 4 on refusal.
|
|
6
|
-
// Writes via temp-file + rename so concurrent readers never see partial
|
|
6
|
+
// Writes via O_EXCL temp-file + rename so concurrent readers never see partial
|
|
7
|
+
// files (same-wave parallel workers + crash mid-write both safe: the original
|
|
8
|
+
// stays byte-intact until the rename lands; a failure or kill before the rename
|
|
9
|
+
// leaves at worst an orphaned .tmp- sibling, never a half-written tasks.yaml),
|
|
7
10
|
// and re-emits the file's dominant line-ending convention (CRLF stays CRLF).
|
|
8
|
-
|
|
11
|
+
// Exit codes: 0 ok · 4 usage/refusal/parse/IO errors.
|
|
12
|
+
import { readFileSync, writeFileSync, renameSync, unlinkSync } from 'node:fs';
|
|
9
13
|
import { parseYaml, stringifyYaml } from './lib/yaml.mjs';
|
|
10
14
|
|
|
11
15
|
const STATUSES = ['pending', 'ready', 'running', 'blocked', 'done', 'failed'];
|
|
@@ -54,7 +58,25 @@ if (prev === 'done' && nextStatus !== 'done' && !force) {
|
|
|
54
58
|
}
|
|
55
59
|
|
|
56
60
|
task.status = nextStatus;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
// O_EXCL ('wx') guarantees the temp path is freshly created — a stale leftover
|
|
62
|
+
// with the same pid+timestamp is never silently truncated and overwritten.
|
|
63
|
+
const content = stringifyYaml(data, comments, { eol });
|
|
64
|
+
let tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
65
|
+
for (let attempt = 0; ; attempt++) {
|
|
66
|
+
try {
|
|
67
|
+
writeFileSync(tmp, content, { flag: 'wx' });
|
|
68
|
+
break;
|
|
69
|
+
} catch (e) {
|
|
70
|
+
if (e?.code === 'EEXIST' && attempt < 10) { tmp = `${file}.tmp-${process.pid}-${Date.now()}-${attempt + 1}`; continue; }
|
|
71
|
+
console.error(`${file}: cannot write temp file (${e?.code ?? e?.message ?? e})`);
|
|
72
|
+
process.exit(4);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
renameSync(tmp, file); // atomic on POSIX: readers observe old-or-new, never partial
|
|
77
|
+
} catch (e) {
|
|
78
|
+
try { unlinkSync(tmp); } catch { /* original intact; leftover tmp is harmless */ }
|
|
79
|
+
console.error(`${file}: atomic rename failed (${e?.code ?? e?.message ?? e}) — original left untouched`);
|
|
80
|
+
process.exit(4);
|
|
81
|
+
}
|
|
60
82
|
console.log(`${taskId}: ${prev} -> ${nextStatus}`);
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// disappeared are pruned by default (--prune is accepted as the explicit
|
|
10
10
|
// no-op spelling of the same behavior). Writes atomically via temp + rename.
|
|
11
11
|
// Exit codes: 0 ok · 2 no .archgen/ dir · 4 usage/IO/marker errors.
|
|
12
|
-
import { existsSync, readFileSync, readdirSync, renameSync, statSync, writeFileSync } from 'node:fs';
|
|
12
|
+
import { existsSync, readFileSync, readdirSync, renameSync, statSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
13
13
|
import { join } from 'node:path';
|
|
14
14
|
import { parseYaml } from './lib/yaml.mjs';
|
|
15
15
|
|
|
@@ -194,9 +194,18 @@ for (const r of ordered) {
|
|
|
194
194
|
else unchanged++;
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
+
// O_EXCL ('wx') guarantees the temp path is freshly created; the original
|
|
198
|
+
// AGENTS.md stays byte-intact until the rename lands (crash mid-write leaves
|
|
199
|
+
// at worst an orphaned .tmp- sibling, never a half-written registry).
|
|
197
200
|
const tmp = `${agentsPath}.tmp-${process.pid}-${Date.now()}`;
|
|
198
|
-
|
|
199
|
-
|
|
201
|
+
try {
|
|
202
|
+
writeFileSync(tmp, out, { flag: 'wx' });
|
|
203
|
+
renameSync(tmp, agentsPath); // atomic on POSIX: readers observe old-or-new, never partial
|
|
204
|
+
} catch (e) {
|
|
205
|
+
try { unlinkSync(tmp); } catch { /* original intact; leftover tmp is harmless */ }
|
|
206
|
+
console.error(`${agentsPath}: atomic write failed (${e?.code ?? e?.message ?? e}) — original left untouched`);
|
|
207
|
+
process.exit(4);
|
|
208
|
+
}
|
|
200
209
|
|
|
201
210
|
console.log(banner);
|
|
202
211
|
for (const n of notes) console.log(n);
|