quest-loop 0.1.0

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.
@@ -0,0 +1,197 @@
1
+ # Quest record format specification
2
+
3
+ This is the byte-level contract for quest records. The `quest` CLI is the
4
+ single write path — records are only created and mutated through it, in both
5
+ backends. Everything here round-trips through `lib/contract.mjs`.
6
+
7
+ ## Store layout (local backend)
8
+
9
+ ```
10
+ .quests/
11
+ ├── config.json # backend selection + defaults
12
+ ├── quests/ # one file per quest: NNN-slug.md
13
+ ├── amendments.md # numbered protocol amendments (always local)
14
+ └── runs.ndjson # runner journal (always local, gitignore-able)
15
+ ```
16
+
17
+ `NNN` is the zero-padded quest id (`001`, `002`, …). `slug` is derived from the
18
+ title: lowercase, `[a-z0-9-]`, max 40 chars.
19
+
20
+ ## config.json
21
+
22
+ ```json
23
+ {
24
+ "backend": "local",
25
+ "github": { "repo": "owner/name" },
26
+ "defaults": {
27
+ "worker": "claude",
28
+ "claude": { "model": "opus", "effort": "xhigh" },
29
+ "codex": { "model": "gpt-5.5", "reasoning_effort": "medium" },
30
+ "max_iterations": 8,
31
+ "priority": "p2"
32
+ },
33
+ "notify": { "command": "" }
34
+ }
35
+ ```
36
+
37
+ Resolution order: `QUEST_DIR` env (points at a `.quests/` dir) →
38
+ `QUEST_BACKEND` env (overrides backend only) → nearest `.quests/config.json`
39
+ walking up from cwd. Not found → every command except `init` exits `3`.
40
+
41
+ ## Frontmatter (strict YAML subset)
42
+
43
+ Only two shapes are legal: `key: scalar` and `key: [a, b, c]` (inline list).
44
+ No nesting, no multi-line values, no quotes-with-escapes. Optional keys are
45
+ **omitted entirely**, never `null`. The parser rejects anything else with a
46
+ precise error (exit 5) — there is no best-effort mode.
47
+
48
+ ```yaml
49
+ ---
50
+ id: 12
51
+ title: Add --json output to the list command
52
+ status: todo
53
+ priority: p2
54
+ worker: claude
55
+ model: inherit
56
+ max_iterations: 8
57
+ parent: 3
58
+ depends_on: [10, 11]
59
+ created: 2026-07-07T12:00:00Z
60
+ updated: 2026-07-07T14:00:00Z
61
+ ---
62
+ ```
63
+
64
+ | Field | Required | Values |
65
+ |---|---|---|
66
+ | `id` | yes | positive integer, store-assigned |
67
+ | `title` | yes | plain string |
68
+ | `status` | yes | `todo \| in_progress \| blocked \| complete \| cancelled` |
69
+ | `priority` | yes | `p0 \| p1 \| p2` |
70
+ | `worker` | yes | `claude \| codex` |
71
+ | `model` | yes | verbatim model string passed to the worker, or `inherit` (use config default) |
72
+ | `effort` | no | reasoning effort passed to the worker (e.g. `xhigh`); omitted = config default |
73
+ | `max_iterations` | yes | positive integer (counts runner **sessions**) |
74
+ | `max_cost` | no | USD number; omitted = uncapped |
75
+ | `parent` | no | quest id (epic linking; children derived by scanning) |
76
+ | `depends_on` | no | list of quest ids (wave ordering) |
77
+ | `created` / `updated` | yes | UTC ISO-8601 `…Z` |
78
+
79
+ ## Body sections (canonical order)
80
+
81
+ `## Objective`, `## Done when`, `## Validation loop` are lint-required; the
82
+ rest are optional but keep this order when present.
83
+
84
+ ```markdown
85
+ # {title}
86
+
87
+ ## Objective
88
+ One concrete outcome, at most 3 sentences. This is the anchor — it may be
89
+ compatibly expanded, never redefined.
90
+
91
+ ## Done when
92
+ - [ ] Each item independently checkable, with evidence.
93
+ - [ ] Adjectives are not evidence; commands and observable outcomes are.
94
+
95
+ ## Validation loop
96
+ ```bash
97
+ <exact commands the executor runs each iteration>
98
+ ```
99
+
100
+ ## Constraints
101
+ - Hard guardrails that must hold along the way.
102
+
103
+ ## Milestones
104
+ - [ ] M1 — discrete testable unit
105
+ - [ ] M2 — …
106
+
107
+ ## Context
108
+ Pointers: files + symbols (never bare line numbers), docs, related quests.
109
+
110
+ ## Out of scope
111
+ - Explicit exclusions.
112
+
113
+ ## Checkpoints
114
+ (append-only; written by `quest checkpoint` only)
115
+ ```
116
+
117
+ ## Checkpoint block
118
+
119
+ Identical bytes in both backends (local: appended under `## Checkpoints`;
120
+ GitHub: an issue comment). The HTML marker makes discovery deterministic.
121
+
122
+ ```markdown
123
+ <!-- quest:checkpoint -->
124
+ ### 2026-07-07T14:32:00Z — quest_status: in_progress
125
+ - iteration: 2
126
+ - pr: https://github.com/owner/repo/pull/12
127
+ - head_sha: abc1234
128
+ - changed: M2 done — one line per milestone touched
129
+ - validation_summary: `npm test` → 42 passed, 0 failed; `quest lint 12` → exit 0
130
+ - failed_approaches: tried X; failed because Y
131
+ - compatible_expansion: added done-when item Z because …
132
+
133
+ Optional free-form note.
134
+ ```
135
+
136
+ - `quest_status` ∈ `in_progress | complete | blocked` — the only legal values.
137
+ - `iteration` required; `pr`, `head_sha`, `failed_approaches`,
138
+ `compatible_expansion` optional.
139
+ - `validation_summary` required. When `quest_status: complete`, lint requires
140
+ at least one backticked command in it (commands, not adjectives).
141
+ - A checkpoint's `quest_status` drives the store `status` transition:
142
+ `in_progress → in_progress`, `complete → complete`, `blocked → blocked`.
143
+
144
+ ## Status transitions
145
+
146
+ ```
147
+ todo → in_progress (quest start, or first checkpoint)
148
+ in_progress → complete (checkpoint quest_status: complete)
149
+ in_progress → blocked (checkpoint quest_status: blocked)
150
+ blocked → in_progress (new checkpoint quest_status: in_progress)
151
+ todo|in_progress|blocked → cancelled (quest cancel --reason)
152
+ ```
153
+
154
+ Any other transition is illegal (exit 5). `complete` and `cancelled` are
155
+ terminal.
156
+
157
+ ## GitHub backend mapping
158
+
159
+ | Concept | Local | GitHub (`gh` only) |
160
+ |---|---|---|
161
+ | record | `quests/NNN-slug.md` | issue; body = same body sections |
162
+ | orchestration metadata | frontmatter | `<!-- quest:meta -->` HTML block at top of body (same `key: value` lines) |
163
+ | id | frontmatter `id` | issue number |
164
+ | status | frontmatter | labels `quest:todo\|in-progress\|blocked\|complete\|cancelled` (+ marker label `quest`); issue state mirrored (complete → closed-completed, cancelled → closed-not-planned) |
165
+ | priority | frontmatter | labels `quest-p0\|p1\|p2` |
166
+ | checkpoint | appended section | issue comment, identical bytes |
167
+ | parent/child | child `parent:` | child meta `parent:` + epic body `## Children` task list (`- [ ] #12`) |
168
+ | config, amendments, runs | `.quests/` | still `.quests/` local — only records live remotely |
169
+
170
+ Fail-honest: every `gh` failure surfaces gh's own stderr and exits `6`. There
171
+ is no fallback from `github` to `local`.
172
+
173
+ ## Worker final-report schema
174
+
175
+ Headless workers end each session with a final message conforming to
176
+ `schemas/final-report.schema.json`:
177
+
178
+ ```json
179
+ {
180
+ "quest_status": "in_progress | complete | blocked",
181
+ "checkpoint_recorded": true,
182
+ "evidence_summary": "one line citing the decisive command + result"
183
+ }
184
+ ```
185
+
186
+ ## CLI exit codes
187
+
188
+ | Code | Meaning |
189
+ |---|---|
190
+ | 0 | success |
191
+ | 2 | usage error (bad flags/arguments) |
192
+ | 3 | no quest store found / config invalid |
193
+ | 4 | quest not found |
194
+ | 5 | contract violation (lint failure, malformed record, illegal transition, missing checkpoint fields) |
195
+ | 6 | backend unavailable (gh missing, unauthenticated, network) |
196
+
197
+ Runner (`quest-run`) adds: `10` ended blocked · `11` budget exhausted.
@@ -0,0 +1,93 @@
1
+ # The quest loop protocol
2
+
3
+ This is the base protocol every quest execution follows. Local amendments (mined
4
+ from retros, see `/quest:retro`) live in `.quests/amendments.md` and extend this
5
+ document — read both. `quest protocol` prints them together.
6
+
7
+ ## Vocabulary
8
+
9
+ - A **quest** is a goal contract: one Objective, evidence-checkable "Done when"
10
+ conditions, a Validation loop of exact commands, Constraints, and optional
11
+ Milestones. The record format is defined in [contract-spec.md](./contract-spec.md).
12
+ - **Store status** (record lifecycle): `todo | in_progress | blocked | complete | cancelled`.
13
+ - **quest_status** (checkpoint verdict, the only vocabulary allowed in
14
+ checkpoints): `in_progress | complete | blocked`.
15
+ - A **checkpoint** is an evidence-citing progress entry appended to the quest
16
+ record via `quest checkpoint`. Checkpoints are the resume artifact: a fresh
17
+ session with zero prior context must be able to continue the quest from the
18
+ record and its checkpoints alone.
19
+
20
+ ## The loop
21
+
22
+ Each iteration:
23
+
24
+ 1. **Orient.** Read the full quest record (`quest show <id>`), the protocol
25
+ (`quest protocol`), all prior checkpoints, and the referenced files. Check
26
+ recent history (`git log --oneline -5`). Re-verify every reference cited in
27
+ the record — cite **symbol + file** (`resolveConfig` in `lib/config.mjs`),
28
+ never bare line numbers, which rot within hours. If a cited reference is
29
+ stale, post the correction in your first checkpoint.
30
+ 2. **One milestone per iteration.** Pick the smallest unfinished milestone and
31
+ implement it end-to-end. If the quest has no milestones, treat the whole
32
+ Objective as one milestone.
33
+ 3. **Verify with the stated validation loop.** Run the quest's Validation loop
34
+ commands exactly as written. **Never silently substitute a different check**
35
+ for a stated one — if an equivalent check must be used, name the
36
+ substitution and why in the checkpoint.
37
+ 4. **Commit green, never red.** Commit the verified milestone with a clear
38
+ message. Do not commit failing states.
39
+ 5. **Checkpoint.** Record progress via `quest checkpoint` using the canonical
40
+ fields (see contract-spec). `validation_summary` cites exact commands and
41
+ their observed results — commands, not adjectives. Floor: at least one
42
+ checkpoint at completion, plus one at any blocker; per-milestone checkpoints
43
+ when a quest has more than 4 milestones.
44
+ 6. **Evaluate stop conditions.**
45
+ - `complete` — every "Done when" item is enumerated as
46
+ **Done / Blocked / Cancelled** with its evidence, and no new TODOs or
47
+ follow-up work remain inside this quest (file a new quest instead).
48
+ - `blocked` — (a) two consecutive iterations failing on the same error,
49
+ (b) a decision only a human can make, or (c) an unsatisfiable "Done when"
50
+ — name the exact discrepancy and the corrected anchor; **never improvise
51
+ a replacement**. Record the blocker precisely and stop.
52
+ - **Budget** — respect `max_iterations` (and cost caps where enforced); if
53
+ exceeded, checkpoint `blocked` with the reason and stop.
54
+
55
+ ## Scope fence
56
+
57
+ Implement exactly and only the Objective. Scope may **compatibly expand**
58
+ (additions that serve the same Objective) with explicit rationale recorded via
59
+ `quest edit --rationale` or a `compatible_expansion` checkpoint field. The
60
+ Objective and existing "Done when" anchors are never rewritten. Adjacent
61
+ improvements go into new quests.
62
+
63
+ ## Honesty rules
64
+
65
+ - Never edit or delete existing tests to make them pass.
66
+ - Never hide failures behind fallbacks or fake success states; surface the real
67
+ error and fail loudly.
68
+ - Report outcomes faithfully: failing checks are reported as failing, skipped
69
+ steps as skipped.
70
+
71
+ ## Review disposition
72
+
73
+ Every external review finding (human or automated) gets an explicit disposition
74
+ before the work merges: **fixed**, **follow-up quest filed** (linked), or
75
+ **rejected with reason**. Unreplied findings are protocol violations.
76
+
77
+ ## Orchestrator rulings
78
+
79
+ When reviewing a finished iteration or run, the orchestrator rules one of:
80
+
81
+ - **accept** — the checkpoint's evidence actually satisfies the Done-when items
82
+ it claims (quote the commands; never accept adjectives).
83
+ - **iterate-with-feedback** — send the specific gap back to the executor.
84
+ - **split** — the quest was bigger than it looked; decompose via `/quest:plan`.
85
+ - **escalate-to-human** — human-only decisions are surfaced verbatim, never
86
+ guessed.
87
+
88
+ ## Sizing
89
+
90
+ - **Small** — one quest, worked inline in the current session.
91
+ - **Medium** — one quest dispatched to an executor (subagent or headless run).
92
+ - **Large** — an epic (parent quest) with child quests in dependency waves via
93
+ `depends_on`; orchestrate wave by wave.
@@ -0,0 +1,50 @@
1
+ ---
2
+ name: retro
3
+ description: Mine finished quest traces into numbered protocol amendments. Use when a quest or wave just finished, when the same failure appeared twice, or when asked to run a retrospective.
4
+ ---
5
+
6
+ # Retro — turn traces into amendments
7
+
8
+ **What this does:** examines what actually happened (checkpoints, diffs, review
9
+ threads) and encodes the deltas as numbered amendments future sessions read.
10
+ **Use when:** a wave completed, a quest went sideways, or evidence contradicts
11
+ the current protocol.
12
+ **Input:** the finished quests' records and their surrounding artifacts.
13
+ **What you get:** `.quests/amendments.md` entries served to every future orient
14
+ via `quest protocol` — the loop that improves the loop.
15
+
16
+ ## Procedure
17
+
18
+ 1. **Gather evidence:**
19
+ ```bash
20
+ quest list --status complete --json && quest list --status blocked --json
21
+ quest show <id> # read the checkpoint trails, not your memory
22
+ git log --oneline -20
23
+ ```
24
+ 2. **Mine for deltas** — ask, with evidence:
25
+ - Where did a stated check get silently substituted?
26
+ - What blocked twice for the same reason? What reference had rotted?
27
+ - Which checkpoint could a fresh session NOT have resumed from?
28
+ - Where did vocabulary drift (statuses invented, fields skipped)?
29
+ - What did a reviewer catch that the validation loop should have?
30
+ 3. **Write amendments** — imperative, numbered, each citing its evidence:
31
+ ```bash
32
+ quest amend --text "State the expected test count in validation_summary — quest 12's 'tests pass' hid three skipped tests (checkpoint 2026-07-07T14:32Z)."
33
+ ```
34
+ One behavioral change per amendment. No platitudes — if it doesn't change
35
+ what the next executor does, it's not an amendment.
36
+ 4. **Record what worked** as a "keep doing" amendment when a practice earned
37
+ its keep (evidence included) — protocols erode when only failures get ink.
38
+ 5. **Nothing to amend?** Say so explicitly: an honest "no deltas this wave"
39
+ entry beats silence.
40
+
41
+ ## Worked example
42
+
43
+ ```bash
44
+ quest show 12 # blocked twice on the same flaky test before anyone noticed
45
+ quest amend --text "Treat a test that fails twice in one quest as a blocker to escalate, not to retry — quest 12 burned 3 iterations rerunning a flaky suite (checkpoints 3–5)."
46
+ quest protocol # confirm the amendment now rides along
47
+ ```
48
+
49
+ **Next:** amendments feed every future `/quest:work` orient automatically.
50
+ Start the next wave with `/quest:orchestrate`.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Quest Retro"
3
+ short_description: "Mine finished quest traces into numbered protocol amendments"
4
+ default_prompt: "Use $retro to turn this wave's traces into protocol amendments."
@@ -0,0 +1,73 @@
1
+ ---
2
+ name: work
3
+ description: Execute one quest iteratively to a checkpointed stop. Use when asked to work a quest by id, when dispatched as a quest executor, or when resuming a quest a previous session left in_progress or blocked.
4
+ argument-hint: "<quest-id>"
5
+ ---
6
+
7
+ # Work a quest
8
+
9
+ **What this does:** runs the quest loop on ONE quest — iterate in small verified
10
+ increments until the quest is `complete` or honestly `blocked`.
11
+ **Use when:** you were given a quest id to execute (by a human or an orchestrator).
12
+ **Input:** a quest id; the record is the whole spec — no other context is assumed.
13
+ **What you get:** working, committed changes plus a checkpoint trail any fresh
14
+ session can resume from.
15
+
16
+ ## The iteration
17
+
18
+ 1. **Orient** (every session, no exceptions):
19
+ ```bash
20
+ quest show <id> --json # the contract + prior checkpoints
21
+ quest protocol # the rules + this store's amendments
22
+ git log --oneline -5
23
+ ```
24
+ If the quest is `todo`, run `quest start <id>`. Re-verify every file/symbol
25
+ reference cited in the record; if one is stale, say so in your first checkpoint.
26
+ 2. **Pick the smallest unfinished milestone** (or the whole Objective if there
27
+ are none) and implement it end-to-end.
28
+ 3. **Verify with the quest's stated Validation loop** — run those commands
29
+ exactly. If you must substitute an equivalent check, name the substitution
30
+ and why in the checkpoint. Never invent a friendlier check.
31
+ 4. **Commit green, never red.**
32
+ 5. **Checkpoint** — the only way progress exists:
33
+ ```bash
34
+ quest checkpoint <id> --status in_progress \
35
+ --summary "M2 done — <one line per milestone touched>" \
36
+ --validation "\`npm test\` → 42 passed, 0 failed"
37
+ ```
38
+ 6. **Check stop conditions** (see `/quest:protocol` for the full rules):
39
+ - All Done-when items hold with evidence → final checkpoint with
40
+ `--status complete`, whose `--note` enumerates EVERY Done-when item as
41
+ Done / Blocked / Cancelled with its evidence.
42
+ - Same error two iterations in a row, a human-only decision, or an
43
+ unsatisfiable Done-when → `--status blocked` naming the exact blocker.
44
+ Blocked is a good stop; improvising past it is not.
45
+ - Budget (`max_iterations`) exceeded → blocked with reason.
46
+ Otherwise: loop to step 2.
47
+ 7. **End every session by displaying the state** — run `quest show <id>` so the
48
+ recorded checkpoint is visible in the conversation (goal-mode evaluators and
49
+ orchestrators verify from it).
50
+
51
+ ## Scope fence
52
+
53
+ Implement exactly and only the Objective. Additions that serve the same
54
+ objective go through `quest edit <id> --add-done-when … --rationale …`.
55
+ Adjacent improvements: note them for a NEW quest; never fold them in.
56
+
57
+ ## Worked example
58
+
59
+ ```bash
60
+ quest show 12 --json # objective: "settings page offers dark mode…"
61
+ quest start 12
62
+ # …implement milestone M1, then:
63
+ npm test # the quest's stated validation loop
64
+ git commit -m "feat: dark mode toggle (quest 12, M1)"
65
+ quest checkpoint 12 --status in_progress \
66
+ --summary "M1 — theme toggle renders and switches CSS vars" \
67
+ --validation "\`npm test\` → 38 passed"
68
+ quest show 12
69
+ ```
70
+
71
+ **Next:** finished or blocked → the orchestrator (or human) rules on your
72
+ checkpoint — see `/quest:orchestrate`. Learned something protocol-worthy →
73
+ mention it so `/quest:retro` can turn it into an amendment.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Work a Quest"
3
+ short_description: "Execute one quest iteratively to a checkpointed stop"
4
+ default_prompt: "Use $work to execute quest <id> per the quest protocol, ending in a recorded checkpoint."