picoclaw

⚙️ Configuration Guide

Back to README

⚙️ Configuration

Config file: ~/.picoclaw/config.json

Security Configuration: For storing API keys, tokens, and other sensitive data, see the Security Configuration Guide.

Environment Variables

You can override default paths using environment variables. This is useful for portable installations, containerized deployments, or running picoclaw as a system service. These variables are independent and control different paths.

Variable Description Default Path
PICOCLAW_CONFIG Overrides the path to the configuration file. This directly tells picoclaw which config.json to load, ignoring all other locations. ~/.picoclaw/config.json
PICOCLAW_HOME Overrides the root directory for picoclaw data. This changes the default location of the workspace and other data directories. ~/.picoclaw

Examples:

# Run picoclaw using a specific config file
# The workspace path will be read from within that config file
PICOCLAW_CONFIG=/etc/picoclaw/production.json picoclaw gateway

# Run picoclaw with all its data stored in /opt/picoclaw
# Config will be loaded from the default ~/.picoclaw/config.json
# Workspace will be created at /opt/picoclaw/workspace
PICOCLAW_HOME=/opt/picoclaw picoclaw agent

# Use both for a fully customized setup
PICOCLAW_HOME=/srv/picoclaw PICOCLAW_CONFIG=/srv/picoclaw/main.json picoclaw gateway

Gateway Log Level

gateway.log_level controls Gateway log verbosity and is configurable in config.json.

{
  "gateway": {
    "log_level": "warn",
    "log_max_size_mb": 2,
    "log_max_backups": 3
  }
}

When omitted, the default is warn. Supported values: debug, info, warn, error, fatal.

log_max_size_mb sets the maximum size of each active log before rotation (default 2, allowed 1–1024). log_max_backups sets how many numbered archives to keep (default 3, allowed 0–100; 0 disables archives). Approximate disk usage per log is (log_max_backups + 1) × log_max_size_mb. These settings apply to logs/gateway.log, the workspace heartbeat.log, and any file selected with PICOCLAW_LOG_FILE; the panic log is trimmed to the configured size at startup. Existing oversized logs are trimmed to their latest content on startup. Environment overrides are PICOCLAW_GATEWAY_LOG_MAX_SIZE_MB and PICOCLAW_GATEWAY_LOG_MAX_BACKUPS. Restart the Gateway for changed rotation settings to take effect.

You can also override this with the environment variable PICOCLAW_LOG_LEVEL.

Workspace Layout

PicoClaw stores data in your configured workspace (default: ~/.picoclaw/workspace):

~/.picoclaw/workspace/
├── sessions/          # Conversation sessions and history
├── memory/           # Long-term memory (MEMORY.md)
├── state/            # Persistent state (last channel, etc.)
├── cron/             # Scheduled jobs database
├── skills/           # Custom skills
├── AGENT.md          # Agent behavior guide
├── HEARTBEAT.md      # Periodic task prompts (checked every 30 min)
├── IDENTITY.md       # Agent identity
├── SOUL.md           # Agent soul
└── USER.md           # User preferences

Note: Changes to AGENT.md, SOUL.md, USER.md and memory/MEMORY.md are automatically detected at runtime via file modification time (mtime) tracking. You do not need to restart the gateway after editing these files — the agent picks up the new content on the next request.

Agent Self-Evolution

The evolution block controls PicoClaw’s self-evolution runtime. When enabled, the agent records completed turns as learning records. In higher modes it can group repeated successful patterns, generate skill drafts, and optionally apply accepted drafts into workspace skills.

{
  "evolution": {
    "enabled": false,
    "mode": "observe",
    "state_dir": "",
    "min_task_count": 2,
    "min_success_ratio": 0.7,
    "cold_path_trigger": "after_turn",
    "cold_path_times": []
  }
}
Field Default Description
enabled false Enables learning-record capture for completed agent turns. Heartbeat turns are ignored.
mode observe observe records data only. draft can generate candidate skill drafts. apply can apply accepted drafts to workspace skills.
state_dir "" Optional directory for evolution state. Leave empty to use the default under the workspace.
min_task_count 2 Minimum related task records required before a pattern is eligible for draft generation.
min_success_ratio 0.7 Minimum success ratio for a task cluster. Use a value greater than 0 and up to 1.
cold_path_trigger after_turn Runs draft generation after_turn, on a scheduled cadence, or disables automatic cold-path runs when set to manual. There is no user-facing manual trigger yet. Applies only in draft and apply modes.
cold_path_times [] Scheduled run times used when cold_path_trigger is scheduled, written as HH:MM strings.

