Skip to content

Configuration

APX uses two configuration layers — global (machine-local, never committed) and project-local (committed to the repo, no secrets). Commands at both layers use dotted-key syntax and are JSON-aware.

The global config file is created on first run. It holds engine credentials, daemon settings, the super-agent model, voice, memory, and Telegram options.

{
"port": 7430,
"host": "127.0.0.1",
"log_level": "info",
"user": {
"language": "en",
"locale": "",
"timezone": ""
},
"super_agent": { ... },
"engines": { ... },
"memory": { ... },
"voice": { ... },
"telegram": { ... },
"projects": []
}

API keys and base URLs for every supported LLM provider:

{
"engines": {
"anthropic": { "api_key": "sk-ant-..." },
"openai": { "api_key": "sk-...", "base_url": "https://api.openai.com/v1" },
"groq": { "api_key": "...", "base_url": "https://api.groq.com/openai/v1" },
"cerebras": { "api_key": "...", "base_url": "https://api.cerebras.ai/v1" },
"openrouter": { "api_key": "...", "base_url": "https://openrouter.ai/api/v1" },
"gemini": { "api_key": "..." },
"ollama": { "base_url": "http://localhost:11434" }
}
}

APX sends keep_alive: -1 with every Ollama chat request. Once APX loads a model, Ollama keeps it in memory, so later turns avoid a cold model load. Stop it explicitly with ollama stop <model> or restart Ollama to free that memory.

This applies only to models APX calls. A host without enough available RAM or VRAM can still make Ollama unload an idle model to load another one.

Any engine accepts a proxy, and only that engine’s traffic goes through it:

{
"engines": {
"zen": { "proxy": "http://127.0.0.1:8888" }
}
}

Everything else — Telegram, the other providers, the vault, the update check — keeps using the normal route. This is deliberately narrower than HTTPS_PROXY or Node’s --use-env-proxy, which are process-wide.

Because the tunnel lives behind the proxy’s address rather than in this machine’s routing table, it does not fight Tailscale the way a VPN client does. A ready-made container is in examples/egress-proxy/.

A proxy that is configured but unreachable fails the call rather than falling back to the direct route: a silent fallback would send the traffic exactly where the proxy was set up to avoid.

{
"super_agent": {
"enabled": false,
"name": "apx",
"model": "anthropic:claude-sonnet-4-5",
"permission_mode": "automatico",
"allowed_tools": [],
"model_fallback": {
"enabled": true,
"models": [
"openrouter:meta-llama/llama-3.3-70b-instruct",
"groq:llama-3.3-70b-versatile"
],
"health_timeout_ms": 800
}
}
}

permission_mode controls which tools the super-agent can run without asking:

ModeBehavior
totalAll tools allowed, no confirmation
automaticoAPX decides automatically based on safety heuristics
permisoOnly tools listed in allowed_tools; everything else asks

The identity file — ~/.apx/identity.json

Section titled “The identity file — ~/.apx/identity.json”

This file sets the assistant’s user-facing name and personality:

{
"name": "APX",
"persona": ""
}

Change name to give your assistant a different display name across all surfaces (Telegram, Desktop, Web). The technical config key super_agent.name is separate — identity.json is what end users see.

Project config — ~/.apx/projects/<apx_id>/config.json

Section titled “Project config — ~/.apx/projects/<apx_id>/config.json”

Project-level overrides take priority over the global config, for that project only. The file lives in the project’s runtime storage, not in its repo: it used to be .apc/config.json, which is committed, so a mistyped scope could stage an api key for the next push. Keys are safe here. Projects configured before the move are migrated the first time the daemon reads them — the old file is moved, not copied.

.apc/ keeps the portable half — project.json, agents, skills, organization — and the daemon refuses to write anything credential-shaped into it.

{
"super_agent": {
"model": "groq:llama-3.3-70b-versatile",
"permission_mode": "total"
},
"telegram": {
"route_to_agent": "reviewer"
}
}

apx config reaches both layers. It edits the project layer by default and the global layer with --global (or --scope global) — so the flag decides which file you are touching.

Terminal window
apx config show --global # ~/.apx/config.json, secrets redacted
apx config show --global | jq .super_agent # JSON on stdout, header on stderr
apx
$ apx config show --global
{
"port": 7430,
"host": "127.0.0.1",
"log_level": "info",
"super_agent": {
  "enabled": true,
  "model": "anthropic:claude-sonnet-4-5",
  "permission_mode": "automatico"
},
"engines": {
  "anthropic": { "api_key": "sk-ant-••••a91f" },
  "openai":    { "api_key": "sk-••••7c2d" },
  "ollama":    { "base_url": "http://localhost:11434" }
},
"telegram": { "enabled": true, "channels": [ { "name": "default" } ] }
}
apx config show --global — the global configuration as JSON, secrets redacted

Values are JSON-aware — booleans, numbers, and arrays are parsed correctly:

Global settings — credentials, the daemon, voice, and the super-agent defaults — need --global. The write goes through the daemon, which reloads the new value immediately:

Terminal window
apx config set --global super_agent.enabled true
apx config set --global super_agent.model "anthropic:claude-sonnet-4-5"
apx config set --global engines.openai.api_key "sk-..."
apx config unset --global super_agent.model # remove key, fall back to default

Project overrides are the default, so they need no flag. Inside the project:

Terminal window
apx config set super_agent.model groq:llama-3.3-70b-versatile
apx config set telegram.route_to_agent reviewer
apx config unset super_agent.model

From anywhere, naming the project:

Terminal window
apx project config set my-app super_agent.model groq:llama-3.3-70b-versatile
apx project config set my-app telegram.route_to_agent reviewer
apx project config unset my-app super_agent.model
apx project config edit my-app # open in $EDITOR

apx model manages the super-agent’s model fallback router — the ordered list of providers APX tries in sequence when the primary model is unavailable:

Terminal window
apx model status # probe all providers, show active model
apx model order ollama openrouter groq # set fallback order
apx model key groq sk-xxxx # save an API key
apx model set openrouter meta-llama/llama-3.3-70b-instruct # pin a model for one provider
apx model test # which model would be picked right now?
apx model enable # enable the fallback router
apx model disable # disable (primary only, no fallback)
apx
$ apx model status
Model router
primary:   anthropic:claude-sonnet-4-5
fallback:  on
order:     anthropic → openrouter → groq → ollama
active:    anthropic:claude-sonnet-4-5

✓ anthropic    claude-sonnet-4-5                up    key:config
✓ openrouter   meta-llama/llama-3.3-70b         up    key:config
✗ groq         llama-3.3-70b-versatile          down  (no key)
✓ ollama       llama3.2:3b                      up    key:config

Keys → ~/.apx/config.json engines.{groq,openrouter}.api_key
Or env: GROQ_API_KEY, OPENROUTER_API_KEY
apx model status — provider probes, API key presence, and active model

apx permission is a shorthand for reading and writing super_agent.permission_mode:

Terminal window
apx permission show # print current mode
apx permission set total # allow all tools
apx permission set automatico # APX decides
apx permission set permiso # only allowed_tools
  • Projects — per-project config and where it lives.
  • Installation — where ~/.apx/ is first created.