Chibi uses a layered configuration system with separate files for core and CLI settings.
Settings are resolved in this order (later overrides earlier):
- Defaults - Built-in default values
- Global config (
~/.chibi/config.toml) - User's base configuration - Environment variables -
CHIBI_API_KEY,CHIBI_MODEL(see below) - Global model overrides (
config.toml[models]) - Per-model API params - Context config (
~/.chibi/contexts/<name>/local.toml) - Per-context overrides - Context model overrides (
local.toml[models]) - Per-context per-model API params - CLI flags - Command-line arguments (highest priority)
Presentation settings (markdown rendering, images, color themes) live in separate files:
- Global CLI config (
~/.chibi/cli.toml) - CLI presentation settings - Context CLI config (
~/.chibi/contexts/<name>/cli.toml) - Per-context overrides
By default, chibi stores all data in ~/.chibi. This can be overridden:
--home <PATH>CLI flag (highest priority)CHIBI_HOMEenvironment variable~/.chibidefault
Use -n home to see the resolved path.
Chibi auto-detects the project root for context-aware features (AGENTS.md loading, codebase indexing). Resolution order:
--project-rootCLI flag (highest priority)CHIBI_PROJECT_ROOTenvironment variable- VCS root detection (walk up from cwd)
- Current working directory (fallback)
Supported VCS markers (checked in order, nearest match wins):
| Marker | VCS |
|---|---|
.git (dir or file) |
Git (incl. worktrees, submodules) |
.hg/ |
Mercurial |
.svn/ |
Subversion |
.bzr/ |
Bazaar |
.pijul/ |
Pijul |
.jj/ |
Jujutsu |
.fslckout (file) |
Fossil |
_FOSSIL_ (file) |
Fossil (alt) |
CVS/ |
CVS (walks up to highest containing dir) |
Chibi loads instruction files from standard locations and injects them into the system prompt. Files are concatenated in order; later entries appear later in the prompt and can effectively override earlier guidance.
Discovery locations (in order):
~/AGENTS.md— user-global, tool-independent instructions~/.chibi/AGENTS.md— chibi-global instructions<project_root>/AGENTS.md— project root- Each directory from project root down to cwd (e.g.
<project_root>/packages/frontend/AGENTS.md)
Empty files are skipped. When cwd equals project root, the root file appears only once.
Content appears in the system prompt under --- AGENT INSTRUCTIONS ---, after the base prompt and before context metadata.
Create ~/.chibi/config.toml (or <CHIBI_HOME>/config.toml if overridden):
All fields are optional. chibi works with no config file at all (free-tier OpenRouter, default model).
# =============================================================================
# Core Settings (all optional)
# =============================================================================
# API key for OpenRouter (https://openrouter.ai/settings/keys)
# Omit for free-tier access (no key needed)
# api_key = "your-api-key-here"
# Model to use (default: ratatoskr:free/agentic)
# model = "anthropic/claude-sonnet-4"
# Context window limit in tokens (default: fetched from ratatoskr registry)
# context_window_limit = 200000
# Warning threshold percentage (default: 80.0)
# warn_threshold_percent = 80.0
# =============================================================================
# Optional Settings
# =============================================================================
# Default username shown to the LLM (default: "user")
username = "user"
# Omit tools from API requests entirely for pure text mode (default: false)
no_tool_calls = false
# Fallback tool when LLM doesn't explicitly call call_agent/call_user
# Options: "call_user" (return to user) or "call_agent" (continue loop)
fallback_tool = "call_user"
# Cost tier for resolving subagent model presets (default: "free")
# Controls which ratatoskr preset tier is used when spawn_agent is given a
# preset capability name (e.g. "fast", "reasoning") instead of an explicit model.
# subagent_cost_tier = "free"
# =============================================================================
# Auto-Compaction
# =============================================================================
# Enable automatic context compaction (default: false)
auto_compact = false
# Threshold percentage to trigger auto-compaction (default: 80.0)
auto_compact_threshold = 80.0
# Target percentage of messages to archive during rolling compaction (default: 50.0)
rolling_compact_drop_percentage = 50.0
# =============================================================================
# Reflection (Persistent Memory)
# =============================================================================
# Enable the reflection feature (default: true)
reflection_enabled = true
# Maximum characters for reflection content (default: 10000)
reflection_character_limit = 10000
# =============================================================================
# Fuel Budget (Agentic Loop Limits)
# =============================================================================
# Total fuel budget for autonomous tool loops (default: 0 = unlimited)
# Each tool-call round and agent continuation costs 1 fuel. First turn is free.
# Set to a positive number to enable fuel tracking (budget enforced,
# fuel info injected into prompts and hook payloads).
fuel = 0
# Fuel cost of an empty LLM response (default: 15)
# When the LLM returns an empty response (no text, no tool calls), this much
# fuel is consumed. High cost prevents infinite empty-response loops.
# Ignored when fuel = 0 (unlimited mode).
fuel_empty_response_cost = 15
# Context lock heartbeat interval in seconds (default: 30)
lock_heartbeat_seconds = 30
# =============================================================================
# Tool Output Caching
# =============================================================================
# Character threshold above which tool outputs are cached (default: 4000)
# When exceeded, output is cached to disk and a truncated preview is sent to the LLM
tool_output_cache_threshold = 4000
# Maximum age for cached outputs before automatic cleanup (default: 7)
# Note: Value is offset by 1 day, so:
# 0 = delete after 1 day (24 hours)
# 1 = delete after 2 days (48 hours)
# 7 = delete after 8 days (default)
tool_cache_max_age_days = 7
# Automatically cleanup old cache entries on exit (default: true)
auto_cleanup_cache = true
# Number of preview characters to show in truncated message (default: 500)
tool_cache_preview_chars = 500
# =============================================================================
# Built-in file operations
# =============================================================================
# Paths allowed for read-only file tools (default: empty = VFS only)
# When empty, file tools only work with vfs:/// URIs. Add paths to allow OS file access.
# file_tools_allowed_paths = ["~", "/tmp"]
# =============================================================================
# Tool Filtering (global baseline, per-context local.toml merges on top)
# =============================================================================
# [tools]
# include = ["update_reflection", "shell_exec"] # allowlist (local overrides entirely)
# exclude = ["file_grep"] # blocklist (local appends)
# exclude_categories = ["agent"] # category blocklist (local appends)
# =============================================================================
# API Parameters
# =============================================================================
[api]
# Temperature for sampling (0.0 to 2.0)
# temperature = 0.7
# Maximum tokens to generate
# max_tokens = 4096
# Nucleus sampling parameter (0.0 to 1.0)
# top_p = 0.9
# Stop sequences (array of strings)
# stop = ["\n\n", "END"]
# Frequency penalty (-2.0 to 2.0)
# frequency_penalty = 0.0
# Presence penalty (-2.0 to 2.0)
# presence_penalty = 0.0
# Random seed for deterministic output
# seed = 12345
# Enable parallel tool calls (default: true)
# parallel_tool_calls = true
# Tool choice: "auto", "none", "required"
# tool_choice = "auto"
# Enable prompt caching (default: true, mainly benefits Anthropic models)
# prompt_caching = true
# Response format: "text" or "json_object"
# [api.response_format]
# type = "json_object"
# -----------------------------------------------------------------------------
# Reasoning Configuration (for models with extended thinking)
# -----------------------------------------------------------------------------
# Use EITHER effort OR max_tokens, not both.
[api.reasoning]
# Effort level: "xhigh", "high", "medium", "low", "minimal", "none"
# Supported by: OpenAI o1/o3/GPT-5 series, Grok models
effort = "medium"
# OR use token budget instead of effort level:
# Supported by: Anthropic Claude, Gemini thinking models, some Qwen models
# max_tokens = 16000
# Exclude reasoning from response (model still reasons internally)
# exclude = false
# Explicitly enable/disable reasoning
# enabled = truePer-model API parameter overrides under [models."<model-id>"] in config.toml (global)
or local.toml (per-context). Local overrides take precedence over global.
Model capabilities (context window, tool call support) come from ratatoskr's registry automatically — no need to configure them here.
Use chibi -M to see what parameters a model supports.
In config.toml (global) or local.toml (per-context):
# Each key should match the model name used in `model` or local.toml
# Claude with extended thinking (token-based reasoning)
[models."anthropic/claude-sonnet-4".api.reasoning]
max_tokens = 32000
# OpenAI reasoning models (effort-based reasoning)
[models."openai/o3".api]
max_tokens = 100000
[models."openai/o3".api.reasoning]
effort = "high"
# Gemini thinking model (token-based reasoning)
[models."google/gemini-2.0-flash-thinking-exp:free".api.reasoning]
max_tokens = 16000When you use a model, chibi checks for a matching entry and applies:
api.*- Model-specific API parameters (merged with global settings)
Each context can override settings in ~/.chibi/contexts/<name>/local.toml:
# Override model for this context
model = "openai/o3"
# Override API key (useful for different billing accounts)
api_key = "sk-different-key"
# Override username
username = "alice"
# Override context window
context_window_limit = 128000
# Override warning threshold
warn_threshold_percent = 90.0
# Override tool omission
no_tool_calls = false
# Override auto-compact behavior
auto_compact = true
auto_compact_threshold = 85.0
# Override fuel budget
fuel = 25
# Override empty response fuel cost
fuel_empty_response_cost = 20
# Override reflection
reflection_enabled = false
# Override tool caching
tool_output_cache_threshold = 8000
tool_cache_max_age_days = 14
auto_cleanup_cache = false
tool_cache_preview_chars = 1000
file_tools_allowed_paths = ["~/projects"]
# Context-specific API parameters
[api]
temperature = 0.3
max_tokens = 8000
[api.reasoning]
effort = "high"
# Tool filtering (merges with global [tools] config)
[tools]
# Allowlist mode - only these tools are available (overrides global include)
# include = ["update_goals", "update_reflection", "send_message"]
# Blocklist mode - these tools are excluded (appends to global exclude)
exclude = ["file_grep"]
# Exclude entire categories (appends to global exclude_categories)
# exclude_categories = ["coding"]Set username via CLI (automatically saves to local.toml):
chibi -u alice "Hello" # Persists to local.toml
chibi -U bob "Hello" # Ephemeral, doesn't persistModel can be set similarly:
chibi -m anthropic/claude-sonnet-4 # Persists to local.toml (validated live)
chibi -s model=anthropic/claude-sonnet-4 "Hello" # Ephemeral, doesn't persistCLI-specific presentation settings live in ~/.chibi/cli.toml. These control how output is rendered in the terminal and are separate from core configuration to support future frontends.
# =============================================================================
# Markdown Rendering
# =============================================================================
# Render LLM output as formatted markdown in the terminal (default: true)
# Set to false for raw output (useful for piping)
render_markdown = true
# =============================================================================
# Diagnostics and Display
# =============================================================================
# Show extra diagnostic info: tools loaded, warnings, fuel, etc. (default: false)
# Equivalent to the -v / --verbose flag
verbose = false
# Hide tool call display (default: false — tool calls shown by default)
# Equivalent to the --hide-tool-calls flag
hide_tool_calls = false
# Show thinking/reasoning content from models that support extended thinking (default: false)
# Equivalent to the --show-thinking flag
show_thinking = false
# =============================================================================
# Image Configuration
# =============================================================================
[image]
# Render images inline in the terminal (default: true)
render_images = true
# Maximum bytes to download for remote images (default: 10 MB)
max_download_bytes = 10485760
# Timeout in seconds for fetching remote images (default: 5)
fetch_timeout_seconds = 5
# Allow fetching images over plain HTTP (default: false, HTTPS only)
allow_http = false
# Maximum image height in terminal lines (default: 25)
max_height_lines = 25
# Percentage of terminal width to use for images (default: 80)
max_width_percent = 80
# Image alignment: "left", "center", "right" (default: "center")
alignment = "center"
# Image rendering mode (default: "auto")
# Options: "auto", "truecolor", "ansi", "ascii", "placeholder"
render_mode = "auto"
# Enable individual rendering modes (default: all true)
enable_truecolor = true
enable_ansi = true
enable_ascii = true
# Image caching for remote images
cache_enabled = true
cache_max_bytes = 104857600 # 100 MB
cache_max_age_days = 30
# =============================================================================
# Markdown Color Scheme
# =============================================================================
[markdown_style]
bright = "#FFFF54" # emphasis, h2 headers
head = "#54FF54" # h3 headers
symbol = "#7ABFC7" # bullets, language labels
grey = "#808080" # borders, muted text
dark = "#000000" # code block background
mid = "#3E31A2" # table headers
light = "#352879" # alternate backgroundsCreate ~/.chibi/contexts/<name>/cli.toml to override CLI settings for specific contexts. Only specify fields you want to change:
# Disable markdown rendering for this context
render_markdown = false
# Always show verbose output in this context
verbose = true
# Always show thinking in this context
show_thinking = true
[image]
# Taller images in this context
max_height_lines = 50
[markdown_style]
# Different color scheme
bright = "#00FF00"Chibi delegates LLM communication to the ratatoskr crate.
| Parameter | Type | Range | Description |
|---|---|---|---|
temperature |
float | 0.0-2.0 | Sampling temperature. Higher = more random. |
max_tokens |
integer | 1+ | Maximum tokens to generate. |
top_p |
float | 0.0-1.0 | Nucleus sampling. Lower = more focused. |
stop |
array | - | Sequences that stop generation. |
seed |
integer | - | Random seed for reproducibility. |
frequency_penalty |
float | - | Penalize frequent tokens. |
presence_penalty |
float | - | Penalize tokens that appeared. |
| Parameter | Type | Description |
|---|---|---|
tool_choice |
string | How the model uses tools (auto, none, required). |
parallel_tool_calls |
boolean | Allow multiple tool calls at once (default: true). |
response_format |
object | Force JSON output format. |
prompt_caching |
boolean | Enable prompt caching (default: true, mainly benefits Anthropic models). |
reasoning.* |
various | Extended thinking configuration (see below). |
For models that support extended thinking (chain-of-thought reasoning).
| Parameter | Type | Values | Description |
|---|---|---|---|
reasoning.effort |
string | xhigh, high, medium, low, minimal, none |
Reasoning effort level. |
reasoning.max_tokens |
integer | 1024-128000 | Token budget for reasoning. |
reasoning.exclude |
boolean | - | Hide reasoning from response. |
reasoning.enabled |
boolean | - | Explicitly enable/disable. |
Note: Use either effort OR max_tokens, not both. Different models support different options:
- Effort-based: OpenAI o1/o3/GPT-5 series, Grok models
- Token-based: Anthropic Claude, Gemini thinking models, Qwen models
When resolving API parameters, chibi merges in this order:
- Defaults (
prompt_caching=true,reasoning.effort="medium",parallel_tool_calls=true) - Global config (
config.toml[api]section) - Global model overrides (
config.toml[models."name".api]section) - Context config (
local.toml[api]section) - Context model overrides (
local.toml[models."name".api]section)
Each layer can override specific values while inheriting others.
Two config fields can be set via environment variables, useful for CI/CD secret injection, container deployments, and quick model switching:
| Variable | Overrides | Example |
|---|---|---|
CHIBI_API_KEY |
api_key in config.toml |
CHIBI_API_KEY=sk-... chibi "hello" |
CHIBI_MODEL |
model in config.toml |
CHIBI_MODEL=openai/o3 chibi "solve this" |
Priority: env vars override config.toml but are overridden by local.toml and CLI flags. See resolution order for the full hierarchy.
Chibi reads these environment variables for feature detection:
COLORTERM- Checked for truecolor support (truecoloror24bit)TERM- Checked for color capability level (truecolor,256color,color)
Plugins receive these environment variables:
CHIBI_VERBOSE=1- Set when-vflag is usedCHIBI_HOOK- Hook point name (for hook calls)CHIBI_TOOL_NAME- Name of the tool being called
Plugin input is passed via stdin as JSON (tool arguments for tool calls, hook data for hooks).
Chibi includes built-in coding tools that work out of the box — no plugins needed. These tools are automatically included in every API request (unless filtered out via tool filtering or --no-tool-calls).
Permission-gated tools prompt for confirmation before executing:
| Tool | Hook | What it does |
|---|---|---|
shell_exec |
PreShellExec |
Execute shell commands |
file_edit |
PreFileWrite |
Patch files (search/replace) |
write_file |
PreFileWrite |
Create or overwrite files |
fetch_url |
PreFetchUrl |
Fetch a URL (gated for sensitive addresses) |
summarize_content |
PreFetchUrl |
Read and summarize a URL source (gated when source is a URL) |
The interactive prompt defaults to allow ([Y/n]) — press Enter to approve, or type n to deny. This makes sense because if you gave the LLM tools, you probably want it to use them.
Read-only tools execute without prompting: dir_list, glob_files, grep_files, file_head, file_tail, file_lines, file_grep, index_query, index_status, index_update.
When no TTY is available (piped input, CI, parent process), the permission handler cannot prompt and fails safe by denying all gated operations. Read-only tools still work.
To allow gated tools in headless mode, use trust mode:
echo '{"command": {"send_prompt": {"prompt": "list files"}}}' | chibi-json
chibi -t "refactor this module"-t / --trust auto-approves all permission checks. Use with caution — the LLM will be able to execute arbitrary shell commands and write files without confirmation.
Plugins can implement custom permission logic via the pre_file_write and pre_shell_exec hooks. A plugin that returns {"denied": true} overrides all other approvals (deny wins). See hooks documentation for details.
By default, fetch_url and summarize_content (when given a URL source) prompt for permission when fetching sensitive URLs (loopback, private network, link-local, cloud metadata). A URL policy replaces this interactive check with declarative rules — useful for automation and chibi-json.
[url_policy]
default = "deny" # deny all URLs by default
allow = [
"preset:loopback", # allow localhost
"https://api.example.com/*", # allow by glob pattern
]
deny_override = ["preset:cloud_metadata"] # always deny, even if allowed aboveEvaluation order (first match wins, highest priority first):
deny_override— unconditional denyallow_override— unconditional allow (except deny_override)deny— standard denyallow— standard allowdefault— fallback (allowif omitted)
Rule types:
preset:<category>— matches a built-in category:loopback,private_network,link_local,cloud_metadata,unparseable- bare string — glob pattern (
*any sequence,?single char,\*literal asterisk)
Config layers: config.toml (global) → local.toml (per-context) → JsonInput (per-invocation). Each layer replaces the previous entirely (no merge). When no policy is set, the interactive permission handler applies as before.
Control which tools are available to the LLM. Tool filtering can be configured globally in config.toml and per-context in local.toml.
[tools]
# Allowlist mode - only these tools are available
# When set, only listed tools can be used
include = ["update_goals", "update_reflection", "send_message"]
# OR blocklist mode - these tools are excluded
# When set, listed tools are removed from available tools
# exclude = ["file_grep", "file_head", "file_tail"]
# Exclude entire tool categories
# exclude_categories = ["shell", "network"]Tool Categories:
| Category | Tools |
|---|---|
memory |
update_reflection, update_goals, read_context, flock_join, flock_leave, flock_list |
flow |
send_message, call_user, model_info, spawn_agent, summarize_content |
fs_read |
file_head, file_tail, file_lines, file_grep, dir_list, glob_files, grep_files |
fs_write |
write_file, file_edit |
shell |
shell_exec |
network |
fetch_url |
index |
index_update, index_query, index_status |
vfs |
vfs_list, vfs_info, vfs_copy, vfs_move, vfs_mkdir, vfs_delete |
synthesised |
Tools defined via .scm files in the VFS |
plugin |
Tools loaded from the plugins directory |
mcp |
MCP tools loaded from the bridge (named <server>_<tool>) |
Global vs. per-context:
[tools]inconfig.tomlsets the global baseline[tools]inlocal.tomlmerges on top:include: local overrides global entirely (if set)exclude: local appends to globalexclude_categories: local appends to global
Scheme tools loaded from the VFS run in a sandbox by default. Override the tier per VFS path prefix using [tools.tiers]:
[tools.tiers]
# path prefix → tier (1 = sandboxed, 2 = unsandboxed)
"/tools/shared" = 1 # default — Modules::Safe + 10M step limit
"/tools/home/admin" = 2 # trusted admin context: full R7RS, no step limit
"/tools/flocks/trusted" = 2 # trusted flock: full R7RSTier values:
1— sandboxed:Modules::Safemodule subset, 10,000,000 step limit. Default for all paths.2— unsandboxed: full R7RS, no step limit. For trusted authors only.
Tier resolution uses prefix matching: the longest matching prefix wins. If no prefix matches, sandboxed (1) is used.
Filter Precedence:
- Config
include(if set, only these tools considered) - Config
exclude(remove from remaining) - Config
exclude_categories(remove matching categories) - Hook
include(intersect with remaining) — viapre_api_toolshook - Hook
exclude(remove from remaining) — viapre_api_toolshook
For dynamic tool filtering based on context or other conditions, use the pre_api_tools hook. See Hooks documentation.
Control which URLs sandboxed synthesised tools may access. Configured globally in config.toml only — [tools.http] in local.toml is ignored (HTTP access is a global security boundary).
[tools.http.allow]
# path prefix → allowlist entry
# Option 1: explicit URL prefix list
"/tools/shared/weather.scm" = ["https://api.openweathermap.org/"]
# Option 2: trust the tool's own `tool-http-allow` declaration
"/tools/home/mycontext/fetch.scm" = "trust-declared"With "trust-declared", chibi reads the tool's top-level tool-http-allow binding (a Scheme list of URL prefix strings) and uses those as the allowlist. This lets tool authors declare their own prefixes without requiring a config change.
Allowlist resolution uses prefix matching: the longest matching VFS path prefix wins. Unsandboxed tools have unrestricted network access regardless of this config.
Control which environment variables are injected into sandboxed synthesised tools. Configured globally in config.toml only — [tools.env] in local.toml is ignored.
[tools.env]
# path prefix → list of env var names to expose
"/tools/shared/weather.scm" = ["WEATHER_API_KEY"]
"/tools/home/mycontext" = ["MY_TOKEN", "MY_SECRET"]At evaluation time, the listed env vars are read from the process environment and injected into the tein context as Scheme string bindings. Variables not present in the environment are silently omitted.
Resolution uses longest-prefix matching on VFS path, same as [tools.tiers].
Configure transcript partitioning in ~/.chibi/config.toml:
[storage]
# Rotate partition after N entries (default: 1000)
partition_max_entries = 1000
# Rotate partition after N estimated LLM tokens (default: 100000)
partition_max_tokens = 100000
# Rotate partition after N seconds (default: 2592000 = 30 days)
partition_max_age_seconds = 2592000
# Bytes per token for estimation heuristic (default: 3)
# Lower values = more conservative (higher token estimates)
# 3 handles mixed English/CJK content; use 4 for English-only
bytes_per_token = 3
# Build bloom filter indexes for search optimization (default: true)
enable_bloom_filters = truePer-context overrides in ~/.chibi/contexts/<name>/local.toml:
[storage]
partition_max_entries = 500
partition_max_tokens = 50000
bytes_per_token = 4 # Less conservative for this contextPartitions rotate when any threshold is reached. This keeps individual partition files manageable while enabling efficient search across conversation history.