agent-templates 0.3.0 → 0.4.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-templates",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "Catalog of multi-agent development architecture patterns - design write-ups plus drop-in scaffolding (agents, slash commands, workflows, templates).",
5
5
  "license": "MIT",
6
6
  "author": "Horace Hou",
@@ -69,6 +69,7 @@ Figures are transcribed from the team-finalized specification dated 2026-07-17 (
69
69
  | **CRLF workflow scripts rejected on Windows** — the Workflow tool's permission layer refuses scripts containing `\r` ("control characters that would be hidden in the approval dialog"), so `/start-milestone` and `/nightly-issues` cannot launch their workflows when git autocrlf has rewritten the installed `.js` files | `[internal]` — **first field observation**: Ruihang2017/Groundwork, Windows 11, Claude Code, 2026-07-18 (catalog issue #21; workaround used: inline `script` param with LF) | Fixed 2026-07-18: catalog ships `.gitattributes` (`* text=auto eol=lf`), `adopt.mjs` normalizes all text installs to LF regardless of source state, and E2E guards assert no `\r` in runtime files (scaffold + installs + catalog self-host) | 2026-07-18 |
70
70
  | **CRLF regression on target checkouts** — issue #21's install-time LF normalization does not survive the target repo's own git: a later `checkout`/clone with `core.autocrlf=true` re-CRLFs the installed workflow scripts, and `Workflow({name: …})` (including `start-all`'s name-resolved `run-milestone` child) is rejected again for control characters | `[internal]` — recurrence: Ruihang2017/Groundwork, Windows 11, Claude Code, 2026-07-18 (catalog issue #23; workaround used: inline `script` param with LF) | Fixed 2026-07-18: `adopt.mjs` installs/appends a `.gitattributes` in the **target repo** pinning `.claude/workflows/*.js` and `.claude/scripts/*.mjs` to `text eol=lf` (marker-checked, append-once); E2E asserts fresh install, append-to-existing, and idempotent re-run | 2026-07-18 |
71
71
  | **Workflow `args` arrive JSON-stringified** — some harness paths deliver the Workflow tool's `args` as a JSON **string**, so `Object.assign(defaults, args)` merges nothing and launch validation throws in milliseconds (`args.tickets must be a non-empty array`, `args.modules must be a non-empty array`) | `[internal]` — Ruihang2017/Groundwork, Windows 11, Claude Code, 2026-07-18 (catalog issue #23; killed the first `run-milestone` launch in 10ms and would crash `/start-all` identically) | Fixed 2026-07-18: all three workflow scripts (`run-milestone.js`, `start-all.js`, `nightly-issues.js`) parse first — `typeof args === 'string' ? JSON.parse(args) : (args \|\| {})`; E2E runs runner + start-all scenarios with stringified args end-to-end | 2026-07-18 |
72
+ | **Intra-module tickets dispatched out of dependency order** — `milestone-dag.mjs` emitted each module's tickets in ID (filename) order, not topologically by their own `blocked_by` edges; when a module's declared order deviates from ID order, run-milestone dispatched a ticket before the sibling it is blocked_by, the Builder stopped at its plan's precondition gate, and the whole module failed (chain-blocking its dependents) | `[internal]` — Ruihang2017/Groundwork2, autonomous `/start-all`, 2026-07-18 (catalog issue #31; module `05-jobs-fit`, `0502 blocked_by 0503` but ID order put 0502 first) | Fixed 2026-07-19: `milestone-dag.mjs` topologically sorts tickets within each module by intra-module `blocked_by` (cross-module edges stay module-level; ID order only as tiebreak), with an intra-module cycle failing loudly like the module-level one. Same Kahn sort now serves both levels. | 2026-07-19 |
72
73
  | **Harness-specific timeouts/failures** for these exact model+effort combinations | **None recorded yet** (as of 2026-07-17) | When observed: record here with harness name, conditions, and date | — |
73
74
 
74
75
  ## 5. Upstream / downstream integration
@@ -152,6 +153,8 @@ Install steps and usage modes: [scaffold/INSTALL.md](scaffold/INSTALL.md). Front
152
153
  | 2026-07-17 | Gate 1 made concrete: `/start-milestone` = the human start signal → tickets auto-published as tracker issues (`publish-tickets.mjs`, adapted from fx-eye-tracking `create-issues.mjs`; `[<id>]` title prefix as dedupe key; smoke-tested dry-run/no-CLI/usage paths) → deterministic milestone runner (`run-milestone.js` Workflow script: stage order, reviewer freshness, bounce cap, merge policy in code). Added `templates/ticket.template.md` (adapted from fx ticket discipline). Recorded the Bash guard boundary as a known pitfall. Clarified `ultracode`: a session setting (`xhigh` + automatic workflow orchestration), not a model effort level — role efforts unchanged. | Maintainer direction (Horace Hou), 2026-07-17. fx-eye-tracking conventions read the same day (read-only). Workflow tool, `.claude/workflows/`, and `ultracode` semantics verified against live docs (workflows, claude-directory, model-config — record in `scaffold/INSTALL.md`). | Horace Hou (direction) / Claude Fable 5 (write-up) |
153
154
  | 2026-07-18 | **`/start-all` shipped** (catalog issue #20; maintainer-decided semantics: failed module blocks dependents, independent branches continue in `autonomous`, any non-CLEAR stops everything in `supervised`, no cost cap, resume via closed-issue filtering): deterministic DAG script (`milestone-dag.mjs`, ticket `blocked_by` as ground truth, cycles/dangling refs are hard errors) + `start-all` workflow composing `run-milestone` per module + `/start-all` command. 19 new E2E checks (DAG fixtures incl. cycle; module-policy scenarios via stubbed child workflows). Per-ticket stages unchanged. | Maintainer answers on issue #20, 2026-07-18. | Horace Hou (decisions) / Claude Fable 5 (build) |
154
155
  | 2026-07-18 | **First field bug fixed** (catalog issue #21, reported from Ruihang2017/Groundwork through the upstream feedback channel): CRLF-rewritten workflow scripts are rejected by the Workflow tool on Windows. Fix: repo-wide `.gitattributes` (`eol=lf`), working tree renormalized (67 files), `adopt.mjs` installs all text as LF, E2E `\r` guards added. Recorded as the pattern's first true `[internal]` pitfall observation. | Field report (Horace Hou via Groundwork), 2026-07-18. | Horace Hou (report) / Claude Fable 5 (fix) |
156
+ | 2026-07-19 | **Field bug #4 fixed** (catalog issue #31, field report from Ruihang2017/Groundwork2): `milestone-dag.mjs` emitted each module's tickets in ID order instead of topologically by intra-module `blocked_by`, so a module whose declared order deviates from ID order dispatched a ticket before its blocker and failed at the Builder's precondition gate. Fix: a shared Kahn `topoSort` now orders both modules and, within each module, tickets by intra-module `blocked_by` (cross-module edges stay module-level; ID order as tiebreak; intra-module cycle fails loudly). E2E +7 (suite-dag D6 the 0502/0503 inversion, D7 intra-module cycle, D8 ID-order tiebreak). run-milestone dispatch loop unchanged. | Field report (Horace Hou via Groundwork2), 2026-07-18. | Horace Hou (report) / Claude Opus 4.8 (fix) |
157
+ | 2026-07-19 | **Pipeline tool surface explicitly pre-allowed** (catalog issue #30, maintainer direction): scaffold `settings.json` now enumerates allow rules for everything the stages legitimately run — deterministic scripts, git branch/commit/push/read set, `npm test`-family, `gh`/`glab` issue list/view/comment/edit|update|note/close/create — so a fully autonomous `/start-all` → deliver → nightly cycle triggers zero interactive approvals. Deliberately not pre-allowed (role discipline stays mechanical): `git merge`/`rebase`/`reset`/`clean`, `gh pr *`, and bare `git:*`/`gh:*`/`glab:*` wildcards — E2E asserts both directions so drift fails the gate. Risk accepted and recorded: `git push:*` includes force variants; `gh issue create:*` is broader than the publish-tickets discipline (nightly report issue needs it); prefix-deny of flags is structurally incomplete so not attempted. | Maintainer direction (Horace Hou), 2026-07-19. | Horace Hou (direction) / Claude Fable 5 (build) |
155
158
  | 2026-07-19 | **Delivery made deterministic** (catalog issue #26, field report: harness safety classifiers blocked the agent-run deliver stage 3/3 after journaled CLEARs): new `.claude/scripts/deliver-ticket.mjs` — clean-tree guard, `--no-ff` merge (idempotent on re-runs, conflicts abort clean), push, tracker close with post-close verification (`--issue` or `[<id>]` title-prefix lookup), deterministic DoD, `DELIVER-SUMMARY-JSON` contract; run-milestone's deliver agent reduced to executing that one command and relaying its summary; `settings.json` gained explicit allow rules for the three deterministic scripts. E2E: new suite-deliver (12 scenarios on real temp git repos + fake CLIs). The tracker close only happens after merge AND push actually landed — a closed issue is what resume filtering treats as delivered, so closing on a failed delivery would silently drop the ticket. One DoD item relocated: the post-merge test run executes deterministically when `testCmd` is supplied (workflow arg, forwarded as `--test-cmd`; `/start-all` passes it through) and otherwise stays with `/verify-delivery` — builder and reviewer both already ran tests on the branch. Per-ticket stages before deliver, and the model/effort table, unchanged. | Field report (Horace Hou via Groundwork), 2026-07-18; fix direction proposed in the issue itself. | Horace Hou (report) / Claude Fable 5 (fix) |
156
159
  | 2026-07-19 | **Field bug #3 fixed** (catalog issue #27, reported from Ruihang2017/Groundwork2): `/start-all` step 3 never stated that `modules[].tickets` elements must be `{id, path, issue}` objects joined from two sources (DAG plan order + per-module `PUBLISH-SUMMARY-JSON`) — the DAG JSON alone emits bare id strings, which run-milestone's validator rejects. Command doc now names the exact shape and the join; `/start-milestone` already documented it. (The issue's other defect — stringified Workflow `args` — was already fixed under #23 / v0.2.1.) | Field report (Horace Hou via Groundwork2), 2026-07-18. | Horace Hou (report) / Claude Fable 5 (fix) |
157
160
  | 2026-07-18 | **Field bug #2 fixed** (catalog issue #23, same reporter channel): (a) #21's install-time LF fix did not survive target-side git checkouts — `adopt.mjs` now installs/appends a target-repo `.gitattributes` pinning `.claude/workflows/*.js` + `.claude/scripts/*.mjs` to `eol=lf` (marker-checked, append-once); (b) Workflow `args` can arrive JSON-stringified — all three workflow scripts gained the `typeof args === 'string' ? JSON.parse(args) : (args \|\| {})` shim. Both recorded as §4 pitfalls; E2E extended (stringified-args runner + start-all scenarios; `.gitattributes` install/append/idempotency). Per-ticket stages and model/effort table unchanged. | Field report (Horace Hou via Groundwork), 2026-07-18. | Horace Hou (report) / Claude Fable 5 (fix) |
@@ -69,18 +69,45 @@ if (errors.length) {
69
69
  process.exit(1)
70
70
  }
71
71
 
72
- // Kahn topological sort; deterministic tiebreak by module name (numeric prefixes sort naturally)
73
- const order = []
74
- const remaining = new Set(Object.keys(modules))
75
- while (remaining.size) {
76
- const ready = [...remaining].filter((m) => [...modules[m].dependsOn].every((d) => !remaining.has(d))).sort()
77
- if (!ready.length) {
78
- console.error(`x dependency cycle among: ${[...remaining].sort().join(', ')}`)
72
+ // Kahn topological sort over `nodes`; `depsOf(n)` returns the nodes that must come
73
+ // before n (deps outside `nodes` are ignored by the caller). Deterministic tiebreak
74
+ // by string order — module names and ticket ids both sort with numeric prefixes
75
+ // naturally. Returns { order } or { cycle } (the nodes left when nothing is ready).
76
+ const topoSort = (nodes, depsOf) => {
77
+ const remaining = new Set(nodes)
78
+ const order = []
79
+ while (remaining.size) {
80
+ const ready = [...remaining].filter((n) => depsOf(n).every((d) => !remaining.has(d))).sort()
81
+ if (!ready.length) return { cycle: [...remaining].sort() }
82
+ order.push(ready[0])
83
+ remaining.delete(ready[0])
84
+ }
85
+ return { order }
86
+ }
87
+
88
+ // module order: a module depends on another via cross-module blocked_by edges
89
+ const modSort = topoSort(Object.keys(modules), (m) => [...modules[m].dependsOn])
90
+ if (modSort.cycle) {
91
+ console.error(`x dependency cycle among: ${modSort.cycle.join(', ')}`)
92
+ process.exit(1)
93
+ }
94
+ const order = modSort.order
95
+
96
+ // tickets WITHIN a module: order by intra-module blocked_by edges (cross-module edges
97
+ // are already satisfied by module ordering above), ID order only as tiebreak. Emitting
98
+ // bare ID order here dispatches a ticket before a sibling it is blocked_by whenever the
99
+ // declared order deviates from ID order — the run-milestone builder then stops at its
100
+ // precondition gate and the whole module fails (catalog issue #31).
101
+ const ticketOrder = {}
102
+ for (const m of order) {
103
+ const ids = new Set(modules[m].tickets.map((t) => t.id))
104
+ const blockedByOf = Object.fromEntries(modules[m].tickets.map((t) => [t.id, t.blockedBy.filter((d) => ids.has(d))]))
105
+ const sorted = topoSort([...ids], (id) => blockedByOf[id])
106
+ if (sorted.cycle) {
107
+ console.error(`x intra-module dependency cycle in ${m} among: ${sorted.cycle.join(', ')}`)
79
108
  process.exit(1)
80
109
  }
81
- const next = ready[0]
82
- order.push(next)
83
- remaining.delete(next)
110
+ ticketOrder[m] = sorted.order
84
111
  }
85
112
 
86
113
  for (const m of order) {
@@ -89,6 +116,6 @@ for (const m of order) {
89
116
  }
90
117
  const json = {
91
118
  order,
92
- modules: Object.fromEntries(order.map((m) => [m, { tickets: modules[m].tickets.map((t) => t.id), dependsOn: [...modules[m].dependsOn].sort() }])),
119
+ modules: Object.fromEntries(order.map((m) => [m, { tickets: ticketOrder[m], dependsOn: [...modules[m].dependsOn].sort() }])),
93
120
  }
94
121
  console.log('DAG-JSON: ' + JSON.stringify(json))
@@ -3,7 +3,43 @@
3
3
  "allow": [
4
4
  "Bash(node .claude/scripts/milestone-dag.mjs:*)",
5
5
  "Bash(node .claude/scripts/publish-tickets.mjs:*)",
6
- "Bash(node .claude/scripts/deliver-ticket.mjs:*)"
6
+ "Bash(node .claude/scripts/deliver-ticket.mjs:*)",
7
+ "Bash(git status:*)",
8
+ "Bash(git log:*)",
9
+ "Bash(git diff:*)",
10
+ "Bash(git show:*)",
11
+ "Bash(git branch:*)",
12
+ "Bash(git checkout:*)",
13
+ "Bash(git switch:*)",
14
+ "Bash(git restore:*)",
15
+ "Bash(git add:*)",
16
+ "Bash(git rm:*)",
17
+ "Bash(git mv:*)",
18
+ "Bash(git commit:*)",
19
+ "Bash(git push:*)",
20
+ "Bash(git fetch:*)",
21
+ "Bash(git pull:*)",
22
+ "Bash(git stash:*)",
23
+ "Bash(git rev-parse:*)",
24
+ "Bash(git remote get-url:*)",
25
+ "Bash(git merge-base:*)",
26
+ "Bash(npm test:*)",
27
+ "Bash(npm run test:*)",
28
+ "Bash(node --test:*)",
29
+ "Bash(gh auth status)",
30
+ "Bash(gh issue list:*)",
31
+ "Bash(gh issue view:*)",
32
+ "Bash(gh issue comment:*)",
33
+ "Bash(gh issue edit:*)",
34
+ "Bash(gh issue close:*)",
35
+ "Bash(gh issue create:*)",
36
+ "Bash(glab auth status)",
37
+ "Bash(glab issue list:*)",
38
+ "Bash(glab issue view:*)",
39
+ "Bash(glab issue note:*)",
40
+ "Bash(glab issue update:*)",
41
+ "Bash(glab issue close:*)",
42
+ "Bash(glab issue create:*)"
7
43
  ]
8
44
  },
9
45
  "hooks": {
@@ -11,7 +11,7 @@ From a checkout of the catalog: `node scripts/adopt.mjs three-agent-architect-bu
11
11
  1. Copy `.claude/` from this scaffold into the target repo root. If the target already has `.claude/settings.json`, merge the `hooks.PreToolUse` entry and the `permissions.allow` list instead of overwriting.
12
12
  2. Install the catalog's **universal templates** (shared by all patterns — source of truth is the catalog root, not this scaffold): `templates/ticket.template.md` → the target repo's `templates/`; the platform half of `templates/tracker/` → `.github/` (ISSUE_TEMPLATE/ + PULL_REQUEST_TEMPLATE.md) or `.gitlab/` (issue_templates/ + merge_request_templates/). Then fill the PR/MR template's **Constraint check** section with the target repo's CLAUDE.md non-negotiables. Hand-written issues and pipeline PRs now share one format that triage can convert and reviewers can verify.
13
13
  3. The write-guard hook needs Node.js ≥ 18 on PATH. It denies main-session Edit/Write with a dispatch instruction; subagent writes pass. Override switch for human-approved out-of-pipeline edits: create `.claude/allow-main-writes`, delete it afterwards — and add that path to `.gitignore`.
14
- 4. The tracker steps (`publish-tickets.mjs`, `deliver-ticket.mjs`, `/verify-delivery`, the nightly sweep) need the platform CLI installed and authenticated: `gh` (GitHub) or `glab` (GitLab). The publish script autodetects the platform from the origin remote; override with `--platform gh|glab` (test doubles / non-PATH binaries: `GH_BIN` / `GLAB_BIN` env overrides). Delivery (merge `--no-ff` + push + verified issue close + deterministic DoD) is `deliver-ticket.mjs` — never an agent improvising git/tracker writes; `settings.json` carries explicit allow rules for the three deterministic scripts so unattended runs do not stall waiting for interactive approval (catalog issue #26).
14
+ 4. The tracker steps (`publish-tickets.mjs`, `deliver-ticket.mjs`, `/verify-delivery`, the nightly sweep) need the platform CLI installed and authenticated: `gh` (GitHub) or `glab` (GitLab). The publish script autodetects the platform from the origin remote; override with `--platform gh|glab` (test doubles / non-PATH binaries: `GH_BIN` / `GLAB_BIN` env overrides). Delivery (merge `--no-ff` + push + verified issue close + deterministic DoD) is `deliver-ticket.mjs` — never an agent improvising git/tracker writes; `settings.json` carries explicit allow rules for the pipeline's whole tool surface (the three deterministic scripts, the enumerated git branch/commit/push set, `npm test`-family test commands, and the enumerated `gh`/`glab` issue commands) so unattended runs do not stall waiting for interactive approval (catalog issues #26, #30). Deliberately NOT pre-allowed: `git merge` / `rebase` / `reset` / `clean` and `gh pr *` — merging belongs to `deliver-ticket.mjs`. If your project's test command is not `npm test` / `npm run test` / `node --test`, add one more allow rule for it (e.g. `Bash(pytest:*)`).
15
15
  5. Append the content of `claude-md-snippet.md` to the target repo's `CLAUDE.md`, and set the **Operating mode** line (`supervised` for a fresh adoption; `autonomous` is the target).
16
16
  6. Ensure the docs layout the pipeline assumes exists: `docs/PRD.md`, `docs/prd/<module>/README.md` (the sub-PRD — `/start-milestone` hard-requires it), `docs/prd/<module>/tickets/` (author tickets from `templates/ticket.template.md`), `docs/adr/`, and an empty `docs/plans/`.
17
17
  7. Check the pattern entry's expiry (README metadata table). If expired, re-verify the model/effort table against current official docs before adopting — do not copy an expired recommendation into a new project.
@@ -25,7 +25,7 @@ From a checkout of the catalog: `node scripts/adopt.mjs three-agent-architect-bu
25
25
  ## Nightly sweep (unattended)
26
26
 
27
27
  - **Entry:** `claude -p "/nightly-issues"` — slash commands expand in headless `-p` mode. `[official]`
28
- - **Permissions:** pre-approve exactly what the pipeline needs in the target repo's `.claude/settings.json` (`permissions.allow`, e.g. `Bash(git:*)`, `Bash(gh:*)` or `Bash(glab:*)`, `Bash(node:*)`, `Bash(npm:*)`), then run with `--permission-mode dontAsk` — the documented CI recommendation: pre-approved tools run, everything else is auto-denied instead of blocking. Subagents run in `acceptEdits` mode (their file edits are auto-approved). Avoid `bypassPermissions` outside isolated containers (documented warning). `[official]`
28
+ - **Permissions:** the scaffold's `settings.json` already enumerates the pipeline's whole tool surface in `permissions.allow` (see step 4 — deterministic scripts, git branch/commit/push set, test commands, `gh`/`glab` issue commands; catalog issue #30). Do NOT widen it to bare wildcards like `Bash(git:*)` or `Bash(gh:*)` that would re-allow the role-discipline-forbidden surface (`git merge`, `gh pr …`) the enumeration deliberately excludes. Add only your project-specific test-command rule, then run with `--permission-mode dontAsk` — the documented CI recommendation: pre-approved tools run, everything else is auto-denied instead of blocking. Subagents run in `acceptEdits` mode (their file edits are auto-approved). Avoid `bypassPermissions` outside isolated containers (documented warning). `[official]`
29
29
  - **Scheduling (Windows, primary):** Task Scheduler — runs whenever the machine is on at the trigger time:
30
30
 
31
31
  ```