From 40adaba31b94067e3be054dc9415bfe15170f5d4 Mon Sep 17 00:00:00 2001 From: chapter37haptics <249148637+chapter37haptics@users.noreply.github.com> Date: Thu, 14 May 2026 20:35:26 +0000 Subject: [PATCH 01/10] =?UTF-8?q?v1:=20customized=20domain=20spec=20?= =?UTF-8?q?=E2=80=94=20closed-loop=20change=20manifest=20for=20VC-to-devel?= =?UTF-8?q?oper=20rewrite?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 10-file change manifest for customizing gbrain from VC/executive use case to developer knowledge base. Three rounds of analysis (write-side only, Codex read-side audit, closed-loop full audit) expanded scope from 3 files to 10. Key finding: quality.md Iron Law is the delegation root that all other files inherit from — must be patched first. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/specs/customized-domain.md | 273 ++++++++++++++++++++++++++++++++ 1 file changed, 273 insertions(+) create mode 100644 docs/specs/customized-domain.md diff --git a/docs/specs/customized-domain.md b/docs/specs/customized-domain.md new file mode 100644 index 000000000..27c9fd4cd --- /dev/null +++ b/docs/specs/customized-domain.md @@ -0,0 +1,273 @@ +# Spec: GBrain Customized Domain (VC to Developer) + +## Goal + +Customize gbrain from a VC/executive personal intelligence system to a developer +knowledge base that documents development processes, architectural decisions, debug +trails, and patterns. The brain should compound development knowledge the same way +upstream gbrain compounds people/company knowledge. + +The key constraint: a new Claude agent in a fresh devcontainer (built from the +Dockerfile at `/workspaces/practicespace-2/.devcontainer/Dockerfile`) should be +able to read the brain and repeat a development process. The brain is institutional +memory that survives across agent sessions and environments. + +## Closed-Loop Criterion + +Knowledge flows in a 6-phase loop. Every file that touches any phase must be +audited. If a file says "people" or "companies" anywhere in the loop, it is a +potential break point where developer knowledge gets lost. + +``` +1. DETECT - agent recognizes something worth capturing +2. WRITE - agent creates/updates a brain page (put_page, add_link, add_timeline_entry) +3. STORE - page lands in PGLite with embeddings for vector search +4. RETRIEVE - agent searches the brain when answering questions (search, query, get_page) +5. PRESENT - agent uses retrieved knowledge in its response +6. ENRICH - on subsequent interactions, agent updates existing pages +``` + +## Developer Entity Types + +Replacing the upstream VC taxonomy (people/, companies/, deals/, meetings/): + +| Directory | Type | Example | Description | +|-----------|------|---------|-------------| +| `projects/` | project | `projects/my-app.md` | Hub pages for active codebases. Sub-pages for project-specific decisions and debug trails | +| `decisions/` | decision | `decisions/chose-postgres-over-sqlite.md` | ADR-style technical decisions with rationale. Cross-project | +| `debug-trails/` | debug-trail | `debug-trails/auth-jwt-rotation-cache-bug.md` | Bugs investigated, root causes, fixes applied | +| `patterns/` | pattern | `patterns/repository-pattern.md` | Reusable dev patterns and practices | +| `processes/` | process | `processes/deploy-to-production.md` | Step-by-step workflows: deploy, test, setup | +| `tools/` | tool | `tools/docker-compose.md` | Tool config, gotchas, setup knowledge | +| `goals/` | goal | `goals/migrate-to-nextjs.md` | Target outcomes per project, links to /goal skill | +| `environments/` | environment | `environments/devcontainer-v2.md` | Devcontainer/Dockerfile fingerprint, toolchain versions | +| `concepts/` | concept | `concepts/event-sourcing.md` | Kept from upstream. Works for dev concepts | +| `meetings/` | meeting | `meetings/2026-05-14-sprint-retro.md` | Kept from upstream. Meetings still happen | + +### Hybrid taxonomy (Option A) + +Project-specific knowledge nests under the project hub: +``` +brain/ ++-- projects/ +| +-- my-app.md <- hub page +| +-- my-app/ +| | +-- decisions/ <- project-specific decisions +| | +-- debug-trails/ <- project-specific debug trails ++-- patterns/ <- cross-project (transferable) ++-- tools/ <- cross-project ++-- processes/ <- cross-project ++-- decisions/ <- cross-project decisions ++-- goals/ ++-- environments/ ++-- concepts/ ++-- meetings/ +``` + +Filing test: does this knowledge transfer to the next project? If yes, file at +the top level. If no, file under the project. + +### Brain-to-skill promotion pipeline + +The brain documents HOW you figured something out. When a process proves +repeatable (2-3 times with only argument changes), it graduates from a +`processes/` brain page to an actual skill file. The brain page keeps the +evidence trail and links to the skill. This is the feedback loop from the +"thin harness, fat skills" ethos. + +- Brain stores: context, evidence, tradeoffs, project-specific constraints, debug history +- Skill files store: stable, parameterized procedures with deterministic steps +- Promotion rule: if reused successfully 2-3 times with only argument changes, graduate to a skill +- Bidirectional links: process page links to skill file path, skill references source brain pages + +## Analysis History (3 rounds) + +### Round 1: Write-side only (3 files) + +First pass identified 3 files to rewrite, 4 to keep unchanged. Focused +entirely on the DETECT and WRITE phases. Did not consider retrieval at all. + +### Round 2: Codex second opinion (+2 read-side patches) + +Codex flagged that 3 write-side files are not sufficient for reliable retrieval: + +- `brain-ops/SKILL.md` Phase 3: "person, company, or topic" biases trigger + behavior. Developer question types need to be explicit. +- `brain-first.md` entity conventions table: acts as a behavioral filter. Agent + constructs slugs from this table. + +### Round 3: Closed-loop audit (+1 skill patch, +2 code patches) + +A fresh agent traced every entity-type mention through all 6 loop phases. + +**Key insight #1: quality.md is NOT domain-neutral.** The previous plan marked +it as "keep unchanged" because citation rules seemed universal. Wrong. +`quality.md` line 25 contains the canonical Iron Law definition: "Every mention +of a person or company WITH a brain page MUST create a back-link." Every other +file's Iron Law reference delegates HERE. If this says "person or company", +back-linking is scoped to only those types system-wide. + +`quality.md` lines 34-36 contain the Notability Gate with criteria for People, +Companies, and Concepts only. Zero criteria for developer entities. Without +positive guidance, the agent defaults to "when in doubt, DON'T create." + +**Key insight #2: brain-ops needs 8 changes, not 1.** Phase 2 trigger (line 69) +is the ENGINE of the loop: "Every message that references a person or company." +If it only fires for people/companies, the READ-ENRICH-WRITE loop is dead for +developer entities. The previous plan found 1 of 8 required changes. + +**Key insight #3: code files participate in the loop.** `link-extraction.ts` +DIR_PATTERN regex only matches upstream directories. Auto-link will NOT create +graph edges for developer directories. `_brain-filing-rules.json` is the +machine-readable companion missing developer `kind` entries. + +## Delegation Chain + +The reason quality.md is the single most important patch: + +``` +signal-detector/SKILL.md line 47 --+ +brain-ops/SKILL.md line 51 --+--> quality.md line 25 (Iron Law canonical def) +_brain-filing-rules.md line 63 --+ "Every mention of a person or company..." + + If this says "person or company", + back-linking is scoped to ONLY those + types system-wide, regardless of what + the other files say. +``` + +Fix quality.md first. Every file that delegates to it inherits the fix. + +## Complete Change Manifest + +### Tier 1: Loop-breaking (without these, developer knowledge is lost) + +#### Files to FULLY REWRITE (3) + +| # | File | Loop Phase | Reason | +|---|------|-----------|--------| +| 1 | `skills/RESOLVER.md` | DETECT | Every trigger is VC-specific. Replace with developer triggers | +| 2 | `skills/signal-detector/SKILL.md` | DETECT + WRITE | Entity detection list (line 70) defines what gets captured. Currently: people, companies, media. Must become: projects, tools, decisions, patterns, processes | +| 3 | `skills/_brain-filing-rules.md` | WRITE + STORE | Entire taxonomy, misfiling table, notability gate, dream-cycle paths | + +#### Skill files to PATCH (3) + +| # | File | Sections to change | Loop Phase | What changes | +|---|------|-------------------|-----------|--------------| +| 4 | `skills/brain-ops/SKILL.md` | Frontmatter `writes_to`, Phase 2 trigger (line 69) + detect (line 71), Iron Law scope (line 49), Phase 4 enrichment triggers (lines 111-112), anti-patterns (line 146). 8 sites total. | ALL | Replace "person or company" with developer entity list at every hard-gate mention | +| 5 | `skills/conventions/brain-first.md` | Header (line 1), entity conventions table (lines 57-64): add 8 rows for developer dirs, replace 4 VC-only rows, remove `deals/` and `yc/` | RETRIEVE | Agent needs slug-construction guidance for all developer directories | +| 6 | `skills/conventions/quality.md` | Iron Law (line 25): generalize to "any entity with a brain page". Notability Gate (lines 34-36): add criteria for projects, decisions, tools, patterns, processes, debug-trails, goals, environments. Example (line 40): replace VC example | WRITE | Root of the delegation chain. All other files inherit from this | + +#### Code/config files to PATCH (2) + +| # | File | What changes | Loop Phase | +|---|------|-------------|-----------| +| 7 | `src/core/link-extraction.ts` | Add `decisions\|debug-trails\|patterns\|processes\|tools\|goals\|environments` to `DIR_PATTERN` regex at line 46 | STORE (auto-link) | +| 8 | `skills/_brain-filing-rules.json` | Add developer `kind` entries + update `dream_synthesize_paths.globs` array | STORE (dream cycle) | + +#### Entrypoint edit (1) + +| # | File | What changes | +|---|------|-------------| +| 9 | `/workspaces/practicespace-2/.devcontainer/entrypoint.sh` | Lines 154-165: drop 3 files from the array (brain-routing.md, subagent-routing.md, ask-user/SKILL.md). Result: 7 files loaded instead of 10 | + +#### Unchanged (1) + +| # | File | Loop Phase | Why safe | +|---|------|-----------|---------| +| 10 | `skills/_output-rules.md` | PRESENT | Rules are genuinely domain-neutral. "Deterministic links", "No slop", "Exact phrasing preservation" work for any entity type. Examples are VC-flavored but illustrative, not behavioral gates | + +### Tier 2: Important but not loop-breaking + +| File | Change | Priority | +|------|--------|----------| +| `src/core/markdown.ts` `inferType()` | Add developer directory-to-type mappings so pages get correct `PageType` instead of falling through to `concept` | Medium | +| `src/commands/doctor.ts` graph_coverage | Expand `type IN (...)` clause to include developer types | Low | +| `brain-ops/SKILL.md` Phase 2.5 | Add developer relationship types (uses, depends_on, decided_in) as examples | Low | + +### Tier 3: Cosmetic / examples only + +| File | Change | +|------|--------| +| `_output-rules.md` lines 39-40 | Optionally replace VC-flavored title examples | +| `brain-first.md` examples | Replace `paul-graham.md` with developer examples | +| `quality.md` line 40 | Replace "400-follower person" with developer equivalent | + +## File Count Summary + +| Category | Count | Files | +|----------|-------|-------| +| Full rewrite | 3 | RESOLVER.md, signal-detector/SKILL.md, _brain-filing-rules.md | +| Skill file patch | 3 | brain-ops/SKILL.md, brain-first.md, quality.md | +| Code/config patch | 2 | link-extraction.ts, _brain-filing-rules.json | +| Entrypoint edit | 1 | entrypoint.sh | +| Unchanged | 1 | _output-rules.md | +| **Total** | **10** | | + +## Execution Order + +1. **quality.md** first (root of delegation chain, every other file inherits) +2. **brain-ops/SKILL.md** second (the loop engine) +3. **signal-detector/SKILL.md** (detection layer) +4. **_brain-filing-rules.md** + **_brain-filing-rules.json** (filing taxonomy) +5. **RESOLVER.md** (routing table) +6. **brain-first.md** (retrieval conventions) +7. **link-extraction.ts** (auto-link code) +8. **entrypoint.sh** (drop 3 irrelevant files) +9. Tier 2 code changes (markdown.ts, doctor.ts) if time allows + +## Process page template (for developer entities) + +Every process page should include these sections to support reproducibility: + +```markdown +--- +type: process +title: Deploy to Production +tags: [deploy, production, ci] +--- + +# Deploy to Production + +> One-paragraph summary of what this process achieves and when to use it. + +## Preconditions +- What must be true before starting + +## Inputs / Parameters +- What varies between runs + +## Steps +1. Exact commands, in order +2. Expected output at each step +3. Checkpoints where you verify before continuing + +## Failure Modes +- What can go wrong and how to recover + +## Verification +- How to confirm the process succeeded + +## Artifacts Produced +- What exists after completion that didn't before + +--- + +## Timeline +- **YYYY-MM-DD** | Source - What happened, who ran it, what changed +``` + +## What was missed and why + +The original analysis treated files as independent. The closed-loop audit +revealed they form a delegation chain where a single entity-type mention in a +canonical source (quality.md) propagates constraints across the entire system. + +Three rounds of analysis were needed: +1. First pass: 3 write-side files (missed read path entirely) +2. Codex second opinion: +2 read-side patches (missed delegation chain and code) +3. Closed-loop audit: +1 skill patch + 2 code patches (complete) + +The lesson: when customizing a domain, trace the delegation chain, not just +individual files. A "keep unchanged" file can be the root constraint that +silently blocks the entire new domain. From b29fab8c314fa9c6f95149900b737c1e81685f0b Mon Sep 17 00:00:00 2001 From: chapter37haptics <249148637+chapter37haptics@users.noreply.github.com> Date: Thu, 14 May 2026 21:00:22 +0000 Subject: [PATCH 02/10] =?UTF-8?q?v2:=20customized=20domain=20spec=20?= =?UTF-8?q?=E2=80=94=20closed-loop=20audit,=20architecture=20compliance,?= =?UTF-8?q?=20Codex=20reviews?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds intro, important files layered diagram, closed-loop 6-phase audit (quality.md delegation chain, brain-ops 8-site patch, types.ts compile gate), architecture compliance section with fixes from Codex (FS-canonical framing, brain-routing.md retained, PageType union blocker, inferType ordering). File count: 3 rewrites + 3 skill patches + 4 code patches + 1 entrypoint = 13. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/specs/customized-domain.md | 224 ++++++++++++++++++++++++++++++-- 1 file changed, 216 insertions(+), 8 deletions(-) diff --git a/docs/specs/customized-domain.md b/docs/specs/customized-domain.md index 27c9fd4cd..2f18c0fa1 100644 --- a/docs/specs/customized-domain.md +++ b/docs/specs/customized-domain.md @@ -1,5 +1,104 @@ # Spec: GBrain Customized Domain (VC to Developer) +## Intro + +GBrain is a personal knowledge brain that teaches AI agents to persist and +retrieve structured knowledge. Out of the box, it is built for a VC/executive +use case: tracking people (founders, investors, colleagues), companies +(portfolio, prospects, competitors), deals (funding rounds, term sheets), and +meetings (board meetings, 1:1s, pitch sessions). The enrichment pipeline fires +on every person or company mention, building dossier-style pages with career +history, beliefs, motivations, relationship context, and a reverse-chronological +timeline of interactions. + +We want to adapt gbrain to a **developer use case**: documenting development +processes, architectural decisions, debug trails, coding patterns, tool +knowledge, and project context. Instead of compounding knowledge about people +and companies, the brain should compound knowledge about how software gets +built. The agent should capture technical decisions as they happen, record +root causes when bugs are debugged, and solidify repeatable processes so that +a completely new Claude agent in a fresh devcontainer can reproduce them. + +The adaptation follows the "thin harness, fat skills" methodology from +`docs/ethos/THIN_HARNESS_FAT_SKILLS.md`: the gbrain CLI (deterministic layer) +stays unchanged. The skill files (latent-space layer) are where domain +knowledge lives, and those are what we rewrite. When a development process +proves repeatable, it graduates from a brain page to a skill file. + +## Important Files + +GBrain's agent behavior is driven by skill files that get concatenated into +`~/.claude/CLAUDE.md` at devcontainer boot (see `entrypoint.sh` lines 149-183). +These files form a layered instruction set that controls how the agent reads +and writes to the brain. + +### Layer 1: Routing (which skill handles which intent) + +| File | Role | Domain-specific? | +|------|------|-----------------| +| `skills/RESOLVER.md` | Trigger-to-skill routing table. When user says X, load skill Y. | YES — every trigger is VC-oriented ("investor updates", "donations", "who is") | + +### Layer 2: Always-on behaviors (fire on every message) + +| File | Role | Domain-specific? | +|------|------|-----------------| +| `skills/signal-detector/SKILL.md` | Ambient capture: detects entities and original thinking on every inbound message. Defines WHAT the agent looks for. | YES — detection list is people, companies, media. Writes to people/, companies/, concepts/ | +| `skills/brain-ops/SKILL.md` | The read-enrich-write loop engine. Defines WHEN the agent checks the brain, WHEN it writes back, and WHEN it enriches. Touches all 6 loop phases. | PARTIALLY — the loop mechanics are domain-agnostic but entity triggers say "person or company" at 8 hard-gate sites | + +### Layer 3: Conventions (cross-cutting rules for all brain writes) + +| File | Role | Domain-specific? | +|------|------|-----------------| +| `skills/conventions/quality.md` | Canonical Iron Law definition (back-linking), citation format, notability gate, source precedence. Every other file delegates here. | PARTIALLY — Iron Law scoped to "person or company" (line 25). Notability gate has criteria only for people/companies/concepts | +| `skills/conventions/brain-first.md` | Lookup chain (search -> query -> get_page -> external APIs). Entity conventions table maps directories to types. | PARTIALLY — table lists people/, companies/, deals/, meetings/, projects/, yc/. Agent constructs slugs from this | +| `skills/conventions/brain-routing.md` | Which brain (DB) and which source (repo) to target. Multi-brain federation rules. | NO — domain-agnostic routing. Relevant even in single-brain Topology 1 for source-axis awareness | +| `skills/_brain-filing-rules.md` | Where to file new pages. Decision protocol, misfiling table, dream-cycle synthesis paths. | YES — entire taxonomy is VC-oriented (people/, companies/, deals/) | +| `skills/_brain-filing-rules.json` | Machine-readable companion. `kind` entries and `dream_synthesize_paths.globs` array. | YES — missing developer entity kinds | + +### Layer 4: Output quality (how brain pages should read) + +| File | Role | Domain-specific? | +|------|------|-----------------| +| `skills/_output-rules.md` | Deterministic links, no slop, exact phrasing preservation, title quality. | NO — rules are genuinely domain-neutral | + +### Layer 5: Code (enforces behavior regardless of skill instructions) + +| File | Role | Domain-specific? | +|------|------|-----------------| +| `src/core/types.ts` | `PageType` union type. Compile-time gate: types not in the union cannot be assigned. | YES — missing developer types (decision, debug-trail, pattern, process, tool, goal, environment) | +| `src/core/markdown.ts` `inferType()` | Maps directory paths to `PageType`. Determines what type a page gets when imported. | YES — missing developer directory mappings | +| `src/core/link-extraction.ts` | `DIR_PATTERN` regex for auto-link. Determines which directory references create graph edges. | YES — missing developer directories | + +### How the layers compose + +``` +User message arrives + | + v +Layer 1 (RESOLVER) -----> routes to the right skill + | + v +Layer 2 (signal-detector) -> DETECTS entities worth capturing +Layer 2 (brain-ops) -------> READ brain, ENRICH pages, WRITE back + | + v +Layer 3 (quality.md) ------> HOW to write (citations, back-links) +Layer 3 (brain-first.md) --> HOW to read (lookup chain, slug construction) +Layer 3 (brain-routing.md) > WHICH brain/source to target +Layer 3 (filing-rules) ----> WHERE to file (directory taxonomy) + | + v +Layer 4 (output-rules) ----> page quality standards + | + v +Layer 5 (code) ------------> enforces types, auto-link, type inference +``` + +The agent reads all layers at boot (concatenated into CLAUDE.md). When any +layer mentions "person or company" as a hard gate, developer entities are +invisible to that layer. The customization must patch every hard gate across +all layers. + ## Goal Customize gbrain from a VC/executive personal intelligence system to a developer @@ -10,7 +109,10 @@ upstream gbrain compounds people/company knowledge. The key constraint: a new Claude agent in a fresh devcontainer (built from the Dockerfile at `/workspaces/practicespace-2/.devcontainer/Dockerfile`) should be able to read the brain and repeat a development process. The brain is institutional -memory that survives across agent sessions and environments. +memory that survives across agent sessions and environments. The cross-environment +reproducibility mechanism is the system-of-record contract: the brain repo (git) +is the portable artifact, and `gbrain sync && gbrain extract all` rebuilds the +DB from it in any fresh environment. ## Closed-Loop Criterion @@ -169,7 +271,7 @@ Fix quality.md first. Every file that delegates to it inherits the fix. | # | File | What changes | |---|------|-------------| -| 9 | `/workspaces/practicespace-2/.devcontainer/entrypoint.sh` | Lines 154-165: drop 3 files from the array (brain-routing.md, subagent-routing.md, ask-user/SKILL.md). Result: 7 files loaded instead of 10 | +| 9 | `/workspaces/practicespace-2/.devcontainer/entrypoint.sh` | Lines 154-165: drop 2 files from the array (subagent-routing.md, ask-user/SKILL.md). Keep brain-routing.md for source-axis awareness. Result: 8 files loaded instead of 10 | #### Unchanged (1) @@ -181,7 +283,8 @@ Fix quality.md first. Every file that delegates to it inherits the fix. | File | Change | Priority | |------|--------|----------| -| `src/core/markdown.ts` `inferType()` | Add developer directory-to-type mappings so pages get correct `PageType` instead of falling through to `concept` | Medium | +| `src/core/types.ts` `PageType` union | Add decision, debug-trail, pattern, process, tool, goal, environment to the type union + `ALL_PAGE_TYPES`. Compile-time break without this | **HIGH (Tier 1)** | +| `src/core/markdown.ts` `inferType()` | Add developer directory-to-type mappings. Ordering: longest prefix first (decisions/ before projects/) for hybrid paths | **HIGH (Tier 1)** | | `src/commands/doctor.ts` graph_coverage | Expand `type IN (...)` clause to include developer types | Low | | `brain-ops/SKILL.md` Phase 2.5 | Add developer relationship types (uses, depends_on, decided_in) as examples | Low | @@ -199,10 +302,10 @@ Fix quality.md first. Every file that delegates to it inherits the fix. |----------|-------|-------| | Full rewrite | 3 | RESOLVER.md, signal-detector/SKILL.md, _brain-filing-rules.md | | Skill file patch | 3 | brain-ops/SKILL.md, brain-first.md, quality.md | -| Code/config patch | 2 | link-extraction.ts, _brain-filing-rules.json | +| Code/config patch | 4 | types.ts, markdown.ts, link-extraction.ts, _brain-filing-rules.json | | Entrypoint edit | 1 | entrypoint.sh | -| Unchanged | 1 | _output-rules.md | -| **Total** | **10** | | +| Unchanged | 2 | _output-rules.md, brain-routing.md | +| **Total** | **13** | | ## Execution Order @@ -213,8 +316,10 @@ Fix quality.md first. Every file that delegates to it inherits the fix. 5. **RESOLVER.md** (routing table) 6. **brain-first.md** (retrieval conventions) 7. **link-extraction.ts** (auto-link code) -8. **entrypoint.sh** (drop 3 irrelevant files) -9. Tier 2 code changes (markdown.ts, doctor.ts) if time allows +8. **types.ts** (PageType union — compile-time prerequisite for markdown.ts) +9. **markdown.ts** `inferType()` (longest-prefix ordering for hybrid paths) +10. **entrypoint.sh** (drop 2 irrelevant files, keep brain-routing.md) +11. Tier 2 code changes (doctor.ts) if time allows ## Process page template (for developer entities) @@ -257,6 +362,109 @@ tags: [deploy, production, ci] - **YYYY-MM-DD** | Source - What happened, who ran it, what changed ``` +## Architecture Compliance + +Audited against `/workspaces/gbrain/docs/architecture/` (4 docs). + +### system-of-record.md — REQUIRES FIXES + +The FS-canonical contract says: markdown repo is the system of record, PGLite +is a derived cache. `gbrain sync && gbrain extract all` rebuilds the DB from +scratch. This spec's closed-loop diagram says "STORE = page lands in PGLite" +which is misleading. The correct flow is: + +``` +agent calls put_page -> markdown written to brain repo -> sync imports to DB -> extract rebuilds graph +``` + +The spec must NOT frame the DB as the primary store. All developer knowledge +follows the same FS-canonical contract as upstream: markdown is canonical, +DB is derived. The `put_page` MCP tool writes to the DB, but `gbrain export` +materializes pages as markdown (entrypoint.sh line 186 runs this every 2min), +and `gbrain sync` rebuilds from markdown. The rebuild invariant must hold: +wipe the DB, re-import from the brain repo, and all developer knowledge +(decisions, patterns, processes, etc.) regenerates identically. + +Callout: the process page template's `---` separator before `## Timeline` must +be placed immediately before the heading to satisfy `markdown.ts`'s sentinel +detection (``, `--- timeline ---`, or `---` immediately before +`## Timeline`/`## History`). The template in this spec follows that convention. + +**Action:** Update the closed-loop diagram phase 3 from "STORE - page lands in +PGLite" to "STORE - page materializes as markdown, DB rebuilt from repo." + +### brains-and-sources.md — REQUIRES CLARIFICATION + +This spec targets Topology 1: single brain, single source, single machine +(PGLite in a devcontainer). The developer directory taxonomy replaces the +default source's directory structure, not the brain or source axis. No new +brains or sources are created. + +Codex flagged: even in Topology 1, the two-axis resolution contract still +exists. Saying `--brain` and `--source` are "irrelevant" is too strong. +The correct framing: the default resolution (`host` brain, `default` source) +handles this setup correctly without explicit flags. The axes exist but the +defaults are sufficient. + +Codex also flagged: dropping `brain-routing.md` from the entrypoint removes +agent awareness of the source/brain axis entirely. Even for a single-brain +setup, the agent should understand the axis model in case the user adds a +second source later. **Decision: keep brain-routing.md in the entrypoint +but deprioritize it (no changes needed to its content).** This changes the +entrypoint from "drop 3 files" to "drop 2 files" (subagent-routing.md and +ask-user/SKILL.md only). + +### infra-layer.md — REQUIRES ADDITIONAL CODE CHANGES + +Search architecture (tsvector + pgvector + RRF) is content-based, not +type-based. Developer pages get identical search treatment. No conflict there. + +However, Codex found a compile-time break the spec missed: + +**`src/core/types.ts` PageType union.** The union type does NOT include +`decision`, `debug-trail`, `pattern`, `process`, `tool`, `goal`, or +`environment`. Adding these to `inferType()` in `markdown.ts` without updating +the `PageType` union in `types.ts` is a TypeScript compile error. This is a +Tier 1 blocker, not Tier 2. + +**`inferType()` ordering for hybrid paths.** The hybrid taxonomy nests +`projects/my-app/decisions/` under `projects/`. If `inferType` checks +`/projects/` before `/decisions/`, nested decision pages get typed as +`project` instead of `decision`. The check order must be: longest prefix +match first (decisions before projects). + +**Link relationship heuristics.** Adding directories to `DIR_PATTERN` enables +auto-link to CREATE edges, but `inferLinkType` classifies all developer +relationships as `mentions` (the default fallback). Functionally degraded +graph behavior, acceptable for v1 but should be noted as a known limitation, +not claimed as compliant. + +### topologies.md — REQUIRES RECONCILIATION + +Topology 1 (single brain on one machine). The devcontainer's entrypoint runs +`gbrain init` (PGLite) + `gbrain serve` (stdio MCP). + +Codex flagged a contradiction: the spec's goal says "a new Claude agent in a +fresh devcontainer should be able to read the brain and repeat a development +process." That is a cross-environment portability claim. But the architecture +section says "no cross-machine concerns apply." These conflict. + +The bridge is the system-of-record contract: the brain repo (git) is the +portable artifact. A fresh devcontainer runs `gbrain sync --repo ~/brain && +gbrain extract all` and the DB rebuilds from the repo. The spec should state +this explicitly as the cross-environment reproducibility mechanism, rather +than claiming no cross-machine concerns exist. + +### Changes required by architecture audit + +Added to the change manifest: + +| # | File | What changes | Tier | +|---|------|-------------|------| +| NEW | `src/core/types.ts` | Add developer types to `PageType` union and `ALL_PAGE_TYPES` | Tier 1 (compile-time break) | +| UPDATED | entrypoint.sh | Drop 2 files (not 3) — keep brain-routing.md | Tier 1 | +| UPDATED | `src/core/markdown.ts` `inferType()` | Moved from Tier 2 to Tier 1 — ordering matters for hybrid paths | Tier 1 | + ## What was missed and why The original analysis treated files as independent. The closed-loop audit From 11a16817c32171907472c790c018a51dd1162d3b Mon Sep 17 00:00:00 2001 From: chapter37haptics <249148637+chapter37haptics@users.noreply.github.com> Date: Thu, 14 May 2026 21:13:25 +0000 Subject: [PATCH 03/10] v3: narrowed entity scope to 4 types, added page templates, Codex review 4 Narrowed from 10 developer entity types to 4: projects (hub), decisions (ADRs), processes (repeatable workflows), concepts (tools + patterns + mental models). project and concept already exist in PageType; only decision and process are new. Halves the code surface: 2 new PageType entries, 2 DIR_PATTERN additions. Added page templates for all 4 types + structured debug-trail timeline entry format. Added concepts/ notability criteria (junk-drawer prevention). Updated change manifest, architecture compliance, and file counts throughout. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/specs/customized-domain.md | 282 ++++++++++++++++++++++++++------ 1 file changed, 235 insertions(+), 47 deletions(-) diff --git a/docs/specs/customized-domain.md b/docs/specs/customized-domain.md index 2f18c0fa1..42b46293f 100644 --- a/docs/specs/customized-domain.md +++ b/docs/specs/customized-domain.md @@ -65,9 +65,9 @@ and writes to the brain. | File | Role | Domain-specific? | |------|------|-----------------| -| `src/core/types.ts` | `PageType` union type. Compile-time gate: types not in the union cannot be assigned. | YES — missing developer types (decision, debug-trail, pattern, process, tool, goal, environment) | -| `src/core/markdown.ts` `inferType()` | Maps directory paths to `PageType`. Determines what type a page gets when imported. | YES — missing developer directory mappings | -| `src/core/link-extraction.ts` | `DIR_PATTERN` regex for auto-link. Determines which directory references create graph edges. | YES — missing developer directories | +| `src/core/types.ts` | `PageType` union type. Compile-time gate: types not in the union cannot be assigned. | YES — missing `decision` and `process` (`project` and `concept` already exist) | +| `src/core/markdown.ts` `inferType()` | Maps directory paths to `PageType`. Determines what type a page gets when imported. | YES — missing `decisions/` and `processes/` mappings | +| `src/core/link-extraction.ts` | `DIR_PATTERN` regex for auto-link. Determines which directory references create graph edges. | YES — missing `decisions` and `processes` (`projects` and `concepts` already in regex) | ### How the layers compose @@ -129,45 +129,55 @@ potential break point where developer knowledge gets lost. 6. ENRICH - on subsequent interactions, agent updates existing pages ``` -## Developer Entity Types +## Developer Entity Types (narrowed scope, v3) -Replacing the upstream VC taxonomy (people/, companies/, deals/, meetings/): +4 entity types replace the upstream VC taxonomy (people/, companies/, deals/). +VC types remain in the infrastructure (PageType union, DIR_PATTERN) but the +agent's behavioral layer (skill files) stops triggering on them. -| Directory | Type | Example | Description | -|-----------|------|---------|-------------| -| `projects/` | project | `projects/my-app.md` | Hub pages for active codebases. Sub-pages for project-specific decisions and debug trails | -| `decisions/` | decision | `decisions/chose-postgres-over-sqlite.md` | ADR-style technical decisions with rationale. Cross-project | -| `debug-trails/` | debug-trail | `debug-trails/auth-jwt-rotation-cache-bug.md` | Bugs investigated, root causes, fixes applied | -| `patterns/` | pattern | `patterns/repository-pattern.md` | Reusable dev patterns and practices | -| `processes/` | process | `processes/deploy-to-production.md` | Step-by-step workflows: deploy, test, setup | -| `tools/` | tool | `tools/docker-compose.md` | Tool config, gotchas, setup knowledge | -| `goals/` | goal | `goals/migrate-to-nextjs.md` | Target outcomes per project, links to /goal skill | -| `environments/` | environment | `environments/devcontainer-v2.md` | Devcontainer/Dockerfile fingerprint, toolchain versions | -| `concepts/` | concept | `concepts/event-sourcing.md` | Kept from upstream. Works for dev concepts | -| `meetings/` | meeting | `meetings/2026-05-14-sprint-retro.md` | Kept from upstream. Meetings still happen | +| Directory | Type | Example | Absorbs | Already in PageType? | +|-----------|------|---------|---------|---------------------| +| `projects/` | project | `projects/my-app.md` | goals, environments, debug-trails (as sections/timeline) | YES | +| `decisions/` | decision | `decisions/chose-postgres-over-sqlite.md` | ADR-style technical decisions with rationale | NO (new) | +| `processes/` | process | `processes/deploy-to-production.md` | Repeatable workflows; graduates to skill files | NO (new) | +| `concepts/` | concept | `concepts/event-sourcing.md` | tools, patterns, reusable mental models | YES | -### Hybrid taxonomy (Option A) +New PageType additions: **2** (`decision`, `process`). +DIR_PATTERN additions: **2** (`decisions`, `processes`). + +### VC-to-developer entity mapping + +| VC domain | Developer domain | Structural role | +|-----------|-----------------|-----------------| +| `people/` | `projects/` | Primary entity everything orbits around | +| `companies/` | `concepts/` | Context entities that primary entities link to | +| `deals/` | `decisions/` | Point-in-time choices that connect entities | +| `meetings/` | (dropped) | Events where entities interact | +| (no analog) | `processes/` | Repeatable procedures that graduate to skill files | + +### Directory structure -Project-specific knowledge nests under the project hub: ``` brain/ +-- projects/ -| +-- my-app.md <- hub page -| +-- my-app/ -| | +-- decisions/ <- project-specific decisions -| | +-- debug-trails/ <- project-specific debug trails -+-- patterns/ <- cross-project (transferable) -+-- tools/ <- cross-project -+-- processes/ <- cross-project -+-- decisions/ <- cross-project decisions -+-- goals/ -+-- environments/ -+-- concepts/ -+-- meetings/ +| +-- my-app.md <- hub page (goals, env, debug as sections) ++-- decisions/ <- cross-project ADRs ++-- processes/ <- repeatable workflows ++-- concepts/ <- reusable knowledge (tools, patterns, models) ``` -Filing test: does this knowledge transfer to the next project? If yes, file at -the top level. If no, file under the project. +Filing test: "Is this a reusable concept? -> concepts/. A step-by-step +procedure? -> processes/. A technical choice with rationale? -> decisions/. +Everything else is a section on the project page." + +### Notability criteria for concepts/ (junk-drawer prevention) + +concepts/ absorbs tools and patterns. To prevent it from becoming a dumping +ground, a concept must be: reusable (applies to more than one project), +cross-project (not tied to a single codebase), stable (won't change next +week), and non-procedural (if it's a series of steps, it's a process, not +a concept). Example: "event sourcing" is a concept. "How to set up Docker +for this project" is a process or a project section. ### Brain-to-skill promotion pipeline @@ -249,7 +259,7 @@ Fix quality.md first. Every file that delegates to it inherits the fix. | # | File | Loop Phase | Reason | |---|------|-----------|--------| | 1 | `skills/RESOLVER.md` | DETECT | Every trigger is VC-specific. Replace with developer triggers | -| 2 | `skills/signal-detector/SKILL.md` | DETECT + WRITE | Entity detection list (line 70) defines what gets captured. Currently: people, companies, media. Must become: projects, tools, decisions, patterns, processes | +| 2 | `skills/signal-detector/SKILL.md` | DETECT + WRITE | Entity detection list (line 70) defines what gets captured. Currently: people, companies, media. Must become: projects, decisions, processes, concepts | | 3 | `skills/_brain-filing-rules.md` | WRITE + STORE | Entire taxonomy, misfiling table, notability gate, dream-cycle paths | #### Skill files to PATCH (3) @@ -257,15 +267,15 @@ Fix quality.md first. Every file that delegates to it inherits the fix. | # | File | Sections to change | Loop Phase | What changes | |---|------|-------------------|-----------|--------------| | 4 | `skills/brain-ops/SKILL.md` | Frontmatter `writes_to`, Phase 2 trigger (line 69) + detect (line 71), Iron Law scope (line 49), Phase 4 enrichment triggers (lines 111-112), anti-patterns (line 146). 8 sites total. | ALL | Replace "person or company" with developer entity list at every hard-gate mention | -| 5 | `skills/conventions/brain-first.md` | Header (line 1), entity conventions table (lines 57-64): add 8 rows for developer dirs, replace 4 VC-only rows, remove `deals/` and `yc/` | RETRIEVE | Agent needs slug-construction guidance for all developer directories | -| 6 | `skills/conventions/quality.md` | Iron Law (line 25): generalize to "any entity with a brain page". Notability Gate (lines 34-36): add criteria for projects, decisions, tools, patterns, processes, debug-trails, goals, environments. Example (line 40): replace VC example | WRITE | Root of the delegation chain. All other files inherit from this | +| 5 | `skills/conventions/brain-first.md` | Header (line 1), entity conventions table (lines 57-64): add `decisions/` and `processes/` rows, replace VC-only rows (`deals/`, `yc/`), keep `projects/` and `concepts/` | RETRIEVE | Agent needs slug-construction guidance for developer directories | +| 6 | `skills/conventions/quality.md` | Iron Law (line 25): generalize to "any entity with a brain page". Notability Gate (lines 34-36): add criteria for projects, decisions, processes, concepts (with junk-drawer prevention for concepts/). Example (line 40): replace VC example | WRITE | Root of the delegation chain. All other files inherit from this | #### Code/config files to PATCH (2) | # | File | What changes | Loop Phase | |---|------|-------------|-----------| -| 7 | `src/core/link-extraction.ts` | Add `decisions\|debug-trails\|patterns\|processes\|tools\|goals\|environments` to `DIR_PATTERN` regex at line 46 | STORE (auto-link) | -| 8 | `skills/_brain-filing-rules.json` | Add developer `kind` entries + update `dream_synthesize_paths.globs` array | STORE (dream cycle) | +| 7 | `src/core/link-extraction.ts` | Add `decisions\|processes` to `DIR_PATTERN` regex at line 46 (`projects` and `concepts` already present) | STORE (auto-link) | +| 8 | `skills/_brain-filing-rules.json` | Add `decision` and `process` kind entries + update `dream_synthesize_paths.globs` for `decisions/` and `processes/` | STORE (dream cycle) | #### Entrypoint edit (1) @@ -283,8 +293,8 @@ Fix quality.md first. Every file that delegates to it inherits the fix. | File | Change | Priority | |------|--------|----------| -| `src/core/types.ts` `PageType` union | Add decision, debug-trail, pattern, process, tool, goal, environment to the type union + `ALL_PAGE_TYPES`. Compile-time break without this | **HIGH (Tier 1)** | -| `src/core/markdown.ts` `inferType()` | Add developer directory-to-type mappings. Ordering: longest prefix first (decisions/ before projects/) for hybrid paths | **HIGH (Tier 1)** | +| `src/core/types.ts` `PageType` union | Add `decision` and `process` to the type union + `ALL_PAGE_TYPES`. Compile-time break without this | **HIGH (Tier 1)** | +| `src/core/markdown.ts` `inferType()` | Add `decisions/` and `processes/` directory mappings. Ordering: check `decisions/` before `projects/` for nested paths | **HIGH (Tier 1)** | | `src/commands/doctor.ts` graph_coverage | Expand `type IN (...)` clause to include developer types | Low | | `brain-ops/SKILL.md` Phase 2.5 | Add developer relationship types (uses, depends_on, decided_in) as examples | Low | @@ -321,9 +331,11 @@ Fix quality.md first. Every file that delegates to it inherits the fix. 10. **entrypoint.sh** (drop 2 irrelevant files, keep brain-routing.md) 11. Tier 2 code changes (doctor.ts) if time allows -## Process page template (for developer entities) +## Page Templates + +### Process page -Every process page should include these sections to support reproducibility: +Repeatable workflows. Graduates to skill files after 2-3 successful reuses. ```markdown --- @@ -362,6 +374,98 @@ tags: [deploy, production, ci] - **YYYY-MM-DD** | Source - What happened, who ran it, what changed ``` +### Decision page + +ADR-style technical decisions with rationale. Cross-project. + +```markdown +--- +type: decision +title: Chose Postgres Over SQLite +tags: [database, architecture] +--- + +# Chose Postgres Over SQLite + +> One-line summary of what was decided and why. + +## Context +- What prompted this decision + +## Options Considered +- Option A: description, pros, cons +- Option B: description, pros, cons + +## Decision +- What was chosen and why + +## Consequences +- What changes as a result +- What trade-offs were accepted + +--- + +## Timeline +- **YYYY-MM-DD** | Source - When decided, by whom, in what context +``` + +### Project page + +Hub page for an active codebase. Goals, environments, and debug trails +live as sections and structured timeline entries, not separate pages. + +```markdown +--- +type: project +title: My App +tags: [active, web] +--- + +# My App + +> One-paragraph summary: what it is, what stage, what matters now. + +## Architecture +- High-level structure, key components + +## Current Goals +- What we're working toward right now + +## Environment +- Runtime: Node 22, Bun 1.3 +- Deploy: devcontainer on Codespaces +- Key config: any non-obvious setup + +## Open Threads +- Active items, blockers, next steps + +## Decisions +- [Chose Postgres](decisions/chose-postgres-over-sqlite.md) +- [API-first architecture](decisions/api-first.md) + +--- + +## Timeline +- **YYYY-MM-DD** | Source - What happened +``` + +### Structured debug-trail timeline entries + +Debug trails are timeline entries on project pages, not separate pages. +Use this structured format so they stay machine-parseable for retrieval: + +```markdown +- **YYYY-MM-DD** | Debug — **Symptom:** auth returning 401 after deploy. + **Root cause:** JWT secret rotated but old key cached in Redis (TTL 24h). + **Fix:** added cache invalidation on secret rotation + reduced TTL to 1h. + **Refs:** [decisions/jwt-rotation-policy](decisions/jwt-rotation-policy.md) + [Source: User, debug session, YYYY-MM-DD] +``` + +Fields: Symptom (what was observed), Root cause (why it happened), Fix (what +was done), Refs (links to related decisions/concepts). All on one timeline +entry so `gbrain search "JWT cache bug"` finds it. + ## Architecture Compliance Audited against `/workspaces/gbrain/docs/architecture/` (4 docs). @@ -422,10 +526,9 @@ type-based. Developer pages get identical search treatment. No conflict there. However, Codex found a compile-time break the spec missed: **`src/core/types.ts` PageType union.** The union type does NOT include -`decision`, `debug-trail`, `pattern`, `process`, `tool`, `goal`, or -`environment`. Adding these to `inferType()` in `markdown.ts` without updating -the `PageType` union in `types.ts` is a TypeScript compile error. This is a -Tier 1 blocker, not Tier 2. +`decision` or `process`. (`project` and `concept` already exist.) Adding +these to `inferType()` in `markdown.ts` without updating the `PageType` +union in `types.ts` is a TypeScript compile error. Tier 1 blocker. **`inferType()` ordering for hybrid paths.** The hybrid taxonomy nests `projects/my-app/decisions/` under `projects/`. If `inferType` checks @@ -461,7 +564,7 @@ Added to the change manifest: | # | File | What changes | Tier | |---|------|-------------|------| -| NEW | `src/core/types.ts` | Add developer types to `PageType` union and `ALL_PAGE_TYPES` | Tier 1 (compile-time break) | +| NEW | `src/core/types.ts` | Add `decision` + `process` to `PageType` union and `ALL_PAGE_TYPES` | Tier 1 (compile-time break) | | UPDATED | entrypoint.sh | Drop 2 files (not 3) — keep brain-routing.md | Tier 1 | | UPDATED | `src/core/markdown.ts` `inferType()` | Moved from Tier 2 to Tier 1 — ordering matters for hybrid paths | Tier 1 | @@ -479,3 +582,88 @@ Three rounds of analysis were needed: The lesson: when customizing a domain, trace the delegation chain, not just individual files. A "keep unchanged" file can be the root constraint that silently blocks the entire new domain. + +## Reviews + +### Codex review 1: Retrieval gap (Round 2) + +**Question:** Will changing 3 write-side files be sufficient for reliable retrieval? + +**Verdict:** No. Two read-side files need patches. + +- `brain-ops/SKILL.md` Phase 3: "person, company, or topic" biases trigger + behavior toward VC entities. Developer question types must be explicit. +- `brain-first.md` entity conventions table: acts as a behavioral filter even + though it's not a hard technical gate. Agent constructs slugs from this table. + +**Impact on spec:** Added 2 read-side patches to the change manifest (Round 2). + +### Codex review 2: Architecture compliance (Round 3 follow-up) + +**Question:** Does the spec adhere to gbrain's architecture docs? + +**Verdict:** Not fully compliant as written. 4 issues found: + +1. `system-of-record.md` — spec framed "STORE = lands in PGLite" which + contradicts the FS-canonical contract (markdown is system of record, DB is + derived cache). +2. `brains-and-sources.md` — spec said `--brain` and `--source` are + "irrelevant" which is too strong even for Topology 1. Dropping + `brain-routing.md` removes source-axis awareness. +3. `infra-layer.md` — `types.ts` PageType union missing developer types + (compile-time break). `inferType()` ordering matters for hybrid paths. +4. `topologies.md` — cross-environment reproducibility goal conflicts with + "no cross-machine concerns" claim. + +**Impact on spec:** Added `types.ts` to Tier 1. Promoted `markdown.ts` from +Tier 2 to Tier 1. Changed entrypoint from "drop 3" to "drop 2" (kept +brain-routing.md). Added explicit FS-canonical framing and rebuild contract. + +### Codex review 3: Infrastructure impact + +**Question:** Does the spec make changes to gbrain's infrastructure layer? + +**Verdict:** Narrow infrastructure touches, no architectural changes. + +| Area | Changed? | +|------|----------| +| Data pipeline (import/chunk/embed/search) | Lightly. `inferType` and `DIR_PATTERN` change classification during import. No changes to chunking, embedding, search, or RRF. | +| Schema (tables/columns/indexes) | No | +| Engine interface (BrainEngine methods) | No | +| MCP server / operations contract | No | +| Sync, migrations, rebuild contract | No | + +File classification: +- `types.ts` PageType — infrastructure-adjacent (compile-time type contract) +- `markdown.ts` inferType — infrastructure (parser routing metadata), narrow +- `link-extraction.ts` DIR_PATTERN — infrastructure (link extraction), narrow +- `_brain-filing-rules.json` — skills layer (agent config), not infra + +**Conclusion:** The 3 code changes extend existing infrastructure patterns +(adding values to a union, paths to a regex, mappings to a switch) rather +than altering pipeline architecture, schema, engine, MCP, or rebuild +contracts. The deterministic foundation stays untouched. + +### Codex review 4: Narrowed entity scope soundness + +**Question:** Is narrowing from 10 entity types to 4 (projects, decisions, +processes, concepts) sound? + +**Verdict:** Mostly sound. Two caveats. + +1. The narrowing is correct for the stated goal (fresh devcontainer + reproducibility). `project + decision + process + concept` is a good + minimal basis for developer operational memory. +2. All merges are correct: debug-trails into project timeline (if entries + are structured), tools into concepts (usage knowledge fits; project- + specific config stays on project pages), patterns into concepts. +3. Medium risk of concepts/ becoming a junk drawer. Mitigate with strict + notability criteria: reusable, cross-project, stable, non-procedural. +4. Low-medium closed-loop break risk. Main concern: debug trails buried + in long project pages may degrade retrieval quality. Mitigate with a + structured debug-entry template for project timeline sections so + root-cause investigations stay machine-parseable. + +**Impact on spec:** Narrowed scope accepted. Added structured debug-trail +timeline entry format to the project page template. Added concepts/ +notability criteria to quality.md patch requirements. From 940c15e2167c559fb0bdf7fd516b1d7d349b7256 Mon Sep 17 00:00:00 2001 From: chapter37haptics <249148637+chapter37haptics@users.noreply.github.com> Date: Thu, 14 May 2026 21:19:11 +0000 Subject: [PATCH 04/10] v3.1: add Context section for new-session onboarding, remove redundant sections Adds comprehensive Context section covering: what gbrain is, how the agent learns to use the brain (boot sequence), what this spec changes, the two repos involved, the user's workflow, what the agent watches for after implementation, existing PageType values, and key architectural constraints. Removes Goal section (absorbed into Intro + Context) and "What was missed" section (covered by Analysis History + Reviews). Net: +120 lines of context, -30 lines of overlap. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/specs/customized-domain.md | 150 +++++++++++++++++++++++++------- 1 file changed, 120 insertions(+), 30 deletions(-) diff --git a/docs/specs/customized-domain.md b/docs/specs/customized-domain.md index 42b46293f..29b6521c7 100644 --- a/docs/specs/customized-domain.md +++ b/docs/specs/customized-domain.md @@ -25,6 +25,126 @@ stays unchanged. The skill files (latent-space layer) are where domain knowledge lives, and those are what we rewrite. When a development process proves repeatable, it graduates from a brain page to a skill file. +## Context + +This section gives a new session everything it needs to implement this spec. + +### What is gbrain + +GBrain is a personal knowledge brain built as a CLI + MCP server. It stores +markdown pages in a PGLite (embedded Postgres) database with vector embeddings +for hybrid search. The AI agent interacts with the brain through MCP tools: +`search`, `query`, `get_page`, `put_page`, `add_link`, `add_timeline_entry`, +`get_backlinks`, `traverse_graph`, and others. The markdown repo (git) is the +system of record; the database is a derived cache rebuilt by `gbrain sync && +gbrain extract all`. + +Architecture docs: `/workspaces/gbrain/docs/architecture/` (4 files: +`system-of-record.md`, `brains-and-sources.md`, `infra-layer.md`, +`topologies.md`). Design philosophy: `docs/ethos/THIN_HARNESS_FAT_SKILLS.md`. + +### How the agent learns to use the brain + +At devcontainer boot, `entrypoint.sh` (lines 149-183 in +`/workspaces/practicespace-2/.devcontainer/entrypoint.sh`) concatenates skill +files from `/usr/local/src/gbrain/skills/` into `~/.claude/CLAUDE.md`. Claude +Code reads this file at the start of every conversation as system-level +instructions. These instructions tell the agent WHEN to check the brain, WHAT +to look for, HOW to write pages, and WHERE to file them. + +The gbrain CLI is installed from a pinned fork commit in the Dockerfile (Layer +10, `/workspaces/practicespace-2/.devcontainer/Dockerfile` line 109). The MCP +server is registered at boot: `claude mcp add -s user gbrain -- gbrain serve` +(entrypoint line 144). Pages are exported to markdown every 2 minutes +(entrypoint line 186). + +### What this spec changes + +This spec rewrites the SKILL FILES (the agent's behavioral instructions) to +replace VC-domain entity detection with developer-domain entity detection. The +gbrain CLI, MCP server, database schema, search architecture, and sync/rebuild +contracts are all unchanged. Two narrow code-level changes extend existing +type/regex patterns to recognize the new entity directories. + +The adaptation is at the "fat skills" layer, not the "thin harness" layer. + +### The two repos involved + +1. **`/workspaces/gbrain/`** (this repo) — the gbrain fork. Skill files live + here at `skills/`. Code files live at `src/core/`. This is where the domain + customization happens. Branch: `chapter37haptics/customized-domain`. + +2. **`/workspaces/practicespace-2/.devcontainer/`** — the devcontainer config. + `entrypoint.sh` controls which skill files get loaded into CLAUDE.md and + `Dockerfile` pins the gbrain commit. One edit needed here: drop 2 files + from the skill file array. + +### The user's workflow (why this matters) + +The user develops with Claude Code inside a devcontainer. The workflow: + +1. Write prompts/specs that Claude's `/goal` skill can use to achieve a goal +2. Claude achieves the goal through a development session +3. The brain captures decisions, debug trails, and patterns along the way +4. The process gets solidified into a `processes/` brain page +5. When a process proves repeatable (2-3 times), it graduates to a skill file +6. A completely new Claude agent in a fresh devcontainer (built from the + Dockerfile) can read the brain and reproduce the process + +The brain is the institutional memory that survives across agent sessions and +environments. The cross-environment reproducibility mechanism is the +system-of-record contract: the brain repo (git) is the portable artifact. + +### What the agent watches for (after this spec is implemented) + +The signal-detector fires on every message and looks for: + +- **Projects** mentioned by name ("the auth service", "my-app") — check brain, + create/update project page if notable +- **Technical decisions** ("we chose X because Y", "decided to", "tradeoff") — + create decision page with context, options, rationale +- **Repeatable processes** ("to deploy, you need to", "the workflow is", "steps + to set up") — create process page with preconditions, steps, verification +- **Reusable concepts** ("event sourcing works by", "the repository pattern", + "Docker needs this flag because") — create/update concept page +- **Debug sessions** ("the bug was caused by", "root cause was") — add + structured timeline entry to the project page +- **Original thinking** — the user's ideas, observations, frameworks — captured + verbatim, same as upstream + +### Existing PageType values (22 total, we add 2) + +``` +person | company | deal | yc | civic | project | concept | source | media | +writing | analysis | guide | hardware | architecture | meeting | note | +email | slack | calendar-event | code | image | synthesis +``` + +We add: `decision`, `process`. Total: 24. `project` and `concept` already +exist. VC types stay in the infrastructure but the agent stops triggering on +them. + +### Key architectural constraints to respect + +1. **FS-canonical contract.** Markdown repo is the system of record. The DB is + a derived cache. `put_page` writes to the DB, `gbrain export` materializes + as markdown, `gbrain sync` rebuilds from markdown. The rebuild invariant + must hold for all developer entity types. + +2. **Topology 1.** Single brain, single source, single machine (PGLite in a + devcontainer). Default resolution (`host` brain, `default` source) is + sufficient. The brain/source axis model still exists and `brain-routing.md` + stays loaded for awareness. + +3. **Delegation chain.** `quality.md` line 25 is the canonical Iron Law + definition. Every other file delegates to it. Fix quality.md first; every + downstream file inherits the fix. + +4. **No infrastructure changes.** The data pipeline (import/chunk/embed/search), + schema (10 tables), engine interface, MCP operations, and sync/rebuild + contracts are all untouched. The code changes (types.ts, markdown.ts, + link-extraction.ts) extend existing patterns, not alter them. + ## Important Files GBrain's agent behavior is driven by skill files that get concatenated into @@ -99,21 +219,6 @@ layer mentions "person or company" as a hard gate, developer entities are invisible to that layer. The customization must patch every hard gate across all layers. -## Goal - -Customize gbrain from a VC/executive personal intelligence system to a developer -knowledge base that documents development processes, architectural decisions, debug -trails, and patterns. The brain should compound development knowledge the same way -upstream gbrain compounds people/company knowledge. - -The key constraint: a new Claude agent in a fresh devcontainer (built from the -Dockerfile at `/workspaces/practicespace-2/.devcontainer/Dockerfile`) should be -able to read the brain and repeat a development process. The brain is institutional -memory that survives across agent sessions and environments. The cross-environment -reproducibility mechanism is the system-of-record contract: the brain repo (git) -is the portable artifact, and `gbrain sync && gbrain extract all` rebuilds the -DB from it in any fresh environment. - ## Closed-Loop Criterion Knowledge flows in a 6-phase loop. Every file that touches any phase must be @@ -568,21 +673,6 @@ Added to the change manifest: | UPDATED | entrypoint.sh | Drop 2 files (not 3) — keep brain-routing.md | Tier 1 | | UPDATED | `src/core/markdown.ts` `inferType()` | Moved from Tier 2 to Tier 1 — ordering matters for hybrid paths | Tier 1 | -## What was missed and why - -The original analysis treated files as independent. The closed-loop audit -revealed they form a delegation chain where a single entity-type mention in a -canonical source (quality.md) propagates constraints across the entire system. - -Three rounds of analysis were needed: -1. First pass: 3 write-side files (missed read path entirely) -2. Codex second opinion: +2 read-side patches (missed delegation chain and code) -3. Closed-loop audit: +1 skill patch + 2 code patches (complete) - -The lesson: when customizing a domain, trace the delegation chain, not just -individual files. A "keep unchanged" file can be the root constraint that -silently blocks the entire new domain. - ## Reviews ### Codex review 1: Retrieval gap (Round 2) From a6bbaefa5f06c07c5c08538c99c9f158a89a4c8b Mon Sep 17 00:00:00 2001 From: chapter37haptics <249148637+chapter37haptics@users.noreply.github.com> Date: Thu, 14 May 2026 21:32:54 +0000 Subject: [PATCH 05/10] v4: replace projects/ with goals/ for clean MECE, add hard boundaries goals/ maps 1:1 to /goal invocations and is cleanly ME with the other 3 types (context-bound episode vs reusable artifact). projects/ had HIGH overlap with decisions/, processes/, concepts/ because the "does it transfer?" test was a judgment call. goals/ eliminates that: capture in goals/ first, promote out when reusable. New PageType additions: 3 (goal, decision, process). DIR_PATTERN: 3. Added MECE boundary table with hard rules for all 6 entity pairs. Goal page template replaces project page template. Codex review 5 added. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/specs/customized-domain.md | 202 +++++++++++++++++++------------- 1 file changed, 119 insertions(+), 83 deletions(-) diff --git a/docs/specs/customized-domain.md b/docs/specs/customized-domain.md index 29b6521c7..bbb91692d 100644 --- a/docs/specs/customized-domain.md +++ b/docs/specs/customized-domain.md @@ -68,16 +68,16 @@ type/regex patterns to recognize the new entity directories. The adaptation is at the "fat skills" layer, not the "thin harness" layer. -### The two repos involved +### This repo -1. **`/workspaces/gbrain/`** (this repo) — the gbrain fork. Skill files live - here at `skills/`. Code files live at `src/core/`. This is where the domain - customization happens. Branch: `chapter37haptics/customized-domain`. +**`/workspaces/gbrain/`** — the gbrain fork. Skill files live here at `skills/`. +Code files live at `src/core/`. This is where the domain customization happens. +Branch: `chapter37haptics/customized-domain`. -2. **`/workspaces/practicespace-2/.devcontainer/`** — the devcontainer config. - `entrypoint.sh` controls which skill files get loaded into CLAUDE.md and - `Dockerfile` pins the gbrain commit. One edit needed here: drop 2 files - from the skill file array. +The devcontainer config lives at `/workspaces/practicespace-2/.devcontainer/` +(separate repo, out of scope for this spec). Its `entrypoint.sh` controls which +skill files get loaded into CLAUDE.md and its `Dockerfile` pins the gbrain +commit. Changes to those files are a follow-up after this spec lands. ### The user's workflow (why this matters) @@ -85,8 +85,8 @@ The user develops with Claude Code inside a devcontainer. The workflow: 1. Write prompts/specs that Claude's `/goal` skill can use to achieve a goal 2. Claude achieves the goal through a development session -3. The brain captures decisions, debug trails, and patterns along the way -4. The process gets solidified into a `processes/` brain page +3. The brain captures the goal execution arc: decisions, debug trails, patterns +4. Reusable knowledge gets promoted out of the goal page into decisions/, processes/, concepts/ 5. When a process proves repeatable (2-3 times), it graduates to a skill file 6. A completely new Claude agent in a fresh devcontainer (built from the Dockerfile) can read the brain and reproduce the process @@ -99,20 +99,21 @@ system-of-record contract: the brain repo (git) is the portable artifact. The signal-detector fires on every message and looks for: -- **Projects** mentioned by name ("the auth service", "my-app") — check brain, - create/update project page if notable +- **Goals** being worked on ("set up JWT auth", "migrate to Postgres") — check + brain, create/update goal page capturing the execution arc - **Technical decisions** ("we chose X because Y", "decided to", "tradeoff") — - create decision page with context, options, rationale + create decision page if it should govern future goals, or log on the goal page + if it's local to this execution - **Repeatable processes** ("to deploy, you need to", "the workflow is", "steps to set up") — create process page with preconditions, steps, verification - **Reusable concepts** ("event sourcing works by", "the repository pattern", "Docker needs this flag because") — create/update concept page - **Debug sessions** ("the bug was caused by", "root cause was") — add - structured timeline entry to the project page + structured timeline entry to the goal page - **Original thinking** — the user's ideas, observations, frameworks — captured verbatim, same as upstream -### Existing PageType values (22 total, we add 2) +### Existing PageType values (22 total, we add 3) ``` person | company | deal | yc | civic | project | concept | source | media | @@ -120,9 +121,8 @@ writing | analysis | guide | hardware | architecture | meeting | note | email | slack | calendar-event | code | image | synthesis ``` -We add: `decision`, `process`. Total: 24. `project` and `concept` already -exist. VC types stay in the infrastructure but the agent stops triggering on -them. +We add: `goal`, `decision`, `process`. Total: 25. `concept` already exists. +VC types stay in the infrastructure but the agent stops triggering on them. ### Key architectural constraints to respect @@ -145,6 +145,17 @@ them. contracts are all untouched. The code changes (types.ts, markdown.ts, link-extraction.ts) extend existing patterns, not alter them. +### After implementation + +- **Upstream tests should pass.** We only add to type unions and regex patterns, + never remove or change existing values. `bun test` and `bun run test:e2e` + should pass unchanged. If anything breaks, it means a code change was more + invasive than the spec intended. +- **End-to-end verification.** After all files are changed, test the closed + loop: say something like "we chose Postgres because of pgvector support" in + a conversation, then in a separate query ask "why did we choose Postgres?" + and verify the brain returns the decision page. + ## Important Files GBrain's agent behavior is driven by skill files that get concatenated into @@ -185,9 +196,9 @@ and writes to the brain. | File | Role | Domain-specific? | |------|------|-----------------| -| `src/core/types.ts` | `PageType` union type. Compile-time gate: types not in the union cannot be assigned. | YES — missing `decision` and `process` (`project` and `concept` already exist) | -| `src/core/markdown.ts` `inferType()` | Maps directory paths to `PageType`. Determines what type a page gets when imported. | YES — missing `decisions/` and `processes/` mappings | -| `src/core/link-extraction.ts` | `DIR_PATTERN` regex for auto-link. Determines which directory references create graph edges. | YES — missing `decisions` and `processes` (`projects` and `concepts` already in regex) | +| `src/core/types.ts` | `PageType` union type. Compile-time gate: types not in the union cannot be assigned. | YES — missing `goal`, `decision`, and `process` (`concept` already exists) | +| `src/core/markdown.ts` `inferType()` | Maps directory paths to `PageType`. Determines what type a page gets when imported. | YES — missing `goals/`, `decisions/`, and `processes/` mappings | +| `src/core/link-extraction.ts` | `DIR_PATTERN` regex for auto-link. Determines which directory references create graph edges. | YES — missing `goals`, `decisions`, and `processes` (`concepts` already in regex) | ### How the layers compose @@ -234,27 +245,31 @@ potential break point where developer knowledge gets lost. 6. ENRICH - on subsequent interactions, agent updates existing pages ``` -## Developer Entity Types (narrowed scope, v3) +## Developer Entity Types (v4) 4 entity types replace the upstream VC taxonomy (people/, companies/, deals/). VC types remain in the infrastructure (PageType union, DIR_PATTERN) but the agent's behavioral layer (skill files) stops triggering on them. -| Directory | Type | Example | Absorbs | Already in PageType? | -|-----------|------|---------|---------|---------------------| -| `projects/` | project | `projects/my-app.md` | goals, environments, debug-trails (as sections/timeline) | YES | -| `decisions/` | decision | `decisions/chose-postgres-over-sqlite.md` | ADR-style technical decisions with rationale | NO (new) | -| `processes/` | process | `processes/deploy-to-production.md` | Repeatable workflows; graduates to skill files | NO (new) | -| `concepts/` | concept | `concepts/event-sourcing.md` | tools, patterns, reusable mental models | YES | +The primary development unit is a `/goal` invocation, not a long-lived project. +`goals/` captures execution episodes (what was attempted, what happened, what +was learned). Reusable artifacts get promoted out to their own directories. -New PageType additions: **2** (`decision`, `process`). -DIR_PATTERN additions: **2** (`decisions`, `processes`). +| Directory | Type | Example | What goes here | Already in PageType? | +|-----------|------|---------|---------------|---------------------| +| `goals/` | goal | `goals/setup-jwt-auth.md` | One /goal execution arc: attempts, debug trails, local decisions, environment state | NO (new) | +| `decisions/` | decision | `decisions/chose-postgres-over-sqlite.md` | Durable choices that govern future work beyond one goal | NO (new) | +| `processes/` | process | `processes/deploy-to-production.md` | Canonical reproducible procedures (no session narrative); graduates to skill files | NO (new) | +| `concepts/` | concept | `concepts/event-sourcing.md` | Context-free reusable understanding: tools, patterns, mental models | YES | + +New PageType additions: **3** (`goal`, `decision`, `process`). +DIR_PATTERN additions: **3** (`goals`, `decisions`, `processes`). ### VC-to-developer entity mapping | VC domain | Developer domain | Structural role | |-----------|-----------------|-----------------| -| `people/` | `projects/` | Primary entity everything orbits around | +| `people/` | `goals/` | Primary entity everything orbits around | | `companies/` | `concepts/` | Context entities that primary entities link to | | `deals/` | `decisions/` | Point-in-time choices that connect entities | | `meetings/` | (dropped) | Events where entities interact | @@ -264,25 +279,39 @@ DIR_PATTERN additions: **2** (`decisions`, `processes`). ``` brain/ -+-- projects/ -| +-- my-app.md <- hub page (goals, env, debug as sections) -+-- decisions/ <- cross-project ADRs -+-- processes/ <- repeatable workflows ++-- goals/ <- one page per /goal execution ++-- decisions/ <- durable cross-goal ADRs ++-- processes/ <- canonical repeatable workflows +-- concepts/ <- reusable knowledge (tools, patterns, models) ``` -Filing test: "Is this a reusable concept? -> concepts/. A step-by-step -procedure? -> processes/. A technical choice with rationale? -> decisions/. -Everything else is a section on the project page." +### MECE boundaries (hard rules, not judgment calls) + +Every pair of entity types has a hard boundary: + +| Pair | Boundary | +|------|----------| +| goals/ vs decisions/ | goals: what happened in one execution run. decisions: durable choice meant to govern future goals | +| goals/ vs processes/ | goals: narrative + debug trail. processes: canonical reproducible procedure (no session story) | +| goals/ vs concepts/ | goals: applied, context-bound. concepts: context-free reusable understanding | +| decisions/ vs processes/ | decisions: what/why we chose. processes: how to execute | +| decisions/ vs concepts/ | decisions: committed policy for a scope. concepts: explanatory model, no commitment | +| processes/ vs concepts/ | processes: stepwise action. concepts: theory/pattern vocabulary | + +**Operational rule:** Capture everything in `goals/` first. Promote out only +when reusable: +- `decision` — if it should constrain other goals +- `process` — if it's reproducible and handoff-worthy +- `concept` — if it generalizes beyond the specific case ### Notability criteria for concepts/ (junk-drawer prevention) concepts/ absorbs tools and patterns. To prevent it from becoming a dumping -ground, a concept must be: reusable (applies to more than one project), -cross-project (not tied to a single codebase), stable (won't change next +ground, a concept must be: reusable (applies to more than one goal), +cross-goal (not tied to a single execution), stable (won't change next week), and non-procedural (if it's a series of steps, it's a process, not a concept). Example: "event sourcing" is a concept. "How to set up Docker -for this project" is a process or a project section. +for this goal" is a process or a goal section. ### Brain-to-skill promotion pipeline @@ -364,7 +393,7 @@ Fix quality.md first. Every file that delegates to it inherits the fix. | # | File | Loop Phase | Reason | |---|------|-----------|--------| | 1 | `skills/RESOLVER.md` | DETECT | Every trigger is VC-specific. Replace with developer triggers | -| 2 | `skills/signal-detector/SKILL.md` | DETECT + WRITE | Entity detection list (line 70) defines what gets captured. Currently: people, companies, media. Must become: projects, decisions, processes, concepts | +| 2 | `skills/signal-detector/SKILL.md` | DETECT + WRITE | Entity detection list (line 70) defines what gets captured. Currently: people, companies, media. Must become: goals, decisions, processes, concepts | | 3 | `skills/_brain-filing-rules.md` | WRITE + STORE | Entire taxonomy, misfiling table, notability gate, dream-cycle paths | #### Skill files to PATCH (3) @@ -372,21 +401,15 @@ Fix quality.md first. Every file that delegates to it inherits the fix. | # | File | Sections to change | Loop Phase | What changes | |---|------|-------------------|-----------|--------------| | 4 | `skills/brain-ops/SKILL.md` | Frontmatter `writes_to`, Phase 2 trigger (line 69) + detect (line 71), Iron Law scope (line 49), Phase 4 enrichment triggers (lines 111-112), anti-patterns (line 146). 8 sites total. | ALL | Replace "person or company" with developer entity list at every hard-gate mention | -| 5 | `skills/conventions/brain-first.md` | Header (line 1), entity conventions table (lines 57-64): add `decisions/` and `processes/` rows, replace VC-only rows (`deals/`, `yc/`), keep `projects/` and `concepts/` | RETRIEVE | Agent needs slug-construction guidance for developer directories | -| 6 | `skills/conventions/quality.md` | Iron Law (line 25): generalize to "any entity with a brain page". Notability Gate (lines 34-36): add criteria for projects, decisions, processes, concepts (with junk-drawer prevention for concepts/). Example (line 40): replace VC example | WRITE | Root of the delegation chain. All other files inherit from this | +| 5 | `skills/conventions/brain-first.md` | Header (line 1), entity conventions table (lines 57-64): add `goals/`, `decisions/`, `processes/` rows, replace VC-only rows (`deals/`, `yc/`), keep `concepts/` | RETRIEVE | Agent needs slug-construction guidance for developer directories | +| 6 | `skills/conventions/quality.md` | Iron Law (line 25): generalize to "any entity with a brain page". Notability Gate (lines 34-36): add criteria for goals, decisions, processes, concepts (with junk-drawer prevention for concepts/). Example (line 40): replace VC example | WRITE | Root of the delegation chain. All other files inherit from this | #### Code/config files to PATCH (2) | # | File | What changes | Loop Phase | |---|------|-------------|-----------| -| 7 | `src/core/link-extraction.ts` | Add `decisions\|processes` to `DIR_PATTERN` regex at line 46 (`projects` and `concepts` already present) | STORE (auto-link) | -| 8 | `skills/_brain-filing-rules.json` | Add `decision` and `process` kind entries + update `dream_synthesize_paths.globs` for `decisions/` and `processes/` | STORE (dream cycle) | - -#### Entrypoint edit (1) - -| # | File | What changes | -|---|------|-------------| -| 9 | `/workspaces/practicespace-2/.devcontainer/entrypoint.sh` | Lines 154-165: drop 2 files from the array (subagent-routing.md, ask-user/SKILL.md). Keep brain-routing.md for source-axis awareness. Result: 8 files loaded instead of 10 | +| 7 | `src/core/link-extraction.ts` | Add `goals\|decisions\|processes` to `DIR_PATTERN` regex at line 46 (`concepts` already present) | STORE (auto-link) | +| 8 | `skills/_brain-filing-rules.json` | Add `goal`, `decision`, and `process` kind entries + update `dream_synthesize_paths.globs` for `goals/`, `decisions/`, and `processes/` | STORE (dream cycle) | #### Unchanged (1) @@ -398,8 +421,8 @@ Fix quality.md first. Every file that delegates to it inherits the fix. | File | Change | Priority | |------|--------|----------| -| `src/core/types.ts` `PageType` union | Add `decision` and `process` to the type union + `ALL_PAGE_TYPES`. Compile-time break without this | **HIGH (Tier 1)** | -| `src/core/markdown.ts` `inferType()` | Add `decisions/` and `processes/` directory mappings. Ordering: check `decisions/` before `projects/` for nested paths | **HIGH (Tier 1)** | +| `src/core/types.ts` `PageType` union | Add `goal`, `decision`, and `process` to the type union + `ALL_PAGE_TYPES`. Compile-time break without this | **HIGH (Tier 1)** | +| `src/core/markdown.ts` `inferType()` | Add `goals/`, `decisions/`, and `processes/` directory mappings | **HIGH (Tier 1)** | | `src/commands/doctor.ts` graph_coverage | Expand `type IN (...)` clause to include developer types | Low | | `brain-ops/SKILL.md` Phase 2.5 | Add developer relationship types (uses, depends_on, decided_in) as examples | Low | @@ -418,9 +441,8 @@ Fix quality.md first. Every file that delegates to it inherits the fix. | Full rewrite | 3 | RESOLVER.md, signal-detector/SKILL.md, _brain-filing-rules.md | | Skill file patch | 3 | brain-ops/SKILL.md, brain-first.md, quality.md | | Code/config patch | 4 | types.ts, markdown.ts, link-extraction.ts, _brain-filing-rules.json | -| Entrypoint edit | 1 | entrypoint.sh | | Unchanged | 2 | _output-rules.md, brain-routing.md | -| **Total** | **13** | | +| **Total** | **12** | | ## Execution Order @@ -433,8 +455,7 @@ Fix quality.md first. Every file that delegates to it inherits the fix. 7. **link-extraction.ts** (auto-link code) 8. **types.ts** (PageType union — compile-time prerequisite for markdown.ts) 9. **markdown.ts** `inferType()` (longest-prefix ordering for hybrid paths) -10. **entrypoint.sh** (drop 2 irrelevant files, keep brain-routing.md) -11. Tier 2 code changes (doctor.ts) if time allows +10. Tier 2 code changes (doctor.ts) if time allows ## Page Templates @@ -514,49 +535,49 @@ tags: [database, architecture] - **YYYY-MM-DD** | Source - When decided, by whom, in what context ``` -### Project page +### Goal page -Hub page for an active codebase. Goals, environments, and debug trails -live as sections and structured timeline entries, not separate pages. +One page per `/goal` execution. Captures the full development arc: what was +attempted, what happened, decisions made locally, debug trails, and what was +learned. The primary authoring unit. ```markdown --- -type: project -title: My App -tags: [active, web] +type: goal +title: Set Up JWT Auth +tags: [auth, security] --- -# My App - -> One-paragraph summary: what it is, what stage, what matters now. +# Set Up JWT Auth -## Architecture -- High-level structure, key components +> One-paragraph summary: what the goal was, whether it succeeded, key outcome. -## Current Goals -- What we're working toward right now +## Approach +- What was attempted, in what order ## Environment -- Runtime: Node 22, Bun 1.3 -- Deploy: devcontainer on Codespaces -- Key config: any non-obvious setup +- Runtime, tools, config relevant to this execution -## Open Threads -- Active items, blockers, next steps +## Local Decisions +- Choices made during this goal that don't govern future goals +- (Durable choices get promoted to decisions/) -## Decisions -- [Chose Postgres](decisions/chose-postgres-over-sqlite.md) -- [API-first architecture](decisions/api-first.md) +## What Was Learned +- Insights that might transfer to other goals +- (Reusable knowledge gets promoted to concepts/) + +## Resulting Process +- If this produced a repeatable workflow, link: [processes/deploy-jwt](processes/deploy-jwt.md) --- ## Timeline -- **YYYY-MM-DD** | Source - What happened +- **YYYY-MM-DD** | Source - What happened during the execution ``` ### Structured debug-trail timeline entries -Debug trails are timeline entries on project pages, not separate pages. +Debug trails are timeline entries on goal pages, not separate pages. Use this structured format so they stay machine-parseable for retrieval: ```markdown @@ -571,6 +592,21 @@ Fields: Symptom (what was observed), Root cause (why it happened), Fix (what was done), Refs (links to related decisions/concepts). All on one timeline entry so `gbrain search "JWT cache bug"` finds it. +### Codex review 5: goals/ vs projects/ for MECE + +**Question:** Should we keep projects/ with disambiguation rules, or replace +with goals/ to match the user's /goal-driven workflow? + +**Verdict:** Replace projects/ with goals/. goals/ is cleanly ME with the other +3 types because it's a context-bound execution episode, while the other 3 are +reusable artifacts. projects/ had HIGH overlap with all 3 (a decision could be +a project section OR a standalone page). goals/ eliminates that overlap because +the filing rule becomes: capture in goals/ first, promote out when reusable. + +**Impact on spec:** Replaced projects/ with goals/ throughout. New PageType +additions: 3 (goal, decision, process) instead of 2. DIR_PATTERN additions: 3 +instead of 2. Added MECE boundary table with hard rules for all 6 pairs. + ## Architecture Compliance Audited against `/workspaces/gbrain/docs/architecture/` (4 docs). @@ -669,8 +705,8 @@ Added to the change manifest: | # | File | What changes | Tier | |---|------|-------------|------| -| NEW | `src/core/types.ts` | Add `decision` + `process` to `PageType` union and `ALL_PAGE_TYPES` | Tier 1 (compile-time break) | -| UPDATED | entrypoint.sh | Drop 2 files (not 3) — keep brain-routing.md | Tier 1 | +| NEW | `src/core/types.ts` | Add `goal` + `decision` + `process` to `PageType` union and `ALL_PAGE_TYPES` | Tier 1 (compile-time break) | +| NOTE | entrypoint.sh (out of scope) | Drop 2 files from array — follow-up in devcontainer repo | N/A | | UPDATED | `src/core/markdown.ts` `inferType()` | Moved from Tier 2 to Tier 1 — ordering matters for hybrid paths | Tier 1 | ## Reviews From 0c6a111684f1f9c7b416c47765d23154e496789c Mon Sep 17 00:00:00 2001 From: chapter37haptics <249148637+chapter37haptics@users.noreply.github.com> Date: Thu, 14 May 2026 21:35:20 +0000 Subject: [PATCH 06/10] v4.1: add spec update rules section 6 rules codified from recurring manual requests during this session: commit after every update, Codex second opinion before decisions, architecture compliance checks, Reviews section maintenance, MECE verification on entity changes, Context section kept current. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/specs/customized-domain.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/docs/specs/customized-domain.md b/docs/specs/customized-domain.md index bbb91692d..0446f0a44 100644 --- a/docs/specs/customized-domain.md +++ b/docs/specs/customized-domain.md @@ -793,3 +793,35 @@ processes, concepts) sound? **Impact on spec:** Narrowed scope accepted. Added structured debug-trail timeline entry format to the project page template. Added concepts/ notability criteria to quality.md patch requirements. + +## Spec Update Rules + +These rules apply to any session that modifies this spec. + +1. **Commit and push after every spec update.** Each version gets its own + commit with a `vN:` prefix in the message summarizing what changed. + Never batch multiple rounds of changes into one commit. + +2. **Get a Codex second opinion before finalizing decisions.** Use + `/gstack-codex` to validate significant decisions (entity scope changes, + architecture compliance, MECE boundaries). Add the verdict to the Reviews + section. Do not finalize a decision based on a single model's analysis. + +3. **Check architecture compliance after structural changes.** Any change to + entity types, filing rules, or code-level patterns must be verified against + `docs/architecture/` (system-of-record, brains-and-sources, infra-layer, + topologies). Document findings in the Architecture Compliance section. + +4. **Add every Codex review to the Reviews section.** Each review gets a + subsection with: the question asked, the verdict, and the impact on the + spec. Reviews are numbered sequentially (Codex review 1, 2, 3...). + +5. **Verify MECE when entity types change.** Any addition, removal, or rename + of entity types requires a pairwise overlap check. Every pair must have a + hard boundary (not a judgment call). Document the boundaries in the MECE + boundaries table. + +6. **Update the Context section when decisions change.** The Context section + is what a new session reads first. If a decision changes the entity types, + the workflow, the file counts, or the architectural constraints, the + Context section must be updated in the same commit. From e351f40064f428a36aa67552bb9c639ca365572d Mon Sep 17 00:00:00 2001 From: chapter37haptics <249148637+chapter37haptics@users.noreply.github.com> Date: Thu, 14 May 2026 21:36:14 +0000 Subject: [PATCH 07/10] v4.2: move Spec Update Rules after Context section Rules are meta-instructions for working on the spec. A new session should see them before the content they'll be modifying. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/specs/customized-domain.md | 63 +++++++++++++++++---------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/docs/specs/customized-domain.md b/docs/specs/customized-domain.md index 0446f0a44..d3ef8015b 100644 --- a/docs/specs/customized-domain.md +++ b/docs/specs/customized-domain.md @@ -156,6 +156,38 @@ VC types stay in the infrastructure but the agent stops triggering on them. a conversation, then in a separate query ask "why did we choose Postgres?" and verify the brain returns the decision page. +## Spec Update Rules + +These rules apply to any session that modifies this spec. + +1. **Commit and push after every spec update.** Each version gets its own + commit with a `vN:` prefix in the message summarizing what changed. + Never batch multiple rounds of changes into one commit. + +2. **Get a Codex second opinion before finalizing decisions.** Use + `/gstack-codex` to validate significant decisions (entity scope changes, + architecture compliance, MECE boundaries). Add the verdict to the Reviews + section. Do not finalize a decision based on a single model's analysis. + +3. **Check architecture compliance after structural changes.** Any change to + entity types, filing rules, or code-level patterns must be verified against + `docs/architecture/` (system-of-record, brains-and-sources, infra-layer, + topologies). Document findings in the Architecture Compliance section. + +4. **Add every Codex review to the Reviews section.** Each review gets a + subsection with: the question asked, the verdict, and the impact on the + spec. Reviews are numbered sequentially (Codex review 1, 2, 3...). + +5. **Verify MECE when entity types change.** Any addition, removal, or rename + of entity types requires a pairwise overlap check. Every pair must have a + hard boundary (not a judgment call). Document the boundaries in the MECE + boundaries table. + +6. **Update the Context section when decisions change.** The Context section + is what a new session reads first. If a decision changes the entity types, + the workflow, the file counts, or the architectural constraints, the + Context section must be updated in the same commit. + ## Important Files GBrain's agent behavior is driven by skill files that get concatenated into @@ -794,34 +826,3 @@ processes, concepts) sound? timeline entry format to the project page template. Added concepts/ notability criteria to quality.md patch requirements. -## Spec Update Rules - -These rules apply to any session that modifies this spec. - -1. **Commit and push after every spec update.** Each version gets its own - commit with a `vN:` prefix in the message summarizing what changed. - Never batch multiple rounds of changes into one commit. - -2. **Get a Codex second opinion before finalizing decisions.** Use - `/gstack-codex` to validate significant decisions (entity scope changes, - architecture compliance, MECE boundaries). Add the verdict to the Reviews - section. Do not finalize a decision based on a single model's analysis. - -3. **Check architecture compliance after structural changes.** Any change to - entity types, filing rules, or code-level patterns must be verified against - `docs/architecture/` (system-of-record, brains-and-sources, infra-layer, - topologies). Document findings in the Architecture Compliance section. - -4. **Add every Codex review to the Reviews section.** Each review gets a - subsection with: the question asked, the verdict, and the impact on the - spec. Reviews are numbered sequentially (Codex review 1, 2, 3...). - -5. **Verify MECE when entity types change.** Any addition, removal, or rename - of entity types requires a pairwise overlap check. Every pair must have a - hard boundary (not a judgment call). Document the boundaries in the MECE - boundaries table. - -6. **Update the Context section when decisions change.** The Context section - is what a new session reads first. If a decision changes the entity types, - the workflow, the file counts, or the architectural constraints, the - Context section must be updated in the same commit. From 58f76d418758acd7571b7797668d113a3b9af97b Mon Sep 17 00:00:00 2001 From: chapter37haptics <249148637+chapter37haptics@users.noreply.github.com> Date: Fri, 15 May 2026 02:10:51 +0000 Subject: [PATCH 08/10] Replace CLAUDE.md with spec-focused trimmed version Keep the original as CLAUDE-original-read-only.md for reference when making improvements, but the full 1445-line / 226KB file is too large to use as the active system prompt for implementing the customized-domain spec. The new CLAUDE.md (192 lines / 14KB) preserves exact text from the original for sections relevant to the spec work. Co-Authored-By: Claude Opus 4.6 (1M context) --- CLAUDE-original-read-only.md | 1445 ++++++++++++++++++++++++++++++++++ CLAUDE.md | 1371 ++------------------------------ 2 files changed, 1504 insertions(+), 1312 deletions(-) create mode 100644 CLAUDE-original-read-only.md diff --git a/CLAUDE-original-read-only.md b/CLAUDE-original-read-only.md new file mode 100644 index 000000000..9b2a6df11 --- /dev/null +++ b/CLAUDE-original-read-only.md @@ -0,0 +1,1445 @@ +# CLAUDE.md + +GBrain is a personal knowledge brain and GStack mod for agent platforms. Pluggable +engines: PGLite (embedded Postgres via WASM, zero-config default) or Postgres + pgvector ++ hybrid search in a managed Supabase instance. `gbrain init` defaults to PGLite; +suggests Supabase for 1000+ files. GStack teaches agents how to code. GBrain teaches +agents everything else: brain ops, signal detection, content ingestion, enrichment, +cron scheduling, reports, identity, and access control. + +## Two organizational axes (read this first) + +GBrain knowledge is organized along two orthogonal axes. Users AND agents must +understand both, or queries misroute silently. + +- **Brain** — WHICH DATABASE. Your personal brain is `host`. You can mount + additional brains (team-published, each with their own DB and access policy) + via `gbrain mounts add` (v0.19+). Routing: `--brain`, `GBRAIN_BRAIN_ID`, + `.gbrain-mount` dotfile. +- **Source** — WHICH REPO INSIDE THE DATABASE. A brain can hold many sources + (wiki, gstack, openclaw, essays). Slugs scope per source. Routing: + `--source`, `GBRAIN_SOURCE`, `.gbrain-source` dotfile. + +Both axes follow the same 6-tier resolution pattern. Read +`docs/architecture/brains-and-sources.md` for topology diagrams (personal, team +mount, CEO-class with multiple team brains) and +`skills/conventions/brain-routing.md` for the agent-facing decision table. + +## Architecture + +Contract-first: `src/core/operations.ts` defines ~47 shared operations (v0.29 adds `get_recent_salience`, `find_anomalies`, `get_recent_transcripts`). CLI and MCP +server are both generated from this single source. Engine factory (`src/core/engine-factory.ts`) +dynamically imports the configured engine (`'pglite'` or `'postgres'`). Skills are fat +markdown files (tool-agnostic, work with both CLI and plugin contexts). + +**Trust boundary:** `OperationContext.remote` distinguishes trusted local CLI callers +(`remote: false` set by `src/cli.ts`) from untrusted agent-facing callers +(`remote: true` set by `src/mcp/server.ts`). Security-sensitive operations like +`file_upload` tighten filesystem confinement when `remote=true` and default to +strict behavior when unset. + +## Key files + +- `src/core/operations.ts` — Contract-first operation definitions (the foundation). Also exports upload validators: `validateUploadPath`, `validatePageSlug`, `validateFilename`, plus `matchesSlugAllowList(slug, prefixes)` (v0.23 glob matcher: `/*` matches recursive children; bare `` matches exact only). `OperationContext.remote` flags untrusted callers; `OperationContext.allowedSlugPrefixes` (v0.23) is the trusted-workspace allow-list set by the dream cycle. `put_page` enforces: when `viaSubagent` and `allowedSlugPrefixes` is set, slug must match the allow-list; else the legacy `wiki/agents//...` namespace check applies. Auto-link enabled for trusted-workspace writes (skipped only when `remote=true && !trustedWorkspace`). As of v0.26.0, every `Operation` also carries `scope?: 'read' | 'write' | 'admin'` + `localOnly?: boolean`. All ops are annotated; `sync_brain`, `file_upload`, `file_list`, and `file_url` are `admin + localOnly` (rejected over HTTP). `OperationContext.auth?: AuthInfo` is threaded through HTTP dispatch for scope enforcement in `serve-http.ts` before the op runs. **v0.26.9 (D12 + F7b):** `OperationContext.remote` is now a REQUIRED field in the TypeScript type — the compiler is the first defense against transports that forget to set it. Four trust-boundary call sites (`put_page` allowlist, file_upload trust-narrowing, submit_job protected-name guard, auto-link skip) flipped from falsy-default (`!ctx.remote`) to fail-closed semantics (`ctx.remote === false` for "trusted-only" sites and `ctx.remote !== false` for "untrust unless explicit-false"). Anything that isn't strictly `false` is now treated as remote. Closed an HTTP MCP shell-job RCE: a `read+write`-scoped OAuth token could submit `shell` jobs because the HTTP request handler's literal context skipped `remote: true` and `submit_job`'s protected-name guard saw a falsy undefined. Stdio MCP set the field correctly via dispatch.ts; HTTP inlined a parallel context-builder for several releases and lost it. +- `src/core/engine.ts` — Pluggable engine interface (BrainEngine). `clampSearchLimit(limit, default, cap)` takes an explicit cap so per-operation caps can be tighter than `MAX_SEARCH_LIMIT`. Exports `LinkBatchInput` / `TimelineBatchInput` for the v0.12.1 bulk-insert API (`addLinksBatch` / `addTimelineEntriesBatch`). As of v0.13.1, `BrainEngine` has a `readonly kind: 'postgres' | 'pglite'` discriminator so migrations (`src/core/migrate.ts`) and other consumers can branch on engine without `instanceof` + dynamic imports. **v0.29:** four new methods — `batchLoadEmotionalInputs(slugs?)` (CTE-shaped read with per-table aggregates so a page × N tags × M takes never produces N×M rows), `setEmotionalWeightBatch(rows)` (`UPDATE FROM unnest($1::text[], $2::text[], $3::real[])` composite-keyed on `(slug, source_id)` for multi-source safety), `getRecentSalience(opts)`, `findAnomalies(opts)`. `PageFilters` extended with `sort?: 'updated_desc' | 'updated_asc' | 'created_desc' | 'slug'` + `PAGE_SORT_SQL` whitelist consumed by both engines (was hardcoded `ORDER BY updated_at DESC`). **v0.32.8 (PR #860):** new `listAllPageRefs(): Promise>` ordered by `(source_id, slug)`. Cheap cross-source enumeration for hot loops on large brains — replaces the `getAllSlugs()→getPage(slug)` N+1 pattern in extract-takes, extract, integrity, which silently defaulted to `source_id='default'` for non-default-source pages. Implementation parity across postgres-engine.ts + pglite-engine.ts. Pinned by `test/e2e/multi-source-bug-class.test.ts`. +- `src/core/engine-factory.ts` — Engine factory with dynamic imports (`'pglite'` | `'postgres'`) +- `src/core/pglite-engine.ts` — PGLite (embedded Postgres 17.5 via WASM) implementation, all 40 BrainEngine methods. `addLinksBatch` / `addTimelineEntriesBatch` use multi-row `unnest()` with manual `$N` placeholders. As of v0.13.1, `connect()` wraps `PGlite.create()` in a try/catch that emits an actionable error naming the macOS 26.3 WASM bug (#223) and pointing at `gbrain doctor`; the lock is released on failure so the next process can retry cleanly. v0.22.0: `searchKeyword` and `searchKeywordChunks` multiply `ts_rank` by the source-factor CASE expression at the chunk-grain level; `searchVector` becomes a two-stage CTE — inner CTE keeps `ORDER BY cc.embedding <=> vec` so HNSW stays usable, outer SELECT re-ranks by `raw_score * source_factor`. Inner LIMIT scales with offset to preserve pagination contract. As of v0.22.6.1, `initSchema()` calls `applyForwardReferenceBootstrap()` BEFORE replaying SCHEMA_SQL — probes for the specific forward-referenced state the embedded schema blob needs (`pages.source_id`, `links.link_source`, `links.origin_page_id`, `content_chunks.symbol_name`, `content_chunks.language`, `sources` FK target table) and adds only what's missing. Closes the upgrade-wedge bug class that bit users 10+ times across 6 schema versions over 2 years (#239/#243/#266/#357/#366/#374/#375/#378/#395/#396). No-op on fresh installs and modern brains. +- `src/core/pglite-schema.ts` — PGLite-specific DDL (pgvector, pg_trgm, triggers) +- `src/core/postgres-engine.ts` — Postgres + pgvector implementation (Supabase / self-hosted). `addLinksBatch` / `addTimelineEntriesBatch` use `INSERT ... SELECT FROM unnest($1::text[], ...) JOIN pages ON CONFLICT DO NOTHING RETURNING 1` — 4-5 array params regardless of batch size, sidesteps the 65535-parameter cap. As of v0.12.3, `searchKeyword` / `searchVector` scope `statement_timeout` via `sql.begin` + `SET LOCAL` so the GUC dies with the transaction instead of leaking across the pooled postgres.js connection (contributed by @garagon). `getEmbeddingsByChunkIds` uses `tryParseEmbedding` so one corrupt row skips+warns instead of killing the query. v0.22.0: `searchKeyword`, `searchKeywordChunks`, and `searchVector` apply source-aware ranking by inlining the source-factor CASE and `NOT (col LIKE …)` hard-exclude clause from `src/core/search/sql-ranking.ts`. `searchVector` switches to a two-stage CTE (HNSW-safe inner ORDER BY, source-boost re-rank in the outer SELECT) and carries `p.source_id` through inner→outer for v0.18 multi-source callers. v0.22.1 (#406): `_savedConfig` retains the connect config; `reconnect()` tears down + recreates the pool from saved config (called by supervisor watchdog after 3 consecutive health-check failures). `executeRaw` is a single-statement passthrough — no per-call retry (D3 dropped that as unsound for non-idempotent statements; recovery is supervisor-driven). v0.22.1 (#363, contributed by @orendi84): `connect()` applies `resolveSessionTimeouts()` from `db.ts` as connection-time startup parameters (`statement_timeout`, `idle_in_transaction_session_timeout`) so orphan pgbouncer backends can't hold locks for hours. v0.22.1 (#409, contributed by @atrevino47): `countStaleChunks()` + `listStaleChunks()` server-side-filter on `embedding IS NULL` for `embed --stale`, eliminating ~76 MB/call client-side pull on a fully-embedded brain; `upsertChunks()` resets both `embedding` AND `embedded_at` to NULL when chunk_text changes without a new embedding (consistency). As of v0.22.6.1, `initSchema()` calls `applyForwardReferenceBootstrap()` BEFORE replaying SCHEMA_SQL on the same forward-reference probe set as the PGLite engine, so old Postgres brains pinned at v0.13/v0.18/v0.19 walk forward cleanly instead of wedging on `column "..." does not exist`. **v0.28.1:** `disconnect()` is now idempotent. New `_connectionStyle` instance field tracks whether the engine owns its pool (worker engines) or shares the module-level singleton; second call on an instance-pool engine is a no-op rather than falling through to `db.disconnect()` and clobbering the singleton. Pinned by `test/e2e/postgres-engine-disconnect-idempotency.test.ts` (2 cases). Closes the bug class where any test sharing an engine across multiple `worker.start()` / `worker.stop()` cycles silently broke its own DB connectivity. +- `src/core/cjk.ts` (v0.32.7 CJK wave) — Single source of truth for CJK detection across the codebase. Exports `CJK_RANGES_REGEX`, `CJK_SLUG_CHARS` (character-class fragment for embedding inside other regexes), `CJK_SENTENCE_DELIMITERS` (`。!?`), `CJK_CLAUSE_DELIMITERS` (`;:,、`), `CJK_DENSITY_THRESHOLD = 0.30`, `hasCJK(s)`, `countCJKAwareWords(s)` (30% density threshold — English docs with one Japanese term stay whitespace-tokenized; Chinese-dominant docs get char-counted), and `escapeLikePattern(s)` (escapes `%`, `_`, `\\` for `ILIKE ... ESCAPE '\\'`). Replaces the inline hasCJK regex previously duplicated at `expansion.ts:58`. BMP-only ranges (Han / Hiragana / Katakana / Hangul Syllables); widening to Unicode property escapes is a v0.33+ TODO. Consumers: `expansion.ts`, `sync.ts:slugifySegment`, `operations.ts:validatePageSlug + validateFilename`, `chunkers/recursive.ts:countWords + DELIMITERS`, `pglite-engine.ts:searchKeyword + searchKeywordChunks`. +- `src/core/audit-slug-fallback.ts` (v0.32.7 CJK wave) — Weekly ISO-week-rotated audit JSONL at `~/.gbrain/audit/slug-fallback-YYYY-Www.jsonl`. `logSlugFallback(slug, sourcePath)` fires when `importFromFile` falls back to a frontmatter slug because `slugifyPath` returned empty (emoji / Thai / Arabic / non-CJK exotic-script filenames). `readRecentSlugFallbacks(days)` reads the last N days for `gbrain doctor`'s `slug_fallback_audit` check. Honors `GBRAIN_AUDIT_DIR` via the shared `resolveAuditDir()` from shell-audit.ts. Separate surface from `sync-failures.jsonl` per codex outside-voice review — that file carries bookmark-gating semantics that info events shouldn't trigger. +- `src/core/embedding-pricing.ts` (v0.32.7 CJK wave) — `EMBEDDING_PRICING` map keyed `provider:model` for the post-upgrade reindex cost estimate. Sibling to `anthropic-pricing.ts`. Entries: OpenAI text-embedding-3-large ($0.13/1M), 3-small ($0.02/1M), ada-002 ($0.10/1M), Voyage 3-large ($0.18/1M), 3 ($0.06/1M). `lookupEmbeddingPrice(modelString)` returns a tagged union (`known` with price + `unknown` with provider name); `estimateCostFromChars(charCount, pricePerMTok)` uses 3.5 chars/token approximation. Unknown providers degrade gracefully to "estimate unavailable" instead of fabricating numbers. +- `src/core/post-upgrade-reembed.ts` (v0.32.7 CJK wave) — Pure functions backing the `gbrain upgrade` chunker-bump cost prompt. `computeReembedEstimate(engine, model)` queries real SQL (`COUNT(*)` + `COALESCE(SUM(LENGTH(compiled_truth)) + SUM(LENGTH(timeline)), 0)`) on `pages WHERE chunker_version < MARKDOWN_CHUNKER_VERSION`. `formatReembedPrompt(est, graceSeconds)` is the stderr-line formatter. `runPostUpgradeReembedPrompt(engine, model, opts)` orchestrates the 10-second Ctrl-C window; TTY-only wait (non-TTY auto-proceeds for CI / cron); `GBRAIN_NO_REEMBED=1` bails out with a doctor-warning marker; `GBRAIN_REEMBED_GRACE_SECONDS=0` skips the wait. +- `src/commands/reindex.ts` (v0.32.7 CJK wave) — `gbrain reindex --markdown [--limit N] [--dry-run] [--json] [--no-embed] [--repo PATH]`. Walks `pages WHERE page_kind = 'markdown' AND chunker_version < MARKDOWN_CHUNKER_VERSION` in 100-row batches, ordered by id. Rows with non-null `source_path` re-import via `importFromFile`; rows without fall back to `importFromContent` against the stored `compiled_truth`. **Both paths pass `forceRechunk: true`** to bypass `importFromContent`'s `content_hash` short-circuit — without that flag (codex post-merge F1), the chunker version bump never reaches pages whose source content hasn't changed since last sync, AND master's v0.32.2 stripFactsFence privacy strip never applies to pre-strip chunks. Idempotent — partial-completion re-runs pick up where they left off via id-ordered batches. Wired into `src/commands/upgrade.ts:runPostUpgrade` after `apply-migrations`. +- `src/commands/sync.ts:resolveSlugByPathOrSourcePath` (v0.32.7 CJK wave, codex post-merge F4) — Resolves a slug by `pages.source_path` first (returns the stored slug for frontmatter-fallback pages whose path doesn't derive a slug), then falls back to `resolveSlugForPath(path)`. Threaded into all 4 delete/rename call sites (`performSync`'s un-syncable cleanup at ~:531, deletes at ~:603, rename oldSlug at ~:622). Without this, emoji-only / Thai / Arabic filenames whose slug came from frontmatter would orphan on delete/rename (the delete path would compute the wrong path-derived slug). Best-effort query — pre-migration brains fall through to the legacy path. +- `src/core/utils.ts` — Shared SQL utilities extracted from postgres-engine.ts. Exports `parseEmbedding(value)` (throws on unknown input, used by migration + ingest paths where data integrity matters) and as of v0.12.3 `tryParseEmbedding(value)` (returns `null` + warns once per process, used by search/rescore paths where availability matters more than strictness). **v0.26.9 (D14):** adds `isUndefinedColumnError(err)` predicate — pattern-matches Postgres SQLSTATE 42703 / "column ... does not exist" with engine-driver shape variation tolerated. Replaces bare `catch {}` blocks in `oauth-provider.ts` so genuine errors (lock timeout, network blip, permission denied) propagate while column-missing falls through to the legacy fallback path. Reusable from any future code that needs the same column-existence probe semantics. **v0.32.8 (PR #860):** adds `validateSourceId(id)` that throws on anything outside `^[a-z0-9_-]+$`. Used by the per-source disk-layout fix in patterns.ts/synthesize.ts before any `join(brainDir, '.sources', source_id, slug+'.md')` call so source_id can't traverse out of brainDir. `rowToPage` updated to populate the now-required `Page.source_id` field from the SELECT projection (`scripts/check-source-id-projection.sh` enforces that every projection feeding `rowToPage` includes the column). +- `src/core/db.ts` — Connection management, schema initialization. v0.22.1 (#363, contributed by @orendi84): `resolveSessionTimeouts()` returns `statement_timeout` + `idle_in_transaction_session_timeout` (defaults: 5min each, env-overridable via `GBRAIN_STATEMENT_TIMEOUT` / `GBRAIN_IDLE_TX_TIMEOUT` / `GBRAIN_CLIENT_CHECK_INTERVAL`). Both `connect()` (module singleton) and `PostgresEngine.connect()` (worker pool) consume the result via postgres.js's `connection` option, sending GUCs as startup parameters that survive PgBouncer transaction mode (unlike the prior `setSessionDefaults` post-pool SET, kept as a back-compat no-op shim). +- `src/commands/migrate-engine.ts` — Bidirectional engine migration (`gbrain migrate --to supabase/pglite`) +- `src/core/import-file.ts` — importFromFile + importFromContent (chunk + embed + tags) +- `src/core/sync.ts` — Pure sync functions (manifest parsing, filtering, slug conversion). v0.22.12 (#500, foundation by @wintermute via #501): `classifyErrorCode(errorMsg)` regex-based classifier with 12 codes (`SLUG_MISMATCH`, `YAML_PARSE`, `YAML_DUPLICATE_KEY`, `MISSING_OPEN`, `MISSING_CLOSE`, `NESTED_QUOTES`, `EMPTY_FRONTMATTER`, `NULL_BYTES`, `INVALID_UTF8`, `STATEMENT_TIMEOUT`, `FILE_TOO_LARGE`, `SYMLINK_NOT_ALLOWED`) plus `UNKNOWN` fallback. `summarizeFailuresByCode(failures)` returns sorted `[{code, count}]`. `code?` optional field on `SyncFailure`; backfilled at ack time on pre-v0.22.12 entries. `acknowledgeSyncFailures()` returns `AcknowledgeResult { count, summary }`. Three regexes (`MISSING_OPEN`, `MISSING_CLOSE`, `EMPTY_FRONTMATTER`) broadened to match actual `markdown.ts:159-244` validator message strings, not just the literal code-name prefix. `FILE_TOO_LARGE` covers all three production size sites in `import-file.ts:199, 352, 401`; `SYMLINK_NOT_ALLOWED` covers the rejection at `:347`. Closes the silent-skip pattern that motivated #500. +- `src/core/storage.ts` — Pluggable storage interface (S3, Supabase Storage, local) +- `src/core/storage-config.ts` (v0.22.11) — Storage tiering: `loadStorageConfig` reads `gbrain.yml`, normalizes deprecated keys (`git_tracked` / `supabase_only`) to canonical (`db_tracked` / `db_only`) with once-per-process deprecation warning, and runs `normalizeAndValidateStorageConfig` (auto-fixes missing trailing `/`, throws `StorageConfigError` on tier overlap). Path-segment matcher: `media/x/` does NOT match `media/xerox/foo`. Replaces gray-matter (broken on delimiter-less YAML) with a dedicated parser for the `gbrain.yml` shape. +- `src/core/disk-walk.ts` (v0.22.11) — `walkBrainRepo(repoPath)` returns `Map` from one recursive `readdirSync`. Skips dot-dirs, `node_modules`, non-`.md` files. Used by `gbrain storage status` to replace per-page `existsSync + statSync` (~400K syscalls on 200K-page brains → tens). +- `src/commands/storage.ts` (v0.22.11) — `gbrain storage status [--repo P] [--json]`. Split into pure data (`getStorageStatus`) + JSON formatter + human formatter (ASCII-only per D10) matching the `orphans.ts` pattern. `PageCountsByTier` and `DiskUsageByTier` are distinct nominal types so swaps fail at compile time. +- `gbrain.yml` (brain repo root, v0.22.11) — Optional storage tiering config. Top-level `storage:` section with `db_tracked:` and `db_only:` array-valued keys. `gbrain sync` auto-manages `.gitignore` for `db_only` paths on successful sync (skips on dry-run, blocked-by-failures, submodule context, or `GBRAIN_NO_GITIGNORE=1`). `gbrain export --restore-only [--repo P] [--type T] [--slug-prefix S]` repopulates missing `db_only` files from the database. +- `src/core/supabase-admin.ts` — Supabase admin API (project discovery, pgvector check) +- `src/core/file-resolver.ts` — File resolution with fallback chain (local -> .redirect.yaml -> .redirect -> .supabase) +- `src/core/chunkers/` — 3-tier chunking (recursive, semantic, LLM-guided). v0.19.0 adds `code.ts` — tree-sitter-based semantic chunker for 29 languages with embedded-asset WASMs (`src/assets/wasm/`), `@dqbd/tiktoken` cl100k_base tokenizer, small-sibling merging. `CHUNKER_VERSION` constant folded into `importCodeFile`'s `content_hash` so chunker shape changes force clean re-chunks across releases. +- `src/core/errors.ts` (v0.19.0) — `StructuredAgentError` + `buildError` + `serializeError`. Every new v0.19.0 agent-facing surface (code-def, code-refs, usage errors) uses this envelope; matches v0.17.0 `CycleReport.PhaseResult.error` shape. +- `src/assets/wasm/` (v0.19.0) — 36 tree-sitter grammar WASMs + tree-sitter runtime. Committed to the repo so `bun --compile` embeds them deterministically via `import path from ... with { type: 'file' }`. The CI guard `scripts/check-wasm-embedded.sh` fails the build if the compiled binary ever silently falls through to recursive chunks. +- `src/commands/code-def.ts` + `src/commands/code-refs.ts` (v0.19.0) — symbol definition + references lookup. Query `content_chunks.symbol_name` or chunk_text ILIKE with `page_kind='code'` filter. Auto-JSON when stdout is not a TTY (gh-CLI convention). Bypass the standard `searchKeyword` `DISTINCT ON (slug)` collapse so multiple call-sites from the same file surface. +- `src/core/search/` — Hybrid search: vector + keyword + RRF + multi-query expansion + dedup. As of v0.22.0, `searchKeyword` / `searchKeywordChunks` / `searchVector` apply source-aware ranking at the SQL layer (curated content like `originals/`, `concepts/`, `writing/` outranks bulk content like `wintermute/chat/`, `daily/`, `media/x/`). `searchVector` uses a two-stage CTE so source-boost re-ranking doesn't kill the HNSW index. Hard-exclude prefixes (`test/`, `archive/`, `attachments/`, `.raw/` by default) filter at retrieval, not post-rank. Both gates honor `detail !== 'high'` so temporal queries surface chat pages normally. +- `src/core/search/intent.ts` — Query intent classifier (entity/temporal/event/general → auto-selects detail level) +- `src/core/search/eval.ts` — Retrieval eval harness: P@k, R@k, MRR, nDCG@k metrics + runEval() orchestrator +- `src/core/search/source-boost.ts` (v0.22.0) — Source-type boost map keyed by slug prefix. `DEFAULT_SOURCE_BOOSTS` (originals/ 1.5, concepts/ 1.3, writing/ 1.4, people/companies/deals/ 1.2, daily/ 0.8, media/x/ 0.7, wintermute/chat/ 0.5) and `DEFAULT_HARD_EXCLUDES` (test/, archive/, attachments/, .raw/). `parseSourceBoostEnv` / `parseHardExcludesEnv` parse comma-separated `prefix:factor` pairs from `GBRAIN_SOURCE_BOOST` / `GBRAIN_SEARCH_EXCLUDE` env vars. `resolveBoostMap` and `resolveHardExcludes` merge defaults + env + caller `SearchOpts.exclude_slug_prefixes`/`include_slug_prefixes`. +- `src/core/search/sql-ranking.ts` (v0.22.0) — Pure SQL string builders. `buildSourceFactorCase(slugColumn, boostMap, detail)` emits a CASE expression with longest-prefix-match wins (returns literal `'1.0'` when `detail === 'high'` for temporal-bypass parity with COMPILED_TRUTH_BOOST). `buildHardExcludeClause(slugColumn, prefixes)` emits `NOT (col LIKE 'p1%' OR col LIKE 'p2%')` — OR-chain wrapped in NOT, NOT `NOT LIKE ALL/ANY` (those quantifiers don't express set-exclusion). LIKE meta-character escape covers all three of `%`, `_`, AND `\` (backslash matters because it's Postgres LIKE's default escape char). Single-quote doubling on SQL string literals so injection-style inputs are inert text. +- `src/commands/eval.ts` — `gbrain eval` command: single-run table + A/B config comparison. v0.25.0 adds sub-subcommand dispatch on `args[0]` so `gbrain eval export` + `gbrain eval prune` + `gbrain eval replay` route into session-capture handlers; bare `gbrain eval --qrels …` fall-through preserves the legacy IR-metrics flow. v0.27.x adds `gbrain eval cross-modal` to the dispatch (the user-facing path is the cli.ts no-DB branch — `src/commands/eval.ts:cross-modal` only fires when callers re-enter with an existing engine). +- `src/commands/eval-cross-modal.ts` (v0.27.x) — multi-model quality gate. Three different-provider frontier models score the OUTPUT against the TASK on a 5-dim list. Verdict `pass` (exit 0) / `fail` (exit 1) / `inconclusive` (exit 2; <2/3 model successes per Q3=A in plans/radiant-napping-lerdorf.md). Reuses `src/core/ai/gateway.ts:chat()` so config/auth/aliasing comes from the gateway recipe registry — no parallel provider stack. Self-configures the gateway (`configureGateway(loadConfig() + process.env)`) since the cli.ts dispatch bypasses `connectEngine()`. Default cycles 3 in TTY, 1 in non-TTY (T11=B partial cost guardrail). Receipts land at `gbrainPath('eval-receipts')/-.json`. The full `--budget-usd` cap is a v0.27.x follow-up TODO. +- `src/core/cross-modal-eval/json-repair.ts` (v0.27.x) — `parseModelJSON(raw)` named export with a 4-strategy fallback chain (direct parse → fence-strip → trailing-comma + single-quote + embedded-newline repair → regex nuclear option). Adversarial input throws rather than fabricating scores — the aggregator treats a throw as "this model contributed nothing this cycle" so the gate stays correct at >=2/3 successes. +- `src/core/cross-modal-eval/aggregate.ts` (v0.27.x) — pure verdict logic. Pass criterion: `(successes >= 2) AND (every dim mean >= 7) AND (every dim min across models >= 5)` (Q2=A floor). Inconclusive when <2/3 models returned parseable scores (Q3=A regression guard for the v1 .mjs `Object.values({}).every(...) === true` empty-array PASS bug). +- `src/core/cross-modal-eval/runner.ts` (v0.27.x) — orchestrator. Each cycle runs `Promise.allSettled([gwChat(slotA), gwChat(slotB), gwChat(slotC)])` (T4=A — bare allSettled, no rate-leases for the CLI path; minion-integration TODO recovers cross-process concurrency). Stops early on PASS or INCONCLUSIVE; runs up to 3 cycles. Default slots: `openai:gpt-4o` / `anthropic:claude-opus-4-7` / `google:gemini-1.5-pro`. `estimateCost()` exports a small per-model pricing table (drifts; refresh alongside model-family bumps). +- `src/core/cross-modal-eval/receipt-name.ts` (v0.27.x) — receipt filename binds (slug, SKILL.md sha-8). `findReceiptForSkill(skillPath, receiptDir)` returns `'found' | 'stale' | 'missing'` (T10=A). Skillify-check item 11 surfaces the status as informational (T7=C); the audit does NOT fail on missing/stale receipts. +- `src/core/cross-modal-eval/receipt-write.ts` (v0.27.x) — wraps `fs.writeFileSync` with `mkdirSync({recursive:true})` ahead of every write (T5 correction; `gbrainPath()` does NOT auto-mkdir). +- `src/commands/eval-export.ts` (v0.25.0) — streams `eval_candidates` rows as NDJSON to stdout with `schema_version: 1` prefix on every line. EPIPE-safe, progress heartbeats on stderr, stable id-desc tiebreaker so `--since` windows never dupe/miss rows. +- `src/commands/eval-prune.ts` (v0.25.0) — explicit retention cleanup. Requires `--older-than DUR`. `--dry-run` reports would-delete count. +- `src/commands/eval-replay.ts` (v0.25.0) — contributor-facing replay tool. Reads NDJSON from `gbrain eval export`, re-runs each captured `query` / `search` op against the current brain, computes set-Jaccard@k between captured + current `retrieved_slugs`, top-1 stability rate, and latency Δ. Stable JSON shape (`schema_version: 1`) for CI gating; human mode prints a regression table. Pure Bun, zero new deps. The dev-loop half of BrainBench-Real that closes the gap between "data captured" and "data used to gate a PR." See `docs/eval-bench.md` for the workflow. +- `src/commands/eval-suspected-contradictions.ts` + `src/core/eval-contradictions/{judge,runner,types,date-filter,cost-tracker,cache,severity-classify,cross-source,trends,calibration,judge-errors,auto-supersession,fixture-redact}.ts` (v0.32.6) — `gbrain eval suspected-contradictions [run|trend|review]`. Probe samples top-K retrieval pairs per query (cross-slug + intra-page chunk-vs-take), date pre-filters (3-rule layered — same-paragraph-dual-date overrides separation rule), LLM judge (query-conditioned per Codex; UTF-8-safe truncation; C1 confidence-floor double-enforcement; resolution_kind output drives M7 paste-ready commands), persistent cache keyed on `(chunk_a_hash, chunk_b_hash, model_id, prompt_version, truncation_policy)` (Codex outside-voice fix — prompt edits cleanly invalidate prior verdicts), Wilson 95% CI calibration on the headline percentage with `small_sample_note` when n<30, judge_errors as first-class typed counters (parse_fail/refusal/timeout/http_5xx/unknown — Codex fix to bias from silent skip), M5 trend writes to `eval_contradictions_runs`, M6 source-tier breakdown reuses `DEFAULT_SOURCE_BOOSTS` prefix logic, deterministic sampling (combined_score DESC + lex tiebreaker — stable cache hit-rate across re-runs). Hermetic via `judgeFn` + `searchFn` DI in the runner; never touches the real gateway in tests. Engine surface: `BrainEngine.listActiveTakesForPages` (P1 batched), `writeContradictionsRun` + `loadContradictionsTrend` (M5), `getContradictionCacheEntry` + `putContradictionCacheEntry` + `sweepContradictionCache` (P2). Schema migrations v51 + v52. MCP op `find_contradictions` (read scope, NOT localOnly, NOT in subagent allowlist — user-initiated only). M1 doctor check surfaces high-severity findings with paste-ready resolution commands. M2 synthesize phase pre-fetches latest probe's top-5-by-severity findings and threads them into `buildSynthesisPrompt` as an informational block. 226 hermetic unit tests + 12 real-Postgres E2E. Plan: `~/.claude/plans/system-instruction-you-are-working-hashed-dewdrop.md`. Architecture doc: `docs/contradictions.md`. +- `src/commands/eval-longmemeval.ts` + `src/eval/longmemeval/{harness,adapter,sanitize}.ts` (v0.28.1) — `gbrain eval longmemeval ` runs the public [LongMemEval](https://huggingface.co/datasets/xiaowu0162/longmemeval) benchmark against gbrain's hybrid retrieval. Architecture: one in-memory PGLite per benchmark run created via `createBenchmarkBrain` + `withBenchmarkBrain` (NO `EphemeralBrain` class). Between questions, `TRUNCATE` over runtime-enumerated `pg_tables` so future schema migrations don't silently leak data across questions; infrastructure tables (`sources`, `config`, `gbrain_cycle_locks`, `subagent_rate_leases`) are preserved. `cli.ts` has a pre-dispatch bypass so `eval longmemeval` skips `connectEngine()` — the user's `~/.gbrain` brain is never opened. `--expansion` defaults to OFF (deterministic, no per-query Haiku call); pass `--expansion` to opt in. Default model resolves through `resolveModel()` 6-tier chain with `models.eval.longmemeval` as the new config key. Sanitization parity: `harness.ts` re-uses `INJECTION_PATTERNS` from `src/core/think/sanitize.ts` (now exported, line 22) so adding a pattern automatically covers takes AND benchmarks. Retrieved chat content is wrapped in `` framing; the answer-gen system prompt declares the content UNTRUSTED. LLM injection seam: `runEvalLongMemEval(args, {client?: ThinkLLMClient})` lets tests stub the client so the full pipeline runs without an Anthropic API key. p50 25.9ms / p99 30.3ms warm reset+import+search on Apple Silicon (per `test/eval-longmemeval.test.ts` perf gate). Hand the JSONL output to LongMemEval's `evaluate_qa.py` to score (their published evaluator, not bundled — needs OpenAI gpt-4o per their spec). +- `docs/eval-bench.md` (v0.25.0) — contributor guide for using captured data to benchmark retrieval changes before merging. Linked from CONTRIBUTING.md under "Running real-world eval benchmarks (touching retrieval code)". +- `src/core/eval-capture.ts` (v0.25.0) — op-layer capture wrapper called from `src/core/operations.ts` `query` + `search` handlers. Catches MCP + CLI + subagent tool-bridge from one site. Fire-and-forget; failures route to `engine.logEvalCaptureFailure` so `gbrain doctor` sees drops cross-process. **Capture is off by default** — `isEvalCaptureEnabled` resolution: explicit `config.eval.capture` (true/false) wins, else `process.env.GBRAIN_CONTRIBUTOR_MODE === '1'`, else off. Production users get a quiet brain; contributors set `export GBRAIN_CONTRIBUTOR_MODE=1` in `.zshrc` to enable the dev loop. PII scrubber gate is independent and defaults to true regardless of CONTRIBUTOR_MODE. +- `src/core/eval-capture-scrub.ts` (v0.25.0) — zero-deps PII scrubber: emails, phones, SSN, Luhn-verified credit cards, JWT-shaped tokens, bearer tokens. +- `src/core/search/hybrid.ts` — Cathedral II `Promise` return shape unchanged in v0.25.0. Adds `onMeta?: (m: HybridSearchMeta) => void` callback so op-layer capture can record what hybridSearch actually did. Existing callers leave it undefined. +- `docs/eval-capture.md` (v0.25.0) — stable NDJSON schema reference for gbrain-evals consumers. +- `test/public-exports.test.ts` (v0.25.0 / R2) — runtime contract test. Imports each of the 17 public subpaths via package name and pins a canary symbol per module. Paired with `scripts/check-exports-count.sh`. +- `src/core/embedding.ts` — OpenAI text-embedding-3-large, batch, retry, backoff. **v0.28.7:** `BATCH_SIZE` reverted 50→100 — the original Voyage safety guard halved OpenAI throughput on every page. Per-recipe pre-split + recursive halving + adaptive shrink-on-miss now live in the gateway, so the outer paginator goes back to its original purpose: progress-callback granularity, not batch protection. +- `src/core/ai/types.ts` — provider/recipe types. **v0.28.7 (#680):** `EmbeddingTouchpoint` extended with optional `chars_per_token` (default 4 chars/token, matching OpenAI tiktoken on English) and `safety_factor` (default 0.8, budget-utilization ceiling). Both consulted only when `max_batch_tokens` is also set. Voyage declares `chars_per_token=1` + `safety_factor=0.5` to handle dense payloads (CJK/JSON/base64) that overshoot tiktoken. The pre-split budget is `max_batch_tokens × safety_factor / chars_per_token`. **v0.28.11 (#719):** `EmbeddingTouchpoint.multimodal_models?: string[]` model-level allow-list for recipes that mix text-only + multimodal models under one touchpoint (Voyage's 12 models share `supports_multimodal: true` but only `voyage-multimodal-3` accepts `/multimodalembeddings`). When omitted, recipe-level `supports_multimodal` is sufficient. `AIGatewayConfig.embedding_multimodal_model?: string` lets `embedMultimodal()` route to a different model than `embedding_model` — brains using OpenAI for text can use Voyage for images without flipping the primary embedding pipeline. +- `src/core/ai/gateway.ts` — unified seam for every AI call. **v0.28.7 (#680):** module-scoped `_embedTransport` defaulting to AI SDK `embedMany`, with `__setEmbedTransportForTests(fn)` test seam so tests drive the public `embed()` function with a stubbed transport instead of probing private helpers. `splitByTokenBudget` and `isTokenLimitError` are now exported `@internal` — pure functions reused directly by the test file. Module-level `_shrinkState: Map` halves the recipe's effective `safety_factor` on token-limit miss (floor 0.05) and heals back ×1.5 toward the ceiling after `SHRINK_HEAL_AFTER=10` consecutive successes. `configureGateway()` walks every registered recipe at construction time and emits a once-per-process stderr warning for any embedding touchpoint missing `max_batch_tokens` (excluding the canonical OpenAI fast-path recipe). `resetGateway()` clears `_shrinkState`, the warned-set, and restores the real transport. ASCII flow diagram embedded in the `embed()` JSDoc covers the routing decision, recursion + halving, and shrinkState lifecycle. **v0.28.11 (#719):** `embedMultimodal()` reads `cfg.embedding_multimodal_model` first (falls back to `cfg.embedding_model` for single-model setups). After the existing recipe-level `supports_multimodal` fast-fail, validates the resolved model against `touchpoint.multimodal_models` when declared — closes the Voyage-text-only-model-into-multimodal-endpoint footgun before any HTTP call (Codex F1 from PR review). New `getMultimodalModel()` accessor mirrors `getEmbeddingModel` / `getChatModel` so doctor and integration tests can read the gateway state. +- `src/core/ai/recipes/voyage.ts` — Voyage AI openai-compatible recipe. **v0.28.7 (#680):** declares `chars_per_token=1` + `safety_factor=0.5` so the gateway pre-splits Voyage batches at a 60K-character budget (50% of 120K-token cap with the dense-tokenizer ratio). Closes the v0.27 backfill loop where ~26% of the corpus stayed un-embedded because tiktoken-grounded budgeting silently undercounted Voyage's actual token usage. **v0.28.11 (#719):** declares `multimodal_models: ['voyage-multimodal-3']` so the gateway rejects text-only Voyage models pointed at the multimodal endpoint with a clear `AIConfigError` instead of waiting for Voyage's HTTP 400. +- `src/core/ai/recipes/anthropic.ts` — Anthropic recipe (chat + expansion touchpoints). **v0.31.12:** chat and expansion `models:` lists drop the v0.31.6 phantom `claude-sonnet-4-6-20250929` date suffix — canonical id is `claude-sonnet-4-6`. The wrong-direction alias `claude-sonnet-4-6 → claude-sonnet-4-6-20250929` is removed; a reverse alias `claude-sonnet-4-6-20250929 → claude-sonnet-4-6` keeps stale user configs working (rescues `facts.extraction_model` and `models.dream.synthesize` set by v0.31.6 installs). Recipe-shape regression pinned by `test/anthropic-model-ids.test.ts` (6 cases, verbatim cherry-pick of PR #830 plus the reverse-alias rescue case). +- `src/core/anthropic-pricing.ts` — Single source of truth for Anthropic model pricing (per-MTok input/output). **v0.31.12:** Opus 4.7 corrected from `$15/$75` to `$5/$25` (the old number was from Opus 4 generation, never refreshed when 4.7 shipped); Opus 4.6 also corrected. Consumed by `src/core/budget-meter.ts` and `src/core/cross-modal-eval/runner.ts` — the cross-modal estimator now reads `ANTHROPIC_PRICING` for Anthropic models instead of duplicating the table, killing the v0.31.6 drift bug class. +- `src/core/model-config.ts` — Model-string resolution (the seam every internal LLM call walks through). **v0.31.12:** four-tier system (`ModelTier = 'utility' | 'reasoning' | 'deep' | 'subagent'`) with `TIER_DEFAULTS` (utility→haiku-4-5, reasoning→sonnet-4-6, deep→opus-4-7, subagent→sonnet-4-6) and `tier?: ModelTier` on `ResolveModelOpts`. Resolution chain is now 8 steps: cliFlag → deprecated key → config key → `models.default` → `models.tier.` → env var → `TIER_DEFAULTS[tier]` → caller fallback. Two new exports — `isAnthropicProvider(modelString)` checks `provider:model` prefix OR `claude-` bare-id pattern, and `enforceSubagentAnthropic()` is the layer-2 runtime guard: when `tier === 'subagent'` resolves to a non-Anthropic provider, it emits a once-per-`(source, model)` stderr warn AND falls back to `TIER_DEFAULTS.subagent` instead of letting the Anthropic Messages API tool-loop attempt to run on OpenAI/Gemini. `_resetDeprecationWarningsForTest()` now also clears `_subagentTierWarningsEmitted` so tests re-emit. +- `src/core/ai/model-resolver.ts` — Recipe-touchpoint validator. **v0.31.12:** `assertTouchpoint(recipe, touchpoint, modelId, extendedModels?)` gains an optional 4th `extendedModels: ReadonlySet` argument. When the modelId is in that set, the native-recipe allowlist throw is bypassed — the user explicitly opted into this model via config so we let provider rejection surface as `model_not_found` at HTTP call time (and `gbrain models doctor` catches it earlier). Default code paths with hardcoded model strings MUST NOT pass `extendedModels` — typos in source code still fail fast. Replaces the earlier plan to soften the validator wholesale (Codex F4/F5 in plan review flagged that as too broad — it would have removed the fail-fast contract for chat + expand + embed all three). +- `src/core/ai/gateway.ts` extension (v0.31.12) — new module-scoped `_extendedModels: Map>` registry feeds `assertTouchpoint`'s 4th-arg path. New `reconfigureGatewayWithEngine(engine)` async function is called from `cli.ts` after `engine.connect()` (and before every command except `CLI_ONLY` no-DB commands) — re-resolves expansion + chat defaults through `resolveModel()` so `models.tier.*` and `models.default` overrides apply to expansion + chat both. `DEFAULT_CHAT_MODEL` corrected to `anthropic:claude-sonnet-4-6` (was the v0.31.6 phantom `-20250929`). New `__setChatTransportForTests` seam mirrors `__setEmbedTransportForTests` so tests drive `chat()` with a stubbed transport. +- `src/core/minions/queue.ts` extension (v0.31.12) — `MinionQueue.add()` now rejects `subagent` jobs whose `data.model` resolves through `isAnthropicProvider()` to a non-Anthropic provider. Lazy-imports `model-config.ts` to avoid pulling engine types into queue's eager-load surface. Layer 1 of the three-layer subagent provider enforcement (Codex F1+F2 in plan review). Layers 2 + 3 live in `src/core/model-config.ts` (`enforceSubagentAnthropic` runtime fallback) and `src/commands/doctor.ts` (`subagent_provider` check). Pinned by 3 cases in `test/agent-cli.test.ts`. +- `src/commands/models.ts` (v0.31.12) — `gbrain models [--json]` read-only routing dashboard: prints tier defaults (`utility`/`reasoning`/`deep`/`subagent`), the resolved value for each (re-walking the resolution chain to attribute properly), every per-task override (11 `PER_TASK_KEYS` entries — `models.dream.synthesize`, `models.dream.patterns`, `models.drift`, `models.auto_think`, `models.think`, `models.subagent`, `facts.extraction_model`, `models.eval.longmemeval`, `models.expansion`, `models.chat`, `models.dream.synthesize_verdict`), the alias map (defaults + user overrides), and a source-of-truth column showing `default` / `config: ` / `env: `. `gbrain models doctor [--skip=] [--json]` fires a 1-token `gateway.chat()` probe against each configured chat + expansion model and classifies failures into `{model_not_found, auth, rate_limit, network, unknown}` — the structural fix for the v0.31.6 silent-no-op bug class. Wired into `cli.ts` dispatch table + `CLI_ONLY` set. +- `src/commands/doctor.ts` extension (v0.31.12) — new `subagent_provider` check (layer 3 of 3 — Codex F13). Warns when `models.tier.subagent` is explicitly set to a non-Anthropic provider (fail-loud since the user clearly meant it — message names the bad value and prints the paste-ready fix command `gbrain config set models.tier.subagent anthropic:claude-sonnet-4-6`); also warns when `models.default` would sneak `subagent` into a non-Anthropic provider via tier inheritance. OK status when subagent tier resolves to Anthropic. Tests cover all three paths in `test/doctor.test.ts`. +- `src/core/check-resolvable.ts` — Resolver validation: reachability, MECE overlap, DRY checks, structured fix objects. v0.14.1: `CROSS_CUTTING_PATTERNS.conventions` is an array (notability gate accepts both `conventions/quality.md` and `_brain-filing-rules.md`). New `extractDelegationTargets()` parses `> **Convention:**`, `> **Filing rule:**`, and inline backtick references. DRY suppression is proximity-based via `DRY_PROXIMITY_LINES = 40`. +- `src/core/repo-root.ts` — Shared `findRepoRoot(startDir?)` (v0.16.4): walks up from `startDir` (default `process.cwd()`) looking for `skills/RESOLVER.md`. Zero-dependency module imported by both `doctor.ts` and `check-resolvable.ts`. Parameterized `startDir` makes tests hermetic. **v0.31.7:** read-path / write-path split. `autoDetectSkillsDir` (shared, read+write-safe) gains tier-0 `$GBRAIN_SKILLS_DIR` explicit operator override (Docker mounts, CI, monorepo subdirs) ahead of the existing 4-tier chain. New `autoDetectSkillsDirReadOnly` wraps it with a tier-5 install-path fallback that walks up from `fileURLToPath(import.meta.url)` and gates on `isGbrainRepoRoot` so unrelated repos can't false-positive. Read-path callers (`doctor`, `check-resolvable`, `routing-eval`) use the read-only variant; write-path callers (`skillpack install`, `skillify scaffold`, `post-install-advisory`) deliberately stay on the shared function so `gbrain skillpack install` from `~` cannot silently retarget the bundled gbrain repo's `skills/` instead of the user's actual workspace. Two new `SkillsDirSource` variants: `'env_explicit'`, `'install_path'`. New `AUTO_DETECT_HINT_READ_ONLY` documents the extra tier. The D6 `--fix` safety gate in `doctor.ts` + `check-resolvable.ts` refuses auto-repair when `detected.source === 'install_path'` so `gbrain doctor --fix` from `~` cannot silently rewrite the bundled install tree. +- `src/commands/check-resolvable.ts` — Standalone CLI wrapper (v0.16.4) over `checkResolvable()`. Exports `parseFlags`, `resolveSkillsDir`, `DEFERRED`, `runCheckResolvable`. Exit rule: **1 on any issue (warnings OR errors)**, stricter than doctor's `ok` flag — honors README:259. Stable JSON envelope `{ok, skillsDir, report, autoFix, deferred, error, message}` — same shape on success and error paths. `--fix` path runs `autoFixDryViolations` BEFORE `checkResolvable` (same ordering as doctor). `scripts/skillify-check.ts` subprocess-calls `gbrain check-resolvable --json` (cached per process) and fails loud on binary-missing — no silent false-pass. **v0.19:** AGENTS.md workspaces now resolve natively (see `src/core/resolver-filenames.ts`) — gbrain inspects the 107-skill OpenClaw deployment whether the routing file is `RESOLVER.md` or `AGENTS.md`. `DEFERRED[]` is empty — Checks 5 + 6 shipped as real code, not issue URLs. **v0.31.7:** the resolver lookup switched from first-match-wins to the multi-file merge in `src/core/check-resolvable.ts` — entries collected from every `RESOLVER.md` / `AGENTS.md` across the skills dir AND its parent, deduped by `skillPath` (first occurrence wins). Lifted reachable skills on the reference OpenClaw layout from 37/224 to 200/224 — the deployment ships a thin `skills/RESOLVER.md` (~40 entries from skillpack) plus a fat `../AGENTS.md` (200+ entries, the real dispatcher), and the previous code only saw the first one. The CLI also switched to `autoDetectSkillsDirReadOnly` so `cd ~ && gbrain check-resolvable` finds the bundled skills via the install-path fallback. `--fix` carries the same D6 safety gate as `gbrain doctor --fix`: refuses to write when `detected.source === 'install_path'`. +- `src/core/resolver-filenames.ts` (v0.19) — central list of accepted routing filenames (`RESOLVER.md`, `AGENTS.md`). Shared by `findRepoRoot`, `check-resolvable`, and skillpack install so every code path walks the same fallback chain. +- `src/commands/skillify.ts` + `src/core/skillify/{generator,templates}.ts` (v0.19) — `gbrain skillify scaffold ` creates all stubs for a new skill in one command: SKILL.md, script, tests, routing-eval.jsonl, resolver entry, filing-rules pointer. `gbrain skillify check