Skip to content

Configuration

OpenVole uses a single vole.config.json file at the project root — plain JSON, no imports, no build step.

Full Example

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"] } },
    { "name": "@openvole/paw-memory", "allow": { "network": ["*"] } },
    { "name": "@openvole/paw-session" },
    { "name": "@openvole/paw-compact" },
    { "name": "@openvole/paw-telegram", "allow": { "network": ["*"], "env": ["TELEGRAM_BOT_TOKEN", "TELEGRAM_ALLOW_FROM"] } },
    { "name": "@openvole/paw-shell", "allow": { "filesystem": ["./"], "env": ["VOLE_SHELL_ALLOWED_DIRS"], "childProcess": true } },
    { "name": "@openvole/paw-dashboard", "allow": { "listen": [3001], "env": ["VOLE_DASHBOARD_PORT"] } }
  ],
  "skills": ["clawhub/summarize"],
  "loop": {
    "maxIterations": 25,
    "confirmBeforeAct": false,
    "taskConcurrency": 1,
    "compactThreshold": 50,
    "toolHorizon": true,
    "maxContextTokens": 128000,
    "responseReserve": 4000,
    "costTracking": "auto",
    "costAlertThreshold": 1.00,
    "rateLimits": {
      "llmCallsPerMinute": 30,
      "llmCallsPerHour": 500,
      "toolExecutionsPerTask": 100,
      "tasksPerHour": { "telegram": 20, "cli": 100 }
    }
  },
  "heartbeat": {
    "enabled": true,
    "intervalMinutes": 30,
    "runOnStart": false
  },
  "toolProfiles": {
    "telegram": { "deny": ["shell_exec", "fs_write", "fs_delete"] },
    "heartbeat": { "allow": ["memory_search", "memory_write", "telegram_send", "shell_exec"] }
  },
  "security": {
    "sandboxFilesystem": true,
    "allowedPaths": ["/home/user/projects"],
    "docker": {
      "enabled": false,
      "image": "node:20-slim",
      "memory": "512m",
      "cpus": "1.0",
      "scope": "session",
      "network": "none"
    }
  },
  "agents": {
    "researcher": {
      "role": "Research assistant",
      "instructions": "Search the web and summarize findings. Do not execute code.",
      "allowTools": ["web_fetch", "scrape_page", "memory_write"],
      "maxIterations": 10
    }
  },
  "net": {
    "enabled": true,
    "instanceName": "my-vole",
    "role": "coordinator",
    "port": 9700,
    "peers": [
      { "url": "http://192.168.1.50:9701", "trust": "full", "allowBrain": false }
    ],
    "share": { "tools": true, "memory": true, "session": false },
    "routing": { "shell_*": "worker-1", "db_*": "db-worker" }
  }
}

Config Sections

brain

Which Brain Paw handles the Think phase of the agent loop.

json
{ "brain": "@openvole/paw-brain" }

The unified paw-brain supports all providers — set BRAIN_PROVIDER env var to ollama, openai, anthropic, gemini, or xai.


paws

Array of paws to load. Each entry is either a package name string or an object with permissions.

String shorthand — no special permissions:

json
{ "paws": ["@openvole/paw-memory", "@openvole/paw-session"] }

Object form — with explicit sandbox permissions:

json
{
  "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"]
      }
    }
  ]
}

Paw Permission Object (allow)

Each paw runs in a sandboxed subprocess. The allow field controls what the paw can access:

KeyTypeDescriptionExample
networkstring[]Outbound network access. ["*"] for any, or specific domains.["api.openai.com", "api.telegram.org"]
listennumber[]Ports the paw can bind (for servers like dashboard).[3001]
filesystemstring[]Additional filesystem paths beyond .openvole/.["./", "/tmp"]
envstring[]Environment variables passed to the subprocess.["TELEGRAM_BOT_TOKEN"]
childProcessbooleanAllow spawning child processes. Required for shell, browser, MCP paws.true

Hook Configuration

Paw hooks can be configured with ordering and pipeline behavior:

