@appchy/jarvis 0.1.37 → 0.1.39

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.
Files changed (108) hide show
  1. package/bin/config-change.mjs +1 -1
  2. package/bin/jarvis.mjs +8 -12
  3. package/bin/pre-tool-use.mjs +2 -2
  4. package/bin/session-start.mjs +1 -1
  5. package/bin/stop.mjs +1 -1
  6. package/bin/user-prompt-submit.mjs +1 -1
  7. package/dist/bin.js +10168 -37341
  8. package/dist/bin.js.map +1 -1
  9. package/dist/data/backends.mjs +469 -0
  10. package/dist/data/chunk-7REP35VA.mjs +462 -0
  11. package/dist/data/chunk-AKQQC5IT.mjs +1224 -0
  12. package/dist/data/chunk-AYOJSS2F.mjs +72 -0
  13. package/dist/data/chunk-RRJ6KKYL.mjs +42 -0
  14. package/dist/data/chunk-YWSWQEJN.mjs +138 -0
  15. package/dist/data/embedders.mjs +80 -0
  16. package/dist/data/finders.mjs +35 -0
  17. package/dist/data/index.mjs +137 -0
  18. package/dist/data/linkers.mjs +83 -0
  19. package/dist/data/mcp.mjs +2624 -0
  20. package/dist/data/persistences.mjs +8 -0
  21. package/dist/data/rerankers.mjs +52 -0
  22. package/dist/data/stores.mjs +38 -0
  23. package/dist/hooks/config-change.js +7 -29
  24. package/dist/hooks/config-change.js.map +1 -1
  25. package/dist/hooks/pre-tool-use.js +129 -32
  26. package/dist/hooks/pre-tool-use.js.map +1 -1
  27. package/dist/hooks/session-start.js +72 -37
  28. package/dist/hooks/session-start.js.map +1 -1
  29. package/dist/hooks/stop.js +140 -32
  30. package/dist/hooks/stop.js.map +1 -1
  31. package/dist/hooks/user-prompt-submit.js +7 -29
  32. package/dist/hooks/user-prompt-submit.js.map +1 -1
  33. package/harness/assets/architecture-template.md +53 -0
  34. package/harness/assets/design-template.md +89 -0
  35. package/harness/assets/domains/architecture.md +43 -0
  36. package/harness/assets/domains/commercial.md +42 -0
  37. package/harness/assets/domains/design.md +42 -0
  38. package/harness/assets/domains/legal.md +43 -0
  39. package/harness/assets/domains/operations.md +39 -0
  40. package/harness/assets/domains/product.md +43 -0
  41. package/harness/assets/domains/quality.md +43 -0
  42. package/harness/assets/domains/security.md +44 -0
  43. package/harness/assets/domains/support.md +45 -0
  44. package/harness/assets/epic-template.md +85 -0
  45. package/harness/assets/feature-template.md +86 -0
  46. package/harness/assets/handoff-template.md +26 -0
  47. package/harness/assets/task-template.md +38 -0
  48. package/harness/assets/version-template.md +43 -0
  49. package/harness/harness/__init__.py +7 -0
  50. package/harness/harness/align.py +582 -0
  51. package/harness/harness/architecture.py +254 -0
  52. package/harness/harness/autonomy.py +374 -0
  53. package/harness/harness/branches.py +408 -0
  54. package/harness/harness/config.py +1482 -0
  55. package/harness/harness/coverage.py +199 -0
  56. package/harness/harness/epic.py +220 -0
  57. package/harness/harness/events.py +153 -0
  58. package/harness/harness/extend.py +99 -0
  59. package/harness/harness/frontmatter.py +218 -0
  60. package/harness/harness/gate.py +591 -0
  61. package/harness/harness/generate.py +267 -0
  62. package/harness/harness/git.py +775 -0
  63. package/harness/harness/ids.py +140 -0
  64. package/harness/harness/kickoff.py +231 -0
  65. package/harness/harness/lint.py +505 -0
  66. package/harness/harness/model.py +364 -0
  67. package/harness/harness/peers.py +187 -0
  68. package/harness/harness/product.py +29 -0
  69. package/harness/harness/registry.py +382 -0
  70. package/harness/harness/report.py +227 -0
  71. package/harness/harness/safety.py +387 -0
  72. package/harness/harness/scaffold.py +129 -0
  73. package/harness/harness/shard.py +63 -0
  74. package/harness/harness/shift.py +348 -0
  75. package/harness/harness/task.py +507 -0
  76. package/harness/harness/tree.py +258 -0
  77. package/harness/harness/version.py +305 -0
  78. package/harness/harness/wrap.py +217 -0
  79. package/harness/hooks/guard.py +259 -0
  80. package/harness/presets/appchy/PRESET.md +717 -0
  81. package/harness/presets/appchy/references/artifacts.md +539 -0
  82. package/harness/presets/appchy/references/graph.md +154 -0
  83. package/harness/presets/appchy/references/operations.md +444 -0
  84. package/harness/presets/appchy/references/research.md +216 -0
  85. package/harness/schema/work.config.schema.json +401 -0
  86. package/harness/test_work.py +5002 -0
  87. package/harness/work.py +534 -0
  88. package/package.json +34 -40
  89. package/bin/config-change.dev.mjs +0 -17
  90. package/bin/jarvis-dev.mjs +0 -30
  91. package/bin/pre-tool-use.dev.mjs +0 -23
  92. package/bin/session-start.dev.mjs +0 -17
  93. package/bin/stop.dev.mjs +0 -17
  94. package/bin/user-prompt-submit.dev.mjs +0 -17
  95. package/dev/bin.js +0 -38821
  96. package/dev/bin.js.map +0 -1
  97. package/dev/env.json +0 -1
  98. package/dev/hooks/config-change.js +0 -110
  99. package/dev/hooks/config-change.js.map +0 -1
  100. package/dev/hooks/pre-tool-use.js +0 -120
  101. package/dev/hooks/pre-tool-use.js.map +0 -1
  102. package/dev/hooks/session-start.js +0 -115
  103. package/dev/hooks/session-start.js.map +0 -1
  104. package/dev/hooks/stop.js +0 -112
  105. package/dev/hooks/stop.js.map +0 -1
  106. package/dev/hooks/user-prompt-submit.js +0 -111
  107. package/dev/hooks/user-prompt-submit.js.map +0 -1
  108. package/dist/env.json +0 -1