Use observe first if you want to inspect learning records without generating skill changes. Use draft when you want PicoClaw to prepare reviewable improvements. Use apply only when you are comfortable letting accepted drafts update workspace skills.

Request Context Policy

turn_profile is an optional request context policy under agents.defaults.turn_profile. Leave it unset or set "enabled": false to keep PicoClaw’s normal behavior. When "enabled": true, the same policy applies to every new turn.

Each block uses the same mode values:

Mode Meaning
default Keep PicoClaw’s normal behavior for that block. Missing blocks and missing mode fields are treated as default.
off Disable that block for the turn.
custom Use an allow list. In this version, custom is supported only for skills and tools; using it for history or system_prompt is a validation error.

Profile blocks:

Block What it controls
history Whether the turn reads prior session history and summary, writes user/assistant/tool messages, ingests context, and runs compaction or summarization.
system_prompt Whether PicoClaw injects its default identity, workspace instructions, memory, runtime context, and summary. External request system prompts are still allowed when this is off.
skills Whether the skill catalog and active skill prompt content are loaded. custom.allow keeps only the listed skill names in prompt context.
tools Which callable tools are exposed to the model and allowed at execution time. custom.allow keeps only listed registered tool names.

When system_prompt.mode is off, tools are still visible, and no external system prompt is supplied, PicoClaw uses its existing tool-use rule as the minimal fallback prompt. If tools.mode is off, no fallback prompt is added.

Example clean web policy:

{
  "agents": {
    "defaults": {
      "turn_profile": {
        "enabled": true,
        "history": { "mode": "off" },
        "system_prompt": { "mode": "off" },
        "skills": { "mode": "off" },
        "tools": {
          "mode": "custom",
          "allow": ["web_search", "web_fetch"]
        }
      }
    }
  }
}

Web launcher dashboard

picoclaw-launcher serves a browser UI that requires password sign-in first. On first run, open /launcher-setup to create the dashboard password. Later manual sign-ins use /launcher-login.

Skill Sources

By default, skills are loaded from:

  1. ~/.picoclaw/workspace/skills (workspace)
  2. ~/.picoclaw/skills (global)
  3. <binary-embedded-path>/skills (builtin, set at build time)

For advanced/test setups, you can override the builtin skills root with:

export PICOCLAW_BUILTIN_SKILLS=/path/to/skills

Using Skills From Chat Channels

Once skills are installed, and MCP servers are configured, you can inspect and force them directly from a chat channel:

Examples:

/list skills
/list mcp
/show mcp github
/use git explain how to squash the last 3 commits
/use italiapersonalfinance
dammi le ultime news

Unified Command Execution Policy

Session Isolation

Session scope controls how much memory is shared between chats, users, threads, and spaces.

For step-by-step recipes and isolation patterns, see the Session Guide.

Routing

Routing is configured through agents.dispatch.rules.

Each rule matches against the normalized inbound context produced by channels. Rules are evaluated from top to bottom. The first matching rule wins. If no rule matches, PicoClaw falls back to the configured default agent.

Supported match fields:

Match values use the same scope vocabulary as the session system:

Rules may optionally override the global session.dimensions value through session_dimensions. This allows routing and session allocation to stay aligned without reintroducing the old bindings or dm_scope formats.

Example:

