Configuration
Everything works out of the box with defaults. If you want to customize, create a dynamo.yaml in your project root.
dynamo.yaml
project:
name: "MyGame"
github_repo: "myorg/mygame"
base_ref: "main"
ai:
provider: "anthropic"
personality: "full" # full | light | minimal
sandbox: "full" # project | full | unrestricted
memory: true # false to disable memory
auto_checkpoint: true # false to disable auto-checkpoints
auto_consolidate: false # true to auto-consolidate memory on session start
slim_mode: false # compact mode for local providers (Ollama etc.)
show_costs: false # show per-turn cost in the status bar
models:
interactive: "anthropic/<model-id>" # model for interactive chat
budget:
session_limit: 5.0 # warn (non-blocking) at 80% / 100% of this spend
shell:
defaultTimeout: 120000 # 2 min (ms)
maxTimeout: 600000 # 10 min max
maxOutput: 50000 # 50K chars before truncation
providers:
deepseek:
type: "openai-compatible"
base_url: "https://api.deepseek.com/v1"
api_key_env: "DEEPSEEK_API_KEY"
engines:
unity:
project_path: "./MyUnityProject"Once a dynamo.yaml exists, project.name is the one required key — everything else has sensible defaults.
Run dynamo config to see your full resolved configuration.
Config namespaces
These top-level namespaces are available (see dynamo config for the full resolved tree):
| Namespace | What it covers |
|---|---|
ai.models.interactive | Model used for interactive chat |
ai.context.* | Context engine — enabled, auto_index, cache |
ai.instructions.* | DYNAMO.md project-instructions loader |
ai.budget | Non-blocking session cost limit (session_limit) |
ai.show_costs | Per-turn cost in the status bar |
ai.slim_mode | Compact mode for local/proxied providers |
ai.openrouter.* | OpenRouter routing — route, data_collection, provider_order, models_fallback |
ai.openai.* | OpenAI-specific settings — tool_search, plus the extras for newer models below |
ai.anthropic.* | Anthropic-specific settings — tool_search |
ai.default_effort | Starting reasoning effort (low … max; default medium) |
ai.auto_mode | Start in Auto Mode (skip tool approval prompts) |
permissions.* | protected_branches, allow_force_push_protected |
hooks | Event-driven shell hooks |
mcp.servers.* | Reserved for third-party MCP servers — declared servers are trust-gated and don't register in shipped builds. The engine bridge doesn't use this key; the engine package registers itself. |
engines.unity.* | Unity engine package settings |
Getting more out of newer OpenAI models
Newer OpenAI models accept a few things older ones don't. All three are off by default — turn one on only if you want it. original image detail and the prompt cache are each checked against your model first: on a model that can't take them, Dynamo sends high instead and leaves the cache as it was. The prompt cache and persisted reasoning only work through OpenAI's newer API (the one current models use), and persisted reasoning only on a model that reasons at all.
These settings reach models on the built-in OpenAI provider (openai/…) only. A custom OpenAI-compatible provider — DeepSeek, Groq and the like — ignores them, even written under its own ai.<name> block.
ai:
openai:
image_detail: "original" # send images untouched instead of resized
explicit_prompt_cache: true # mark the reusable part of the prompt yourself
persisted_reasoning: true # let the model keep its own train of thought| Setting | What it does |
|---|---|
image_detail | How much of a picture the model gets to see — both pictures you attach and ones Dynamo opens itself. Leave it unset and nothing changes: a picture Dynamo opens goes at high, one you attach at auto (OpenAI decides). original sends the picture untouched — worth it for a dense sprite sheet or a screenshot full of small text, and it costs more tokens; on a model that can't take it, Dynamo sends high. low and auto are also accepted. |
explicit_prompt_cache | By default OpenAI decides on its own how much of your prompt to reuse from cache. This hands the decision to Dynamo, which marks up to three points instead: the part that never changes, a point partway back through the conversation, and the end of the last exchange. A short session needs fewer — one on the first message, two until there is enough history for the middle one to be worth a slot. Whether that beats OpenAI's own choice depends on the session, so treat it as an experiment: try it on a long session with a lot of tool work and compare the cached-token figure after each response (Token Display) before you keep it on. |
persisted_reasoning | Carries the model's own reasoning from one message to the next, so it picks up where it left off instead of re-deriving. Resets whenever the conversation does — a new model, /clear, /resume, a rollback, or a compaction. |
Turning these on doesn't change Dynamo's privacy posture: every OpenAI request still asks OpenAI not to keep it for retrieval (store: false).
Personality Levels
| Level | Description |
|---|---|
full | Warm game-dev teammate — conversational, shares thinking (default for interactive) |
light | Helpful and clear, less personality |
minimal | Terse and direct |
Override with DYNAMO_PERSONALITY env var.
Environment Variables
API Keys
| Variable | Provider |
|---|---|
ANTHROPIC_API_KEY | Anthropic (Claude) |
OPENAI_API_KEY | OpenAI (GPT) |
OPENROUTER_API_KEY | OpenRouter (200+ models) |
GOOGLE_API_KEY | Google (Gemini) |
XAI_API_KEY | xAI (Grok) |
For Ollama, no API key is needed — Dynamo auto-detects a running Ollama instance.
For custom providers (DeepSeek, Groq, etc.), set the key name in api_key_env in your provider config.
Overrides
| Variable | Purpose |
|---|---|
DYNAMO_AI_PROVIDER | Override default provider |
DYNAMO_PERSONALITY | Override personality level |
DYNAMO_CONFIG_DIR | Override config directory location (default ~/.config/dynamo/; %APPDATA%\dynamo on Windows) |
DYNAMO_SHELL_TIMEOUT | Override default shell timeout (ms) |
DYNAMO_NERD_FONTS | Force Nerd Fonts on (1) or off (0) |
NO_COLOR | Disable all terminal colors |
COLORTERM | Set to truecolor for 24-bit color in tmux or over SSH |
FORCE_COLOR | Force a color level (2 for 256-color, 3 for truecolor) |
ANTHROPIC_WORKSPACE_ID | Workspace id for an Anthropic key created without a workspace |
Auth Priority
Dynamo resolves an API key in this order:
- Environment variable for the provider —
ANTHROPIC_API_KEY,OPENAI_API_KEY,OPENROUTER_API_KEY,GOOGLE_API_KEY,XAI_API_KEY. - Stored credentials —
credentials.jsonin your config dir, written bydynamo setup(mode0600).
That's the whole chain: keys are never read from preferences.json or dynamo.yaml. OpenClaw doesn't sit in this order at all — if you have an OpenClaw install, its .env is loaded at startup and fills in variables that aren't already set, so it feeds step 1 rather than overriding it. Ollama needs no key.
If no key is found, the provider is simply unavailable — dynamo setup is how you add one.
OpenClaw Integration
If you use OpenClaw, Dynamo detects it automatically:
- API key import — your OpenClaw API keys are imported automatically (explicit environment variables always take priority)
- Model aliases — an alias you've set in OpenClaw (e.g.
/model my-fast) resolves here too, if OpenClaw knows the model - Context window sizes — imported so Dynamo knows each model's limits
- Config watching — Dynamo watches for changes to your OpenClaw config and picks them up live
- Manual sync — run
/syncto re-sync OpenClaw settings on demand
No OpenClaw? No problem. Dynamo works fine standalone.
File Locations
Paths under ~/.config/dynamo/ are %APPDATA%\dynamo\ on Windows.
| File | Location |
|---|---|
| Sessions | ~/.config/dynamo/sessions/ |
| Preferences | ~/.config/dynamo/preferences.json |
| Credentials | ~/.config/dynamo/credentials.json |
| Checkpoints | ~/.config/dynamo/checkpoints/ |
| Global memory | ~/.config/dynamo/memory/ |
| Project memory | .dynamo/memory/ |
| Project config | ./dynamo.yaml |
| Project skills | .dynamo/skills/ |
| Personal skills | ~/.config/dynamo/skills/ |
| Input history | ~/.config/dynamo/input-history.jsonl |