Skip to content

Brain Paws

The Brain is a Paw — the core is LLM-ignorant. Swap models by swapping Brain Paws. All Brain Paws implement the same think() interface.

Unified Brain Paw

Use @openvole/paw-brain — a single unified brain paw that supports all LLM providers:

bash
vole paw add @openvole/paw-brain

Set the provider via BRAIN_PROVIDER env var, or let it auto-detect from available API keys:

ProviderBRAIN_PROVIDERRequired Env Var
Ollama (local)ollamaOLLAMA_HOST, OLLAMA_MODEL
Anthropic ClaudeanthropicANTHROPIC_API_KEY
OpenAIopenaiOPENAI_API_KEY
Google GeminigeminiGEMINI_API_KEY
xAI GrokxaiXAI_API_KEY
Claude Code (local CLI)claude-codenone — uses the local claude CLI's own auth
Antigravity (local CLI)antigravitynone — uses the local agy CLI's own auth

Legacy single-provider paws (paw-ollama, paw-claude, paw-openai, paw-gemini, paw-xai) are deprecated but still available.

Configuration

Set the active brain in vole.config.json:

json
{
  "brain": "@openvole/paw-brain",
  "paws": [
    {
      "name": "@openvole/paw-brain",
      "allow": {
        "network": ["*"],
        "env": ["BRAIN_PROVIDER", "BRAIN_API_KEY", "BRAIN_MODEL",
                "OLLAMA_HOST", "OLLAMA_MODEL", "OLLAMA_API_KEY",
                "OPENAI_API_KEY", "ANTHROPIC_API_KEY", "GEMINI_API_KEY"]
      }
    }
  ]
}

Generic env vars (BRAIN_API_KEY, BRAIN_MODEL) work across all providers. Provider-specific env vars (e.g. GEMINI_API_KEY) take precedence over generic ones.

A provider must be configured. If none is set — no BRAIN_PROVIDER, no provider API key, and no OLLAMA_HOST/OLLAMA_MODEL — paw-brain exits with a clear error instead of silently defaulting to Ollama (changed in 2.1.0).

Mock provider (testing)

Set BRAIN_PROVIDER=mock (echo and test are aliases) for a free, deterministic brain that makes no network calls and no LLM calls — ideal for testing the dashboard chat, the VoleNet mesh, or the agent loop, and for CI. It has two modes:

  • echo (default) — replies with the incoming message. Set BRAIN_MOCK_REPLY for a fixed reply instead.
    bash
    BRAIN_PROVIDER=mock BRAIN_MOCK_REPLY="pong"
  • scripted — set BRAIN_MOCK_SCRIPT to a JSON array of steps, walked one per think() call. Each step is either {"tool":"name","params":{...}} to emit a tool call or {"response":"text"} for a final reply.
    bash
    BRAIN_PROVIDER=mock BRAIN_MOCK_SCRIPT='[{"tool":"shell","params":{"command":"date"}},{"response":"done"}]'

To pass the sandbox, add any mock env vars you use to the paw's allow.env, e.g. "BRAIN_MOCK_SCRIPT", "BRAIN_MOCK_REPLY".

Claude Code provider (local CLI)

Set BRAIN_PROVIDER=claude-code (aliases claudecode, cc) to use the local, authenticated Claude Code CLI as the brain — no API key; it uses the CLI's own auth. Each think() renders the system prompt + transcript and runs claude -p --output-format json, returning Claude Code's final answer.

  • Auth profile — point at a config dir with CLAUDE_CODE_CONFIG_DIR (e.g. ~/.claude-ep); it maps to the CLI's CLAUDE_CONFIG_DIR.
  • Other envCLAUDE_CODE_CMD (default claude), CLAUDE_CODE_MODEL, CLAUDE_CODE_PERMISSION_MODE (e.g. bypassPermissions, to let Claude Code use its own tools without an interactive prompt), CLAUDE_CODE_ARGS (extra CLI flags), CLAUDE_CODE_TIMEOUT_MS (default 1800000 — 30 min; see Timeouts).

Grant "childProcess": true (it spawns the CLI) and add the CLAUDE_CODE_* vars you use to the paw's allow.env.

Calling OpenVole's own tools

Set CLAUDE_CODE_EXPOSE_TOOLS=1 and Claude Code can call the agent's own tools (memory, schedules, VoleNet, …) as mcp__openvole__<tool>, alongside its built-ins. paw-brain writes a --mcp-config pointing the CLI at the control plane's MCP endpoint (/mcp/<agent>); the engine injects VOLE_DASHBOARD_URL, VOLE_AGENT_ID, and the dashboard token, so it works automatically under vole serve. Add CLAUDE_CODE_EXPOSE_TOOLS, VOLE_DASHBOARD_URL, VOLE_DASHBOARD_TOKEN, and VOLE_AGENT_ID to allow.env. See Dashboard → Tools over MCP.