{
  "agents": {
    "list": [
      { "id": "main", "default": true },
      { "id": "support" },
      { "id": "sales" }
    ],
    "dispatch": {
      "rules": [
        {
          "name": "vip in support group",
          "agent": "sales",
          "when": {
            "channel": "telegram",
            "chat": "group:-1001234567890",
            "sender": "12345"
          },
          "session_dimensions": ["chat", "sender"]
        },
        {
          "name": "telegram support group",
          "agent": "support",
          "when": {
            "channel": "telegram",
            "chat": "group:-1001234567890"
          },
          "session_dimensions": ["chat"]
        }
      ]
    }
  },
  "session": {
    "dimensions": ["chat"]
  }
}

In the example above, the VIP rule must appear before the broader group rule. Because routing is strictly ordered, more specific rules should be placed earlier and broader fallback rules later.

For more complete routing and model-tier examples, see the Routing Guide.

Agent Tool Allowlist

Per-agent tool declarations live in AGENT.md frontmatter, not in config.json.

If tools is omitted from frontmatter, the agent gets the normal globally enabled tool set. If tools is present, PicoClaw registers only the listed runtime tools for that agent.

---
name: Research Agent
description: Specialist for web research and in-depth analysis.
tools: [read_file, write_file, web_search, web_fetch, message]
skills: [deep-research]
mcpServers: [web-index]
---

You are the research agent.

Notes:

Agent Discovery (Automatic)

When an agent has spawnable peers and can call spawn, PicoClaw injects a structured agent registry into that agent’s system prompt on every turn. No extra list_agents tool call is required.

This registry is intended to make delegation concrete and reliable, especially when using spawn with a target agent_id.

Each entry includes:

Field Meaning
id Stable agent id
name Agent identity name from AGENT.md frontmatter
description Agent identity description from AGENT.md frontmatter

Important behavior:

Example injected shape:

{
  "agents": [
    {
      "id": "research",
      "name": "Research Agent",
      "description": "Specialist for long-form investigation and web work."
    }
  ]
}

In practice, this means a generalist agent can choose a peer based on its role description, then call spawn with the peer’s agent_id. The runtime resolves the rest.

🔒 Security Sandbox

PicoClaw runs in a sandboxed environment by default. The agent can only access files and execute commands within the configured workspace.

Default Configuration

{
  "agents": {
    "defaults": {
      "workspace": "~/.picoclaw/workspace",
      "restrict_to_workspace": true
    }
  }
}
Option Default Description
workspace ~/.picoclaw/workspace Working directory for the agent
restrict_to_workspace true Restrict file/command access to workspace

Protected Tools

When restrict_to_workspace: true, the following tools are sandboxed:

Tool Function Restriction
read_file Read files Only files within workspace
write_file Write files Only files within workspace
list_dir List directories Only directories within workspace
search_files Search file contents or filenames Uses the same read-path restrictions; paginated, bounded results
edit_file Edit files Only files within workspace
append_file Append to files Only files within workspace
exec Execute commands Command paths must be within workspace

Additional Exec Protection

Even with restrict_to_workspace: false, the exec tool blocks these dangerous commands:

File Access Control

Config Key Type Default Description
tools.allow_read_paths string[] [] Additional paths allowed for reading outside workspace
tools.allow_write_paths string[] [] Additional paths allowed for writing outside workspace
tools.search_files.enabled bool true Enables regex content search and glob-based filename search
tools.message.media_enabled bool false Allows the message tool to attach local media files by path. This is separate from tools.send_file.enabled; enable it only when unified text/media/caption delivery is intended.

Read File Mode

read_file has two mutually exclusive implementations selected by config. PicoClaw registers exactly one of them at startup:

Config Key Type Default Description
tools.read_file.enabled bool true Enables the read_file tool
tools.read_file.mode string bytes Selects the read_file implementation: bytes or lines
tools.read_file.max_read_file_size int 65536 Maximum bytes returned by read_file

Mode: bytes

Optimized for arbitrary files and binary-safe pagination.

Parameters:

Use bytes when:

Mode: lines

Text-oriented behavior, optimized for source files, markdown, logs, and configs. The tool reads sequentially by line and stops when the configured byte budget is reached.

Parameters:

Behavior notes:

Use mode = lines when:

Example

{
  "tools": {
    "read_file": {
      "enabled": true,
      "mode": "lines",
      "max_read_file_size": 65536
    }
  }
}