json
{
  "name": "@openvole/paw-memory",
  "hooks": {
    "perceive": { "order": 1, "pipeline": true }
  },
  "allow": { "network": ["*"] }
}

Common Paw Permissions

PawNeedsConfig
paw-brainLLM API access"network": ["*"], env vars for provider
paw-shellSpawn processes"childProcess": true, "filesystem": ["./"]
paw-browserSpawn Chrome"childProcess": true, "network": ["*"]
paw-databaseNative addonsDisable sandbox: "sandboxFilesystem": false
paw-dashboardBind HTTP port"listen": [3001]
paw-telegramTelegram API"network": ["api.telegram.org"] or ["*"]
paw-memoryEmbedding API"network": ["*"]
paw-compactLLM for compaction"network": ["*"]
paw-mcpSpawn MCP servers"childProcess": true
paw-filesystemRead/write files"filesystem": ["./"]
paw-imageNative addons (sharp)Disable sandbox: "sandboxFilesystem": false

skills

Array of skill names to load. Skills are context-aware prompt templates that activate based on available tools.

json
{ "skills": ["clawhub/summarize", "clawhub/email-triage", "local/my-workflow"] }

Skills from clawhub/ are fetched from the VoleHub registry. Skills from local/ are loaded from .openvole/skills/.


loop

Controls the agent loop — how the Brain thinks, acts, and manages context.

OptionTypeDefaultDescription
maxIterationsnumber10Max loop iterations per task. Resets on successful tool execution.
confirmBeforeActbooleanfalseIf true, ask user confirmation before executing tools.
taskConcurrencynumber1Max tasks running in parallel.
compactThresholdnumber50Message count that triggers compact hooks. 0 to disable.
toolHorizonbooleantrueBrain starts with core tools only, discovers others via discover_tools. Reduces context bloat.
maxContextTokensnumber128000Max context window size in tokens. Core trims messages by priority to fit.
responseReservenumber4000Tokens reserved for the Brain's response output.
costTrackingstring"auto""auto": track for cloud providers. "enabled": always track. "disabled": off.
costAlertThresholdnumberWarn when a single task exceeds this USD amount.
rateLimitsobjectRate limiting (see below).

Rate Limits

json
{
  "loop": {
    "rateLimits": {
      "llmCallsPerMinute": 30,
      "llmCallsPerHour": 500,
      "toolExecutionsPerTask": 100,
      "tasksPerHour": {
        "telegram": 20,
        "cli": 100,
        "heartbeat": 6
      }
    }
  }
}
OptionDescription
llmCallsPerMinuteMax Brain (LLM) calls per minute across all tasks.
llmCallsPerHourMax Brain calls per hour.
toolExecutionsPerTaskMax tool executions within a single task.
tasksPerHourPer-source task rate limits. Keys are source names (cli, telegram, heartbeat, etc.).

Context Budget

The ContextBudgetManager trims messages by priority when the context exceeds maxContextTokens:

  1. Old tool results (lowest priority — trimmed first)
  2. Old error messages
  3. Old assistant/brain messages
  4. Session history

Never trimmed: system prompt, first user message, last 2 brain responses.


heartbeat

Periodic autonomous wake-up. The agent reads HEARTBEAT.md and acts on scheduled jobs without user input.

OptionTypeDefaultDescription
enabledbooleanfalseEnable heartbeat scheduling.
intervalMinutesnumber30Minutes between heartbeat wake-ups.
runOnStartbooleanfalseRun a heartbeat immediately on startup.
json
{ "heartbeat": { "enabled": true, "intervalMinutes": 15, "runOnStart": true } }

Common intervals:

Use CaseIntervalDescription
DevOps monitoring10Health checks, alerts every 10 min
Personal assistant30Email/calendar checks every 30 min
Data monitoring15Watch for changes every 15 min
Content automation360Content cycle every 6 hours
Research aggregator720Daily research report every 12 hours

The heartbeat instructions live in .openvole/HEARTBEAT.md. The agent reads this file each wake-up and decides what actions to take.


toolProfiles

Restrict which tools are available per task source. Useful for limiting what external channels (Telegram, Slack) can trigger.

