Files
codecraft/config.example.toml
T
Richard ZinkandClaude Opus 5.5 ec1b9b4925 Add file badges, menu icons, LSP diagnostics, robust compaction
- Files in chat: preview with type/size badges and file name; attachment chips
- Menu and settings tabs with icons
- Heatmap: distinct colour for empty hours, hourly labels
- Context chip shows used/total tokens (e.g. 221k/240k) plus percent
- LSP client: diagnostics appended to edit/write results and a diagnostics tool
  (typescript-language-server, pyright, rust-analyzer, gopls, clangd; sandboxed)
- Compaction summarizes a plain transcript and retries once on empty output
- files/stat endpoint

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 19:50:12 +01:00

344 lines
14 KiB
TOML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# =============================================================================
# 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"
# 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
# Max. subagents running at the same time (all sessions). Additionally, each
# subagent can be limited with max_parallel, and each provider/model with
# max_concurrency (see below).
max_parallel_subagents = 4
# MCP servers with more tools than this are loaded on demand (see [mcp.*] load).
mcp_direct_limit = 15
# 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.
#
# Concurrency: max_concurrency limits simultaneous requests – on the provider
# (= the host) and/or per model. Requests beyond the limit wait in a queue,
# e.g. for self-hosted models that can only process one request at a time.
#
# options: extra request body fields sent as-is, e.g.
# options = { temperature = 0.5, reasoning_budget_tokens = 5000 }
#
# 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 = ""
max_concurrency = 1 # one request at a time on this host
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>.
# users = [...]: who may use the server. Default: admins only.
# Use ["*"] for all users or list usernames, e.g. ["anna", "ben"].
# load = "auto" (default) | "always" | "on_demand": servers with many tools
# (more than server.mcp_direct_limit) are not sent with every request; the
# model finds them with mcp_search and calls them with mcp_call. This keeps
# requests small – important for self-hosted models.
# 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"
bash_output = "allow"
kill_shell = "allow"
web_fetch = "ask"
web_search = "allow"
diagnostics = "allow"
browser_snapshot = "allow"
image_compare = "allow"
generate_image = "ask" # costs money per image
"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.
# -----------------------------------------------------------------------------
# Subagents can run on a different model (and host) than the chat, and in the
# background: the main agent calls task(background = true), keeps working and
# receives the result as a message when the subagent is done.
# [agents.writer]
# mode = "subagent"
# description = "Writes documentation, summaries, guides and translations."
# model = "local/qwen3-4b" # optional, otherwise the session model
# tools = ["read", "glob", "grep"] # optional, default: all tools
# max_parallel = 1 # optional, instances at the same time
# prompt = '''
# You are a technical writer. Write clear, well-structured text.
# '''
# -----------------------------------------------------------------------------
# Image generation (fal.ai)
# -----------------------------------------------------------------------------
# Agents get the tool generate_image; the "Images" page creates images manually.
# Images are saved in the project (output_dir) and listed in a gallery.
# Model ids: https://fal.ai/models – price is per image (for the statistics).
# size_param: "image_size" (FLUX-style presets, default) or "aspect_ratio" ("16:9").
# -----------------------------------------------------------------------------
[images]
enabled = false
base_url = "https://fal.run"
api_key = "${FAL_KEY}"
default_model = "fal-ai/flux/schnell"
output_dir = "generated"
models = [
{ id = "fal-ai/flux/schnell", name = "FLUX.1 schnell – fast", price = 0.003 },
{ id = "fal-ai/flux-2-pro", name = "FLUX.2 pro" },
{ id = "fal-ai/ideogram/v3", name = "Ideogram 3 – text in images", size_param = "aspect_ratio" },
{ id = "fal-ai/recraft/v4/pro/text-to-image", name = "Recraft V4 pro – design" },
]
# -----------------------------------------------------------------------------
# Users & sign-in
# -----------------------------------------------------------------------------
# Users are managed in the web UI (Settings → Users). On first start without
# users, the server prints a one-time setup code to its log; use it in the UI
# to create the first admin – or set CODECRAFT_ADMIN_USER and
# CODECRAFT_ADMIN_PASSWORD in the environment.
#
# Every user works in their own directory <workspace>/<username>; admins can
# use the whole workspace. Note: file tools are confined to that directory,
# but shell commands run in the shared container and are not sandboxed.
# -----------------------------------------------------------------------------
[auth]
# Lifetime of a login in days.
session_days = 30
# External URL of this server – required for single sign-on (OIDC redirects).
public_url = ""
# Secure cookies: "auto" (when served via https), "true" or "false".
cookie_secure = "auto"
# Single sign-on via OpenID Connect (Authentik, Authelia, Keycloak, ...).
# Redirect URI to register at the IdP: <public_url>/api/auth/oidc/callback
[auth.oidc]
enabled = false
issuer = "https://auth.example.org/application/o/codecraft/"
client_id = "codecraft"
client_secret = "${OIDC_CLIENT_SECRET}"
scopes = ["openid", "profile", "email", "groups"]
username_claim = "preferred_username"
groups_claim = "groups"
# Members of this group are admins; empty = manage roles in CodeCraft.
admin_group = ""
# Only members of this group may sign in; empty = no restriction.
allowed_group = ""
# Create users automatically on their first sign-in.
auto_create = true
# Link a sign-in to an existing local user with the same username.
# Only enable this if you trust the usernames of your IdP.
link_by_username = false
button_label = "Single sign-on"
# -----------------------------------------------------------------------------
# Web search (web_search tool)
# -----------------------------------------------------------------------------
[search]
# "duckduckgo" (no key, may be rate-limited), "searxng" (self-hosted, set url),
# "brave" or "tavily" (api_key, e.g. "${BRAVE_API_KEY}")
provider = "duckduckgo"
url = ""
api_key = ""
# -----------------------------------------------------------------------------
# Language servers (diagnostics after edits, tool "diagnostics")
# -----------------------------------------------------------------------------
# Built in: rust (rust-analyzer), typescript (typescript-language-server),
# python (pyright-langserver), go (gopls), c (clangd) – used when installed.
# TypeScript and Python servers ship with the image. Servers run in the
# user's sandbox and stop after 15 minutes without use.
# -----------------------------------------------------------------------------
[lsp]
enabled = true
# Add or override a server:
# [lsp.servers.zig]
# command = "zls"
# extensions = ["zig"]
# root_markers = ["build.zig"]
# -----------------------------------------------------------------------------
# Sandbox
# -----------------------------------------------------------------------------
# Shell commands and git of a user run in a bubblewrap sandbox: system
# read-only, only the user's folders writable, own home, own processes, no
# server environment. The network is shared (package managers keep working).
# Needs the security options in docker-compose.yml. Without a working
# sandbox, non-admin users cannot run shell commands.
[sandbox]
# "auto" = non-admin users, "always" = everybody (admins too), "off" = nobody
mode = "auto"
# -----------------------------------------------------------------------------
# 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