Exec Security

Config Key Type Default Description
tools.exec.allow_remote bool false Allow exec tool from remote channels (Telegram/Discord etc.)
tools.exec.enable_deny_patterns bool true Enable dangerous command interception
tools.exec.custom_deny_patterns string[] [] Custom regex patterns to block
tools.exec.custom_allow_patterns string[] [] Custom regex patterns to allow

Security Note: Symlink protection is enabled by default — all file paths are resolved through filepath.EvalSymlinks before whitelist matching, preventing symlink escape attacks.

Known Limitation: Child Processes From Build Tools

The exec safety guard only inspects the command line PicoClaw launches directly. It does not recursively inspect child processes spawned by allowed developer tools such as make, go run, cargo, npm run, or custom build scripts.

That means a top-level command can still compile or launch other binaries after it passes the initial guard check. In practice, treat build scripts, Makefiles, package scripts, and generated binaries as executable code that needs the same level of review as a direct shell command.

For higher-risk environments:

Error Examples

[ERROR] tool: Tool execution failed
{tool=exec, error=Command blocked by safety guard (path outside working dir)}
[ERROR] tool: Tool execution failed
{tool=exec, error=Command blocked by safety guard (dangerous pattern detected)}

Disabling Restrictions (Security Risk)

If you need the agent to access paths outside the workspace:

Method 1: Config file

{
  "agents": {
    "defaults": {
      "restrict_to_workspace": false
    }
  }
}

Method 2: Environment variable

export PICOCLAW_AGENTS_DEFAULTS_RESTRICT_TO_WORKSPACE=false

⚠️ Warning: Disabling this restriction allows the agent to access any path on your system. Use with caution in controlled environments only.

Security Boundary Consistency

The restrict_to_workspace setting applies consistently across all execution paths:

Execution Path Security Boundary
Main Agent restrict_to_workspace ✅
Subagent / Spawn Inherits same restriction ✅
Heartbeat tasks Inherits same restriction ✅

All paths share the same workspace restriction — there’s no way to bypass the security boundary through subagents or scheduled tasks.

Heartbeat (Periodic Tasks)

PicoClaw can perform periodic tasks automatically. Create a HEARTBEAT.md file in your workspace:

# Periodic Tasks

- Check my email for important messages
- Review my calendar for upcoming events
- Check the weather forecast

The agent will read this file every 30 minutes (configurable) and execute any tasks using available tools.

Async Tasks with Spawn

For long-running tasks (web search, API calls), use the spawn tool to create a subagent:

# Periodic Tasks

## Quick Tasks (respond directly)

- Report current time

## Long Tasks (use spawn for async)

- Search the web for AI news and summarize
- Check email and report important messages

Key behaviors:

Feature Description
spawn Creates async subagent, doesn’t block heartbeat
Independent context Subagent has its own context, no session history
message tool Subagent communicates with user directly via message tool
Non-blocking After spawning, heartbeat continues to next task

How Subagent Communication Works

Heartbeat triggers
    ↓
Agent reads HEARTBEAT.md
    ↓
For long task: spawn subagent
    ↓                           ↓
Continue to next task      Subagent works independently
    ↓                           ↓
All tasks done            Subagent uses "message" tool
    ↓                           ↓
Respond HEARTBEAT_OK      User receives result directly

The subagent has access to tools (message, web_search, etc.) and can communicate with the user independently without going through the main agent.

Configuration:

{
  "heartbeat": {
    "enabled": true,
    "interval": 30
  }
}
Option Default Description
enabled true Enable/disable heartbeat
interval 30 Check interval in minutes (min: 5)

Environment variables:

For constrained devices, enable the static low-power profile:

{
  "power": {
    "low_power": true,
    "low_power_heartbeat_interval": 120,
    "poll_interval_multiplier": 5
  }
}

