Rust backend (axum/tokio): agent loop with streaming, tools (fs, bash, web_fetch, todo, ask_user, subagents, skills, craft snapshots/compare), permissions with modes and rules, Anthropic + OpenAI-compatible providers, MCP client (stdio/HTTP, elicitation), SQLite sessions, usage statistics, compaction, commented TOML config editable via toml_edit. React PWA: chat with live streaming, permission/question cards, modes (build/plan/craft), settings for providers/models/prices/MCP/permissions, raw config editor, statistics dashboard, i18n (en/de). Docker setup. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
209 lines
8.4 KiB
TOML
209 lines
8.4 KiB
TOML
# =============================================================================
|
||
# 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 <data_dir>/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 "<provider>/<model>".
|
||
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 <base_url>/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 <api_key>" (openai) or
|
||
# "x-api-key: <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 <FAL_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__<server>__<tool>.
|
||
# 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__<server>__<tool>" or "mcp__<server>__*".
|
||
# 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
|