Open Second Brain
Memory server
First committed by hermes-vps-agent
Published in itechmeat/open-second-brain. Publisher page
550 GitHub stars
What it is
Second brain for AI agents using Obsidian-compatible Markdown vaults. Works with Hermes, Claude Code, Codex, and OpenClaw.
AutoGineer overview, from the brain’s own files
Open Second Brain acts as a memory provider for AI agents, enabling them to read and write persistent knowledge directly into an Obsidian-compatible Markdown vault. It employs a deterministic 'dream' pass to convert repeated signals into actionable rules, while maintaining a hash-chained log for auditability. The system supports various agent clients through MCP servers, lifecycle hooks, and a dedicated CLI, ensuring that agent-learned information remains accessible, versioned, and searchable as standard Markdown files.
How it works
Memory model: Hybrid
AutoGineer overview, from the brain’s own files
The system organizes data into a Brain folder containing Markdown files. Agents interact with this vault via MCP servers, lifecycle hooks, or the o2b CLI. Signals from agents are stored in an inbox, processed through a dream pass to generate preferences, and stored as rules in active.md. A search index is maintained in a hidden directory and can be rebuilt from the source files. The system also supports truth ledgers, decision models, and staged review gates for agent writes.
| Folder | Role | Files |
|---|---|---|
| .github | agent-config | 7 |
| bin | scripts | 1 |
| docs | docs | 774 |
| hooks | hooks | 35 |
| scripts | scripts | 22 |
| skills | agent-instructions | 6 |
| src | source-code | 1496 |
| templates | templates | 23 |
| tests | tests | 2101 |
| .agents | folder | 1 |
| .ai-notes | folder | 1 |
| .apb | folder | 87 |
| .claude-plugin | folder | 2 |
| .codex-plugin | folder | 1 |
| .githooks | folder | 2 |
| install | folder | 16 |
| openclaw | folder | 1 |
| openspec | folder | 33 |
| plugins | folder | 21 |
| schemas | folder | 5 |
The agent reads
- install/codex.md evidence: README.md
- search_iterative_recall_enabled evidence: README.md
- search_pool_max_per_session evidence: README.md
- docs/decision-models.md evidence: README.md
The agent writes
- package.json evidence: CLAUDE.md
- CHANGELOG.md evidence: CLAUDE.md
- docs/brain-store.md evidence: README.md
- docs/updating.md evidence: README.md
Requirements
Runtimes: Node.js, Python >=3.11, Bun
Databases: SQLite
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Google Antigravity, Kiro, OpenCode, Amp, Roo Code, Cline, JetBrains Junie, Devin (ex-Windsurf)
Set it up
This brain runs code automatically: 54 hooks (codex), 3 scripts. Review .githooks/pre-commit, .githooks/pre-push, hooks/hooks.json, package.json, plugins/codex/hooks/hooks.json before opening the folder in Claude Code. No step below turns a hook on for you.
.githooks/pre-commit:runs on git pre-commit.githooks/pre-push:runs on git pre-pushhooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" post-write-reminder; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook post-write-reminder; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" subagent-inject; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook subagent-inject; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" reground-deliver; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook reground-deliver; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" active-inject; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook active-inject; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" gap-agenda; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook gap-agenda; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" backlog-nudge; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook backlog-nudge; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" log-catchup; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook log-catchup; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" view-render; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook view-render; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" recall-inject; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook recall-inject; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" nav-inject; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook nav-inject; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" counterparty-brief; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook counterparty-brief; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" reground-deliver; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook reground-deliver; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" pretool-orient; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook pretool-orient; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" pretool-host-backup; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook pretool-host-backup; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" stop-log-guardrail; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook stop-log-guardrail; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" answer-quote-check; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook answer-quote-check; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" hygiene-digest; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook hygiene-digest; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" subagent-inject; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook subagent-inject; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" gap-promote; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook gap-promote; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" active-inject; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook active-inject; exit 0hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0package.json:bun scripts/prepare.ts || exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" post-write-reminder; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook post-write-reminder; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" subagent-inject; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook subagent-inject; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" reground-deliver; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook reground-deliver; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" active-inject; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook active-inject; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" gap-agenda; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook gap-agenda; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" backlog-nudge; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook backlog-nudge; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" log-catchup; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook log-catchup; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" view-render; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook view-render; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" recall-inject; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook recall-inject; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" nav-inject; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook nav-inject; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" counterparty-brief; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook counterparty-brief; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" reground-deliver; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook reground-deliver; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" pretool-orient; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook pretool-orient; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" pretool-host-backup; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook pretool-host-backup; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" stop-log-guardrail; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook stop-log-guardrail; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" answer-quote-check; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook answer-quote-check; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" hygiene-digest; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook hygiene-digest; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" subagent-inject; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook subagent-inject; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" gap-promote; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook gap-promote; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" active-inject; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook active-inject; exit 0plugins/codex/hooks/hooks.json:r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0
- Not scanned by AutoGineerThe author’s MCP configuration (.claude-plugin/plugin.json) also starts it in a way AutoGineer does not offer. Read that file: AutoGineer did not scan that path; what it runs is listed under “This brain runs”. https://github.com/itechmeat/open-second-brain/blob/233b91d1bdc7cf74c47ea1c1fd72e949887e1fc4/.claude-plugin/plugin.json
First committed by hermes-vps-agent. Published in itechmeat/open-second-brain. Licence: MIT License.
Usage
AutoGineer overview, from the brain’s own files
- Initialize a new vault for agent memory
- Connect agents like Claude Code or Codex via MCP
- Manage agent preferences and rules through automated dream passes
- Audit agent activity using hash-chained logs
- Perform semantic or keyword searches across agent-generated notes
- Enforce write-path integrity with staged review gates
- “o2b brain today”
- Displays the current day's view and active memory markers for the agent session.
- “o2b brain rollback”
- Restores the vault state from the last snapshot, reversing recent brain mutations.
Documentation by hermes-vps-agent
Open Second Brain
Image: Open Second Brain - your knowledge, amplified by AI
Open Second Brain is a memory layer for AI agents that lives in an Obsidian vault. Agents read and write it through MCP servers, lifecycle hooks and the o2b CLI. Everything the agent learns is a Markdown file under Brain/, so you can open, edit, grep and version it like any other note. A deterministic dream pass turns repeated signals into rules and retires the ones nothing uses; no model runs inside that algorithm.
How it fits
flowchart LR
subgraph Clients["Agent clients"]
Plug["Plugins: Claude Code, Codex,<br/>Hermes, opencode, Grok Build"]
Mcp["MCP config: Cursor, kiro, Copilot CLI,<br/>Gemini CLI, ZCode, any MCP host"]
Claw["OpenClaw<br/>in-process plugin"]
Cliu["Aider, Pi<br/>CLI and context file"]
end
subgraph Product["Open Second Brain"]
Srv["MCP servers<br/>open-second-brain, open-second-brain-writer"]
Hooks["Lifecycle hooks<br/>o2b-hook"]
Cli["CLI<br/>o2b"]
Core["Core"]
end
subgraph Vault["Your vault"]
Brain["Brain/<br/>Markdown the agent writes"]
Notes["Your notes"]
Index[(".open-second-brain/brain.sqlite<br/>rebuildable search index")]
end
Plug --> Srv
Plug --> Hooks
Mcp --> Srv
Claw --> Core
Cliu --> Cli
Srv --> Core
Hooks --> Core
Cli --> Core
Core --> Brain
Core --> Index
Core -. reads, writes a named note on request .-> NotesEach client reaches the same core through a plugin, an MCP registration or the CLI. The core keeps its own records under Brain/ and a generated search index under .open-second-brain/ that it can rebuild from the files. Your notes are read; the note tools write one only at a path the caller names.
flowchart LR
Agent["Agent"] -->|brain_feedback| Inbox["Brain/inbox/<br/>signal"]
Inbox -->|dream pass| Pref["Brain/preferences/<br/>rule"]
Pref -->|rendered into| Active["Brain/active.md"]
Active -->|read at session start| Agent
Agent -->|brain_apply_evidence| Log["Brain/log/"]
Log -->|next dream pass| PrefThe learning loop: signals become rules, rules reach the next session through Brain/active.md, and applied or violated evidence confirms, quarantines or retires them. Details: docs/how-it-works.md.
Install
Install Bun 1.1 or later:
install/prerequisites.md.Install the plugin for your client (guides below), or get the
o2bCLI:install/prerequisites.md.Create the vault files:
o2b init --vault /path/to/vault --name "My Second Brain" o2b brain init --vault /path/to/vaultConnect the client (table below), then check the result:
o2b doctor --vault /path/to/vault o2b install --check
The full router with readiness criteria is install.md; native Windows is covered in install/windows.md.
Supported clients
| Client | Integration | Guide |
|---|---|---|
| Claude Code | Marketplace plugin: MCP servers and hooks | install/claudecode.md |
| OpenAI Codex | Marketplace plugin, then o2b install --target codex --apply | install/codex.md |
| ChatGPT desktop | Reads the shared Codex config: o2b install --target codex --apply | install/codex.md |
| Hermes Agent | Plugin and memory provider | install/hermes.md |
| OpenClaw | Native plugin, no MCP | install/openclaw.md |
| opencode | o2b install --target opencode --apply: MCP servers and a native plugin | install/opencode.md |
| Grok Build | o2b install --target grok --apply: MCP servers and hooks | install/grok.md |
| Cursor | o2b install --target cursor --apply | install/cursor.md |
| kiro | o2b install --target kiro --apply | install/kiro.md |
| GitHub Copilot CLI | o2b install --target copilot-cli --apply | install/copilot-cli.md |
| Gemini CLI | o2b install --target gemini-cli --apply | install/gemini-cli.md |
| ZCode | MCP servers added to its config by hand | install/zcode.md |
| Aider | o2b install --target aider --apply: context file, no MCP | install/aider.md |
| Pi | o2b install --target pi --apply: skill over the CLI | install/pi.md |
| Any other MCP host | o2b install --target generic --apply --out - prints the server entries | install/generic.md |
o2b uninstall --target <name> --apply removes what o2b install wrote; the vault is never touched (install.md).
Capabilities
Preferences that learn and expire. Signals, a deterministic dream pass, confidence and retirement: how it works.
Reversible changes. Brain mutations take a snapshot first;
o2b brain rollbackrestores it: snapshots.Attributed writes.
o2b brain writeslists every note write by agent and device,writes revertplans a restore,o2b brain freezestops all writers, ando2b brain log verifychecks the hash-chained log: Brain CLI.Search. Keyword search with an optional semantic lane, result explanations, recall profiles and compact cards; an opt-in iterative loop (
search_iterative_recall_enabled, default off) keeps querying when coverage gaps survive, pausing with a plan the caller answers throughbrain_search's round trip; and an opt-in per-source-session cap (search_pool_max_per_session, default off) keeps one long imported session from filling the candidate window, so diversity spreads across sessions: search CLI, iterative recall, pool cap, ranking.Session recall. Import agent transcripts already on disk, search them, or select whole-thread coverage under a character budget (
o2b brain session-grep --operation coverage --char-budget <n>, with--entity-keyseeding the fan-out from mined entity mentions): session logs, coverage.Hygiene.
o2b brain hygiene scanfinds contested, duplicate, stale and unused memories;applyruns only the findings you pick: maintenance.Claim ledger.
o2b brain truth ingestrecords an entity claim with an optional validity window (--valid-from/--valid-until; with the flags absent, a window on the source record's frontmatter is adopted and frozen at ingest),truth eventsrecalls a windowed slice of the ledger, andtruth stategrounds an agent-stated claim with an anchoring verdict - committed, or reported back with reason codes.truth stateaccepts an optional opaque--sample-idnaming the context-pack sample the claim drew on, and claim reads report the receipt and outcome provenance behind it at the caller's reach - "receipt known, outcome unknown", never an invented verdict: entity truth CLI.Corrections.
o2b brain lifecycle correct <target>reports a correction's blast radius and retires the affected records - validity-closed by default, tombstoned with--flatly-wrong, dry run by default and--applyto write. A retired record that recall can still serve is served only beside its correction, never alone: belief lifecycle CLI.Sharing and backup. Knowledge packs export a chosen subset;
o2b brain bank-exportwrites a one-file backup bundle: knowledge packs.Secret custody. Credentials live encrypted in the vault's state dir behind a capability-gated store;
$secret:NAMEreferences resolve at the use sites,o2b brain secret unlockwraps the keyfile under a passphrase, andsecret export/importmove the store between installs as one passphrase-encrypted bundle: custody CLI.Today view and note markers.
o2b brain today,@osb loopand@osb setmarkers: Brain CLI.Self-inspection.
o2b version,o2b install --frictionando2b state statusreport what is installed and where state lives: CLI reference.MCP surface. Tools, tool profiles for hosts with tool limits, and the always-loaded writer server:
docs/mcp.md.
Optional features
Semantic search: an embedding provider plus
sqlite-vec; theembeddings-setupskill walks through it:skills/embeddings-setup/SKILL.md.Decision models: a typed judgment model that can rerank search and filter candidates, off by default per use:
docs/decision-models.md.Deep relational recall: a fourth search arm over typed links, off by default. Its traversal runs under width budgets - 8 seeds, 4 edges per node, 16 nodes in total, and a hub above 12 walked edges is reached but not expanded - each overridable through an
OPEN_SECOND_BRAIN_SEARCH_TRAVERSAL_*environment variable or asearch_traversal_*config key; entity co-occurrence bridges join the walk by default and switch off separately (OPEN_SECOND_BRAIN_SEARCH_ENTITY_BRIDGES): retrieval quality.Staged review for agent writes, off by default. With no key set every write publishes exactly as before.
write_approval.notes/OPEN_SECOND_BRAIN_WRITE_APPROVAL_NOTES_ENABLEDandwrite_approval.ingest/OPEN_SECOND_BRAIN_WRITE_APPROVAL_INGEST_ENABLED(each falling back to thewrite_approval.enabledmaster, default off) stage note creates and ingest summary pages intoBrain/pending/beside the staged signals, where they stay out of the search index until an operator runso2b brain pending listand applies or rejects them; write-path integrity.A permissions document, absent by default.
Brain/_permissions.yaml(an operator-edited vault file) resolvesallow/ask/denyper agent, role and target for the write, ingest and owner-write actions; with the file absent every check behaves exactly as today.askstages the write,denyrefuses with thewrite-refusedtoken and the next commando2b brain permissions show, and every ask/deny verdict lands in a queryable decision ledger underBrain/logs/decisions/;o2b brain permissions showdry-runs the decision table,ledgerreads the rows; Brain CLI.The owner-write gate, off by default.
integrity.owner_scope_writesinBrain/_brain.yaml(off|warn|fail, defaultoff) refuses a caller-named owner that differs from the caller's resolved identity on the preference and note lanes (warnallows and records one decision-ledger row); a documentowner_writeverdict composes most-restrictive-wins with the gate; write-time integrity.Named MCP tokens, optional.
o2b mcp token mint|rotate|revoke|listkeeps a hash-at-rest token per agent (.open-second-brain/secrets/mcp-tokens.json; material shown exactly once). Over HTTP a valid token authenticates as its agent per request, the shared--api-keystays valid as the operator master credential, andmcp_tokens_required/OPEN_SECOND_BRAIN_MCP_TOKENS_REQUIRED(defaultfalse) makes a non-empty token map refuse credential-less requests.o2b bootstrap --target <harness> [--token] [--rotate] [--check]provisions MCP registration, token and receipt in one idempotent command, ando2b bootstrap --remove <harness>tears a provision down again; the minted token authenticates HTTP clients configured by hand, while the registered stdio harness presents no credential and keeps its config-derived identity; core CLI.Ambient capture consent, opt-out.
guardrails.ambient_writeback: falsesuppresses the ambient extraction lane with a countedambient-withheldevent (absent keeps today's behavior), andguardrails.ambient_ttl_daysstamps anexpiration_dateon ambient-extracted signals so reads drop them after the window (absent stamps nothing); a TTL-stamped signal still stages when the review gate is on and survives apply verbatim.Open decisions.
o2b brain decision open --title <t> --question <q> --option <o> [...]parks a question with enumerated options atBrain/decisions/open-<slug>.md;resolvemints the realtype: decisionpage,discardcloses without deciding, and the morning brief renders up to five open questions: belief lifecycle.
What is new
Open Second Brain 1.98.0 is the agent-presence and self-improvement release. o2b install --target <host> --apply now writes the brain-usage block into the agent-instruction file the installed host reads at the vault root (AGENTS.md for codex, cursor, opencode and aider; GEMINI.md for gemini-cli) under the same consent prompt as the config writes, preserving every byte outside the block and recording its ownership so uninstall removes exactly the pair the tool wrote; the dream pass gains an operator-approved exit into those same files, where a lesson promotes into a managed lessons block only with a fresh approval pinned to the approved text, and the doctor grades every block state it can name. The skill lane gains a benchmark-gated rewrite loop: a skill is rewritten only after a candidate beats the incumbent on scored dev tasks with full coverage and survives the one held-out check - Open Second Brain never calls a model, the scorer reads structural predicates and nothing the agent claims about its own work, and the accept stays an operator step on the command line. And ChatGPT desktop is named where its operators look for it: it reads the shared Codex config, so one codex registration serves both. Every release is described in the CHANGELOG.
Documentation
| Topic | Page |
|---|---|
| Mental model, vault layout, dream pass, safety properties | docs/how-it-works.md |
| Every CLI verb and flag | docs/cli-reference.md |
| MCP protocol, tools, writer split | docs/mcp.md |
| Brain store: setup, sync, migration, the human view | docs/brain-store.md |
| Architecture and configuration model | docs/architecture.md |
Updating (o2b update) and upgrade notes | docs/updating.md |
| Observability events | docs/observability.md |
| Metrics data contract | docs/metrics.md |
| Cross-project pointer | docs/cross-project-pointer.md |
| Scheduled Brain digest (Hermes cron) | docs/hermes-cron.md |
| Stability policy | docs/stability.md |
| Origin of the idea | docs/idea.md |
Project
CHANGELOG · Security policy · Source on GitHub · MIT License
docs/observability.md
Observability contract
Open Second Brain records what it did - learning events, recall decisions, served context, session activity - across a small set of file-based surfaces inside the vault. This document is the contract for anyone consuming those surfaces: which events exist, when they fire, what correlates them, what safety guarantees their payloads carry, and how the record shapes evolve. Everything here is verified against the source files named in each section.
Surfaces at a glance
| Surface | Location | Writer | Format |
|---|---|---|---|
| Brain log | Brain/log/<date>[.<device-id>].md + JSONL sidecar | appendLogEvent() in src/core/brain/log.ts | Markdown line + JSONL row per event |
| Continuity store | Brain/log/continuity/<month>[.<device-id>].jsonl | appendContinuityRecord() in src/core/brain/continuity/store.ts | one JSON record per line |
| Idempotency ledger | Brain/logs/idempotency/<month>[.<device-id>].jsonl | rememberKey() in src/core/brain/idempotency-ledger.ts | one key -> content hash record per line |
| Decision ledger | Brain/logs/decisions/<month>[.<device-id>].jsonl | appendDecisionLedger() in src/core/brain/permissions/ledger.ts; read back by o2b brain permissions ledger | one JSON decision row per line (see "The decision ledger" below) |
| Preference mutation audit | Brain/log/pref-audit/<pref-id>/device[.<device-id>].jsonl (legacy flat Brain/log/pref-audit/<pref-id>[.<device-id>].jsonl still read) | appendPrefAudit() in src/core/brain/pref-audit.ts | one JSON record per line |
| Session lineage ledger | Brain/.state/session-lineage[.<device-id>].jsonl (+ session-lineage-gaps[.<device-id>].jsonl) | recordLineageObservation() in src/core/brain/lineage/ledger.ts | one JSON record per line, sequence-numbered and hash-chained per file |
| Session lifecycle audit | Brain/log/session-lifecycle/<ISO-week>[.<device-id>].jsonl | captureSessionLifecycleEvent() in src/core/brain/session-lifecycle.ts | JSONL audit rows |
| Other audit weeks | <ISO-week>[.<device-id>].jsonl under Brain/log/hygiene/, Brain/log/secret-custody/, Brain/log/schema-mutations/, Brain/log/watchdog/ (fallback .open-second-brain/watchdog-audit/) and .open-second-brain/hook-audit/ | appendAuditRecord() in src/core/reliability/audit.ts, the one writer every audit site calls | JSONL audit rows |
| Fixed-name ledgers | Brain/log/query-demand, Brain/log/recurrence-support, Brain/log/capture-decisions, Brain/skill-proposals/verifier-rejections, Brain/preferences/pref-<slug>.history, Brain/projects/git/<repo>/commits and .open-second-brain/maintenance-runs, each <stem>[.<device-id>].jsonl | the owning module's path helper through shardedFileName() in src/core/brain/ledger-shards.ts | one JSON record per line |
| Bench runs | <runs-dir>/<run-id>/ (default .open-second-brain/bench-runs/; excluded from git by the guard block o2b brain init seeds into the vault .gitignore) | runMemoryBench() in src/core/bench/phases.ts | checkpoint.json, per-question results, report.json |
| Failed automatic upgrade | .open-second-brain/self-heal-upgrade.json (per device, not synced with Brain/) | recordSelfHealUpgradeFailure() in src/core/maintenance/self-heal-upgrade-state.ts | one JSON object: failed_at, error, consecutive_failures, pending, retry_after; read by o2b doctor (self_heal_upgrade), o2b brain status and o2b brain upgrade --dry-run |
| Metrics | Brain/metrics/<surface>[.<device-id>].jsonl | appendMetric() in src/core/brain/metrics.ts | one run-level JSON record per line (see docs/metrics.md) |
| Signal archive | Brain/inbox/archived/sig-*.md | the dream pass (archiveStaleSignals() in src/core/brain/dream-apply.ts, policy in src/core/brain/signal-archive.ts) | the inbox signal file, moved byte for byte; the moving run's dream log event lists every id under archived_signals |
| Dedup index cache | $OPEN_SECOND_BRAIN_DEDUP_CACHE_DIR, else the user cache dir open-second-brain/dedup-index/<vault-digest>.json (outside the vault; OPEN_SECOND_BRAIN_DEDUP_CACHE=0 disables) | writeDedupIndexCache() in src/core/brain/dedup-index-cache.ts | one JSON file per vault: per directory its listing digest, count and mtime, per signal file its size, mtime, id and dedup_hash; derived, safe to delete |
The per-device shard rule
Every append-only ledger above is one file per period (or per key, or per surface) PER DEVICE. The vault is replicated with Syncthing, and two machines appending to one file inside a single sync window produce a .sync-conflict-* copy that no reader merges — so the rows split silently across two files. The shard suffix removes the contention instead of resolving it after the fact: a device only ever appends to the file its own id names.
The grammar is <base>[.<device-id>].<ext>, and it lives in exactly one place, src/core/brain/ledger-shards.ts. The device id is the lowercase slug resolveDeviceId() produces (src/core/config.ts), which is device-local config and never synced. A file with no device suffix is the shard with the EMPTY id: legacy history stays readable, no migration renames anything, and a vault whose device id resolves empty (O2B_DEVICE_ID="", or a config that cannot be read) keeps writing exactly the bytes it always did.
Every reader merges every shard it finds, in the one order all devices agree on: the ledger's own sort key, then the shard id, then position within the shard. The shard id is the tie-break rather than the arrival order because arrival order is precisely what differs between two Syncthing peers — so two machines reading the same set of shards return the same sequence. The continuity store adds its content-hash record id as a last resort after the shard id, which is what keeps a single-shard vault reading back in exactly the order it did before sharding existed.
Two names are never shards. A *.sync-conflict-* copy is excluded from every listing even when its middle segment fits the shard-id shape (the sync-conflict prefix is reserved in the device-id validator for the same reason), and o2b brain doctor reports any leftover copy under any ledger directory as sync-conflict-log, naming the directory so the union+dedup merge has an address. A name whose base does not match the ledger's own layout is not that ledger's file at all — bases go into the grammar as patterns, or as escaped literals where the base is a value (a preference id may legitimately contain a dot).
The audit weeks and the fixed-name ledgers adopted the grammar in 1.63.0. Their readers merge every shard: the maintenance journal, the git commit store and the recurrence-support ledger interleave shards by each row's own time without ever reordering the rows of one shard (so a single-shard vault reads exactly as before, and the order-sensitive recurrence fold never replays one device's purge before another device's earlier event), the git store keeps one copy of each commit and tag, the query-demand read keeps its timestamp order, the preference edit history reads shards in shard-id order, and the schema-pack digest picks the newest record across every week shard. The capture-decision and verifier-rejection ledgers have no reader; only their writers changed. A rewrite touches only the shard this device writes: query-demand compaction caps that shard, and the maintenance-journal cap sweep rewrites only the local shard, so the journal cap applies per device. o2b state status reports a sharded fixed-name ledger present when its legacy file or any shard exists, and the doctor's sync-conflict-log sweep covers the directories of these two rows except the maintenance journal's .open-second-brain/ root. Where a swept directory also holds whole files (Brain/skill-proposals/, Brain/preferences/, a git repository's state.json), a conflict copy without the .jsonl extension is not a split shard: it keeps the sync-conflict-log code with a hand-resolve remedy instead of the merge instruction. A source-layout test fails when a new append-mode writer uses neither the shard helpers nor a named allow-list entry.
The session lineage ledger is the one with an extra invariant: its sequence numbers and hash chain are per FILE, so a per-device shard is a per-device chain, compaction is per shard, and verifyLineageLedger verifies each shard separately and reports each finding under that shard's own path. A break in one machine's ledger says nothing about another's.
The prompt_prefix metric surface measures STRUCTURAL prompt-prefix stability (whether the kernel handed the agent a byte-stable, cache-eligible preamble across a generation pass), never a provider's cache-hit rate the kernel cannot observe. It stores only the SHA-256 hash and length of the prefix, never the raw prompt - the same payload-safety rule as generation_report. See docs/metrics.md.
Brain log events
appendLogEvent() writes one human-readable line to the daily Markdown log plus a structured JSONL sidecar row. These events are always-on: each one is the audit trail of the operation that produced it, never optional telemetry. Kinds (from BRAIN_LOG_EVENT_KIND in src/core/brain/types.ts):
| Kind | Fires when |
|---|---|
dream, promote, retire, noted-redundant, signal-suppressed, skip-corrupted-frontmatter, reconcile | the deterministic learning pass runs. The dream event lists signals moved to inbox/processed/ under moved_to_processed and signals moved to inbox/archived/ (older than dream.contradiction_window_days, never consumed) under archived_signals |
feedback, apply-evidence, force-confirmed, reject | a taste signal or evidence event is recorded |
pin, unpin, rollback, merge, upgrade | operator-facing vault maintenance |
freeze, unfreeze | an operator stopped or reopened the content lane for every device that syncs the vault (o2b brain freeze / o2b brain unfreeze). One event per real transition only - a second freeze, or an unfreeze on an open vault, writes nothing. freeze carries the reason and the device_id it was set from; unfreeze carries the frozen_at, by and reason read off the marker before it was removed, which is the only place they survive the file |
write-refused | a write was refused because the vault is frozen. Appended at the MCP tool boundary - the guard that refuses sits below the log module and cannot append without closing an import cycle - one per refused call, carrying the tool, the agent and the marker's reason. The Brain log itself keeps writing while frozen (the audit write lane, WRITE_LANE.audit in src/core/brain/freeze-marker.ts), because a freeze that silenced the log would erase the record of itself |
scan-inline, import-session, import-claude-memory | capture and import operations |
note | a narrative milestone is recorded (brain_note); since v1.81.0 also the answer-quote-check Stop hook's enforce trail - exactly one event per turn that found unverified quoted spans, carrying hook: answer-quote-check, the phases that ran, the checked and unverified counts, and the findings as capped one-line previews |
note-write | a vault note is created, updated, appended to, or reverted |
session-lifecycle | a captured lifecycle event also produced Brain writes |
decision-open | a question was parked with enumerated options at Brain/decisions/open-<slug>.md, ahead of the decision it may become. Payload carries the open wikilink, the title, the option count and the agent. Distinct from decision-record because nothing has been decided yet |
decision-resolved | an open decision was closed by choosing one of its options, minting a real type: decision page. Payload carries the open wikilink, the minted decision wikilink, the choice and the agent. The minted page itself carries the usual decision-record event; this event records the transition |
decision-discarded | an open decision was closed WITHOUT a decision. Payload carries the open wikilink, the reason and the agent. Separated from decision-resolved so "never decided" is machine-filterable against "decided as X" |
ambient-withheld | an ambient extraction capture was suppressed by operator consent (guardrails.ambient_writeback: false). One event per suppressed capture, carrying the count of signals the capture would have written - never their content. Keys absent log nothing, because the lane ran as today |
lessons-approved, lessons-denied, lessons-promoted (agent-presence, t_1e952e43) | the operator records a lesson-promotion decision or a managed block receives lesson content. Operator CLI only - o2b brain lessons approve / deny / refresh-blocks; no agent-facing surface can mint these events, so the audit trail of what entered an agent rules file is operator-authored by construction. lessons-approved carries the pref wikilink, the targets, the pinned approved_content_hash and the consent verdict; lessons-denied carries the pref and the verdict; lessons-promoted carries the targets that changed and the prefs delivered, one event per write that landed (a no-op refresh emits nothing). The doctor grades managed blocks in the four-state vocabulary absent | current | drifted | stale-lessons (registered in the verdict-vocabulary census), where stale-lessons is an approval whose pinned hash no longer matches the live text; the counts ride the brain status snapshot (lessons.approved/denied/stale) without a new surface |
Note writes
Every note mutation funnels through two seams - createNote and the write-batch kernel - and each one appends exactly ONE note-write event. The payload is all strings, because the log payload contract admits string | string[] and nothing else:
| Field | What it holds |
|---|---|
write_id | nw_<14 timestamp digits>_<16 hex>, derived from the event body, so two devices that record the same write agree on its id |
op | create, update, append, or revert (NOTE_WRITE_OP) |
target | vault-relative POSIX path of the note |
hash_before | sha-256 of the bytes replaced, or the literal absent when the target did not exist - deliberately not the sha-256 of zero bytes, which an empty FILE would also produce |
hash_after | sha-256 of the bytes now on disk, or the same literal absent when the write left no file - which only a revert that removes a note the selected writes created produces, paired with bytes_after: 0 |
bytes_before / bytes_after | byte sizes, rendered as decimal strings |
agent | resolveAgentName() against the config the writing surface runs under; caller-asserted by construction, as src/core/write-binding/index.ts states |
The device is NOT a payload field: it rides on the log shard name exactly as it does for every other event, and origin_channel is stamped by the appender. listNoteWrites (src/core/brain/notes/write-log.ts) reads the record back and reports the shard as the device, the empty string being the legacy un-sharded log rather than an unknown machine. o2b brain writes and the brain_writes MCP tool are the two surfaces over it, and brain_agent_query --kind note answers "which notes did this agent touch" off the same events.
Order, and the gap the receipt names. The bytes are written FIRST and the event appended second, so a log failure never fails a write that has already landed - the snapshot-event precedent, with the silence removed. recordNoteWrite never throws: it returns write_id: null with an audit_reason, and every note-write result and MCP receipt carries both. A write that authored no bytes - a skipped create (if_exists: "skip") or a byte-identical rewrite - records nothing and carries no write_id at all; the receipt reports the skip through the op's own flag (updated: false / appended: false).
Before-image store. The bytes an update or append replaced are kept at Brain/.state/write-images/<sha256>, stored BEFORE the atomic write so a crash or a failed store never leaves the prior bytes replaced without their copy - a byte-identical rewrite is decided first and stores no image, because the prior bytes stay on disk and an image would claim a replace that never happened - and skipped when an image of that content already exists - so a note toggled between two states costs two files, not two per write. The store is a STATE_SURFACES row inside the snapshot region; o2b brain writes prune-images [--older-than-days N] [--dry-run] bounds it by file age, default 30 days (WRITE_IMAGE_RETENTION_DAYS). An image is a copy of note content the snapshot region already archives, so removing one loses no content - it only narrows how far back a revert can reach, which a revert plan reports by name.
Revert. o2b brain writes revert (--agent A | --device D | --path P) [--since --until] reads the same events back and plans what undoing them would do; brain_writes action plan_revert returns the same plan and never applies it. A selector naming none of agent, device or path is refused by name (unbounded_selector): a time window alone selects every write by every agent on every machine, which is a vault rollback and has its own verb. Per target, over the selected writes S (oldest..newest) and every recorded write A on that target:
| Verdict | When |
|---|---|
refuse / unrecorded | the current bytes cannot be read at all, so no drift verdict is possible |
refuse / drift | sha-256 of the bytes on disk is not the hash_after of the newest write in S - including the target being gone when it should be there |
refuse / interleaved | a write in A \ S sits between the oldest and newest write in S in the merged total order - (timestamp, shard id, line), the order readLogDay already yields. Timestamps are second-precision, so "between" is a position and not a clock comparison: line order inside one shard IS append order, and three writes in one second on one device are perfectly ordered. The one tie that is not evidence is a same-second tie ACROSS shards, where the merge falls back to the shard id - a name, not a clock - and two devices could have written in either order. So a non-selected write sharing a second with a selected write is trusted only when it shares that write's shard; a cross-shard tie is interleaved on doubt |
refuse / already-reverted | the target already holds exactly what the revert would produce |
refuse / image-missing | a restore's before-image is not in the store, or no longer hashes to its own name |
delete | the oldest write in S has hash_before: absent AND no write in A precedes it - the selection brought the note into existence |
restore | otherwise: put back the before-image of the oldest write in S |
A refused target is reported, never skipped, and the plan's digest - sha256(canonical JSON of { selector, entries }), deliberately NOT covering planned_at - covers refusals too, so an operator who applies a digest applies the plan they read. --apply <digest> re-plans from scratch and refuses digest_mismatch before any byte moves when the vault changed in between; a plan with no actionable entry is refused nothing_to_apply; a frozen vault refuses the whole apply by name before anything is read. Everything that does run goes inside ONE withDestructiveSnapshot under the note-revert reason, so a revert that half-succeeds still has one recovery point covering the state before all of it. Each restored or deleted target keeps a before-image of the bytes it replaced and is recorded through recordNoteWrite with op: revert - a delete as hash_after: absent, bytes_after: 0 - which is what makes a revert attributable and itself revertible: reverting the reverting agent puts the bytes back.
The log chain
Once the log is the attribution record for every write, a line someone deleted or edited has to be detectable. Every JSONL row appended from v1.55.0 on carries two extra keys after payload:
h—sha256(canonical JSON of { prev, ts, kind, payload }), this row's chain hash;prev— thehof the previous chained line in the same shard, ornullat that shard's genesis.
prev is inside the hash rather than beside it, which is what makes the structure a chain: editing any earlier line changes every later hash, so a tampered history cannot be re-linked without rewriting the whole shard from the edit forward. The appender computes the link from the shard text it already holds under the directory lock, which is also what makes the link correct — two appenders reading the same head would otherwise write two lines claiming the same predecessor.
One chain per shard. Two machines append to two files that Syncthing delivers in whatever order it likes, so there is no total order to chain across; the chain's unit is one file and a break in one device's shard says nothing about another's. The markdown twin is a derived rendering and is NOT chained — a human-editable view is the wrong thing to hold to a hash, and the JSONL sidecar is the machine-primary surface every reader already prefers.
Report-only. readLogDay reads ts, kind and payload and nothing else, so a broken shard still yields every event it holds. A log that refused to be read because someone edited it would be a worse outcome than the edit. What the chain buys is that the edit has a name, a file and a line number.
o2b brain log verify [--json] walks every shard and reports the first break in each, by path and line: hash-mismatch (the line was edited after it was written), prev-mismatch (a line between it and its predecessor was removed or reordered), malformed (the line carries no usable chain link where the chain had already started). It exits 1 when any shard does not link up. o2b brain doctor emits one log-chain-broken warning per broken shard with the same next command. Neither repairs anything: the only way to make a broken chain verify is to rewrite the history it records, which is the act the chain exists to detect.
Rows written before the chain shipped carry no h. They are counted as legacy and are clean while they precede the chain — the first chained line after them anchors the shard with prev: null. The same shape after a chained line is not history but a line whose links were stripped, and it is reported. The head of a shard is not exempt either: the Brain log never compacts, so a first chained line naming a predecessor means the head of the file was cut off. Sync-conflict copies are excluded from verification — they are the doctor's separate sync-conflict-log finding, and their chain never held by construction.
The decision ledger
The Brain log, the pref-audit, the idempotency ledger and the continuity store each record what happened; none of them answers "which rule allowed, asked or denied this write". The decision ledger (Brain/logs/decisions/, write-side-trust wave) is the queryable record of that answer: one JSONL row per gate disposition that was not a plain publish, written by the gate that produced the verdict. appendDecisionLedger() (src/core/brain/permissions/ledger.ts) appends to the month/device shards on the shared shard grammar - the per-device rule and the merged (timestamp, shard id, line) read order are exactly the ones "The per-device shard rule" above states.
The row shape is closed: ts, actor (the resolved principal), via (token, config or operator - where the identity came from), action (write, ingest or owner_write), target, verdict (the disposition - allow, ask, deny, a gate mode such as warn, or a refusal token), source (the deciding rule: an entry id, an agent or role name, default, or a gate key such as integrity.owner_scope_writes), reason (the named token), and the optional tool and correlation_id that join a row to the other trails the way event-trace.ts joins log events.
When rows land is deliberately quiet:
| Trigger | Rows |
|---|---|
| No permissions document, every gate key off | none - default-silent like every ledger |
A permissions document resolves ask or deny for a staged-lane write | one row naming the entry, role or default that decided |
A permissions document resolves allow | one row ONLY when the document sets ledger.record_allows: true |
integrity.owner_scope_writes: warn allows a caller-named foreign owner on the preference lane | one row carrying the gate key as source |
The append contract is absolute: a failed append NEVER throws and never blocks the verdict it records. The ledger rides behind gates that must refuse or stage a write even when accountability cannot be written, so every failure - an unwritable directory, a lock another writer holds - comes back as { logged: false, audit_reason } that the caller surfaces; the receipt carries the reason rather than claiming a record that does not exist.
o2b brain permissions ledger --actor <name> --action <a> --verdict <v> --since <iso> --until <iso> --limit <n> reads the merged rows back (--json for the raw rows); every filter is optional and applied after the deterministic sort, so two devices listing the same shards agree on the order. The ledger is append-only and has no prune verb: retention follows the same open question as every sharded ledger in the vault.
Continuity record kinds
Every continuity record shares one envelope, and exactly these eight fields in this order: schema, id, kind, createdAt, sourceRefs, payload, private, redacted. The table marks how each kind is gated - this is the always-on vs opt-in matrix, verified against the call sites named in the right column.
| Kind | Gate | Emitted by |
|---|---|---|
recall_telemetry | opt-in per call (telemetry option/param); the prompt-time hook emitter is gated by recall_inject_enabled instead | packContext (mode: context_pack), buildPreCompressPack (mode: pre_compress), brain_search MCP handler (mode: search), brain_query MCP handler (mode: query, since v0.40.0 - payload carries the query kind only, never the supplied preference id / topic / timestamp), and since v1.46.0 the UserPromptSubmit recall-inject hook (mode: search, channel: hook, mapping its inject / abstain / error decision onto ok / empty / error; with the optional recall_inject decision-model use in shadow or enforce, metadata gains a decision_model object - mode, outcome (ok, not_sent or degraded), latency_ms, notes_dropped, abstained - and the abstain reason decision_model_abstain, never prompt or note text; see docs/decision-models/recall-inject.md) |
context_receipt | opt-in per call (receipt option/param) | packContext, buildPreCompressPack |
gate_telemetry | config key recall_gate_telemetry (default off) | brain_recall_gate MCP handler; a call carrying decision_answerable while that decision-model use is on adds adequacy_level and decision_answerable (probability, disagrees); since v1.69.0 a call carrying turn_id records it under turn_id, which the read-model lifts like every other turn id; since v1.82.0 a call that carried a measured quality also records the graded surfacing key - key (null exactly where nothing was measurable), tier and the channel the decision arrived over - and the summary counts the measured records by tier (by_tier) |
negative_recall | config key recall_gate_telemetry (default off - the SAME gate as gate_telemetry above, so one config decision governs both observations the recall gate makes) | brain_recall_gate MCP handler on the zero-usable-result path only (emitNegativeRecallTelemetry in src/core/brain/gate-telemetry.ts) - one record per gate call whose caller reported no usable result, carrying the typed corpus verdict (state, complete, the named unknown_reason when the verdict is unknown, reason) plus the reduced coverage receipt when one could be built (coverage_digest, documents, chunks, schema_version, embedding_signature, last_indexed_at, scope, unindexed_roots). Two receipt fields are not copied into the payload: index_path is deliberately dropped - a host filesystem path is not vault content and these records sync between devices, and the digest already binds it; the embeddings census the receipt carries is likewise absent from the payload and likewise bound by coverage_digest, so a reader comparing two records still sees a keyword-only index differ from a fully embedded one. Same prompt invariant as gate_telemetry: a SHA-256 prefix (prompt_hash) and the length (prompt_chars), never the prompt. A call with usable results writes NO record, so a corpus statement is never invented for an attempt that had one |
generation_report | opt-in per call (enable) or config key generation_trace_enabled (default off) | inbound agent report after a generation handoff (brain_generation_reports action record, o2b brain generation-reports record) |
mcp_route_latency | config key mcp_route_metrics_enabled (default off) | the MCP server's tool-call seam (MCPServer.invokeToolHandler in src/mcp/server.ts) - one record per tools/call and per CLI-bridge callTool; payload carries the tool name, scope, status, duration, and argument KEY NAMES only, never argument values, plus the optional decision_ms and allowlisted stages timings |
decision_model_call | the optional decision model is active (decision_model_enabled: "true" AND the named key variable set, which a self-hosted laya or openjev server on loopback does not need, and no vault opt-out); an install without the feature writes none | runDecision in src/core/decision-model/run.ts - one record per attempted decision request: use, mode, provider, model (the answering version), calibrated, question_count, candidate_count, input_tokens, output_tokens, cost_usd, cost_source (reported, estimated or unknown), latency_ms, outcome (ok or a degrade reason), state_hash (sha-256 of the redacted state), origin (eval or ping) when not an ordinary use call, plus per-use identifiers (a rerank adds head_size, withheld_count, budget_dropped_count, frontmatter_only_count when a frontmatter-only chunk was not sent, injection_suspected in enforce, answerable_probability, and in shadow heuristic_order and decision_order as paths, in enforce decision_permutation as head positions; every other use adds its own identifiers and counts, described on its page under docs/decision-models/). Never the state, a passage, a prompt or a question text. Fail-open: a failed write never fails the search. The daily cost gate and o2b decision-model report read these records |
decision_model_extract_commit | the optional decision model is active and the extract_prefilter use is not off | commit phase of brain_extract_signals / o2b brain extract-signals (src/core/brain/extract-signals-prefilter.ts) - one record per commit that wrote items: session_id, mode, written_count, source_turns (the cited turn ids that name a real turn of the session) and without_source_turn_count; turn ids and counts only, never text. Read by o2b decision-model report --use extract_prefilter for its regret metric |
token_impact | config key token_impact_ledger_enabled (default off) | brain_token_impact action record (emitTokenImpact in src/core/brain/token-impact.ts) - one sample per context pack; payload carries the tokenizer-exact prompt-token counts (baseline_tokens, packed_tokens, signed delta_tokens), the method label (exact/fallback), an optional opaque pack_id, an optional source attribution (decision_model:<use> for savings of a decision-model use), and the optional modeled inference-avoidance estimate - never raw prompts or recalled text |
token_impact_outcome | config key token_impact_ledger_enabled (default off) | brain_token_impact action outcome (recordTokenImpactOutcome) - one first-pass/repair/retry post used only to calibrate the modeled ledger |
context_pack_outcome | config key context_pack_outcome_enabled (default off) | brain_context_pack_outcome action post (postContextPackOutcome in src/core/brain/context-pack-outcome.ts) - one compact per-sample outcome row for a carried context-pack quality-sample id: first-pass/repair/retry counters plus three STRICTLY SEPARATE token signals (exact_prompt_token_savings, modeled_inference_avoidance, observed_provider_tokens), never merged; payload carries counters + an opaque sample_id only, never raw prompts or recalled text, and a caller-omitted field is not invented. One post writes THREE records, all joined on the same sample_id: this row, a token_impact_outcome calibration post, and a context_pack_evidence row (both listed separately below and in this table). The thin wrapper emitContextPackOutcome returns only this row; the two composed records are written either way |
context_pack_evidence | config key context_pack_outcome_enabled (default off - the same gate as the outcome row it accompanies) | composed by every brain_context_pack_outcome action post (recordContextPackEvidence in src/core/brain/context-pack-evidence.ts) - one row per outcome row, joined on the same sample_id, carrying the evidence the kernel reads back off disk (the context_receipt that id names: final_text_hash, item_count, final_text_chars) and a closed verdict over the acting agent's optional claim: match, mismatch, unclaimed (evidence obtained, nothing asserted), or unresolved. A mismatch lists the drifted fields and is RECORDED, never resolved - the outcome row is neither rejected nor silently corrected by it. An unresolved verdict names why through a separate token, sample_absent (the log was read and holds no such receipt) or evidence_unreadable (the log could not be read at all), so absence is never reported as inability. Payload carries those tokens + the opaque sample_id only, never raw prompts or recalled text. NOT an independent attestation: the agent id on the row is self-asserted and this same process wrote the receipt it now reads. The post response echoes the payload under evidence, so a contradicted claim is visible to the poster and not only to a later reader |
ingest_dedup | always-on, fail-open; written ONLY by a run that actually dropped something | the three ingest runs that drop an item on an exact sha-256 dedup_hash collision: captureSessionLifecycleEvent, scanInline, importSession (emitIngestDedupReport in src/core/brain/dedup-telemetry.ts) - one record per run, payload carries the surface, the run's exact_deduped total, and a by_source map keyed by the session id or vault-relative note path being re-ingested. A run that deduped nothing writes NO record, so a real zero stays distinguishable from an absent measurement. Every count is an EXACT-hash drop; the semantic detectors nominate merge candidates and never drop, so no semantic figure appears here |
session_turn, session_summary_node | always-on within its operation | session-recall import (src/core/brain/session-recall.ts) - the write IS the operation |
pre_compact_extract | always-on within its operation | explicit pre-compact extraction (src/core/brain/pre-compact-extract.ts) |
source_invalidation | always-on within its operation | source drift detection (appendContinuitySourceInvalidation) |
skill_rewrite_eval_grade | always-on, one record per COMPLETED benchmark-gated skill rewrite gate run (agent-presence, t_635e3e72); a run that ends before the gates complete - a promote still awaiting its single held-out check - writes nothing | recordSkillRewriteGrade in src/core/brain/skill-proposals.ts, called from o2b brain skill-proposals rewrite-score: payload carries the skill name, the spec hash and tasks hash the run verified against, the metric (tasks_passed_rate), the seed and split rule, the final verdict (promote / hold / not_enough_evidence, where a hold is also what a missed held-out check downgrades a promote to), the baseline and candidate rates, and per-task rows (task_id, passed, failed_checks) for the dev and held-out arms. Identifiers, numbers, booleans and check ids only - never task text and never transcript text; the payload is rebuilt field by field at the boundary so nothing else in the caller's object survives. Kept never-folded so an operator can audit why a rewrite landed or held; the MCP status surface reads the same rows read-only |
Session lifecycle capture (captureSessionLifecycleEvent) writes audit rows and Brain log events, and no continuity record at all unless the event actually dropped a repeat - in which case it writes exactly one ingest_dedup record. Both halves of that boundary are pinned by regression tests (tests/core/brain/continuity-emit.test.ts for the silent path, tests/core/brain/dedup-telemetry.test.ts for the dedup path).
Schema version and evolution rule
Since v0.39.0 every new continuity record is stamped schema: "o2b.continuity.v1" (CONTINUITY_SCHEMA_VERSION in src/core/brain/continuity/types.ts).
Records written before the stamp existed carry no
schemafield; every reader treatsundefinedas v1. Existing JSONL files are never migrated.Additive optional fields do NOT bump the version. Renames, removals, or semantic changes bump to
o2b.continuity.v2.The record id (
recordId(), sha-256 over kind + createdAt + sourceRefs + payload) deliberately EXCLUDES the schema field, so identical records keep identical dedup ids across the stamp transition. Locked by a known-answer test.Consumers should go through the read-model (
src/core/brain/continuity/read-model.ts), which absorbs the version dispatch, liftssession_id/turn_idinto first-class fields, and applies the masking policy below.
Correlation IDs
| Field | Where | Stable join? |
|---|---|---|
id (ctn_<stamp>_<sha16>) | every continuity record | yes - content-hash dedup id |
createdAt | every continuity record | ordering key (store sorts by createdAt, then id) |
sourceRefs[].id / .path | continuity records | joins records to vault artifacts |
session_id, turn_id | payloads of session-scoped kinds; lifted by the read-model | yes - the cross-surface session join |
handoffKind, handoffRef | generation_report payload handoff; lifted by the read-model | yes - joins a generation report to the write-session / context-receipt / dream run it traced |
timestamp + agent | Brain log events | per-event attribution |
agentId, isSidechain | SessionTurn, from a transcript that records delegation | yes - the only thing separating a delegated sub-agent's turns from its parent's, because a sub-agent transcript reuses the PARENT's session id |
Multi-agent vaults attribute writers via per-agent identity (brain_agent_query). Delegated sub-agents are correlated as of v1.49.0, and by the additive route this sentence used to promise: SessionTurn carries an optional agentId and an optional isSidechain: true, both emitted only where the transcript records them, so a flat transcript keeps its pre-delegation shape byte for byte. A sub-agent transcript reuses its PARENT's session id, so those two fields are the only thing separating the two agents' turns. The SubagentStop hook records the close under <delegator>-sub-<agent-id>; the agent_transcript_path the event also carries is deliberately not persisted, being a machine-local host path.
Absence is its own identity. Since v1.81.0 a payload with no string session_id is a no-session record, never a member of a blank bucket: the readers no longer coerce the missing key to "", so scoped recall excludes such records (the lineage ledger already omitted blank declarations, so the scope set never held them), grouping sites skip them instead of lumping every unattributed record from every unrelated lane together, and the brain_session_summary digest omits its session_id key rather than answering "". o2b brain doctor counts the rows older writers left under the legacy coercion with the count-only, fail-soft blank-session-identity check - one issue per affected record kind, no fix field: the continuity store is append-only, and rewriting it is a backup-gated design, not a doctor step.
Payload safety
Every continuity payload passes safeContinuityPayload() (src/core/brain/continuity/redaction.ts) before it reaches disk:
<private>...</private>regions are stripped and replaced; the record is flaggedprivate: true.Secret-shaped tokens are redacted to
***REDACTED***; the record is flaggedredacted: true.The sanitized payload is deep-frozen; nothing mutates it after the flags are computed.
gate_telemetrynever stores the raw prompt by construction - only a SHA-256 prefix (prompt_hash) and the length (prompt_chars). The test suite asserts this against the persisted files, not just returned values.negative_recallshares that construction (same module, same hash helper) and adds one rule of its own: the coverage receipt it carries dropsindex_path, so no host filesystem path replicates with the vault.generation_reportfollows the same rule: the handoff prompt is hashed and counted but never persisted - onlyprompt_hash(full SHA-256 hex) andprompt_charsland on disk, plus token counts. The kernel never calls an LLM; the report is the agent's INBOUND record after it performed a generation for a brain handoff, so the local token estimate (local_estimate.input_tokens) is always present while the agent-reportedusageblock is present only when supplied - absent is reported as absent, never fabricated. A grep-guarded regression test pins that nofetch/provider HTTP call exists undersrc/corefor this feature, and a persisted-file assertion confirms no raw prompt survives.mcp_route_latencycarries an optionaldecision_ms(wall time spent in decision-model requests during that call) only when the call made at least one; records from an install without the feature are unchanged.mcp_route_latencycarries an optionalstagesarray of{ name, ms }entries (v1.74.0): the wall time the call spent in each write stage, summed per name in first-seen order and rounded to 0.1 ms. Names come from the closedROUTE_STAGEallowlist insrc/core/route-scope.ts-validate,idempotency_lookup,near_duplicate_lookup,document_write,idempotency_remember,log_append,preference_write,write_receipt,lint- andemitMcpRouteLatencydrops any other name, any negative value and any non-finite value before the record is written, so no path, topic or other free text can land on disk. The key is omitted when no stage ran, so a record from a route without stages is byte-identical to before. Stage timings never appear in the response of the call being measured; they live only in its continuity record, whichbrain_route_metricsreads back. Stages can nest, so they are not a partition ofduration_ms:lintwraps the receipt lint, and the near-duplicate scoring inside that lint is also counted undernear_duplicate_lookup. The same milliseconds then appear under both names,lintincludes that scoring, and the stages of one record can add up to more than its duration.Routes that emit stages, by the write helpers they reach: every route that writes a signal through
writeSignalgetsvalidateanddocument_write, plusidempotency_lookupand, when the signal is written,idempotency_rememberonly when the signal carries an idempotency key, which onlybrain_feedbackaccepts (itsidempotency_keyargument). That coversbrain_feedbackandbrain_extract_signals; the latter writes one signal per accepted item, so its stage values are summed across items.brain_feedbackaddsnear_duplicate_lookup(the write-conflict advisory),log_append(the feedback log line, and the second log line underforce_confirmed; the advisory's own log line is not timed) andpreference_writewithforce_confirmed; a retry that the idempotency key dedupes stops afteridempotency_lookup. Every note write that ends in a write receipt -brain_create_note,brain_update_note,brain_append_noteandbrain_write_batch- getswrite_receiptfor each note it writes or rewrites,document_writefor each note it creates, and, when at least one page was written,lintandnear_duplicate_lookupfrom the receipt lint (the latter also covers the keyword-index widening when that is on). One route scope per tool call carries bothdecision_msandstages; withmcp_route_metrics_enabledoff no scope is opened and every stage helper reduces to a plain call.Hook capture is not an MCP route: lifecycle hooks call
captureSessionLifecycleEventdirectly and hand the dedup walk to a detached worker, so they never pass throughinvokeToolHandlerand carry no stage timings.mcp_route_latencyrecords the route (tool name), MCP scope, status, duration, and the sorted set of argument KEY NAMES only - the tool's own JSON-Schema property names, never operator-supplied argument values - so no prompt, note body, or preference id can land on disk. A persisted-file test asserts key names survive while values never do.The masking policy lives in the read-model (
src/core/brain/continuity/read-model.ts) and governs only the readers that go through it: records flaggedprivateare dropped by default and kept only on explicit request; masked text is never un-masked. That is FOUR modules - theo2b brain continuityverbs (trajectory export and listing), the bench harness,brain_event_trace, and skill-usage aggregation. Twenty-two other modules calllistContinuityRecordson the store directly and see raw records: noprivatedrop and no schema-version dispatch. The policy is read-model-wide, NOT store-wide. Both lists are asserted by name intests/core/brain/continuity/reader-census.test.ts, which fails when a module joins or leaves either set, and both COUNTS are pinned there as equalities rather than floors - the direct floor used to sit at twenty against a reality of twenty-one, which is how the number in this sentence came to be wrong. Auditing the direct readers is tracked separately.A hook's
tool_responseis READ and never written. Lifecycle capture consults it to decide whether the call it is reacting to actually succeeded - a failedbrain_feedbackmust not be replayed, because replaying it mints the record the tool declined to create - and the decline is counted rather than swallowed. The response body itself is arbitrary tool output and never reaches a payload, so declaring it in the hook contract costs nothing on disk.privateis the ONLY visibility signal a record carries, and it is inferred from a<private>region in the payload rather than declared. A caller-declaredscopefield was built for this envelope and removed before release: nothing in the codebase could supply one - no tool argument, no command-line flag, no config key and no library entry point - and its single vocabulary member would have narrowed a record's visibility rather than widened it, since a declared scope is dropped by every reader that does not name it. Adding a declaration to the envelope is a schema change;tests/core/brain/continuity/record-envelope.test.tspins the eight fields and their order so the next attempt has to be argued for.
Fail-open rules
Telemetry must never block or fail the primary operation. The guarantee is structural, not conventional: gated surfaces route through emitGatedTelemetry(gate, build) (src/core/brain/continuity/emit.ts):
gate off (
undefined/false/null): the build thunk is NEVER invoked - no payload object, no hash, no write on the no-consumer path;a throwing thunk or store write is swallowed and reported as
null; the context pack, pre-compress pack, search response, and recall-gate decision all complete normally with the telemetry field simply absent.
No-consumer regression tests cover each gated surface, so a future call site cannot silently regress to eager payload construction. Writers whose continuity append IS the primary operation (session-recall import, pre-compact extract) stay fail-fast on purpose - failing silently there would lose user data, not telemetry.
Reading the surfaces
brain_recall_telemetry(MCP) ando2b brain recall-telemetry list|summary|gate-list|gate-summaryaggregate recall and gate records. Since v1.46.0 everyrecall_telemetrypayload carries achannelnaming the seam the recall came through -mcp,cli, orhook, a closed set. It is a property of the emit site rather than a caller argument: the MCP handlers stampmcp,o2b brain context-pack --telemetrystampscli, and the recall-inject hook stampshook. Every emit site must name one, enforced at build time, so no new record lacks it.channelis clip-protected alongsidesession_idandagent_id, so an output-budget clip may not drop it. Filter on it with thechannelargument (MCP) or--channel(CLI) onlistandsummary, and read theby_channelrollup onsummary; a channel with no record is absent from that rollup rather than reported as0. Records written before v1.46.0 carry nochannelat all and are never migrated, so they count intotal/by_mode/by_statusbut fall into noby_channelbucket, and anychannelfilter excludes them.o2b brain doctorcrosses the rollup against per-channel install state and reportsrecall-channel-silent(installed, expected to deliver, silent for 30 days) orrecall-channel-unmeasured(one half of that cross could not be read - the latter rides theuncertainstream and does not affect the exit code).The recall-inject hook's optional decision-model filter (
decision_model_uses: "recall_inject:shadow|enforce", seedocs/decision-models/recall-inject.md) adds to the hook'srecall_telemetrymetadataand to its local hook-audit line adecision_modelobject:mode,outcome(ok,not_sentordegraded),latency_ms(the time the filter added to the prompt),notes_droppedandabstained(inshadow, whatenforcewould have done). Only the local audit line addsdegrade_reasonon a failure. Inenforcea withheld brief is anabstainwith reasondecision_model_abstain(statusempty). Itsdecision_model_callrecords carrynote_paths(a note that may not leave the machine as(withheld)),helps,inject_any,abstained,notes_dropped,withheld_count,budget_dropped_countandbudget_ms; an enforced brief that got shorter writes onetoken_impactsample withsource: decision_model:recall_injectwhentoken_impact_ledger_enabledis on. None of these carries prompt or note text.o2b decision-model report --use recall_injectreads them with p50/p95 added latency, timeout rate, abstain rate and notes dropped next to the hook's recall telemetry.The recall-inject hook's local hook-audit line (
action: recall_inject_decision) carries what only the hook knows, each field present only when it applies:config_invalid(the settings amongrecall_inject_max_notes,recall_inject_max_chars,recall_inject_time_budget_msandrecall_inject_confidence_floorwhose value was rejected, so the built-in default ran; a value taken from the environment is named by itsOPEN_SECOND_BRAIN_RECALL_INJECT_*variable),dedupe_sets(already_injectedanddigest_paths, the sizes of the session's recall set and SessionStart digest set the decision consulted, not counts of suppressed notes; absent without a session id or withrecall_inject_dedupeoff),ledger_recorded: false(an injected brief whose post-stdout ledger write failed, so its notes can repeat; absent when the write succeeded or no ledger applies),slices(one{name, outcome, notes}per declared slice,outcomebeinginjector that slice's abstain reason)slices_config: "invalid"(the vault's_brain.yamlfailed to load; the search reads the same file, so that decision is anerrorwith faultretriever_failed) and, since v1.73.0,retrieval_degraded(the retrieval trail codes of the searches behind the decision, each once in first-seen order, for examplesemantic-cost-unpricedwhen the hook's query embed was refused by the cost gate). The gap-promote hook's audit line carries the sameretrieval_degradedfield for its recall checks. Slice names are vault policy vocabulary and ride the local audit line only, never the syncedrecall_telemetryrecord. The abstain reasonsall_already_injectedandall_slices_abstainedreach both surfaces through the existingreasonfield. Seedocs/decision-models/recall-inject.md.brain_recall_telemetryoperation: "cost"(MCP) ando2b brain recall-telemetry costfold WRITE volume against the read telemetry above: memory-write ops (Brain-logfeedback/apply-evidence/noteverbs plushost_memory_writecontinuity records) are counted per period and reported alongside reads as a write-vs-read ratio, awrite_heavyflag, and a rough weighted cost signal. Weights (--write-cost/--read-cost, default 1 each) model "some tools charge on write, some on read";--write-heavy-ratio(default 1) sets the write-heavy threshold. Read-only; period-scoped by--since/--until.brain_create_notefile creation emits no telemetry event today and is not counted.brain_recall_telemetryoperation: "dead_weight"(MCP) ando2b brain recall-telemetry dead-weight(since v1.80.0) read the other side of the same records: pages currently in scope that no recorded recall within the telemetry window ever surfaced. The denominator is the vault walk's included paths (current on-disk truth), not the index's document table, so a deleted-but-indexed page is never reported as dead weight; the retrieved set is the union of recordedtop_artifactsand observed-use source references, windowed by--since/--until(the report states the earliest matching record). The payload carriespages_total,pages_retrieved,dead_countand a cappeddeadlist behind the usualvault_pathenvelope, plus agate_caveat: telemetry is opt-in and records only surfaced top rows, so the report claims "no recorded retrieval surface within telemetry history", never absolute never. Read-only; at remote reach hidden rows are dropped beforetotal.brain_context_receiptsando2b brain context-receiptsinspect served-context receipts.The score-aware tail trim (opt-in
tail_trim_context_packconfig key, default off) adds to acontext_packrecall_telemetryrecord'smetadatafour counters, present only when the trim actually ran:tail_trim_dropped(tail items dropped whole),tail_trim_kept_by_query_terms(tail items kept because their query-term overlap nearly matched the top delivered score),tail_trim_rescued(formerover-budgetcandidates re-admitted under the freed budget) andtail_trim_tokens_saved(tokens freed, net of the budget the rescue re-spent; never negative, because the rescue may spend only the budget the trim freed). The same counters ride thecontext_receiptbudgetblock, and each dropped item'stail-trimskip reason surfaces as the telemetry gaptail_trim. An untrimmed pack carries none of these keys, so its records stay byte-identical.The answer-quote-check Stop hook (since v1.81.0) is the answer-boundary counterpart of the receipts above: it verifies the quoted spans in the assistant's own answer against the evidence the turn actually had - the note a span's context names, else the injection ledger's delivered notes - and annotates the unverified ones. Verdicts:
verified,not-in-note,source-truncated,note-unavailable,not-text; degradation never upgrades a verdict, so a truncated source armssource-truncatedon a miss and an unreadable note armsnote-unavailable, never an all-clear. The annotation rides the StopadditionalContextchannel Claude Code renders; the other registered runtimes stay silent. Gated per phase byquote_check.recall|active|subagentin_brain.yaml, eachoff|shadow|enforce, defaultshadow; inenforcethe turn also lands one Brain-lognoteevent (the enforce trail in the table above), so findings survive the session. The check reads only the transcript's bounded tail window and writes nothing else; it never blocks and never edits a transcript.The SessionStart hook writes one
context_receiptper injection (host: "hook",trigger: "session_inject") with one item per source it injected. On a measured run itsbudgetblock carriesinject_budget_chars(the configured value),budgeted_source_countand, since v1.70.0,scoped_rules_chars: the length of the rendered scoped operator rules block,0when none rendered. The scoped block is a budgeted source namedscoped-rules, but it is subtracted from the budget rather than charged against the full ceiling: the active body was budgeted toinject_budget_charsminusscoped_rules_chars(never below zero). Thebudgetblock is present whenever the scoped block rendered, also when there is noactive.md. A run that fell back to the last good cache records nobudgetblock, as before, but keeps thestanding-rulesandscoped-rulesitems, which are produced outside the fail-open boundary. See "Scoped operator rules" inhow-it-works.md.With
reground_parts_enabledon, the same receipt'sextra.injectiongains the chunked re-grounding fields:utf16_chars(the joined payload length in UTF-16 code units),part_ceiling_chars(the per-part ceiling it was cut to,nullon a runtime without thereground-delivercarrier or without a session id),parts_total,parts_dropped(parts past the 8-part maximum that were never queued; when it is above zero the last delivered part ends with(context truncated: N further part(s) not delivered)) andover_budget(truewhen parts were dropped, when a part is still longer than the ceiling, or when the queue could not be written and the whole payload went out as one part). That last case also setsreground_fallback: "ledger_write_failed", which no other path writes, so a failed queue write is told apart from a plain over-budget payload. A part-ceiling key (reground_part_chars,reground_part_chars_claudecode,reground_part_chars_codex) whose value is out of range or not an integer falls through to the next level and is named inconfig_invalid(by its environment variable, such asOPEN_SECOND_BRAIN_REGROUND_PART_CHARS, when the rejected value came from the environment), present only then. With the flag off none of these fields appears and the receipt keeps its shape. Each part thereground-deliverhook hands out writes one hook-audit line (actor: reground-deliver,action: reground_part_delivered,targetthe host eventPostToolUseorUserPromptSubmit) withpart(the 1-based part number),total,epoch(the SessionStart that queued it, as<source>:<epoch-ms>with the source one ofstartup,resume,clearorcompact, any other value recorded asunknown),bytes(UTF-8),utf16_chars,part_ceiling_charsandover_budget(the part alone is longer than the ceiling). A take that fails for a reason other than lock contention (an unreadable state directory, a full disk) writesaction: reground_take_failedwithok: false, no part andepoch(the queue's SessionStart,nullwhen unreadable), once per epoch on each machine: a state write that keeps failing leaves the queue undrained, and the repeats on later tool calls write no further line. A tool call inside a delegated sub-agent (the payload carriesagent_id) takes no part and writes no line. A process-ceiling exit writesaction: hook_ceiling_exceeded,target: reground.brain_route_metrics(MCP,operation: "list"|"summary") reads route-level MCP tool latency.listreturns rawmcp_route_latencyrecords (filter bytool/status/since/until/limit);summaryrolls each tool up into count, error count, and min/avg/max plus p50/p95/p99 latency, ordered slowest-first so an operator can identify which endpoint blocks an agent turn by route rather than by aggregate benchmark. A route whose records carrystagesalso gets astagesroll-up - per stage name, inROUTE_STAGEorder, the count, the average and the nearest-rank p95 in ms - and a route without stages has nostageskey. Records are emitted only whenmcp_route_metrics_enabledis on (default off); read-only.brain_token_impact(MCP,operation: "record"|"outcome"|"list"|"summary") is the durable value-of-memory ledger.recordposts one context pack's prompt-token delta (baseline_tokens−packed_tokens, labelledmethod: tokenizer|heuristic— how the CALLER produced the counts, never how accurate they are; the ledger counts nothing itself and verifies neither. Samples written under the retiredexact/fallbacklabels are still read and classified) plus an optional modeled inference-avoidance estimate (modeled_avoided_inferences×modeled_tokens_per_inference);outcomeposts afirst_pass/repair/retryresult.summarykeeps the two ledgers STRICTLY SEPARATE:prompt_token_deltareports the net/saved/added tokens with a per-methodsplit (so a tokenizer-produced count is never averaged in with a heuristic estimate), whilemodeled_inference_avoidancereports the raw modeled figure and acalibrated_savings_tokensdampened by the observed first-pass rate from posted outcomes (null until an outcome exists — uncalibrated, not zero).listreturns raw samples (filter bypack_id/method/host/since/until/limit);summaryacceptsmax_samplesto bound aggregation. Writes are emitted only whentoken_impact_ledger_enabledis on (default off) and are payload-safe (counts + opaquepack_idonly, never prompts or recalled text);list/summaryread regardless of the gate. Aggregates are recomputed from the continuity store on every read, so they survive restarts.brain_event_trace(MCP) ando2b brain event-tracejoin the Brain log to the continuity store: given a logged event (by day,--atstamp, kind, or--session-id), they resolve the continuity records attached to it via the stable correlation ids above (session_id,turn_id, and artifactsourceRefs), so an operator can answer "which context was supplied to this action?" from one surface. Each attached record reportsjoinedBy(session/turn/artifact); open the full record through the per-kind readers (context-receipts show,recall-telemetry,generation-reports show). Read-only;privaterecords are dropped unless explicitly kept.brain_generation_reports(MCP, actionsrecord/list/summary) ando2b brain generation-reports record|list|summary|showpost and read inbound LLM generation traces.summaryrolls up call counts, the always-present local token estimate, agent-reported usage where present, and a per-path linkage map so a memory path resolves back to the generation reports that produced or consumed it.o2b brain continuity export --format atof|atifrenders the store as standard trajectory formats (ATOF JSONL event stream; ATIF v1.7 one document per session) for replay and eval tooling. Read-only;privaterecords never reach an export file. Mapping decisions:docs/brainstorm/memory-observability-suite/atof-atif-mapping.md.o2b brain bench memorymeasures memory quality over disposable fixture vaults and reports quality, latency, context cost, and failure modes as separate families (o2b.bench.v2report schema). Beyond the retrieval categories it scores three failure modes the retrieval questions cannot see:proactive_recalldrivesdecideRecallInjectover the fixture and reportsknow_to_ask_failure_rateandfalse_fire_rate(both denominated in decisions, so a strategy that always injects scores worse than one that abstains correctly);write_fidelitygrades the provenance that survives the shipped extraction, insertion and dedup path with no model call;source_isolationasserts on delivered context-pack contents under a requested owner scope and gates at zero.context_cost.avg_injected_tokensisestimateTokensover the strings the bench actually injected — the suite's one token estimator. Two things the numbers do NOT say:recall_inject_enabledis off by default, so the proactive metric describes a capability rather than delivered behaviour, andintegrity.owner_scope_deliveryis off by default, so an isolation fixture must set it tofailor the gate is vacuous. The committed baseline istests/fixtures/bench/failure-modes.baseline.json, compared bytests/core/bench/failure-modes-baseline.test.tsinside the ordinarybun testgate. Since v1.82.0 the verb's suite registry maps a--suitename to its loader plus a declared capability set ({embeddings: boolean}; omitting--suitestays the byte-identical locomo default), the run identity folds the pinned search knobs and the proactive-recall admission floor into the checkpoint hash beside the fixture hash - a resumed run that would mix configurations fails the identity guard by name - and two suites join locomo:--suite longmemevalscores the LongMemEval dataset shape with the strictlongmemeval: {recall_all_at_5, abstention_excluded}family (the committed sample fixture certifies CI, the full dataset is operator-supplied, and the judge ridesbench_judge_cmdwithquestion/answer/goldadded to the stdin payload only for suites that provide them; the embeddings capability is apply-gated and its arming is API-only this wave, with a shared provider+model+text-hash vector cache under the runs dir), and--suite surfacing-replayreplays a recorded prompt corpus through the shipped decision core and scores the graded surfacing gate's know_to_ask / false_fire rates, which closes the caveat that the structural gate alone was not scoreable: the graded admission key is a measured bound, and the replay suite is the instrument that re-measures it. Since v1.83.0 the capability set also declaressampling, and--sample-seed <value>plus--sample-cap <n>(a pair - either alone is refused by name; a non-positive or non-integer cap is refused naming the value; a suite without the capability is refused naming the suite, and longmemeval is the only one that has it) run a seeded, question-type-proportional subset of the dataset instead of the whole fixture: abstention questions are excluded first and their count still lands inabstention_excluded, the survivors are stratified by the dataset's ownquestion_typevalues, each stratum contributes its population-proportional share of the cap by largest-remainder apportionment (remainders compared as integers, ties by stratum name), and the draw is a seeded shuffle over entries sorted by question id - no wall clock, noMath.random- so dataset file order cannot change the subset and the same seed and cap always select the same questions. Sampling happens before conversion, so a sampled run materializes notes and continuity records only for the questions it scores. A sampled run's--jsonreport carries the sampling receipt in itslongmemevalfamily:sample_population,sample_selectedand the per-stratumsample_stratasit besideabstention_excluded, each present only on a sampled run and absent from a whole-dataset report, and the humanlongmemevalreport line gainssample_selected Nonly on a sampled run; the seed and cap fold into the run identity with the same spread-omission the floor uses: run ids of runs without sampling are byte-stable, and a resumed run whose sampling options changed fails the identity guard by name (the guard's message names the sampling options beside the pinned knobs and the floor).
Consumers should treat unknown record kinds and unknown payload fields as fine - skip what you do not recognize (the store and read-model already behave this way).
512 files · 486 not served here
- .agents/plugins/marketplace.json (not served here)
- .ai-notes/.gitignore (not served here)
- .apb/.gitignore (not served here)
- .apb/config.yaml (not served here)
- .apb/playbooks/osb-feature-release/1.1.0/playbook.yaml (not served here)
- .apb/playbooks/osb-feature-release/1.2.0/playbook.yaml (not served here)
- .apb/playbooks/osb-feature-release/1.3.0/playbook.yaml (not served here)
- .apb/playbooks/osb-feature-release/1.4.0/playbook.yaml (not served here)
- .apb/playbooks/osb-feature-release/current (not served here)
- .apb/playbooks/osb-feature-release/lifecycle (not served here)
- .apb/playbooks/osb-feature-release/meta/1.1.0.yaml (not served here)
- .apb/playbooks/osb-feature-release/meta/1.2.0.yaml (not served here)
- .apb/playbooks/osb-feature-release/meta/1.3.0.yaml (not served here)
- .apb/playbooks/osb-pr-prepare/1.0.0/playbook.yaml (not served here)
- .apb/playbooks/osb-pr-prepare/1.0.0/scripts/arch-gate.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.0.0/scripts/check-context.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.0.0/scripts/check-pr.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.0.0/scripts/check-release.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.0.0/scripts/ci-wait.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.0.0/scripts/lib.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.0.0/scripts/qa-gates.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.0.0/scripts/zg-index.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.1.0/playbook.yaml (not served here)
- .apb/playbooks/osb-pr-prepare/1.1.0/scripts/arch-gate.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.1.0/scripts/check-context.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.1.0/scripts/check-pr.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.1.0/scripts/check-release.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.1.0/scripts/ci-wait.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.1.0/scripts/final-gates.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.1.0/scripts/lib.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.1.0/scripts/qa-gates.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.1.0/scripts/zg-index.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.2.0/playbook.yaml (not served here)
- .apb/playbooks/osb-pr-prepare/1.2.0/scripts/arch-gate.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.2.0/scripts/check-context.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.2.0/scripts/check-pr.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.2.0/scripts/check-release.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.2.0/scripts/ci-wait.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.2.0/scripts/final-gates.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.2.0/scripts/lib.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.2.0/scripts/qa-gates.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.2.0/scripts/zg-index.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.4.0/playbook.yaml (not served here)
- .apb/playbooks/osb-pr-prepare/1.4.0/scripts/arch-gate.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.4.0/scripts/check-context.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.4.0/scripts/check-pr.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.4.0/scripts/check-release.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.4.0/scripts/ci-wait.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.4.0/scripts/cycle-run.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.4.0/scripts/final-gates.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.4.0/scripts/lib.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.4.0/scripts/qa-gates.sh (not served here)
- .apb/playbooks/osb-pr-prepare/1.4.0/scripts/zg-index.sh (not served here)
- .apb/playbooks/osb-pr-prepare/current (not served here)
- .apb/playbooks/osb-pr-prepare/lifecycle (not served here)
- .apb/playbooks/osb-pr-prepare/meta/1.0.0.yaml (not served here)
- .apb/playbooks/osb-pr-prepare/meta/1.1.0.yaml (not served here)
- .apb/playbooks/osb-pr-prepare/meta/1.4.0.yaml (not served here)
- .apb/playbooks/osb-release/1.0.0/playbook.yaml (not served here)
- .apb/playbooks/osb-release/1.0.0/scripts/discard.sh (not served here)
- .apb/playbooks/osb-release/1.0.0/scripts/lib.sh (not served here)
- .apb/playbooks/osb-release/1.0.0/scripts/publish.sh (not served here)
- .apb/playbooks/osb-release/1.0.0/scripts/release-image-style.md (not served here)
- .apb/playbooks/osb-release/1.0.0/scripts/render.sh (not served here)
- .apb/playbooks/osb-release/1.0.0/scripts/render.ts (not served here)
- .apb/playbooks/osb-release/1.0.0/scripts/scope.sh (not served here)
- .apb/playbooks/osb-release/1.0.0/scripts/stage.sh (not served here)
- .apb/playbooks/osb-release/current (not served here)
- .apb/playbooks/osb-release/lifecycle (not served here)
- .apb/playbooks/osb-release/meta/1.0.0.yaml (not served here)
- .apb/playbooks/osb-triage-validator/1.2.0/playbook.yaml (not served here)
- .apb/playbooks/osb-triage-validator/1.3.0/playbook.yaml (not served here)
- .apb/playbooks/osb-triage-validator/current (not served here)
- .apb/playbooks/osb-triage-validator/lifecycle (not served here)
- .apb/playbooks/osb-triage-validator/meta/1.2.0.yaml (not served here)
- .apb/playbooks/osb-triage-validator/meta/1.3.0.yaml (not served here)
- .apb/playbooks/osb-upstream-watch/1.0.0/playbook.yaml (not served here)
- .apb/playbooks/osb-upstream-watch/1.0.0/scripts/materialize-collector.sh (not served here)
- .apb/playbooks/osb-upstream-watch/current (not served here)
- .apb/playbooks/osb-upstream-watch/lifecycle (not served here)
- .apb/playbooks/osb-upstream-watch/meta/1.0.0.yaml (not served here)
- .apb/profiles/osb-collector/SOUL.md (not served here)
- .apb/profiles/osb-collector/profile.yaml (not served here)
- .apb/profiles/osb-developer/SOUL.md (not served here)
- .apb/profiles/osb-developer/profile.yaml (not served here)
- .apb/profiles/osb-reviewer/SOUL.md (not served here)
- .apb/profiles/osb-reviewer/profile.yaml (not served here)
- .apb/profiles/osb-validator/SOUL.md (not served here)
- .apb/profiles/osb-validator/profile.yaml (not served here)
- .claude-plugin/marketplace.json (not served here)
- .claude-plugin/plugin.json
- .codex-plugin/plugin.json (not served here)
- .codexignore (not served here)
- .gitattributes (not served here)
- .githooks/pre-commit (not served here)
- .githooks/pre-push (not served here)
- .github/dependabot.yml (not served here)
- .github/scripts/ci-scope.sh (not served here)
- .github/scripts/windows-timings.sh (not served here)
- .github/windows-test-timings.json (not served here)
- .github/workflows/ci.yml (not served here)
- .github/workflows/plugin-scanner.yml (not served here)
- .github/workflows/release.yml (not served here)
- .gitignore (not served here)
- .oxfmtrc.json (not served here)
- ATTRIBUTION.md
- AUTOGINEER-RUNS.md
- CHANGELOG.md
- CLAUDE.md
- LICENSE
- README.md
- SECURITY.md
- __init__.py (not served here)
- after-install.md
- bin/o2b-discipline-report (not served here)
- bun.lock (not served here)
- bunfig.toml (not served here)
- cli.py (not served here)
- docs/architecture.md
- docs/brain-store.md
- docs/brainstorm/a-label-is-not-a-boundary/cli-output/claude.md (not served here)
- docs/brainstorm/a-label-is-not-a-boundary/cli-output/prompt.md (not served here)
- docs/brainstorm/a-label-is-not-a-boundary/design.md (not served here)
- docs/brainstorm/a-label-is-not-a-boundary/plan.md (not served here)
- docs/brainstorm/a-label-is-not-a-boundary/recon/census-lexer.md (not served here)
- docs/brainstorm/a-label-is-not-a-boundary/recon/conventions-and-release-machinery.md (not served here)
- docs/brainstorm/a-label-is-not-a-boundary/recon/egress-boundary.md (not served here)
- docs/brainstorm/a-label-is-not-a-boundary/recon/fleet-and-shared-scope.md (not served here)
- docs/brainstorm/a-label-is-not-a-boundary/recon/identity-and-attribution.md (not served here)
- docs/brainstorm/a-label-is-not-a-boundary/recon/mcp-instruction-surface.md (not served here)
- docs/brainstorm/a-label-is-not-a-boundary/recon/owner-scope-isolation.md (not served here)
- docs/brainstorm/a-label-is-not-a-boundary/recon/retrieval-confidence-floor.md (not served here)
- docs/brainstorm/a-label-is-not-a-boundary/variants.md (not served here)
- docs/brainstorm/actionable-now-batch/cli-output/consultant.md (not served here)
- docs/brainstorm/actionable-now-batch/cli-output/prompt.md (not served here)
- docs/brainstorm/actionable-now-batch/design.md (not served here)
- docs/brainstorm/actionable-now-batch/plan.md (not served here)
- docs/brainstorm/actionable-now-batch/variants.md (not served here)
- docs/brainstorm/agent-boundary-control-surfaces/README.md (not served here)
- docs/brainstorm/agent-boundary-control-surfaces/cli-output/claude.md (not served here)
- docs/brainstorm/agent-boundary-control-surfaces/cli-output/prompt.md (not served here)
- docs/brainstorm/agent-boundary-control-surfaces/design.md (not served here)
- docs/brainstorm/agent-boundary-control-surfaces/plan.md (not served here)
- docs/brainstorm/agent-boundary-control-surfaces/variants.md (not served here)
- docs/brainstorm/agent-capability-cli-integration/README.md (not served here)
- docs/brainstorm/agent-capability-cli-integration/adr.md (not served here)
- docs/brainstorm/agent-capability-cli-integration/cli-output/claude.md (not served here)
- docs/brainstorm/agent-capability-cli-integration/cli-output/prompt.md (not served here)
- docs/brainstorm/agent-capability-cli-integration/context.md (not served here)
- docs/brainstorm/agent-capability-cli-integration/design.md (not served here)
- docs/brainstorm/agent-capability-cli-integration/implementation-notes.md (not served here)
- docs/brainstorm/agent-capability-cli-integration/notes.md (not served here)
- docs/brainstorm/agent-capability-cli-integration/phase-log.md (not served here)
- docs/brainstorm/agent-capability-cli-integration/plan.md (not served here)
- docs/brainstorm/agent-capability-cli-integration/pr-notes.md (not served here)
- docs/brainstorm/agent-capability-cli-integration/scope.md (not served here)
- docs/brainstorm/agent-capability-cli-integration/task-body.md (not served here)
- docs/brainstorm/agent-capability-cli-integration/test-matrix.md (not served here)
- docs/brainstorm/agent-capability-cli-integration/variants.md (not served here)
- docs/brainstorm/agent-capability-cli-integration/verification.md (not served here)
- docs/brainstorm/agent-presence-self-improvement/cli-output/consultant.md (not served here)
- docs/brainstorm/agent-presence-self-improvement/cli-output/prompt.md (not served here)
- docs/brainstorm/agent-presence-self-improvement/design.md (not served here)
- docs/brainstorm/agent-presence-self-improvement/plan.md (not served here)
- docs/brainstorm/agent-presence-self-improvement/variants.md (not served here)
- docs/brainstorm/agent-surface-suite/cli-output/claude.md (not served here)
- docs/brainstorm/agent-surface-suite/cli-output/prompt.md (not served here)
- docs/brainstorm/agent-surface-suite/design.md (not served here)
- docs/brainstorm/agent-surface-suite/plan.md (not served here)
- docs/brainstorm/agent-surface-suite/variants.md (not served here)
- docs/brainstorm/agent-write-contract-suite/cli-output/claude.md (not served here)
- docs/brainstorm/agent-write-contract-suite/cli-output/prompt.md (not served here)
- docs/brainstorm/agent-write-contract-suite/design.md (not served here)
- docs/brainstorm/agent-write-contract-suite/plan.md (not served here)
- docs/brainstorm/agent-write-contract-suite/variants.md (not served here)
- docs/brainstorm/answer-trust/cli-output/consultant.md (not served here)
- docs/brainstorm/answer-trust/cli-output/prompt.md (not served here)
- docs/brainstorm/answer-trust/design.md (not served here)
- docs/brainstorm/answer-trust/plan.md (not served here)
- docs/brainstorm/answer-trust/variants.md (not served here)
- docs/brainstorm/auto-migrate-on-upgrade/design.md (not served here)
- docs/brainstorm/auto-migrate-on-upgrade/plan.md (not served here)
- docs/brainstorm/auto-migrate-on-upgrade/variants.md (not served here)
- docs/brainstorm/belief-lifecycle-decision-memory/cli-output/claude.md (not served here)
- docs/brainstorm/belief-lifecycle-decision-memory/cli-output/prompt.md (not served here)
- docs/brainstorm/belief-lifecycle-decision-memory/design.md (not served here)
- docs/brainstorm/belief-lifecycle-decision-memory/plan.md (not served here)
- docs/brainstorm/belief-lifecycle-decision-memory/variants.md (not served here)
- docs/brainstorm/brain-centric-layout/design.md (not served here)
- docs/brainstorm/brain-centric-layout/plan.md (not served here)
- docs/brainstorm/brain-integrity-safety-hardening/cli-output/claude.md (not served here)
- docs/brainstorm/brain-integrity-safety-hardening/cli-output/prompt.md (not served here)
- docs/brainstorm/brain-integrity-safety-hardening/design.md (not served here)
- docs/brainstorm/brain-integrity-safety-hardening/plan.md (not served here)
- docs/brainstorm/brain-integrity-safety-hardening/variants.md (not served here)
- docs/brainstorm/brain-integrity-suite/cli-output/claude.md (not served here)
- docs/brainstorm/brain-integrity-suite/cli-output/prompt.md (not served here)
- docs/brainstorm/brain-integrity-suite/design.md (not served here)
- docs/brainstorm/brain-integrity-suite/plan.md (not served here)
- docs/brainstorm/brain-integrity-suite/pr-body.md (not served here)
- docs/brainstorm/brain-integrity-suite/variants.md (not served here)
- docs/brainstorm/brain-lifecycle-review-suite/cli-output/claude.md (not served here)
- docs/brainstorm/brain-lifecycle-review-suite/cli-output/prompt.md (not served here)
- docs/brainstorm/brain-lifecycle-review-suite/design.md (not served here)
- docs/brainstorm/brain-lifecycle-review-suite/plan.md (not served here)
- docs/brainstorm/brain-lifecycle-review-suite/variants.md (not served here)
- docs/brainstorm/brain-lifecycle-suite/cli-output/claude.md (not served here)
- docs/brainstorm/brain-lifecycle-suite/cli-output/prompt.md (not served here)
- docs/brainstorm/brain-lifecycle-suite/design.md (not served here)
- docs/brainstorm/brain-lifecycle-suite/plan.md (not served here)
- docs/brainstorm/brain-lifecycle-suite/variants.md (not served here)
- docs/brainstorm/brain-model-semantics-foundation/adr.md (not served here)
- docs/brainstorm/brain-model-semantics-foundation/cli-output/claude.md (not served here)
- docs/brainstorm/brain-model-semantics-foundation/cli-output/prompt.md (not served here)
- docs/brainstorm/brain-model-semantics-foundation/design.md (not served here)
- docs/brainstorm/brain-model-semantics-foundation/plan.md (not served here)
- docs/brainstorm/brain-model-semantics-foundation/variants.md (not served here)
- docs/brainstorm/brain-portability-interop/cli-output/claude.md (not served here)
- docs/brainstorm/brain-portability-interop/cli-output/prompt.md (not served here)
- docs/brainstorm/brain-portability-interop/design.md (not served here)
- docs/brainstorm/brain-portability-interop/plan.md (not served here)
- docs/brainstorm/brain-portability-interop/variants.md (not served here)
- docs/brainstorm/brain-safety-governance-suite/cli-output/claude.md (not served here)
- docs/brainstorm/brain-safety-governance-suite/cli-output/prompt.md (not served here)
- docs/brainstorm/brain-safety-governance-suite/design.md (not served here)
- docs/brainstorm/brain-safety-governance-suite/plan.md (not served here)
- docs/brainstorm/brain-safety-governance-suite/variants.md (not served here)
- docs/brainstorm/cjk-schema-lifecycle-recovery/cli-output/claude.md (not served here)
- docs/brainstorm/cjk-schema-lifecycle-recovery/cli-output/prompt.md (not served here)
- docs/brainstorm/cjk-schema-lifecycle-recovery/design.md (not served here)
- docs/brainstorm/cjk-schema-lifecycle-recovery/plan.md (not served here)
- docs/brainstorm/cjk-schema-lifecycle-recovery/variants.md (not served here)
- docs/brainstorm/codegraph-link-depth-mcp/cli-output/claude.md (not served here)
- docs/brainstorm/codegraph-link-depth-mcp/cli-output/prompt.md (not served here)
- docs/brainstorm/codegraph-link-depth-mcp/design.md (not served here)
- docs/brainstorm/codegraph-link-depth-mcp/plan.md (not served here)
- docs/brainstorm/codegraph-link-depth-mcp/variants.md (not served here)
- docs/brainstorm/codegraph-mcp-operational-readability/cli-output/claude.md (not served here)
- docs/brainstorm/codegraph-mcp-operational-readability/cli-output/prompt.md (not served here)
- docs/brainstorm/codegraph-mcp-operational-readability/design.md (not served here)
- docs/brainstorm/codegraph-mcp-operational-readability/plan.md (not served here)
- docs/brainstorm/codegraph-mcp-operational-readability/variants.md (not served here)
- docs/brainstorm/context-continuity-receipts-suite/cli-output/claude.md (not served here)
- docs/brainstorm/context-continuity-receipts-suite/cli-output/prompt.md (not served here)
- docs/brainstorm/context-continuity-receipts-suite/design.md (not served here)
- docs/brainstorm/context-continuity-receipts-suite/plan.md (not served here)
- docs/brainstorm/context-continuity-receipts-suite/variants.md (not served here)
- docs/brainstorm/context-injection-pipeline/cli-output/consultant.md (not served here)
- docs/brainstorm/context-injection-pipeline/cli-output/prompt.md (not served here)
- docs/brainstorm/context-injection-pipeline/design.md (not served here)
- docs/brainstorm/context-injection-pipeline/plan.md (not served here)
- docs/brainstorm/context-injection-pipeline/variants.md (not served here)
- docs/brainstorm/context-integrity-gates/cli-output/claude.md (not served here)
- docs/brainstorm/context-integrity-gates/cli-output/prompt.md (not served here)
- docs/brainstorm/context-integrity-gates/design.md (not served here)
- docs/brainstorm/context-integrity-gates/plan.md (not served here)
- docs/brainstorm/context-integrity-gates/variants.md (not served here)
- docs/brainstorm/context-pack-economics-observability/cli-output/claude.md (not served here)
- docs/brainstorm/context-pack-economics-observability/cli-output/prompt.md (not served here)
- docs/brainstorm/context-pack-economics-observability/design.md (not served here)
- docs/brainstorm/context-pack-economics-observability/plan.md (not served here)
- docs/brainstorm/context-pack-economics-observability/variants.md (not served here)
- docs/brainstorm/continuity-hygiene-freshness/cli-output/claude.md (not served here)
- docs/brainstorm/continuity-hygiene-freshness/cli-output/prompt.md (not served here)
- docs/brainstorm/continuity-hygiene-freshness/design.md (not served here)
- docs/brainstorm/continuity-hygiene-freshness/plan.md (not served here)
- docs/brainstorm/continuity-hygiene-freshness/variants.md (not served here)
- docs/brainstorm/cross-agent-query-foundation/cli-output/claude.md (not served here)
- docs/brainstorm/cross-agent-query-foundation/cli-output/prompt.md (not served here)
- docs/brainstorm/cross-agent-query-foundation/design.md (not served here)
- docs/brainstorm/cross-agent-query-foundation/plan.md (not served here)
- docs/brainstorm/cross-agent-query-foundation/variants.md (not served here)
- docs/brainstorm/crossvault-cards-eventtrace-fixes/design.md (not served here)
- docs/brainstorm/crossvault-cards-eventtrace-fixes/plan.md (not served here)
- docs/brainstorm/crossvault-cards-eventtrace-fixes/variants.md (not served here)
- docs/brainstorm/cycle-20261020/cli-output/claude.md (not served here)
- docs/brainstorm/cycle-20261020/cli-output/prompt.md (not served here)
- docs/brainstorm/cycle-20261020/design.md (not served here)
- docs/brainstorm/cycle-20261020/plan.md (not served here)
- docs/brainstorm/cycle-20261020/variants.md (not served here)
- docs/brainstorm/dated-commitments/cli-output/claude.md (not served here)
- docs/brainstorm/dated-commitments/cli-output/prompt.md (not served here)
- docs/brainstorm/dated-commitments/design.md (not served here)
- docs/brainstorm/dated-commitments/plan.md (not served here)
- docs/brainstorm/dated-commitments/variants.md (not served here)
- docs/brainstorm/default-scope-feedback/cli-output/claude.md (not served here)
- docs/brainstorm/default-scope-feedback/cli-output/prompt.md (not served here)
- docs/brainstorm/default-scope-feedback/design.md (not served here)
- docs/brainstorm/default-scope-feedback/plan.md (not served here)
- docs/brainstorm/default-scope-feedback/variants.md (not served here)
- docs/brainstorm/delivery-trust/cli-output/consultant.md (not served here)
- docs/brainstorm/delivery-trust/cli-output/prompt.md (not served here)
- docs/brainstorm/delivery-trust/design.md (not served here)
- docs/brainstorm/delivery-trust/plan.md (not served here)
- docs/brainstorm/delivery-trust/variants.md (not served here)
- docs/brainstorm/distilled-provenance/cli-output/claude.md (not served here)
- docs/brainstorm/distilled-provenance/cli-output/expected-output.md (not served here)
- docs/brainstorm/distilled-provenance/cli-output/prompt.md (not served here)
- docs/brainstorm/distilled-provenance/design.md (not served here)
- docs/brainstorm/distilled-provenance/plan.md (not served here)
- docs/brainstorm/distilled-provenance/variants.md (not served here)
- docs/brainstorm/embedding-provider-suite/cli-output/claude.md (not served here)
- docs/brainstorm/embedding-provider-suite/cli-output/prompt.md (not served here)
- docs/brainstorm/embedding-provider-suite/design.md (not served here)
- docs/brainstorm/embedding-provider-suite/plan.md (not served here)
- docs/brainstorm/embedding-provider-suite/variants.md (not served here)
- docs/brainstorm/entity-truth-dream-suite/cli-output/claude.md (not served here)
- docs/brainstorm/entity-truth-dream-suite/cli-output/prompt.md (not served here)
- docs/brainstorm/entity-truth-dream-suite/design.md (not served here)
- docs/brainstorm/entity-truth-dream-suite/plan.md (not served here)
- docs/brainstorm/entity-truth-dream-suite/variants.md (not served here)
- docs/brainstorm/evidence-at-the-boundary/cli-output/claude.md (not served here)
- docs/brainstorm/evidence-at-the-boundary/cli-output/prompt.md (not served here)
- docs/brainstorm/evidence-at-the-boundary/design.md (not served here)
- docs/brainstorm/evidence-at-the-boundary/plan.md (not served here)
- docs/brainstorm/evidence-at-the-boundary/recon/0e79f0-lint-on-write.md (not served here)
- docs/brainstorm/evidence-at-the-boundary/recon/130-hermes-readiness.md (not served here)
- docs/brainstorm/evidence-at-the-boundary/recon/155-include-paths.md (not served here)
- docs/brainstorm/evidence-at-the-boundary/recon/160-source-trust.md (not served here)
- docs/brainstorm/evidence-at-the-boundary/recon/161-slug-race.md (not served here)
- docs/brainstorm/evidence-at-the-boundary/recon/3309-retrieval-trail.md (not served here)
- docs/brainstorm/evidence-at-the-boundary/recon/a3254-readiness-liveness.md (not served here)
- docs/brainstorm/evidence-at-the-boundary/recon/conventions.md (not served here)
- docs/brainstorm/evidence-at-the-boundary/recon/e24c6d-schema-completeness.md (not served here)
- docs/brainstorm/evidence-at-the-boundary/recon/e5f447-recall-channels.md (not served here)
- docs/brainstorm/evidence-at-the-boundary/variants.md (not served here)
- docs/brainstorm/grok-native-integration/cli-output/claude.md (not served here)
- docs/brainstorm/grok-native-integration/cli-output/prompt.md (not served here)
- docs/brainstorm/grok-native-integration/design.md (not served here)
- docs/brainstorm/grok-native-integration/plan.md (not served here)
- docs/brainstorm/grok-native-integration/variants.md (not served here)
- docs/brainstorm/hermes-memory-provider/cli-output/claude.md (not served here)
- docs/brainstorm/hermes-memory-provider/cli-output/prompt.md (not served here)
- docs/brainstorm/hermes-memory-provider/design.md (not served here)
- docs/brainstorm/hermes-memory-provider/plan.md (not served here)
- docs/brainstorm/hermes-memory-provider/variants.md (not served here)
- docs/brainstorm/hermes-static-tool-schemas/cli-output/claude.md (not served here)
- docs/brainstorm/hermes-static-tool-schemas/cli-output/prompt.md (not served here)
- docs/brainstorm/hermes-static-tool-schemas/design.md (not served here)
- docs/brainstorm/hermes-static-tool-schemas/plan.md (not served here)
- docs/brainstorm/hermes-static-tool-schemas/variants.md (not served here)
- docs/brainstorm/hindsight-brain-loop-ops/cli-output/claude.md (not served here)
- docs/brainstorm/hindsight-brain-loop-ops/cli-output/prompt.md (not served here)
- docs/brainstorm/hindsight-brain-loop-ops/design.md (not served here)
- docs/brainstorm/hindsight-brain-loop-ops/plan.md (not served here)
- docs/brainstorm/hindsight-brain-loop-ops/variants.md (not served here)
- docs/brainstorm/honest-embedding-spend/cli-output/claude.md (not served here)
- docs/brainstorm/honest-embedding-spend/cli-output/prompt.md (not served here)
- docs/brainstorm/honest-embedding-spend/design.md (not served here)
- docs/brainstorm/honest-embedding-spend/plan.md (not served here)
- docs/brainstorm/honest-embedding-spend/variants.md (not served here)
- docs/brainstorm/honest-query-embed-and-safe-upgrades/cli-output/claude.md (not served here)
- docs/brainstorm/honest-query-embed-and-safe-upgrades/cli-output/prompt.md (not served here)
- docs/brainstorm/honest-query-embed-and-safe-upgrades/design.md (not served here)
- docs/brainstorm/honest-query-embed-and-safe-upgrades/plan.md (not served here)
- docs/brainstorm/honest-query-embed-and-safe-upgrades/variants.md (not served here)
- docs/brainstorm/hook-update-resilience/design.md (not served here)
- docs/brainstorm/hook-update-resilience/plan.md (not served here)
- docs/brainstorm/hook-update-resilience/variants.md (not served here)
- docs/brainstorm/index-freshness/design.md (not served here)
- docs/brainstorm/index-freshness/plan.md (not served here)
- docs/brainstorm/indexer-durability/cli-output/claude.md (not served here)
- docs/brainstorm/indexer-durability/cli-output/prompt.md (not served here)
- docs/brainstorm/indexer-durability/design.md (not served here)
- docs/brainstorm/indexer-durability/plan.md (not served here)
- docs/brainstorm/indexer-durability/variants.md (not served here)
- docs/brainstorm/ingestion-import-robustness/design.md (not served here)
- docs/brainstorm/ingestion-import-robustness/plan.md (not served here)
- docs/brainstorm/ingestion-import-robustness/variants.md (not served here)
- docs/brainstorm/integrity-control-agent-memory-surface/cli-output/claude.md (not served here)
- docs/brainstorm/integrity-control-agent-memory-surface/cli-output/prompt.md (not served here)
- docs/brainstorm/integrity-control-agent-memory-surface/design.md (not served here)
- docs/brainstorm/integrity-control-agent-memory-surface/plan.md (not served here)
- docs/brainstorm/integrity-control-agent-memory-surface/variants.md (not served here)
- docs/brainstorm/knowledge-intake-and-consolidation/cli-output/claude.md (not served here)
- docs/brainstorm/knowledge-intake-and-consolidation/cli-output/prompt.md (not served here)
- docs/brainstorm/knowledge-intake-and-consolidation/design.md (not served here)
- docs/brainstorm/knowledge-intake-and-consolidation/plan.md (not served here)
- docs/brainstorm/knowledge-intake-and-consolidation/variants.md (not served here)
- docs/brainstorm/knowledge-provenance/cli-output/claude.md (not served here)
- docs/brainstorm/knowledge-provenance/cli-output/prompt.md (not served here)
- docs/brainstorm/knowledge-provenance/design.md (not served here)
- docs/brainstorm/knowledge-provenance/plan.md (not served here)
- docs/brainstorm/knowledge-provenance/variants.md (not served here)
- docs/brainstorm/language-agnostic-fact-extraction/cli-output/claude.md (not served here)
- docs/brainstorm/language-agnostic-fact-extraction/cli-output/prompt.md (not served here)
- docs/brainstorm/language-agnostic-fact-extraction/design.md (not served here)
- docs/brainstorm/language-agnostic-fact-extraction/plan.md (not served here)
- docs/brainstorm/language-agnostic-fact-extraction/variants.md (not served here)
- docs/brainstorm/link-graph-surfaces/cli-output/claude.md (not served here)
- docs/brainstorm/link-graph-surfaces/cli-output/prompt.md (not served here)
- docs/brainstorm/link-graph-surfaces/design.md (not served here)
- docs/brainstorm/link-graph-surfaces/plan.md (not served here)
- docs/brainstorm/link-graph-surfaces/variants.md (not served here)
- docs/brainstorm/link-recall-intelligence/cli-output/claude.md (not served here)
- docs/brainstorm/link-recall-intelligence/cli-output/prompt.md (not served here)
- docs/brainstorm/link-recall-intelligence/design.md (not served here)
- docs/brainstorm/link-recall-intelligence/plan.md (not served here)
- docs/brainstorm/link-recall-intelligence/variants.md (not served here)
- docs/brainstorm/manifest-dependency-facts/cli-output/claude.md (not served here)
- docs/brainstorm/manifest-dependency-facts/cli-output/expected-output.md (not served here)
- docs/brainstorm/manifest-dependency-facts/cli-output/prompt.md (not served here)
- docs/brainstorm/manifest-dependency-facts/design.md (not served here)
- docs/brainstorm/manifest-dependency-facts/plan.md (not served here)
- docs/brainstorm/manifest-dependency-facts/variants.md (not served here)
- docs/brainstorm/mcp-context-economy/cli-output/claude.md (not served here)
- docs/brainstorm/mcp-context-economy/cli-output/prompt.md (not served here)
- docs/brainstorm/mcp-context-economy/design.md (not served here)
- docs/brainstorm/mcp-context-economy/plan.md (not served here)
- docs/brainstorm/mcp-context-economy/variants.md (not served here)
- docs/brainstorm/mcp-error-codes/cli-output/claude.md (not served here)
- docs/brainstorm/mcp-error-codes/cli-output/prompt.md (not served here)
- docs/brainstorm/mcp-error-codes/design.md (not served here)
- docs/brainstorm/mcp-error-codes/plan.md (not served here)
- docs/brainstorm/mcp-error-codes/variants.md (not served here)
- docs/brainstorm/memory-integrity/cli-output/claude.md (not served here)
- docs/brainstorm/memory-integrity/cli-output/prompt.md (not served here)
- docs/brainstorm/memory-integrity/design.md (not served here)
- docs/brainstorm/memory-integrity/plan.md (not served here)
- docs/brainstorm/memory-integrity/variants.md (not served here)
- docs/brainstorm/memory-observability-suite/atof-atif-mapping.md (not served here)
- docs/brainstorm/memory-observability-suite/cli-output/claude.md (not served here)
- docs/brainstorm/memory-observability-suite/cli-output/prompt.md (not served here)
- docs/brainstorm/memory-observability-suite/design.md (not served here)
- docs/brainstorm/memory-observability-suite/plan.md (not served here)
- docs/brainstorm/memory-observability-suite/variants.md (not served here)
- docs/brainstorm/memory-signal-provenance-lifecycle/cli-output/claude.md (not served here)
- docs/brainstorm/memory-signal-provenance-lifecycle/cli-output/prompt.md (not served here)
- docs/brainstorm/memory-signal-provenance-lifecycle/design.md (not served here)
- docs/brainstorm/memory-signal-provenance-lifecycle/plan.md (not served here)
- docs/brainstorm/memory-signal-provenance-lifecycle/variants.md (not served here)
- docs/brainstorm/memory-subsystem-alignment/cli-output/claude.md (not served here)
- docs/brainstorm/memory-subsystem-alignment/cli-output/prompt.md (not served here)
- docs/brainstorm/memory-subsystem-alignment/design.md (not served here)
- docs/brainstorm/memory-subsystem-alignment/plan.md (not served here)
- docs/brainstorm/memory-subsystem-alignment/variants.md (not served here)
- docs/brainstorm/memory-write-path-integrity/cli-output/claude.md (not served here)
- docs/brainstorm/memory-write-path-integrity/cli-output/prompt.md (not served here)
- docs/brainstorm/memory-write-path-integrity/design.md (not served here)
- docs/brainstorm/memory-write-path-integrity/plan.md (not served here)
- docs/brainstorm/memory-write-path-integrity/variants.md (not served here)
- docs/brainstorm/near-duplicate-defense/cli-output/claude.md (not served here)
- docs/brainstorm/near-duplicate-defense/cli-output/codex.md (not served here)
- docs/brainstorm/near-duplicate-defense/cli-output/opencode.md (not served here)
- docs/brainstorm/near-duplicate-defense/cli-output/prompt.md (not served here)
- docs/brainstorm/near-duplicate-defense/cli-output/second-claude.md (not served here)
- docs/brainstorm/near-duplicate-defense/design.md (not served here)
- docs/brainstorm/near-duplicate-defense/plan.md (not served here)
- docs/brainstorm/near-duplicate-defense/variants.md (not served here)
- docs/brainstorm/no-dead-ends/cli-output/claude.md (not served here)
- docs/brainstorm/no-dead-ends/cli-output/prompt.md (not served here)
- docs/brainstorm/no-dead-ends/design.md (not served here)
- docs/brainstorm/no-dead-ends/plan.md (not served here)
- docs/brainstorm/no-dead-ends/variants.md (not served here)
- docs/brainstorm/non-markdown-ingest/cli-output/claude.md (not served here)
- docs/brainstorm/non-markdown-ingest/cli-output/expected-output.md (not served here)
- docs/brainstorm/non-markdown-ingest/cli-output/prompt.md (not served here)
- docs/brainstorm/non-markdown-ingest/design.md (not served here)
- docs/brainstorm/non-markdown-ingest/plan.md (not served here)
- docs/brainstorm/non-markdown-ingest/variants.md (not served here)
- docs/brainstorm/note-change-truth-maintenance/cli-output/claude.md (not served here)
- docs/brainstorm/note-change-truth-maintenance/cli-output/prompt.md (not served here)
- docs/brainstorm/note-change-truth-maintenance/cli-output/task-bodies.md (not served here)
- docs/brainstorm/note-change-truth-maintenance/design.md (not served here)
- docs/brainstorm/note-change-truth-maintenance/plan.md (not served here)
- docs/brainstorm/note-change-truth-maintenance/variants.md (not served here)
- docs/brainstorm/nothing-runs-unwatched/cli-output/claude.md (not served here)
- docs/brainstorm/nothing-runs-unwatched/cli-output/prompt.md (not served here)
- docs/brainstorm/nothing-runs-unwatched/design.md (not served here)
- docs/brainstorm/nothing-runs-unwatched/plan.md (not served here)
- docs/brainstorm/nothing-runs-unwatched/recon/architect-module.md (not served here)
- docs/brainstorm/nothing-runs-unwatched/recon/concurrency-and-cancellation.md (not served here)
- docs/brainstorm/nothing-runs-unwatched/recon/durability-and-ownership.md (not served here)
- docs/brainstorm/nothing-runs-unwatched/recon/failure-mode-bench.md (not served here)
- docs/brainstorm/nothing-runs-unwatched/recon/ingest-adapters-and-lease.md (not served here)
- docs/brainstorm/nothing-runs-unwatched/recon/progress-reporting.md (not served here)
- docs/brainstorm/nothing-runs-unwatched/recon/provider-sunset.md (not served here)
- docs/brainstorm/nothing-runs-unwatched/review/claims-and-refusals.md (not served here)
- docs/brainstorm/nothing-runs-unwatched/review/cross-cutting.md (not served here)
- docs/brainstorm/nothing-runs-unwatched/review/locks-and-races.md (not served here)
- docs/brainstorm/nothing-runs-unwatched/review/progress-and-cancellation.md (not served here)
- docs/brainstorm/nothing-runs-unwatched/review/tests-and-docs.md (not served here)
- docs/brainstorm/nothing-runs-unwatched/variants.md (not served here)
- docs/brainstorm/nothing-writes-silently/cli-output/claude.md (not served here)
- docs/brainstorm/nothing-writes-silently/cli-output/prompt.md (not served here)
- docs/brainstorm/nothing-writes-silently/design.md (not served here)
- docs/brainstorm/nothing-writes-silently/plan.md (not served here)
- docs/brainstorm/nothing-writes-silently/variants.md (not served here)
- docs/brainstorm/opencode-native-integration/cli-output/claude.md (not served here)
- docs/brainstorm/opencode-native-integration/cli-output/prompt.md (not served here)
- docs/brainstorm/opencode-native-integration/design.md (not served here)
- docs/brainstorm/opencode-native-integration/plan.md (not served here)
- docs/brainstorm/opencode-native-integration/variants.md (not served here)
- docs/brainstorm/operability-first-run/design.md (not served here)
- docs/brainstorm/operability-first-run/plan.md (not served here)
- docs/brainstorm/operability-first-run/variants.md (not served here)
- docs/brainstorm/operational-friction-reduction/design.md (not served here)
- docs/cli-reference.md
- docs/cross-project-pointer.md
- docs/decision-models.md
- docs/hermes-cron.md
- docs/how-it-works.md
- docs/idea.md
- docs/ingest-manifest.md
- docs/mcp.md
- docs/metrics.md
- docs/observability.md
- docs/stability.md
- docs/updating.md
- hooks/hooks.json
- install.md
- plugins/codex/LICENSE
Advantages
- Human-readable and editable memory stored as standard Markdown files in an Obsidian vault. evidence: README.md
- Deterministic dream pass ensures rules are derived from repeated signals without requiring additional model runs. evidence: README.md
- Supports reversible changes through snapshots and rollback capabilities. evidence: README.md
Limitations
- Requires Bun runtime for the CLI and core operations. evidence: README.md
- Advanced features like semantic search require additional setup with sqlite-vec. evidence: README.md
- Some integrations depend on specific client-side plugin support or MCP host capabilities. evidence: README.md
Security
Risk level: Low risk
This brain runs
MCP servers (2)
.claude-plugin/plugin.json(open-second-brain):${CLAUDE_PLUGIN_ROOT}/scripts/o2b mcp --harness claude-code.claude-plugin/plugin.json(open-second-brain-writer):${CLAUDE_PLUGIN_ROOT}/scripts/o2b mcp --scope writer --harness claude-code
Git hooks (2)
.githooks/pre-commit(pre-commit):runs on git pre-commit.githooks/pre-push(pre-push):runs on git pre-push
Agent instructions that run or fetch something (46)
CLAUDE.md:bun run scripts/sync-version.tsCLAUDE.md:CI gates on `bun run scripts/sync-version.ts --check` (the `validate` job, step "Verify manifest version sync").CLAUDE.md:Run the `--check` form locally before pushing a version change.CLAUDE.md:Bump `package.json` (and run `sync-version.ts`) on the feature branch and include it in the SAME pull request as the feature, before you push.CLAUDE.md:Bump `package.json` to `X.Y.Z` and run `bun run scripts/sync-version.ts`.CLAUDE.md:After changing a skill or `hooks/hooks.json`, run:CLAUDE.md:bun run sync-plugin-mirrorsCLAUDE.md:CI gates on `bun run sync-plugin-mirrors:check` (the `validate` and `windows` jobs), and the pre-commit hook runs the same check.docs/legacy-skills/agent-event-log/SKILL.md:Read-only queries (running `git log`, `o2b status`, `vault_health`, `second_brain_query`).docs/legacy-skills/agent-event-log/SKILL.md:**Technical identifiers stay verbatim regardless of surrounding language**: command names (`bun test`, `o2b doctor`), file paths (`src/core/event-log.ts`), package and library names (`proper-lockfile`, `@anthropic-ai/sdk`), API symbols, error messages quoted from logs.plugins/codex/skills/brain-memory/SKILL.md:Read-only inspection (running `git log`, `o2b status`, `vault_health`).plugins/codex/skills/brain-memory/SKILL.md:After scan, the source line becomes `@osb✓ [[sig-...]]` so a second run is idempotent.plugins/codex/skills/codegraph-partner/SKILL.md:Run these checks in order.plugins/codex/skills/codegraph-partner/SKILL.md:No install talk.plugins/codex/skills/codegraph-partner/SKILL.md:| | not_indexed (CLI present, no `.codegraph/` or `initialized: false`) | Offer one line: "run `codegraph init <path>` to index this repo".plugins/codex/skills/codegraph-partner/SKILL.md:Whenever you run `codegraph init` in any repository on the user's behalf, immediately read that repo's `.gitignore` and append a `.codegraph/` line if one is not already present.plugins/codex/skills/decision-model-setup/SKILL.md:That is the operator's command, and only the operator can run it: the key is operator-only, so the `brain_settings` tool refuses an agent's write to it with `operator_only_setting` on every machine, switched or not.plugins/codex/skills/decision-model-setup/SKILL.md:Ask the operator to run the command;plugins/codex/skills/decision-model-setup/SKILL.md:Does not install servers or download model weights.plugins/codex/skills/embeddings-setup/SKILL.md:Every run that uses it prints one stderr warning per endpoint.plugins/codex/skills/embeddings-setup/SKILL.md:If the install path missed it, force a rebuild:plugins/codex/skills/embeddings-setup/SKILL.md:bun pm ls | grep sqlite-vecplugins/codex/skills/embeddings-setup/SKILL.md:bun install --forceplugins/codex/skills/embeddings-setup/SKILL.md:When the index already exists and only some chunks lack vectors, price the work first with the dry run, then apply it:plugins/codex/skills/embeddings-setup/SKILL.md:Does not invoke `brew install` on the user's behalf.plugins/codex/skills/schema-author/SKILL.md:Preview the batch first with `schema_apply_mutations` (`dry_run=true`) or `o2b brain schema apply --dry-run --mutation ...`: it returns the pack that would result and its diff and writes nothing at all - no config write, no audit record, no lock file.plugins/codex/skills/schema-author/SKILL.md:It does not run the two checks that exist only because the apply writes: the vault-identity write guard, and the atomic writer's re-parse of the rendered YAML.plugins/codex/skills/schema-author/SKILL.md:Re-run lint/stats after mutation and report changed tokens plus any remaining findings.skills/brain-memory/SKILL.md:Read-only inspection (running `git log`, `o2b status`, `vault_health`).skills/brain-memory/SKILL.md:After scan, the source line becomes `@osb✓ [[sig-...]]` so a second run is idempotent.skills/codegraph-partner/SKILL.md:Run these checks in order.skills/codegraph-partner/SKILL.md:No install talk.skills/codegraph-partner/SKILL.md:| | not_indexed (CLI present, no `.codegraph/` or `initialized: false`) | Offer one line: "run `codegraph init <path>` to index this repo".skills/codegraph-partner/SKILL.md:Whenever you run `codegraph init` in any repository on the user's behalf, immediately read that repo's `.gitignore` and append a `.codegraph/` line if one is not already present.skills/decision-model-setup/SKILL.md:That is the operator's command, and only the operator can run it: the key is operator-only, so the `brain_settings` tool refuses an agent's write to it with `operator_only_setting` on every machine, switched or not.skills/decision-model-setup/SKILL.md:Ask the operator to run the command;skills/decision-model-setup/SKILL.md:Does not install servers or download model weights.skills/embeddings-setup/SKILL.md:Every run that uses it prints one stderr warning per endpoint.skills/embeddings-setup/SKILL.md:If the install path missed it, force a rebuild:skills/embeddings-setup/SKILL.md:bun pm ls | grep sqlite-vecskills/embeddings-setup/SKILL.md:bun install --forceskills/embeddings-setup/SKILL.md:When the index already exists and only some chunks lack vectors, price the work first with the dry run, then apply it:skills/embeddings-setup/SKILL.md:Does not invoke `brew install` on the user's behalf.skills/schema-author/SKILL.md:Preview the batch first with `schema_apply_mutations` (`dry_run=true`) or `o2b brain schema apply --dry-run --mutation ...`: it returns the pack that would result and its diff and writes nothing at all - no config write, no audit record, no lock file.skills/schema-author/SKILL.md:It does not run the two checks that exist only because the apply writes: the vault-identity write guard, and the atomic writer's re-parse of the rendered YAML.skills/schema-author/SKILL.md:Re-run lint/stats after mutation and report changed tokens plus any remaining findings.
Hooks (54)
hooks/hooks.json(PostToolUse):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0hooks/hooks.json(PostToolUse):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" post-write-reminder; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook post-write-reminder; exit 0hooks/hooks.json(PostToolUse):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" subagent-inject; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook subagent-inject; exit 0hooks/hooks.json(PostToolUse):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" reground-deliver; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook reground-deliver; exit 0hooks/hooks.json(SessionStart):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" active-inject; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook active-inject; exit 0hooks/hooks.json(SessionStart):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" gap-agenda; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook gap-agenda; exit 0hooks/hooks.json(SessionStart):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" backlog-nudge; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook backlog-nudge; exit 0hooks/hooks.json(SessionStart):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" log-catchup; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook log-catchup; exit 0hooks/hooks.json(SessionStart):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" view-render; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook view-render; exit 0hooks/hooks.json(SessionStart):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0hooks/hooks.json(UserPromptSubmit):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0hooks/hooks.json(UserPromptSubmit):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" recall-inject; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook recall-inject; exit 0hooks/hooks.json(UserPromptSubmit):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" nav-inject; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook nav-inject; exit 0hooks/hooks.json(UserPromptSubmit):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" counterparty-brief; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook counterparty-brief; exit 0hooks/hooks.json(UserPromptSubmit):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" reground-deliver; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook reground-deliver; exit 0hooks/hooks.json(PreToolUse):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" pretool-orient; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook pretool-orient; exit 0hooks/hooks.json(PreToolUse):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" pretool-host-backup; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook pretool-host-backup; exit 0hooks/hooks.json(Stop):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0hooks/hooks.json(Stop):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" stop-log-guardrail; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook stop-log-guardrail; exit 0hooks/hooks.json(Stop):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" answer-quote-check; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook answer-quote-check; exit 0hooks/hooks.json(Stop):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" hygiene-digest; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook hygiene-digest; exit 0hooks/hooks.json(SubagentStart):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" subagent-inject; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook subagent-inject; exit 0hooks/hooks.json(SubagentStop):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0hooks/hooks.json(SessionEnd):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0hooks/hooks.json(SessionEnd):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" gap-promote; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook gap-promote; exit 0hooks/hooks.json(PostCompact):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" active-inject; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook active-inject; exit 0hooks/hooks.json(PostCompact):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0plugins/codex/hooks/hooks.json(PostToolUse):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0plugins/codex/hooks/hooks.json(PostToolUse):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" post-write-reminder; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook post-write-reminder; exit 0plugins/codex/hooks/hooks.json(PostToolUse):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" subagent-inject; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook subagent-inject; exit 0plugins/codex/hooks/hooks.json(PostToolUse):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" reground-deliver; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook reground-deliver; exit 0plugins/codex/hooks/hooks.json(SessionStart):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" active-inject; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook active-inject; exit 0plugins/codex/hooks/hooks.json(SessionStart):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" gap-agenda; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook gap-agenda; exit 0plugins/codex/hooks/hooks.json(SessionStart):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" backlog-nudge; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook backlog-nudge; exit 0plugins/codex/hooks/hooks.json(SessionStart):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" log-catchup; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook log-catchup; exit 0plugins/codex/hooks/hooks.json(SessionStart):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" view-render; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook view-render; exit 0plugins/codex/hooks/hooks.json(SessionStart):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0plugins/codex/hooks/hooks.json(UserPromptSubmit):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0plugins/codex/hooks/hooks.json(UserPromptSubmit):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" recall-inject; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook recall-inject; exit 0plugins/codex/hooks/hooks.json(UserPromptSubmit):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" nav-inject; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook nav-inject; exit 0plugins/codex/hooks/hooks.json(UserPromptSubmit):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" counterparty-brief; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook counterparty-brief; exit 0plugins/codex/hooks/hooks.json(UserPromptSubmit):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" reground-deliver; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook reground-deliver; exit 0plugins/codex/hooks/hooks.json(PreToolUse):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" pretool-orient; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook pretool-orient; exit 0plugins/codex/hooks/hooks.json(PreToolUse):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" pretool-host-backup; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook pretool-host-backup; exit 0plugins/codex/hooks/hooks.json(Stop):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0plugins/codex/hooks/hooks.json(Stop):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" stop-log-guardrail; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook stop-log-guardrail; exit 0plugins/codex/hooks/hooks.json(Stop):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" answer-quote-check; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook answer-quote-check; exit 0plugins/codex/hooks/hooks.json(Stop):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" hygiene-digest; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook hygiene-digest; exit 0plugins/codex/hooks/hooks.json(SubagentStart):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" subagent-inject; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook subagent-inject; exit 0plugins/codex/hooks/hooks.json(SubagentStop):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0plugins/codex/hooks/hooks.json(SessionEnd):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0plugins/codex/hooks/hooks.json(SessionEnd):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" gap-promote; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook gap-promote; exit 0plugins/codex/hooks/hooks.json(PostCompact):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" active-inject; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook active-inject; exit 0plugins/codex/hooks/hooks.json(PostCompact):r="$CLAUDE_PLUGIN_ROOT"; if [ -n "$r" ] && [ -x "$r/scripts/o2b-hook" ]; then exec "$r/scripts/o2b-hook" session-capture; fi; command -v o2b-hook >/dev/null 2>&1 && exec o2b-hook session-capture; exit 0
Package scripts (1)
package.json(prepare):bun scripts/prepare.ts || exit 0
- Low risk: scripts-present (.githooks/pre-commit)
- Low risk: scripts-present (.githooks/pre-push)
- Low risk: network-instructions (plugins/codex/skills/codegraph-partner/SKILL.md:115)
- Low risk: scripts-present (scripts/prepare.ts)
- Low risk: network-instructions (skills/codegraph-partner/SKILL.md:115)
Attribution and licence
- First committed by
hermes-vps-agent
- Declared authors
- Open Second Brain contributors (declared in .claude-plugin/plugin.json)
- Open Second Brain contributors (declared in pyproject.toml)
- Publisher
- Serg Eroshe (Community)
- Source
- itechmeat/open-second-brain · commit 233b91d
- Licence
- MIT License (files served here)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
- Contributors
- solaitken, itechmeat, Yori940619, hermes-vps-agent, DanBennettUK
AutoGineer is not affiliated with or endorsed by hermes-vps-agent or Serg Eroshe.
Install from source
486 of its files are not served here, so there is no ZIP. itechmeat/open-second-brain at 233b91d