With low_power enabled, the heartbeat interval defaults to 120 minutes (or the larger configured normal interval), and the agent loop blocks on inbound events instead of waking every 100 ms. poll_interval_multiplier scales maintenance intervals: 5 turns a 30-minute media cleanup interval into 150 minutes, a 10-second channel-maintenance interval into 50 seconds, and a 2-second config-file check into 10 seconds when hot reload is enabled. Set low_power_heartbeat_interval and poll_interval_multiplier to tune the profile. Channel protocol keepalives remain unchanged so connected integrations stay available.

Providers

[!NOTE] Groq provides free voice transcription via Whisper. If configured, audio messages from any channel will be automatically transcribed at the agent level.

Provider Purpose Get API Key
gemini LLM (Gemini direct) aistudio.google.com
zhipu LLM (Zhipu direct) bigmodel.cn
volcengine LLM (Volcengine direct) volcengine.com
openrouter LLM (recommended, access to all models) openrouter.ai
anthropic LLM (Claude direct) console.anthropic.com
openai LLM (GPT direct) platform.openai.com
deepseek LLM (DeepSeek direct) platform.deepseek.com
qwen LLM (Qwen direct) dashscope.console.aliyun.com
groq LLM + Voice transcription (Whisper) console.groq.com
cerebras LLM (Cerebras direct) cerebras.ai
vivgrid LLM (Vivgrid direct) vivgrid.com

Model Configuration (model_list)

What’s New? PicoClaw now prefers explicit provider + native model configuration (for example "provider": "zhipu", "model": "glm-4.7"). The legacy single-field provider/model form remains supported for compatibility when provider is omitted.

This design also enables multi-agent support with flexible provider selection:

PicoClaw supports separating sensitive data (API keys, tokens, secrets) from your main configuration by storing them in a .security.yml file.

Key Benefits:

Quick Setup:

  1. Create ~/.picoclaw/.security.yml with your API keys: ```yaml model_list: gpt-5.4: api_keys:
    • “sk-proj-your-actual-openai-key” claude-sonnet-4.6: api_keys:
    • “sk-ant-your-actual-anthropic-key” channels: telegram: token: “your-telegram-bot-token” web: brave: api_keys:
    • “BSAyour-brave-api-key” glm_search: api_key: “your-glm-search-api-key” ```
  2. Set proper permissions:
    chmod 600 ~/.picoclaw/.security.yml
    
  3. Remove sensitive fields from config.json (recommended):
    {
      "model_list": [
     {
       "model_name": "gpt-5.4",
       "provider": "openai",
       "model": "gpt-5.4"
       // api_key loaded from .security.yml
     }
      ],
      "channel_list": {
     "telegram": {
       "enabled": true,
       "type": "telegram",
       // token loaded from .security.yml
     }
      }
    }
    

How it works:

For complete documentation, see ../security/security_configuration.md.

All Supported Vendors

Vendor provider Value Default API Base Protocol API Key
OpenAI openai https://api.openai.com/v1 OpenAI Get Key
Anthropic anthropic https://api.anthropic.com/v1 Anthropic Get Key
智谱 AI (GLM) zhipu https://open.bigmodel.cn/api/paas/v4 OpenAI Get Key
DeepSeek deepseek https://api.deepseek.com/v1 OpenAI Get Key
Google Gemini gemini https://generativelanguage.googleapis.com/v1beta Gemini Get Key
Groq groq https://api.groq.com/openai/v1 OpenAI Get Key
Moonshot moonshot https://api.moonshot.cn/v1 OpenAI Get Key
通义千问 (Qwen) qwen https://dashscope.aliyuncs.com/compatible-mode/v1 OpenAI Get Key
NVIDIA nvidia https://integrate.api.nvidia.com/v1 OpenAI Get Key
Ollama ollama http://localhost:11434/v1 OpenAI Local (no key needed)
LM Studio lmstudio http://localhost:1234/v1 OpenAI Optional (local default: no key)
OpenRouter openrouter https://openrouter.ai/api/v1 OpenAI Get Key
LiteLLM Proxy litellm http://localhost:4000/v1 OpenAI Your LiteLLM proxy key
VLLM vllm http://localhost:8000/v1 OpenAI Local
Cerebras cerebras https://api.cerebras.ai/v1 OpenAI Get Key
VolcEngine (Doubao) volcengine https://ark.cn-beijing.volces.com/api/v3 OpenAI Get Key
神算云 shengsuanyun https://router.shengsuanyun.com/api/v1 OpenAI —
BytePlus byteplus https://ark.ap-southeast.bytepluses.com/api/v3 OpenAI Get Key
Vivgrid vivgrid https://api.vivgrid.com/v1 OpenAI Get Key
LongCat longcat https://api.longcat.chat/openai OpenAI Get Key
ModelScope (魔搭) modelscope https://api-inference.modelscope.cn/v1 OpenAI Get Token
Antigravity antigravity Google Cloud Custom OAuth only
GitHub Copilot github-copilot localhost:4321 gRPC —

