From a95999841706fc8fb33fd7466e04315e60b4526b Mon Sep 17 00:00:00 2001 From: ruv Date: Sun, 4 Oct 2026 22:03:45 -0400 Subject: [PATCH] docs(adr): mod-system ADR index, status/date/cross-link corrections, ADR link check Index of ADRs 404-451 with status, builds-on, PR and tests. Corrects ADR-404/444/447 statuses that contradicted shipped code, 444-446 dates (committed 2026-10-04), stale follow-ups in 446/448, adds superseded-in-part back-links (422, 424, 430 amendments) and scripts/check-adr-links.mjs (+node:test) for broken links and duplicate numbers. Co-Authored-By: RuFlo --- scripts/check-adr-links.mjs | 81 +++++++++++++++++++ scripts/check-adr-links.test.mjs | 48 +++++++++++ ...ADR-404-claude-code-mods-function-hooks.md | 2 +- ...-cards-grouped-nav-and-page-scoped-asks.md | 2 + ...ADR-424-console-compact-nav-with-search.md | 2 + v3/docs/adr/ADR-430-console-menu-design.md | 5 ++ .../ADR-444-claude-controls-the-console.md | 4 +- v3/docs/adr/ADR-445-agentdb-as-a-mod.md | 8 +- v3/docs/adr/ADR-446-plugins-as-mods.md | 6 +- ...47-native-mod-guidance-observation-loop.md | 4 +- ...8-console-the-room-shared-activity-feed.md | 4 +- v3/docs/adr/INDEX-mod-system.md | 73 +++++++++++++++++ 12 files changed, 226 insertions(+), 13 deletions(-) create mode 100644 scripts/check-adr-links.mjs create mode 100644 scripts/check-adr-links.test.mjs create mode 100644 v3/docs/adr/INDEX-mod-system.md diff --git a/scripts/check-adr-links.mjs b/scripts/check-adr-links.mjs new file mode 100644 index 0000000000..91f2b03320 --- /dev/null +++ b/scripts/check-adr-links.mjs @@ -0,0 +1,81 @@ +#!/usr/bin/env node +// Checks the 4xx ADRs under v3/docs/adr: no duplicate ADR number, every relative markdown link resolves, and every +// ADR named on a "Builds on / Extends / Supersedes" header line exists. Exit 1 on any finding. +import { existsSync, readdirSync, readFileSync } from 'node:fs' +import { dirname, join, resolve } from 'node:path' +import { fileURLToPath } from 'node:url' + +export const ADR_DIR = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'v3', 'docs', 'adr') + +// Number -> how many files may share it. 430 has two files (the menu accents ADR and the menu-design amendments); +// renumbering one would break the code comments that cite "ADR-430" for either. New duplicates still fail. +export const KNOWN_DUPLICATES = { 430: 2 } + +const FILE = /^ADR-(4\d\d)-.+\.md$/ +const RELATION = /^\s*(builds on|extends|supersedes|superseded by|complements)\b[^\n]*/gim + +const stripCode = text => text.replace(/^(```|~~~)[\s\S]*?^\1[^\n]*$/gm, '').replace(/`[^`\n]*`/g, '') + +export function listAdrs(dir = ADR_DIR) { + return readdirSync(dir).filter(f => FILE.test(f)).sort().map(f => ({ file: f, number: Number(FILE.exec(f)[1]) })) +} + +export function checkDuplicates(adrs, known = KNOWN_DUPLICATES) { + const byNumber = new Map() + for (const a of adrs) byNumber.set(a.number, [...(byNumber.get(a.number) ?? []), a.file]) + const out = [] + for (const [n, files] of byNumber) if (files.length > (known[n] ?? 1)) out.push(`duplicate ADR number ${n}: ${files.join(', ')}`) + return out +} + +export function relativeLinks(markdown) { + const out = [] + for (const m of stripCode(markdown).matchAll(/\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g)) { + const target = m[1] + if (/^([a-z][a-z0-9+.-]*:|#|\/\/)/i.test(target)) continue + out.push(target.split('#')[0]) + } + return out.filter(Boolean) +} + +export function checkLinks(adrs, dir = ADR_DIR) { + const out = [] + for (const a of adrs) { + for (const target of relativeLinks(readFileSync(join(dir, a.file), 'utf8'))) { + if (!existsSync(resolve(dir, decodeURIComponent(target)))) out.push(`${a.file}: broken relative link ${target}`) + } + } + return out +} + +export function relatedNumbers(markdown) { + const out = [] + for (const m of markdown.matchAll(RELATION)) { + // "ruOS ADR-043" names another repo's ADR, not one of ours. + const line = m[0].replace(/\bruOS ADR[- ]?\d+/gi, '') + for (const n of line.matchAll(/\bADR[- ]?(\d{3})|(?<=\d{3}[A-Z]?\/)(\d{3})\b/g)) out.push(Number(n[1] ?? n[2])) + } + return [...new Set(out)] +} + +export function checkRelations(adrs, dir = ADR_DIR) { + const known = new Set(readdirSync(dir).map(f => /^ADR-(\d+)/.exec(f)?.[1]).filter(Boolean).map(Number)) + const out = [] + for (const a of adrs) { + const header = readFileSync(join(dir, a.file), 'utf8').split('\n').slice(0, 14).join('\n') + for (const n of relatedNumbers(header)) if (!known.has(n)) out.push(`${a.file}: relation line names ADR ${n}, which has no file`) + } + return out +} + +export function run(dir = ADR_DIR) { + const adrs = listAdrs(dir) + return [...checkDuplicates(adrs), ...checkLinks(adrs, dir), ...checkRelations(adrs, dir)] +} + +if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { + const findings = run() + for (const f of findings) console.error(f) + console.log(findings.length ? `${findings.length} ADR finding(s)` : `ok: ${listAdrs().length} ADRs checked`) + process.exit(findings.length ? 1 : 0) +} diff --git a/scripts/check-adr-links.test.mjs b/scripts/check-adr-links.test.mjs new file mode 100644 index 0000000000..8ede4a2f71 --- /dev/null +++ b/scripts/check-adr-links.test.mjs @@ -0,0 +1,48 @@ +import assert from 'node:assert/strict' +import { mkdtempSync, rmSync, writeFileSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import test from 'node:test' +import { checkDuplicates, checkLinks, checkRelations, listAdrs, relatedNumbers, relativeLinks, run } from './check-adr-links.mjs' + +function fixture(files) { + const dir = mkdtempSync(join(tmpdir(), 'adr-check-')) + for (const [name, body] of Object.entries(files)) writeFileSync(join(dir, name), body) + return dir +} + +test('the real ADR directory is clean', () => { + assert.deepEqual(run(), []) +}) + +test('a duplicate ADR number fails, a known one does not', () => { + const dir = fixture({ 'ADR-401-a.md': '#', 'ADR-401-b.md': '#', 'ADR-430-a.md': '#', 'ADR-430-b.md': '#', 'ADR-430-c.md': '#' }) + try { + const found = checkDuplicates(listAdrs(dir)) + assert.equal(found.length, 2) + assert.match(found[0], /401/) + assert.match(found[1], /430/) + assert.deepEqual(checkDuplicates(listAdrs(dir).filter(a => a.file !== 'ADR-430-c.md')).filter(f => /430/.test(f)), []) + } finally { rmSync(dir, { recursive: true }) } +}) + +test('a broken relative link fails; urls, anchors, code and fences are ignored', () => { + const body = [ + '# ADR 410', '', '[ok](ADR-411-b.md#sec) [bad](missing.md) [web](https://x.test/a.md) [here](#top)', + '`[inline](nope.md)`', '```', '[fenced](nope2.md)', '```', + ].join('\n') + const dir = fixture({ 'ADR-410-a.md': body, 'ADR-411-b.md': '# b' }) + try { + assert.deepEqual(relativeLinks(body), ['ADR-411-b.md', 'missing.md']) + assert.deepEqual(checkLinks(listAdrs(dir), dir), ['ADR-410-a.md: broken relative link missing.md']) + } finally { rmSync(dir, { recursive: true }) } +}) + +test('relation lines name existing ADRs; other repos\' ADRs are not ours', () => { + assert.deepEqual(relatedNumbers('Builds on: ADR-406 (missions), ADR 437 and ADR-441\nStatus: ADR-999'), [406, 437, 441]) + assert.deepEqual(relatedNumbers('Extends: ADR 404. Preserves ADR 322A, and ADR 324/325; ruOS ADR-043'), [404, 322, 324, 325]) + const dir = fixture({ 'ADR-410-a.md': '# t\n\nBuilds on: ADR-411, ADR-499\n', 'ADR-411-b.md': '# b' }) + try { + assert.deepEqual(checkRelations(listAdrs(dir), dir), ['ADR-410-a.md: relation line names ADR 499, which has no file']) + } finally { rmSync(dir, { recursive: true }) } +}) diff --git a/v3/docs/adr/ADR-404-claude-code-mods-function-hooks.md b/v3/docs/adr/ADR-404-claude-code-mods-function-hooks.md index 17ede6c203..7e9efe74c9 100644 --- a/v3/docs/adr/ADR-404-claude-code-mods-function-hooks.md +++ b/v3/docs/adr/ADR-404-claude-code-mods-function-hooks.md @@ -1,6 +1,6 @@ # ADR 404: Ruflo as a Claude Code Mod (Function Hooks) -Status: Proposed +Status: Accepted (implemented in plugins/ruflo-mods, PR #3608; the follow-ups listed below remain open) Date: 2026 10 01 diff --git a/v3/docs/adr/ADR-422-console-cards-grouped-nav-and-page-scoped-asks.md b/v3/docs/adr/ADR-422-console-cards-grouped-nav-and-page-scoped-asks.md index 31252f5671..ec5e34cb9d 100644 --- a/v3/docs/adr/ADR-422-console-cards-grouped-nav-and-page-scoped-asks.md +++ b/v3/docs/adr/ADR-422-console-cards-grouped-nav-and-page-scoped-asks.md @@ -10,6 +10,8 @@ Scope: `plugins/ruflo-console`: `hooks/views/card.ts`, `hooks/views/marks.ts`, ` Extends: ADR 407, ADR 412 (answers open where they were asked). Companion to ADR 421 (the boot screen). +Superseded in part by: ADR 424 (the nav card is now the compact nav). + ## 1. Context A page was a long column of rows with a ruled heading between its sections. Where one section ended and the next began was a thin line; the flat tab bar listed some views by icon and hid the rest behind the main menu; and an ask raised on one page (for example Mission Control's "ask claude -p for guidance") was drawn in full on every page you moved to, above the content, with a Yes button that answered a question you were no longer looking at. diff --git a/v3/docs/adr/ADR-424-console-compact-nav-with-search.md b/v3/docs/adr/ADR-424-console-compact-nav-with-search.md index 01acec7165..2635b2e05d 100644 --- a/v3/docs/adr/ADR-424-console-compact-nav-with-search.md +++ b/v3/docs/adr/ADR-424-console-compact-nav-with-search.md @@ -10,6 +10,8 @@ Scope: `plugins/ruflo-console`: `hooks/nav-state.ts`, `hooks/views/nav.ts`, `hoo Extends: ADR 422 (cards and the grouped nav), which this replaces for the nav card. +Superseded in part by: ADR 442 (the Plugins page sits in TOOLS, not NETWORK). + ## 1. Context The grouped nav of ADR 422 listed every page at once: a title row with the style chooser, then a row per group, nine rows in a bordered card at 100 columns. It was complete but long, and finding a page meant reading all of it. diff --git a/v3/docs/adr/ADR-430-console-menu-design.md b/v3/docs/adr/ADR-430-console-menu-design.md index 86cbd4ec61..6f58e6c015 100644 --- a/v3/docs/adr/ADR-430-console-menu-design.md +++ b/v3/docs/adr/ADR-430-console-menu-design.md @@ -1,3 +1,8 @@ +# ADR 430 (amendments): The main menu design, as it changed on 2026 10 03 + +Status: Accepted (ships in ruflo-console 0.26.0) + +Companion to ADR 430 (the menu's accents, chips and badges); both files carry the number 430. Extends: ADR 407 (the cockpit). Superseded in part by: ADR 442 (the Plugins page sits in TOOLS, not NETWORK). ## Amendment (2026 10 03): narrow panes keep their styling, and the groups fold diff --git a/v3/docs/adr/ADR-444-claude-controls-the-console.md b/v3/docs/adr/ADR-444-claude-controls-the-console.md index 719d5a69f8..1571c4a2b5 100644 --- a/v3/docs/adr/ADR-444-claude-controls-the-console.md +++ b/v3/docs/adr/ADR-444-claude-controls-the-console.md @@ -1,8 +1,8 @@ # ADR 444: Claude controls the console: model tools, an autonomy level and a live dashboard -Status: Proposed +Status: Accepted (implemented in ruflo-console 0.30.0, PR #3696; the autopilot default of section 6 shipped in 0.32.0) -Date: 2026 10 05 +Date: 2026 10 04 Scope: `plugins/ruflo-console` (new `model-tools.ts`, `views/control.ts`; `register.ts`, `settings.ts`, `state.ts`, `scripts/smoke.sh`, `scripts/e2e-control.sh`) diff --git a/v3/docs/adr/ADR-445-agentdb-as-a-mod.md b/v3/docs/adr/ADR-445-agentdb-as-a-mod.md index 1751ea6976..f1106d51b0 100644 --- a/v3/docs/adr/ADR-445-agentdb-as-a-mod.md +++ b/v3/docs/adr/ADR-445-agentdb-as-a-mod.md @@ -2,7 +2,7 @@ Status: Accepted (implemented in ruflo-agentdb 0.4.0 and ruflo-console 0.31.0) -Date: 2026 10 05 +Date: 2026 10 04 Scope: `plugins/ruflo-agentdb` (new function-hook mod: `hooks/*.ts`, `scripts/bench.mjs`, `tests/`), `plugins/ruflo-console` (a status reader and an "AgentDB mod" section on the Memory page, a Help guide) @@ -12,13 +12,13 @@ Builds on: ADR-404 (ruflo as a mod), ADR-444 (the model-tool and level pattern) `ruflo-agentdb` was skills and commands over the 15 `agentdb_*` MCP tools: a person (or Claude, when told) asks, the tools answer. The console's Memory Lab already drives them by hand. Nothing happened *automatically*, and nothing watched what Claude writes into memory. A mod can do both inside the session: bring relevant memory into a prompt without being asked, and refuse to let secrets be stored. -## 2. Review of the packages (2026-10-05) +## 2. Review of the packages (2026-10-04) | | `agentdb` | `ruvector` | |---|---|---| | Latest | 3.0.0-alpha.20 (2026-07-30), `latest` and `alpha` tags | 0.3.3 (2026-09-23) | | What ruflo uses | `^3.0.0-alpha.17`, which resolves to alpha.20 | CLI pins `^0.2.27`, which for a 0.x package **excludes 0.3**; the `ruflo-ruvector` plugin hard-codes `ruvector@0.2.25` in 117 places | -| Useful to a mod | `query --synthesize-context`, `recall with-certificate` (retrieval with a causal-utility score and a **provenance certificate**), `store-pattern`, `route --prompt`, reflexion, skill and causal commands, `mcp start` | `hooks recall / remember / rag-context / suggest-context`, `reembed` (embedding provenance, ADR-210), an MCP server of 97 tools with a **default-deny policy** (`RUVECTOR_MCP_ALLOW`, `RUVECTOR_MCP_DENY`, `RUVECTOR_MCP_PROFILE=readonly`, ADR-256) | +| Useful to a mod | `query --synthesize-context`, `recall with-certificate` (retrieval with a causal-utility score and a **provenance certificate**), `store-pattern`, `route --prompt`, reflexion, skill and causal commands, `mcp start` | `hooks recall / remember / rag-context / suggest-context`, `reembed` (embedding provenance, ruvector ADR-210), an MCP server of 97 tools with a **default-deny policy** (`RUVECTOR_MCP_ALLOW`, `RUVECTOR_MCP_DENY`, `RUVECTOR_MCP_PROFILE=readonly`, ruvector ADR-256) | | Kept out on purpose | `sync start-server` / `connect` (QUIC, network) | `brain` (a shared, network knowledge base), `edge`, `server`, `cluster` | Measured here (warm `npx`, five runs): `agentdb status` 0.48 to 0.56 s, `ruvector hooks recall` 0.41 to 0.47 s, against 22 ms for a bare Node start. A CLI call on every prompt costs about half a second; an already-connected MCP tool answers without the process start. **Decision: the mod calls the connected MCP tool in-process, and uses a CLI only as a deadline-bounded fallback.** @@ -53,7 +53,7 @@ Settings are the plugin's `userConfig`, which the console's Settings page alread - Moving the ruflo CLI to `ruvector` 0.3.x. - Use of `recall with-certificate` provenance certificates in the frame (the CLI has it; whether a connected tool exposes it is UNVERIFIED). -## 6. Result (2026-10-05) +## 6. Result (2026-10-04) - Implemented as designed: `hooks/{options,screen,recall,tools,guard,command,status,register}.ts`, all under 120 lines; `claude plugin validate` lists the hooks (`session.start`, `prompt.submit`, `tool.call`, `command.run`) and only `$.clock`, `$.command`, `$.fs.write`, `$.mcp.call`, `$.session.root`, `$.tool.list` as calls: no `$.http`, no `$.process`. - **The mod reads memory with `$.mcp.call`** on the connected server (the name is split out of `$.tool.list()`), so it needs no CLI and is not blocked by a permission prompt; `hooks_recall` / `agentdb_hierarchical-recall` / `agentdb_pattern-search` take `query` and `topK` (checked against the tool schemas). diff --git a/v3/docs/adr/ADR-446-plugins-as-mods.md b/v3/docs/adr/ADR-446-plugins-as-mods.md index 9dbe72a8cc..1cebc606d0 100644 --- a/v3/docs/adr/ADR-446-plugins-as-mods.md +++ b/v3/docs/adr/ADR-446-plugins-as-mods.md @@ -2,7 +2,7 @@ Status: Accepted (implemented in 39 plugins, each bumped one minor version) -Date: 2026 10 05 +Date: 2026 10 04 Builds on: ADR-404 (ruflo as a mod), ADR-445 (AgentDB as a mod) @@ -22,7 +22,7 @@ Eight headless workers, each in its own git worktree and branch from main, each ## 3. Consequences and follow-ups -- Each mod carries its own copy of the small secret screen from ADR-445 (`screen.ts`): plugins install as separate directories, so there is nowhere shared to import from. A fix to the screen must be applied in each copy; the follow-up is a generator or a shared package that is vendored at release. -- 39 more slash commands (`/…-mod`) and 39 small status files per project. The console does not list them yet. +- Each mod carries its own copy of the small secret screen from ADR-445 (`screen.ts`): plugins install as separate directories, so there is nowhere shared to import from. A fix to the screen must be applied in each copy. Since PR #3711, `scripts/sync-mod-screen.mjs` regenerates the shared region of each copy from one source and the all-plugins smoke runs it with `--check`. +- 39 more slash commands (`/…-mod`) and 39 small status files per project. The console lists them from ruflo-console 0.33.1 (PR #3707, a Mods section on the Room and a count on Overview). - The guards watch tool names by string; a tool renamed in the CLI silently stops being guarded. A fleet check that every watched name exists in the tool registry is a follow-up (a spot check found only prefixes and tools served by other MCP servers missing). - Workers shared `/tmp/modgen` and one overwrote another's generator; their generated output was unaffected, but the next fan-out should give each worker a private scratch directory. diff --git a/v3/docs/adr/ADR-447-native-mod-guidance-observation-loop.md b/v3/docs/adr/ADR-447-native-mod-guidance-observation-loop.md index b77373ea62..ded181613d 100644 --- a/v3/docs/adr/ADR-447-native-mod-guidance-observation-loop.md +++ b/v3/docs/adr/ADR-447-native-mod-guidance-observation-loop.md @@ -1,8 +1,10 @@ # ADR-447: Native mod guidance and observation loop Date: 2026-10-04 -Status: Proposed +Status: Accepted (implemented in ruflo-mods 0.2.0 and the CLI guidance adapter, PR #3702) Scope: ruflo-mods and the Guidance Control Plane CLI adapter +Builds on: ADR-404 (ruflo as a mod), ADR-445 (AgentDB as a mod), ADR-322A (evaluation and promotion) +Followed by: ADR-449 (the evaluator and promotion contracts this ADR defers to), ADR-450 (threat model), ADR-451 (capability roadmap) ## Context diff --git a/v3/docs/adr/ADR-448-console-the-room-shared-activity-feed.md b/v3/docs/adr/ADR-448-console-the-room-shared-activity-feed.md index 7829772e7d..a2b480cb0c 100644 --- a/v3/docs/adr/ADR-448-console-the-room-shared-activity-feed.md +++ b/v3/docs/adr/ADR-448-console-the-room-shared-activity-feed.md @@ -4,7 +4,7 @@ Status: Accepted (implemented in ruflo-console 0.33.0; §3.2, the expiry event, Date: 2026 10 04 -Scope: `plugins/ruflo-console`: new `hooks/views/room.ts`, `hooks/data/room.ts`; edits to `hooks/state.ts` (`ViewId`, `VIEWS`, `Pending`), `hooks/views/pane.ts` (`BODIES`), `hooks/runner.ts` (`ask`), `hooks/palette.ts` (three new ids), `hooks/model-tools.ts` (`console_state` reads the new feed). +Scope: `plugins/ruflo-console`: new `hooks/views/room.ts`, `hooks/data/room.ts`, `hooks/room.ts`; edits to `hooks/state.ts` (`ViewId`, `VIEWS`, `Pending`), `hooks/views/pane.ts` (`BODIES`), `hooks/runner.ts` (`ask`), `hooks/palette.ts` (three new ids), `hooks/model-tools.ts` (`console_state` reads the new feed). Builds on: ADR 407 (cockpit), ADR 416 (Timeline and Events — read-only, per-page), ADR 444 (Claude controls the console — the model tools and the pending-confirm contract this ADR extends). @@ -61,7 +61,7 @@ An expired confirm must leave a trace. `confirm()` (`runner.ts:147-150`) gains o - Queuing more than one pending confirm. - Changing the 30 s TTL. - A feed entry becoming clickable the way an Events line is (ADR 416 §2.2) — likely yes, deferred to keep this ADR's diff to the merge, not new interaction. -- Whether `room` joins `CORE_TABS` (`pane.ts:55`, the keyless-view tab set) — a design call for whoever builds it, not an architectural one. +- Whether `room` joins `CORE_TABS` (the keyless-view tab set) — a design call for whoever builds it, not an architectural one. (Built in 0.33.0: `room` is in `CORE_TABS`, `hooks/views/pane.ts:57`.) ## 6. Consequences diff --git a/v3/docs/adr/INDEX-mod-system.md b/v3/docs/adr/INDEX-mod-system.md new file mode 100644 index 0000000000..1a8f59e0d3 --- /dev/null +++ b/v3/docs/adr/INDEX-mod-system.md @@ -0,0 +1,73 @@ +# Index: the mod-system ADRs (404 to 451) + +Checked 2026-10-04 against `main` at b4ba5a6c2. "PR" is the merged pull request that added the ADR file (found with `gh api repos/ruvnet/ruflo/commits//pulls`); "Shipped in" is the version the ADR's own status line names, confirmed against the `version` in the plugin's `plugin.json` at the commit that added the ADR or its code. "Tests" are test files the ADR names or that the commit implementing it added (console tests are in `plugins/ruflo-console/tests/`, `.spec.ts` unless noted). `—` means the ADR does not say. `node scripts/check-adr-links.mjs` checks the links, the relation lines and the numbering of the 4xx files. + +Two files carry the number 430 (the menu's accents, and the menu-design amendments); `scripts/check-adr-links.mjs` allows exactly that pair. + +## The mod platform and the plugin fleet + +| ADR | Title | Status | Date | Builds on / extends | Superseded by | PR | Shipped in | Tests | +|---|---|---|---|---|---|---|---|---| +| 404 | Ruflo as a Claude Code mod (function hooks) | Accepted | 10-01 | related 150, 174, 324, 405 | — | #3608 | ruflo-mods (0.2.0 now) | `bench-mods-latency.ts`, mods suites | +| 405 | ruOS desktops as swarm execution hosts | Proposed | 10-01 | related 150, 324, 325 | — | #3605 | ruflo-ruos 0.1.0 (status not updated) | `smoke.sh` | +| 445 | AgentDB as a mod: safe recall, a write guard, `/agentdb-mod` | Accepted | 10-04 | 404, 444 | — | #3697 | ruflo-agentdb 0.4.0, console 0.31.0 | `agentdb-mod.spec.ts`, plugin tests, `bench.mjs` | +| 446 | The plugin fleet as mods (39 plugins) | Accepted | 10-04 | 404, 445 | — | #3700 | 39 plugins; 44 plugins have a mod today | per-plugin `claude plugin test`, `smoke-all-plugins` | +| 447 | Native mod guidance and observation loop | Accepted | 10-04 | 404, 445, 322A | — | #3702 | ruflo-mods 0.2.0 + CLI `guidance` adapter | `guidance.test.ts`, `mods-guidance-e2e.test.ts`, workflow `mod-guidance.yml` | +| 449 | Guidance learning loop on the mod system | Proposed | 10-04 | 404, 447, 322A/C, 446 | — | not merged (branch `loop/adr-guidance`) | — | — | +| 450 | Threat model of the mod system | Proposed | 10-05 (see note) | 404, 444, 445, 446, 447, 448 | — | not merged (branches `loop/sec-threat`, `loop/sec-console`, `loop/autopilot-limits`) | — | `threat-model.spec.ts`, `threat.test.ts` | +| 451 | Mod capability roadmap | Proposed | 10-04 | 404, 445, 446, 447 | — | not merged (branch `loop/research-roadmap`) | — | — | + +## Console: mission control and Claude control + +| ADR | Title | Status | Date | Builds on / extends | Superseded by | PR | Shipped in | Tests | +|---|---|---|---|---|---|---|---|---| +| 406 | Mission control through compatible mods | Proposed | 10-01 | extends 404; complements 405 | — | #3617 | partly (console missions, see note) | — | +| 407 | The ruflo-console cockpit | Accepted | 10-02 | extends 404, 406 | — | #3634 | console 0.6.2 | `conformance`, `smoke.sh`, `sweep.test.ts` | +| 408 | Mission Control in the cockpit | Accepted | 10-02 | extends 406, 407 | — | #3640 | console 0.11.0 | `ask-claude`, `goap`, `e2e-smoke.sh` | +| 409 | The planner and the one lifecycle | Accepted | 10-03 | extends 406, 407; detail of 408 | — | #3647 | console 0.14.x | `mission-control`, `mission-review` | +| 410 | Claude's guidance and the AIDefence screen | Accepted | 10-03 | extends 409 | — | #3647 | console 0.14.x | `mission-guidance`, `mission-review` | +| 411 | The Claude UI bridge: Ask, Launch, plugin map | Accepted | 10-03 | extends 407 | — | #3647 | console 0.14.x | `ask-claude`, `plugin-coverage` | +| 412 | Answers open where they were asked | Accepted | 10-03 | extends 407 | — | #3647 | console 0.14.x | `attention.test.ts`, `labs.test.ts` | +| 413 | The regression system | Accepted | 10-03 | extends 407 | — | #3647 | console 0.14.x | `smoke.sh`, `e2e-smoke.sh` | +| 414 | The Loop Manager | Accepted | 10-03 | extends 411 | — | #3647 | console 0.15.0 | `loops` | +| 415 | The Learning page and the Optimizer | Accepted | 10-03 | extends 412 | — | #3647 | console 0.16.0, 0.17.0 | `learning`, `optimizer` | +| 416 | Timeline and Events | Accepted | 10-03 | extends 407 | — | #3648 | console 0.18.0 | `watch` | +| 417 | The AgentBBS section | Accepted | 10-03 | extends 407 | — | #3651 | console 0.19.0 | `agentbbs`, `xruv.test.ts` | +| 418 | Tool rows name their mission task | Accepted | 10-03 | extends 407, 409 | — | #3652 | console 0.20.0 | `tool-owner` | +| 419 | AgentDB reads in the Memory Lab, coverage audit | Accepted | 10-03 | extends 407, 411 | — | #3653 | console 0.21.0 | `memory-lab` | +| 420 | Tool-coverage audit and a live smoke | Accepted | 10-03 | extends 407, 411, 413, 419 | — | #3655 | console 0.21.0 | `e2e-smoke.sh` | +| 421 | The boot screen brings every area online | Accepted | 10-03 | extends 407 | — | #3658 | console 0.22.0 | `diagrams` | +| 422 | Cards, a grouped nav, page-scoped asks | Accepted | 10-03 | extends 407, 412 | 424 (the nav card, in part) | #3659 | console 0.23.0 | `card`, `missions.test.ts` | +| 423 | "Start here" steps | Accepted | 10-03 | extends 407, 422 | — | #3660 | console 0.24.0 | `steps` | +| 424 | A compact nav with search | Accepted | 10-03 | extends 422 | 442 (Plugins group, in part) | #3663 | console 0.25.0 | `nav-state`, `nav.test.ts` | +| 425 | The Missions list | Accepted | 10-03 | extends 409, 407, 424 | — | #3665 | console 0.26.0 | `mission-list` | +| 426 | Self-check, boot report, visible runs | Accepted | 10-03 | extends 421, 411, 413, 420 | — | #3665 | console 0.26.0 | `self-check` | +| 427 | Security sentries | Accepted | 10-03 | extends 414, 411, 426 | — | #3665 | console 0.26.0 | `sentries` | +| 428 | Update check and auto-update | Accepted | 10-03 | extends 407, 426 | — | #3665 | console 0.26.0 | `updates` | +| 429 | The band: panel, standing row, links | Accepted | 10-03 | extends 407, 409, 428 | — | #3665 | console 0.26.0 | `band` | +| 430 | Main menu: accents, chips, badges | Accepted | 10-03 | extends 407, 429 | — | #3665 | console 0.26.0 | `design`, `menu-style`, `footer-layout` | +| 430 | Main menu design (amendments file) | Accepted | 10-03 | extends 407 | 442 (Plugins group, in part) | #3665 | console 0.26.0 | — | +| 431 | Live run check, render smoke, menu design throughout | Accepted | 10-03 | extends 426, 430, 420 | — | #3665 | console 0.26.0 | `live-read`, `render-smoke` | +| 432 | Cyberpunk boot uplink and Refresh | Accepted | 10-03 | extends 426, 430 | — | #3665 | console 0.26.0 | `boot-cyber` | +| 433 | Menu entry and page-title strike-in | Accepted | 10-03 | extends 430, 432 | — | #3665 | console 0.26.0 | `menu-entry` | +| 434 | Plugins page detects the marketplace | Accepted | 10-03 | — | — | #3665 | console 0.26.0 | `plugin-ops` | +| 435 | The palette page design | Accepted | 10-03 | extends 430, 431 | — | #3665 | console 0.26.0 | `palette-view` | +| 436 | Help: ruHelp and guides | Accepted | 10-03 | — | — | #3665 | console 0.26.0 | `help-docs` | +| 437 | Cost across providers | Accepted | 10-03 | — | — | #3667 | console 0.27.0, ruflo-cost-tracker 0.27.0 | `cost-ledger`, `_pricebook.mjs` | +| 438 | Research integration contract | Accepted | 10-04 | — | — | #3667 | console 0.28.0 | — | +| 439 | Console research start and confirm | Accepted | 10-04 | — | — | #3667 | console 0.28.0 | `mission-research` | +| 440 | Research web-fetch guard | Accepted | 10-04 | — | — | #3667 | ruflo-mods, console 0.28.0 | `research.test.ts` | +| 441 | Loop-centric missions | Accepted | 10-04 | — | — | #3667 | console 0.28.0 | `goap`, `mission-guidance` | +| 442 | Sandbox page; Plugins moves to TOOLS | Accepted | 10-04 | supersedes part of 424, 430 | — | #3667 | console 0.28.0 | `sandbox`, `nav.spec.ts` | +| 443 | Missions Claude knows about; verified evidence; spend | Accepted | 10-04 | 406, 437, 441 | — | #3695 | console 0.29.0, cost-tracker 0.27.1 | `mission-context`, `mission-cost`, `mission-loop` | +| 444 | Claude controls the console | Accepted | 10-04 | 406, 443 | — | #3696 | console 0.30.0 (autopilot default 0.32.0) | `model-tools`, `e2e-control.sh` | +| 448 | The Room: a shared live feed | Accepted | 10-04 | 407, 416, 444 | — | #3704 (doc), #3705 (page) | console 0.33.0 (expiry event 0.32.2) | `room`, `nav`, `runner`, `watch` | + +Other ADRs outside 404-451 that the mod ADRs lean on: 150 (removable integrations), 174 (failures as a learning signal), 322 and 322A/B/C (flywheel, evaluation and promotion, receipts), 324 and 325 (policy engine, claims plane), 103 (witness). The console's Mods section (`hooks/data/mods.ts`, console 0.33.1, PR #3707) reads the status files ADR 446 defines. + +## Notes + +- **Dates.** ADRs 444, 445 and 446 were dated 2026 10 05 but were committed on 2026-10-04 (14:36 -0400, merged 19:24 UTC); corrected. ADR 450 on branch `loop/sec-threat` has the same slip (2026 10 05); fix it when that branch is merged. +- **ADR 405 and 406** still read "Proposed" although parts shipped (ruflo-ruos 0.1.0 for 405; mission records and the console for 406, which accepted ADRs 408, 409 and 443 build on). Their owners should decide whether to mark them Accepted with the unbuilt parts split out; this index does not change them. +- **Forward links.** ADR 447 now names 449, 450 and 451 as its followers. The reverse links (449, 450 and 451 naming each other) belong in those files, which are not on `main` yet: 449 cites 404, 446 and 447 but not 450 or 451; 450 cites 444 to 448 but not 449 or 451; 451 cites 445 to 447 but not 449 or 450. +- **ADRs with no stated parent:** 434, 436, 437, 438, 439, 440, 441 carry no `Builds on` or `Extends` line.