@appchy/jarvis 0.1.36 → 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 +10104 -37174
  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 -38718
  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,717 @@
1
+ ---
2
+ name: work
3
+ description: This skill should be used when the user wants to pick up, resume, plan, organize or complete a piece of coding work in this repo — anything that names a task, references the backlog (`work/`), asks for a plan, or wraps up a change. Work lives as task folders grouped under versions in `work/`.
4
+ ---
5
+
6
+ # Work
7
+
8
+ **This is the method this organisation works by, and it is one document.** It ships inside
9
+ `@appchy/jarvis` and is INJECTED at session start rather than loaded as a Claude Code skill —
10
+ so it reaches a Codex or Cursor session on the same terms, and a repo customises it through
11
+ `instructions.preset` / `instructions.extend` in its own `.claude/work.config.json` rather than
12
+ by forking it. The mechanics `work.py` enforces, the method
13
+ this organisation works by, and the things true only in a repo that serves its own board over MCP —
14
+ all of it here, resolved, with nothing layered on top and nothing correcting it from below.
15
+
16
+ It was three files until 2026-08-25: a generic engine, one organisation's preset, and a repo-local
17
+ file that corrected the middle one. The split existed so a stranger could take the engine and decline
18
+ the opinions, and it cost every session three reads to assemble one answer — in the one repo where
19
+ the harness and the product are the same thing. `appchy:work` still ships that split for the repos
20
+ that have not migrated. This one names its own tools.
21
+
22
+ ## What this is
23
+
24
+ A **lean harness for coding sessions**. Each non-trivial piece of work is a task folder under
25
+ `work/`. The harness delivers:
26
+
27
+ - **Continuity (across conversations only)** — when you hand a task to a *fresh conversation* (you're
28
+ wrapping up, or the user asks to continue in a new session), a templated `handoff.md` carries
29
+ status + next step + a dated log so the next session is oriented in one read. **You do NOT maintain
30
+ it during a single working session** — write/update it only at the handoff moment. Mid-session, the
31
+ task's bucket + `task.md` + code are the truth.
32
+ - **Safety** — work ships as small, reviewable, end-to-end increments.
33
+ - **No drift** — every fact has one owner file (§Ownership); everyone else links to it, never
34
+ restates it.
35
+ - **Plan ONCE, per epic — never per task.** The design, the blast-radius grind and the seam calls
36
+ happen **once for the whole goal**, in `epic.md`. A task then *executes* it. Re-deriving the
37
+ architecture for each small task is the cost this tier exists to remove — it burns tokens, and
38
+ worse, two tasks that re-analysed separately reach two different answers.
39
+
40
+ Drive everything through **`work`** — it is on PATH and it owns status, links and the README table,
41
+ and it lints for drift. Never edit `work/` by hand.
42
+
43
+ ## Plan against the graph — the loop, with the real tool names
44
+
45
+ This repo is **also one queryable graph**, served over MCP by its own engine, beside the board on the
46
+ same surface. It is the fast path for planning and it is faster and more complete than grep. Every
47
+ repo here has ONE server named `jarvis` and it is that repo's own — a checked-in `.mcp.json` running
48
+ `jarvis serve`.
49
+
50
+ **The loop, in order:**
51
+
52
+ 1. **`map_brief {}`** — orient. What is in flight, the most-cited rules, health, and **whether the
53
+ index is fresh**.
54
+ 2. **`map_scope {task}`** — the task in words → the edit set, the governing rules, the covering tests
55
+ and the blast radius, in one call. This IS the planning step; asking its pieces separately is the
56
+ slow path. For a BUILD-NEW task the code does not exist yet — use `map_search` + `map_read`.
57
+ 3. **`map_read {id}`** — the FULL text of every rule it surfaced. **A one-line summary is not the
58
+ rule.** Not delegable, not skippable: this is where a plan meets the constraint that rewrites it.
59
+ 4. **Draft**, citing the ids you read so the builder cannot trip them.
60
+ 5. **`map_scope {edits}`** — before committing, ask what governance the diff touches that the plan
61
+ never cited. The mirror of step 2, and the one that catches a rule you never knew applied.
62
+
63
+ `map_search` finds a node by concept when you do not know the path; `map_connections` says why a file
64
+ exists or where a rule is enforced; `map_connections` and `map_graph` give neighbours, impact, paths
65
+ and coupling hotspots. Reach for them when `map_scope` is not enough.
66
+
67
+ **Two things before you trust an answer.** The map is **95% code** — ~3,600 code nodes against ~290
68
+ knowledge artifacts — so `map_search` for a concept and `map_connections` for why a file exists both earn
69
+ their place. And **the index goes stale, loudly and often**: `stale` means *graph.json older than
70
+ HEAD*, and this repo commits on every board write, so a `jarvis work move` marks the code graph stale
71
+ without changing a line of code. Read the freshness, do not read the *word* — a graph one commit
72
+ behind a `docs(work):` commit is fine; one that predates the code you are about to edit is not.
73
+ `jarvis build graph` rebuilds it — incrementally — and nothing does it for you.
74
+
75
+ **Delegate the grind, never the reading.** A grind hands back a map of pointers; you open the files
76
+ and the rule text it points at and reason over those primary sources. If you could plan off the
77
+ report without opening a file, it laundered a paraphrase into your plan. The graph calls above stay
78
+ **yours**: a cheap delegate rarely has the map's tools at all, so run them here and hand over the
79
+ results as a seed set.
80
+
81
+ The plan's *As-found* must say what the sweep confirmed — the callers, where the seam lives, what
82
+ stays clean — not "probably".
83
+
84
+ ## Two doors onto the board, and they read different checkouts
85
+
86
+ - **`work` on PATH reads the clone you are standing in** — this repo, this branch, whatever your
87
+ working tree says right now. Use it for anything beyond the five agent-facing tools: `verify`,
88
+ `observed`, `handoff`, `move`, `where`, `rules`, `align`, `coverage`, `sync`.
89
+ - **`work_*` over MCP resolves to the workspace's own machine** and reads *its* clone.
90
+
91
+ **A read does not pull.** `work_list` parses the tree as it stands, and that checkout may be behind or
92
+ on another branch. A write refreshes first; a read does not. **`jarvis work sync`** forces a fresh pull and
93
+ changes nothing — run it when you are not sure something moved under you. Branches are allowed to
94
+ differ, and that is not a bug: a branch's board describes that branch's world and merges when the
95
+ branch does.
96
+
97
+ ## How to work here
98
+
99
+ <!-- applies:begin -->
100
+ **The seven no gate can catch.** This is the index, not the argument — each one is worked out
101
+ somewhere below, and the section that owns it is the one to read. It is deliberately terse because
102
+ it arrives a second time, mid-run, when you are about to write a file: a rule read at the top of a
103
+ session is a rule forgotten by the time it bites.
104
+
105
+ 1. **Align before you plan** — open questions and an outline, never a finished plan. (*How to work
106
+ here*)
107
+ 2. **Product, UX and architecture calls are the user's** — `AskUserQuestion`. Mechanics are yours.
108
+ (*How to work here*)
109
+ 3. **Park what you cannot answer** — `work_update {id, question}`; it never blocks. Deciding
110
+ because asking felt expensive is the failure. (*Running unattended*)
111
+ 4. **Cite only rules you opened** — a summary is not the rule. (*Governance cuts both ways*)
112
+ 5. **One goal per task, cut downward** — never a layer sliced across and the rest stranded.
113
+ (*Two-pass decomposition*)
114
+ 6. **No legacy left behind.** (*Building*)
115
+ 7. **Report what happened, not what you meant** — failures shown, skips named, and *verified* only
116
+ of something you watched pass. (*Output budgets*)
117
+ <!-- applies:end -->
118
+
119
+ **Read the standards before planning — hard pre-step, not a suggestion.** Before you propose *any*
120
+ plan: the standards and conventions the `SessionStart` hook named under *read before planning* —
121
+ it lists them from this repo's own config — plus the governing rules in
122
+ `work/architecture/README.md` and the org-domain READMEs (`jarvis work where <id>` resolves any id to its
123
+ home). The plan must fit the existing conventions, package layout and the dependency rule, and must
124
+ not regress a rule.
125
+
126
+ **Work back and forth with the user. Never jump to a plan.** Surface the open questions and an
127
+ outline first, ask through `AskUserQuestion`, and route every product, UX or architecture decision
128
+ through them. In every repo this harness runs, that is a durable RULE with an id of its own, not a
129
+ preference — `jarvis work where` resolves it. Tiny mechanics need no sign-off.
130
+
131
+ ### Governance cuts both ways
132
+
133
+ 1. **Guardrail — protect the direction.** Before finalizing ANY plan, sweep it against the durable
134
+ rules and the task's `owner:` `<feature>.md`: read **in full** every rule the plan's edit set
135
+ touches (`jarvis work rules --task <name>` derives the ones its regions are subject to; `map_scope`
136
+ surfaces the cited ones; a wide sweep of the domain tree catches the uncited rest). A plan that
137
+ contradicts a rule has exactly two legal outcomes: **change the plan**, or **the user explicitly
138
+ supersedes** — route the conflict through `AskUserQuestion` (old direction vs new, with what each
139
+ costs), and record the call as a NEW rule marking the old one `Superseded by <new id>`. Never
140
+ silently violate; never quietly re-argue a decision inside a plan file. Cite the constraining ids.
141
+ 2. **Sync — plan-then-apply, never mid-build.** `work/product/**`, `work/architecture/**` and
142
+ `work/quality/**` describe **what is true NOW** — never a proposal, never the future tense. So a
143
+ governance edit is **stated in the plan first**: `plan.md` (or the epic's §Governance this
144
+ implies) names the owner file and the change it will make, the user approves the whole thing, and
145
+ it lands **with the code or not at all**. When direction changes mid-session, update the
146
+ governance in the SAME session, then **sweep what it invalidates**: queued briefs, `version.md`,
147
+ `epic.md`, in-flight `plan.md` / `handoff.md`, and every `<feature>.md` that now describes the old
148
+ world. A stale brief is a trap for the next session — treat "docs describe a retired design" as a
149
+ bug with the priority of a failing test.
150
+ 3. **Forward-compat — protect the future.** A plan correct in isolation can still be a trap. Before
151
+ finalizing a non-trivial one, run three explicit tests against the current + next 1–2 versions:
152
+ **Known-next** — can every later task sharing this task's `code` region extend the proposed seam
153
+ *without replacing this task's core*? **Option / LRM** — which *irreversible* choices does this
154
+ make now, and is this their Last Responsible Moment? Leave the reversible rest open on purpose and
155
+ say so. **Consumer** — a piece pitched as a *foundation* must name **≥2 near-term consumers**; one
156
+ or none is premature or mis-scoped. Foundation-before-feature ordering is an INFERENCE you draw
157
+ from `jarvis work code <region>` overlap and the feature graph, not a lint. A cheap reshape happens in
158
+ the plan; a real trade-off routes through `AskUserQuestion` and lands as a new rule.
159
+
160
+ The completion gate enforces all three: a task that changed behaviour is not complete until every
161
+ `AC-nn` it targeted has passing evidence, `<feature>.md` (+ its `state:`), the durable rules and any
162
+ touched briefs match what was actually built. `map_scope {edits}` over the edit set flags governance the
163
+ diff touches that the plan never cited.
164
+
165
+ **Feature state is evidence-derived.** `idea → defined → building → shipped → retired` follows
166
+ evidence, not mood: `defined` once Problem + Stories + Behaviour + Acceptance criteria are complete;
167
+ `building` once an in-progress task names it in `owner:`; `shipped` once every in-scope `AC-nn` has
168
+ passing evidence + a release reference; `retired` once a durable rule says the behaviour is gone.
169
+
170
+ **The spec may say the code is wrong.** `<feature>.md` is the source of truth for what the app should
171
+ *do*; code, tests and screenshots are evidence about what it *does*. When they conflict, the code is
172
+ the bug — never infer intended behaviour from buggy code, and never edit `<feature>.md` to match what
173
+ the code happens to do.
174
+
175
+ ### Building
176
+
177
+ **Leave no legacy.** No deprecated paths, no compat shims, no dead code, no `@deprecated`
178
+ re-exports. Boy-scout as you go.
179
+
180
+ **The task is the shippable unit — nothing inside it is.** Keep going until the task lands green,
181
+ consistent and integrated end-to-end. A task cuts *down* through every layer it needs (types → db →
182
+ API → UI); it never cuts *across* one layer and strands the rest.
183
+
184
+ **Two-pass decomposition — plan the epic DEEP, then execute.** **Pass 1 (the epic)** is where the
185
+ thinking happens, once: the as-found, the blast radius, the shared seams, the slice order, the
186
+ governance implied. Story-map the goal into vertical e2e slices; tag each slice's `code` region +
187
+ `owner:` feature + the `AC-nn` it `covers`; pick a **walking-skeleton** first slice (thin end-to-end,
188
+ not a foundation *layer* built ahead of a consumer); record each region's seam + known-next +
189
+ consumers in `epic.md` §Plan. The sibling sweep (`jarvis work code <region>`) belongs here, done once for
190
+ every task in the goal. **Pass 2 (pickup)** *reads* Pass 1 and builds — it does not re-derive it. If
191
+ pickup finds the epic plan didn't settle something, that is a **gap in the epic plan**: settle it and
192
+ write it back UP, so the next task inherits the answer.
193
+
194
+ **Refactor work is its own commit.** Restructuring existing code *without changing behaviour* is its
195
+ own phase and its own commit — never mixed with a feature or fix.
196
+
197
+ **Tests trace to feature acceptance criteria — through a TAG, never a comment.**
198
+
199
+ ```ts
200
+ covers("sessions/AC-01", "sessions/AC-04"); // vitest, file- or suite-scoped
201
+ test.describe("…", { tag: ["@sessions/AC-01"] }, () => {…}) // Playwright
202
+ ```
203
+
204
+ The trace unit is the feature's `AC-nn` in the task's `owner:` `<feature>.md`, always
205
+ **feature-qualified** — a bare `AC-01` names a different criterion in each feature file. **Never
206
+ write the binding in a comment**: a `// Covers:` header survives the test being renamed, skipped or
207
+ deleted, so the criterion goes on claiming evidence no run produces. A tag cannot outlive its test.
208
+ Describe titles stay human-readable — product behaviour, not file paths, and no bare ids. Comments
209
+ obey the comment rule in this repo's standards and carry no wiring: the non-obvious WHY, nothing
210
+ else, and **no governance ids in code**.
211
+
212
+ ## Sessions — handing work on, and starting one beside you
213
+
214
+ **A session that runs out of room continues on the same item.** When you wrap:
215
+
216
+ 1. `jarvis work handoff <task>` and fill it, bring the docs current, move what finished.
217
+ 2. **Hand back a continuation prompt for the person to paste.** `jarvis work kickoff <task>` derives it —
218
+ never hand-write it. It
219
+ also prints the **name** to pass, which is what makes a session findable: without one Claude Code
220
+ derives a name from the FOLDER, identical for every run in a repo.
221
+ 3. **Do NOT start it yourself.** See below — this reversed on 2026-09-03.
222
+
223
+ **Starting a session is the person's call, not the wrap's** (founder, 2026-09-03). This document said
224
+ the opposite for weeks — that starting the successor was "the default, not an option to offer" — and
225
+ the measured result was a machine nobody could keep track of: _"i think we are kinda abusing the
226
+ jarvis start session, it's kinda hard to keep track on it, and sometimes i get a duplicate and hard
227
+ to keep track. it should happen only when i ask for it."_
228
+
229
+ So: **`session_start` runs when the person asks for it and at no other time.** Not on a wrap, not for
230
+ side work, not to hand something on. What a wrap owes is the prompt and a clear statement of where
231
+ things stand; what happens to that prompt is the person's business. The old reasoning — that a
232
+ started session "replaces the paste" and saves somebody typing — was real and was outweighed: a
233
+ session nobody asked for is a session nobody is expecting, and several of those at once is a board
234
+ you cannot read.
235
+
236
+ The rest of what was here still holds when a person DOES ask for one: a session started against a
237
+ stale `handoff.md` is worse off than one that was pasted a prompt, because it believes the file. And
238
+ **never start one onto work somebody is already doing** — if the item is already in progress under
239
+ another session, the board names its holder; hand it the handoff and say so.
240
+
241
+ **Side work is written down, not started.** When the person asks for something outside what you hold,
242
+ `work_create` it and say so. It costs this session nothing and it costs them no session to track.
243
+
244
+ **It waits for the person, and that is the point.** A started session runs with this machine's
245
+ permission settings, so it works until it reaches something that needs a person and then parks,
246
+ holding its place. It is not stalled and it has not failed.
247
+
248
+ **Opening a running session in a second local client forks it.** Measured 2026-08-22: a jarvis-started
249
+ session opened in the VS Code panel starts a **second** `claude --resume` process on the same id, both
250
+ alive, both appending to one transcript, both running the work. Reaching it from Remote Control — the
251
+ phone, claude.ai — costs the session nothing. Know which door you are walking through.
252
+
253
+ **What the board never works out for itself:** the link between a session and the item it worked.
254
+ Nothing infers it. An item whose `sessions:` is empty while a run is working it is a run nobody can
255
+ find tomorrow.
256
+
257
+ ## Three tiers: version, epic, task
258
+
259
+ | Tier | What it is | Rule | Lifetime |
260
+ |---|---|---|---|
261
+ | **Version** | A **RELEASE** | states a user-visible `outcome:`; **cannot open while an earlier one is unreleased** | permanent record |
262
+ | **Epic** | A folder inside a version holding its tasks | owns `epic.md` — *the* plan-it-together doc; **usually ≥3 tasks** | **archived at release** |
263
+ | **Task** | **ONE goal**, end-to-end, internally phased | never shredded; never loose — it always names an epic | archived at release |
264
+ | **Feature** | The durable spec — behaviour, `AC-nn`, `state:` | permanent, and orthogonal to all three | forever |
265
+
266
+ ```
267
+ versions/01-one-board/
268
+ version.md the RELEASE — outcome: what a user can newly do
269
+ sessions-you-can-walk-away-from/ EPIC — plan it together
270
+ epic.md
271
+ in-progress/name-the-sessions/
272
+ queue/stop-and-reap/
273
+ ```
274
+
275
+ > A task is **independently shippable**: when it's done the repo is green, consistent and integrated —
276
+ > never a broken intermediate.
277
+
278
+ **Feature ⟂ epic.** A **feature is permanent** (the WHAT: `AC-nn`, `state:`). An **epic is temporary**
279
+ (the HOW-NOW: the work moving one *or more* features in one release). An epic *may span features*,
280
+ which is why its `covers:` ids are **feature-qualified** (`sessions/AC-03`) while a task's are bare.
281
+
282
+ **An epic usually holds AT LEAST THREE tasks**, and `work` warns below it. The tier exists so the
283
+ design is done ONCE for a whole goal; at one or two tasks there is no "whole goal" to plan and
284
+ `epic.md` degenerates into a second copy of the task brief.
285
+
286
+ - **One task → it is not an epic.** Put it in an existing epic. Group by the surface and the audience,
287
+ not by which package the diff touches.
288
+ - **Two tasks → the same, UNLESS more work is genuinely anticipated** — meaning the epic's §Plan can
289
+ *name* the slices it has not cut yet, not that more might turn up.
290
+ - **Under the floor with real depth behind it → cut the tasks, don't merge.** An epic whose Plan lists
291
+ five slices and has one folder is *under-cut*. An epic with **zero** tasks is the worst case: a goal
292
+ nobody has cut work for has not been planned, only wished.
293
+ - **The floor is a floor, not a target.** A long-running epic at nine tasks is fine.
294
+
295
+ **Merging epics is prose work, not folder work.** Moving the folders takes one `mv`; what matters is
296
+ that the surviving `epic.md` absorbs every settled call from the ones being dissolved *before* their
297
+ files are deleted. **Read a dissolving `epic.md` in full first** — a thin epic is exactly where a
298
+ fully-planned, deliberately-deferred goal hides.
299
+
300
+ A version's status is derived: **planned** until tasks start, **current** while any is in-progress,
301
+ **released** once `jarvis work release` stamps it. Release **flattens the done tier**, removes each
302
+ `epic.md`, then `work archive` strips each task to its `task.md` and moves the version to
303
+ `work/archive/versions/<v>/`.
304
+
305
+ **Archived is off the board, not gone.** `list`, the README table and every lint see only `versions/`.
306
+ `jarvis work path <v>` and `jarvis work where <id>` still resolve into the archive.
307
+
308
+ **A finished epic goes off the board too**: an epic whose every task is complete drops into
309
+ `<v>/complete/` and prints as one `DONE` line. It is **derived and materialized, never declared** —
310
+ settled after every mutation, in BOTH directions, so reopening one task lifts its epic straight back.
311
+
312
+ **Epics are planned in the backlog and pulled into a cut when it opens.** `jarvis work epic-new <name>` with
313
+ no `--version` is the normal move; `jarvis work place <epic> --version <v>` promotes the whole epic.
314
+
315
+ ## Artifact model
316
+
317
+ A task carries different files at each state. **Never create a file before its state** — a queue task
318
+ is a brief and nothing else.
319
+
320
+ | State | Files | Budget |
321
+ |---|---|---|
322
+ | queue / backlog | `task.md` only | no length cap — carry what a cold reader needs |
323
+ | in-progress | `task.md` — the design is in `epic.md` §Plan and is not restated here. (`plan.md` **only** for a call the epic plan left unsettled; `handoff.md` **only** when handing to a new conversation) | handoff ≤80 |
324
+ | complete (version unreleased) | same; if a handoff exists, stamp it DONE | — |
325
+ | archived (version released) | `task.md` only | — |
326
+
327
+ **A task is ONE goal, phased internally — never shredded.** If it spans **3+ `code` regions** the lint
328
+ says so, and it is right: that is an epic wearing a task costume. Split it by *goal*, not by layer.
329
+
330
+ `epic.md` is mandatory for an epic and owns three things nothing else does — the **Goal** in user
331
+ terms, the **Plan** every task builds against, and **Governance this implies**. It is **removed by
332
+ `jarvis work release`**.
333
+
334
+ `handoff.md` is the **cross-conversation** artifact, not a per-task journal: **not** scaffolded on
335
+ pickup — create it with `jarvis work handoff <name>` only when handing the task to a fresh session. A task
336
+ can complete within one session having never had a handoff.
337
+
338
+ Conditional extras: `research.md` **or** a `research/` subfolder with `00-report.md` — never both,
339
+ never topic-suffixed siblings; `ui.md` for UI work. Working checklists live in native `TodoWrite`, not
340
+ in the task folder.
341
+
342
+ Version-level: `version.md` is mandatory; `design.md` and `architecture.md` are conditional. Version
343
+ `stories.md` is **retired** — stories live per-feature. Full format specs:
344
+ [`references/artifacts.md`](references/artifacts.md).
345
+
346
+ Durable rules live in **the domain or system that owns them** — `work/architecture/<system>.md` for
347
+ how something is built, or an org-domain's `README.md` for what it does, how it looks, how we know
348
+ it's good, what keeps it safe, how we run it, how users get unblocked, how we reach users, or what
349
+ binds us. **There is no central ledger.** `jarvis work where <id>` resolves any id to its home, and an id is
350
+ permanent — only the home moves. Never link into a task folder for a rule.
351
+
352
+ ## Layout
353
+
354
+ ```
355
+ work/
356
+ ├── README.md overview + auto-generated table (work owns it)
357
+ ├── ROADMAP.md the release sequence — order, never status
358
+ ├── versions/<v>/
359
+ │ ├── version.md (mandatory; `outcome:`)
360
+ │ ├── design.md · architecture.md (conditional)
361
+ │ ├── <epic>/epic.md + {queue,in-progress,complete}/<task>/
362
+ │ └── complete/<epic>/ every task done — off the board, still in the cut
363
+ ├── backlog/<epic>/<task>/ epics planned but not yet in a cut — NO buckets here
364
+ ├── archive/versions/<v>/ released + archived cuts
365
+ ├── research/<dir>/ shared research (each has a 00-report.md summary)
366
+ ├── product/README.md what this domain owns + its rules; behaviour specs sit beside it
367
+ │ ├── <feature>.md what the app does — bridged to versions/ via task.md's `owner:`
368
+ │ └── wireframes/<feature>/
369
+ └── architecture/ design/ quality/ security/ the other eight org-domains, each
370
+ operations/ support/ commercial/ legal/ hosting the rules it owns
371
+ ```
372
+
373
+ **Nine org-domains, and every one may host rules** — what it does → how it's built → how it looks →
374
+ how we know it's good → what keeps it safe → how we run it → how users get unblocked → how we reach
375
+ and earn → what binds us. `product/` holds `<feature>.md` behaviour specs *and* a `## Rules` section:
376
+ a feature spec says what the app does today and can be retired; a product rule says what the product
377
+ *is* and outlives any feature expressing it. A domain declares itself with `type: domain` frontmatter,
378
+ never by filename, and never declares a `code:` region — regions belong to systems, one region to
379
+ exactly one owner.
380
+
381
+ A task's status is its bucket; never a frontmatter field — which is why `backlog/` has no buckets at
382
+ either tier. Its **epic is derived from where it sits**. Names are globally unique across tasks, epics
383
+ *and* versions, so `pull`/`rehome`/`path` dispatch on what the name IS.
384
+
385
+ **There is no app tier** — this repo is ONE product, so a feature sits directly under `product/`.
386
+
387
+ ## Operations
388
+
389
+ `work` regenerates `work/README.md` after every mutating command. Run it from anywhere.
390
+
391
+ **An agent reaches the board through TOOLS; the CLI is the person's door and the harness's**
392
+ (founder, 2026-08-28). The CLI is not a fallback — where a row below has a tool, use it, and where
393
+ a row is marked *a person's* it is not yours to run: raise it instead. Measured over 30 days across
394
+ four repos, sessions made 4,686 CLI calls against 851 tool calls, because until 2026-09-06 the tool
395
+ surface could not prove an item and therefore could not finish one. It can now.
396
+
397
+ ### The loop, as an agent runs it
398
+
399
+ | Operation | Tool |
400
+ |---|---|
401
+ | See what exists, and what is free | `work_list` · `{takeable: true}` for what nobody holds |
402
+ | Pick up a task | `work_take {id, actor, sessionId}` — it never refuses because somebody else is on it; you are told who |
403
+ | **Park a question** | `work_update {id, question: {question, options, owner}}` — parks the item until a person answers |
404
+ | **Record an eyes-on** | `work_update {id, observed: {ac, saw}}`, or pass `observed` straight to `work_complete` |
405
+ | **Prove it** | `work_verify {id}` — runs every configured gate. It does NOT block: ask again for progress, and again for the result |
406
+ | Complete a task | `work_complete {id, delivered, notIncluded}` — refuses unless the gates passed at this commit |
407
+ | Record work you found | `work_create {name, epic, …}` — for something outside what you hold, never to track your own steps |
408
+ | How work is done here | `work_start` — once. `{method: true}` for this document |
409
+ | Finish the session | `work_wrap` — what is uncommitted, what is in flight, what the tree disagrees about, and the next session's prompt |
410
+ | Look up a rule | `map_read {id}` — the full text AND where it lives. This is what `where` did |
411
+ | Plan a change | `map_scope {task}` → `map_read` each rule → draft → `map_scope {edits}` |
412
+
413
+ ### The CLI, which is a person's door
414
+
415
+ Run these yourself only when you are the person at the keyboard. An agent that finds one of these is
416
+ the only way forward has hit a real gap: **park a question, do not shell out.**
417
+
418
+ | Operation | Command | Whose |
419
+ |---|---|---|
420
+ | Create a version | `jarvis work version-new <v> --outcome "…" [--title] [--order] [--design] [--architecture]` | a person's |
421
+ | Create an epic | `jarvis work epic-new <name> [--version <v>] [--covers <feature>/AC-01,…] [--owner <feature>\|<domain>]` | a person's |
422
+ | Create a feature | `jarvis work feature-new <feature> [--state …]` | a person's |
423
+ | Place work in a cut | `jarvis work place <epic> --version <v>` · `jarvis work place <task> --version <v> --epic <e>` | a person's |
424
+ | Take it back out | `jarvis work place <name> --backlog --epic <e>` | a person's |
425
+ | Carry an epic forward | `jarvis work epic-new <name> --version <v> --continues <earlier epic>` | a person's |
426
+ | Release / archive | `jarvis work release <v>` · `jarvis work archive <v>` | a person's |
427
+ | Answer a parked question | `jarvis work needs` → `jarvis work answer <task> --choose "…"` | a person's |
428
+ | Read the shift | `jarvis work status` · `jarvis work digest --since YYYY-MM-DD` | a person's |
429
+ | Config | `jarvis work config` | a person's |
430
+ | Create a task | `jarvis work new <name> --epic <e> [--priority] [--depends] [--owner] [--code] [--covers]` | either — `work_create` is the tool |
431
+ | List | `jarvis work list` | either — `work_list` is the tool |
432
+ | Pick up / complete | `jarvis work move <name> in-progress\|complete --delivered "…" --not-included "…"` | either — `work_take` / `work_complete` |
433
+ | Prove it | `jarvis work verify --task <name>` (blocks) · `--async` (what the tool uses) | either — `work_verify` |
434
+ | Record an approved plan | `jarvis work plan <name> [--file <path>]` | either |
435
+ | Hand off | `jarvis work handoff <name>`, then fill it | either — **no tool yet**; the prose is judgement |
436
+ | Open the NEXT session | `jarvis work kickoff <name>` — never hand-write the prompt | either — `work_wrap` embeds it |
437
+ | Take work unattended | `jarvis work next [--instance <id>] [--peek]` | an automation's |
438
+ | Get the board fresh | `jarvis work sync` | either |
439
+ | Path / rule lookup | `jarvis work path <name>` · `jarvis work where <id>` · `jarvis work rules --task <name>` · `jarvis work code <region>` | either — `map_read` / `map_scope` |
440
+ | Hygiene checkpoint | `/code-review` (bugs) and `/simplify` (quality) | either |
441
+
442
+ Playbooks (cold-start read order, decomposition, plan-at-pickup, archive):
443
+ [`references/operations.md`](references/operations.md).
444
+
445
+ **`jarvis work list` and every mutation print the shape lints**: a task spanning **3+ `code` regions** (it is
446
+ an epic, not a task), an epic **under 3 tasks** (fold it into one that fits), an epic with no
447
+ `covers:`, a version with no `outcome:`, and a task left loose in a version that has adopted epics.
448
+ The two task-count rules are one rule from both ends: **a task is one goal, an epic is several**. A
449
+ **done** epic is exempt from the floor; it is history, not a plan.
450
+
451
+ `jarvis work align` reports every misalignment class — dangling citation · orphan/uncovered AC · unenforced
452
+ rule · retired concept still named live · complete-but-unreleased version · an `epic.md` surviving a
453
+ release. Report-only, exit 0.
454
+
455
+ ## Every board write lands in git
456
+
457
+ **Where `git.commit` is on — it is in jarvis, and `jarvis work config` says for any repo** — a board write
458
+ **pulls, writes, commits and pushes**, and the
459
+ commit is what makes the write unloseable, so it happens the moment the change does. There is no
460
+ debounce and no window: an item created inside such a window existed in **no git history anywhere**
461
+ and had to be recovered by hand, which is the failure this closes. Only the push may fail; when it
462
+ does you are told plainly, the change is still committed, and `jarvis work sync` sends it later.
463
+
464
+ **The commit's trailers ARE the activity record**, so there is no `work/.events.jsonl` here — that
465
+ file records a session id rather than a machine or a branch, and it appends at the end, so two active
466
+ branches conflict on it every time. `status`, `log` and `digest` read `git log` instead.
467
+
468
+ ```
469
+ docs(work): moved name-the-sessions
470
+
471
+ moved from=queue · to=in-progress
472
+
473
+ Work-Item: name-the-sessions
474
+ Work-Event: moved
475
+ Work-Machine: <host>
476
+ Work-Session: <the run that made the change>
477
+ ```
478
+
479
+ Four keys and no more: who, when and which branch are git's own, and a second copy of a fact is a
480
+ second thing to drift. Two things never reach git — a **hold** (`.claim`), because coordination that
481
+ replicates is two machines holding one item with neither knowing, and a **refused completion**,
482
+ because nothing changed for a commit to carry.
483
+
484
+ **One consequence worth holding on to**: most commits in this repo are board writes that change no
485
+ code, and `stale` is defined as *graph older than HEAD*. See §Plan against the graph.
486
+
487
+ ## Somebody else is on it
488
+
489
+ The harness knows who else is working — a `.claim` carries an instance id and a machine, a board
490
+ commit carries `Work-Session` and `Work-Machine`. Where that matters it says **whether you can reach
491
+ them**:
492
+
493
+ | You see it | When |
494
+ |---|---|
495
+ | `next` skips a task | its `code:` regions are held by another session |
496
+ | `move <name> in-progress` | a live claim on it belongs to somebody else — a **note**, not a refusal |
497
+ | `status` → IN FLIGHT | a task is held by a session that is not you |
498
+ | any write | a pull brought board changes in: *the board moved under you — <what> · from <who>* |
499
+
500
+ - **`— this machine`** → that session is addressable. `ListAgents` lists it, `SendMessage` reaches it.
501
+ Use it when the plan has to change and waiting for a lease to expire is the wrong answer.
502
+ - **`— another machine`** → it cannot be reached from here. The board is the only thing you share, so
503
+ say it on the board: `ask`, a `handoff`, or a task note.
504
+
505
+ **The harness never messages anyone.** It reports who and whether they are reachable; opening the
506
+ conversation is your call. A `move` that warns still moves — `next` is the door that declines held
507
+ work.
508
+
509
+ **Two things about holds.** A hold belongs to a **person**, not a machine — so a session you start can
510
+ update and complete an item you are holding, and two of your own sessions never lock each other out.
511
+ And a hold is **time-bounded and lives in the daemon's memory**: it does not survive a restart and is
512
+ not written into the tree. Take an item when you are about to start it, not to reserve it.
513
+
514
+ ## Running unattended — what you decide, and what you park
515
+
516
+ Everything above assumes someone is in the chair. **On a schedule, nobody is** — and *route every
517
+ product, UX or architecture decision through the user* then has two readings, both wrong: block
518
+ forever on a question nobody is awake to answer, or decide it yourself and leave no trace that a call
519
+ the founder owned was made without them. The second is what actually happens, and it is invisible. So
520
+ the boundary is a value, not a habit.
521
+
522
+ **Every task carries a `tier:`** — what its blast radius IS, not its size (`code:` region count
523
+ already measures that):
524
+
525
+ | Tier | What it means |
526
+ |---|---|
527
+ | 0 | reversible and local — a typo, a comment, a test name |
528
+ | 1 | an ordinary change behind existing tests |
529
+ | 2 | new behaviour, a new seam, or a reversible migration |
530
+ | 3 | **irreversible**, or it touches money, secrets, personal data or the law |
531
+
532
+ The tier is **derived** where the tree already knows it — an `owner:` of `security` / `legal` /
533
+ `commercial` floors a task at 3 — and may be **raised by hand, never lowered**. A run that can talk
534
+ its own blast radius down has no ceiling at all.
535
+
536
+ **At or below `autonomy.ceiling` (2 unless the repo raises or lowers it) you decide inside the plan. Above it, and for every product
537
+ or UX call at any tier, you ASK — and move on.**
538
+
539
+ ```
540
+ work_update {id: "<task>", question: {question: "…", options: ["a", "b"], owner: "founder"}}
541
+ ```
542
+
543
+ Parking writes the question, puts the task in `blocked/`, and **never fails**. It does not stall the shift:
544
+ take the next task. The founder answers the batch on their own clock (`jarvis work needs` is their one
545
+ screen — a person's door), and a question whose answer belongs in a domain rule is one nobody
546
+ should have to ask twice.
547
+ **Never** substitute your own judgement for a question you were about to ask — that is the one failure
548
+ this section exists to prevent, and nothing downstream can detect it.
549
+
550
+ **The loop a scheduled instance runs:**
551
+
552
+ ```
553
+ jarvis work next # take ONE task, claim it, print the read order
554
+ # … read what it printed, build, and then, through TOOLS:
555
+ work_verify {id} # runs every gate; ask again until it is finished
556
+ work_complete {id, delivered, notIncluded, observed}
557
+ # … or, when you hit something that is not yours to decide:
558
+ work_update {id, question: {…}} # park it and go back to `next`
559
+ ```
560
+
561
+ `next` is the one step with no tool: claiming work unattended is a scheduler's job, not a session's.
562
+ Everything after it is a tool call, and a session that cannot finish through them has found a gap
563
+ worth parking a question about.
564
+
565
+ `next` refuses a task whose dependencies are unmet, whose tier is above the ceiling, or whose `code:`
566
+ regions another live instance holds — so two instances never collide, and never reach two different
567
+ answers to the same seam.
568
+
569
+ **Completion is a run, not a claim.** `work_complete` (and `move … complete`) is a gate that **refuses**: every acceptance
570
+ criterion checked, `verify.*` actually executed and passing at the current commit, and every `covers:`
571
+ criterion carrying either coverage a run produced or a recorded eyes-on (`jarvis work observed <task> --ac
572
+ AC-01 --saw "…"` — what you *saw*, not a checkbox). A tier-3 task needs a human's name on it. When a
573
+ human genuinely accepts the risk, `--accept "<reason>" --owner <name>` records it as an event; there
574
+ is no silent override, and you must never invent an owner for one.
575
+
576
+ **State `--not-included` every time.** It is what stops a shipped task reading as more than it is, and
577
+ it is the one field nothing else can infer for you.
578
+
579
+ ## Model routing — the brain decides, and nothing it delegates to judges
580
+
581
+ **The brain decides, and delegation is for finding and typing.** Whatever your client gives you to
582
+ delegate with — a subagent, a cheaper model, a second session — it gets retrieval or already-decided
583
+ edits, and never a judgement. Planning, deciding and verifying happen in the main session, in front
584
+ of the user.
585
+
586
+ This is a founder call with a history. Two goal-given agents, `worker` (implementation) and
587
+ `architect` (design + doc alignment), both existed and both were deleted: the token saving was real
588
+ but the output was sloppy, the work happened where the founder could not see it, and a subagent that
589
+ makes a judgement call makes it with less context than the session that briefed it. **Do not propose
590
+ re-adding an agent that is given a goal.** If handing down a *judgement* feels tempting, that is a
591
+ signal the plan is not decision-complete — finish the thinking.
592
+
593
+ Two named subagents, `donkey` and `grinder`, carried the two halves below until 2026-09-03, when they
594
+ went with the Claude Code plugin this product stopped requiring. **A Claude-Code-only affordance
595
+ cannot be part of a method meant to run anywhere**, so the names are gone and the discipline is not.
596
+ Both halves are written below as what you do, not who does it — apply them to whatever you actually
597
+ have.
598
+
599
+ **Decided work is a pair of hands, not a junior.** Hand down only what is **already decided** — a
600
+ diff in prose, never a goal: exact old→new strings, an exact file list that is the whole of its
601
+ world, an exact verify command. It touches code and never governance (`work/**`, `STANDARDS.md`,
602
+ `CLAUDE.md`, `.claude/**`), never git, no migration, no database, no dev server, and it **stops with
603
+ a question** rather than deciding anything. Delegate when the job is fully specified, bulky or
604
+ repetitive, and the brief costs less than the edit would. **Announce what you are handing down before
605
+ you dispatch**, then don't block on it — and **read the diff yourself afterwards**, because the
606
+ report claims the brief was applied, never that the change was right. The safety argument is entirely
607
+ that there was nothing left to decide, so it is **exactly as safe as your brief**: write it as if the
608
+ reader has no context, no taste and no authority, because that is the correct model of it.
609
+
610
+ **Retrieval is an indexing job, not a summarizing one.** A grind returns a **map** — `path:line`
611
+ pointers, the blast radius, the governing ids, and a coverage ledger that includes the queries which
612
+ found nothing. It says *where to look and why it matched*; it must never say *what the file means*,
613
+ because then the brain trusts a paraphrase and stops reading, and a cheap paraphrase silently drops
614
+ the qualifier, contradiction or ordering the whole plan turns on. **Read the primary sources
615
+ yourself.** Grind wide and surface it all: a pointer the brain discards costs nothing, a pointer the
616
+ grind pruned is invisible.
617
+
618
+ So the split is: **something cheap finds and types, the brain decides what any of it means.**
619
+
620
+ **Model policy — Opus default, Fable explicit-only.** The brain runs on **Opus**. **Fable is never a
621
+ default** — only a deliberate ask: `/model fable`, or a one-off `model: fable` override for heavy
622
+ design.
623
+
624
+ Where your client can hold a delegate open, keep it **warm**: send follow-ups to the same one rather
625
+ than starting again, so a refined grind — or a hand stopped on a question — needs no re-brief.
626
+
627
+ **Research is the one thing that leaves the session** — it goes to `codex:codex-rescue`. A same-model
628
+ researcher is allowed and costs the independent read. The take file is named for whoever wrote it, so
629
+ a second model can go over the same raw sources later and file its opinion beside the first
630
+ ([`references/research.md`](references/research.md)).
631
+
632
+ **Plan mode is optional.** The plan→approve→implement gate is a conversation: propose a plan (in chat,
633
+ or a task `plan.md`), the user approves, THEN build. Run normal + auto permission mode for speed;
634
+ reach for plan mode (Shift+Tab) only when the user wants the brain hard-blocked from editing until
635
+ they have read the whole plan.
636
+
637
+ ## Ownership — one writer per fact
638
+
639
+ Every fact has exactly **one owner file**. Every other file links to it, never restates it. A session
640
+ reading the spine never meets two competing versions of the same fact.
641
+
642
+ | Fact | Sole owner | Everyone else |
643
+ |---|---|---|
644
+ | Scope + acceptance criteria | `task.md` | link it, never repeat criteria |
645
+ | Technical design + as-found, for the whole goal | **`epic.md` §Plan** — written ONCE, before the tasks are cut | a task READS it and does not restate it |
646
+ | A design call one task had to make that the epic plan did not settle | that task's `plan.md` — **the exception, not the norm** | if it affects a sibling it is folded UP into `epic.md` immediately |
647
+ | The governance edits work will make | the plan (`epic.md` §Governance this implies, or `plan.md`) **until they land** | domain docs are current state and never carry a proposal |
648
+ | What a release delivers | `version.md`'s `outcome:` + §Goal | ROADMAP.md carries the *order*, never the status |
649
+ | Live status | the task's **bucket** | never a frontmatter copy — an epic's tier is derived FROM these |
650
+ | Which epic a task belongs to | **where the folder sits** | never a frontmatter field |
651
+ | Status + next step **for a new conversation** | `handoff.md` top two lines | written only at handoff |
652
+ | Durable rule + rationale | the **domain or system that owns it** | cite the id, one line; `jarvis work where` resolves it |
653
+ | What the app should do (behaviour, `AC-nn`) | `<feature>.md` | link it + cite `AC-nn`, never restate |
654
+ | Feature state | `<feature>.md` frontmatter | never a task/version-side copy |
655
+ | Task ↔ feature link | `task.md`'s `owner:` — a bare `<feature>` or org-domain | `<feature>.md` never lists tasks back |
656
+ | Which `AC-nn` a task satisfies | `task.md`'s `covers:` | `<feature>.md` owns the text; coverage rolls up as a query |
657
+ | Code-locality of a task | `task.md`'s `code:` — vocabulary **derived** from each `work/architecture/<system>.md` | query via `jarvis work code <region>`; never a side registry |
658
+ | How a system is built | `work/architecture/<system>.md` — `### <id>` + `enforced_by` | cite the id |
659
+ | The product, described | `work/product/README.md` | ROADMAP.md's framing can stay outward-facing |
660
+
661
+ Four rules keep it true:
662
+
663
+ 1. **Approach hand-over.** `task.md`'s `## Approach` exists only until the goal is planned. Once
664
+ `epic.md` §Plan covers it, Approach collapses to one line: `Approach → epic.md`.
665
+ 2. **Rule promotion.** A durable rule goes straight to the domain or system that owns it, with the
666
+ next free number **read off the tree** (never remembered — concurrent sessions allocate too).
667
+ Rationale never lives in two places.
668
+ 3. **Scope change is one-directional.** Edit acceptance in `task.md` → adjust `plan.md`. Never the
669
+ reverse, never partial.
670
+ 4. **Contradiction = fix now.** Meet a clash between spine files? Resolve it in the owner file and
671
+ reduce the others to pointers *before* continuing.
672
+
673
+ ## Output budgets
674
+
675
+ The spend is authored prose. Keep it tight:
676
+
677
+ - **Link code, never restate it.** Reference `path:line`, don't paste code.
678
+ - **Bullets over prose.** Caps: `handoff.md` ≤80 lines · `plan.md` As-found ≤40 · Design ≤80.
679
+ **`task.md` has NO cap** — a brief is read by a session starting cold, and the findings, dead ends
680
+ and warnings that make that cheap are exactly what a length rule deletes.
681
+ - **Research is read by summary.** Every research dir carries a `00-report.md` (≤30 lines,
682
+ decisions-relevant only); read that, drill into the rest only when a question demands it.
683
+ - **Prune-on-absorb.** When `handoff.md` hits its cap, move durable facts into the owning domain's
684
+ rules and drop the log tail.
685
+
686
+ ## Pitfalls
687
+
688
+ - **Queue / backlog tasks are briefs only.** A `plan.md`/`handoff.md` in a queue folder is a lint.
689
+ - **A task inside an epic should not need a `plan.md`** — the design was settled once, in `epic.md`
690
+ §Plan. One is a lint: fold it up, or keep it and accept that the epic plan had a gap.
691
+ - **`handoff.md` caps at 80 lines** and must keep its `**Status:**` / `**NEXT:**` header lines.
692
+ - **Cannot `new` without `--epic`.** Create the epic first — with no `--version` it lands in the
693
+ backlog, which is usually right.
694
+ - **Don't reach for `epic-new` to house one task.** Ask which existing epic it belongs to first;
695
+ create a new one only when you can name the slices that follow it.
696
+ - **Cannot `version-new` while an earlier version is unreleased**, or without `--outcome`. If the work
697
+ has no stateable release outcome yet, it is an epic.
698
+ - **Cannot `move` a backlog task** — `pull` it into a version first.
699
+ - **Cannot `move … complete` on an unproven task.** The gate refuses *before* the folder moves.
700
+ - **Cannot `move … blocked`.** A blocked task with no recorded question is one nobody can unblock.
701
+ Use `ask`.
702
+ - **Cannot lower a task's `tier:`** below the floor its `owner:` derives.
703
+ - **A `verify.*` command containing `&&`, `;`, `|`, `>` or `$()` is refused at config load.** They run
704
+ without a shell, so a shell operator would be passed to the first binary as a literal argument — a
705
+ gate reporting PASS because its second half never ran. Put the composition in a script.
706
+ - **Cannot `new` or `epic-new` into a released version.**
707
+ - **Cannot `release`** a version with incomplete tasks, zero tasks, or no `outcome:`. **Cannot
708
+ `archive`** one that isn't released.
709
+ - **`release` deletes every `epic.md`.** Anything durable in an epic's §Plan or §Governance must have
710
+ landed in its owner doc before you release — git keeps the text, but nobody will look.
711
+ - **Names are globally unique across tasks, epics and versions.** Renaming = move the folder by hand +
712
+ update any `depends_on:`.
713
+ - **`README.md` BACKLOG markers are load-bearing** — preserve them if you hand-edit around the table.
714
+ - **A task's `covers:` is bare (`AC-01`); an epic's is feature-qualified (`sessions/AC-03`).**
715
+ - **An epic that moves no product criterion sets `owner:` to an org-domain** instead of leaving
716
+ `covers:` empty. The domain IS the stated finish line, and it is checked.
717
+ - **`owner:` is format-checked only** — a dangling reference is a lint warning, not a refusal.