Basic Configuration

{
  "model_list": [
    {
      "model_name": "ark-code-latest",
      "provider": "volcengine",
      "model": "ark-code-latest",
      "api_keys": ["sk-your-api-key"]
    },
    {
      "model_name": "gpt-5.4",
      "provider": "openai",
      "model": "gpt-5.4",
      "api_keys": ["sk-your-openai-key"]
    },
    {
      "model_name": "claude-sonnet-4.6",
      "provider": "anthropic",
      "model": "claude-sonnet-4.6",
      "api_keys": ["sk-ant-your-key"]
    },
    {
      "model_name": "glm-4.7",
      "provider": "zhipu",
      "model": "glm-4.7",
      "api_keys": ["your-zhipu-key"]
    }
  ],
  "agents": {
    "defaults": {
      "model": "gpt-5.4"
    }
  }
}

Security Note: You can remove api_keys fields from your config and store them in .security.yml instead. See Security Configuration above for details.

Note: The enabled field can be set to false to disable a model entry without removing it. When omitted, it defaults to true during migration for models that have API keys.

Resolution rules:

Streaming Configuration

Provider streaming uses a double opt-in and is disabled by default. The agent only tries streaming when the current channel has settings.streaming.enabled: true, the active model entry has streaming.enabled: true, and both the provider and channel support streaming. If any condition is missing, PicoClaw uses the normal non-streaming request path.

Pico WebUI is the first fully wired channel. Pico creates the first assistant message with the existing message.create wire message, then updates that same message with message.update; no new Pico wire message type is introduced.

Leave streaming unset when you do not want streaming. An omitted streaming block means disabled; you do not need to write "streaming": {"enabled": false}.

Opt-in example:

{
  "model_list": [
    {
      "model_name": "gpt-5.4",
      "provider": "openai",
      "model": "gpt-5.4",
      "api_keys": ["sk-your-openai-key"],
      "streaming": {
        "enabled": true
      }
    }
  ],
  "channel_list": {
    "pico": {
      "enabled": true,
      "type": "pico",
      "settings": {
        "token": "YOUR_PICO_TOKEN",
        "streaming": {
          "enabled": true
        }
      }
    }
  }
}
Field Type Default Description
channel_list.<name>.settings.streaming.enabled bool false Allows this channel to display provider streaming output
channel_list.<name>.settings.streaming.throttle_seconds int Pico default after enabling: 0 Minimum interval for intermediate updates; final content is always flushed
channel_list.<name>.settings.streaming.min_growth_chars int Pico default after enabling: 1 Minimum character growth before sending an intermediate update; final content is always flushed
model_list[].streaming.enabled bool false Allows this model entry to try provider streaming requests

Legacy Telegram environment variables remain compatible: PICOCLAW_CHANNELS_TELEGRAM_STREAMING_ENABLED, PICOCLAW_CHANNELS_TELEGRAM_STREAMING_THROTTLE_SECONDS, and PICOCLAW_CHANNELS_TELEGRAM_STREAMING_MIN_GROWTH_CHARS. They only apply to Telegram settings and do not enable or modify Pico settings.streaming.

Failure behavior is intentionally conservative: if streaming fails before any visible chunk is sent, PicoClaw retries once through the normal Chat() path. If a chunk has already been shown to the user, PicoClaw does not send a second non-streaming answer, because that would duplicate visible output.

