Repository navigation
Configuration
Everything user-level lives in ~/.codingdude/ (override with CODEDUDE_HOME).
The main file is config.toml, created with defaults on first use. Edit it by
hand or through the Config panel — the panel writes the same file. Either
way, changes apply from the next run; no server restart.
Full reference: docs/manual/configuration.md.
Model names are always provider:model. The provider is either a built-in
(deepseek, zai, openai, anthropic, google, github, groq,
mistral, ollama, bedrock) or any name you define.
[models]
main = "deepseek:deepseek-v4-pro" # primary agent loop
subagent = "deepseek:deepseek-v4-flash" # delegated sub-agents
fallback = "zai:glm-5.3" # automatic failover when main errorsAny OpenAI-compatible provider is config-only — no code:
[providers.openrouter]
api_key = "sk-or-..."
base_url = "https://openrouter.ai/api/v1"
# env_var = "OPENROUTER_API_KEY" # default is <NAME>_API_KEY
[models]
main = "openrouter:anthropic/claude-sonnet-4"A provider with a base_url routes every name:model binding to that endpoint.
Without one, built-in names resolve through pydantic-ai's native support.
http:// base URLs are accepted for localhost only; remote endpoints must be
https://.
-
Environment wins over a stored
api_key. - Env var names:
ZAI_API_KEY,DEEPSEEK_API_KEY,GITHUB_PAT(built-ins); custom providers default to<NAME>_API_KEY, overridable withenv_var. - Keys stored in
config.tomlare reported back as presence only — never as text — by both the UI and the API. -
Verify keys sends one minimal request per provider. For GitHub it checks
api.github.com/user; for chat providers any of 200/400/404 counts as authenticated (a 400 only means the smoke model name is not on your plan).
Coding-plan keys are rejected by the standard Z.AI API; they work only against the coding-plan endpoint:
[models]
main = "zai:glm-5.3"
subagent = "zai:glm-5.3-flash"
fallback = "zai:glm-5.3-flash"
fallback_base_url = "https://api.z.ai/api/coding/paas/v4"
thinking = "low"Despite the name, fallback_base_url routes every zai: binding to that
endpoint. If fallback is a zai: model and the URL is unset, the Config panel
warns you.
| Key | Default | Purpose |
|---|---|---|
main / subagent / fallback
|
see above | model slots |
fallback_base_url |
(unset) | endpoint override for zai: bindings |
vision |
(unset) | vision-capable model for image input; unset disables images |
thinking |
(unset) | reasoning depth: minimal–xhigh, or off
|
max_tokens |
provider default | raise if responses get truncated |
context_limit |
inferred from the model name | context-window override; drives compaction and the meter |
compact_per_request |
true |
model-free compaction before every request while a run is live |
prompt_cache |
"1h" |
true, false, or a retention tier (5m/30m/1h/12h) |
prompt_cache_messages |
true |
also cache the growing conversation (main loop only) |
prompt_cache_settings |
{} |
provider-specific cache knobs; keys validated at load |
request_limit |
500 |
max model requests per run |
max_cost_usd |
(unset) | hard USD ceiling per agent.run() — see Spend and Context
|
max_total_tokens |
(unset) | hard token ceiling per agent.run()
|
pricing |
(unset) | cost rates, USD per 1M tokens |
[shell]
default = "bash" # or "powershell"
[delegation] # how much MORE one delegate call may spend
max_requests = 40
# max_cost_usd = 1.00
[planning]
github_mirror = true # mirror tickets/roadmap items to GitHub issues via gh
[trace]
deltas = "compact" # or "full"max_requests and max_cost_usd under [delegation] are a slice beyond
what the session already spent, bounded by the session's request_limit — a
ceiling enforced before the call, not a receipt afterwards.
[telemetry]
enabled = false # off by default
otlp_endpoint = "http://127.0.0.1:4318" # any local OTLP/HTTP collector
service_name = "codingdude"Local only (send_to_logfire=False) — no token, no account, nothing leaves the
machine, because prompts contain your code. Every malformed value is logged once
and turns tracing off rather than failing a run. See
Observability for the OpenLIT walkthrough.
Delegations can name one of six fixed functions, and each staffs from its own
profile. Only model and thinking are configurable — the tool policy is
registry-locked in code, which is the safety property.
[models.functions.evaluator]
model = "zai:glm-5.3-flash"
thinking = "low"| Function | Staffs | Recommended |
|---|---|---|
architect |
plan-level seam work | strongest model, max thinking — used rarely |
designer |
user-facing behaviour before code | strong model, high thinking |
coder |
the bulk of implementation | strong model, medium thinking |
debugger |
probe loops | fast model, medium thinking |
evaluator |
boundary-based grading | cheap model, low thinking |
researcher |
web / primary-source reads | cheap model, low thinking |
An unknown function name, a model without its provider: prefix, or any other
key fails fast at load.
# myproject/.codingdude.toml
shell = "powershell"
[models]
main = "openrouter:anthropic/claude-sonnet-4" # this project only
[kickoff]
existing = """
Our pipeline: plan first, implement, run `uv run pytest -q` plus ruff and mypy,
then request review. Never push without an explicit "push" from me.
"""The [models] overlay is a field-wise merge, validated; an invalid override logs
a warning and the global lineup is used unchanged. [kickoff] overrides the
bundled orientation prompt that runs on a session's first turn (existing
for a populated project, new for a greenfield one).
[models]
pricing = { deepseek-v4-pro = { input = 0.27, output = 1.1 } }USD per 1M tokens, matched by model name or substring (so glm-5 covers
glm-5.3 and glm-5.3-flash). Unpriced models are accounted tokens-only in the
Cost panel.
- The Config panel's save is a merge: only fields you changed are written; an
explicit clear is needed to empty one. A partial save can never wipe
fallback_base_url. - Stored keys round-trip as a sentinel, so saving the panel verbatim cannot overwrite a real key with a placeholder.
- A payload that fails validation is rejected before any write — a bad save cannot brick the next boot.
-
[telemetry]is global only; it is not honoured in a project file.
Start
How it works
Using it
Project