Download
Docs menu

Configuring tutti.toml

tutti.toml in the root of a repository tells Tutti how to give every agent a working copy of your app: what to install, which dev servers to run, which ports they need, and who's on the team. Commit it, and everyone on your team gets the same setup.

Create one

  • In the app: choose Set up on the project. Tutti detects your stack (Django, FastAPI, Flask, Next.js, Vite, Nest, Rails, Laravel, Go, Rust, Spring, monorepos, Docker Compose, databases) and proposes a file to review and save.
  • From a terminal: tutti init prints a suggestion for the current repository; tutti init --write saves it.
  • By describing it: in project settings, Change with Claude takes a sentence ("add a Redis service, run migrations on setup") and shows a checked diff to accept. Nothing is saved until you do.

Saving tutti.toml from Tutti approves its commands. A tutti.toml that arrives with the repository, or changes later, runs only after you review it; see Trust.

A full example

A Django API and a Vite storefront, each conversation with its own database:

[project]
base_branch = "main"
default_agent = "claude-code"
team = "full-stack"

[setup]
copy = [".env"]                 # copied from your checkout into each worktree
symlink = ["frontend/node_modules/.cache"]
script = """
createdb shop_$TUTTI_SESSION
cd backend && uv sync && uv run python manage.py migrate && uv run python manage.py loaddata demo
cd ../frontend && pnpm install
"""

[teardown]
script = "dropdb --if-exists shop_$TUTTI_SESSION"

[run]
api = { cmd = "uv run python manage.py runserver 127.0.0.1:$TUTTI_PORT", cwd = "backend", url = "http://localhost:$TUTTI_PORT" }
web = { cmd = "pnpm dev --port $TUTTI_PORT_1", cwd = "frontend", url = "http://localhost:$TUTTI_PORT_1" }

[ports]
extra = 1

[env]
DATABASE_URL = "postgres://localhost/shop_$TUTTI_SESSION"
VITE_API_URL = "http://localhost:$TUTTI_PORT"

[checks]
test = "cd backend && uv run pytest -q"
lint = "cd frontend && pnpm lint"

[[team.members]]
id = "sarah"
name = "Sarah"
role = "lead"

[[team.members]]
id = "tom"
name = "Tom"
role = "backend"
strengths = "APIs, data models and payments; careful with migrations"
agent = "claude-code"

[[team.members]]
id = "ada"
name = "Ada"
role = "frontend"
agent = "codex"

Editor support

Point your editor at the JSON Schema for completion and checks: https://tutti.build/schemas/tutti.schema.json. With the Even Better TOML extension, add this as the first line:

#:schema https://tutti.build/schemas/tutti.schema.json

Unknown keys are reported as warnings, not errors, so older and newer versions of Tutti can share a file.

Reference

Every key Tutti reads, from the current schema.

[project]

Basics for the project.

Key Type What it does
base_branch string Branch new sessions start from (defaults to the repo's current default branch).
branch_prefix string Prefix for session branches (default tutti/).
default_agent string Agent used when none is chosen.
name string Display name (defaults to the repository folder name).
team string The team Tutti suggests for this project, by template id (e.g. feature-squad, full-stack, campaign, outreach). Without it Tutti picks one from the contents.

[setup] and [teardown]

Runs once after a session's worktree is created. [teardown]: Runs when a session is archived (before its worktree is removed).

Key Type What it does
copy array of strings Files copied from the main checkout into the worktree (e.g. .env). Missing files are skipped.
script string Shell script (run with sh -c on Unix, PowerShell on Windows unless shell is set).
shell array of strings Override the shell, e.g. ["bash", "-lc"].
symlink array of strings Paths symlinked from the main checkout (shared caches). Falls back to copying where symlinks are unavailable.

[run.<name>]

Dev servers / long-running processes, started on demand per session.

Key Type What it does
cmd string Command line (shell), e.g. pnpm dev --port $TUTTI_PORT.
cwd string Working directory relative to the worktree root.
env table Extra environment for this service only. $TUTTI_* variables are expanded.
url string URL to open, e.g. http://localhost:$TUTTI_PORT.

[ports]

Ports per conversation. $TUTTI_PORT is always there.

Key Type What it does
extra number Extra ports per session beyond TUTTI_PORT (exposed as TUTTI_PORT_1..N, max 9).

[env]

Extra environment for setup, run, teardown and agents. $TUTTI_* variables are expanded. Keys are variable names, values are strings.

[checks]

Named checks (tests, lint) used by recipes, testers and arena scoring. Keys are names, values are shell commands, e.g. test = "uv run pytest -q".

[agents.<id>]

Per-agent overrides, keyed by adapter id (claude-code, codex, …) or a custom name.

Key Type What it does
args array of strings Extra command-line arguments.
cmd string For custom agents (generic terminal adapter): the command to run.
env table Extra environment for this agent only. $TUTTI_* variables are expanded.
idle_seconds number Generic adapter: seconds without output before the session counts as idle.
model string Model id passed to the agent (e.g. claude-opus-5-5).
prompt_regex string Generic adapter: regex matching the agent's input prompt, to detect "waiting for input".

[[team.members]]

The project's team, shared through the repository. Each teammate's notes and history stay on each person's machine.

Key Type What it does
agent string Agent (claude-code, codex, …); omitted = picked from the role.
id string Stable id: lowercase letters, digits and dashes (e.g. ada).
model string Model; omitted = the agent's default from settings.
name string Display name.
photo string Photo, relative to the repository root (e.g. .tutti/team/ada.png).
role string Role: lead, developer, backend, frontend, tester, reviewer, security, docs, investigator, upgrader, researcher, copywriter, editor, seo, sdr, analyst.
strengths string What they're good at and how they should work.

Agent ids

Built in: claude-code, codex, gemini, opencode, aider. Any other name with a cmd is a custom agent that runs in a terminal:

[agents.my-agent]
cmd = "my-agent --model local"
prompt_regex = "^> $"        # how Tutti sees it's waiting for input
idle_seconds = 20

Environment variables Tutti sets

TUTTI_PORT, TUTTI_PORT_1…, TUTTI_WORKTREE, TUTTI_ROOT, TUTTI_BRANCH, TUTTI_SESSION, TUTTI_SESSION_ID and TUTTI_PROJECT. See Worktrees and ports.

Review setup commands for acme-shop, listing the setup script, two dev servers and the environment variable names from tutti.toml.
What the example's commands look like when a teammate opens the repository.

Something missing or unclear? Ask us, and we'll answer and improve this page.