What leaves your machine
Per harness, what the @valorbrain/connect hooks send, where, with which credential, how often and how to turn them off. All of it taken from the code.
This page describes the automatic traffic that @valorbrain/connect
(version 0.9.0, hook protocol v2) installs in each harness: what the hooks send
without the agent asking. The MCP tool calls the agent makes on its own
(memory_store, memory_retrieve…) carry whatever the model decides to send
and are not covered here.
Hooks installed by earlier versions move to 0.9.0 through self-heal (below),
except Codex: self-heal leaves Codex hooks alone unless the contract
changes, so a Codex install from before 0.9.0 keeps the 0.8.1 hooks until you
run the installer again (and trust the hooks in /hooks). Until then a saved
--checkpoint off does nothing on Codex; only VALORBRAIN_CHECKPOINT=off turns
the checkpoint off there.
Every number below comes from the source code. Where the code does not settle something, the page says not determined in the code.
Summary
| Harness | Hooked events | What leaves per event | Config file |
|---|---|---|---|
| Claude Code | SessionStart, UserPromptSubmit, Stop | start: ids; prompt: up to 8,000 characters; stop: counters only. With opt-in (--transcript on, connect ≥ 0.10.1), stop also sends the session transcript (up to 8 MiB), at most every 10 min | ~/.claude/settings.json |
| Codex | SessionStart, UserPromptSubmit, Stop | same as Claude Code, but the session transcript (opt-in) needs connect ≥ 0.12.0 | ~/.codex/hooks.json |
| Gemini CLI | SessionStart, BeforeAgent, AfterAgent | same as Claude Code, but the session transcript (opt-in) needs connect ≥ 0.12.0 | ~/.gemini/settings.json |
| Kiro | SessionStart, UserPromptSubmit, Stop (V3) or agentSpawn, userPromptSubmit, stop (legacy) | same as Claude Code, but the session transcript (opt-in) needs connect ≥ 0.12.0 | ~/.kiro/hooks/valorbrain.json (V3) or ~/.kiro/agents/valorbrain.json (legacy) |
| Cursor | sessionStart, stop | start: ids; stop: counters only. No prompt hook. With opt-in (--transcript on, connect ≥ 0.12.0), stop also sends the session transcript (up to 8 MiB), at most every 10 min | ~/.cursor/hooks.json |
| Grok CLI | Stop | counters only. With opt-in (--transcript on, connect ≥ 0.10.1), also the session transcript (up to 8 MiB), at most every 10 min | ~/.grok/hooks/valorbrain.json |
| OpenCode | plugin: chat.message; session.idle only with the transcript on | prompt: up to 8,000 characters. With opt-in (--transcript on, plugin v2 with connect ≥ 0.12.0), also the main session's transcript (up to 8 MiB), at most every 10 min | ~/.config/opencode/plugins/valorbrain.ts |
| Hermes Agent | MemoryProvider plugin: start, every turn, compression, session end | each turn's prompt; the session transcript (up to 8 MiB) only with opt-in (--transcript on) | ~/.hermes/config.yaml + ~/.hermes/plugins/valorbrain/__init__.py |
| Oh My Pi (OMP) | own bridge (session_start, every turn, turn end, session end) | start: ids; prompt: up to 8,000 characters; turn end: counters only; the session transcript (up to 8 MiB) only with opt-in (--transcript on) | ~/.omp/agent/hooks/pre/valorbrain.ts |
OpenClaw is not installed by @valorbrain/connect and is out of scope here.
The shared hook client
Claude Code, Codex, Gemini CLI, Kiro, Cursor, Grok and OpenCode run the same
client: npx -y @valorbrain/connect@0.9.0 hook <event> --harness=<id>. The version
is pinned (never latest): the hook runs on every prompt, so only a reviewed
version reaches your machine. It reads the JSON the harness passes on stdin and
sends only the fields below.
Endpoint
POST https://valorbrain-api.valor.digital/api/v1/hooks/cue, with
Authorization: Bearer <token> and content-type: application/json.
If the route answers 404 or 405 (engine without hooks/cue; the result is
cached for 6 hours) or 403 (an old engine that treats the POST as a write), the
client takes the legacy path: an MCP memory_prepare call on
POST https://valorbrain-api.valor.digital/mcp with message (the prompt cut
to 8,000 characters, or "session start") and fast_mode: true.
Body per event
| Moment | Fields sent |
|---|---|
| Session start | harness, session_id, event: "session_start", and source when the harness sends that field |
| Prompt | harness, session_id, event: "prompt", prompt (the first 8,000 characters), and source when present |
| Stop | harness, session_id, event: "stop", and state with five numbers: turns, busy_ms, checkpoints, session_started_at, last_checkpoint_at |
Stop sends no conversation text. When the server answers with a checkpoint, the client hands that text to the harness's own model, which decides what to record through MCP. Whatever the model records leaves through that MCP call, not through the hook. The one exception is the transcript upload below, which exists only with opt-in.
Transcript (opt-in: Claude Code and Grok with connect ≥ 0.10.1; Codex, Gemini CLI, Kiro, Cursor and OpenCode with connect ≥ 0.12.0)
Off by default. Turn it on per harness with
npx -y @valorbrain/connect --harness <id> --transcript on (writes
send_transcript: true in that harness's entry of ~/.valorbrain/connect.json;
--transcript off writes false) or for the whole machine with
VALORBRAIN_SEND_TRANSCRIPT=on, which wins over the file both ways (off,
0, false, no / on, 1, true, yes). Only an explicit on sends. This
Stop upload exists from the 0.10.1 hook on for Claude Code and Grok, and from
0.12.0 on for Codex, Gemini CLI, Kiro, Cursor and OpenCode: the hook runs the
version the engine pins, and an older hook does not make it even with the
switch on.
| Harnesses | Claude Code, Grok CLI, Codex, Gemini CLI, Kiro, Cursor and OpenCode. A Stop uploads only through its own harness's hook file: Cursor running Claude Code's settings.json, or Grok running Cursor's hooks.json, does not upload with the other harness's credential. (The exception for extraction hooks wired by hand, on any harness, is right below) |
| What leaves | the session's transcript file (where the hook finds it, per harness, is in the next table), its whole content as the harness writes it, up to 8 MiB. Above that, for a JSONL file only the end of the file is sent, and each line dropped from the head becomes an empty line; a single-file JSON transcript (older Gemini CLI) above 8 MiB is not cut and is not sent. Along with it: sessionId, hookEventName: "Stop", workingDir (the session's directory) and, only for Claude Code with CLAUDE_CODE_SESSION_ATTENDED=1, sessionAttended: "1". OpenCode writes no transcript file: plugin v2 builds one on every session.idle at ~/.valorbrain/state/opencode/<session>.jsonl (on your disk only, 0600) with what you typed, the assistant's text and the tool calls. Each tool's input (as JSON) and output are cut at 2,000 characters, with a …[truncated N chars] marker: an edit or write carries the whole file in its input, and that content does not leave whole. Model reasoning, attached files and synthetic parts are left out. That file is what leaves, under the same rules. The plugin removes files in that directory that have been idle for more than 7 days |
| Endpoint | POST https://valorbrain-api.valor.digital/api/v1/hooks/run, two calls per upload: episode-extractor, then decision-extractor |
| When | at Stop, after 3 Stops of the session; later ones only when the file grew and 10 min passed since the last upload. At most 8 uploads per 10 min per harness. Only a person's main session uploads: the runs left out are listed below the table. Also never for a continuation Stop (stop_hook_active), a Grok turn that did not end with end_turn, or a Cursor or OpenCode turn that did not end as completed. A 401, 403 or 413 pauses the harness's uploads for 6 h; a 429, for 30 min |
| How | a separate (detached) process uploads; the hook does not wait for it. Each request is cut at 180 s. Failures go to ~/.valorbrain/connect.log, one line, never content |
Where the hook finds the file:
| Harness | File |
|---|---|
| Claude Code | the payload's transcript_path |
| Grok CLI | the payload's transcriptPath |
| Codex | the payload's transcript_path: the rollout under ~/.codex/sessions/ |
| Gemini CLI | AfterAgent's transcript_path: ~/.gemini/tmp/<project>/chats/session-*.jsonl (older versions: a single .json file) |
| Cursor | the payload's transcript_path or CURSOR_TRANSCRIPT_PATH; without them, by conversation_id under ~/.cursor/projects/<workspace>/agent-transcripts/ (<id>.jsonl or <id>/<id>.jsonl). .jsonl files only |
| Kiro | the payload carries no path, only session_id and cwd. Kiro CLI 3.0 / --v3: ~/.kiro/sessions/<sha256 of cwd, 16 characters>/<sess_…>/messages.jsonl, and, when the cwd hash misses, the same <sess_…>/messages.jsonl in any directory under ~/.kiro/sessions/. Legacy engine: ~/.kiro/sessions/cli/<id>.jsonl |
| OpenCode | the JSONL the plugin writes under ~/.valorbrain/state/opencode/ |
Runs that never upload, even with the switch on:
- Claude Code: an SDK-driven session (
CLAUDE_CODE_ENTRYPOINTstarting withsdk) and every session Claude Code marks as unattended (CLAUDE_CODE_SESSION_ATTENDED=0:-p/SDK, background sessions and a claude started by another claude). With=1, the upload carriessessionAttended: "1", and the engine takes facts only from turns a person typed. Without the variable, the field is not sent. - Codex:
codex exec(what the Codex SDK runs),codex mcp-server, SDK clients of the app-server and sub-agent threads. The hook reads this from the rollout'ssession_metaline (source,thread_source,originator); a rollout without that line does not upload either. - Gemini CLI:
gemini -p/--prompt, Gemini with the query on the command line (without-i) and Gemini in CI (CI=trueorGITHUB_ACTIONS=true), Gemini's own "headless" rule; sub-agent sessions (kind: "subagent"in the file). On a GitHub runner Gemini does not passCIorGITHUB_ACTIONSto the hook (see the Gemini CLI section); there only the command-line check applies. - Kiro:
kiro-cli chat --no-interactive; on the legacy engine, sessions an ACP client opened (session_created_reason: "subagent"in~/.kiro/sessions/cli/<id>.json). - Cursor:
cursor-agent -p/--print. Cursor'sstopfires only for the main conversation; subagents havesubagentStop, which connect does not wire. - OpenCode: subagent sessions (with a
parentID) are never read.
Gemini CLI, Kiro and Cursor say neither in the payload nor in the environment
that a run is non-interactive. The hook runs one ps (Linux and macOS), walks
the process tree up from its parent and reads the harness process's command
line. None of this leaves the machine. Where there is no ps (Windows) or it
fails, this check does not happen and the run counts as interactive: only the
3-Stop floor applies.
Hand-wired legacy extraction hooks (decision-extractor, episode-extractor,
handoff-generator, feedback-loop, precompact-extract) keep uploading the
transcript while the switch is unset: wiring them by hand is the opt-in. With
--transcript off (or VALORBRAIN_SEND_TRANSCRIPT=off), a 0.10.1 or later hook
neither reads nor sends the transcript, and the hooks that only read the
transcript are not called at all.
Credential
The token is looked up in this order, and the first match wins:
--token=on the command line (installs older than protocol v2 only; self-heal migrates it to the file).- The
VALORBRAIN_TOKENenvironment variable. - This harness's entry in
~/.valorbrain/connect.json(mode 0600, one entry per harness). This is thevbm_…token the installer wrote. api_keyin~/.valorbrain/config.json(the CLI's file).
The API base is --api=, then VALORBRAIN_API_URL, then the base saved with
the token, and finally https://valorbrain-api.valor.digital. Without a token
the hook makes no network call and writes one line to stderr.
Cadence
- Synchronous, not fire-and-forget: the harness waits for the answer,
because it becomes context. The client cuts each request at 4 s
(
VALORBRAIN_HOOK_TIMEOUT_MSchanges it). The harness kills the process at 10 s (Gemini: 10,000 ms). - Session start: one call. A second start in the same session within 20 s makes no network call.
- Prompt: one call per prompt. An empty prompt makes none. With prompt
sending off for the harness (
--prompt off, below), the prompt hook makes no network call. - Stop: most stops send nothing. The decision is local, and the client
only calls the server when a checkpoint is due. Default policy (the server's
answer overrides it): at least 3 turns, or 2 turns adding up to
8 min of work; at least 10 min apart (never less than 1 min); at most
6 checkpoints per session. A stop without
session_idmakes no call. - Server-side limit: 300 calls per 10 min per token
(
VALORBRAIN_HOOK_CUE_MAX_PER_10MINon the engine). - Every error exits with code 0 and at most one stderr line; the hook never blocks the prompt.
Maintenance traffic (self-heal)
Every hook run also attempts a self-heal, limited to once every 6 hours per
machine (tracked in ~/.valorbrain/connect-state.json;
VALORBRAIN_HEAL_INTERVAL_MS changes the interval) and to 2.5 s of waiting
on the hook path:
GET https://valorbrain-api.valor.digital/setup/artifacts?agent=<id>&hooks=2, without a credential. The manifest is used only if it carries a valid ed25519 signature from one of the keys built into connect (the active one or the reserve;X-ValorBrain-Manifest-*headers; the public key in use is at/setup/manifest-keys); without one nothing is written. If the contract changed, it rewrites the harness's rules and hooks locally (Codex is left out of automatic hook migration), except files you edited by hand: those stay as they are and the warning goes to stderr and~/.valorbrain/connect.log. Running the installer again shows the diff and asks before overwriting.POST https://valorbrain-api.valor.digital/api/v1/runtimes/registerwith the token, within 2.5 s. It sendsruntime_key(<harness>:<hostname>:<home path>),agent_platform,display_name,hostname,plugin_version: "0.9.0"andcapabilities(harness, installed contract version,connector: "connect",self_heal: true, hook protocol).
The same declaration is sent once at the end of every install.
During install
Without --token, the installer opens the computer approval:
POST https://valorbrain.valor.digital/api/v1/cli/device/code with
client: "connect", the list of harnesses, device_label
(<hostname> (<operating system>), up to 80 characters) and install_id (16 random
hex characters kept in ~/.valorbrain/install-id). It then polls
/api/v1/cli/device/token until approval.
Source: /www/valorbrain-cli/packages/connect/hook.mjs,
/www/valorbrain-cli/packages/connect/index.mjs,
/www/valorbrain-cli/packages/connect/login.mjs,
/opt/valorbrain/src/hooks/cue.ts, /opt/valorbrain/src/server.ts
Per harness
Claude Code
| Events | SessionStart, UserPromptSubmit, Stop (10 s timeout each) |
| What leaves | start: ids; prompt: up to 8,000 characters; stop: counters only, and only when a checkpoint is due. With the transcript on (opt-in), stop also sends the session transcript (see "Transcript" above) |
| Endpoint | POST https://valorbrain-api.valor.digital/api/v1/hooks/cue |
| Credential | Bearer with the vbm_… token from the claude-code entry in ~/.valorbrain/connect.json (full order above) |
| Cadence | 1 call per session start and per prompt; stop per the policy |
| Turn off | hooks only: npx -y @valorbrain/connect --token <vbm_…> --harness claude-code --mcp-only; everything (MCP, rules, hooks, credential): npx -y @valorbrain/connect --harness claude-code --remove; or delete the entries containing @valorbrain/connect in ~/.claude/settings.json; checkpoint only: npx -y @valorbrain/connect --harness claude-code --checkpoint off or VALORBRAIN_CHECKPOINT=off; transcript (off by default): --transcript on / --transcript off or VALORBRAIN_SEND_TRANSCRIPT |
SDK-driven Claude Code sessions (CLAUDE_CODE_ENTRYPOINT starting with sdk)
never get a checkpoint and make no network call on stop. With the transcript
on, a session with CLAUDE_CODE_SESSION_ATTENDED=0 does not upload it either,
and with =1 the upload carries sessionAttended: "1" (connect ≥ 0.12.0; see
"Transcript" above).
Source: /opt/valorbrain/src/harness/adapters.ts (claude-code adapter),
/www/valorbrain-cli/packages/connect/hook.mjs
Codex
| Events | SessionStart, UserPromptSubmit, Stop (10 s timeout each) |
| What leaves | same as Claude Code. With the transcript on (opt-in, connect ≥ 0.12.0), stop also sends the session's rollout; codex exec, codex mcp-server, SDK clients and sub-agents never upload (see "Transcript" above) |
| Endpoint | POST https://valorbrain-api.valor.digital/api/v1/hooks/cue |
| Credential | codex entry in ~/.valorbrain/connect.json |
| Cadence | same as Claude Code |
| Turn off | hooks only: npx -y @valorbrain/connect --token <vbm_…> --harness codex --mcp-only; everything (MCP, rules, hooks, credential): npx -y @valorbrain/connect --harness codex --remove; or delete the entries containing @valorbrain/connect in ~/.codex/hooks.json; checkpoint only: npx -y @valorbrain/connect --harness codex --checkpoint off (0.9.0 hooks) or VALORBRAIN_CHECKPOINT=off; transcript (off by default): --transcript on / --transcript off or VALORBRAIN_SEND_TRANSCRIPT |
Codex asks you to review and trust changed hooks once, in /hooks. That is
why self-heal does not migrate Codex hooks on its own: an install from before
0.9.0 keeps the 0.8.1 hooks, which do not read a saved --checkpoint off, until
you run the installer again.
Source: /opt/valorbrain/src/harness/adapters.ts (codexHooksArtifact),
/opt/valorbrain/src/harness/hosted.ts
Gemini CLI
| Events | SessionStart, BeforeAgent (prompt), AfterAgent (stop), 10,000 ms timeout each |
| What leaves | same as Claude Code. With the transcript on (opt-in, connect ≥ 0.12.0), AfterAgent also sends the session file; gemini -p, a query on the command line, CI and sub-agents never upload (see "Transcript" above) |
| Endpoint | POST https://valorbrain-api.valor.digital/api/v1/hooks/cue |
| Credential | gemini-cli entry in ~/.valorbrain/connect.json (full order above). With Gemini's environment redaction on, VALORBRAIN_TOKEN does not reach the hook (its name contains TOKEN), and the file is what counts |
| Cadence | same as Claude Code |
| Turn off | hooks only: npx -y @valorbrain/connect --token <vbm_…> --harness gemini-cli --mcp-only; everything (MCP, rules, hooks, credential): npx -y @valorbrain/connect --harness gemini-cli --remove; or delete the valorbrain-* entries under hooks in ~/.gemini/settings.json; prompt: npx -y @valorbrain/connect --harness gemini-cli --prompt off; checkpoint: npx -y @valorbrain/connect --harness gemini-cli --checkpoint off; transcript (off by default): --transcript on / --transcript off. The VALORBRAIN_SEND_PROMPT, VALORBRAIN_CHECKPOINT and VALORBRAIN_SEND_TRANSCRIPT variables work too, except on a GitHub runner (below) |
Gemini CLI (0.43) passes its hooks its own process environment, plus the
GEMINI_* variables. It filters that environment in two cases only:
- with
security.environmentVariableRedaction.enabled: truein Gemini'ssettings.json: variables with secret-like names (TOKEN,KEY,SECRET,AUTH,PASSWORD…), a few fixed names and those listed inblockedare dropped; - on a GitHub runner (
GITHUB_SHAset, orSURFACE=Github): only a short list (PATH,HOME,TERM…) and those listed inallowedpass.
So VALORBRAIN_SEND_PROMPT, VALORBRAIN_CHECKPOINT and
VALORBRAIN_SEND_TRANSCRIPT reach the hook and work as on the other harnesses,
except on a GitHub runner. The choices saved in ~/.valorbrain/connect.json
(--prompt, --checkpoint, --transcript) always work. On a GitHub runner
CI and GITHUB_ACTIONS do not reach the hook either; there, what keeps the
transcript from being sent is the command-line check (-p or a query in argv).
Source: /opt/valorbrain/src/harness/adapters.ts (geminiHooksArtifact),
/opt/valorbrain/src/harness/hosted.ts
Kiro
| Events | V3 engine (default): SessionStart, UserPromptSubmit, Stop in the standalone file. Legacy engine (--kiro-engine=legacy): agentSpawn, userPromptSubmit, stop in the agent config, with timeout: 10000 |
| What leaves | same as Claude Code. With the transcript on (opt-in, connect ≥ 0.12.0), stop also sends the session file, which the hook finds by session_id under ~/.kiro/sessions/; kiro-cli chat --no-interactive and, on the legacy engine, sessions opened by an ACP client never upload (see "Transcript" above) |
| Endpoint | POST https://valorbrain-api.valor.digital/api/v1/hooks/cue |
| Credential | kiro entry in ~/.valorbrain/connect.json |
| Cadence | same as Claude Code. Connect sets no timeout in the V3 file; Kiro's default is not determined in the code |
| Turn off | hooks only: npx -y @valorbrain/connect --token <vbm_…> --harness kiro --mcp-only; everything: npx -y @valorbrain/connect --harness kiro --remove (MCP, rules, credential and the files of both modes); or delete ~/.kiro/hooks/valorbrain.json and ~/.kiro/agents/valorbrain.json; checkpoint only: npx -y @valorbrain/connect --harness kiro --checkpoint off or VALORBRAIN_CHECKPOINT=off; transcript (off by default): --transcript on / --transcript off or VALORBRAIN_SEND_TRANSCRIPT |
With --scope workspace, the file goes to .kiro/ inside the project.
Source: /opt/valorbrain/src/harness/adapters.ts (kiro adapter),
/www/valorbrain-cli/packages/connect/index.mjs (scopedManifest)
Cursor
| Events | sessionStart, stop (10 s timeout each). No prompt hook: beforeSubmitPrompt can block a prompt but cannot add context |
| What leaves | start: ids; stop: counters only. With the transcript on (opt-in, connect ≥ 0.12.0), stop also sends the conversation's .jsonl transcript; cursor-agent -p and turns that did not end as completed never upload (see "Transcript" above) |
| Endpoint | POST https://valorbrain-api.valor.digital/api/v1/hooks/cue |
| Credential | cursor entry in ~/.valorbrain/connect.json |
| Cadence | 1 call per session start; stop per the policy. Cursor itself caps follow-ups per conversation (loop_limit, default 5) |
| Turn off | hooks only: npx -y @valorbrain/connect --token <vbm_…> --harness cursor --mcp-only; everything (MCP, rules, hooks, credential): npx -y @valorbrain/connect --harness cursor --remove; or delete the entries containing valorbrain in ~/.cursor/hooks.json; checkpoint only: npx -y @valorbrain/connect --harness cursor --checkpoint off or VALORBRAIN_CHECKPOINT=off; transcript (off by default): --transcript on / --transcript off or VALORBRAIN_SEND_TRANSCRIPT |
Cursor also loads ~/.claude/settings.json. When it fires Claude Code's prompt
hook, the client recognizes Cursor from the payload and does not call
hooks/cue. A Cursor stop arriving through that file does not upload the
transcript: only ~/.cursor/hooks.json does, with the cursor credential.
Source: /opt/valorbrain/src/harness/adapters.ts (cursorHooksArtifact),
/www/valorbrain-cli/packages/connect/hook.mjs
Grok CLI
| Events | Stop (10 s timeout). Grok discards the output of passive events, so start and prompt are not wired |
| What leaves | counters only, and only when a checkpoint is due and the turn ended with end_turn. With the transcript on (opt-in), also the session transcript (see "Transcript" above) |
| Endpoint | POST https://valorbrain-api.valor.digital/api/v1/hooks/cue |
| Credential | grok entry in ~/.valorbrain/connect.json |
| Cadence | stop per the policy |
| Turn off | hooks only: npx -y @valorbrain/connect --token <vbm_…> --harness grok --mcp-only; everything (MCP, rules, hooks, credential): npx -y @valorbrain/connect --harness grok --remove; or delete ~/.grok/hooks/valorbrain.json; checkpoint only: npx -y @valorbrain/connect --harness grok --checkpoint off or VALORBRAIN_CHECKPOINT=off; transcript (off by default): --transcript on / --transcript off or VALORBRAIN_SEND_TRANSCRIPT |
Grok also loads ~/.cursor/hooks.json. A session start arriving through that
file with Grok's payload does not call hooks/cue.
Source: /opt/valorbrain/src/harness/adapters.ts (grok adapter),
/www/valorbrain-cli/packages/connect/hook.mjs
OpenCode
| Events | plugin: chat.message (every user message). With the transcript on, also session.idle (end of each turn) of the main session. No session start |
| What leaves | the message text, cut to 8,000 characters in the plugin and again in the client, plus session_id. With the transcript on (opt-in, plugin v2 and connect ≥ 0.12.0), the stop also sends the main session's transcript (see "Transcript" above). Off, the plugin does not read the session |
| Endpoint | POST https://valorbrain-api.valor.digital/api/v1/hooks/cue (the plugin runs connect's hook client: hook context-surfacing --format=text --harness=opencode). With the transcript on, the plugin also runs hook stop --harness=opencode, which uploads to POST …/api/v1/hooks/run |
| Credential | opencode entry in ~/.valorbrain/connect.json |
| Cadence | 1 call per message; the plugin kills the process after 9 s. With the transcript on, 1 stop per turn of the main session, and the upload follows the "Transcript" rules above |
| Turn off | VALORBRAIN_OPENCODE_DISABLE=true; plugin only: npx -y @valorbrain/connect --token <vbm_…> --harness opencode --mcp-only; everything (MCP, rules, plugin, credential): npx -y @valorbrain/connect --harness opencode --remove; or delete ~/.config/opencode/plugins/valorbrain.ts; transcript (off by default): --transcript on / --transcript off or VALORBRAIN_SEND_TRANSCRIPT |
Once per load, the plugin also fetches
GET https://valorbrain-api.valor.digital/setup/artifacts?agent=opencode (or the
base in VALORBRAIN_URL) without a credential, and sends
POST <origin of the MCP URL in opencode.json>/api/v1/runtimes/register with
the token from opencode.json, hostname, the home path and the contract
version (2.5 s timeout). VALORBRAIN_OPENCODE_DISABLE=true turns this off too.
Source: /opt/valorbrain/src/harness/adapters.ts (opencodePluginSource)
Hermes Agent
Hermes does not use the shared hook client. Connect writes a Python
MemoryProvider plugin that, without a local valorbrain binary, runs the hooks
on the engine.
| Events | session start (session-bootstrap); every turn of 5 or more characters (context-surfacing, on a background thread); compression (precompact-extract, then postcompact-inject on the next turn); session end (decision-extractor, handoff-generator, feedback-loop in parallel) |
| What leaves | on turns: hook, sessionId, hookEventName and the full prompt (no client-side cut). The session transcript (~/.hermes/valorbrain-transcripts/<session>.jsonl, up to 8 MiB, every user message and every assistant reply) leaves only with opt-in: without it the plugin does not even write the file, and the session-end and compression extraction does not run |
| Endpoint | POST <VALORBRAIN_ENGINE_URL>/api/v1/hooks/run. Fallbacks: GET /api/v1/memory/working-context?format=md at start and POST /api/v1/memory/prepare (prompt, recall_budget: 600, fast_mode: true) per turn |
| Credential | Authorization: Bearer with VALORBRAIN_API_TOKEN, which the installer writes under env in ~/.hermes/config.yaml (the same vbm_… as MCP). Extra headers: X-Source-Agent, X-Source-System (default hermes) and, when set, X-Tenant-ID and X-User-ID |
| Cadence | timeouts: 30 s for lifecycle hooks, 90 s for context-surfacing, 5 s for REST calls |
| Turn off | prompt: npx -y @valorbrain/connect --harness hermes --prompt off or VALORBRAIN_SEND_PROMPT=off in the env of ~/.hermes/config.yaml (no per-turn recall). Transcript (opt-in): --transcript on or VALORBRAIN_SEND_TRANSCRIPT=on. Everything: npx -y @valorbrain/connect --harness hermes --remove (removes mcp_servers.valorbrain, memory.provider, the env keys and the plugin); or change memory.provider in ~/.hermes/config.yaml |
Hermes has no hooks in the manifest: --mcp-only changes nothing there. The
memory plugin stays installed and sends the prompt of each turn; to stop it,
use --prompt off (or --remove, which takes everything out).
Other plugin calls: GET /foundations?limit=10 and GET /health at start;
POST /api/v1/runtimes/register at start (with hostname);
POST /api/v1/runtimes/heartbeat at most every 300 s; and
GET /setup/instructions when the message asks to set up ValorBrain.
Non-primary contexts (subagent, cron, flush) neither write the transcript nor run the session-end and compression extraction.
The engine accepts at most 40 hooks/run calls per 10 min per tenant.
Source: /opt/valorbrain/src/hermes/__init__.py,
/opt/valorbrain/src/harness/adapters.ts (hermes adapter),
/www/valorbrain-cli/packages/connect/index.mjs (mergeYaml)
Oh My Pi (OMP)
OMP has no command hooks: it loads TS factories from ~/.omp/agent/hooks/pre/.
In hosted mode (manifest hooks=2, from the engine release that ships the
hosted bridge), connect writes the bridge to ~/.omp/agent/hooks/pre/valorbrain.ts.
It talks HTTP to the engine directly (fetch), with no npx per event. Before
that engine release, connect writes only the MCP entry and the rules, and there
is no automatic traffic.
| Events | session_start, before_agent_start (each user turn, main session only), session_stop (end of each turn), session_shutdown (end of session) |
| What leaves | start: ids; prompt: the first 8,000 characters; turn end: counters only, and only when a checkpoint is due. The session transcript leaves only with opt-in: each user message and each assistant reply (text parts only; tool output cut at 500 characters; internal reasoning left out), with each turn's time, up to 8 MiB (above that, the oldest lines are sent empty). Subagents never send |
| Endpoint | context and checkpoint: POST https://valorbrain-api.valor.digital/api/v1/hooks/cue; transcript (opt-in): POST https://valorbrain-api.valor.digital/api/v1/hooks/run with episode-extractor, then decision-extractor, and input with sessionId, hookEventName and workingDir (the session's directory) |
| Credential | VALORBRAIN_TOKEN, then the omp entry in ~/.valorbrain/connect.json, then api_key in ~/.valorbrain/config.json. The bridge only reads these files, never writes them |
| Cadence | 1 call per session start and per prompt, each cut at 4 s; checkpoint per the policy. Transcript (opt-in): the first upload and the session-end upload only after at least 3 user turns since the previous upload, so a short run never uploads; mid-session, later uploads at least 10 min apart and only with new conversation. 2 calls per upload. omp -p (print and json modes) never uploads. The upload runs in a separate bun process so OMP's exit never waits on it; the token reaches that process through its environment, never the disk; a 401, 403, 413 or 429 stops the upload |
| Turn off | prompt: npx -y @valorbrain/connect --harness omp --prompt off or VALORBRAIN_SEND_PROMPT=off; checkpoint: --checkpoint off or VALORBRAIN_CHECKPOINT=off; transcript (opt-in, off by default): --transcript on or VALORBRAIN_SEND_TRANSCRIPT=on turn it on, --transcript off or VALORBRAIN_SEND_TRANSCRIPT=off turn it off; the bridge only: npx -y @valorbrain/connect --token <vbm_…> --harness omp --mcp-only; everything: npx -y @valorbrain/connect --harness omp --remove; or delete ~/.omp/agent/hooks/pre/valorbrain.ts |
Failures go to ~/.omp/agent/valorbrain-hooks.log (0600), one line per failure
or upload, never content or the token. The bridge does not run the connect
client, so self-heal does not update it: a new version arrives when you run the
installer again.
Source: /opt/valorbrain/src/harness/omp-bridge-hosted.ts,
/opt/valorbrain/src/harness/adapters.ts (omp adapter)
What does not leave
This applies to the shared hook client (every harness above except Hermes and
OMP, which have their own clients). For the OMP bridge with the transcript off
(the default) the same holds: nothing beyond the three hooks/cue bodies.
- Transcript: the hooks the installer wires (
session-start,prompt,stop) do not read the transcript file unless the switch is on. Apart from the three bodies above, the legacy fallback and self-heal, they send nothing. With--transcript on, Claude Code and Grok, and from connect 0.12.0 on Codex, Gemini CLI, Kiro, Cursor and OpenCode, send the transcript as described in "Transcript" above. To find the file and to decide whether a person runs the session, the hook reads only on the machine: the first line of the Codex rollout, the start of the Gemini file,~/.kiro/sessions/and~/.cursor/projects/<workspace>/agent-transcripts/, and the command line of the processes above it (ps). Exception: while the switch is unset (the default), a legacy extraction hook you wired by hand (decision-extractor,episode-extractor,handoff-generator,feedback-loop,precompact-extract), on any harness, still reads and sends the transcript; only--transcript off(orVALORBRAIN_SEND_TRANSCRIPT=off) stops it. - Working directory and the rest of the payload:
cwd,transcript_pathand the other fields the harness passes stay on the machine.cwdonly goes into a local hash that identifies the session (on Kiro, also into the hash that finds the session's directory). With the transcript on, the transcript file andcwd(asworkingDir) go in the transcript upload; an extraction hook wired by hand also sendscwd, the prompt and the last assistant reply when the harness passes them. - Assistant replies and tool output: not part of the
hooks/cuebodies. They go inside the transcript whenever it is sent (switch on, or an extraction hook wired by hand while the switch is unset). - Token on the command line: under protocol v2 the token lives in
~/.valorbrain/connect.json(0600), never in the hook's argv.
On the server, the hooks/cue read log keeps only the hash of the query, not
its text.
Source: /www/valorbrain-cli/packages/connect/hook.mjs,
/opt/valorbrain/src/harness/adapters.ts, /opt/valorbrain/src/server.ts,
/opt/valorbrain/src/access-tracker.ts
How to turn it off
- Everything:
npx -y @valorbrain/connect --remove. It undoes the whole install of the detected harnesses: MCP entries, rules, hooks and the credentials in~/.valorbrain/connect.json. - One harness:
npx -y @valorbrain/connect --harness <id> --remove(the same, for that one). - Hooks only, keeping MCP and the rules: run the install again with
--mcp-only(npx -y @valorbrain/connect --token <vbm_…> --harness <id> --mcp-only). Nothing leaves per turn; running again without--mcp-onlyputs the hooks back. Hooks you edited by hand go only with--forceor a yes at the prompt. The re-run needs the token (--token <vbm_…>, as in the install): run unattended, as from an agent's shell, connect stops without one. On Hermes, which has no hooks, the flag changes nothing (its plugin keeps sending the prompt); on OMP it removes the hook bridge. - Stop checkpoint only, per harness:
npx -y @valorbrain/connect --harness <id> --checkpoint off(writescheckpoint: falsein that harness's entry;--checkpoint onturns it back on). For the whole machine:VALORBRAIN_CHECKPOINT=off(or0, orfalse) in the harness's environment, which wins over the file both ways. On Gemini CLI the variable does not reach the hook on a GitHub runner (see the Gemini CLI section), and there only--checkpoint offworks; on a Codex install from before 0.9.0, only the variable, until you reinstall. - The prompt only, per harness:
npx -y @valorbrain/connect --harness <id> --prompt off(writessend_prompt: falsein that harness's entry of~/.valorbrain/connect.json;--prompt onturns it back on). For the whole machine:VALORBRAIN_SEND_PROMPT=offin the harness's environment (on a GitHub runner Gemini CLI does not pass that variable to its hooks; there, use--prompt off). Without the prompt, session start and the checkpoint go on; per-prompt recall stops. - Transcript (Claude Code, Grok, Codex, Gemini CLI, Kiro, Cursor, OpenCode,
Hermes and OMP): off by default; turn it on
with
npx -y @valorbrain/connect --harness <id> --transcript on, or withVALORBRAIN_SEND_TRANSCRIPT=onin the harness's environment, which wins over the file both ways.--transcript offturns it off. - By hand: delete the entries whose command contains
@valorbrain/connectin the harness's file (table below). Deleting only~/.valorbrain/connect.jsonis not enough if~/.valorbrain/config.jsonhas anapi_key, because the hook falls back to that key.
How to verify
npx -y @valorbrain/connect --statusshows, per harness, whether hooks are wired, which protocol they use, which engine they talk to, and the mode (mcp-onlyorhooks).npx -y @valorbrain/connect --token <vbm_…> --dry-runshows what would be written, without writing anything.- The files you can open:
| Harness | Where the hooks live |
|---|---|
| Claude Code | ~/.claude/settings.json → hooks |
| Codex | ~/.codex/hooks.json |
| Gemini CLI | ~/.gemini/settings.json → hooks |
| Kiro | ~/.kiro/hooks/valorbrain.json (V3) or ~/.kiro/agents/valorbrain.json (legacy) |
| Cursor | ~/.cursor/hooks.json |
| Grok CLI | ~/.grok/hooks/valorbrain.json |
| OpenCode | ~/.config/opencode/plugins/valorbrain.ts |
| Hermes Agent | ~/.hermes/config.yaml and ~/.hermes/plugins/valorbrain/__init__.py |
| Oh My Pi (OMP) | ~/.omp/agent/hooks/pre/valorbrain.ts |
| All (credential) | ~/.valorbrain/connect.json |