ralphctl 0.18.0 → 0.20.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.
package/README.md CHANGED
@@ -8,6 +8,7 @@
8
8
  [![Claude Code](https://img.shields.io/badge/Claude_Code-supported-191919?style=flat&logo=anthropic&logoColor=white)](https://docs.anthropic.com/en/docs/claude-code)
9
9
  [![GitHub Copilot CLI](https://img.shields.io/badge/GitHub_Copilot_CLI-supported-000?style=flat&logo=githubcopilot&logoColor=white)](https://docs.github.com/en/copilot/github-copilot-in-the-cli)
10
10
  [![OpenAI Codex CLI](https://img.shields.io/badge/OpenAI_Codex_CLI-supported-412991?style=flat&logo=openai&logoColor=white)](https://github.com/openai/codex)
11
+ [![OpenCode](https://img.shields.io/badge/OpenCode-supported-f59e0b?style=flat&logo=opencollective&logoColor=white)](https://opencode.ai/)
11
12
  [![Built with Donuts](https://img.shields.io/badge/%F0%9F%8D%A9-Built_with_Donuts-ff6f00?style=flat)](https://github.com/lukas-grigis/ralphctl)
12
13
 
13
14
  <p align="center">
@@ -18,18 +19,15 @@
18
19
 
19
20
  **A ralph harness for long-running AI coding tasks — a hardened ralph loop that drives your coding agent of choice
20
21
  ([Claude Code](https://docs.anthropic.com/en/docs/claude-code),
21
- [GitHub Copilot CLI](https://docs.github.com/en/copilot/github-copilot-in-the-cli), or
22
- [OpenAI Codex CLI](https://github.com/openai/codex)) across one or more repositories.**
22
+ [GitHub Copilot CLI](https://docs.github.com/en/copilot/github-copilot-in-the-cli),
23
+ [OpenAI Codex CLI](https://github.com/openai/codex), or [OpenCode](https://opencode.ai/)) across one or more
24
+ repositories.**
23
25
 
24
26
  > _"I'm helping!"_ — Ralph Wiggum
25
27
 
26
28
  > [!NOTE]
27
- > **Active development.** New features and polish ship regularly. All three providers — Claude Code,
28
- > GitHub Copilot CLI, and OpenAI Codex CLI — are supported; pick one per flow or mix them, in one command,
29
- > from a preset matrix of 20 presets across five families (`standard`, `economic`, `strong-gate`, `fast`,
30
- > `frontier`), each in `mixed` / `claude-only` / `copilot-only` / `codex-only` variants.
31
- > Upgrades are best-effort: install the latest version, redo your config, proceed.
32
- > See [Upgrading](#upgrading) and [CHANGELOG](./CHANGELOG.md).
29
+ > **Active development.** New features and polish ship regularly. Upgrades are best-effort: install the
30
+ > latest version, redo your config, proceed. See [Upgrading](#upgrading) and [CHANGELOG](./CHANGELOG.md).
33
31
 
34
32
  ---
35
33
 
@@ -50,7 +48,7 @@ plan → generate → evaluate → verify loop turns one-shot prompting into a r
50
48
 
51
49
  AI coding agents are powerful but lose context on long tasks, need babysitting when things break, and have no way to
52
50
  coordinate changes across multiple repositories. ralphctl wraps your chosen AI CLI — Claude Code, GitHub Copilot CLI,
53
- or OpenAI Codex CLI — in a
51
+ OpenAI Codex CLI, or OpenCode — in a
54
52
  structured harness that decomposes your work into dependency-ordered tasks, drives each one through
55
53
  a [generator-evaluator loop](https://www.anthropic.com/engineering/harness-design-long-running-apps) that catches issues
56
54
  before moving on, and persists context across sessions so nothing gets lost.
@@ -67,14 +65,32 @@ npm install -g ralphctl
67
65
 
68
66
  > Needs [Node.js](https://nodejs.org/) ≥ 24 — `mise use node@24` or `nvm install 24`.
69
67
 
70
- Install one of the supported CLIs — [Claude Code](https://docs.anthropic.com/en/docs/claude-code),
71
- [GitHub Copilot CLI](https://docs.github.com/en/copilot/github-copilot-in-the-cli), or
72
- [OpenAI Codex CLI](https://github.com/openai/codex) — and authenticate it, then confirm ralphctl can see it:
68
+ Want to poke around before setting up a provider CLI? `ralphctl demo` seeds a throwaway sandbox
69
+ project (three sprints, one per pre-flow state) and launches straight into it — zero setup:
73
70
 
74
71
  ```bash
75
- ralphctl doctor # verifies your provider CLI is installed + authenticated — the #1 first-run failure
72
+ ralphctl demo
76
73
  ```
77
74
 
75
+ Otherwise, install one of the supported CLIs and authenticate it:
76
+
77
+ | CLI | Install | Auth |
78
+ | ---------------------------------------------------------------------------------- | ------------------------------------ | --------------------- |
79
+ | [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | `npm i -g @anthropic-ai/claude-code` | Anthropic account |
80
+ | [GitHub Copilot CLI](https://docs.github.com/en/copilot/github-copilot-in-the-cli) | `npm i -g @github/copilot` | GitHub Copilot seat |
81
+ | [OpenAI Codex CLI](https://github.com/openai/codex) | `npm i -g @openai/codex` | ChatGPT / OpenAI |
82
+ | [OpenCode](https://opencode.ai/) | `npm i -g opencode-ai` | your own key, or none |
83
+
84
+ Then confirm ralphctl can see it:
85
+
86
+ ```bash
87
+ ralphctl doctor # checks your provider CLI is on PATH — and reports auth for the CLIs that can answer — the #1 first-run failure
88
+ ```
89
+
90
+ `doctor`'s auth check is only as honest as each CLI lets it be: Claude Code and OpenAI Codex answer locally via their own
91
+ `auth status` / `login status` verbs, OpenCode reports whether it has a saved credential (its free tier works with zero),
92
+ and GitHub Copilot has no non-interactive auth-status command at all — that row always reports `unknown`, not a guess.
93
+
78
94
  When `doctor` is green, launch:
79
95
 
80
96
  ```bash
@@ -87,7 +103,7 @@ flow (refine / plan / implement / readiness / …), or open the Sprints submenu
87
103
  or create a sprint. No commands to memorize.
88
104
 
89
105
  **Requirements:** [Node.js](https://nodejs.org/) ≥ 24, [Git](https://git-scm.com/), and one supported AI CLI in `PATH`
90
- and authenticated.
106
+ and authenticated (OpenCode takes your own keys, or runs on its free tier with none).
91
107
 
92
108
  <details>
93
109
  <summary>Prefer the CLI for inspection + one-shot operations?</summary>
@@ -120,7 +136,7 @@ ralphctl export-context --sprint <id> --project <id> --output <path>
120
136
 
121
137
  # Settings
122
138
  ralphctl settings show
123
- ralphctl settings apply-preset claude-only # or mixed / copilot-only / codex-only / *-economic / *-strong-gate / *-fast / *-frontier
139
+ ralphctl settings apply-preset claude-only # or mixed / copilot-only / codex-only / opencode-only / *-economic / *-strong-gate / *-fast / *-frontier
124
140
  ralphctl settings set ai.implement.generator.provider claude-code
125
141
  ralphctl settings set ai.implement.generator.model <model-id>
126
142
  ralphctl settings set ai.implement.generator.effort high
@@ -134,19 +150,21 @@ ralphctl settings set ai.implement.evaluator.model <model-id>
134
150
 
135
151
  ## How It Works
136
152
 
137
- ```
138
- You describe what to build ralphctl drives it to done
139
- ───────────────────────── ────────────────────────────────────────────
140
- ┌──────────┐ ┌──────────┐ ┌────────┐ ┌──────┐ ┌───────────┐ ┌────────┐
141
- │ Create │──>│ Add │───────>│ Refine │──>│ Plan │──>│ Implement │──>│ Review │──> done
142
- │ Sprint │ │ Tickets │ │ (WHAT) │ │(HOW) │ │ Loop │ │ Loop │
143
- └──────────┘ └──────────┘ └────────┘ └──────┘ └───────────┘ └────────┘
144
- │ │ │ │
145
- AI clarifies AI builds AI implements you steer
146
- requirements the task + AI reviews revisions,
147
- with you graph each task close to done
153
+ ```mermaid
154
+ flowchart LR
155
+ A[Create sprint] --> B[Add tickets] --> C[Refine] --> D[Plan] --> E[Implement] --> F[Review] --> G[Done]
156
+
157
+ classDef you fill:#eef2ff,stroke:#6366f1,color:#1e1b4b
158
+ classDef ai fill:#ecfdf5,stroke:#10b981,color:#052e16
159
+ classDef end_ fill:#f1f5f9,stroke:#94a3b8,color:#0f172a
160
+ class A,B you
161
+ class C,D,E,F ai
162
+ class G end_
148
163
  ```
149
164
 
165
+ The first two steps are yours (blue); from **Refine** onward ralphctl drives (green), with approval gates where
166
+ your judgement matters.
167
+
150
168
  **Refine** is implementation-agnostic: the AI clarifies requirements with you, ticket by ticket, and flips each one from
151
169
  `pending` to `approved`. **Plan** requires every ticket approved — the AI explores the affected repos and generates a
152
170
  dependency-ordered task graph. **Implement** drives those tasks in dependency order through a generator-evaluator cycle:
@@ -156,13 +174,41 @@ loop — once every task lands, the sprint enters `review` and you run human-ste
156
174
  the AI revises, and the sprint flips to `done` when you're satisfied. Opening a PR (`ralphctl create-pr`) is separate
157
175
  and optional.
158
176
 
177
+ The loop inside **Implement** is what separates a ralph harness from a bare `while` loop — every task passes an
178
+ independent reviewer before the harness moves on:
179
+
180
+ ```mermaid
181
+ flowchart LR
182
+ T[Next task] --> G[Generator] --> E{Evaluator}
183
+ E -->|pass| V{Verify}
184
+ E -->|fail| R[Retry]
185
+ V -->|green| D[Done]
186
+ V -->|red| R
187
+ R --> G
188
+ R -.->|attempts exhausted| B[Blocked]
189
+
190
+ classDef work fill:#ecfdf5,stroke:#10b981,color:#052e16
191
+ classDef gate fill:#fefce8,stroke:#eab308,color:#422006
192
+ classDef ok fill:#f1f5f9,stroke:#94a3b8,color:#0f172a
193
+ classDef bad fill:#fef2f2,stroke:#ef4444,color:#450a0a
194
+ class T,G,R work
195
+ class E,V gate
196
+ class D ok
197
+ class B bad
198
+ ```
199
+
200
+ Both gates send the task back, but they spend different budgets: a failed review re-runs the generator
201
+ _within_ the same attempt (up to `harness.maxTurns` turns), while a red verify fails the attempt outright and
202
+ opens a fresh one (up to `harness.maxAttempts`, after which the task is flagged `blocked`).
203
+
159
204
  Key properties:
160
205
 
161
206
  - **Dependency-ordered execution** — tasks run in topological order; no task starts until its blockers are done.
162
207
  Opt-in parallelism (`concurrency.maxParallelTasks` > 1) runs independent tasks within a dependency wave concurrently,
163
208
  each in its own git worktree folded onto one branch — default stays serial
164
209
  - **Generator-evaluator cycle** — an independent AI reviewer checks each task; if it fails, the generator gets the
165
- critique and iterates (up to `harness.maxAttempts` tries before the task is flagged `blocked`)
210
+ critique and iterates (up to `harness.maxTurns` turns per attempt, across at most `harness.maxAttempts`
211
+ attempts before the task is flagged `blocked`)
166
212
  - **Context persistence** — sprint state, branch, progress history, and per-task context survive across sessions;
167
213
  interrupted runs resume automatically
168
214
  - **Multi-repo support** — one sprint can span several repositories with per-repo setup and verify scripts
@@ -174,26 +220,45 @@ For the full architectural picture see [`.claude/docs/ARCHITECTURE.md`](./.claud
174
220
 
175
221
  ## Providers
176
222
 
177
- ralphctl drives three AI coding CLIs. Choose one per flow — or mix them, say plan with one and implement with
178
- another — through a [preset](#configuration) or per-row settings. All three are supported and in everyday use.
223
+ ralphctl drives four AI coding CLIs. All four run every flow and are supported first-class. Pick one per
224
+ flow — or mix them, say plan with one and implement with another — through a [preset](#configuration) or
225
+ per-row settings.
226
+
227
+ | Provider | CLI | Install | Auth | Context file |
228
+ | ----------------------------------------- | ---------- | ------------------------------------ | --------------------- | --------------------------------- |
229
+ | **Claude Code** (`claude-code`) | `claude` | `npm i -g @anthropic-ai/claude-code` | Anthropic account | `CLAUDE.md` |
230
+ | **GitHub Copilot CLI** (`github-copilot`) | `copilot` | `npm i -g @github/copilot` | GitHub Copilot seat | `.github/copilot-instructions.md` |
231
+ | **OpenAI Codex CLI** (`openai-codex`) | `codex` | `npm i -g @openai/codex` | ChatGPT / OpenAI | `AGENTS.md` |
232
+ | **OpenCode** (`opencode`) | `opencode` | `npm i -g opencode-ai` | your own key, or none | `AGENTS.md` |
233
+
234
+ **Which one?**
235
+
236
+ - **Claude Code** — read-only flows deny the edit, shell and network tools at the CLI level, the finest-grained
237
+ gate of the four.
238
+ - **GitHub Copilot CLI** — no extra billing relationship if you already have a seat. Read-only flows deny the
239
+ shell tool; file writes stay open, bounded by path scope.
240
+ - **OpenAI Codex CLI** — a natural fit inside the ChatGPT/OpenAI ecosystem. Its sandbox has two modes only,
241
+ so path scope is the fine-grained safety envelope.
242
+ - **OpenCode** — vendor-neutral: it fronts 75+ providers and local runtimes on a bring-your-own-key model, so
243
+ you can run a specific model, a local model, or no account at all.
244
+
245
+ On every backend the `Write` tool stays open by design — the harness's `signals.json` lands through it — so
246
+ path scope (cwd + mounted roots) is always part of the safety envelope. See the
247
+ [provider reference](./docs/providers.md#permission-model-per-backend) for the exact mapping.
248
+
249
+ Bundled skill injection and forensic capture work on all four; only the on-disk skills directory differs
250
+ (`.claude/` / `.github/` / `.agents/` / `.opencode/`). Parallel execution is provider-agnostic. Claude Code
251
+ has the most real-world mileage simply because it came first — the others are equally supported, with
252
+ correspondingly less of it.
179
253
 
180
- | Provider | CLI | Headless permission mapping | Native context file |
181
- | ----------------------------------------- | --------- | ----------------------------------------------------------------------------------------------- | --------------------------------- |
182
- | **Claude Code** (`claude-code`) | `claude` | `--permission-mode bypassPermissions` + per-tool deny list | `CLAUDE.md` at repo root |
183
- | **GitHub Copilot CLI** (`github-copilot`) | `copilot` | `--autopilot --max-autopilot-continues=200` + `--allow-all` (per-tool deny list when read-only) | `.github/copilot-instructions.md` |
184
- | **OpenAI Codex CLI** (`openai-codex`) | `codex` | `-s workspace-write` (topology-scoped) | `AGENTS.md` |
254
+ 📖 **[Full provider reference →](./docs/providers.md)** — permission mapping per backend, per-provider setup,
255
+ model ids, mixing backends, and known limitations.
185
256
 
186
- Claude Code has the most end-to-end mileage inside the harness — it's the most battle-tested of the three — but Copilot
187
- and Codex run every flow and are supported first-class. Two small differences worth knowing: bundled skill injection
188
- and `bodyFile` forensic artifacts currently no-op on Copilot and Codex, and Codex's sandbox has only two modes
189
- (read-only / workspace-write), so path scope (cwd + `--add-dir`) is its fine-grained safety envelope rather than a
190
- per-tool deny list. Parallel execution is provider-agnostic — it works with whichever provider each implement role is
191
- configured to use. Hit a rough edge with any provider? Please [open an
192
- issue](https://github.com/lukas-grigis/ralphctl/issues).
257
+ Hit a rough edge with any provider? Please [open an issue](https://github.com/lukas-grigis/ralphctl/issues).
193
258
 
194
- One-shot configuration for any provider: `ralphctl settings apply-preset <name>` where `<name>` is one of
195
- 20 presets across five families — `standard`, `economic`, `strong-gate`, `fast`, and `frontier`, each in
196
- `mixed` / `claude-only` / `copilot-only` / `codex-only` variants.
259
+ One-shot configuration: `ralphctl settings apply-preset <name>` where `<name>` is one of 21 presets —
260
+ `standard`, `economic`, `strong-gate`, `fast`, and `frontier` families, each in `mixed` / `claude-only` /
261
+ `copilot-only` / `codex-only` variants, plus `opencode-only`.
197
262
 
198
263
  ---
199
264
 
@@ -215,6 +280,8 @@ One-shot configuration for any provider: `ralphctl settings apply-preset <name>`
215
280
  first — the crashed attempt is settled as aborted (kept in history) and a fresh attempt opens automatically
216
281
  - **Pair or let it run** — work alongside your AI agent interactively, or let it execute unattended
217
282
  - **Zero-memorization start** — run `ralphctl` with no args for a guided menu
283
+ - **Bring your own model** — four backends to choose from, one of which (OpenCode) is vendor-neutral, so the
284
+ harness reaches hosted, aggregated, and local models alike
218
285
 
219
286
  ---
220
287
 
@@ -226,7 +293,7 @@ Configure via the TUI `Settings` view or one-shot CLI commands.
226
293
  `apply-preset`.
227
294
 
228
295
  <details>
229
- <summary>All 20 presets across five families</summary>
296
+ <summary>All 21 presets</summary>
230
297
 
231
298
  ```bash
232
299
  # Standard — flagship model per flow
@@ -234,6 +301,7 @@ ralphctl settings apply-preset mixed # best-fit provider per flow
234
301
  ralphctl settings apply-preset claude-only # every flow on Claude Code
235
302
  ralphctl settings apply-preset copilot-only # every flow on GitHub Copilot CLI
236
303
  ralphctl settings apply-preset codex-only # every flow on OpenAI Codex CLI
304
+ ralphctl settings apply-preset opencode-only # every flow on OpenCode's free tier (no auth)
237
305
 
238
306
  # Economic — implement starts one tier below flagship; escalation ladder climbs only on plateau
239
307
  ralphctl settings apply-preset mixed-economic
@@ -260,7 +328,9 @@ ralphctl settings apply-preset copilot-frontier
260
328
  ralphctl settings apply-preset codex-frontier
261
329
  ```
262
330
 
263
- Twenty presets across five families ship, all equally first-class — none is marked default. Applying a
331
+ Twenty-one presets ship, all equally first-class — none is marked default. `opencode-only` sits outside the
332
+ five-family grid on purpose: every free-tier model is at the same (zero) price point, so `economic` / `frontier`
333
+ variants of it would differ in name only. Applying a
264
334
  preset stamps the entire `ai` section plus `harness.escalateOnPlateau` in one transaction (`fast` stamps it
265
335
  `false` so a plateau settles; all others stamp it `true`). On a fresh install the welcome view silently
266
336
  auto-seeds a preset based on which provider CLIs it detects on `PATH`.
@@ -318,6 +388,7 @@ export RALPHCTL_HOME="/path/to/custom/dir"
318
388
  | ---------------------------- | -------------- | ---------------------------------------------------- |
319
389
  | `RALPHCTL_HOME` | `~/.ralphctl/` | Override application root (data + config + state) |
320
390
  | `RALPHCTL_SKIP_LEGACY_CHECK` | unset | Bypass the v0.6.x legacy-layout detector at boot |
391
+ | `RALPHCTL_DEBUG_TRACE` | unset | Write a `<sprintDir>/events.ndjson` debug trace |
321
392
  | `RALPHCTL_NO_TUI` | unset | Suppress implicit interactive prompts in `implement` |
322
393
  | `NO_COLOR` | unset | Suppress ANSI colors |
323
394
  | `CI` | auto-detected | Suppress implicit interactive prompts in `implement` |
@@ -360,14 +431,17 @@ readiness / create sprint) stay TUI-only by design. The CLI exposes inspection +
360
431
 
361
432
  ### Getting Started
362
433
 
363
- | Command | Description |
364
- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
365
- | `ralphctl` | Interactive TUI (primary surface) |
366
- | `ralphctl doctor` | Check environment health |
367
- | `ralphctl settings show` | Print current settings |
368
- | `ralphctl settings set <key> <value>` | Set a single settings key |
369
- | `ralphctl settings apply-preset <name>` | Stamp the entire `ai` section — 20 presets across five families: `standard` / `economic` / `strong-gate` / `fast` / `frontier`, each in `mixed` / `*-only` / `*-economic` / `*-strong-gate` / `*-fast` / `*-frontier` variants |
370
- | `ralphctl completion <shell>` | Print shell tab-completion script |
434
+ | Command | Description |
435
+ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
436
+ | `ralphctl` | Interactive TUI (primary surface) |
437
+ | `ralphctl demo` | Seed a throwaway sandbox project and launch straight into it — zero setup, no provider CLI required to look around (`--no-launch` to seed only, `--home <dir>` to relocate) |
438
+ | `ralphctl doctor` | Check environment health |
439
+ | `ralphctl settings show` | Print current settings |
440
+ | `ralphctl settings set <key> <value>` | Set a single settings key |
441
+ | `ralphctl settings apply-preset <name>` | Stamp the entire `ai` section — 21 presets: `standard` / `economic` / `strong-gate` / `fast` / `frontier` families, each in `mixed` / `*-only` variants, plus `opencode-only` |
442
+ | `ralphctl completion <shell>` | Print shell tab-completion script |
443
+ | `ralphctl agents list` | List bundled + operator agent definitions and the implement role each is bound to |
444
+ | `ralphctl skills list` | List bundled + manually-dropped skills — tier, enabled flows, provenance |
371
445
 
372
446
  ### Project & Sprint Inspection
373
447
 
@@ -384,6 +458,7 @@ readiness / create sprint) stay TUI-only by design. The CLI exposes inspection +
384
458
  | `ralphctl ticket list / show <id>` | Inspect tickets |
385
459
  | `ralphctl ticket remove <id>` | Remove a ticket from a draft sprint |
386
460
  | `ralphctl task list / show <id>` | Inspect tasks (planning generates them) |
461
+ | `ralphctl task evaluation <id>` | Print the latest evaluator verdict (`evaluation.md`) for the task's last attempt |
387
462
  | `ralphctl task unblock <id>` | Reset a blocked task to `todo` |
388
463
 
389
464
  ### Sprint Lifecycle
@@ -404,10 +479,11 @@ readiness / create sprint) stay TUI-only by design. The CLI exposes inspection +
404
479
 
405
480
  ### Maintenance
406
481
 
407
- | Command | Description |
408
- | ------------------------------------------------------------------------------------------ | ----------------------------------------------- |
409
- | `ralphctl runs list [--flow <name>]` | List per-run forensic artifacts grouped by flow |
410
- | `ralphctl runs prune [--older-than 7d] [--keep-last <n>] [--flow <name>] [--dry-run] [-y]` | Delete per-run forensic artifacts |
482
+ | Command | Description |
483
+ | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ |
484
+ | `ralphctl runs list [--flow <name>]` | List per-run forensic artifacts grouped by flow |
485
+ | `ralphctl runs stats [--sprint <id>] [--project <id>] [--since <date>] [--json]` | Harness outcome rollup — outcome mix, first-pass rate, plateaus, escalation efficacy |
486
+ | `ralphctl runs prune [--older-than 7d] [--keep-last <n>] [--flow <name>] [--dry-run] [-y]` | Delete per-run forensic artifacts |
411
487
 
412
488
  Run `ralphctl <command> --help` for flag-level detail.
413
489
 
@@ -420,6 +496,7 @@ Run `ralphctl <command> --help` for flag-level detail.
420
496
  | Resource | Description |
421
497
  | ------------------------------------------------ | -------------------------------------------------------- |
422
498
  | [Architecture](./ARCHITECTURE.md) | Data models, harness loop, file storage, error reference |
499
+ | [Providers](./docs/providers.md) | Per-backend setup, permission mapping, model ids, limits |
423
500
  | [Adding a provider](./docs/adding-a-provider.md) | Extension guide: wire a new AI CLI into the harness |
424
501
  | [Requirements](./.claude/docs/REQUIREMENTS.md) | Acceptance criteria and feature checklist |
425
502
  | [Contributing](./CONTRIBUTING.md) | Dev setup, code style, PR process |