@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.
- package/bin/config-change.mjs +1 -1
- package/bin/jarvis.mjs +8 -12
- package/bin/pre-tool-use.mjs +2 -2
- package/bin/session-start.mjs +1 -1
- package/bin/stop.mjs +1 -1
- package/bin/user-prompt-submit.mjs +1 -1
- package/dist/bin.js +10104 -37174
- package/dist/bin.js.map +1 -1
- package/dist/data/backends.mjs +469 -0
- package/dist/data/chunk-7REP35VA.mjs +462 -0
- package/dist/data/chunk-AKQQC5IT.mjs +1224 -0
- package/dist/data/chunk-AYOJSS2F.mjs +72 -0
- package/dist/data/chunk-RRJ6KKYL.mjs +42 -0
- package/dist/data/chunk-YWSWQEJN.mjs +138 -0
- package/dist/data/embedders.mjs +80 -0
- package/dist/data/finders.mjs +35 -0
- package/dist/data/index.mjs +137 -0
- package/dist/data/linkers.mjs +83 -0
- package/dist/data/mcp.mjs +2624 -0
- package/dist/data/persistences.mjs +8 -0
- package/dist/data/rerankers.mjs +52 -0
- package/dist/data/stores.mjs +38 -0
- package/dist/hooks/config-change.js +7 -29
- package/dist/hooks/config-change.js.map +1 -1
- package/dist/hooks/pre-tool-use.js +129 -32
- package/dist/hooks/pre-tool-use.js.map +1 -1
- package/dist/hooks/session-start.js +72 -37
- package/dist/hooks/session-start.js.map +1 -1
- package/dist/hooks/stop.js +140 -32
- package/dist/hooks/stop.js.map +1 -1
- package/dist/hooks/user-prompt-submit.js +7 -29
- package/dist/hooks/user-prompt-submit.js.map +1 -1
- package/harness/assets/architecture-template.md +53 -0
- package/harness/assets/design-template.md +89 -0
- package/harness/assets/domains/architecture.md +43 -0
- package/harness/assets/domains/commercial.md +42 -0
- package/harness/assets/domains/design.md +42 -0
- package/harness/assets/domains/legal.md +43 -0
- package/harness/assets/domains/operations.md +39 -0
- package/harness/assets/domains/product.md +43 -0
- package/harness/assets/domains/quality.md +43 -0
- package/harness/assets/domains/security.md +44 -0
- package/harness/assets/domains/support.md +45 -0
- package/harness/assets/epic-template.md +85 -0
- package/harness/assets/feature-template.md +86 -0
- package/harness/assets/handoff-template.md +26 -0
- package/harness/assets/task-template.md +38 -0
- package/harness/assets/version-template.md +43 -0
- package/harness/harness/__init__.py +7 -0
- package/harness/harness/align.py +582 -0
- package/harness/harness/architecture.py +254 -0
- package/harness/harness/autonomy.py +374 -0
- package/harness/harness/branches.py +408 -0
- package/harness/harness/config.py +1482 -0
- package/harness/harness/coverage.py +199 -0
- package/harness/harness/epic.py +220 -0
- package/harness/harness/events.py +153 -0
- package/harness/harness/extend.py +99 -0
- package/harness/harness/frontmatter.py +218 -0
- package/harness/harness/gate.py +591 -0
- package/harness/harness/generate.py +267 -0
- package/harness/harness/git.py +775 -0
- package/harness/harness/ids.py +140 -0
- package/harness/harness/kickoff.py +231 -0
- package/harness/harness/lint.py +505 -0
- package/harness/harness/model.py +364 -0
- package/harness/harness/peers.py +187 -0
- package/harness/harness/product.py +29 -0
- package/harness/harness/registry.py +382 -0
- package/harness/harness/report.py +227 -0
- package/harness/harness/safety.py +387 -0
- package/harness/harness/scaffold.py +129 -0
- package/harness/harness/shard.py +63 -0
- package/harness/harness/shift.py +348 -0
- package/harness/harness/task.py +507 -0
- package/harness/harness/tree.py +258 -0
- package/harness/harness/version.py +305 -0
- package/harness/harness/wrap.py +217 -0
- package/harness/hooks/guard.py +259 -0
- package/harness/presets/appchy/PRESET.md +717 -0
- package/harness/presets/appchy/references/artifacts.md +539 -0
- package/harness/presets/appchy/references/graph.md +154 -0
- package/harness/presets/appchy/references/operations.md +444 -0
- package/harness/presets/appchy/references/research.md +216 -0
- package/harness/schema/work.config.schema.json +401 -0
- package/harness/test_work.py +5002 -0
- package/harness/work.py +534 -0
- package/package.json +34 -40
- package/bin/config-change.dev.mjs +0 -17
- package/bin/jarvis-dev.mjs +0 -30
- package/bin/pre-tool-use.dev.mjs +0 -23
- package/bin/session-start.dev.mjs +0 -17
- package/bin/stop.dev.mjs +0 -17
- package/bin/user-prompt-submit.dev.mjs +0 -17
- package/dev/bin.js +0 -38718
- package/dev/bin.js.map +0 -1
- package/dev/env.json +0 -1
- package/dev/hooks/config-change.js +0 -110
- package/dev/hooks/config-change.js.map +0 -1
- package/dev/hooks/pre-tool-use.js +0 -120
- package/dev/hooks/pre-tool-use.js.map +0 -1
- package/dev/hooks/session-start.js +0 -115
- package/dev/hooks/session-start.js.map +0 -1
- package/dev/hooks/stop.js +0 -112
- package/dev/hooks/stop.js.map +0 -1
- package/dev/hooks/user-prompt-submit.js +0 -111
- package/dev/hooks/user-prompt-submit.js.map +0 -1
- 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.
|