@rafinery/cli 0.2.2 → 0.4.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 +105 -0
- package/README.md +17 -7
- package/bin/rafa.mjs +78 -8
- package/blueprint/.claude/agents/atlas.md +28 -20
- package/blueprint/.claude/agents/bloom.md +15 -8
- package/blueprint/.claude/agents/compass.md +46 -0
- package/blueprint/.claude/agents/prism.md +42 -25
- package/blueprint/.claude/commands/rafa.md +190 -13
- package/blueprint/.claude/rafa/contract.md +482 -0
- package/blueprint/.claude/skills/rafa-build/SKILL.md +76 -0
- package/blueprint/.claude/skills/rafa-distill/SKILL.md +87 -0
- package/blueprint/{.rafa/capabilities/improve.md → .claude/skills/rafa-improve/SKILL.md} +10 -5
- package/blueprint/.claude/skills/rafa-insights/SKILL.md +71 -0
- package/blueprint/{.rafa/capabilities/leverage.md → .claude/skills/rafa-leverage/SKILL.md} +9 -4
- package/blueprint/.claude/skills/rafa-plan/SKILL.md +74 -0
- package/blueprint/{.rafa/capabilities/scan.md → .claude/skills/rafa-scan/SKILL.md} +14 -9
- package/blueprint/{.rafa/capabilities/validate.md → .claude/skills/rafa-validate/SKILL.md} +14 -5
- package/lib/blueprint.mjs +22 -12
- package/lib/brain-repo.mjs +100 -0
- package/lib/checkpoint.mjs +138 -0
- package/lib/ci-setup.mjs +109 -0
- package/lib/claude-config.mjs +5 -5
- package/lib/compile.mjs +6 -21
- package/lib/distill.mjs +237 -0
- package/lib/fold.mjs +53 -0
- package/lib/gate/compile.mjs +549 -0
- package/lib/gate/verify-citations.mjs +156 -0
- package/lib/hydrate.mjs +96 -0
- package/lib/init.mjs +69 -35
- package/lib/leverage/adapters/claude-code.mjs +5 -4
- package/lib/mcp-client.mjs +97 -0
- package/lib/mcp-config.mjs +93 -0
- package/lib/migrations/index.mjs +39 -3
- package/lib/pull.mjs +129 -0
- package/lib/push.mjs +93 -14
- package/lib/releases.mjs +36 -0
- package/lib/verify-citations.mjs +9 -0
- package/lib/working-set.mjs +113 -0
- package/package.json +2 -2
- package/blueprint/.rafa/bin/rafa-compile.mjs +0 -390
- package/blueprint/.rafa/bin/rafa-push.mjs +0 -75
- package/blueprint/.rafa/bin/verify-citations.mjs +0 -153
- package/blueprint/.rafa/capabilities/build.md +0 -38
- package/blueprint/.rafa/capabilities/plan.md +0 -38
- package/blueprint/.rafa/contract.md +0 -303
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
# rafa brain contract — v1
|
|
2
|
+
|
|
3
|
+
The strict protocol every brain file obeys, and the `manifest.json` the platform
|
|
4
|
+
ingests. This is the **single source of truth** shared by the writers (atlas, bloom,
|
|
5
|
+
prism) and the reader (the platform ingest). If a file violates this, the compile
|
|
6
|
+
step **fails loudly** and the authoring agent must correct it — the platform never
|
|
7
|
+
guesses, never assumes a value.
|
|
8
|
+
|
|
9
|
+
**Canonical home: `.claude/rafa/contract.md` in the CODE repo** (blueprint split,
|
|
10
|
+
0.4.0) — the contract versions with the CLI that implements it (`rafa compile` ships
|
|
11
|
+
inside `@rafinery/cli`, never vendored). A **stamped copy** rides every brain push as
|
|
12
|
+
`contract.md` in the brain repo, so any reader of the brain repo knows which contract
|
|
13
|
+
version that brain conforms to.
|
|
14
|
+
|
|
15
|
+
Pipeline:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
agents write .md (frontmatter per this contract)
|
|
19
|
+
→ rafa compile (deterministic: parse frontmatter, VALIDATE, fail loudly)
|
|
20
|
+
├ FAIL → structured error (file · field · rule) → author agent fixes → retry
|
|
21
|
+
└ PASS → emit manifest.json
|
|
22
|
+
→ git push → webhook → INGEST = JSON.parse(manifest) + shape-check → Convex
|
|
23
|
+
→ query APIs (per repo+branch) → platform renders
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Two enforcement points: **compile-time** (structure — this contract) and **prism**
|
|
27
|
+
(semantics — truth of the content). Structure is validated *before* semantics.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## File-type registry — every `.rafa` file has a declared class
|
|
32
|
+
|
|
33
|
+
No consumer ever guesses. **Every** file type is classified here; a `structured` type has
|
|
34
|
+
a schema (parse it), a `verbatim` type is prose (display it, never parse for data), a
|
|
35
|
+
`generated` type is machine-written by a named tool. If a file matching a `structured` path
|
|
36
|
+
doesn't validate, compile fails.
|
|
37
|
+
|
|
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
|
+
| active pointer | `active.md` | **generated** | — (`# <plan-id>` or "No active plan"; compile emits it as `activePlanId`, §7) | conductor |
|
|
50
|
+
| contract copy | `contract.md` | **generated** | — (stamped copy of `.claude/rafa/contract.md`, written by `rafa push`) | tool |
|
|
51
|
+
| agent | `.claude/agents/*.md` (code repo) | **structured** (local gate — NOT in manifest) | §10 | rafa |
|
|
52
|
+
|
|
53
|
+
The `agent` type is the one structured type outside `.rafa/`: the shipped agent cards
|
|
54
|
+
in the code repo. Compile validates them (§10) so a malformed card fails the gate like
|
|
55
|
+
any other contract violation, but they are never emitted into `manifest.json` — the
|
|
56
|
+
platform doesn't ingest agents (yet); the gate exists so the agents themselves are
|
|
57
|
+
never un-schema'd. The SOPs the cards point at are committed skills in the code repo
|
|
58
|
+
(`.claude/skills/rafa-*/SKILL.md`); the gate tools are `@rafinery/cli` commands —
|
|
59
|
+
neither lives under `.rafa/`, which holds purely knowledge + state.
|
|
60
|
+
|
|
61
|
+
`structured` types are compiled into `manifest.json` (§1) — that JSON is the ONLY thing the
|
|
62
|
+
platform ingests. `verbatim`/`generated` files are shown as-is in the file browser (fetched
|
|
63
|
+
lazily), never parsed. A file under a `structured` path that isn't in this table → compile
|
|
64
|
+
error (no rogue unschema'd data files).
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 0. Global rules
|
|
69
|
+
|
|
70
|
+
- **Frontmatter is the only machine-read surface.** The markdown **body is prose**
|
|
71
|
+
and is NEVER parsed for data. Every value the platform shows comes from frontmatter
|
|
72
|
+
(via the compiled manifest), or from the body rendered *verbatim* (never scraped).
|
|
73
|
+
- **`schemaVersion` is required** on every file and in the manifest. Unknown version
|
|
74
|
+
→ ingest reports an error, does not guess.
|
|
75
|
+
- **`id` is required and stable.** It MUST equal the filename stem (`foo.md` → `foo`).
|
|
76
|
+
Renames are safe because rows are keyed by `id`, not path.
|
|
77
|
+
- **Required fields are required.** Missing/empty required field = compile failure.
|
|
78
|
+
The validator **never fills a default for a required field** — that would be
|
|
79
|
+
assuming. Optional fields have documented defaults.
|
|
80
|
+
- **Enums are closed.** A value outside the enum = compile failure (not coerced).
|
|
81
|
+
|
|
82
|
+
### Frontmatter grammar (strict subset — the only shapes allowed)
|
|
83
|
+
|
|
84
|
+
Frontmatter is a leading `---` … `---` block. Within it, only these forms are legal;
|
|
85
|
+
anything else is a compile error:
|
|
86
|
+
|
|
87
|
+
```yaml
|
|
88
|
+
key: scalar # string | number | true | false
|
|
89
|
+
key: "quoted string" # quotes stripped
|
|
90
|
+
key: [a, b, c] # flow list of scalars
|
|
91
|
+
key: { a: x, b: y } # flow map of scalars
|
|
92
|
+
key: # block list …
|
|
93
|
+
- item
|
|
94
|
+
- item
|
|
95
|
+
key: >- # folded scalar: continuation lines joined with one space
|
|
96
|
+
first part
|
|
97
|
+
second part
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
No nested block maps, no anchors, no literal (`|`) blocks. The folded scalar (`>-`/`>`)
|
|
101
|
+
is the ONLY multiline form, added for agent cards (§10) whose descriptions fold.
|
|
102
|
+
Deterministic to parse: indented non-empty lines after `>-` join with a single space.
|
|
103
|
+
|
|
104
|
+
### cites DSL
|
|
105
|
+
|
|
106
|
+
Each cite is one string: `` `<path>:<line> :: <token>` ``
|
|
107
|
+
|
|
108
|
+
- split on the **first** ` :: ` → (`left`, `token`)
|
|
109
|
+
- in `left`, split on the **last** `:` → (`path`, `line`)
|
|
110
|
+
- `line` is digits (`"42"`) or a range (`"14-18"`)
|
|
111
|
+
|
|
112
|
+
Compile parses each into `{ file, line, token }`. A cite that doesn't match → error.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## 1. manifest.json — the ingestion contract
|
|
117
|
+
|
|
118
|
+
Machine-generated by `rafa compile`, committed to the brain repo, read by ingest as
|
|
119
|
+
JSON. This is the exact shape the platform binds to.
|
|
120
|
+
|
|
121
|
+
```jsonc
|
|
122
|
+
{
|
|
123
|
+
"schemaVersion": 1,
|
|
124
|
+
"generatedAt": "2026-07-03T10:00:00Z", // ISO-8601, stamped by compile
|
|
125
|
+
"repo": "owner/repo", // CODE repo full_name (identity)
|
|
126
|
+
"branch": "main", // code branch this brain reflects
|
|
127
|
+
"codeSha": "abc123…", // code commit the brain was built for
|
|
128
|
+
|
|
129
|
+
"health": { // from brain/checklist.md — or null
|
|
130
|
+
"verdict": "PASS", // "PASS" | "ITERATE"
|
|
131
|
+
"score": 95, // 0–100
|
|
132
|
+
"gates": { "fidelity": "pass", "coverage": "pass" },
|
|
133
|
+
"counts": { "blockers": 0, "majors": 0, "minors": 2 }
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
"ledger": { // from improve/ledger.md — or null
|
|
137
|
+
"open": 7,
|
|
138
|
+
"debtScore": 13,
|
|
139
|
+
"byPriority": { "P0": 0, "P1": 1, "P2": 3, "P3": 3 }
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
"coverage": { // from brain/coverage.md — or null
|
|
143
|
+
"domains": [ // one row per domain, its scan status
|
|
144
|
+
{ "domain": "design-system", "status": "mapped" },
|
|
145
|
+
{ "domain": "external-integrations", "status": "thin" }
|
|
146
|
+
]
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
"notes": [
|
|
150
|
+
{
|
|
151
|
+
"id": "agent-name-contract",
|
|
152
|
+
"kind": "rule", // "rule" | "playbook" (from directory)
|
|
153
|
+
"type": "contract", // contract | convention | flow | how-to
|
|
154
|
+
"domain": "web-agent-bridge",
|
|
155
|
+
"title": "…",
|
|
156
|
+
"summary": "…",
|
|
157
|
+
"links": ["other-note-id"], // [] if none
|
|
158
|
+
"failure": "silent", // "silent" | "loud" | omitted
|
|
159
|
+
"cites": [{ "file": "src/x.tsx", "line": "42", "token": "research_agent" }],
|
|
160
|
+
"path": "brain/rules/agent-name-contract.md" // prose body (lazy fetch)
|
|
161
|
+
}
|
|
162
|
+
],
|
|
163
|
+
|
|
164
|
+
"improvements": [
|
|
165
|
+
{
|
|
166
|
+
"id": "dead-model-options-google-crewai",
|
|
167
|
+
"priority": "P1", // P0 | P1 | P2 | P3
|
|
168
|
+
"lens": "product", // security|correctness|performance|architecture|product|ops
|
|
169
|
+
"status": "open", // open | backlog | fixed | wontfix
|
|
170
|
+
"title": "…",
|
|
171
|
+
"summary": "…",
|
|
172
|
+
"fix": "…",
|
|
173
|
+
"leverage": { "impact": "high", "effort": "low" }, // impact/effort ∈ low|medium|high
|
|
174
|
+
"blastRadius": ["web-agent-bridge"], // [] if none
|
|
175
|
+
"cites": [{ "file": "…", "line": "25", "token": "…" }],
|
|
176
|
+
"path": "improve/improvements/dead-model-options-google-crewai.md"
|
|
177
|
+
}
|
|
178
|
+
]
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**The manifest carries KNOWLEDGE only.** Plans and the active pointer left it
|
|
183
|
+
(0.4.0 — the plans channel, §7): they are pushed on approval via `push_plan` /
|
|
184
|
+
`set_active_plan` and never ride the brain repo. Legacy manifests carrying
|
|
185
|
+
`plans[]`/`activePlanId` are tolerated and IGNORED by ingest (never written).
|
|
186
|
+
|
|
187
|
+
Ingest is `JSON.parse` + a shape-check against this schema. Any mismatch (missing
|
|
188
|
+
key, wrong enum, wrong type, unknown `schemaVersion`) → a **surfaced ingest error**
|
|
189
|
+
on the platform, never a guessed value.
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## 2. Note files — `brain/rules/*.md`, `brain/playbooks/*.md`
|
|
194
|
+
|
|
195
|
+
`kind` is derived from the directory (`rules/` → `rule`, `playbooks/` → `playbook`).
|
|
196
|
+
|
|
197
|
+
```yaml
|
|
198
|
+
---
|
|
199
|
+
schemaVersion: 1
|
|
200
|
+
id: agent-name-contract # required · == filename stem
|
|
201
|
+
type: contract # required · contract | convention | flow | how-to
|
|
202
|
+
domain: web-agent-bridge # required · non-empty
|
|
203
|
+
title: The agent name is a cross-process contract # required
|
|
204
|
+
summary: Only "research_agent" is fully wired end to end # required
|
|
205
|
+
links: [copilotkit-runtime-route-convention] # optional · default []
|
|
206
|
+
failure: silent # optional · silent | loud
|
|
207
|
+
cites: # required · ≥ 1
|
|
208
|
+
- src/lib/model-selector-provider.tsx:42 :: research_agent
|
|
209
|
+
- agents/python/main.py:20 :: research_agent
|
|
210
|
+
---
|
|
211
|
+
(prose body — rendered verbatim, never parsed)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## 3. Improvement files — `improve/improvements/*.md`
|
|
217
|
+
|
|
218
|
+
```yaml
|
|
219
|
+
---
|
|
220
|
+
schemaVersion: 1
|
|
221
|
+
id: dead-model-options-google-crewai # required · == filename stem
|
|
222
|
+
priority: P1 # required · P0 | P1 | P2 | P3
|
|
223
|
+
lens: product # required · security|correctness|performance|architecture|product|ops
|
|
224
|
+
status: open # required · open | backlog | fixed | wontfix
|
|
225
|
+
title: Two of the four model options are dead and fail silently # required
|
|
226
|
+
summary: google_genai and crewai route to unwired agents # required
|
|
227
|
+
fix: Wire both agents in main.py, or remove them from the picker # required
|
|
228
|
+
leverage: { impact: high, effort: low } # required · impact/effort ∈ low|medium|high
|
|
229
|
+
blast_radius: [web-agent-bridge, external-integrations] # optional · default []
|
|
230
|
+
cites: # required · ≥ 1
|
|
231
|
+
- src/components/ModelSelector.tsx:25 :: google_genai
|
|
232
|
+
found: 2026-07-02 # optional · ISO date
|
|
233
|
+
---
|
|
234
|
+
(prose body)
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Note: `title`, `summary`, `fix` are now **required frontmatter** — previously scraped
|
|
238
|
+
from prose. That scraping is gone; these are authored values.
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## 4. Health file — `brain/checklist.md`
|
|
243
|
+
|
|
244
|
+
```yaml
|
|
245
|
+
---
|
|
246
|
+
schemaVersion: 1
|
|
247
|
+
verdict: PASS # required · PASS | ITERATE
|
|
248
|
+
score: 95 # required · 0–100
|
|
249
|
+
gates: { fidelity: pass, coverage: pass } # required · each pass | fail
|
|
250
|
+
counts: { blockers: 0, majors: 0, minors: 2 } # required · non-negative ints
|
|
251
|
+
---
|
|
252
|
+
(prism report body)
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## 5. Ledger file — `improve/ledger.md`
|
|
258
|
+
|
|
259
|
+
The debt figure is **authored in frontmatter** (bloom's number), not parsed from a
|
|
260
|
+
table. `open`/`by_priority` are cross-checked against the improvement rows at ingest.
|
|
261
|
+
Flat keys only — no nesting (compile maps `debt_score`→`debtScore`, `by_priority`→`byPriority`).
|
|
262
|
+
|
|
263
|
+
```yaml
|
|
264
|
+
---
|
|
265
|
+
schemaVersion: 1
|
|
266
|
+
open: 7
|
|
267
|
+
debt_score: 13
|
|
268
|
+
by_priority: { P0: 0, P1: 1, P2: 3, P3: 3 }
|
|
269
|
+
---
|
|
270
|
+
(human-readable trend/tables in the body)
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## 6. Coverage file — `brain/coverage.md`
|
|
276
|
+
|
|
277
|
+
The scan's breadth report. `domains` is a **flow map** of `domain: status`, one entry per
|
|
278
|
+
domain found (compile emits it as `[{ domain, status }]` in the manifest). Status enum:
|
|
279
|
+
`mapped | thin | stubbed | empty`. The body holds the human per-criterion PASS/FAIL narrative.
|
|
280
|
+
|
|
281
|
+
```yaml
|
|
282
|
+
---
|
|
283
|
+
schemaVersion: 1
|
|
284
|
+
domains: { design-system: mapped, components: mapped, api: thin, external-integrations: empty }
|
|
285
|
+
---
|
|
286
|
+
(per-criterion PASS/FAIL narrative in the body)
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## 7. Plan files — `plans/**/*.md` (+ the plans channel)
|
|
292
|
+
|
|
293
|
+
Each child owns exactly one file (so merges never conflict; parent progress is
|
|
294
|
+
derived by counting).
|
|
295
|
+
|
|
296
|
+
```yaml
|
|
297
|
+
---
|
|
298
|
+
schemaVersion: 1
|
|
299
|
+
id: multitenant-c1-schema # required · == filename stem · GLOBALLY unique across plans/**
|
|
300
|
+
plan: multitenant # required · the parent plan id
|
|
301
|
+
parent: multitenant # required · parent plan id (child), or null (root)
|
|
302
|
+
kind: parent | child # required
|
|
303
|
+
title: … # required
|
|
304
|
+
status: todo | in-progress | done | blocked | superseded | abandoned # required (child); parent may omit
|
|
305
|
+
branch: feat/mt-c1 # optional · the branch this executes on
|
|
306
|
+
baseSha: abc123 # optional · commit it was cut from
|
|
307
|
+
---
|
|
308
|
+
(prose body — for a child it MUST contain a `## Done-check` section: the expected
|
|
309
|
+
outcome prism validates execution against. Compile never parses bodies; a missing
|
|
310
|
+
Done-check is rejected by prism's PLAN validation, not by compile.)
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
Rules (all compile-enforced unless noted):
|
|
314
|
+
|
|
315
|
+
- **Global id uniqueness.** `plans/**` is nested, so stems could collide; a duplicate
|
|
316
|
+
plan id anywhere under `plans/` is a compile error. Convention: prefix children
|
|
317
|
+
with the plan id (`<plan>-c1-….md`).
|
|
318
|
+
- **`kind: parent`** → `parent` MUST be `null` and `plan` MUST equal `id`.
|
|
319
|
+
- **`kind: child`** → `plan` MUST resolve to a `kind: parent` file in the same
|
|
320
|
+
compile, and `parent` MUST equal `plan` (flat parent→children in v1). A dangling
|
|
321
|
+
child is a loud error; a parent with zero children is valid (a plan just created).
|
|
322
|
+
- **Progress is never stored.** A `progress` key in plan frontmatter is a compile
|
|
323
|
+
error. Parent progress is `count(children where status == done) / count(children)`
|
|
324
|
+
— derived at read time, everywhere (compile, platform, MCP).
|
|
325
|
+
- **Statuses.** `done` exists only on prism PASS (the execution gate). The two
|
|
326
|
+
TERMINAL statuses close work honestly without pretending `done`:
|
|
327
|
+
`superseded` (a newer plan replaces it) · `abandoned` (deliberately dropped).
|
|
328
|
+
`blocked` is waiting, not terminal. Statuses are set in sessions; the platform
|
|
329
|
+
board renders them read-only.
|
|
330
|
+
- **`active.md` → `activePlanId`.** Compile reads the generated pointer: a first line
|
|
331
|
+
`# <plan-id>` must resolve to a `kind: parent` plan (else compile error);
|
|
332
|
+
`# No active plan` or a missing `active.md` → `activePlanId: null` (documented
|
|
333
|
+
default — the pointer is generated, absence means "none", never a guess of one).
|
|
334
|
+
The PLATFORM pointer is set separately through `set_active_plan` (below).
|
|
335
|
+
|
|
336
|
+
**Transport — the plans channel (0.4.0; plans never ride the brain manifest):**
|
|
337
|
+
|
|
338
|
+
- **Authoring**: plans are drafted as the files above (compile-validated —
|
|
339
|
+
determinism holds; `.rafa/plans/` is the working copy).
|
|
340
|
+
- **Push on approval**: the dev's approval IS the trigger — `push_plan` sends the
|
|
341
|
+
whole plan (parent + children + bodies) to the platform; `set_active_plan`
|
|
342
|
+
points the repo's active pointer at it. Build cadence re-pushes statuses +
|
|
343
|
+
`## Log` journals (`push_plan` upsert / `update_plan_status`).
|
|
344
|
+
- **Pull-based work**: `list_plans` returns NAMES ONLY (id · title · status ·
|
|
345
|
+
progress); **"load plan X"** = `get_plan` (bodies included) materialized back
|
|
346
|
+
into `.rafa/plans/` by the session. Nothing plan-shaped is hydrated until
|
|
347
|
+
explicitly loaded.
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## 8. Versioning & the validate-and-correct loop
|
|
352
|
+
|
|
353
|
+
- **`schemaVersion`** bumps when this contract changes incompatibly. Ingest refuses
|
|
354
|
+
an unknown version (surfaced error) rather than mis-reading it.
|
|
355
|
+
- **Validate-and-correct:** `rafa compile` validates every file. On failure it emits
|
|
356
|
+
a structured error — `path · field · rule` — to the **authoring agent** (atlas for
|
|
357
|
+
notes, bloom for improvements/ledger, prism for checklist). The agent edits the
|
|
358
|
+
file and compile re-runs. Bounded retries; if it can't converge, a **hard failure**
|
|
359
|
+
blocks the push (better than a silently-wrong brain).
|
|
360
|
+
- The validator **reports, never auto-fills** a required value.
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
## 9. The read side — knowledge MCP (platform-served)
|
|
365
|
+
|
|
366
|
+
The platform serves the **ingested** brain to any MCP client (the build agent, a
|
|
367
|
+
teammate's session, Slack/incident.io agents) — the read-side twin of this contract.
|
|
368
|
+
One backend: the platform. Local files are the *authoring* surface; the platform is
|
|
369
|
+
the *serving* surface, and it serves only what passed compile + ingest.
|
|
370
|
+
|
|
371
|
+
**Envelope — mandatory on every tool response:**
|
|
372
|
+
|
|
373
|
+
```jsonc
|
|
374
|
+
{
|
|
375
|
+
"source": "platform",
|
|
376
|
+
"brainForSha": "<snapshot codeSha>", // the ingested manifest's codeSha — one source
|
|
377
|
+
"ingestedAt": "<ISO time of ingest>",
|
|
378
|
+
"schemaVersion": 1,
|
|
379
|
+
"synthesized": false // raw tools: always false
|
|
380
|
+
}
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
**Error semantics (no assumed values, outward):** snapshot has an `ingestError` →
|
|
384
|
+
every tool returns that error loudly, never partial data. Repo connected but never
|
|
385
|
+
pushed (no snapshot) → `"no brain ingested — run rafa push"`. Invalid/mismatched key
|
|
386
|
+
→ loud auth error, never a fallback. Empty search → empty result, never a stretched
|
|
387
|
+
match.
|
|
388
|
+
|
|
389
|
+
**Tools (read-only — ALL writes flow files → compile → push → ingest):**
|
|
390
|
+
|
|
391
|
+
| Tool | Args | Returns |
|
|
392
|
+
|---|---|---|
|
|
393
|
+
| `get_brain_status` | `repo` | envelope + per-type counts, health, coverage summary, `activePlanId`, `ingestError?` |
|
|
394
|
+
| `get_coverage` | `repo` | coverage rows (the domain map — how an agent navigates) |
|
|
395
|
+
| `search_knowledge` | `q`, `types?`, `domain?`, `limit?` | ranked candidates (fields per type below) |
|
|
396
|
+
| `get_rule` / `get_playbook` / `get_improvement` | `repo`, `id` | full frontmatter + lazy-fetched body + cites as objects |
|
|
397
|
+
| `list_improvements` | `repo`, `status?`, `priority?`, `domain?` | ledger rows |
|
|
398
|
+
| `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/` |
|
|
399
|
+
| `get_active_plan` | `repo` | resolves the channel pointer (`set_active_plan`) → `get_plan`, or "no active plan" |
|
|
400
|
+
|
|
401
|
+
`repo` must match the key's scope exactly; `branch` is reserved (branch-keyed
|
|
402
|
+
instances land in Slice 2 — third-party clients default to the production brain,
|
|
403
|
+
i.e. the default branch's instance).
|
|
404
|
+
|
|
405
|
+
**Search = deterministic lexical retrieval; the server retrieves, the agent decides.**
|
|
406
|
+
Fields searched per type — rule/playbook: `title, summary, domain, type` ·
|
|
407
|
+
improvement: `title, summary, lens, blast_radius` · plan: `title, plan, parent`.
|
|
408
|
+
Score = Σ over matched case-folded query tokens of field weight (`title` 3 ·
|
|
409
|
+
`domain`/`lens`/`blast_radius`/`type`/`plan`/`parent` 2 · `summary` 1); tie-break
|
|
410
|
+
score desc then id asc; fields a type lacks are omitted, never defaulted. Candidates
|
|
411
|
+
carry `matchKind: "lexical"` (`"semantic"` reserved). `ask_knowledge` is a reserved
|
|
412
|
+
tool id for the synthesis layer (responses will carry `synthesized: true`).
|
|
413
|
+
|
|
414
|
+
**Auth:** per-repo machine keys, minted on the platform, sent as
|
|
415
|
+
`Authorization: Bearer`. Keys are stored hashed platform-side and live client-side in
|
|
416
|
+
`~/.config/rafinery/credentials.json` — never inside the code repo or this brain repo.
|
|
417
|
+
|
|
418
|
+
**Client wiring (written by `rafa init`, secret-free where committed):** a key is
|
|
419
|
+
minted at setup generation and delivered consume-once through the setup fetch;
|
|
420
|
+
`.mcp.json` (committed) registers the `rafinery` server with
|
|
421
|
+
`Authorization: Bearer ${RAFA_MCP_KEY}` env expansion; the raw key lands in
|
|
422
|
+
`.claude/settings.local.json` `env` (gitignored) and `~/.config/rafinery/credentials.json`
|
|
423
|
+
(0600). Teammates mint their own key on the platform (repo → Agent access).
|
|
424
|
+
|
|
425
|
+
### §9 addendum — state-plane tools (three-store model, working-set architecture)
|
|
426
|
+
|
|
427
|
+
The knowledge plane stays strictly read-only (org-brain writes go ONLY through
|
|
428
|
+
files → compile → push → ingest). Seven additional tools write **collaboration
|
|
429
|
+
state**, marked by `envelope.plane: "state"`:
|
|
430
|
+
|
|
431
|
+
| Tool | Store | Notes |
|
|
432
|
+
|---|---|---|
|
|
433
|
+
| `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 |
|
|
434
|
+
| `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 |
|
|
435
|
+
| `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` |
|
|
436
|
+
| `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 |
|
|
437
|
+
| `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 |
|
|
438
|
+
| `push_plan` / `list_plans` / `update_plan_status` / `set_active_plan` | **plans** — (repo) work objects | the dedicated push-on-approval channel (§7): approval pushes the whole plan (bodies stored); `list_plans` = names only; statuses push back from sessions; the active pointer is explicit, never inferred |
|
|
439
|
+
|
|
440
|
+
State tools work with or without an ingested brain (a working set can exist —
|
|
441
|
+
and a plan can be pushed — before the first scan) and are exempt from the
|
|
442
|
+
snapshot/ingestError gates. `get_plan`/`get_active_plan` share this exemption
|
|
443
|
+
(plans are work objects, not snapshot-derived knowledge). The retired
|
|
444
|
+
bucket-note tools (`stage/list/resolve_bucket_note`, pre-0.4.0) are superseded
|
|
445
|
+
by the working-set tools.
|
|
446
|
+
|
|
447
|
+
## 10. Agent cards — `../.claude/agents/*.md` (local gate)
|
|
448
|
+
|
|
449
|
+
The shipped agents are contract-governed artifacts: every card is validated by
|
|
450
|
+
`rafa compile` (a malformed agent fails the gate) but never enters `manifest.json`.
|
|
451
|
+
No assumed values — applied to the agents themselves.
|
|
452
|
+
|
|
453
|
+
```yaml
|
|
454
|
+
---
|
|
455
|
+
name: prism # required · MUST equal filename stem
|
|
456
|
+
version: 0.4.0 # required · semver (MAJOR.MINOR.PATCH)
|
|
457
|
+
model: opus # required · non-empty (trailing # comment = the why)
|
|
458
|
+
groundTruth: code-vs-claim # required · code-at-sha | code-vs-claim | code-trend | sessions-over-time
|
|
459
|
+
description: >- # required · non-empty (folded scalar allowed, §0)
|
|
460
|
+
…
|
|
461
|
+
tools: Read, Grep, … # required · non-empty
|
|
462
|
+
color: orange # optional
|
|
463
|
+
duties: # required · block list, ≥ 1 · each a duty DSL string
|
|
464
|
+
- <duty> :: <sop-path> :: <bar>
|
|
465
|
+
---
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
**Duty DSL** (one string per duty, split on ` :: `, exactly three parts):
|
|
469
|
+
- `duty` — kebab-case name of the responsibility.
|
|
470
|
+
- `sop-path` — path relative to the CODE repo root (e.g.
|
|
471
|
+
`.claude/skills/rafa-validate/SKILL.md`); the file MUST exist at compile time (a
|
|
472
|
+
duty without a procedure is a claim, not a contract). Legacy `.rafa/`-relative
|
|
473
|
+
paths (pre-0.4.0 `capabilities/*.md`) still resolve during the migration window.
|
|
474
|
+
- `bar` — the explicit pass/fail sentence for this duty. Never empty: a duty whose
|
|
475
|
+
bar can't be stated can't be validated, so it doesn't ship.
|
|
476
|
+
|
|
477
|
+
Versioning: bump `version:` with any card change; record the *why* outside the card
|
|
478
|
+
(cards ship to end users and stay clean of build-log clutter).
|
|
479
|
+
|
|
480
|
+
---
|
|
481
|
+
|
|
482
|
+
This contract is the thing to test against.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rafa-build
|
|
3
|
+
description: "rafa SOP — execute the active plan task by task: atlas implements from recalled knowledge, prism gates done on each Done-check, bloom sweeps the ledger; progress + journals sync at checkpoints. Loaded on /rafa build."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# build — execute the plan, trio-choreographed, compounding (capability #4)
|
|
7
|
+
|
|
8
|
+
> Status: **active.** The work-time loop where recall + validation + improvement all
|
|
9
|
+
> fire — the mission payoff. Depends on: plan (#3), brain (#1), ledger (#2).
|
|
10
|
+
> Invoke via `/rafa build`.
|
|
11
|
+
|
|
12
|
+
Execute the approved plan with all three agents in the loop, knowledge served by the
|
|
13
|
+
platform MCP (one read path — the same surface any third-party agent uses).
|
|
14
|
+
|
|
15
|
+
## The trio at build time
|
|
16
|
+
|
|
17
|
+
| Role | Agent | Job per task |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| **Executor** | atlas | RECALL the task's brain slice via MCP (`search_knowledge` + `get_rule`/`get_playbook`; honor non-exemplars) → implement, convention-adherent |
|
|
20
|
+
| **Validator** | prism | validate the execution against the child's `## Done-check` — strict, unbiased, against code + brain, never against atlas's claims. **`status: done` only on prism PASS**; FAIL → atlas corrects (validate-and-correct at work time). This gate is conductor-flow SOP — deterministic enforcement is the deferred capture-engine's job |
|
|
21
|
+
| **Improver** | bloom | **push**: new improvement opportunities spotted during execution → new ledger files. **close**: improvements fixed in passing → `status: fixed`. **nudge**: top-leverage open item in the task's blast radius — opt-in, never blocking |
|
|
22
|
+
|
|
23
|
+
## Procedure
|
|
24
|
+
|
|
25
|
+
1. **Resume** — `get_active_plan` (platform) or local `active.md`; staleness check
|
|
26
|
+
(envelope `brainForSha` vs local stamp → prompt `rafa push` if behind). MCP
|
|
27
|
+
recall is automatic throughout — SOP-driven, never dev-invoked; a repo without
|
|
28
|
+
the `rafinery` MCP connected falls back to local `.rafa/` file reads.
|
|
29
|
+
**Session consent (asked ONCE, verbs ENUMERATED):** *"keep the platform
|
|
30
|
+
updated as I work? That means exactly: (1) plan status + Log pushes on
|
|
31
|
+
cadence, (2) checkpointing this branch's working set (edited/new brain
|
|
32
|
+
files) — announced per file as it happens, (3) nothing else."* Revocable
|
|
33
|
+
anytime ("stop pushing"). On "no": journal locally only, push at the end on
|
|
34
|
+
approval. Dev-level insights are NEVER under this consent — each is its own
|
|
35
|
+
offer.
|
|
36
|
+
2. **Per task:** atlas recalls → implements → prism validates vs `## Done-check` →
|
|
37
|
+
bloom sweeps (push new / close fixed / nudge) → update the child file's `status`
|
|
38
|
+
**and append a dated entry to the child's `## Log`** — what was done, what was
|
|
39
|
+
decided, what surprised (body prose: displayed verbatim on the platform, never
|
|
40
|
+
parsed; the plan files at `.rafa/plans/<plan>/` ARE the local cache) → at the
|
|
41
|
+
task-done CHECKPOINT (under the session consent): `push_plan` /
|
|
42
|
+
`update_plan_status` (the plans channel — statuses + Log journals) +
|
|
43
|
+
`rafa checkpoint` (the branch working set), so the platform and every MCP
|
|
44
|
+
consumer reflect live progress. Checkpoint moments: task done · plan
|
|
45
|
+
approved · explicit ask · cadence · git push/pull — never session-end. A
|
|
46
|
+
checkpoint CONFLICT (a teammate's newer copy of the same file) is decided
|
|
47
|
+
IN THIS SESSION: read the `.theirs.md` copy, merge/adopt/keep, re-checkpoint.
|
|
48
|
+
3. **Brain changes mid-build — WHERE you are decides WHERE it goes.**
|
|
49
|
+
- **On the default branch (main):** run a full `/rafa scan` (regenerate →
|
|
50
|
+
prism → compile → push); the brain re-stamps at the new sha, so
|
|
51
|
+
`brain = f(code@sha)` stays exact.
|
|
52
|
+
- **On any other branch:** the org brain is NEVER written from a branch —
|
|
53
|
+
it describes main, and a branch-state scan would poison it for everyone.
|
|
54
|
+
Invalidated/learned knowledge → the branch **working set**: hydrate the
|
|
55
|
+
affected note (`rafa hydrate <rule|playbook> <id>`) and edit it, or author
|
|
56
|
+
a new note file under `.rafa/brain/**` — `rafa checkpoint` syncs it. It
|
|
57
|
+
enters the org brain at merge-to-main, through distillation. This is the
|
|
58
|
+
knowledge-propagates-like-code rule, enforced.
|
|
59
|
+
The working-set files ARE the sanctioned branch authoring surface — what is
|
|
60
|
+
never allowed is editing main's brain around the scan/compile/push gates.
|
|
61
|
+
4. **Verify** (prism-style) before declaring the plan done; final `push_plan` +
|
|
62
|
+
`set_active_plan` (clear) + `rafa checkpoint`. A plan that stops being worth
|
|
63
|
+
finishing closes honestly: `superseded` or `abandoned`, never fake-`done`.
|
|
64
|
+
|
|
65
|
+
**Lite plans** (single-child, from plan-lite) run the same per-task loop — the
|
|
66
|
+
Done-check gate never relaxes; only the ceremony around it shrinks (no bloom nudge,
|
|
67
|
+
single checkpoint + plan push at the end).
|
|
68
|
+
|
|
69
|
+
## Deferred / open
|
|
70
|
+
- **The capture engine** — `Stop`/`PostToolUse` hooks making the gates + capture
|
|
71
|
+
automatic rather than conductor-driven SOP (deterministic-enforcement lesson).
|
|
72
|
+
- **Incremental re-scan** — cite-graph invalidation (diff → invalidate notes citing
|
|
73
|
+
changed files → re-verify/regenerate only those). Needs: partial-brain cache-key
|
|
74
|
+
semantics + the seam-neighbor scope rule. Designed (see
|
|
75
|
+
.fable/sessions/2026-07-07-brain-versioning-and-incremental.md); first post-loop item.
|
|
76
|
+
- Show-thinking + pivot protocol from the atlas character.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rafa-distill
|
|
3
|
+
description: "rafa SOP — merge-time reconciliation: validate a merged branch's WORKING SET against merged MAIN (prism), author survivors into the org brain through verify-citations + compile + push (atlas), refute loudly with citations; contested items flagged needs-adjudication, never guessed. Loaded on /rafa distill or the merge offer; CI runs the same SOP headlessly (rafa distill --headless)."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# distill — merge-time reconciliation of a branch working set into the org brain
|
|
7
|
+
|
|
8
|
+
> Status: **active.** Two runners, ONE SOP: the org's CI (`rafa distill
|
|
9
|
+
> --headless`, installed by `rafa ci-setup`, driven by the ORG'S OWN
|
|
10
|
+
> `ANTHROPIC_API_KEY` — never stored on the platform) and the dev session
|
|
11
|
+
> (offer-driven at bootstrap, or explicit `/rafa distill <branch>`) as the
|
|
12
|
+
> fallback when CI isn't wired or failed. Depends on: brain (#1), the branch
|
|
13
|
+
> working set (synced via `rafa checkpoint`).
|
|
14
|
+
|
|
15
|
+
The rigor gradient this enforces (ratified 2026-07-10): **dev↔dev = CAS + a
|
|
16
|
+
session prompt · branch↔branch = free mechanical fold (no LLM, no prism) ·
|
|
17
|
+
branch→main = full distillation + gates.** Cost tracks consequence. Working-set
|
|
18
|
+
files are candidate-grade — attributed, loose, never served as org truth. The
|
|
19
|
+
merge to main is the one moment rigor fires: what survives validation against
|
|
20
|
+
merged main enters the org brain through the normal gates; what doesn't is
|
|
21
|
+
refuted loudly back to its author; what can't be decided is flagged
|
|
22
|
+
`needs-adjudication` — NEVER guessed. Knowledge propagates exactly like the
|
|
23
|
+
code it describes.
|
|
24
|
+
|
|
25
|
+
## Trigger
|
|
26
|
+
|
|
27
|
+
- **CI (normal path):** the reconcile workflow fires on the PR-merged EVENT
|
|
28
|
+
(squash/rebase-safe — ancestry is never consulted): merge to the default
|
|
29
|
+
branch → `rafa distill --headless <branch>` · branch→parent merge →
|
|
30
|
+
`rafa fold --from <branch> --to <parent>` (mechanical, no LLM).
|
|
31
|
+
- **Offer (session fallback):** at bootstrap the conductor checks
|
|
32
|
+
`get_working_set` for active files on branches whose code reached main —
|
|
33
|
+
*"branch <x> merged with N working-set files — distill now?"* Part of the
|
|
34
|
+
ONE bootstrap digest. Boundary consent; accepted offer = invocation.
|
|
35
|
+
- **Explicit:** `/rafa distill <branch>`.
|
|
36
|
+
|
|
37
|
+
## Procedure (the trio, distillation roles)
|
|
38
|
+
|
|
39
|
+
1. **Collect** — `get_working_set(repo, branch, status: active)`. Zero files →
|
|
40
|
+
nothing to do, say so, stop. Rows already `needs-adjudication` are a HUMAN's
|
|
41
|
+
to resolve — surface them in the digest, never fold them in silently.
|
|
42
|
+
2. **Validate (prism, context-isolated)** — the target is **merged MAIN as of
|
|
43
|
+
NOW, never the fork point and never a stale checkout**: `git fetch origin`
|
|
44
|
+
first; judge every claim against the fetched trunk. Confirm every citation
|
|
45
|
+
resolves (the cited line contains its token — grep it yourself). A claim
|
|
46
|
+
that can't be confirmed with a `file:line` is REFUTED (cited reason).
|
|
47
|
+
Contested/low-confidence → `needs-adjudication`, never a guess. Files about
|
|
48
|
+
code the merge did NOT touch are judged on their own merits, same bar.
|
|
49
|
+
3. **Author (atlas)** — for each survivor: write/update the org-brain file
|
|
50
|
+
(contract §2) with real cites into main; `anchor:` on contracts (hydrated
|
|
51
|
+
files lost it — re-declare); fold into an existing note when one covers the
|
|
52
|
+
topic (supersede, never duplicate).
|
|
53
|
+
4. **Gate + ship** — `rafa verify-citations` AND `rafa compile` to exit 0 →
|
|
54
|
+
`rafa push`. Only now has anything entered the org brain. A failed gate
|
|
55
|
+
aborts EVERYTHING: nothing resolved, nothing pushed, working set intact.
|
|
56
|
+
5. **Resolve** — `resolve_working_file(path, distilled)` for survivors —
|
|
57
|
+
CAS: only a live row resolves; a failure means ANOTHER runner already
|
|
58
|
+
distilled this branch — STOP and reconcile against what it shipped.
|
|
59
|
+
`resolve_working_file(path, refuted, note)` for failures — TELL the author
|
|
60
|
+
which files died and why (cited); refutation is feedback, not silence.
|
|
61
|
+
`resolve_working_file(path, needs-adjudication, note)` for the undecidable —
|
|
62
|
+
the next session's digest offers the decision.
|
|
63
|
+
|
|
64
|
+
## Branch→branch merges (sub-feature → feature): FOLD, don't distill
|
|
65
|
+
|
|
66
|
+
Distillation targets ONLY the default branch. When a sub-feature merges into
|
|
67
|
+
its parent branch, the working set is **folded forward mechanically** —
|
|
68
|
+
`rafa fold --from <branch> --to <parent>` (or the CI fold job): absent on the
|
|
69
|
+
parent → re-keyed · identical content → merged silently · true same-file
|
|
70
|
+
divergence → `needs-adjudication` on the parent row (incoming preserved,
|
|
71
|
+
attributed). No LLM, no prism — the knowledge keeps riding with the code until
|
|
72
|
+
the code reaches main.
|
|
73
|
+
|
|
74
|
+
Sub-feature CONTEXT: a branch's working knowledge = org brain (via MCP) + its
|
|
75
|
+
own working set + unmerged ANCESTOR branches' working sets (the conductor
|
|
76
|
+
derives the ancestor chain from git and calls `get_working_set` per ancestor —
|
|
77
|
+
the platform stores no lineage).
|
|
78
|
+
|
|
79
|
+
## Rules
|
|
80
|
+
|
|
81
|
+
- Validation target is main at distillation time, never the fork point.
|
|
82
|
+
- An abandoned branch's working set is never distilled — it dies with the
|
|
83
|
+
branch (propagation mirrors code).
|
|
84
|
+
- No file skips steps 2–4; there is no fast path into the org brain.
|
|
85
|
+
- CI can detect and flag; only a dev session resolves a human's divergence.
|
|
86
|
+
- Dev-level observations found among the files route to `put_dev_insight`
|
|
87
|
+
(the author's user brain), never to the org brain.
|