Initial Request
src/assets/agents/git.md is a 938-line, 59,376-character hand-maintained file [verified: wc -c -l src/assets/agents/git.md → 938 59376] that Phase 2 must split into a contract layer plus generated per-provider references. Splitting it requires the MDS compiler to own it, but the build script today:
- only compiles
src/assets/commands/*.mds;
- has no notion of a generator host — an agent file whose real frontmatter must survive as body text so
loadShippedDefaults() can still read model:;
- validates its output directory with a raw string equality (
scripts/build-mds.ts:166-173 [verified]: const expectedOutputDir = 'dist/commands'; if (host.outputDir !== expectedOutputDir) { … process.exit(1) });
- does not validate the output filename at all (
scripts/build-mds.ts:178 [verified]: const dest = path.join(outAbs, \${host.basename}.md`)`);
- is unknown to the installer (
src/targets/claude-code/installer.ts:498-524 [verified] reads agentsDir() only) and to the model pipeline (src/core/agent-models.ts:469-504 [verified] loadShippedDefaults reads agentsDir() only).
Phase 1 converts git.md → git.mds, teaches build-mds.ts the generator-host convention through a typed, Result-returning src/core/mds-variants.ts, makes the installer and the model pipeline read the compiled agent with a loud failure rather than a silent skip, and converts every remaining count literal into a name manifest so three later phases stop colliding on the same integer.
AC-1.1 is the whole review: dist/agents/git.md byte-identical to the Phase-0 golden.
Honest user-visible-change statement
"Zero user-visible change. dist/agents/git.md is byte-identical to the file it replaces, the 13 compiled command outputs are byte-unchanged, and the frozen github-status-lines.txt is untouched. The only observable difference is that npm run build:cli alone no longer produces installable agents — npm run build:mds is now required."
This sentence is the CHANGELOG entry and the PR's first paragraph. It is not marketing: it is the claim the golden test mechanically proves.
Execution: SEQUENTIAL_CODE_AGENTS · context-risk: CRITICAL · Design artifact: .devflow/docs/design/tracker-phase-1.2026-09-05_1155.md (authoritative; local, gitignored — a 60k-truncated copy is posted as a collapsed comment).
Product Requirements
Depends on
Phase 0 (#322) merged to main. Tracking issue: #321.
Acceptance criteria
- AC-1.1 —
dist/agents/git.md byte-identical to the golden captured at the Phase-0 merge commit — this test is the review
- AC-1.2 — no
@if with a single reachable arm, no variant list, no (module, op) iteration [DR-16 amendment] grep over the union src/assets/agents/git.mds ∪ src/core/mds-variants.ts ∪ scripts/build-mds.ts — not a git.mds-only grep, which cannot see src/core/ and so cannot mechanically check clause (iii)
- AC-1.3 (amended) — tarball install produces a working
git agent; the src-fallback branch is exercised on an unconverted agent, and the loud-failure branch on git — because Phase 1's own negative guard deletes src/assets/agents/git.md, making "dist absent ⇒ falls back to src" unreachable for the converted agent — the AC text as originally written is self-contradictory for git; the reworded text above is the binding one
- AC-1.4 —
loadShippedDefaults() has an entry for every getAllAgentNames(), and ['git'] === 'haiku'
- AC-1.5 — the 13 command outputs byte-unchanged
- AC-1.6 — registry completeness holds with
git resolved from dist/agents
- AC-1.7 — build-mds exits 1 with the exact "typo?" message for
dist/wrong-dir and rejects name-template: ../x, name-template: a/b, output-dir: dist/../.., output-dir: dist/commands/
- AC-1.8 — count literals are name manifests; the build's printed host/partial numbers agree with the manifest (a
spawnSync assertion — no test asserts them today) NEW test required — the highest-risk P1 gap. See §12 row P1-a and [C16]. Tracked as open item O-8 in the master artifact.
- AC-1.9 —
test:integration runs in CI and covers the dist-preferred agent path
- AC-1.10 —
@mdscript/mds devDep pin 0.2.0 + lock mirror + absent-from-dependencies; a repo-wide grep for src/assets/agents/git.md returns only intended src-fallback sites
- AC-1.11 — the frozen status-line fixture unchanged
- AC-1.12 (new) — the tarball's
src/assets/mds/*.mds entry count is pinned deliberately (0 or N) — the value is Gate-2 decision D-A: (a) ship it, pin the count
- Prefix-shippability — After phase N: (i)
npm run build && npm test && npm run test:integration && npm pack --dry-run are green; (ii) a fresh install from the tarball drives /plan → /implement → /code-review → /resolve → /release on a GitHub project with no new prompt and no new file in git status; (iii) every artifact in the tree has at least one reachable consumer in this phase's end-state — no file, define, list element, frontmatter key or conditional arm exists solely for a later phase (ADR-003); (iv) the frozen github-status-lines.txt fixture is byte-identical to its Phase-0 capture.
Subtasks
| # |
Domain |
Owned files (with anchors) |
Depends on |
Gate before next |
Handoff contents |
| S1 |
build script / TS core / installer |
scripts/build-mds.ts (:101-104 readOutputDir [verified], :114-124 stripOutputDirKey [verified], :159-173 escape guard + dest pin [verified], IGNORE_DIRS :40-48 [verified], DEVFLOW_MDS_ROOT escape hatch :34 [verified]) · new src/core/mds-variants.ts · src/core/assets.ts (compiledAgentsDir() after commandsDir() :41-43 [verified]; optional mdsDir()) · src/targets/claude-code/installer.ts:498-524 [verified] · src/core/agent-models.ts:469-504 [verified] · new tests/mds-variants.test.ts · new tests/build-mds-generator-hosts.test.ts |
Phase 0 merged to main |
G1.1 |
the exact generator-frontmatter block shape stripGeneratorFrontmatter accepts (reproduced verbatim in §7 P1-S4); the 13 dist/commands/*.md SHA-256s recorded before and after S1, confirming they are unchanged; the new allowlist's resolved-path semantics |
| S2 |
prompt assets |
src/assets/agents/git.md → src/assets/agents/git.mds (git mv + generator frontmatter + 142 brace escapes + 9 indented fences) |
S1 (G1.1 green) |
G1.2 — the hard gate |
cmp -s dist/agents/git.md tests/fixtures/golden/git-agent.md exit 0, recorded verbatim; the enumerated list of the 9 indented fences with their git.mds line numbers; grep -c '\\{' dist/agents/git.md == 0; the statement that src/assets/agents/git.md no longer exists, which is why AC-1.3's src-fallback arm must be tested on an unconverted agent |
| S3 |
tests + packaging + docs |
tests/build-mds.test.ts (:67-73, :85-89, :474-482 → name manifests [all verified]) · tests/packaging.test.ts (:42-95 Guard 3 [verified], :213-250 Guard 5 reason string, :324-337 [verified]) · tests/core-paths-assets.test.ts:64-79 · tests/build.test.ts · tests/git-agent.test.ts / registry-integrity.test.ts / skill-references.test.ts / agent-name-guards.test.ts / agent-frontmatter.test.ts (repoint audit — should be no-ops if Phase 0's resolver did its job) · new tests/guards/dist-agents.test.ts · package.json:9-17 [verified] · CLAUDE.md (:89, :91, :116, :257, :276) · five .devflow/features/*/KNOWLEDGE.md [drift: source §P1.3 says six; §0.7 and P1-S15 enumerate five] · docs/reference/platform-assumptions.md · CHANGELOG.md |
S2 (G1.2 green) |
G1.3 |
— (terminal) |
Gates
| Gate |
Must be green before |
Assertion |
| G1.1 |
S2 starts |
npm run build exits 0; npm test green; the 13 dist/commands/*.md SHA-256s identical to the Phase-0 merge commit (AC-1.5); the five negative build cases (AC-1.7) exit 1 with the exact … is not the expected '…' — typo? message (AC-1.7). |
| G1.2 |
S3 starts — the hard gate |
npm run build:mds exits 0 and cmp -s dist/agents/git.md tests/fixtures/golden/git-agent.md and grep -c '\\{' dist/agents/git.md == 0. No test may be repointed before this holds. |
| G1.3 |
PR opens |
Full prefix-shippability (§2 standing AC); loadShippedDefaults() ⊇ getAllAgentNames() and ['git'] === 'haiku' (AC-1.4); registry completeness with git resolved from dist/agents (AC-1.6); the build's printed host/partial counts agree with the manifest via spawnSync (AC-1.8); github-status-lines.txt unchanged (AC-1.11). |
/implement spawn notes
| Subtask |
Spawn parameters |
| S1 |
CREATE_PR: false · HANDOFF_REQUIRED: true |
| S2 |
CREATE_PR: false · HANDOFF_REQUIRED: true |
| S3 |
CREATE_PR: true · HANDOFF_REQUIRED: false (terminal; S3 opens the PR per implement.mds:409) |
Commits are pathspec-scoped (git commit -- <owned paths>) so per-subtask provenance survives the squash-merge (PF-020's validated cheap mitigation). No PR split for Phase 1 (Gate-2 decision D-G) — the phase is one issue, one branch, one PR.
Execution strategy
SEQUENTIAL_CODE_AGENTS — 3 subtasks (S1 → S2 → S3). Context risk: CRITICAL.
Rationale:
src/assets/agents/git.mds cannot compile until stripGeneratorFrontmatter and the resolved-path dest allowlist exist in scripts/build-mds.ts. The conversion's only verification is the build, so build changes must land first.
- The conversion (S2) is a 59,376-character transformation whose acceptance test is byte-equality against a frozen golden. This is the single highest-risk edit in the whole feature and must be the only thing in its agent's context.
- Test repointing (S3) must not begin until byte-equality holds, or a repointed test's red state is ambiguous between "the repoint is wrong" and "the conversion is wrong."
Why PARALLEL_CODE_AGENTS is rejected — the rejection holds and is phase-independent [DR-23]:
npm run build is rm -rf dist && npm run build:cli && npm run build:mds ([verified package.json:20]);
/implement has no worktree isolation — a grep for worktree in implement.mds returns zero hits;
- read closures overlap across every partition (PF-020's 2026-08-30 closure rule).
Because every Code agent's verification step deletes the shared dist/ while a sibling is mid-suite, and Phase 0 deliberately makes every dist-scanning guard fail loud on a missing directory (AC-0.16 / §0.1-R3), any concurrent pair manufactures nondeterministic red. That disqualifier is independent of write-set disjointness. [DR-23] additionally records that Phase 1's S-level dependencies are hard, not merely scheduled: S2 cannot compile without S1's build changes, and S3's red states are ambiguous without S2's byte-equality — this is not one of the two weak dependencies DR-23 flags elsewhere in the plan. If per-agent worktrees ever land, Phase 1 is still not a parallelism candidate. This is a tooling limitation, not a plan limitation.
PR title
refactor(build): compile the Git agent from an MDS generator host
Implementation Plan
Design artifact (authoritative): .devflow/docs/design/tracker-phase-1.2026-09-05_1155.md — local and gitignored. A copy truncated at the 60k comment cap is posted as a collapsed comment: #323 (comment). Run with /implement .devflow/docs/design/tracker-phase-1.2026-09-05_1155.md. Tracking issue: #321.
Initial Request
src/assets/agents/git.mdis a 938-line, 59,376-character hand-maintained file [verified:wc -c -l src/assets/agents/git.md→938 59376] that Phase 2 must split into a contract layer plus generated per-provider references. Splitting it requires the MDS compiler to own it, but the build script today:src/assets/commands/*.mds;loadShippedDefaults()can still readmodel:;scripts/build-mds.ts:166-173[verified]:const expectedOutputDir = 'dist/commands'; if (host.outputDir !== expectedOutputDir) { … process.exit(1) });scripts/build-mds.ts:178[verified]:const dest = path.join(outAbs, \${host.basename}.md`)`);src/targets/claude-code/installer.ts:498-524[verified] readsagentsDir()only) and to the model pipeline (src/core/agent-models.ts:469-504[verified]loadShippedDefaultsreadsagentsDir()only).Phase 1 converts
git.md→git.mds, teachesbuild-mds.tsthe generator-host convention through a typed,Result-returningsrc/core/mds-variants.ts, makes the installer and the model pipeline read the compiled agent with a loud failure rather than a silent skip, and converts every remaining count literal into a name manifest so three later phases stop colliding on the same integer.AC-1.1 is the whole review:
dist/agents/git.mdbyte-identical to the Phase-0 golden.Honest user-visible-change statement
This sentence is the CHANGELOG entry and the PR's first paragraph. It is not marketing: it is the claim the golden test mechanically proves.
Execution:
SEQUENTIAL_CODE_AGENTS· context-risk: CRITICAL · Design artifact:.devflow/docs/design/tracker-phase-1.2026-09-05_1155.md(authoritative; local, gitignored — a 60k-truncated copy is posted as a collapsed comment).Product Requirements
Depends on
Phase 0 (#322) merged to
main. Tracking issue: #321.Acceptance criteria
dist/agents/git.mdbyte-identical to the golden captured at the Phase-0 merge commit — this test is the review@ifwith a single reachable arm, no variant list, no(module, op)iteration [DR-16 amendment] grep over the unionsrc/assets/agents/git.mds ∪ src/core/mds-variants.ts ∪ scripts/build-mds.ts— not agit.mds-only grep, which cannot seesrc/core/and so cannot mechanically check clause (iii)gitagent; the src-fallback branch is exercised on an unconverted agent, and the loud-failure branch ongit— because Phase 1's own negative guard deletessrc/assets/agents/git.md, making "dist absent ⇒ falls back to src" unreachable for the converted agent — the AC text as originally written is self-contradictory forgit; the reworded text above is the binding oneloadShippedDefaults()has an entry for everygetAllAgentNames(), and['git'] === 'haiku'gitresolved fromdist/agentsdist/wrong-dirand rejectsname-template: ../x,name-template: a/b,output-dir: dist/../..,output-dir: dist/commands/spawnSyncassertion — no test asserts them today) NEW test required — the highest-risk P1 gap. See §12 row P1-a and [C16]. Tracked as open item O-8 in the master artifact.test:integrationruns in CI and covers the dist-preferred agent path@mdscript/mdsdevDep pin0.2.0+ lock mirror + absent-from-dependencies; a repo-wide grep forsrc/assets/agents/git.mdreturns only intended src-fallback sitessrc/assets/mds/*.mdsentry count is pinned deliberately (0 or N) — the value is Gate-2 decision D-A: (a) ship it, pin the countnpm run build && npm test && npm run test:integration && npm pack --dry-runare green; (ii) a fresh install from the tarball drives/plan → /implement → /code-review → /resolve → /releaseon a GitHub project with no new prompt and no new file ingit status; (iii) every artifact in the tree has at least one reachable consumer in this phase's end-state — no file, define, list element, frontmatter key or conditional arm exists solely for a later phase (ADR-003); (iv) the frozengithub-status-lines.txtfixture is byte-identical to its Phase-0 capture.Subtasks
scripts/build-mds.ts(:101-104readOutputDir[verified],:114-124stripOutputDirKey[verified],:159-173escape guard + dest pin [verified],IGNORE_DIRS:40-48[verified],DEVFLOW_MDS_ROOTescape hatch:34[verified]) · newsrc/core/mds-variants.ts·src/core/assets.ts(compiledAgentsDir()aftercommandsDir():41-43[verified]; optionalmdsDir()) ·src/targets/claude-code/installer.ts:498-524[verified] ·src/core/agent-models.ts:469-504[verified] · newtests/mds-variants.test.ts· newtests/build-mds-generator-hosts.test.tsmainstripGeneratorFrontmatteraccepts (reproduced verbatim in §7 P1-S4); the 13dist/commands/*.mdSHA-256s recorded before and after S1, confirming they are unchanged; the new allowlist's resolved-path semanticssrc/assets/agents/git.md→src/assets/agents/git.mds(git mv+ generator frontmatter + 142 brace escapes + 9 indented fences)cmp -s dist/agents/git.md tests/fixtures/golden/git-agent.mdexit 0, recorded verbatim; the enumerated list of the 9 indented fences with theirgit.mdsline numbers;grep -c '\\{' dist/agents/git.md== 0; the statement thatsrc/assets/agents/git.mdno longer exists, which is why AC-1.3's src-fallback arm must be tested on an unconverted agenttests/build-mds.test.ts(:67-73,:85-89,:474-482→ name manifests [all verified]) ·tests/packaging.test.ts(:42-95Guard 3 [verified],:213-250Guard 5 reason string,:324-337[verified]) ·tests/core-paths-assets.test.ts:64-79·tests/build.test.ts·tests/git-agent.test.ts/registry-integrity.test.ts/skill-references.test.ts/agent-name-guards.test.ts/agent-frontmatter.test.ts(repoint audit — should be no-ops if Phase 0's resolver did its job) · newtests/guards/dist-agents.test.ts·package.json:9-17[verified] ·CLAUDE.md(:89,:91,:116,:257,:276) · five.devflow/features/*/KNOWLEDGE.md[drift: source §P1.3 says six; §0.7 and P1-S15 enumerate five] ·docs/reference/platform-assumptions.md·CHANGELOG.mdGates
npm run buildexits 0;npm testgreen; the 13dist/commands/*.mdSHA-256s identical to the Phase-0 merge commit (AC-1.5); the five negative build cases (AC-1.7) exit 1 with the exact… is not the expected '…' — typo?message (AC-1.7).npm run build:mdsexits 0 andcmp -s dist/agents/git.md tests/fixtures/golden/git-agent.mdandgrep -c '\\{' dist/agents/git.md== 0. No test may be repointed before this holds.loadShippedDefaults() ⊇ getAllAgentNames()and['git'] === 'haiku'(AC-1.4); registry completeness withgitresolved fromdist/agents(AC-1.6); the build's printed host/partial counts agree with the manifest viaspawnSync(AC-1.8);github-status-lines.txtunchanged (AC-1.11)./implementspawn notesCREATE_PR: false·HANDOFF_REQUIRED: trueCREATE_PR: false·HANDOFF_REQUIRED: trueCREATE_PR: true·HANDOFF_REQUIRED: false(terminal; S3 opens the PR perimplement.mds:409)Commits are pathspec-scoped (
git commit -- <owned paths>) so per-subtask provenance survives the squash-merge (PF-020's validated cheap mitigation). No PR split for Phase 1 (Gate-2 decision D-G) — the phase is one issue, one branch, one PR.Execution strategy
SEQUENTIAL_CODE_AGENTS— 3 subtasks (S1 → S2 → S3). Context risk: CRITICAL.Rationale:
src/assets/agents/git.mdscannot compile untilstripGeneratorFrontmatterand the resolved-path dest allowlist exist inscripts/build-mds.ts. The conversion's only verification is the build, so build changes must land first.Why
PARALLEL_CODE_AGENTSis rejected — the rejection holds and is phase-independent [DR-23]:npm run buildisrm -rf dist && npm run build:cli && npm run build:mds([verifiedpackage.json:20]);/implementhas no worktree isolation — a grep forworktreeinimplement.mdsreturns zero hits;Because every Code agent's verification step deletes the shared
dist/while a sibling is mid-suite, and Phase 0 deliberately makes every dist-scanning guard fail loud on a missing directory (AC-0.16 / §0.1-R3), any concurrent pair manufactures nondeterministic red. That disqualifier is independent of write-set disjointness. [DR-23] additionally records that Phase 1's S-level dependencies are hard, not merely scheduled: S2 cannot compile without S1's build changes, and S3's red states are ambiguous without S2's byte-equality — this is not one of the two weak dependencies DR-23 flags elsewhere in the plan. If per-agent worktrees ever land, Phase 1 is still not a parallelism candidate. This is a tooling limitation, not a plan limitation.PR title
refactor(build): compile the Git agent from an MDS generator hostImplementation Plan
Design artifact (authoritative):
.devflow/docs/design/tracker-phase-1.2026-09-05_1155.md— local and gitignored. A copy truncated at the 60k comment cap is posted as a collapsed comment: #323 (comment). Run with/implement .devflow/docs/design/tracker-phase-1.2026-09-05_1155.md. Tracking issue: #321.