@rafinery/cli 0.5.0 → 0.6.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/CHANGELOG.md +97 -0
- package/bin/rafa.mjs +30 -5
- package/blueprint/.claude/agents/atlas.md +2 -1
- package/blueprint/.claude/commands/rafa.md +71 -6
- package/blueprint/.claude/rafa/contract.md +32 -0
- package/blueprint/.claude/rafa/hooks/post-tool.mjs +62 -0
- package/blueprint/.claude/rafa/hooks/pre-push +24 -0
- package/blueprint/.claude/rafa/hooks/session-start.mjs +229 -0
- package/blueprint/.claude/rafa/hooks/statusline.mjs +113 -0
- package/blueprint/.claude/rafa/hooks/user-prompt-submit.mjs +87 -0
- package/blueprint/.claude/skills/rafa-build/SKILL.md +11 -4
- package/blueprint/.claude/skills/rafa-plan/SKILL.md +7 -0
- package/blueprint/.claude/skills/rafa-scan/SKILL.md +14 -3
- package/blueprint/.claude/skills/rafa-validate/SKILL.md +15 -2
- package/lib/blueprint.mjs +9 -1
- package/lib/brain-repo.mjs +10 -4
- package/lib/ci-setup.mjs +2 -0
- package/lib/claude-config.mjs +77 -0
- package/lib/dirty.mjs +114 -0
- package/lib/distill.mjs +4 -0
- package/lib/gate/compile.mjs +40 -0
- package/lib/gate/verify-citations.mjs +214 -23
- package/lib/githook.mjs +54 -0
- package/lib/init.mjs +18 -0
- package/lib/pull.mjs +7 -0
- package/lib/push.mjs +21 -0
- package/lib/reflex.mjs +76 -0
- package/lib/releases.mjs +35 -0
- package/lib/status.mjs +152 -0
- package/lib/update.mjs +13 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,103 @@ The machine-readable version of this lives in [`lib/releases.mjs`](lib/releases.
|
|
|
4
4
|
CLI reads it to tell a client, on `rafa update`, exactly what an upgrade requires (nothing,
|
|
5
5
|
a re-scan, or a `rafa migrate`).
|
|
6
6
|
|
|
7
|
+
## 0.6.0 — core solidity: checker v2 + the M5 capture engine
|
|
8
|
+
|
|
9
|
+
**Adopt with:** `npx @rafinery/cli@latest update` — re-vendors the new lockstep hook
|
|
10
|
+
scripts (`.claude/rafa/hooks/`), merges the sensor hooks into `.claude/settings.json`
|
|
11
|
+
(never clobbers yours), and installs the per-clone git pre-push boundary. Brain data
|
|
12
|
+
unchanged; no re-scan. Teammates get the git hook at their next `rafa pull`.
|
|
13
|
+
|
|
14
|
+
**The ratchet (checker v2)** — the two catches prism recommended in the 2026-06-08 live
|
|
15
|
+
run are now deterministic gates in `rafa verify-citations`:
|
|
16
|
+
|
|
17
|
+
- **Absence (B3)**: a note that claims something does NOT exist declares
|
|
18
|
+
`absent: <token>` (repeatable, anchor-style). Every declared absence is re-grepped
|
|
19
|
+
every run (docs/`.md` excluded) — the moment code grows the thing, the gate fails with
|
|
20
|
+
the exact site. Mechanizes the 2026-06-08 blocker class (a "stubbed" note the code had
|
|
21
|
+
outgrown).
|
|
22
|
+
- **Inventory**: `coverage.md` declares `inventory:` entries
|
|
23
|
+
(`- <name> :: <glob> :: <count>`); each is recomputed via `git ls-files ':(glob)…'` —
|
|
24
|
+
coverage claiming a surface inventory the repo has outgrown fails with the path diff.
|
|
25
|
+
- **WARN heuristic (non-failing)**: an absence-shaped `title`/`summary` with no `absent:`
|
|
26
|
+
declared is listed for prism's 3b audit — a heuristic never fails the gate (that would
|
|
27
|
+
be an assumed value).
|
|
28
|
+
- **Recorded gate level**: the checker writes `citation-check.json`
|
|
29
|
+
(`{checkerVersion, at, pass, gates, warns}`) and `rafa compile` folds it into
|
|
30
|
+
`manifest.citations` — the platform knows which checker version a brain actually
|
|
31
|
+
passed. No recorded run → `citations: null`, honestly.
|
|
32
|
+
- Selftest extended: absence + inventory logic proven on throwaway git fixtures
|
|
33
|
+
(prism's mutation probe covers the new gates).
|
|
34
|
+
|
|
35
|
+
**The M5 capture engine** — checkpoint/staleness moments become deterministic code, not
|
|
36
|
+
SOP adherence (the E2E-proven weak link: a full build once produced zero captures,
|
|
37
|
+
silently):
|
|
38
|
+
|
|
39
|
+
- **SessionStart digest** (`.claude/rafa/hooks/session-start.mjs`): the session starts
|
|
40
|
+
knowing — dirty code files → the brain notes citing them (local manifest, or
|
|
41
|
+
`get_code_context` fail-soft ≤2s), pending `*.theirs.md` checkpoint conflicts, the
|
|
42
|
+
active plan. Prints nothing when there is nothing (silence is the honest digest).
|
|
43
|
+
- **PostToolUse dirty-marker** (`.claude/rafa/hooks/post-tool.mjs`): every Edit/Write is
|
|
44
|
+
appended to `.rafa/dirty.jsonl` the moment it happens — monotonic, no session-end
|
|
45
|
+
dependency (there is no session end), never blocks, transport-excluded from brain
|
|
46
|
+
pushes via `.rafa/.gitignore`.
|
|
47
|
+
- **git pre-push boundary**: `git push` of the code branch runs `rafa checkpoint`
|
|
48
|
+
(non-blocking — a checkpoint problem never stops a code push; conflicts land as
|
|
49
|
+
`.theirs.md` for YOUR decision). Installed at init/pull/update; a foreign pre-push
|
|
50
|
+
hook is respected, never clobbered (the chain line is printed instead).
|
|
51
|
+
- **`rafa dirty [--json|--consume]`**: the cite-graph invalidator's query surface —
|
|
52
|
+
dirty files → citing notes; at boundaries the conductor OFFERS a scoped refresh
|
|
53
|
+
(atlas re-derives only the citing notes → gates → checkpoint), `--consume` clears the
|
|
54
|
+
queue after the refresh ships. Past the drift threshold (15 files / 10 notes) the
|
|
55
|
+
digest recommends `/rafa scan --brain-only` — the fire-alarm rung.
|
|
56
|
+
- **Recursion guard (U7)**: headless runs (CI fold/distill, the Agent SDK worker) set
|
|
57
|
+
`RAFA_HOOKS_DISABLED=1`; every hook exits 0 immediately. Hooks also no-op outside a
|
|
58
|
+
rafa-provisioned repo (no `rafa.json` → silent).
|
|
59
|
+
- **The correction reflex** (`.claude/rafa/hooks/user-prompt-submit.mjs` +
|
|
60
|
+
`rafa reflex`): a correction-shaped prompt ("no —", "never use X", "use Y instead")
|
|
61
|
+
is queued to `.rafa/reflex.jsonl` AND answered with a steering injection at that
|
|
62
|
+
exact moment — the session validates and banks it through the normal gates
|
|
63
|
+
same-session (branch: cited note + checkpoint · main: full gates), confirms in one
|
|
64
|
+
line, and consumes the queue entry with a verdict. Ungroundable claims are never
|
|
65
|
+
banked; unprocessed corrections from abandoned sessions surface at the next
|
|
66
|
+
session start (monotonic). Corrections are the highest-value knowledge signal —
|
|
67
|
+
they no longer evaporate.
|
|
68
|
+
- **`rafa push` re-runs the checker itself** (before compile; improvements ledger too
|
|
69
|
+
when present) — a stale or hand-stamped `citation-check.json` can never ride a push;
|
|
70
|
+
the record that ships is the record of THAT push. Mechanized same-day from the
|
|
71
|
+
2026-07-13 prism live-run recommendation (the disposition protocol working).
|
|
72
|
+
- Checker hardening: grep hits under `.rafa/**` are excluded categorically — the brain
|
|
73
|
+
never counts as "code", so an accidentally-tracked `.rafa/` can't self-collide the
|
|
74
|
+
completeness/absence gates.
|
|
75
|
+
|
|
76
|
+
**The frictionless loop** — devs won't run commands in order, so the loop guides
|
|
77
|
+
itself (owner directive; anti-nag etiquette unwaived — guidance is ambient,
|
|
78
|
+
front-loaded, or earned, never interleaved):
|
|
79
|
+
|
|
80
|
+
- **Loop-state statusline**: `.claude/rafa/hooks/statusline.mjs` renders
|
|
81
|
+
`rafa ▸ plan <id> 2/5 → <task> · 3 stale · 1 correction` at the bottom of every
|
|
82
|
+
session (silent outside rafa repos; a dev's existing statusline is NEVER replaced).
|
|
83
|
+
`rafa status [--line|--json]` is the harness-neutral core it mirrors.
|
|
84
|
+
- **Suggested next**: the SessionStart digest gains one deterministic
|
|
85
|
+
`[rafa · next]` line — ranked conflicts → corrections → resume plan → staleness —
|
|
86
|
+
so every session opens knowing the single best next step.
|
|
87
|
+
- **Direct-do path** (conductor 1.8.0): small work (≤ 1 domain, no contract surface,
|
|
88
|
+
one sitting) gets NO plan files and no approval — act first; the sensors carry the
|
|
89
|
+
loop; escalates to plan-lite with one announce line only when the work grows.
|
|
90
|
+
- **Brainstorm mode**: during exploration the conductor is a grounded, cited
|
|
91
|
+
participant with zero workflow talk; at crystallization, exactly one offer (a plan
|
|
92
|
+
if it's work, a working-set note if it's a conclusion).
|
|
93
|
+
|
|
94
|
+
**Portability (owner directive, 2026-07-13):** built for Claude Code now, ships for
|
|
95
|
+
Cursor/Codex later — loop logic lives in the harness-neutral core (CLI verbs + the
|
|
96
|
+
`.rafa/*.jsonl` queues + gates + MCP); everything under `.claude/rafa/hooks/` is a
|
|
97
|
+
thin per-harness adapter. The event protocol (detect → queue → steer →
|
|
98
|
+
bank-through-gates) is the portable contract.
|
|
99
|
+
|
|
100
|
+
The honest boundary, by design: hooks make **sync, staleness, and boundaries**
|
|
101
|
+
deterministic; **authoring stays model work** — steered by the injected digest, visible
|
|
102
|
+
on the platform ("working set clean" is a real answer, not a gap).
|
|
103
|
+
|
|
7
104
|
## 0.5.0 — plans v2: the work-item tree
|
|
8
105
|
|
|
9
106
|
**Adopt with:** `npx @rafinery/cli@latest update` → it runs the mechanical `rafa migrate`
|
package/bin/rafa.mjs
CHANGED
|
@@ -1,18 +1,25 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// rafa — the rafinery CLI. Thin dispatcher; each command lives in ../lib.
|
|
3
3
|
//
|
|
4
|
-
// rafa init [<setup-url>] provision this repo (vendor blueprint + wire the platform)
|
|
4
|
+
// rafa init [<setup-url>] provision this repo (vendor blueprint + wire the platform + sensors)
|
|
5
5
|
// rafa update re-sync the blueprint into this repo (shadcn-style)
|
|
6
6
|
// rafa compile run the contract gate → .rafa/manifest.json
|
|
7
|
-
// rafa verify-citations deterministic citation checker (B1/B2/policy
|
|
7
|
+
// rafa verify-citations deterministic citation checker (B1/B2/policy/absence/inventory)
|
|
8
8
|
// rafa push compile + push .rafa/ to the brain remote (main-branch act)
|
|
9
9
|
// rafa pull [--full] make this clone brain-ready (lazy skeleton; --full mirrors)
|
|
10
|
+
// rafa checkpoint sync this branch's working set (CAS; conflicts → .theirs.md)
|
|
11
|
+
// rafa hydrate fault knowledge into the lazy .rafa/
|
|
12
|
+
// rafa dirty [--json] staleness queue → citing notes; --consume after a refresh
|
|
13
|
+
// rafa fold branch→parent mechanical fold of the working set (no LLM)
|
|
14
|
+
// rafa distill --headless CI merge-to-main distillation (org's own LLM key)
|
|
15
|
+
// rafa ci-setup write the reconcile workflow (fold + distill on PR merge)
|
|
10
16
|
// rafa leverage inspect your agent toolbox → proactive tips
|
|
11
17
|
// rafa migrate bring structured files (plans/config) up to the current schema
|
|
12
18
|
//
|
|
13
19
|
// The gate tools live INSIDE this package (blueprint split, 0.4.0) — nothing is
|
|
14
20
|
// vendored into .rafa/bin anymore. The LLM work (scan / improve / plan) runs
|
|
15
|
-
// inside Claude Code via /rafa.
|
|
21
|
+
// inside Claude Code via /rafa. The M5 sensor hooks (.claude/rafa/hooks/) are
|
|
22
|
+
// vendored LOCKSTEP; commands are agent-internal machinery (zero-command rule).
|
|
16
23
|
|
|
17
24
|
import { readFileSync } from "node:fs";
|
|
18
25
|
import { dirname, join } from "node:path";
|
|
@@ -30,6 +37,9 @@ const COMMANDS = [
|
|
|
30
37
|
"pull",
|
|
31
38
|
"checkpoint",
|
|
32
39
|
"hydrate",
|
|
40
|
+
"dirty",
|
|
41
|
+
"reflex",
|
|
42
|
+
"status",
|
|
33
43
|
"fold",
|
|
34
44
|
"distill",
|
|
35
45
|
"ci-setup",
|
|
@@ -53,8 +63,10 @@ Commands:
|
|
|
53
63
|
--keep keep all changed owned files without asking
|
|
54
64
|
(default: ask per file; in a non-TTY it keeps them)
|
|
55
65
|
compile Validate the brain against the contract → .rafa/manifest.json.
|
|
56
|
-
verify-citations Deterministic citation checker: every cite resolves (B1),
|
|
57
|
-
contract anchor's code occurrences are cited (B2), policy
|
|
66
|
+
verify-citations Deterministic citation checker (v2): every cite resolves (B1),
|
|
67
|
+
every contract anchor's code occurrences are cited (B2), policy
|
|
68
|
+
holds, declared absences re-grepped (B3), coverage inventories
|
|
69
|
+
re-counted. Records the run (citation-check.json → manifest).
|
|
58
70
|
push Compile, then push .rafa/ to your brain remote (from main — the
|
|
59
71
|
org brain describes the default branch). Stamps the contract copy.
|
|
60
72
|
pull Make this clone brain-ready — bootstraps the lazy .rafa/ skeleton
|
|
@@ -67,6 +79,19 @@ Commands:
|
|
|
67
79
|
hydrate Fault knowledge into the lazy .rafa/: hydrate rule <id> ·
|
|
68
80
|
hydrate playbook <id> (org brain, stamped disposable-cache) ·
|
|
69
81
|
hydrate --working-set (this branch's synced files).
|
|
82
|
+
dirty The staleness queue (M5): code files edited since the last brain
|
|
83
|
+
reconcile → the brain notes citing them. --json for agents;
|
|
84
|
+
--consume clears it AFTER a scoped refresh shipped. The queue is
|
|
85
|
+
written by the PostToolUse sensor hook the moment an edit happens.
|
|
86
|
+
reflex The correction queue (M5): corrections the UserPromptSubmit sensor
|
|
87
|
+
detected. List/--json; --consume <id> [verdict] AFTER banking it
|
|
88
|
+
through the gates (or judging it session-only). Corrections are
|
|
89
|
+
the highest-value knowledge signal — they must never evaporate.
|
|
90
|
+
status Where the loop stands, from local state only: active plan +
|
|
91
|
+
task progress · stale count · corrections · conflicts.
|
|
92
|
+
--line = the one-line ambient form (statuslines/prompts) ·
|
|
93
|
+
--json = machine shape. Harness-neutral core: the Claude Code
|
|
94
|
+
statusline adapter mirrors exactly this.
|
|
70
95
|
fold Branch→parent MECHANICAL fold of the working set (no LLM):
|
|
71
96
|
rafa fold --from <branch> --to <parent>. Divergence → flagged
|
|
72
97
|
needs-adjudication for the next dev session, never guessed.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: atlas
|
|
3
|
-
version: 3.
|
|
3
|
+
version: 3.7.0
|
|
4
4
|
model: opus # authoring is correctness-critical — a hallucinated note poisons the brain; best model, never cheap
|
|
5
5
|
groundTruth: code-at-sha
|
|
6
6
|
description: >-
|
|
@@ -17,6 +17,7 @@ duties:
|
|
|
17
17
|
- "repair :: .claude/skills/rafa-scan/SKILL.md :: every blocker + major in checklist.md fixed against the code · checker re-run to exit 0 · never weaken a check to pass it"
|
|
18
18
|
- "plan-drafting :: .claude/skills/rafa-plan/SKILL.md :: recall-grounded decomposition (coverage → search → notes) · blast radius named · contract §7 files · every child carries a Done-check"
|
|
19
19
|
- "build-execution :: .claude/skills/rafa-build/SKILL.md :: implement per recalled knowledge · never hand-edit brain files around the gate · return what changed, cited"
|
|
20
|
+
- "scoped-refresh :: .claude/skills/rafa-scan/SKILL.md :: re-derive ONLY the dirty-cited notes against current code (input: rafa dirty --json) · same gates as scan (verify-citations exit 0) · on main: compile+push; on a branch: working-set edit + checkpoint · queue consumed only after the refresh ships"
|
|
20
21
|
---
|
|
21
22
|
|
|
22
23
|
# atlas — senior design engineer
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
version: 1.
|
|
2
|
+
version: 1.8.0
|
|
3
3
|
description: rafa — the repo's engineering SOP. Use whenever the dev wants to plan a feature or change, build/execute against the active plan, improve code health, or ground work in the repo's brain — intent counts, the dev does NOT need to type /rafa. Also explicit: /rafa <init|scan|improve|plan|build|push|leverage|migrate|update|help> [--brain-only]. Admin verbs (init/scan/push/migrate/update) run ONLY when explicitly invoked.
|
|
4
4
|
---
|
|
5
5
|
|
|
@@ -13,14 +13,40 @@ Admin verbs are expensive or side-effectful and run **only when explicitly typed
|
|
|
13
13
|
|
|
14
14
|
| Prompt shape | Route |
|
|
15
15
|
|---|---|
|
|
16
|
-
|
|
|
16
|
+
| small work — radius ≤ 1 domain, no contract surface, fits one sitting | **DIRECT-DO**: recall → implement → verify → done. NO plan files, NO approval, NOTHING to remember — the sensors carry the loop (dirty-mark, reflex, checkpoint-at-push). Escalate only if it GROWS (below). |
|
|
17
|
+
| "let's add / build / implement / refactor X" — real blast radius (≥ 2 domains, a contract surface, or multi-session) (no active plan) | `## plan` — weight by blast radius: lite vs full (see plan.md § plan-lite) |
|
|
17
18
|
| same, with an active plan covering it | `## build` |
|
|
18
19
|
| "why / how / where does X …" (a question) | recall-and-answer: MCP `search_knowledge` → cited answer. No choreography. |
|
|
20
|
+
| exploration — "what if / should we / compare / thinking about X" | **BRAINSTORM mode** (§ below): grounded participant, zero workflow talk, one offer at crystallization. |
|
|
19
21
|
| "list plans / what plans are there" | `list_plans` — NAMES ONLY (id · title · status · progress); never dump bodies |
|
|
20
22
|
| "load / open / work on plan X" | `get_plan(X)` → materialize parent + children (bodies) into `.rafa/plans/<X>/` + set `active.md` → resume per `## build` |
|
|
21
23
|
| "improve / clean up / what's rotting" | `## improve` |
|
|
22
24
|
| explicit `/rafa <admin verb>` — init · scan · push · migrate · update | that verb, and ONLY then |
|
|
23
25
|
|
|
26
|
+
**Direct-do — the light path must be lighter than bypassing rafa.** For small work
|
|
27
|
+
the default INVERTS: act first, record only if it earns recording. No announcement
|
|
28
|
+
ceremony either — just do it (recall still automatic; verify still real: types/lint/
|
|
29
|
+
tests as the repo warrants). **The escalation rule:** the moment the work grows — a
|
|
30
|
+
second domain, a contract surface, or it clearly won't finish this sitting — say ONE
|
|
31
|
+
line (*"this grew — recording it as a plan so it's resumable"*), create the plan-lite
|
|
32
|
+
files THEN, and continue; never ask permission to keep the loop honest, and never
|
|
33
|
+
escalate a task that stayed small. What keeps direct-do safe with zero ceremony: the
|
|
34
|
+
sensors (every edit dirty-marked, corrections reflexed, `git push` checkpoints) plus
|
|
35
|
+
§capture for anything learned — the loop closes without the dev or you filing
|
|
36
|
+
paperwork.
|
|
37
|
+
|
|
38
|
+
**Brainstorm mode — grounded participant, not a process.** During exploration:
|
|
39
|
+
recall automatically and cite (the brain is WHY the brainstorm is good), think WITH
|
|
40
|
+
the dev, and say NOTHING about plans, captures, checkpoints, or process — zero
|
|
41
|
+
workflow talk mid-exploration. At CRYSTALLIZATION (the dev stops exploring and
|
|
42
|
+
starts concluding — "ok let's do X", "so the decision is Y", or asks to proceed):
|
|
43
|
+
exactly ONE offer, shaped by what the conversation produced — work → *"want me to
|
|
44
|
+
turn this into a plan?"* · a durable conclusion with no work attached → *"bank the
|
|
45
|
+
conclusion as a note?"* (a plan-less decision lands as a working-set note under
|
|
46
|
+
§capture, so brainstorm output survives even when no work item ever exists). A "no"
|
|
47
|
+
stands for the session. If nothing crystallized, offer nothing — an open exploration
|
|
48
|
+
is a fine place to end.
|
|
49
|
+
|
|
24
50
|
**Announce-and-proceed, never ask-permission:** state the route in one line — *"this
|
|
25
51
|
looks plan-shaped — following the plan SOP (say 'skip' to bypass)"* — then go. "skip"
|
|
26
52
|
always wins, immediately and without argument. Never narrate other devs' activity
|
|
@@ -63,6 +89,11 @@ Three interaction modes by the weight of the action:
|
|
|
63
89
|
- session start, local ahead of platform → *"brain is N commits behind — push?"*
|
|
64
90
|
- reconciliation pending → *"branch <x> merged with N working-set files — distill now?"*
|
|
65
91
|
- adjudication pending → *"1 file diverged at the <x>→<y> fold — pick a copy?"*
|
|
92
|
+
- staleness (the M5 dirty queue, injected by the SessionStart digest or read via
|
|
93
|
+
`rafa dirty --json` at boundaries) → *"N notes cite files you've touched — refresh
|
|
94
|
+
just those?"* — accepted = atlas scoped-refresh (only the citing notes, gates as
|
|
95
|
+
usual, checkpoint/push per branch rules), then `rafa dirty --consume`. Past the
|
|
96
|
+
drift threshold the offer escalates to */rafa scan --brain-only* (the fire-alarm).
|
|
66
97
|
- user brain EMPTY (first session / founding scan just completed) → *"want me to
|
|
67
98
|
bootstrap your insights from your usage report? (compass distills it; every
|
|
68
99
|
candidate is offered — nothing banked without your yes)"* — accepted = run
|
|
@@ -74,13 +105,47 @@ blocks; keep working, the offer stands · admin verbs stay explicit — an ACCEP
|
|
|
74
105
|
offer is the explicit invocation.
|
|
75
106
|
|
|
76
107
|
**Bootstrap digest — one question, however much is pending.** Session start may
|
|
77
|
-
accumulate many offers (staleness push, N distills, needs-adjudication flags,
|
|
78
|
-
nudge). NEVER ask them serially — batch into ONE itemized digest:
|
|
79
|
-
pending: brain push · 2 merged branches to distill · 1 file needs
|
|
80
|
-
want any now, or later?"*
|
|
108
|
+
accumulate many offers (staleness push, N distills, needs-adjudication flags, dirty
|
|
109
|
+
notes to refresh, a nudge). NEVER ask them serially — batch into ONE itemized digest:
|
|
110
|
+
*"4 things pending: brain push · 2 merged branches to distill · 1 file needs
|
|
111
|
+
adjudication · 3 notes cite code you changed — want any now, or later?"*
|
|
81
112
|
Dismissible as a unit; offer fatigue trains reflexive yes, which corrodes every
|
|
82
113
|
consent rung above it.
|
|
83
114
|
|
|
115
|
+
**The M5 sensors feed you — you never poll.** Four deterministic instruments run
|
|
116
|
+
outside the model (blueprint hooks + the git boundary): the SessionStart digest
|
|
117
|
+
injects staleness/conflicts/corrections/active-plan as context at session start ·
|
|
118
|
+
every Edit/Write is dirty-marked into `.rafa/dirty.jsonl` the moment it happens ·
|
|
119
|
+
`git push` runs `rafa checkpoint` mechanically (non-blocking) · a correction-shaped
|
|
120
|
+
prompt is queued to `.rafa/reflex.jsonl` AND arrives with a `[rafa · reflex <id>]`
|
|
121
|
+
steering injection. Your part is the JUDGMENT half: consume `rafa dirty --json` at
|
|
122
|
+
natural boundaries, offer the scoped refresh (above), and run `rafa dirty --consume`
|
|
123
|
+
ONLY after a refresh actually shipped through the gates. Sensors make the moments
|
|
124
|
+
deterministic; authoring stays yours.
|
|
125
|
+
|
|
126
|
+
**Guidance is ambient · front-loaded · earned — never interleaved.** The dev sees
|
|
127
|
+
the loop three ways and ONLY three: the **statusline** (always-on one-liner —
|
|
128
|
+
plan progress · stale · corrections · conflicts; `rafa status --line` is the same
|
|
129
|
+
truth for any surface) · the digest's **`[rafa · next] suggested next:`** line
|
|
130
|
+
(deterministic, ranked: conflicts → corrections → resume plan → staleness) — honor
|
|
131
|
+
it by putting that item FIRST in the bootstrap digest · the **boundary offers**.
|
|
132
|
+
Never emit mid-flow "next step" reminders; the statusline already says it silently.
|
|
133
|
+
|
|
134
|
+
**The correction reflex (bank it THIS session, not next scan).** When the
|
|
135
|
+
`[rafa · reflex <id>]` injection arrives: first address the dev's correction; then
|
|
136
|
+
judge it — is this DURABLE repo knowledge (a convention/contract/fact a future
|
|
137
|
+
session needs), or a one-off steer? Durable → bank NOW through the gates: on a
|
|
138
|
+
branch, author/edit the note under `.rafa/brain/**` (≥1 resolving cite) +
|
|
139
|
+
`rafa checkpoint`; on main, full gates (verify-citations · compile · push). Confirm
|
|
140
|
+
to the dev in ONE line — note id + where it landed — then
|
|
141
|
+
`rafa reflex --consume <id>`. Not durable (preference, out-of-code claim,
|
|
142
|
+
one-off) → say it stays session-only and consume with verdict `session-only`. An
|
|
143
|
+
ungroundable claim is NEVER banked (no cite = no note — tell the dev honestly).
|
|
144
|
+
Unprocessed corrections from abandoned sessions surface in the bootstrap digest —
|
|
145
|
+
work them like any pending item. Dev-level preferences route to compass's offer
|
|
146
|
+
path (user brain), never the org stores. Raw transcripts never enter any shared
|
|
147
|
+
store; only the distilled, cited note ships.
|
|
148
|
+
|
|
84
149
|
**The frame is CONSENT (owner, 2026-07-10).** Four rungs, each action needs exactly
|
|
85
150
|
one: (1) **implied** — the message itself consents to what it asks, and only that ·
|
|
86
151
|
(2) **session** — asked once, remembered, revocable mid-session ("stop pushing") ·
|
|
@@ -46,8 +46,11 @@ doesn't validate, compile fails.
|
|
|
46
46
|
| plan | `plans/**/*.md` | **structured** | §7 | plan/build |
|
|
47
47
|
| log | `brain/log.md` | **verbatim** | — (prose trail) | conductor |
|
|
48
48
|
| citation-check | `**/citation-check.md` | **generated** | — (by `rafa verify-citations`) | tool |
|
|
49
|
+
| citation-check record | `**/citation-check.json` | **generated** | `{ checkerVersion, at, pass, gates, warns }` (by `rafa verify-citations`; compile folds it into `manifest.citations`) | tool |
|
|
49
50
|
| active pointer | `active.md` | **generated** | — (`# <plan-id>` or "No active plan"; compile emits it as `activePlanId`, §7) | conductor |
|
|
50
51
|
| contract copy | `contract.md` | **generated** | — (stamped copy of `.claude/rafa/contract.md`, written by `rafa push`) | tool |
|
|
52
|
+
| dirty queue | `dirty.jsonl` | **generated** (local state — transport-excluded, NEVER pushed/ingested) | one `{f, t}` JSON line per code edit (by the PostToolUse sensor hook; read by `rafa dirty` + the SessionStart digest) | tool |
|
|
53
|
+
| reflex queue | `reflex.jsonl` | **generated** (local state — transport-excluded, NEVER pushed/ingested; transcript pointers are LOCAL, raw transcripts never ship) | `{id, p, t, tp}` per detected correction + append-only `{id, done, verdict, at}` markers (by the UserPromptSubmit sensor; read by `rafa reflex` + the digest) | tool |
|
|
51
54
|
| agent | `.claude/agents/*.md` (code repo) | **structured** (local gate — NOT in manifest) | §10 | rafa |
|
|
52
55
|
|
|
53
56
|
The `agent` type is the one structured type outside `.rafa/`: the shipped agent cards
|
|
@@ -146,6 +149,12 @@ JSON. This is the exact shape the platform binds to.
|
|
|
146
149
|
]
|
|
147
150
|
},
|
|
148
151
|
|
|
152
|
+
"citations": { // from brain/citation-check.json — or null
|
|
153
|
+
"checkerVersion": 2, // the gate level this brain passed
|
|
154
|
+
"pass": true, // that run's verdict (recorded, never assumed)
|
|
155
|
+
"at": "2026-07-12T10:00:00Z" // when the checker last ran
|
|
156
|
+
}, // null = no recorded checker run rode this push
|
|
157
|
+
|
|
149
158
|
"notes": [
|
|
150
159
|
{
|
|
151
160
|
"id": "agent-name-contract",
|
|
@@ -204,6 +213,14 @@ title: The agent name is a cross-process contract # required
|
|
|
204
213
|
summary: Only "research_agent" is fully wired end to end # required
|
|
205
214
|
links: [copilotkit-runtime-route-convention] # optional · default []
|
|
206
215
|
failure: silent # optional · silent | loud
|
|
216
|
+
anchor: research_agent # optional · checker gate B2: EVERY code hit of this
|
|
217
|
+
# token must be a cited site (`anchor: none` = explicit
|
|
218
|
+
# exemption for composition/ordering contracts)
|
|
219
|
+
absent: legacy_agent_name # optional · checker gate B3: this token must appear
|
|
220
|
+
# NOWHERE in code (docs/.md excluded) — declare one for
|
|
221
|
+
# every claim that depends on something NOT existing;
|
|
222
|
+
# the checker re-greps it every run, so the claim can
|
|
223
|
+
# never silently go stale. Repeatable (one per line).
|
|
207
224
|
cites: # required · ≥ 1
|
|
208
225
|
- src/lib/model-selector-provider.tsx:42 :: research_agent
|
|
209
226
|
- agents/python/main.py:20 :: research_agent
|
|
@@ -211,6 +228,12 @@ cites: # required · ≥ 1
|
|
|
211
228
|
(prose body — rendered verbatim, never parsed)
|
|
212
229
|
```
|
|
213
230
|
|
|
231
|
+
`anchor:`/`absent:` are **checker declarations** (consumed by `rafa verify-citations`
|
|
232
|
+
gates B2/B3, not emitted into the manifest). A note whose title/summary reads as an
|
|
233
|
+
absence claim without declaring `absent:` is listed as a checker WARN — prism's
|
|
234
|
+
worklist, never a gate failure (a heuristic that fails the gate would be an assumed
|
|
235
|
+
value).
|
|
236
|
+
|
|
214
237
|
---
|
|
215
238
|
|
|
216
239
|
## 3. Improvement files — `improve/improvements/*.md`
|
|
@@ -282,10 +305,19 @@ domain found (compile emits it as `[{ domain, status }]` in the manifest). Statu
|
|
|
282
305
|
---
|
|
283
306
|
schemaVersion: 1
|
|
284
307
|
domains: { design-system: mapped, components: mapped, api: thin, external-integrations: empty }
|
|
308
|
+
inventory: # optional · declared surface inventories, re-counted by
|
|
309
|
+
- route-pages :: apps/web/app/**/page.tsx :: 23 # the checker every run
|
|
310
|
+
- api-routes :: apps/web/app/api/**/route.ts :: 2
|
|
285
311
|
---
|
|
286
312
|
(per-criterion PASS/FAIL narrative in the body)
|
|
287
313
|
```
|
|
288
314
|
|
|
315
|
+
`inventory:` entries are `<name> :: <glob> :: <count>` — the checker recomputes each
|
|
316
|
+
count via `git ls-files ':(glob)<glob>'` and FAILS on drift (coverage claiming a
|
|
317
|
+
surface inventory the repo has outgrown). atlas declares one per framework surface it
|
|
318
|
+
maps (route pages, API routes, workflows — whatever the repo's shape makes load-bearing);
|
|
319
|
+
compile validates the grammar, the checker owns the truth.
|
|
320
|
+
|
|
289
321
|
---
|
|
290
322
|
|
|
291
323
|
## 7. Plan files — `plans/**/*.md` (+ the plans channel) — **v2: the work-item tree**
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// rafa hook · PostToolUse (Edit|Write|MultiEdit|NotebookEdit) — the dirty-marker.
|
|
3
|
+
//
|
|
4
|
+
// M5 capture engine, sensor #1: every code edit is recorded the moment it happens
|
|
5
|
+
// (monotonic, event-driven — never at session end, because there is no session end).
|
|
6
|
+
// Appends {f, t} to .rafa/dirty.jsonl; the SessionStart digest and `rafa dirty`
|
|
7
|
+
// resolve entries to the brain notes that cite those files (the codeRefs plane).
|
|
8
|
+
//
|
|
9
|
+
// Hard rules: NEVER block the session (exit 0 on every path, all errors swallowed),
|
|
10
|
+
// no network, no LLM, O(append). Honors RAFA_HOOKS_DISABLED=1 (headless workers /
|
|
11
|
+
// CI distillation set it — the recursion guard).
|
|
12
|
+
|
|
13
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
14
|
+
import { join, relative, isAbsolute, sep } from "node:path";
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
if (process.env.RAFA_HOOKS_DISABLED === "1") process.exit(0);
|
|
18
|
+
|
|
19
|
+
let input = "";
|
|
20
|
+
try {
|
|
21
|
+
input = readFileSync(0, "utf8"); // stdin: the hook event JSON
|
|
22
|
+
} catch {
|
|
23
|
+
process.exit(0);
|
|
24
|
+
}
|
|
25
|
+
let evt = null;
|
|
26
|
+
try {
|
|
27
|
+
evt = JSON.parse(input);
|
|
28
|
+
} catch {
|
|
29
|
+
process.exit(0);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const root = process.env.CLAUDE_PROJECT_DIR || evt?.cwd || process.cwd();
|
|
33
|
+
if (!existsSync(join(root, "rafa.json"))) process.exit(0); // not a rafa-provisioned repo
|
|
34
|
+
|
|
35
|
+
const fp = evt?.tool_input?.file_path || evt?.tool_input?.notebook_path;
|
|
36
|
+
if (!fp || typeof fp !== "string") process.exit(0);
|
|
37
|
+
|
|
38
|
+
const rel = isAbsolute(fp) ? relative(root, fp) : fp;
|
|
39
|
+
// Outside the repo, or not code-plane: knowledge/state/tooling edits don't dirty the brain.
|
|
40
|
+
if (rel.startsWith("..") || isAbsolute(rel)) process.exit(0);
|
|
41
|
+
const top = rel.split(sep)[0];
|
|
42
|
+
if ([".rafa", ".claude", ".git", "node_modules"].includes(top) || rel === "rafa.json") process.exit(0);
|
|
43
|
+
|
|
44
|
+
const rafaDir = join(root, ".rafa");
|
|
45
|
+
mkdirSync(rafaDir, { recursive: true });
|
|
46
|
+
|
|
47
|
+
// Transport exclusion, belt-and-braces: the queue is session-local state and must
|
|
48
|
+
// never ride a brain push (`rafa push` commits .rafa/ wholesale). ensureBrainRepo
|
|
49
|
+
// writes this too — this covers the window before any pull/push ran here.
|
|
50
|
+
const gi = join(rafaDir, ".gitignore");
|
|
51
|
+
const body = existsSync(gi) ? readFileSync(gi, "utf8") : "";
|
|
52
|
+
if (!/^dirty\.jsonl$/m.test(body))
|
|
53
|
+
writeFileSync(gi, body + (body === "" || body.endsWith("\n") ? "" : "\n") + "dirty.jsonl\n");
|
|
54
|
+
|
|
55
|
+
appendFileSync(
|
|
56
|
+
join(rafaDir, "dirty.jsonl"),
|
|
57
|
+
JSON.stringify({ f: rel.split(sep).join("/"), t: new Date().toISOString() }) + "\n",
|
|
58
|
+
);
|
|
59
|
+
} catch {
|
|
60
|
+
/* a sensor must never take down the session */
|
|
61
|
+
}
|
|
62
|
+
process.exit(0);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# rafa pre-push hook v1 (installed by @rafinery/cli init/pull/update — safe to
|
|
3
|
+
# delete; it will be offered again, never forced over a foreign hook).
|
|
4
|
+
#
|
|
5
|
+
# M5 capture engine, sensor #3: `git push` of the CODE branch is a ratified
|
|
6
|
+
# natural checkpoint boundary — so the branch WORKING SET (edited/new brain
|
|
7
|
+
# files) syncs to the platform deterministically here, not only when a session
|
|
8
|
+
# remembers its SOP. Non-blocking by design: a checkpoint problem must never
|
|
9
|
+
# stop a code push (exit 0 on every path; conflicts land as .theirs.md copies
|
|
10
|
+
# for the next session to decide — printed, never auto-resolved).
|
|
11
|
+
|
|
12
|
+
[ "$RAFA_HOOKS_DISABLED" = "1" ] && exit 0
|
|
13
|
+
[ -f "rafa.json" ] || exit 0
|
|
14
|
+
|
|
15
|
+
echo "rafa · checkpoint (pre-push boundary) …"
|
|
16
|
+
npx -y @rafinery/cli checkpoint || {
|
|
17
|
+
code=$?
|
|
18
|
+
if [ "$code" = "2" ]; then
|
|
19
|
+
echo "rafa · checkpoint CONFLICT — a teammate's newer copy landed as *.theirs.md; decide in your next session (merge/adopt/keep, re-run rafa checkpoint). Push continues."
|
|
20
|
+
else
|
|
21
|
+
echo "rafa · checkpoint skipped (exit $code) — push continues; run 'rafa checkpoint' manually when convenient."
|
|
22
|
+
fi
|
|
23
|
+
}
|
|
24
|
+
exit 0
|