Configuration
Arcana is configured through JSON config files — a project-level arcana.json plus an optional global file. Most settings have sensible defaults and can be overridden with environment variables.
Prefer environment variables for API keys so they stay out of version control.
Config file location
Arcana merges configuration from three layers, later winning:
| Layer | Path | Notes |
|---|---|---|
| Global | ~/.config/arcana/arcana.json (or .jsonc) | Created automatically with a $schema stub on first run |
| Project | arcana.json / arcana.jsonc in your repo | Arcana walks up parent directories to find the nearest one |
| Environment | env vars | Always win for API keys and provider overrides |
The legacy layout is still loaded: ~/.arcana/config.json, with the root overridable via ARCANA_HOME:
export ARCANA_HOME=/custom/path
# Legacy config is then loaded from /custom/path/config.json
Escape hatches: ARCANA_CONFIG / ARCANA_CONFIG_DIR / ARCANA_CONFIG_CONTENT point config at an explicit path or inline JSON, and ARCANA_DISABLE_PROJECT_CONFIG=1 ignores project files entirely. Unknown keys are rejected with a validation error.
Full config reference
{
"$schema": "https://arcana.otnelhq.com/config.json",
"model": "anthropic/claude-sonnet-4-6",
"small_model": "anthropic/claude-haiku-4-5",
"provider": "openai",
"utilityModel": "gpt-4o-mini",
"apiKey": "sk-...",
"default_agent": "primary",
"instructions": ["Always run tests after refactoring"],
"agent": {
"reviewer": { "description": "Code review agent", "model": "anthropic/claude-opus-4" }
},
"permission": {
"edit": "allow",
"bash": "ask",
"webfetch": "deny"
},
"mcp": {
"browser": { "type": "local", "command": ["agent-browser", "mcp", "--tools", "core"], "enabled": true }
},
"dataDir": "~/.arcana/data",
"skillsDirs": ["~/.arcana/skills"],
"memory": {
"enabled": true,
"maxSessions": 1000
},
"cron": {
"enabled": true,
"intervalSeconds": 60
},
"gateway": {
"telegram": { "token": "...", "allowedUsers": ["12345678"] },
"discord": { "token": "...", "allowedChannels": ["987654321"] },
"slack": { "botToken": "xoxb-...", "signingSecret": "...", "allowedChannels": ["C0123"] },
"whatsapp": { "phoneNumberId": "...", "accessToken": "...", "appSecret": "...", "allowedUsers": ["14155551234"] }
}
}
Core settings
| Key | Type | Default | Description |
|---|---|---|---|
provider | string | auto-detected | LLM provider (openai, anthropic, gemini, etc.) |
model | string | auto-detected | Model ID (gpt-4o, claude-sonnet-4, or provider/model) |
small_model | string | — | Cheap model for extraction and compaction (new-style key) |
utilityModel | string | main model | Cheap model for extraction and compaction (legacy key, still honored) |
apiKey | string | — | Provider API key (prefer env vars) |
default_agent | string | primary | Agent used when none is specified |
instructions[] | string[] | — | Project instructions injected into every session |
agent{} | object | — | Custom agents: description, mode, model, permission, disable |
permission{} | object | — | Per-tool allow/ask/deny with glob patterns (last match wins). See Permissions |
mcp{} | object | — | MCP servers: local command[] or remote url + headers. See MCP & Tools |
dataDir | string | ~/.arcana/data | Directory for sessions, memory, and local DB |
Provider auto-detection
If neither provider nor model is set in the config or environment, Arcana auto-detects from available API keys using the models.dev catalog (200+ models across 33 providers).
# Set a provider key — Arcana detects it automatically
export OPENAI_API_KEY=sk-...
arcana run "hello" # Uses OpenAI automatically
Memory settings
| Key | Type | Default | Description |
|---|---|---|---|
memory.enabled | boolean | true | Enable conversation memory and fact extraction |
memory.maxSessions | number | 1000 | Maximum sessions to retain in local DB |
Memory stores conversation history, extracted facts, and skill usage stats in SQLite under ~/.arcana/data/.
Session compaction
Long sessions auto-summarize near the context limit (default 85%).
| Key | Type | Default | Description |
|---|---|---|---|
compaction.auto | boolean | true | Enable automatic compaction |
compaction.threshold_percent | number | 85 | Trigger when usage reaches this % of context (1–100) |
compaction.intra | boolean | true | Mid-loop compact during multi-step tool runs |
compaction.intra_min_steps | number | 3 | Min agent loop steps before intra compact |
compaction.intra_min_tokens | number | 5000 | Min usage before intra compact is worth it |
{
"compaction": {
"auto": true,
"threshold_percent": 85,
"intra": true
}
}
Set "intra": false to only compact between user turns. Set "auto": false to disable all auto compact (manual /compact still works).
Setting "auto": false will stop all automatic compaction. You can still compact manually with /compact.
Cron settings
| Key | Type | Default | Description |
|---|---|---|---|
cron.enabled | boolean | true | Enable the cron scheduler |
cron.intervalSeconds | number | 60 | How often the scheduler checks for due jobs |
Skills settings
| Key | Type | Default | Description |
|---|---|---|---|
skillsDirs | string[] | ["~/.arcana/skills", " | Directories to scan for SKILL.md files |
Gateway settings
Configure chat platform adapters. See Gateway for full setup instructions.
| Key | Type | Description |
|---|---|---|
gateway.telegram.token | string | Telegram bot token |
gateway.telegram.allowedUsers | string[] | Allowed Telegram user IDs |
gateway.discord.token | string | Discord bot token |
gateway.discord.allowedChannels | string[] | Allowed Discord channel IDs |
gateway.slack.botToken | string | Slack bot token (xoxb-...) |
gateway.slack.signingSecret | string | Slack signing secret |
gateway.slack.allowedChannels | string[] | Allowed Slack channel IDs |
gateway.whatsapp.phoneNumberId | string | Meta phone number ID |
gateway.whatsapp.accessToken | string | Meta access token |
gateway.whatsapp.appSecret | string | Meta app secret (required for production) |
gateway.whatsapp.allowedUsers | string[] | Allowed phone numbers (with country code) |
Environment variables
All config file settings can be overridden with environment variables.
| Env var | Overrides | Description |
|---|---|---|
ARCANA_HOME | config path | Root directory for the legacy layout (default: ~/.arcana) |
ARCANA_PROVIDER | provider | LLM provider |
ARCANA_MODEL | model | Model ID |
ARCANA_API_KEY | apiKey | Provider API key |
OPENAI_API_KEY | apiKey | Fallback when provider is openai |
ARCANA_SKILLS_DIRS | skillsDirs | Skill directories (separated by ;) |
ARCANA_PROXY_KEY | — | Proxy license key (auto-loaded from ~/.arcana/proxy_key) |
ARCANA_CONFIG | config path | Explicit config file path |
ARCANA_CONFIG_DIR | config dir | Explicit config directory |
ARCANA_CONFIG_CONTENT | config body | Inline JSON config content |
ARCANA_DISABLE_PROJECT_CONFIG=1 | — | Ignore project-level arcana.json |
ARCANA_PURE=1 | — | Skip all external config, skills, and state |
ARCANA_SERVER_USERNAME | — | Username for non-loopback serve (default arcana) |
ARCANA_ENGINE_BASE_URL | — | Engine HTTP endpoint (default http://localhost:4096) |
ARCANA_DEPLOYMENT_MODE | — | LOCAL, HYBRID, or ENTERPRISE |
ARCANA_ML_RUNTIME=1 | — | Enable the signal engine (quality gates, auto model switching) |
Provider-specific env vars
| Env var | Provider |
|---|---|
ANTHROPIC_API_KEY | Anthropic |
GEMINI_API_KEY | Google Gemini |
AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY | Amazon Bedrock |
CLOUDFLARE_ACCOUNT_ID + CLOUDFLARE_API_TOKEN | Cloudflare Workers AI |
XAI_API_KEY | xAI (Grok) |
Use arcana doctor to confirm which keys are detected.
Data directory
Default: ~/.arcana/data/
| Path | Contents |
|---|---|
sessions/ | Session transcripts |
memory.db | SQLite DB with facts, skill stats |
cron-jobs.json | Scheduled job definitions |
~/.arcana/workspace-trust.json | Trusted workspace fingerprints (at the Arcana home root, not in data/) |
Trust and security settings
| Setting | Location | Description |
|---|---|---|
arcana trust | CLI command | Trust current workspace for project plugins/tools |
ARCANA_DISABLE_WORKSPACE_TRUST=1 | Env var | Skip trust checks (dev only) |
ARCANA_TRUST_WORKSPACE=1 | Env var | Force-trust for CI |
ARCANA_SERVER_PASSWORD | Env var | Required for non-loopback arcana serve |
ARCANA_GATEWAY_OPEN=1 | Env var | Allow empty gateway allowlists (dev only) |