For model-specific TTS request fields such as custom speech voice names or response_format: "mp3", use model_list[].extra_body.

Vendor-Specific Examples

Tip: You can omit api_key fields and store them in .security.yml for better security. See Security Configuration.

OpenAI ```json { "model_name": "gpt-5.4", "provider": "openai", "model": "gpt-5.4" // api_key: set in .security.yml } ```
OpenRouter TTS (MAI Voice 2) ```json { "model_name": "mai-voice-2", "provider": "openrouter", "model": "microsoft/mai-voice-2", "api_base": "https://openrouter.ai/api/v1", "extra_body": { "voice": "en-US-Harper:MAI-Voice-2", "response_format": "mp3" } // api_key: set in .security.yml } ``` Pair this with: ```json { "voice": { "tts_model_name": "mai-voice-2" } } ```
VolcEngine (Doubao) ```json { "model_name": "ark-code-latest", "provider": "volcengine", "model": "ark-code-latest" // api_key: set in .security.yml } ```
智谱 AI (GLM) ```json { "model_name": "glm-4.7", "provider": "zhipu", "model": "glm-4.7" // api_key: set in .security.yml } ```
DeepSeek ```json { "model_name": "deepseek-chat", "provider": "deepseek", "model": "deepseek-chat" // api_key: set in .security.yml } ```
Anthropic ```json { "model_name": "claude-sonnet-4.6", "provider": "anthropic", "model": "claude-sonnet-4.6" // api_key: set in .security.yml } ``` > Run `picoclaw auth login --provider anthropic` to paste your API token. For direct Anthropic API access or custom endpoints that only support Anthropic's native message format: ```json { "model_name": "claude-opus-4-6", "provider": "anthropic-messages", "model": "claude-opus-4-6", "api_keys": ["sk-ant-your-key"], "api_base": "https://api.anthropic.com" } ``` > Use `anthropic-messages` when the endpoint requires Anthropic's native `/v1/messages` format instead of OpenAI-compatible `/v1/chat/completions`.
Ollama (local) ```json { "model_name": "llama3", "provider": "ollama", "model": "llama3" } ```
LM Studio (local) ```json { "model_name": "lmstudio-local", "provider": "lmstudio", "model": "openai/gpt-oss-20b" } ``` `api_base` defaults to `http://localhost:1234/v1`. API key is optional unless your LM Studio server enables authentication.
With explicit `provider`, PicoClaw sends `openai/gpt-oss-20b` unchanged to LM Studio. The legacy compatibility form `"model": "lmstudio/openai/gpt-oss-20b"` still resolves to the same upstream model ID when `provider` is omitted.
Custom Proxy / LiteLLM ```json { "model_name": "my-custom-model", "provider": "openai", "model": "custom-model", "api_base": "https://my-proxy.com/v1" // api_key: set in .security.yml } ``` With explicit `provider`, PicoClaw sends `model` unchanged. That means `"provider": "litellm", "model": "lite-gpt4"` sends `lite-gpt4`, while `"provider": "litellm", "model": "openai/gpt-4o"` sends `openai/gpt-4o`. The legacy compatibility forms `litellm/lite-gpt4` and `litellm/openai/gpt-4o` still resolve the same way when `provider` is omitted.

Load Balancing

Configure multiple endpoints for the same model name — PicoClaw will automatically round-robin between them:

Option 1: Multiple API Keys in .security.yml (Recommended)

# .security.yml
model_list:
  gpt-5.4:
    api_keys:
      - "sk-proj-key-1"
      - "sk-proj-key-2"
// config.json
{
  "model_list": [
    {
      "model_name": "gpt-5.4",
      "provider": "openai",
      "model": "gpt-5.4",
      "api_base": "https://api.openai.com/v1"
      // api_keys loaded from .security.yml
    }
  ]
}

Option 2: Multiple Model Entries