Antigravity provider (local CLI)

Set BRAIN_PROVIDER=antigravity (aliases agy, ag) to use the local, authenticated Antigravity CLI (agy, Google's successor to the Gemini CLI) as the brain — no API key; it uses the CLI's own auth. Each think() renders the system prompt + transcript and runs agy --print, returning the CLI's final answer.

  • ModelANTIGRAVITY_MODEL (run agy models to list what your account can reach — gemini-3.x, claude-*, gpt-oss-*).
  • Other envANTIGRAVITY_CMD (default agy), ANTIGRAVITY_AGENT, ANTIGRAVITY_EFFORT (low|medium|high), ANTIGRAVITY_MODE (accept-edits|plan), ANTIGRAVITY_SKIP_PERMISSIONS, ANTIGRAVITY_SANDBOX, ANTIGRAVITY_ADD_DIR, ANTIGRAVITY_CWD, ANTIGRAVITY_ARGS, ANTIGRAVITY_TIMEOUT_MS (default 1800000 — 30 min; see Timeouts), ANTIGRAVITY_MAX_PROMPT_BYTES.

Grant "childProcess": true (it spawns the CLI) and add the ANTIGRAVITY_* vars you use to the paw's allow.env.

No OpenVole tool access. Unlike claude-code, this provider does not expose OpenVole's own tools to the CLI: agy has no per-invocation --mcp-config, so it runs its own agent loop with its own tools and returns a final text answer — it makes no OpenVole tool calls. Use it as a text/chat brain, not for an agent that must drive OpenVole tools (memory, schedules, VoleNet, sub-agents). The prompt is passed as a command-line argument, so it is bounded by ARG_MAX (~1 MB); an oversized prompt fails fast with a clear error — lower loop.maxContextTokens or raise ANTIGRAVITY_MAX_PROMPT_BYTES.

Timeouts — how long a brain may think

A long agentic run is normal, so it's worth knowing exactly which clocks apply.

The core does not time out thinking. The engine calls the brain paw over IPC, and think is explicitly exempt from VOLE_IPC_TIMEOUT_MS — that 5-minute ceiling governs tool calls and lifecycle hooks, never inference. Nothing in the loop, the dashboard (whose 10s command timeout only covers submitting the task), or the control plane caps a response either.

So the only limit is the one the provider imposes:

ProviderLimitConfigurable
claude-code30 min (paw-brain ≥ 2.5.1; was 10 min)CLAUDE_CODE_TIMEOUT_MS
antigravity30 min (was 10 min)ANTIGRAVITY_TIMEOUT_MS
anthropic10 min — the SDK's own defaultnot exposed by OpenVole
openai, gemini, xai, ollamawhatever their SDK/host defaults tonot exposed by OpenVole

For a CLI brain the timeout covers the whole agentic run — Claude Code does its own tool-calling inside that single think, so its turns, edits, and searches all live under one clock. Raise it per agent when your work is long:

env
CLAUDE_CODE_TIMEOUT_MS=3600000   # 1 hour

(The var must also be listed in that paw's allow.env — the onboarding default already includes it.)

When the limit is hit the CLI is killed and the task fails with a clear timeout error. Older versions (paw-brain < 2.5.1) could instead surface the CLI's raw JSON error envelope as if it were the agent's reply — a silent, expensive failure. Upgrade if you see JSON in a chat bubble.

BRAIN.md

The Brain Paw scaffolds a BRAIN.md file in its local config directory on first run:

.openvole/paws/paw-brain/BRAIN.md

This file is the system prompt — it overrides the default system prompt entirely. Edit it to customize how the Brain behaves. The Brain Paw owns this file, not the core.

Identity Files

All Brain Paws load these optional identity files from .openvole/ on startup:

FilePurpose
BRAIN.mdSystem prompt (per-brain, in paw data dir)
SOUL.mdAgent personality and tone
USER.mdUser profile and preferences
AGENT.mdOperating rules and constraints

How think() Works

  1. The core calls think() on the Brain Paw with the current context
  2. The Brain Paw builds the system prompt from BRAIN.md, identity files, metadata, tools, and skills
  3. It sends the prompt + message history to the LLM
  4. The LLM returns either a text response (final answer) or tool calls (continue loop)
  5. The Brain Paw returns the plan to the core

The core doesn't know which LLM was used, what API was called, or how the prompt was built. It just receives a plan.