json
{
  "toolProfiles": {
    "telegram": {
      "deny": ["shell_exec", "fs_write", "fs_delete"]
    },
    "heartbeat": {
      "allow": ["memory_search", "memory_write", "telegram_send", "web_fetch"]
    },
    "cli": {}
  }
}
FieldDescription
allowAllowlist — only these tools can be used. If set, everything else is denied.
denyDenylist — these tools are blocked. Everything else is allowed.

If both allow and deny are set, deny takes precedence. Profile keys match the task source: cli, telegram, slack, heartbeat, api, etc.


security

Controls the subprocess sandbox and isolation.

OptionTypeDefaultDescription
sandboxFilesystembooleantrueEnable Node.js --permission sandbox for paw subprocesses.
allowedPathsstring[][]Additional filesystem paths paws can access beyond .openvole/.
dockerobjectDocker container sandbox (optional, stronger isolation).
json
{
  "security": {
    "sandboxFilesystem": true,
    "allowedPaths": ["/home/user/data"]
  }
}

Docker Sandbox

Runs paw subprocesses inside Docker containers for stronger isolation.

OptionTypeDefaultDescription
enabledbooleanfalseEnable Docker sandboxing.
imagestring"node:20-slim"Base Docker image.
memorystring"512m"Memory limit per container.
cpusstring"1.0"CPU limit per container.
scopestring"session""session": container per task session. "shared": one container reused.
networkstring"none"Docker network mode: "none", "bridge", or "host".
allowedDomainsstring[]Outbound domains allowed when network: "bridge".
json
{
  "security": {
    "docker": {
      "enabled": true,
      "image": "node:20-slim",
      "memory": "256m",
      "cpus": "0.5",
      "network": "bridge",
      "allowedDomains": ["api.openai.com"]
    }
  }
}

agents

Named agent profiles for sub-agent spawning via the spawn_agent core tool. Each profile defines a restricted execution context.

OptionTypeDefaultDescription
rolestringHuman-readable role description (injected into context).
instructionsstringAdditional instructions for the sub-agent.
allowToolsstring[]Tools this agent can use (allowlist).
denyToolsstring[]Tools this agent cannot use (denylist, takes precedence).
maxIterationsnumber10Max loop iterations for this agent.
json
{
  "agents": {
    "researcher": {
      "role": "Research assistant",
      "instructions": "Search the web and summarize findings. Do not execute shell commands.",
      "allowTools": ["web_fetch", "scrape_page", "memory_write", "memory_search"],
      "maxIterations": 15
    },
    "coder": {
      "role": "Code generator",
      "denyTools": ["telegram_send", "email_send"],
      "maxIterations": 20
    }
  }
}

The Brain can spawn these via spawn_agent({ profile: "researcher", task: "..." }).


net (VoleNet)

Distributed agent networking — connect multiple OpenVole instances across machines.

OptionTypeDefaultDescription
enabledbooleanfalseEnable VoleNet.
instanceNamestring"vole"Human-readable name for this instance.
rolestring"peer""coordinator", "worker", or "peer".
portnumber9700WebSocket/HTTP port for peer communication.
keyPathstring.openvole/net/vole_keyPath to Ed25519 keypair.
peersarray[]Peer connections (see below).
shareobjectWhat to share with peers.
routingobjectTool-to-peer routing rules.
brainSourcestring"local""local", "remote", or a specific peer name.
leaderstring"auto""auto" (lowest instance ID) or a specific instance name.
heartbeatModestring"leader""leader": only leader runs heartbeat. "independent": each instance runs its own.
brainModestring"local""local": handle own tasks. "loadbalance": route to least-loaded brain.
taskOverflowstring"reject""reject": reject when queue full. "forward": forward to least-loaded peer.
maxQueuedTasksnumber10Max queued tasks before overflow triggers.
tlsobjectTLS certificate for encrypted transport.
discoverystring"manual"Peer discovery method: "manual" or "mdns".

Peer Configuration

