Skip to content

Engines

An engine is a direct LLM adapter inside APX. When you call apx exec or apx chat, APX resolves the target model, selects the matching adapter, and calls the provider API — no external process is spawned.

This is distinct from apx run, which delegates to an external coding CLI. See Runtimes for that path.

ProviderAdapter IDNotes
AnthropicanthropicClaude models; key from ANTHROPIC_API_KEY or config
OpenAIopenaiGPT and o-series models; key from OPENAI_API_KEY or config
GeminigeminiGoogle Gemini models; key from GEMINI_API_KEY or config
OllamaollamaLocal models; no API key needed, just base_url
GroqgroqOpenAI-compatible; default model llama-3.3-70b-versatile
OpenRouteropenrouterOpenAI-compatible; routes to many providers; default model meta-llama/llama-3.3-70b-instruct
MockmockReturns a canned response; useful for testing and CI

Engines are configured in ~/.apx/config.json under the engines key:

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

API keys can also be set via environment variables — ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, GROQ_API_KEY, OPENROUTER_API_KEY — without editing the config file.

When specifying a model to --model or in an agent definition, APX accepts two forms:

  • Explicit: <provider>:<model> — e.g. ollama:llama3.2, anthropic:claude-sonnet-4-5, openrouter:meta-llama/llama-3.3-70b-instruct
  • Inferred: bare model name — APX resolves the provider automatically:
    • claude-* → anthropic
    • gpt-*, o1-*, o3-*, o4-* → openai
    • gemini-* → gemini
    • mock → mock

If APX cannot infer the provider, use the explicit provider:model form.

Terminal window
apx exec "<prompt>" [--model <id>] [--max-tokens N] [--temperature T] [--project <name|id|path>]
apx exec -a <agent> "<prompt>" [--model <id>]

Without -a, the call goes to the APX super-agent (the daemon’s default). With -a, it uses the specified APC agent’s system prompt and memory.

Examples:

Terminal window
# Super-agent, default model
apx exec "Summarize the open tasks in this project"
# Specific agent with model override
apx exec -a reviewer "What are the riskiest changes in this PR?" --model anthropic:claude-opus-4-5
# Local Ollama model
apx exec "Explain this stack trace" --model ollama:llama3.2
# Force a specific output size
apx exec "Write a haiku about daemons" --max-tokens 100
Terminal window
apx chat <agent> [--model <id>] [--conversation <id>] [--project <name|id|path>]

apx chat opens an interactive REPL that keeps a conversation thread alive across turns. Each session is stored under ~/.apx/projects/<apx-id>/agents/<slug>/conversations/. Pass --conversation <id> to resume a previous thread.

Terminal window
apx chat reviewer
apx chat reviewer --conversation abc123

For the APX super-agent (the daemon’s own assistant), APX maintains a model fallback router. Instead of failing when a provider is unavailable, it tries providers in a configurable order.

The router is configured under super_agent.model_fallback in ~/.apx/config.json:

{
"super_agent": {
"model": "ollama:llama3.2:3b",
"model_fallback": {
"enabled": true,
"models": [
"openrouter:meta-llama/llama-3.3-70b-instruct",
"groq:llama-3.3-70b-versatile"
],
"health_timeout_ms": 800
}
}
}

The router tries super_agent.model first. If it fails the health check (Ollama strictly verifies the model is pulled; cloud providers check reachability within health_timeout_ms), it walks model_fallback.models in order and uses the first healthy one.

super_agent.model is also what every project agent with Model: inherit (or no model) runs on. To give the super-agent a different model without moving the whole fleet, set super_agent.self_model (Settings → Super-agent → Own model). It is a preference, not a pin: it is health-checked and falls down the same chain, router #1 first. Switch that off with super_agent.self_model_fallback: false (the checkbox under it) to fail instead; a project agent pinned to its own Model: has the same switch (model_fallback: false, apx agent set --no-model-fallback).

An account whose usage limit is spent is skipped for an hour instead of being retried on every turn, and turns nobody is watching (a2a, routines) stop rather than fall through, unless they started on a model you chose with its fallback on — see the super-agent page. For the ChatGPT plan, reasoning effort is a setting of the model, not another model: the panel shows an Effort control beside every model picker and displays the pair as gpt-5.6-luna · high. It is stored as a suffix on the model id — chatgpt-codex:gpt-5.6-luna@medium (minimal|low|medium|high|xhigh), which is also how the CLI takes it — or as a default in engines.chatgpt-codex.reasoning_effort.

Every engine call is recorded in ~/.apx/usage/<day>.jsonl (UTC days) with its model, surface, agent, duration and tokens. apx usage summarizes a day by model, channel and agent:

Terminal window
apx usage # today
apx usage --date 2026-09-23 --since 11
apx usage breaker # the spend breaker: last hour of background calls, any pause
apx usage resume # lift a pause now

Background work — routines, agents talking to each other, and task threads agents hand to each other — has an hourly ceiling on model calls, counted over the last hour, globally and per project. Past it, that work pauses (30 minutes by default) and you get one Telegram line saying so. Your own chats are never paused, and neither is an agent you are waiting on from one of them. The limits live in super_agent.spend_breaker:

{ "super_agent": { "spend_breaker": {
"enabled": true, "calls_per_hour": 400, "project_calls_per_hour": 250, "pause_min": 30
} } }

The apx model subcommands let you inspect and configure the fallback router without editing JSON by hand:

Terminal window
apx model status # print provider health, fallback order, and active model
apx model order ollama openrouter groq # set the attempt order
apx model key groq sk-xxxx # save a provider API key
apx model key openrouter sk-or-xxxx
apx model set openrouter openrouter/anthropic/claude-3.7-sonnet # pin a specific model for a provider
apx model test # resolve which model the router would pick right now
apx model enable # enable the fallback router
apx model disable # disable (primary model only)
apx
$ apx model status
Model router
primary:   anthropic:claude-sonnet-4-5
fallback:  on
order:     ollama → openrouter → groq
active:    anthropic:claude-sonnet-4-5

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

Keys → ~/.apx/config.json engines.{groq,openrouter}.api_key
Or env: GROQ_API_KEY, OPENROUTER_API_KEY
apx model status — shows provider health, fallback order, and currently active model

apx model key writes the key into engines.<provider>.api_key in ~/.apx/config.json. Two providers that are commonly used as fallbacks have shortcut names:

Terminal window
apx model key groq <key> # → engines.groq.api_key
apx model key openrouter <key> # → engines.openrouter.api_key

For Anthropic, OpenAI, and Gemini, set keys the same way:

Terminal window
apx model key anthropic <key>
apx model key openai <key>
apx model key gemini <key>

The config file uses the key engines for what this documentation calls engines (direct LLM adapters). An earlier design used the key model_providers internally. If you see references to model_providers in older skill files or notes, they refer to the same concept; the canonical key in ~/.apx/config.json is engines.

apx exec / apx chatapx run
Execution modelDirect LLM call inside APXExternal CLI subprocess
File edits / shellNoYes (the external CLI can write files and run commands)
Model choice--model flag or agent config, resolved by APXControlled by the external CLI’s own config
SpeedFast — one API callSlower — spawns a process, may take minutes
Use whenQuick Q&A, generation, reasoningFull coding-agent work (edits, terminal)