@@ -0,0 +1,539 @@
1
+ # Artifacts — file format specs
2
+
3
+ The on-demand reference for every file this skill scaffolds, reads or
4
+ maintains. Load this when writing or editing a `task.md`, `epic.md`,
5
+ `handoff.md`, `plan.md`, a domain's hosted rules, `version.md`, `<feature>.md`,
6
+ `design.md` or `architecture.md`.
7
+
8
+ `SKILL.md` carries the workflow + the ownership rules; this file carries the
9
+ contracts. Keep both in sync with the templates under `assets/`.
10
+
11
+ ## Conventions
12
+
13
+ - Frontmatter is YAML between `---` fences.
14
+ - File-level title is `# Title` on the first body line.
15
+ - Names (task, epic and version) are kebab-case and globally unique across all three.
16
+ - Dates are `YYYY-MM-DD` (today's, when the file is created or updated).
17
+ - Files marked **scaffolded** are written by `work.py` from `assets/`
18
+ templates. Everything else is created by hand — only when the state needs
19
+ it, never pre-emptively.
20
+
21
+ ## `task.md` — the brief (the only file that survives archive)
22
+
23
+ The single source of truth for a task's scope. **There is no length cap** (the
24
+ old ≤30 was removed 2026-08-02): a brief is read by a session starting cold, so
25
+ front-load the hard reasoning, the dead ends and the big-picture traps rather
26
+ than making it re-derive them. What must NOT appear is a competing plan — the
27
+ design is settled once, in `epic.md` §Plan, and a `plan.md` in a queue folder is
28
+ still a lint. Length was never the failure; a second design doc is.
29
+
30
+ ```yaml
31
+ ---
32
+ priority: P1 # P0 now · P1 next · P2 later
33
+ depends_on: [other-task-name]
34
+ tags: [engine] # optional — area tags; the vocabulary is `tags.allowed` in config
35
+ owner: lesson-flow # a bare <feature> or org-domain — expected on every task (lint)
36
+ code: [renderer, compose] # optional, multi-valued — durable code-locality, see below
37
+ covers: [AC-01, AC-02] # optional, multi-valued — the feature's AC ids this task satisfies
38
+ start: 2026-08-01 # optional — YYYY-MM-DD
39
+ end: 2026-08-10 # optional — YYYY-MM-DD, must be >= start
40
+ created: 2026-05-22
41
+ updated: 2026-05-22
42
+ sessions: # added by work.py — never by hand
43
+ - 2026-05-22 <session-id>
44
+ plans: # added by `work.py plan` — pointers to native-mode plans
45
+ - 2026-05-22 <plans.dir>/<slug>.md
46
+ completed: 2026-05-22 # added by `work.py move … complete`, absent otherwise
47
+ ---
48
+ ```
49
+
50
+ Recognised keys: `priority`, `depends_on`, `tags`, `product`, `code`,
51
+ `covers`, `start`, `end`, `created`, `updated`, `sessions`, `plans`,
52
+ `completed`. `sessions:`, `plans:` and `completed:` are written by `work.py`
53
+ — leave them alone.
54
+
55
+ `owner: <feature>` or `owner: <domain>` bridges an engineering task to
56
+ the product layer — the sole owner of the task↔feature link (see the
57
+ Ownership table in `SKILL.md`). **There is no app tier** while `product.tiers` is
58
+ `flat`: the repo is ONE product,
59
+ so a feature name is globally unique and `product/<feature>.md` is its
60
+ whole address. Set it with `work.py new --owner
61
+ <feature>|<domain>` or by hand; format-checked (kebab segments) but never
62
+ existence-checked at write time — a stale or not-yet-scaffolded reference
63
+ surfaces as a `work.py list` lint warning instead of a refusal. **Every task
64
+ is expected to carry one** — a task with no `owner:` also surfaces as
65
+ a lint warning. No reciprocal `tasks:` list on the feature side — that
66
+ link is always a query over this field, never hand-maintained on the other
67
+ end.
68
+
69
+ **A bare `owner: <domain>`** — `operations`, `quality`, `harness`… — is how a
70
+ task with **no user-facing feature** links: the harness itself, the docs tooling,
71
+ CI, the deploy pipeline. It satisfies the link requirement without inventing a
72
+ fake feature, and it **retired the old `product: infra` sentinel**, which modelled
73
+ infrastructure as an app so the lint would pass. Infrastructure is a domain
74
+ (`work/operations/`), not an app. Product-building tasks still take a real
75
+ `<feature>`.
76
+
77
+ `code: [<region>, …]` (optional, multi-valued) — a durable,
78
+ cross-version code-locality tag, ORTHOGONAL to `owner` (code-locality ≠
79
+ behaviour). The vocabulary is **derived**: a region is valid because some
80
+ `work/architecture/<system>.md` declares it in its `code:`. There is no
81
+ hand-curated list to keep in sync — `work.py new --code a,b` dies on a region no
82
+ system owns. Query every task touching a region with `work.py code <region>`,
83
+ and the rules it drags in with `work.py rules --task <name>`.
84
+
85
+ `covers: [AC-nn, …]` (optional, multi-valued) — which of the linked
86
+ feature's `AC-nn` acceptance criteria this task satisfies. Set via `work.py
87
+ new --covers AC-01,AC-02`; format-checked at write time (`AC-\d+`), and
88
+ existence-checked (does that AC actually exist in the linked `<feature>.md`) as
89
+ a `work.py list` lint warning. A feature's coverage — which `AC-nn` are
90
+ covered by a COMPLETED task's `covers:` — rolls up automatically; a `shipped`
91
+ feature with an uncovered AC is a lint warning.
92
+
93
+ `start` / `end` (optional, `YYYY-MM-DD`) — a task-level date window. Set
94
+ via `work.py new --start/--end`; validated as dates, and `start <= end` when
95
+ both are present.
96
+
97
+ Body sections, in order:
98
+
99
+ 1. `# Title` — kebab-derived human title.
100
+ 2. **Problem** — what's wrong / what's needed. One or two paragraphs;
101
+ enough to start cold.
102
+ 3. **Context & findings** — investigation notes (root cause, `path:line`
103
+ refs, what was ruled out). Empty until investigated.
104
+ 4. **Approach** — fill in *only once agreed*, and **omit the heading until
105
+ then**. Once the goal is planned this collapses to one line —
106
+ `Approach → epic.md` (or `→ plan.md` in the rare task-local case) — so the
107
+ architecture has a single owner.
108
+ 5. **Acceptance criteria** — checkable outcomes (`- [ ] …`), one concrete
109
+ line each. These are the task's intent in checkable form; tests trace
110
+ back to them via a `covers()` call or a Playwright tag — never a comment.
111
+ 6. **Open questions** — unknowns to resolve at pick-up.
112
+
113
+ There is no "Plans & analysis" section and no task-level `stories.md`: the
114
+ design lives in `epic.md` §Plan, written once for the goal; live status is the
115
+ task's bucket.
116
+
117
+ Scaffolded by `work.py new <name>`. Template:
118
+ [`../assets/task-template.md`](../assets/task-template.md).
119
+
120
+ ## `handoff.md` — the CROSS-CONVERSATION continuity file (not a per-session journal)
121
+
122
+ Write/refresh this **only when you hand the task to a fresh conversation** —
123
+ you're wrapping up, or the user asks to continue elsewhere. **You do NOT touch
124
+ it while actively working the task in one conversation**; a task can complete
125
+ within a single session having never had a filled handoff. `work.py move …
126
+ in-progress` scaffolds the template so it's ready, but an empty/untouched
127
+ scaffold mid-work is fine. When you do write it, it's the one file the next
128
+ session reads to know *where things stand*. **Hard cap 80 lines** —
129
+ prune-on-absorb when over (move durable facts to `plan.md` / the owning domain,
130
+ drop the oldest log entries).
131
+
132
+ ```
133
+ # handoff — <task>
134
+
135
+ **Status:** <one line: where the task is right now>
136
+ **NEXT:** <one line: the single next action to take>
137
+
138
+ ## Read order
139
+ <the files a cold session reads, in order — e.g. task.md → plan.md → the governing rules>
140
+
141
+ ## Log
142
+ - 2026-06-12 <what happened this session, ≤3 lines, latest first>
143
+ - 2026-06-11 <older entry>
144
+
145
+ ## Decisions
146
+ - <id>: <title> # promoted to the owning domain — pointer only
147
+ - <small, task-local decision that didn't earn a D-number>
148
+ ```
149
+
150
+ Rules:
151
+
152
+ - `**Status:**` and `**NEXT:**` capture the in-flight snapshot *for the next
153
+ conversation*; they're written at handoff, never duplicated into `task.md`,
154
+ `plan.md` or `version.md`. The always-true live status is the task's bucket.
155
+ - `## Log` is dated and **latest-first**; the top line is always the freshest
156
+ truth. Pruning removes from the bottom.
157
+ - `## Decisions` holds small task-local calls as bullets (only worth recording
158
+ if you're handing off). A durable one goes to the domain that owns it and is
159
+ reduced here to `<id>: <title>`.
160
+
161
+ Scaffolded by `work.py move … in-progress` / `work.py handoff <name>`.
162
+ Template: [`../assets/handoff-template.md`](../assets/handoff-template.md).
163
+
164
+ ## `plan.md` — the EXCEPTION, not the norm (task-level, in-progress only)
165
+
166
+ **The design lives in `epic.md` §Plan**, written once for the whole goal. A task
167
+ gets a `plan.md` only when pickup surfaces a call that document did not settle —
168
+ and that is a **gap in the epic plan**, so the usual fix is to settle it *there*
169
+ and let every sibling inherit it. `work.py list` warns when a task inside an epic
170
+ carries one. Keep it only for a call genuinely nobody else needs.
171
+
172
+ (Everything below is the format for that case, and for a task in a
173
+ grandfathered flat version that has no epic.) One living file, written **at
174
+ pickup, never in the queue**, and the **sole owner** of whatever design it
175
+ does hold. Plan mode is a *drafting tool*, not a storage location: its plan lives
176
+ in the conversation and is discarded once settled — the durable design (the
177
+ *why-this-shape*, which has no other home) is what lands in `plan.md`. The older
178
+ `work.py plan` → the `plans:` pointer into `plans.dir` is at most an
179
+ **archival snapshot** of a native-mode plan (useful for the D172 web/cowork
180
+ handoff), never a second source of truth: if `plan.md` exists, it wins.
181
+
182
+ **Decision-complete before you build.** No *decision* is ever handed to a subagent —
183
+ the brain decides, and a delegate only types out edits already settled to the exact
184
+ string (SKILL.md §Model routing) — so the reader of this plan is the session that
185
+ picks the task up, possibly days later with none of today's context.
186
+ Before it is a plan:
187
+ - **Resolve every open question** with the founder first. A plan with an
188
+ unresolved fork is NOT ready — settle it, don't carry it forward.
189
+ - **Make every input explicit** so nothing has to be inferred twice: the exact
190
+ files / `path:line` to touch, the rule ids / `<feature>.md` requirements to honour,
191
+ the edge cases + failure behaviour, data shapes, and the `AC-nn` it satisfies.
192
+ - If a reader would have to ask *"how should this work?"*, the plan is
193
+ incomplete — finish that thinking here.
194
+
195
+ The test is the same one the founder call rests on: work that would *surface*
196
+ decisions while being built (an unproven approach, runtime-only correctness,
197
+ intricate logic) is not settled, however complete the plan looks.
198
+
199
+ ```
200
+ # plan — <task>
201
+
202
+ ## As-found (≤40 lines)
203
+ <raw, factual account of how the in-scope code works today — no opinions.
204
+ This replaces the old state.md; it lives here, beside the architecture it informs.>
205
+
206
+ ## Architecture (≤80 lines)
207
+ ┌─ diagram ─┐ …rationale… …pseudo-code for the load-bearing pieces…
208
+ └───────────┘
209
+
210
+ ## Build
211
+ <steps / phases / prose — whatever fits. Anchor-link what each step
212
+ implements ([→ Architecture §…], [wireframes/ui.md → Mixer]).>
213
+
214
+ ## Completion
215
+ <acceptance criteria met · hygiene clean · tests green>
216
+ ```
217
+
218
+ - **`## As-found`** — the as-found baseline (former `state.md`). Kept live
219
+ for the task's footprint: extend as scope grows; don't rewrite an entry as
220
+ the code changes.
221
+ - **`## Architecture`** — lead with a diagram, then rationale (*why* this
222
+ shape, alternatives weighed), then pseudo-code for the load-bearing pieces.
223
+ For UI work keep this to the *technical* shape and anchor-link
224
+ `wireframes/ui.md` for what the user sees. Link code paths; never paste code.
225
+ - **`## Build`** — lay it out however's clearest. The only hard rule is at
226
+ the task level: when it lands the repo is green and integrated;
227
+ intermediate states are not separately shippable.
228
+
229
+ Only create `plan.md` when the task genuinely needs a design — a one-line fix
230
+ doesn't. Refactor-natured work is its own commit, kept separate from feature/fix
231
+ work.
232
+
233
+ ## Hosted rules — `architecture/<system>.md` and the org-domain READMEs
234
+
235
+ A lightweight ADR ledger — **only** the business / product / high-level
236
+ architecture decisions that set lasting direction and must not regress.
237
+ Not a log of plan-level choices (those live in code + git history), and
238
+ never a duplicate of current operating truth (that's the files `spine.standards`
239
+ and `spine.conventions` name, and the code).
240
+
241
+ Shape: an `## Index` of one-line titles up top (scannable without reading
242
+ the body), then entries grouped by area (`## Direction` / `## Architecture`
243
+ / `## Engine model` / `## Agent & editing` / `## Product & UX` /
244
+ `## Decided, not built`).
245
+
246
+ ```
247
+ ### <id> — <the rule, in one line>
248
+ The engine core stays a vector IR; glTF-export and Three.js-preview are
249
+ additive backends, not the render pipeline. Why: keeps assets portable and
250
+ the core small. Supersedes: <id>.
251
+ ```
252
+
253
+ Rules:
254
+
255
+ - **Significance gate.** Add an entry only when a decision sets lasting
256
+ direction and isn't self-evident from the code. "Would a future session
257
+ regress this without the entry?" — if no, don't add it.
258
+ - **Append-only, immutable.** A change of mind is a NEW entry marking the
259
+ old one `Superseded by <id>` — never edit history.
260
+ - **2–6 lines per entry**: the decision + the why (+ `Supersedes:`). Keep
261
+ the index line in sync.
262
+ - This is the only file others deep-link for rationale — cite the id,
263
+ never restate.
264
+
265
+ ## `version.md` — the RELEASE record
266
+
267
+ One per version, scaffolded by `work.py version-new`. **A version is a release**
268
+ and `version-new` enforces both halves of that: it **refuses without
269
+ `--outcome`**, and it **refuses while any earlier version is still unreleased**.
270
+ If you cannot state the outcome, the work is an epic until you can.
271
+
272
+ ```yaml
273
+ ---
274
+ created: 2026-05-22
275
+ updated: 2026-05-22
276
+ order: 10 # roadmap sort order — optional; see derivation below
277
+ outcome: a teacher can publish a lesson under their own name # REQUIRED
278
+ start: 2026-06-01 # optional — YYYY-MM-DD
279
+ end: 2026-06-30 # optional — YYYY-MM-DD, must be >= start
280
+ target: 2026-06-30 # optional; line absent when no target
281
+ released: 2026-06-30 # absent until `work.py release`
282
+ archived: 2026-07-02 # absent until `work.py archive`
283
+ ---
284
+ ```
285
+
286
+ `outcome` (**required**) — ONE line, in user terms, saying what someone can newly
287
+ **do** when this ships. Not a task summary and not a component list. It is
288
+ printed by `list` and by `release`, rendered into the README table, and lint-
289
+ checked on every mutation. The honest one is better than the flattering one:
290
+ `16-mcp-package`'s reads *"nothing user-visible — a refactor released as a
291
+ version, the exact shape the release gate now refuses"*, which is precisely why
292
+ the gate exists.
293
+
294
+ `order` (optional, int) — the roadmap's legible sort key, read at every
295
+ site that lists versions (`list`, the README table, `code`). Set via
296
+ `work.py version-new --order N`; derived when absent: an explicit `order:`
297
+ frontmatter value wins, else a leading numeric prefix on the version's own
298
+ name (`80-scene-generator` → 0, `100-poc-map` → 3), else `9999` (unordered
299
+ versions sort last, never breaking the roadmap). A name with a numeric prefix
300
+ and an explicit `--order` that disagree is refused at scaffold time.
301
+
302
+ `start` / `end` (optional, `YYYY-MM-DD`) — a version-level date window
303
+ for the roadmap timeline. Set via `work.py version-new --start/--end`;
304
+ validated as dates, and `start <= end` when both are given. Distinct from
305
+ `target` (the release-date estimate) and `released` (the actual ship date).
306
+
307
+ Body: `# Title` · **Goal** (the capability in user terms — expands `outcome:`,
308
+ never contradicts it) · **Scope** (narrative reasoning for why these epics ship
309
+ together — the live task list is the README table, don't mirror it) · **Release
310
+ notes** (finalised at release).
311
+
312
+ Template: [`../assets/version-template.md`](../assets/version-template.md).
313
+
314
+ ## `epic.md` — the plan-it-together doc (TEMPORARY)
315
+
316
+ One per epic, scaffolded by `work.py epic-new`. An **epic** is the tier between
317
+ version and task: the coherent goal you plan as a whole, and the
318
+ folder holding the tasks that deliver it.
319
+
320
+ ```yaml
321
+ ---
322
+ type: epic
323
+ created: 2026-08-01
324
+ updated: 2026-08-01
325
+ covers: [profiles/AC-03, sharing/AC-01] # FEATURE-QUALIFIED
326
+ ---
327
+ ```
328
+
329
+ `covers` — the feature acceptance criteria this epic moves, each **qualified by
330
+ its feature**. That is the one format difference from a task's bare `covers:
331
+ [AC-01]`, and it exists because an epic **spans features** by design (the org
332
+ tier touches `profiles`, `sharing`, `content-trust` and `accounts` at
333
+ once), so a bare id would name several criteria at the same time. An epic with
334
+ no `covers:` is a lint: work that moves no stated criterion is work nobody can
335
+ tell is finished.
336
+
337
+ Body: `# Title` · **Goal** (what a user can newly do, one paragraph) · **Plan**
338
+ (see below — THE design) · **Governance this implies** · **Non-goals**.
339
+
340
+ **`## Plan` is the design, written ONCE for the whole goal, and it replaced the
341
+ per-task `plan.md`.** As-found (`path:line`, confirmed by the sweep) · target
342
+ architecture + the shared seams every task builds against · the constraining
343
+ rules (`work.py rules --task` over the union of the tasks' `code`
344
+ regions) · the slices in landing order · the forward-compat pass. Budgets are the
345
+ ones `plan.md` used to carry: As-found ≤40 lines, Architecture ≤80.
346
+
347
+ This is the tier's whole purpose. Before it, every small task re-ran the same
348
+ as-found, the same blast-radius sweep and the same seam argument — expensive, and
349
+ worse, two tasks that analysed separately reached two different answers. A task
350
+ now **executes** this plan. It gets a `plan.md` of its own only for a call this
351
+ document did not settle, and that is a **gap here**: settle it and write it back
352
+ up, so the next task inherits the answer rather than re-deriving it.
353
+
354
+ **`## Governance this implies` is plan-then-apply.** `work/product/**`,
355
+ `work/architecture/**` and `work/quality/**` describe what is true NOW, never a
356
+ proposal — so the domain-doc edits this epic will make are listed here, one
357
+ line each naming the owner file and the change, and applied when the work lands.
358
+ If the epic implies no governance change, say so explicitly.
359
+
360
+ **Lifetime: `work.py release` DELETES this file.** How the work was planned
361
+ stops being true the moment it ships; the folder stays as the grouping of what
362
+ shipped, and git holds the text. So anything durable in **Plan** or
363
+ **Governance this implies** must have landed in its owner doc *before* release.
364
+
365
+ Where it lives: **in the backlog by default** (`epic-new <name>` with no
366
+ `--version`). A version is expensive to open and its boundary is known only the
367
+ day it opens, so an epic is planned first and promoted with `work.py pull <epic>
368
+ --version <v>` — which moves the folder whole and gives its tasks the `queue/`
369
+ bucket they had no need of in the backlog.
370
+
371
+ Template: [`../assets/epic-template.md`](../assets/epic-template.md).
372
+
373
+ ## `stories.md` — RETIRED (was version-level)
374
+
375
+ **Retired 2026-07-17.** Stories now live per-feature in
376
+ `work/product/**.md` (§`<feature>.md`), the durable owner of behaviour —
377
+ release/priority tooling *references* behaviour, it never owns it. New versions
378
+ no longer scaffold a `stories.md`; a `version.md`'s **Scope** links the feature
379
+ stories in the cut. Existing files carry a dated deprecation pointer and stay
380
+ for history (git). There is no task-level stories.md either — a task's intent is
381
+ its acceptance criteria in `task.md`, which cite the feature `AC-` ids they serve.
382
+
383
+ ## `design.md` — claude.ai/design UI brief ONLY (conditional, version-level)
384
+
385
+ Scaffolded only with `work.py version-new --design` — UI-bearing versions
386
+ need it; an engine-only version doesn't. **This is the claude.ai/design UI
387
+ brief and nothing else** — the version's technical design lives in
388
+ `architecture.md` (below). Sections: `# Title — claude.ai/design brief` ·
389
+ **Goal** · **User stories** (lifted from `stories.md`) · **Audience** ·
390
+ **Workflow** (the two-pass + cleanup instructions that produce
391
+ `wireframes/project/` and `wireframes/ui.md`).
392
+
393
+ The Workflow section is load-bearing — edit it only if the design workflow
394
+ itself changes. Template:
395
+ [`../assets/design-template.md`](../assets/design-template.md).
396
+
397
+ ## `architecture.md` — version-level technical brief (conditional, version-level)
398
+
399
+ Scaffolded only with `work.py version-new --architecture` — a version whose
400
+ tasks share seams/contracts a single technical brief should own; a small or
401
+ single-task version doesn't need one. **Not** a UI brief (that's `design.md`)
402
+ and not a duplicate of per-task design: it owns the *cross-task* technical
403
+ design (the "plan FROM this" doc — shared architecture, phased build order,
404
+ rules) while each task's own `plan.md` still owns that task's own
405
+ As-found/Architecture at pickup. Sections: `# Title — technical architecture
406
+ + phased plan` · **As-found** · **Target architecture** · **Code map** · **Phases**
407
+ (each independently shippable) · **Risks**. The **Code map** is one block
408
+ per `code` region the version touches — its **seam**, **known-next constraints**,
409
+ **consumers** (features/tasks), and **foundation task** — a MAP of
410
+ seams/decisions/links (never a code dump) where Pass-1 topology + the architect's
411
+ foundation reasoning land (`SKILL.md` §Two-pass decomposition). Template:
412
+ [`../assets/architecture-template.md`](../assets/architecture-template.md).
413
+
414
+ ## `wireframes/ui.md` — canonical per-page UI spec
415
+
416
+ Produced by Claude Design from `design.md`, in `wireframes/ui.md` (sibling to
417
+ `work/`, alongside `wireframes/project/`). Per changed page: **Layout**
418
+ (ASCII before → after) · **Changed elements** (Does / Looks / Relates to /
419
+ Blast radius, one per changed element) · **Backend changes deduced** (the
420
+ bridge into each task's `plan.md`). Scope tightly — only changed elements
421
+ appear. A task may anchor-link sections of this from its `plan.md`.
422
+
423
+ ## `work/product/` — the product layer (orthogonal to `versions/`)
424
+
425
+ A **separate, sibling tree** to `versions/` — not nested under a version, because a
426
+ feature is a durable product concept that can span many release cuts (idea → defined
427
+ in one, building → shipped over several more), while a version is one time-boxed
428
+ cut. The only bridge between the two trees is `task.md`'s `owner:` field (above) —
429
+ one-directional, so nothing here ever lists its tasks back.
430
+
431
+ ```
432
+ work/product/
433
+ ├── README.md — what this domain owns (the product, described)
434
+ ├── <feature>.md — the durable behaviour spec
435
+ └── wireframes/<feature>/ — appears only once a wireframe exists; never scaffolded
436
+ ```
437
+
438
+ **There is no app tier, and no folder tier.** The repo is ONE product, so a feature
439
+ is a FILE directly under `product/`, its name is globally unique, and `owner:` is a
440
+ bare feature name. `app-new` and `feature-new --app` are gone with it.
441
+
442
+ **And the path is permanent.** A spec is never a folder holding one file: a folder
443
+ that appears the day a sibling arrives is a path that changes on file count, which
444
+ breaks every inbound citation on a day unrelated to the content. So a sibling goes
445
+ in a KIND folder next to the spec (`product/wireframes/<feature>/`), the way a
446
+ version's wireframes already sit beside `version.md` rather than inside it.
447
+
448
+ ### `<feature>.md` — the durable behaviour spec
449
+
450
+ **The sole source of truth for what a feature should do**, independent of the
451
+ code. If code and this file disagree, the code is what's wrong (see `SKILL.md`
452
+ §The spec may say the code is wrong). Stories live HERE, next to the feature —
453
+ not at the version level (retired).
454
+
455
+ ```yaml
456
+ ---
457
+ type: feature
458
+ state: defined # idea | defined | building | shipped | retired — evidence-derived
459
+ depends_on: [other-feature] # optional, multi-valued — an enabler feature this one needs first
460
+ log:
461
+ - 2026-08-01 defined (created) # the state TIMELINE — one dated line per transition
462
+ ---
463
+ ```
464
+
465
+ `depends_on` (optional) — a **bare `<feature>`**; there is no app tier to
466
+ qualify against, and an app-qualified value is itself a lint warning.
467
+ Existence-checked as a `work.py list` lint warning, same as `owner:` on tasks.
468
+
469
+ No `# Title` heading (unlike every other spine file) — a feature's display name is
470
+ its kebab-case folder name. Body sections, in order:
471
+
472
+ 1. **Problem** — what's wrong or needed, in product language.
473
+ 2. **Stories** — the value/context lens (user story *or* job story), NOT the
474
+ container. Each story points at the `B-`/`AC-` ids it frames. Intent, not a
475
+ backlog — one or a few.
476
+ 3. **Behaviour** — `B-nn` observable rules: what the app DOES, phrased
477
+ independent of implementation. Links the feature's own `wireframes/` folder
478
+ once one exists (via `artifact-design`) rather than restating it.
479
+ 4. **Acceptance criteria** — `AC-nn` checkable conditions that bound "done"
480
+ (observable condition → outcome, incl. failure/edge). Plain IDed bullets by
481
+ default; Given/When/Then only where a gnarly rule earns it. **The trace
482
+ unit**: a task's `owner:` cites the AC ids it implements, and a test declares
483
+ them with `covers("<feature>/AC-nn")` or `{ tag: ["@<feature>/AC-nn"] }` — a
484
+ binding the runner reads, so it cannot outlive the test that carries it.
485
+ 5. **Non-goals** — what the feature deliberately does NOT do (bounds the spec).
486
+
487
+ `B-`/`AC-` ids are unique **within the feature**; never reuse an id after ship.
488
+
489
+ `state` is EVIDENCE-DERIVED, not hand-mood (see `SKILL.md` §Feature state):
490
+ `idea` (open product questions) → `defined` (all sections complete) →
491
+ `building` (an in-progress task targets it) → `shipped` (every in-scope AC has
492
+ passing evidence + a release ref) → `retired` (a durable rule says it's gone). It describes **what is true now**, never an
493
+ intention — an AC that states a plan belongs in the plan until the
494
+ evidence exists.
495
+ `work.py list` lints the bookkeeping (id uniqueness, valid links, no `shipped`
496
+ without evidence).
497
+
498
+ Feature names are **globally unique**, like every other name in `work/` — there is
499
+ no app tier to scope them within, which is exactly why `owner:` is a bare
500
+ feature name and `product/<feature>.md` is a feature's whole address.
501
+
502
+ Scaffolded by `work.py feature-new <feature> [--state ...]`. Template:
503
+ [`../assets/feature-template.md`](../assets/feature-template.md).
504
+
505
+ No product-decision ledger: rationale for a feature lives inline in its own
506
+ `<feature>.md` prose, the same way a task's rationale lives in `task.md` — never a
507
+ second ledger-shaped file.
508
+
509
+ ## Conditional task-level files
510
+
511
+ Created only when the state needs them; never pre-emptively. **One canonical
512
+ home each — no suffix variants** (`plan-x.md`, `state-y.md` are lint errors;
513
+ a task that needs two plans is two tasks).
514
+
515
+ - **Research** — *either* a single `research.md` (raw external findings:
516
+ quotes, links, data) *or*, when it's large, a `research/` subfolder with a
517
+ mandatory `00-report.md` (≤30 lines, decisions-relevant findings only) plus
518
+ the raw notes. Never both forms, never topic-suffixed siblings. The read
519
+ order points at the summary; drill into the rest only when a question
520
+ demands it.
521
+ - **`ui.md`** — task-scoped per-page UI spec (same format as
522
+ `wireframes/ui.md`); folded back into the canonical spec when the task
523
+ settles.
524
+ Working checklists (`hygiene.*` findings) are **not** task
525
+ files — they live in native `TodoWrite`. Work them off the todo list, not a
526
+ `slop.md` / `review.md` in the folder (those were retired).
527
+
528
+ There is no task-level `decisions.md` and no version-level `HANDOFF.md` /
529
+ `roadmap.md`: durable rules live in the domain that owns them (small task-local
530
+ ones only surface in a `handoff.md` if you're handing off), and live status is
531
+ the README table + each task's bucket.
532
+
533
+ ## `work/research/<dir>/` — shared research pool
534
+
535
+ Cross-task research (engine audits, market analysis, prior art) lives here,
536
+ one subfolder per topic. **Each subfolder carries a `00-*.md` summary**
537
+ (canonically `00-report.md`; `00-synthesis.md` / `00-analysis.md` etc. also
538
+ count), ≤30 lines, as its distilled entry point — that's what the read order
539
+ points at; the numbered files behind it are drilled into only when needed.