Repository navigation
v1.70.0 - Operator Rules Scoped to the Project, the Harness and the Host - Per-Profile Hermes Settings and Readers That Answer at the Caller's Reach
Open Second Brain v1.70.0 - Operator Rules Scoped to the Project, the Harness and the Host - Per-Profile Hermes Settings and Readers That Answer at the Caller's Reach
Before this release, a rule or a setting meant for one context carried over into every other: the operator standing rules in Open Second Brain were one vault-wide file, and on a Hermes gateway that multiplexes profiles the plugin read its settings from the gateway process environment, which belongs to the launch profile. Version 1.70.0 (#229) resolves scope per serving context: the MCP server derives one identity from the project, the harness and the host, the operator can write standing rules for one project, one harness or one machine under Brain/standing-rules/, which the SessionStart hook and brain_context render below the vault-wide operator standing rules at local reach within their own cap, and on a multiplexed Hermes gateway each profile reads its settings from its own profile scope and gets its own MCP child. The today, monthly and operator brief views, the doctor and a long list of readers and writers now treat a page or record the caller cannot read at its reach as absent, and a page derived from reserved records carries their visibility.
What ships
- Scoped operator rules. Beside the vault-wide
Brain/standing-rules.md, the operator can write one file per scope value:Brain/standing-rules/project/<key>.md,Brain/standing-rules/harness/<harness id>.mdandBrain/standing-rules/host/<device id>.md. Each session renders the files whose key matches its own project, harness and device under a## Scoped operator rulesheader that states the precedence (below the operator standing rules, above every recalled preference, lesson and context pack), one subheading per file. The operator's text is never rewritten, the files are read on every render and never cached, and they render only at local reach; a file that cannot be read becomes oneUNAVAILABLE:line with its vault-relative path and an error code (ESCAPEfor a file or folder behind a symbolic link that leaves the vault). - A server-resolved scope identity. No caller names its own scope. The project is the basename of the directory holding the nearest
.o2b-vault.jsonpointer (written byo2b brain project link), the harness comes from the launch-time--harnessoption, falling back to--host-target, and the host is the device id. Keys are normalised (NFC, lowercase) to letters, combining marks, digits and-in any script, at most 64 characters; an axis that does not resolve matches no file. o2b mcp --harness <id>. Names the harness the server runs under, from a closed list (aider,claude-code,codex,copilot-cli,cursor,gemini-cli,generic,grok,hermes,kiro,openclaw,opencode,pi); an unknown value exits 2 and lists the accepted ones. The Claude Code plugin registers both of its MCP servers with--harness claude-code, and the Hermes plugin launches its bridge with--harness hermes. A refused--host-targetvalue is now echoed JSON-quoted with its control characters escaped, like a refused--harnessvalue.scoped_rulesonbrain_context. At local reach, when at least one scoped file matched, the scoped block follows the standing rules incontentand the result carriesscoped_rules: {scope: {project, harness, host}, files: [{path, axis, truncated}]}with vault-relative paths. No input argument is added.- Its own cap, charged to the injection budget.
active.scoped_rules_max_charscaps the scoped block (default 2000, at least 200); when the cap cuts anything the host file drops first, then the harness file, and a notice states the kept and total characters and the number of dropped files. In the SessionStart hook, which renders the project and host files, the block's length is subtracted frominject_budget_charsbefore the active context is assembled, and the receipt'sbudgetblock records it asscoped_rules_chars. - Scoped rule files cannot be written by an agent. Every write path that refuses
Brain/standing-rules.mdnow also refuses any path insideBrain/standing-rules/, compared as written and after resolving symbolic links, and a rules folder behind a symbolic link that leaves the vault no longer makes the other guarded writes fail. - Per-profile Hermes settings on a multiplexed gateway. With
gateway.multiplex_profileson,VAULT_DIR,VAULT_AGENT_NAME,VAULT_TIMEZONE,OPEN_SECOND_BRAIN_CONFIGandOPEN_SECOND_BRAIN_MCP_TIMEOUTare read from the turn's Hermes profile scope (the profile's.env), never from the gateway process environment;XDG_CONFIG_HOMEandLOCALAPPDATAare read from the profile scope first. A setting the profile does not hold falls through to the config chain. Without multiplexing every answer is unchanged. - Each Hermes profile gets its own MCP child. The child's environment carries the profile's own agent name, timezone, config path and vault, and two profiles that differ in any of those or in their config directories no longer share one child. A profile-scoped variable set in the gateway environment is named once per process with one WARNING, without its value; a turn with no bound profile scope raises a named
ProfileScopeErrorand the per-turn vault reminder is omitted with one WARNING instead of failing the turn. settings_source:inhermes open-second-brain config. The first line names the source the command resolved from: the profile scope of a multiplexed gateway, or the process environment. A non-finiteOPEN_SECOND_BRAIN_MCP_TIMEOUTis read as meant:nanis a malformed value that keeps the default deadline,infdisables the deadline.- The today, monthly and operator brief views and the doctor answer at the caller's reach. Below local reach
brain_briefview="today"no longer lists an open loop or obligation on a page the caller cannot read,view="monthly"counts from the events the caller may see,view="operator"computes its doctor and digest counts, top actions, verification entries and trust verdict from what the caller may see, andbrain_doctorfills its caps, counts stale-dependency rows, runs its concept-gap and contradiction detectors, lists instruction-file warnings and plans itsrepairpreview from readable pages and records only. - More readers and writers treat a page or record the caller cannot read at its reach as absent.
brain_obligation,brain_intention,brain_intent_review,brain_healthconcept gaps,brain_triggerscans,brain_stale_scan,brain_review_candidatesand its signal clusters,brain_retention,brain_context_receipts,brain_tension,brain_lifecycle,brain_expire,brain_apply_evidence, thebrain_feedbackhints,brain_derive_fact,brain_decision,brain_labels,brain_scaffold_stub,brain_dead_ends,brain_diarize,brain_hygienerefreshandbrain_anticipatory_context; a write aimed at such a page is refused before anything is written. Below local reachbrain_dreamserves a dry run andbrain_maintenancerefusesrun. A local caller and the CLI see no change. - Derived pages keep the visibility of their sources. A preference drafted by the dream pass from reserved signals, or superseding or rebutting a reserved record, carries the strictest visibility of those sources, and a persisted tension page carries the stricter visibility of its two source notes.
- Fixes along the way.
brain_retentionrecommendations and forget-plan entries carry the vault-relative path, so a trigger scan queues a readable retention row;brain_intentionlistjudges each chain by its own file name; at local reachbrain_maintenancerunis allowed even whenintegrity.owner_scope_deliveryisfail; and thebrain_scaffold_stubambiguity refusal no longer ends in an empty candidate list.
Docs
docs/how-it-works.mdgains "Scoped operator rules",docs/mcp.mdthescoped_ruleskey and--harness,docs/cli-reference.mdtheo2b mcp --harnessline,docs/observability.mdthescoped_rules_charsfield,docs/stability.mdthe two new layers,install/hermes.md"Multiple Hermes profiles" anddocs/updating.md"Upgrading to 1.70.0"; the README names this release (#229).
Install or update
# Claude Code
claude plugin marketplace update open-second-brain
claude plugin update open-second-brain@open-second-brain
# Codex
codex plugin marketplace upgrade open-second-brain
# Hermes
hermes plugins update open-second-brain
# Every other runtime, then confirm
o2b update
o2b doctorNew installs start from the README and the guides in install/. Hermes users update o2b and the Hermes plugin together: the plugin now launches its bridge as o2b mcp --harness hermes, and an o2b older than 1.70.0 refuses the flag, so the bridge does not start until o2b is updated as well; the Claude Code plugin runs the o2b it ships and needs no step. On a multiplexed gateway, a profile that relied on the launch profile's environment now falls through to the config chain, so move such a setting into that profile's .env. A vault without Brain/standing-rules/ renders exactly as before.
Process wins
- The thread through the release is that a rule or a setting meant for one context stays in that context: a project's conventions render only in that project, a machine's notes only on that machine, and one Hermes profile's vault and timezone only in that profile's turns.
- Three review rounds (self-review and a focused review each) ran on the branch with every finding fixed and pinned by a test that failed first, and two test audits confirmed the pins red under mutation; the reach changes carry A/B tests through the real MCP server (a vault with the unreadable page against one without, normalised answers identical) in 23 test files; an OpenCodeReview delegation pass over 93 of 93 reviewable files found 13 findings, all fixed, and the architecture gate against the merge base found no new violation.
- Quality record (the PR's verification, under Bun 1.4.0, the CI pin): full test suite 15,088 pass / 19 skip / 0 fail across 1,430 files, Python plugin tests 199 OK (2 skipped) on Python 3.11 and the static-schema anti-drift test passing against the live tool list, typecheck green, lint at 0 errors, formatting, install, version sync, plugin mirrors, link ratchet, OpenClaw bundle and Hermes scan all green.
Notes
- Harness-scoped files render on the MCP surfaces only in this release; the SessionStart hook renders the project and host files. There are no combination scope files (for example project and host together); the matching single-axis files are joined instead.
- Other variables the TypeScript core reads from the environment (search settings, the MCP API key, embedding keys, the Telegram settings) still come from the gateway process environment on a multiplexed Hermes gateway, and the shared Hermes bridge resolves the gateway's working directory, so it usually matches no project-scoped file.
- The CodeRabbit review was skipped by its 100-file limit (the change set is 166 files).
- Full entries: CHANGELOG.md, PR #229, compare v1.69.0...v1.70.0.
- The version bump to 1.70.0 shipped inside the feature PR (#229), per the project rule in
CLAUDE.md. - Release image: the canonical terminal style, here as an interaction diagram (animated GIF in this body; static PNG, 2x PNG and the SVG source attached as assets).
