# ============================================================================= # CodeCraft – configuration # ============================================================================= # # This file is the single source of truth for the server. Everything here can # also be edited in the web UI (Settings). The UI edits this file in place and # keeps your comments and formatting intact. # # Location: $CODECRAFT_CONFIG, otherwise /config.toml (Docker: /data/config.toml) # # Secrets: any string value may reference environment variables with ${NAME}, # e.g. api_key = "${ANTHROPIC_API_KEY}". Prefer this over literal keys – keys # entered in the UI are stored here in plain text. # ============================================================================= [server] # Address the HTTP server listens on. bind = "0.0.0.0:8787" # Root directory the agents may work in. Sessions pick a project folder below it. # Docker: mount your projects here (see docker-compose.yml). workspace = "/workspace" # Where sessions (SQLite) and runtime state are stored. data_dir = "/data" # Access token for the web UI and API. Leave empty to disable auth (only do # this on localhost!). Recommended: auth_token = "${CODECRAFT_TOKEN}" auth_token = "${CODECRAFT_TOKEN}" # Default model for new sessions, as "/". default_model = "anthropic/claude-sonnet-5-5" # Cheap/fast model for titles and history compaction. Falls back to default_model. small_model = "anthropic/claude-haiku-5-5" # Compact the conversation automatically when the context is this full (0.0–1.0). auto_compact_threshold = 0.85 # Currency label for the cost statistics (prices below are in this currency). currency = "USD" # ----------------------------------------------------------------------------- # Providers # ----------------------------------------------------------------------------- # kind = "anthropic" → Anthropic Messages API (and compatible endpoints) # kind = "openai" → OpenAI-compatible /chat/completions (Gemini, opencode Go, # fal, OpenRouter, Ollama, vLLM, llama.cpp, LM Studio, ...) # # models: optional list. If empty, the model list is fetched from /models. # Per-model options: context (tokens), max_output (tokens), reasoning (bool), # vision (bool, can read images), effort ("low" | "medium" | "high" | "xhigh" | "max"). # # Prices (per 1M tokens, used for the statistics): # input_price, output_price, cache_read_price, cache_write_price # Cache prices default to input_price when omitted. Costs are stored per request, # so changing a price only affects future requests. # # Authentication: by default "Authorization: Bearer " (openai) or # "x-api-key: " (anthropic). Override with auth_header / auth_prefix. # Extra static headers: headers = { "X-Foo" = "bar" } # ----------------------------------------------------------------------------- [providers.anthropic] kind = "anthropic" base_url = "https://api.anthropic.com/v1" api_key = "${ANTHROPIC_API_KEY}" # Current Claude models think adaptively; "effort" controls depth and cost. # Prices: Anthropic list prices in USD per 1M tokens (Nov 2026) – adjust if needed. models = [ { id = "claude-opus-5-5", context = 1000000, max_output = 64000, reasoning = true, vision = true, effort = "high", input_price = 4.0, output_price = 20.0, cache_read_price = 0.20, cache_write_price = 5.0 }, { id = "claude-sonnet-5-5", context = 1000000, max_output = 64000, reasoning = true, vision = true, effort = "medium", input_price = 2.0, output_price = 10.0, cache_read_price = 0.20, cache_write_price = 2.5 }, { id = "claude-haiku-5-5", context = 1000000, max_output = 32000, reasoning = true, vision = true, effort = "low", input_price = 0.10, output_price = 0.50, cache_read_price = 0.01, cache_write_price = 0.125 }, ] # Google Gemini through its OpenAI-compatible endpoint. [providers.gemini] kind = "openai" base_url = "https://generativelanguage.googleapis.com/v1beta/openai" api_key = "${GEMINI_API_KEY}" models = [] # discovered automatically enabled = false # set to true once GEMINI_API_KEY is available # opencode Go subscription (OpenAI-compatible endpoint for most models). # Current model list: https://opencode.ai/inference/go/v1/models [providers.opencode-go] kind = "openai" base_url = "https://opencode.ai/inference/go/openai/v1" api_key = "${OPENCODE_API_KEY}" models = [] enabled = false # fal.ai – OpenRouter-backed LLM router. fal expects "Authorization: Key ". # NOTE: verify base_url against the fal docs for your account. [providers.fal] kind = "openai" base_url = "https://fal.run/openrouter/router/openai/v1" api_key = "${FAL_KEY}" auth_prefix = "Key " models = [ { id = "google/gemini-2.5-flash", context = 1000000, max_output = 32000, vision = true }, ] enabled = false # Self-hosted (Ollama shown; vLLM/llama.cpp/LM Studio work the same way). # From inside Docker, the host is reachable as host.docker.internal. [providers.local] kind = "openai" base_url = "http://host.docker.internal:11434/v1" api_key = "" models = [] enabled = false # ----------------------------------------------------------------------------- # MCP servers # ----------------------------------------------------------------------------- # type = "stdio" → command + args (+ env), started as a child process # type = "http" → Streamable HTTP endpoint (url + optional headers) # Tools appear to the model as mcp____. # MCP servers may ask you questions (elicitation); they show up in the UI. # ----------------------------------------------------------------------------- # [mcp.trilium] # type = "http" # url = "https://notes.example.org/mcp" # headers = { Authorization = "Bearer ${TRILIUM_TOKEN}" } # [mcp.filesystem] # type = "stdio" # command = "npx" # args = ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"] # env = {} # enabled = false # ----------------------------------------------------------------------------- # Permissions # ----------------------------------------------------------------------------- # For each tool: "allow" | "ask" | "deny". "ask" forwards the request to the UI. # MCP tools can be addressed as "mcp____" or "mcp____*". # Session permission modes in the UI override this: # default → these rules # accept_edits → file edits allowed without asking # bypass → everything allowed (use with care) # ----------------------------------------------------------------------------- [permissions] read = "allow" glob = "allow" grep = "allow" list = "allow" todo_write = "allow" ask_user = "allow" task = "allow" write = "ask" edit = "ask" bash = "ask" web_fetch = "ask" browser_snapshot = "allow" image_compare = "allow" "mcp__*" = "ask" # Shell command patterns (glob, matched against the full command). First match wins. [permissions.bash_rules] "git status*" = "allow" "git diff*" = "allow" "git log*" = "allow" "ls*" = "allow" "pwd" = "allow" "rm -rf /*" = "deny" # ----------------------------------------------------------------------------- # Agents (modes) # ----------------------------------------------------------------------------- # Built-in: build (full access), plan (read-only, proposes a plan), # craft (study → build → check → ready), and subagents # general + explore used by the "task" tool. # Define your own or override built-ins here. mode = "primary" shows up in the # mode switcher, mode = "subagent" is only available through the task tool. # ----------------------------------------------------------------------------- # [agents.reviewer] # mode = "subagent" # description = "Reviews code changes for bugs and style issues." # model = "anthropic/claude-opus-5-5" # optional, otherwise session model # tools = ["read", "glob", "grep", "bash"] # optional, default: all tools # prompt = """ # You are a meticulous code reviewer. ... # """ # ----------------------------------------------------------------------------- # Craft mode # ----------------------------------------------------------------------------- [craft] # Headless Chromium binary used to study websites and check builds. chromium = "chromium" # Screen widths used for screenshots and comparisons. widths = [390, 768, 1440] # Clean room: only what a visitor sees (screenshots, visible text, layout). # Set to false for "deep" mode (page source and scripts may be read). clean_room = true