json
{
  "net": {
    "peers": [
      {
        "url": "http://192.168.1.50:9701",
        "trust": "full",
        "allowBrain": false,
        "allowTools": ["shell_exec"],
        "denyTools": ["vault_read"]
      }
    ]
  }
}
FieldTypeDescription
urlstringPeer endpoint URL.
truststring"full": all access. "tool": specific tools only. "read": memory search only.
allowToolsstring[]Tools this peer can execute on our instance (with trust: "tool").
denyToolsstring[]Tools this peer cannot use on our instance.
allowBrainbooleanAllow this peer to delegate tasks to our Brain (LLM cost on us).

Sharing

json
{
  "net": {
    "share": {
      "tools": true,
      "memory": true,
      "session": false
    }
  }
}
FieldDescription
toolsShare our local tools with connected peers.
memoryPropagate memory writes to peers and accept remote memory searches.
sessionSync session transcripts between peers (shared conversation).

Routing

Route tool calls to specific peers by glob pattern:

json
{
  "net": {
    "routing": {
      "shell_*": "server-worker",
      "db_*": "db-worker",
      "scrape_*": "web-scraper"
    }
  }
}

When multiple peers share the same tool, the Brain can target a specific peer using <peerName>/<toolName> syntax (e.g. us-monitor/shell_exec).

VoleNet Setup

bash
# 1. Generate identity on each instance
vole net init my-instance

# 2. Exchange keys
vole net show-key                    # on instance A
vole net trust "vole-ed25519 ..."    # on instance B (paste A's key)

# 3. Configure peers in vole.config.json (see above)

# 4. Start both instances
vole start

.openvole Directory Structure

.openvole/
├── paws/
│   ├── paw-memory/          ← memory data
│   │   ├── MEMORY.md
│   │   └── user/, paw/, heartbeat/
│   ├── paw-session/         ← session transcripts
│   │   └── cli:default/, telegram:123/
│   ├── paw-brain/           ← brain paw data
│   │   └── BRAIN.md         ← system prompt (scaffolded on first run)
│   └── paw-mcp/             ← MCP config
│       └── servers.json
├── net/                     ← VoleNet identity (if enabled)
│   ├── vole_key             ← Ed25519 private key
│   ├── vole_key.pub         ← public key
│   └── authorized_voles     ← trusted peer keys
├── workspace/               ← agent scratch space
├── skills/                  ← local and clawhub skills
├── logs/                    ← log files
│   └── vole.log
├── vault.json               ← encrypted key-value store
├── schedules.json           ← persistent cron schedules
├── SOUL.md                  ← agent personality
├── USER.md                  ← user profile
├── AGENT.md                 ← operating rules
└── HEARTBEAT.md             ← recurring job definitions

Each paw gets its own data directory at .openvole/paws/<name>/. The installed npm package stays immutable — all user data lives in the local paw directory.


Identity Files

Customize agent behavior with markdown files in .openvole/:

FilePurposeUsed By
BRAIN.mdCustom system prompt — overrides the default prompt entirely.Brain Paw
SOUL.mdAgent personality, tone, and identity.System Prompt
USER.mdUser profile, preferences, timezone.System Prompt
AGENT.mdOperating rules and behavioral constraints.System Prompt
HEARTBEAT.mdRecurring job definitions for heartbeat wake-ups.Heartbeat Task

These files are loaded into the system prompt on every iteration. Edit them to shape how the agent behaves.


Environment Variables

Global environment variables that affect OpenVole core:

VariableDescription
VOLE_LOG_LEVELLog level: debug, info, warn, error. Default: info.
VOLE_LOG_FILEPath to log file. Default: .openvole/logs/vole.log.
VOLE_DASHBOARD_PORTDashboard HTTP port. Default: 3001.
VOLE_DEBUGEnable debug mode (true/false).
VOLE_IPC_TIMEOUT_MSIPC timeout for paw communication in ms. Default: 300000.
VOLE_COMPACT_MODELExplicit model for LLM compaction (if unset, uses simple compaction).

Provider-specific env vars are passed to paws via the allow.env config — they are not globally available to all paws.

Released under the MIT License.