@rafinery/cli 0.6.0 → 0.7.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/bin/rafa.mjs +7 -0
- package/blueprint/.claude/agents/sage.md +66 -0
- package/blueprint/.claude/commands/rafa.md +205 -325
- package/blueprint/.claude/rafa/contract.md +188 -131
- package/blueprint/.claude/skills/rafa-build/SKILL.md +9 -1
- package/blueprint/.claude/skills/rafa-distill/SKILL.md +6 -1
- package/blueprint/.claude/skills/rafa-sage/SKILL.md +201 -0
- package/blueprint/.claude/skills/rafa-scan/SKILL.md +41 -2
- package/lib/benchmark.mjs +573 -0
- package/lib/blueprint.mjs +2 -0
- package/lib/gate/compile.mjs +258 -49
- package/package.json +1 -1
|
@@ -24,7 +24,7 @@ agents write .md (frontmatter per this contract)
|
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
Two enforcement points: **compile-time** (structure — this contract) and **prism**
|
|
27
|
-
(semantics — truth of the content). Structure is validated
|
|
27
|
+
(semantics — truth of the content). Structure is validated _before_ semantics.
|
|
28
28
|
|
|
29
29
|
---
|
|
30
30
|
|
|
@@ -35,23 +35,23 @@ a schema (parse it), a `verbatim` type is prose (display it, never parse for dat
|
|
|
35
35
|
`generated` type is machine-written by a named tool. If a file matching a `structured` path
|
|
36
36
|
doesn't validate, compile fails.
|
|
37
37
|
|
|
38
|
-
| Type
|
|
39
|
-
|
|
40
|
-
| rule
|
|
41
|
-
| playbook
|
|
42
|
-
| health
|
|
43
|
-
| coverage
|
|
44
|
-
| improvement
|
|
45
|
-
| ledger
|
|
46
|
-
| plan
|
|
47
|
-
| log
|
|
48
|
-
| citation-check
|
|
49
|
-
| citation-check record | `**/citation-check.json`
|
|
50
|
-
| active pointer
|
|
51
|
-
| contract copy
|
|
52
|
-
| dirty queue
|
|
53
|
-
| reflex queue
|
|
54
|
-
| agent
|
|
38
|
+
| Type | Path glob | Class | Schema | Author |
|
|
39
|
+
| --------------------- | --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
|
|
40
|
+
| rule | `brain/rules/*.md` | **structured** | §2 | atlas |
|
|
41
|
+
| playbook | `brain/playbooks/*.md` | **structured** | §2 | atlas |
|
|
42
|
+
| health | `brain/checklist.md` | **structured** | §4 | prism |
|
|
43
|
+
| coverage | `brain/coverage.md` | **structured** | §6 | atlas |
|
|
44
|
+
| improvement | `improve/improvements/*.md` | **structured** | §3 | bloom |
|
|
45
|
+
| ledger | `improve/ledger.md` | **structured** | §5 | bloom |
|
|
46
|
+
| plan | `plans/**/*.md` | **structured** | §7 | plan/build |
|
|
47
|
+
| log | `brain/log.md` | **verbatim** | — (prose trail) | conductor |
|
|
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 |
|
|
50
|
+
| active pointer | `active.md` | **generated** | — (`# <plan-id>` or "No active plan"; compile emits it as `activePlanId`, §7) | conductor |
|
|
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 |
|
|
54
|
+
| agent | `.claude/agents/*.md` (code repo) | **structured** (local gate — NOT in manifest) | §10 | rafa |
|
|
55
55
|
|
|
56
56
|
The `agent` type is the one structured type outside `.rafa/`: the shipped agent cards
|
|
57
57
|
in the code repo. Compile validates them (§10) so a malformed card fails the gate like
|
|
@@ -72,7 +72,7 @@ error (no rogue unschema'd data files).
|
|
|
72
72
|
|
|
73
73
|
- **Frontmatter is the only machine-read surface.** The markdown **body is prose**
|
|
74
74
|
and is NEVER parsed for data. Every value the platform shows comes from frontmatter
|
|
75
|
-
(via the compiled manifest), or from the body rendered
|
|
75
|
+
(via the compiled manifest), or from the body rendered _verbatim_ (never scraped).
|
|
76
76
|
- **`schemaVersion` is required** on every file and in the manifest. Unknown version
|
|
77
77
|
→ ingest reports an error, does not guess.
|
|
78
78
|
- **`id` is required and stable.** It MUST equal the filename stem (`foo.md` → `foo`).
|
|
@@ -108,7 +108,7 @@ Deterministic to parse: indented non-empty lines after `>-` join with a single s
|
|
|
108
108
|
|
|
109
109
|
Each cite is one string: `` `<path>:<line> :: <token>` ``
|
|
110
110
|
|
|
111
|
-
- split on the **first**
|
|
111
|
+
- split on the **first** `::` → (`left`, `token`)
|
|
112
112
|
- in `left`, split on the **last** `:` → (`path`, `line`)
|
|
113
113
|
- `line` is digits (`"42"`) or a range (`"14-18"`)
|
|
114
114
|
|
|
@@ -124,67 +124,82 @@ JSON. This is the exact shape the platform binds to.
|
|
|
124
124
|
```jsonc
|
|
125
125
|
{
|
|
126
126
|
"schemaVersion": 1,
|
|
127
|
-
"generatedAt": "2026-07-03T10:00:00Z",
|
|
128
|
-
"repo": "owner/repo",
|
|
129
|
-
"branch": "main",
|
|
130
|
-
"codeSha": "abc123…",
|
|
131
|
-
|
|
132
|
-
"health": {
|
|
133
|
-
|
|
134
|
-
"
|
|
127
|
+
"generatedAt": "2026-07-03T10:00:00Z", // ISO-8601, stamped by compile
|
|
128
|
+
"repo": "owner/repo", // CODE repo full_name (identity)
|
|
129
|
+
"branch": "main", // code branch this brain reflects
|
|
130
|
+
"codeSha": "abc123…", // code commit the brain was built for
|
|
131
|
+
|
|
132
|
+
"health": {
|
|
133
|
+
// from brain/checklist.md — or null
|
|
134
|
+
"verdict": "PASS", // "PASS" | "ITERATE"
|
|
135
|
+
"score": 95, // 0–100
|
|
135
136
|
"gates": { "fidelity": "pass", "coverage": "pass" },
|
|
136
|
-
"counts": { "blockers": 0, "majors": 0, "minors": 2 }
|
|
137
|
+
"counts": { "blockers": 0, "majors": 0, "minors": 2 },
|
|
137
138
|
},
|
|
138
139
|
|
|
139
|
-
"ledger": {
|
|
140
|
+
"ledger": {
|
|
141
|
+
// from improve/ledger.md — or null
|
|
140
142
|
"open": 7,
|
|
141
143
|
"debtScore": 13,
|
|
142
|
-
"byPriority": { "P0": 0, "P1": 1, "P2": 3, "P3": 3 }
|
|
144
|
+
"byPriority": { "P0": 0, "P1": 1, "P2": 3, "P3": 3 },
|
|
143
145
|
},
|
|
144
146
|
|
|
145
|
-
"coverage": {
|
|
146
|
-
|
|
147
|
+
"coverage": {
|
|
148
|
+
// from brain/coverage.md — or null
|
|
149
|
+
"domains": [
|
|
150
|
+
// one row per domain, its scan status
|
|
147
151
|
{ "domain": "design-system", "status": "mapped" },
|
|
148
|
-
{ "domain": "external-integrations", "status": "thin" }
|
|
149
|
-
]
|
|
152
|
+
{ "domain": "external-integrations", "status": "thin" },
|
|
153
|
+
],
|
|
150
154
|
},
|
|
151
155
|
|
|
152
|
-
"citations": {
|
|
153
|
-
|
|
154
|
-
"
|
|
155
|
-
"
|
|
156
|
-
|
|
156
|
+
"citations": {
|
|
157
|
+
// from brain/citation-check.json — or null
|
|
158
|
+
"checkerVersion": 2, // the gate level this brain passed
|
|
159
|
+
"pass": true, // that run's verdict (recorded, never assumed)
|
|
160
|
+
"at": "2026-07-12T10:00:00Z", // when the checker last ran
|
|
161
|
+
}, // null = no recorded checker run rode this push
|
|
157
162
|
|
|
158
163
|
"notes": [
|
|
159
164
|
{
|
|
160
165
|
"id": "agent-name-contract",
|
|
161
|
-
"kind": "rule",
|
|
162
|
-
"type": "contract",
|
|
166
|
+
"kind": "rule", // "rule" | "playbook" (from directory)
|
|
167
|
+
"type": "contract", // contract | convention | flow | how-to
|
|
163
168
|
"domain": "web-agent-bridge",
|
|
164
169
|
"title": "…",
|
|
165
170
|
"summary": "…",
|
|
166
|
-
"links": ["other-note-id"],
|
|
167
|
-
"failure": "silent",
|
|
168
|
-
"
|
|
169
|
-
|
|
170
|
-
|
|
171
|
+
"links": ["other-note-id"], // [] if none
|
|
172
|
+
"failure": "silent", // "silent" | "loud" | omitted
|
|
173
|
+
"bodyTokens": 180, // OPTIONAL · ceil(bodyChars/4) size estimate of the
|
|
174
|
+
// prose body — deterministic (no LLM), for recall-savings
|
|
175
|
+
"cites": [
|
|
176
|
+
{
|
|
177
|
+
"file": "src/x.tsx",
|
|
178
|
+
"line": "42",
|
|
179
|
+
"token": "research_agent",
|
|
180
|
+
"targetTokens": 940,
|
|
181
|
+
},
|
|
182
|
+
], // targetTokens OPTIONAL · ceil(fileChars/4) of the CITED
|
|
183
|
+
// file — OMITTED when unreadable at compile (never 0)
|
|
184
|
+
"path": "brain/rules/agent-name-contract.md", // prose body (lazy fetch)
|
|
185
|
+
},
|
|
171
186
|
],
|
|
172
187
|
|
|
173
188
|
"improvements": [
|
|
174
189
|
{
|
|
175
190
|
"id": "dead-model-options-google-crewai",
|
|
176
|
-
"priority": "P1",
|
|
177
|
-
"lens": "product",
|
|
178
|
-
"status": "open",
|
|
191
|
+
"priority": "P1", // P0 | P1 | P2 | P3
|
|
192
|
+
"lens": "product", // security|correctness|performance|architecture|product|ops
|
|
193
|
+
"status": "open", // open | backlog | fixed | wontfix
|
|
179
194
|
"title": "…",
|
|
180
195
|
"summary": "…",
|
|
181
196
|
"fix": "…",
|
|
182
|
-
"leverage": { "impact": "high", "effort": "low" },
|
|
183
|
-
"blastRadius": ["web-agent-bridge"],
|
|
197
|
+
"leverage": { "impact": "high", "effort": "low" }, // impact/effort ∈ low|medium|high
|
|
198
|
+
"blastRadius": ["web-agent-bridge"], // [] if none
|
|
184
199
|
"cites": [{ "file": "…", "line": "25", "token": "…" }],
|
|
185
|
-
"path": "improve/improvements/dead-model-options-google-crewai.md"
|
|
186
|
-
}
|
|
187
|
-
]
|
|
200
|
+
"path": "improve/improvements/dead-model-options-google-crewai.md",
|
|
201
|
+
},
|
|
202
|
+
],
|
|
188
203
|
}
|
|
189
204
|
```
|
|
190
205
|
|
|
@@ -197,6 +212,16 @@ Ingest is `JSON.parse` + a shape-check against this schema. Any mismatch (missin
|
|
|
197
212
|
key, wrong enum, wrong type, unknown `schemaVersion`) → a **surfaced ingest error**
|
|
198
213
|
on the platform, never a guessed value.
|
|
199
214
|
|
|
215
|
+
**Size stamps (`bodyTokens`, `cites[].targetTokens`) are ADDITIVE OPTIONAL.** compile
|
|
216
|
+
stamps each note's body-token estimate and, per cite, the cited file's token estimate —
|
|
217
|
+
both `ceil(chars/4)`, computed deterministically at compile time (no LLM, no network) to
|
|
218
|
+
feed the platform's recall-savings estimator. `targetTokens` is **omitted** for any cite
|
|
219
|
+
whose target is unreadable at compile (honest absence — never a guessed `0`). Because
|
|
220
|
+
these fields are purely additive and optional, `schemaVersion` **stays 1**: ingest never
|
|
221
|
+
refuses a manifest for lacking them, so a legacy manifest produced without them (or with
|
|
222
|
+
some cites carrying no `targetTokens`) remains valid. The shape-check treats them as
|
|
223
|
+
optional and tolerates their absence.
|
|
224
|
+
|
|
200
225
|
---
|
|
201
226
|
|
|
202
227
|
## 2. Note files — `brain/rules/*.md`, `brain/playbooks/*.md`
|
|
@@ -206,22 +231,24 @@ on the platform, never a guessed value.
|
|
|
206
231
|
```yaml
|
|
207
232
|
---
|
|
208
233
|
schemaVersion: 1
|
|
209
|
-
id: agent-name-contract
|
|
210
|
-
type: contract
|
|
211
|
-
domain: web-agent-bridge
|
|
212
|
-
title: The agent name is a cross-process contract
|
|
213
|
-
summary: Only "research_agent" is fully wired end to end
|
|
214
|
-
links: [copilotkit-runtime-route-convention]
|
|
215
|
-
failure: silent
|
|
216
|
-
anchor:
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
234
|
+
id: agent-name-contract # required · == filename stem
|
|
235
|
+
type: contract # required · contract | convention | flow | how-to
|
|
236
|
+
domain: web-agent-bridge # required · non-empty
|
|
237
|
+
title: The agent name is a cross-process contract # required
|
|
238
|
+
summary: Only "research_agent" is fully wired end to end # required
|
|
239
|
+
links: [copilotkit-runtime-route-convention] # optional · default []
|
|
240
|
+
failure: silent # optional · silent | loud
|
|
241
|
+
anchor:
|
|
242
|
+
research_agent # optional · checker gate B2: EVERY code hit of this
|
|
243
|
+
# token must be a cited site (`anchor: none` = explicit
|
|
244
|
+
# exemption for composition/ordering contracts)
|
|
245
|
+
absent:
|
|
246
|
+
legacy_agent_name # optional · checker gate B3: this token must appear
|
|
247
|
+
# NOWHERE in code (docs/.md excluded) — declare one for
|
|
248
|
+
# every claim that depends on something NOT existing;
|
|
249
|
+
# the checker re-greps it every run, so the claim can
|
|
250
|
+
# never silently go stale. Repeatable (one per line).
|
|
251
|
+
cites: # required · ≥ 1
|
|
225
252
|
- src/lib/model-selector-provider.tsx:42 :: research_agent
|
|
226
253
|
- agents/python/main.py:20 :: research_agent
|
|
227
254
|
---
|
|
@@ -241,18 +268,18 @@ value).
|
|
|
241
268
|
```yaml
|
|
242
269
|
---
|
|
243
270
|
schemaVersion: 1
|
|
244
|
-
id: dead-model-options-google-crewai
|
|
245
|
-
priority: P1
|
|
246
|
-
lens: product
|
|
247
|
-
status: open
|
|
248
|
-
title: Two of the four model options are dead and fail silently
|
|
249
|
-
summary: google_genai and crewai route to unwired agents
|
|
250
|
-
fix: Wire both agents in main.py, or remove them from the picker
|
|
251
|
-
leverage: { impact: high, effort: low }
|
|
252
|
-
blast_radius: [web-agent-bridge, external-integrations]
|
|
253
|
-
cites:
|
|
271
|
+
id: dead-model-options-google-crewai # required · == filename stem
|
|
272
|
+
priority: P1 # required · P0 | P1 | P2 | P3
|
|
273
|
+
lens: product # required · security|correctness|performance|architecture|product|ops
|
|
274
|
+
status: open # required · open | backlog | fixed | wontfix
|
|
275
|
+
title: Two of the four model options are dead and fail silently # required
|
|
276
|
+
summary: google_genai and crewai route to unwired agents # required
|
|
277
|
+
fix: Wire both agents in main.py, or remove them from the picker # required
|
|
278
|
+
leverage: { impact: high, effort: low } # required · impact/effort ∈ low|medium|high
|
|
279
|
+
blast_radius: [web-agent-bridge, external-integrations] # optional · default []
|
|
280
|
+
cites: # required · ≥ 1
|
|
254
281
|
- src/components/ModelSelector.tsx:25 :: google_genai
|
|
255
|
-
found: 2026-07-02
|
|
282
|
+
found: 2026-07-02 # optional · ISO date
|
|
256
283
|
---
|
|
257
284
|
(prose body)
|
|
258
285
|
```
|
|
@@ -267,10 +294,10 @@ from prose. That scraping is gone; these are authored values.
|
|
|
267
294
|
```yaml
|
|
268
295
|
---
|
|
269
296
|
schemaVersion: 1
|
|
270
|
-
verdict: PASS
|
|
271
|
-
score: 95
|
|
272
|
-
gates: { fidelity: pass, coverage: pass }
|
|
273
|
-
counts: { blockers: 0, majors: 0, minors: 2 }
|
|
297
|
+
verdict: PASS # required · PASS | ITERATE
|
|
298
|
+
score: 95 # required · 0–100
|
|
299
|
+
gates: { fidelity: pass, coverage: pass } # required · each pass | fail
|
|
300
|
+
counts: { blockers: 0, majors: 0, minors: 2 } # required · non-negative ints
|
|
274
301
|
---
|
|
275
302
|
(prism report body)
|
|
276
303
|
```
|
|
@@ -332,24 +359,25 @@ Each item owns exactly one file (merges never conflict; progress is derived).
|
|
|
332
359
|
```yaml
|
|
333
360
|
---
|
|
334
361
|
schemaVersion: 1
|
|
335
|
-
id: payments-c3-webhooks
|
|
336
|
-
plan: payments
|
|
337
|
-
parent: payments-c3
|
|
338
|
-
kind: epic | task | subtask
|
|
339
|
-
title: Handle provider webhooks
|
|
340
|
-
description:
|
|
362
|
+
id: payments-c3-webhooks # required · == filename stem · GLOBALLY unique across plans/**
|
|
363
|
+
plan: payments # required · the ROOT (epic) id
|
|
364
|
+
parent: payments-c3 # required · the parent ITEM id (any rank above), or null (epic)
|
|
365
|
+
kind: epic | task | subtask # required · epic = root only · task's parent = the epic · subtask's parent = a task
|
|
366
|
+
title: Handle provider webhooks # required · WHAT (Linear title · Jira summary · Asana name)
|
|
367
|
+
description:
|
|
368
|
+
>- # optional · WHY + context — syncs 1:1 with vendor description/notes
|
|
341
369
|
reconciliation must be automatic; manual matching doesn't scale
|
|
342
|
-
approach: verify HMAC → enqueue → idempotent apply
|
|
343
|
-
status: todo | in-progress | done | superseded | abandoned
|
|
344
|
-
assignee: rohik
|
|
345
|
-
blocked_by: [payments-c2]
|
|
346
|
-
blocked_reason: "vendor sandbox access"
|
|
347
|
-
priority: 2
|
|
348
|
-
estimate: 3
|
|
349
|
-
branch: feat/webhooks
|
|
350
|
-
baseSha: abc123
|
|
351
|
-
domains: [payments]
|
|
352
|
-
external: { provider: jira, key: PAY-142 }
|
|
370
|
+
approach: verify HMAC → enqueue → idempotent apply # optional · HOW, one line — rafa value-add
|
|
371
|
+
status: todo | in-progress | done | superseded | abandoned # required (task/subtask); epic may omit
|
|
372
|
+
assignee: rohik # optional · WHO (free string pre-orgs; unanimous vendor word)
|
|
373
|
+
blocked_by: [payments-c2] # optional · item ids this waits on — a dependency IS a blocker
|
|
374
|
+
blocked_reason: "vendor sandbox access" # optional · external blocks (no dependency id to point at)
|
|
375
|
+
priority: 2 # optional · 0 none · 1 urgent · 2 high · 3 medium · 4 low (Linear scale)
|
|
376
|
+
estimate: 3 # optional · points (Linear estimate / Jira story points)
|
|
377
|
+
branch: feat/webhooks # optional · ↔ Linear branchName
|
|
378
|
+
baseSha: abc123 # optional · commit it was cut from
|
|
379
|
+
domains: [payments] # optional · EPIC only · the blast radius — the brain link
|
|
380
|
+
external: { provider: jira, key: PAY-142 } # optional · tracker identity — READ-ONLY to sessions
|
|
353
381
|
---
|
|
354
382
|
(prose body — a LEAF item (a task with no subtasks, or a subtask) MUST carry a
|
|
355
383
|
`## Done-check`; `## Log` is the execution journal; `## Decisions` mirrors the
|
|
@@ -384,7 +412,7 @@ Rules (all compile-enforced unless noted):
|
|
|
384
412
|
**Decisions — first-class deliberation records (channel-borne, never frontmatter):**
|
|
385
413
|
the frontmatter grammar is flat and bodies are never parsed, so structured decisions
|
|
386
414
|
live on the PLATFORM, pushed via `log_decision` at checkpoint moments:
|
|
387
|
-
`{ item, at, actor, context, options[], decision, rationale }` —
|
|
415
|
+
`{ item, at, actor, context, options[], decision, rationale }` — _actor_ is who
|
|
388
416
|
decided (the dev for steering; the agent for proposals it made under standing
|
|
389
417
|
consent). Text fidelity: **paraphrase + short verbatim quotes only where the exact
|
|
390
418
|
wording carries the decision** (transcripts never land in shared stores). Sessions
|
|
@@ -414,7 +442,10 @@ imported comments are never scraped into decisions.
|
|
|
414
442
|
## 8. Versioning & the validate-and-correct loop
|
|
415
443
|
|
|
416
444
|
- **`schemaVersion`** bumps when this contract changes incompatibly. Ingest refuses
|
|
417
|
-
an unknown version (surfaced error) rather than mis-reading it.
|
|
445
|
+
an unknown version (surfaced error) rather than mis-reading it. **Additive OPTIONAL
|
|
446
|
+
fields do NOT bump it** — e.g. the note size stamps (`bodyTokens`,
|
|
447
|
+
`cites[].targetTokens`, §1): ingest tolerates their absence, so a legacy manifest
|
|
448
|
+
without them stays valid at the same `schemaVersion`.
|
|
418
449
|
- **Validate-and-correct:** `rafa compile` validates every file. On failure it emits
|
|
419
450
|
a structured error — `path · field · rule` — to the **authoring agent** (atlas for
|
|
420
451
|
notes, bloom for improvements/ledger, prism for checklist). The agent edits the
|
|
@@ -428,18 +459,18 @@ imported comments are never scraped into decisions.
|
|
|
428
459
|
|
|
429
460
|
The platform serves the **ingested** brain to any MCP client (the build agent, a
|
|
430
461
|
teammate's session, Slack/incident.io agents) — the read-side twin of this contract.
|
|
431
|
-
One backend: the platform. Local files are the
|
|
432
|
-
the
|
|
462
|
+
One backend: the platform. Local files are the _authoring_ surface; the platform is
|
|
463
|
+
the _serving_ surface, and it serves only what passed compile + ingest.
|
|
433
464
|
|
|
434
465
|
**Envelope — mandatory on every tool response:**
|
|
435
466
|
|
|
436
467
|
```jsonc
|
|
437
468
|
{
|
|
438
469
|
"source": "platform",
|
|
439
|
-
"brainForSha": "<snapshot codeSha>",
|
|
470
|
+
"brainForSha": "<snapshot codeSha>", // the ingested manifest's codeSha — one source
|
|
440
471
|
"ingestedAt": "<ISO time of ingest>",
|
|
441
472
|
"schemaVersion": 1,
|
|
442
|
-
"synthesized": false
|
|
473
|
+
"synthesized": false, // raw tools: always false
|
|
443
474
|
}
|
|
444
475
|
```
|
|
445
476
|
|
|
@@ -451,15 +482,16 @@ match.
|
|
|
451
482
|
|
|
452
483
|
**Tools (read-only — ALL writes flow files → compile → push → ingest):**
|
|
453
484
|
|
|
454
|
-
| Tool
|
|
455
|
-
|
|
456
|
-
| `get_brain_status`
|
|
457
|
-
| `get_coverage`
|
|
458
|
-
| `search_knowledge`
|
|
459
|
-
| `
|
|
460
|
-
| `
|
|
461
|
-
| `
|
|
462
|
-
| `
|
|
485
|
+
| Tool | Args | Returns |
|
|
486
|
+
| ----------------------------------------------- | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
487
|
+
| `get_brain_status` | `repo` | envelope + per-type counts, health, coverage summary, `activePlanId`, `ingestError?` |
|
|
488
|
+
| `get_coverage` | `repo` | coverage rows (the domain map — how an agent navigates) |
|
|
489
|
+
| `search_knowledge` | `q`, `types?`, `domain?`, `limit?` | ranked candidates (fields per type below) |
|
|
490
|
+
| `ask_knowledge` | `repo`, `q` | the guarded synthesis read (below) — `{answer, synthesized, citations[], retrieval, usage?}` |
|
|
491
|
+
| `get_rule` / `get_playbook` / `get_improvement` | `repo`, `id` | full frontmatter + lazy-fetched body + cites as objects |
|
|
492
|
+
| `list_improvements` | `repo`, `status?`, `priority?`, `domain?` | ledger rows |
|
|
493
|
+
| `get_plan` | `repo`, `id` (parent or child) | parent + all children **with stored bodies** + **derived** progress; a child id resolves the whole plan with `requestedChild` set — this is what "load plan X" materializes into `.rafa/plans/` |
|
|
494
|
+
| `get_active_plan` | `repo` | resolves the channel pointer (`set_active_plan`) → `get_plan`, or "no active plan" |
|
|
463
495
|
|
|
464
496
|
`repo` must match the key's scope exactly; `branch` is reserved (branch-keyed
|
|
465
497
|
instances land in Slice 2 — third-party clients default to the production brain,
|
|
@@ -471,8 +503,32 @@ improvement: `title, summary, lens, blast_radius` · plan: `title, plan, parent`
|
|
|
471
503
|
Score = Σ over matched case-folded query tokens of field weight (`title` 3 ·
|
|
472
504
|
`domain`/`lens`/`blast_radius`/`type`/`plan`/`parent` 2 · `summary` 1); tie-break
|
|
473
505
|
score desc then id asc; fields a type lacks are omitted, never defaulted. Candidates
|
|
474
|
-
carry `matchKind: "lexical"` (`"semantic"` reserved).
|
|
475
|
-
|
|
506
|
+
carry `matchKind: "lexical"` (`"semantic"` reserved).
|
|
507
|
+
|
|
508
|
+
**`ask_knowledge` — the guarded synthesis read (the reserved id, filled 2026-07-13
|
|
509
|
+
per the served-brain spec).** For THIN clients (Slack bots, dashboards); full agents
|
|
510
|
+
should prefer `search_knowledge` + `get_*` and compose with their own model. The
|
|
511
|
+
guarantees, in order: 0. **Enumerable intents route deterministically BEFORE retrieval** — command-shaped
|
|
512
|
+
asks ("list improvements [open|P0]", "list plans", "status/health", "coverage")
|
|
513
|
+
return the actual rows (`retrieval.matchKind: "intent"`, `items[]`), no LLM
|
|
514
|
+
involved. Interrogatives (how/why/where/when) always retrieve instead — a missed
|
|
515
|
+
intent degrades to search; a wrong intent would answer the wrong thing.
|
|
516
|
+
|
|
517
|
+
1. **Retrieval first, deterministic** — the same lexical scorer, top-K candidates.
|
|
518
|
+
2. **Empty = honest empty**: `{answer: null, synthesized: false, found: 0}` with a
|
|
519
|
+
"no knowledge found" message — never composed from general knowledge; the empty
|
|
520
|
+
ask is logged into the same knowledge-gaps feed as an empty search
|
|
521
|
+
(`payload.via: "ask"`).
|
|
522
|
+
3. **Composition uses retrieved cited notes ONLY**; answers are marked
|
|
523
|
+
`synthesized: true` and carry `citations[]` ({id, title, kind, domain?, path}).
|
|
524
|
+
4. **Raw mode**: with no org synthesis key configured, returns `rawMode: true` +
|
|
525
|
+
the top cited candidates (no LLM call) — the surface degrades to search, never
|
|
526
|
+
to silence or invention.
|
|
527
|
+
5. **Custody**: synthesis runs on the ORG'S OWN LLM key (a platform tokens row,
|
|
528
|
+
provider `anthropic`, encrypted at rest, decrypted per call server-side, never
|
|
529
|
+
logged). Usage is metered to `usageEvents` (purpose `ask`, runner `platform`).
|
|
530
|
+
6. **Caps are loud**: a per-repo daily cap returns an explicit error, never a
|
|
531
|
+
silent throttle.
|
|
476
532
|
|
|
477
533
|
**Auth:** per-repo machine keys, minted on the platform, sent as
|
|
478
534
|
`Authorization: Bearer`. Keys are stored hashed platform-side and live client-side in
|
|
@@ -491,15 +547,15 @@ The knowledge plane stays strictly read-only (org-brain writes go ONLY through
|
|
|
491
547
|
files → compile → push → ingest). Seven additional tools write **collaboration
|
|
492
548
|
state**, marked by `envelope.plane: "state"`:
|
|
493
549
|
|
|
494
|
-
| Tool
|
|
495
|
-
|
|
496
|
-
| `list_dev_insights` / `put_dev_insight` / `remove_dev_insight`
|
|
497
|
-
| `checkpoint_sync`
|
|
498
|
-
| `get_working_set`
|
|
499
|
-
| `resolve_working_file`
|
|
500
|
-
| `fold_working_set`
|
|
501
|
-
| `push_plan` / `list_plans` / `update_plan_status` / `set_active_plan` / `log_decision` | **plans** — (repo) work objects
|
|
502
|
-
| `report_improvement_status`
|
|
550
|
+
| Tool | Store | Notes |
|
|
551
|
+
| -------------------------------------------------------------------------------------- | ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
552
|
+
| `list_dev_insights` / `put_dev_insight` / `remove_dev_insight` | **user brain** — account-scoped, cross-repo, PRIVATE | consent-gated by the conductor; never logged to repo activity; nothing person-scoped is ever served to another user |
|
|
553
|
+
| `checkpoint_sync` | **branch working set** — (repo, branch, file path) rows | pushes edited/new brain files from the lazy `.rafa/` instance at CHECKPOINTS (task done · plan approved · explicit ask · cadence · git push/pull — never session-end) under **base-version CAS**: each file carries the row `version` last seen (null = create); a stale base returns the newer copy as a per-file conflict for the HUMAN in that session to resolve |
|
|
554
|
+
| `get_working_set` | branch working set | hydration (a session starts with its branch's working set), the branch view, distillation collect; `needs-adjudication` rows carry the incoming copy in `pending` |
|
|
555
|
+
| `resolve_working_file` | branch working set | `distilled` / `refuted` (+ cited note) at merge-to-main distillation; `keep-current` for adjudication decisions; CAS on status — a racing distill fails loudly |
|
|
556
|
+
| `fold_working_set` | branch working set | branch→parent-branch MECHANICAL fold (no LLM, no prism — rigor only at main): absent → re-keyed · identical → merged · divergent → `needs-adjudication` on the parent row |
|
|
557
|
+
| `push_plan` / `list_plans` / `update_plan_status` / `set_active_plan` / `log_decision` | **plans** — (repo) work objects | the push-on-approval channel (§7 v2): approval pushes the whole work-item TREE (items[], bodies stored); `list_plans` = names only; statuses push back (5-value enum — blocked is derived); `log_decision` records the deliberation trail (paraphrase + pivotal quotes); the active pointer is explicit, never inferred |
|
|
558
|
+
| `report_improvement_status` | **events only** — no store | a LIVE session signal (bloom's fixed-in-passing during build). The improvement ledger row is untouched — it has ONE writer, the ingest (K1); the platform overlays the report as pending-reconciliation until the next brain push confirms it |
|
|
503
559
|
|
|
504
560
|
State tools work with or without an ingested brain (a working set can exist —
|
|
505
561
|
and a plan can be pushed — before the first scan) and are exempt from the
|
|
@@ -529,7 +585,8 @@ duties: # required · block list, ≥ 1 · each a duty DSL s
|
|
|
529
585
|
---
|
|
530
586
|
```
|
|
531
587
|
|
|
532
|
-
**Duty DSL** (one string per duty, split on
|
|
588
|
+
**Duty DSL** (one string per duty, split on `::`, exactly three parts):
|
|
589
|
+
|
|
533
590
|
- `duty` — kebab-case name of the responsibility.
|
|
534
591
|
- `sop-path` — path relative to the CODE repo root (e.g.
|
|
535
592
|
`.claude/skills/rafa-validate/SKILL.md`); the file MUST exist at compile time (a
|
|
@@ -538,7 +595,7 @@ duties: # required · block list, ≥ 1 · each a duty DSL s
|
|
|
538
595
|
- `bar` — the explicit pass/fail sentence for this duty. Never empty: a duty whose
|
|
539
596
|
bar can't be stated can't be validated, so it doesn't ship.
|
|
540
597
|
|
|
541
|
-
Versioning: bump `version:` with any card change; record the
|
|
598
|
+
Versioning: bump `version:` with any card change; record the _why_ outside the card
|
|
542
599
|
(cards ship to end users and stay clean of build-log clutter).
|
|
543
600
|
|
|
544
601
|
---
|
|
@@ -45,9 +45,14 @@ platform MCP (one read path — the same surface any third-party agent uses).
|
|
|
45
45
|
steering, the agent for its own proposals; PARAPHRASE + short verbatim
|
|
46
46
|
quotes only where the wording carries the decision — transcripts never land
|
|
47
47
|
in shared stores; mirror each into the item's `## Decisions` section) +
|
|
48
|
+
**`report_loop_event(category: "prism-verdict", outcome: PASS|ITERATE,
|
|
49
|
+
subject: <task id>)`** at the moment prism rules on the Done-check (sage's
|
|
50
|
+
evidence — shapes only: the verdict + the task id, never code) +
|
|
48
51
|
`rafa checkpoint` (the branch working set), so the platform and every MCP
|
|
49
52
|
consumer reflect live progress. Checkpoint moments: task done · plan
|
|
50
53
|
approved · explicit ask · cadence · git push/pull — never session-end. The
|
|
54
|
+
loop-event emits ride the SAME checkpoint beats — one per outcome as it
|
|
55
|
+
occurs, monotonic, NEVER a session-end sweep. The
|
|
51
56
|
git-push boundary is MECHANICAL (M5): the pre-push hook runs `rafa checkpoint`
|
|
52
57
|
itself, non-blocking — the session still owns the task-done/plan-approved
|
|
53
58
|
moments. A checkpoint CONFLICT (a teammate's newer copy of the same file) is
|
|
@@ -56,7 +61,10 @@ platform MCP (one read path — the same surface any third-party agent uses).
|
|
|
56
61
|
3. **Brain changes mid-build — WHERE you are decides WHERE it goes.**
|
|
57
62
|
- **On the default branch (main):** run a full `/rafa scan` (regenerate →
|
|
58
63
|
prism → compile → push); the brain re-stamps at the new sha, so
|
|
59
|
-
`brain = f(code@sha)` stays exact.
|
|
64
|
+
`brain = f(code@sha)` stays exact. When the gate runs, emit
|
|
65
|
+
**`report_loop_event(category: "gate-result", outcome: exit0|failed,
|
|
66
|
+
subject: <compile|verify-citations>)`** at that checkpoint beat — the gate's
|
|
67
|
+
own moment, never deferred to session-end.
|
|
60
68
|
- **On any other branch:** the org brain is NEVER written from a branch —
|
|
61
69
|
it describes main, and a branch-state scan would poison it for everyone.
|
|
62
70
|
Invalidated/learned knowledge → the branch **working set**: hydrate the
|
|
@@ -57,7 +57,12 @@ code it describes.
|
|
|
57
57
|
CAS: only a live row resolves; a failure means ANOTHER runner already
|
|
58
58
|
distilled this branch — STOP and reconcile against what it shipped.
|
|
59
59
|
`resolve_working_file(path, refuted, note)` for failures — TELL the author
|
|
60
|
-
which files died and why (cited); refutation is feedback, not silence.
|
|
60
|
+
which files died and why (cited); refutation is feedback, not silence. At
|
|
61
|
+
that same resolve beat emit **`report_loop_event(category:
|
|
62
|
+
"distill-refutation", outcome: refuted|distilled, subject: <path or note
|
|
63
|
+
id>)`** — sage's evidence that a claim met the gates or was refuted (shapes
|
|
64
|
+
only: the outcome + a file/note reference, never the refuted content, never
|
|
65
|
+
the cited code). Checkpoint-adjacent, monotonic, never a session-end sweep.
|
|
61
66
|
`resolve_working_file(path, needs-adjudication, note)` for the undecidable —
|
|
62
67
|
the next session's digest offers the decision.
|
|
63
68
|
|