agent-templates 0.4.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.4.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,7 @@ 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) |
155
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) |
156
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) |
157
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) |
@@ -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))