Concepts

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

HarnessHooked eventsWhat leaves per eventConfig file
Claude CodeSessionStart, UserPromptSubmit, Stopstart: 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
CodexSessionStart, UserPromptSubmit, Stopsame as Claude Code, but the session transcript (opt-in) needs connect ≥ 0.12.0~/.codex/hooks.json
Gemini CLISessionStart, BeforeAgent, AfterAgentsame as Claude Code, but the session transcript (opt-in) needs connect ≥ 0.12.0~/.gemini/settings.json
KiroSessionStart, 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)
CursorsessionStart, stopstart: 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 CLIStopcounters 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
OpenCodeplugin: chat.message; session.idle only with the transcript onprompt: 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 AgentMemoryProvider plugin: start, every turn, compression, session endeach 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

MomentFields sent
Session startharness, session_id, event: "session_start", and source when the harness sends that field
Promptharness, session_id, event: "prompt", prompt (the first 8,000 characters), and source when present
Stopharness, 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.

HarnessesClaude 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 leavesthe 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
EndpointPOST https://valorbrain-api.valor.digital/api/v1/hooks/run, two calls per upload: episode-extractor, then decision-extractor
Whenat 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
Howa 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:

HarnessFile
Claude Codethe payload's transcript_path
Grok CLIthe payload's transcriptPath
Codexthe payload's transcript_path: the rollout under ~/.codex/sessions/
Gemini CLIAfterAgent's transcript_path: ~/.gemini/tmp/<project>/chats/session-*.jsonl (older versions: a single .json file)
Cursorthe 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
Kirothe 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
OpenCodethe 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_ENTRYPOINT starting with sdk) 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 carries sessionAttended: "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's session_meta line (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=true or GITHUB_ACTIONS=true), Gemini's own "headless" rule; sub-agent sessions (kind: "subagent" in the file). On a GitHub runner Gemini does not pass CI or GITHUB_ACTIONS to 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's stop fires only for the main conversation; subagents have subagentStop, 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:

  1. --token= on the command line (installs older than protocol v2 only; self-heal migrates it to the file).
  2. The VALORBRAIN_TOKEN environment variable.
  3. This harness's entry in ~/.valorbrain/connect.json (mode 0600, one entry per harness). This is the vbm_… token the installer wrote.
  4. api_key in ~/.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_MS changes 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_id makes no call.
  • Server-side limit: 300 calls per 10 min per token (VALORBRAIN_HOOK_CUE_MAX_PER_10MIN on 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/register with the token, within 2.5 s. It sends runtime_key (<harness>:<hostname>:<home path>), agent_platform, display_name, hostname, plugin_version: "0.9.0" and capabilities (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

EventsSessionStart, UserPromptSubmit, Stop (10 s timeout each)
What leavesstart: 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)
EndpointPOST https://valorbrain-api.valor.digital/api/v1/hooks/cue
CredentialBearer with the vbm_… token from the claude-code entry in ~/.valorbrain/connect.json (full order above)
Cadence1 call per session start and per prompt; stop per the policy
Turn offhooks 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

EventsSessionStart, UserPromptSubmit, Stop (10 s timeout each)
What leavessame 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)
EndpointPOST https://valorbrain-api.valor.digital/api/v1/hooks/cue
Credentialcodex entry in ~/.valorbrain/connect.json
Cadencesame as Claude Code
Turn offhooks 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

EventsSessionStart, BeforeAgent (prompt), AfterAgent (stop), 10,000 ms timeout each
What leavessame 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)
EndpointPOST https://valorbrain-api.valor.digital/api/v1/hooks/cue
Credentialgemini-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
Cadencesame as Claude Code
Turn offhooks 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: true in Gemini's settings.json: variables with secret-like names (TOKEN, KEY, SECRET, AUTH, PASSWORD…), a few fixed names and those listed in blocked are dropped;
  • on a GitHub runner (GITHUB_SHA set, or SURFACE=Github): only a short list (PATH, HOME, TERM…) and those listed in allowed pass.

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

EventsV3 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 leavessame 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)
EndpointPOST https://valorbrain-api.valor.digital/api/v1/hooks/cue
Credentialkiro entry in ~/.valorbrain/connect.json
Cadencesame as Claude Code. Connect sets no timeout in the V3 file; Kiro's default is not determined in the code
Turn offhooks 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

EventssessionStart, stop (10 s timeout each). No prompt hook: beforeSubmitPrompt can block a prompt but cannot add context
What leavesstart: 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)
EndpointPOST https://valorbrain-api.valor.digital/api/v1/hooks/cue
Credentialcursor entry in ~/.valorbrain/connect.json
Cadence1 call per session start; stop per the policy. Cursor itself caps follow-ups per conversation (loop_limit, default 5)
Turn offhooks 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

EventsStop (10 s timeout). Grok discards the output of passive events, so start and prompt are not wired
What leavescounters 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)
EndpointPOST https://valorbrain-api.valor.digital/api/v1/hooks/cue
Credentialgrok entry in ~/.valorbrain/connect.json
Cadencestop per the policy
Turn offhooks 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

Eventsplugin: chat.message (every user message). With the transcript on, also session.idle (end of each turn) of the main session. No session start
What leavesthe 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
EndpointPOST 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
Credentialopencode entry in ~/.valorbrain/connect.json
Cadence1 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 offVALORBRAIN_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.

Eventssession 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 leaveson 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
EndpointPOST <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
CredentialAuthorization: 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
Cadencetimeouts: 30 s for lifecycle hooks, 90 s for context-surfacing, 5 s for REST calls
Turn offprompt: 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.

Eventssession_start, before_agent_start (each user turn, main session only), session_stop (end of each turn), session_shutdown (end of session)
What leavesstart: 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
Endpointcontext 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)
CredentialVALORBRAIN_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
Cadence1 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 offprompt: 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 (or VALORBRAIN_SEND_TRANSCRIPT=off) stops it.
  • Working directory and the rest of the payload: cwd, transcript_path and the other fields the harness passes stay on the machine. cwd only 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 and cwd (as workingDir) go in the transcript upload; an extraction hook wired by hand also sends cwd, the prompt and the last assistant reply when the harness passes them.
  • Assistant replies and tool output: not part of the hooks/cue bodies. 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-only puts the hooks back. Hooks you edited by hand go only with --force or 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 (writes checkpoint: false in that harness's entry; --checkpoint on turns it back on). For the whole machine: VALORBRAIN_CHECKPOINT=off (or 0, or false) 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 off works; 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 (writes send_prompt: false in that harness's entry of ~/.valorbrain/connect.json; --prompt on turns it back on). For the whole machine: VALORBRAIN_SEND_PROMPT=off in 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 with VALORBRAIN_SEND_TRANSCRIPT=on in the harness's environment, which wins over the file both ways. --transcript off turns it off.
  • By hand: delete the entries whose command contains @valorbrain/connect in the harness's file (table below). Deleting only ~/.valorbrain/connect.json is not enough if ~/.valorbrain/config.json has an api_key, because the hook falls back to that key.

How to verify

  • npx -y @valorbrain/connect --status shows, per harness, whether hooks are wired, which protocol they use, which engine they talk to, and the mode (mcp-only or hooks).
  • npx -y @valorbrain/connect --token <vbm_…> --dry-run shows what would be written, without writing anything.
  • The files you can open:
HarnessWhere 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

See also Tokens and Hosts.

On this page