{
  "model_list": [
    {
      "model_name": "gpt-5.4",
      "provider": "openai",
      "model": "gpt-5.4",
      "api_base": "https://api1.example.com/v1",
      "api_keys": ["sk-key1"]
    },
    {
      "model_name": "gpt-5.4",
      "provider": "openai",
      "model": "gpt-5.4",
      "api_base": "https://api2.example.com/v1",
      "api_keys": ["sk-key2"]
    }
  ]
}

Migration from Legacy providers Config

The old providers configuration is deprecated and has been removed in V2. Existing V0/V1 configs are auto-migrated. See docs/migration/model-list-migration.md for the full guide.

Provider Architecture

PicoClaw routes providers by protocol family:

This keeps the runtime lightweight while making new OpenAI-compatible backends mostly a config operation (api_base + api_keys).

Zhipu (legacy providers format) ```json { "agents": { "defaults": { "workspace": "~/.picoclaw/workspace", "model": "glm-4.7", "max_tokens": 8192, "temperature": 0.7, "max_tool_iterations": 20, "max_parallel_turns": 5 } }, "providers": { "zhipu": { "api_key": "Your API Key", "api_base": "https://open.bigmodel.cn/api/paas/v4" } } } ``` > **Note**: The `providers` format is deprecated. Use the new `model_list` format with `.security.yml` for better security. > > **`max_parallel_turns`**: Controls concurrent processing of messages from different sessions. `5` is the default; `0` or `1` = sequential; `>1` = parallel. Messages from the same session are always serialized. See [Steering docs](/picoclaw/architecture/steering.html) for details.
Full config example ```json { "agents": { "defaults": { "model_name": "claude-opus-4-5" } }, "session": { "dm_scope": "per-channel-peer", "backlog_limit": 20 }, "channel_list": { "telegram": { "enabled": true, "type": "telegram", // token: set in .security.yml "allow_from": ["123456789"] } }, "tools": { "web": { "duckduckgo": { "enabled": true, "max_results": 5 } } }, "heartbeat": { "enabled": true, "interval": 30 } } ``` > **Note**: Sensitive fields (`api_key`, `token`, etc.) can be omitted and stored in `.security.yml` for better security.

Tool Loop Detection

Loop detection is an optional guard against consecutive identical tool calls within one turn:

{
  "agents": {
    "defaults": {
      "loop_detection": {
        "enabled": true,
        "repeat_threshold": 3,
        "critical_threshold": 6,
        "window_size": 20
      }
    }
  }
}

At repeat_threshold, PicoClaw adds a turn-local warning for the model. At critical_threshold, it stops the loop with a final response. window_size bounds the per-turn hash history and must cover the critical threshold. Calls are compared using the tool name and complete arguments, so legitimate pagination and different paths or IDs remain distinct. spawn_status polling is excluded because the same request can return a new task status; it also resets any preceding repeat streak. The feature is disabled by default and complements, rather than replaces, max_tool_iterations.

Scheduled Tasks / Reminders

PicoClaw supports cron-style scheduled tasks via the cron tool. The agent can set, list, and cancel reminders or recurring jobs that trigger at specified times.

{
  "tools": {
    "cron": {
      "enabled": true,
      "exec_timeout_minutes": 5,
      "allow_command": true,
      "command_allowed_remotes": []
    }
  }
}

Scheduled tasks persist across restarts and are stored in ~/.picoclaw/workspace/cron/.

Command cron jobs can execute shell commands. By default, remote channels cannot schedule command jobs. To allow specific remote channels, set command_allowed_remotes to entries such as "telegram" or "telegram:1234567890"; use "*" only if every non-empty channel should be allowed. The "*" wildcard is potentially dangerous because any remote channel that can talk to PicoClaw can schedule shell commands. This does not bypass allow_command, command_confirm, or exec safety checks.

Advanced Topics

Topic Description
Security Configuration Store API keys and secrets in separate .security.yml file
Sensitive Data Filtering Filter API keys and tokens from tool results before sending to LLM
Hook System Event-driven hooks: observers, interceptors, approval hooks
Steering Inject messages into a running agent loop between tool calls
SubTurn Subagent coordination, concurrency control, lifecycle
Context Management Context boundary detection, proactive budget check, compression