/** Configuration reference — project.toml, agents.toml, and bot.toml docs. */ import type { Metadata } from 'next' /** Page metadata for the configuration reference. */ export const metadata: Metadata = { title: 'Configuration — Huskies Docs', description: 'Reference for project.toml, agents.toml, and bot.toml configuration files.', } /** Renders the configuration reference for all huskies TOML files. */ export default function ConfigurationPage() { return ( <>
Huskies is configured via three TOML files in your .huskies/ directory. All files are
created by huskies init with sensible defaults.
Project-wide settings. Lives at .huskies/project.toml.
| Key | Type | Default | Description |
|---|---|---|---|
| default_qa | string |
"server"
|
Default QA mode. One of "server" (automated gate run),{' '}
"agent" (spawn a QA agent), or "human" (manual
approval).
|
| default_coder_model | string |
"sonnet"
|
Default model for coder agents. Only agents matching this model are auto-assigned. Use{' '}
"opus" on individual stories for complex tasks.
|
| max_coders | integer |
3
|
Maximum concurrent coder agents. Stories wait in 2_current/ when all slots are
full.
|
| max_retries | integer |
3
|
Maximum retries per story per pipeline stage before marking it as blocked. Set to{' '}
0 to disable.
|
| base_branch | string | auto-detected | Base branch for merges and agent prompts. When unset, huskies reads the current HEAD branch. |
| rate_limit_notifications | bool |
false
|
Send chat notifications when API soft rate limits are hit. Hard blocks and story-blocked notifications are always sent. |
| timezone | string |
"UTC"
|
IANA timezone for timer scheduling (e.g. "Europe/London",{' '}
"America/New_York"). Timer HH:MM inputs are interpreted in this
timezone.
|
The [[component]] sections define how to build and verify each part of your project.
The server runs setup commands before accepting a story's QA and teardown commands after
merging.
{`[[component]]
name = "frontend"
path = "frontend"
setup = ["npm ci", "npm run build"]
teardown = []
[[component]]
name = "server"
path = "."
setup = ["mkdir -p frontend/dist", "cargo check"]
teardown = []`}
Individual stories can override project defaults using YAML front matter:
{`---
name: "My Complex Story"
qa: agent # override default_qa
agent: opus # use the opus coder agent
---`}
Agent definitions. Lives at .huskies/agents.toml. Each [[agent]] block
defines one agent slot.
| Key | Description |
|---|---|
| name |
Unique identifier for this agent slot (e.g. "coder-1",{' '}
"qa").
|
| stage |
Pipeline stage this agent handles. One of "coder",{' '}
"qa", or "mergemaster".
|
| role | Human-readable description of the agent's responsibilities (shown in status output). |
| model |
Claude model to use. One of "sonnet" (claude-sonnet-4-6) or{' '}
"opus" (claude-opus-4-6).
|
| max_turns | Maximum conversation turns before the agent is forcefully stopped. |
| max_budget_usd | Maximum API spend in USD before the agent is stopped. |
| prompt | The initial user-turn prompt sent to the agent. Supports template variables (see below). |
| system_prompt | The system prompt sent to the agent session. |
The following variables are interpolated into prompt and system_prompt at
agent start time:
| Variable | Description |
|---|---|
| {'{{story_id}}'} |
The story's ID slug (e.g. 42_story_add_login).
|
| {'{{worktree_path}}'} | Absolute path to the agent's git worktree. |
| {'{{base_branch}}'} |
The base branch name from project.toml.
|
{`[[agent]]
name = "coder-opus"
stage = "coder"
role = "Senior engineer for complex tasks."
model = "opus"
max_turns = 80
max_budget_usd = 20.00
prompt = "You are working on story {{story_id}} ..."
system_prompt = "You are a senior full-stack engineer ..."`}
To use this agent for a specific story, add agent: opus to the story's front
matter, or run start <number> opus in chat.
.huskies/AGENT.md)
Place a file at .huskies/AGENT.md in your project root to append project-specific
guidance to every agent's initial prompt at spawn time.
.huskies/AGENT.md each time an agent is spawned — no caching, no
restart required.
INFO log line is emitted showing the
file path and byte count.
agents.toml or project.toml)
.huskies/AGENT.md
{`# .huskies/AGENT.md
## Documentation
Docs live in \`website/docs/*.html\`, not Markdown files.
Edit the relevant .html file when a story asks for documentation.
## Quality gates
Run \`cargo clippy -- -D warnings\` before committing. Zero warnings allowed.`}
Edit the file at any time — the next agent spawn picks up the latest content automatically.
Chat transport configuration. Lives at .huskies/bot.toml. This file is gitignored as
it contains credentials. Copy the appropriate example file to get started:
cp .huskies/bot.toml.matrix.example .huskies/bot.toml
Only one transport can be active at a time. See the{' '} Chat transports guide for setup instructions for each platform.
| Key | Description |
|---|---|
| enabled |
Set to true to activate the bot. Set to false to disable without
removing the file.
|
| transport |
Transport type: "matrix", "whatsapp",{' '}
"slack", or "discord".
|
| display_name | Optional. Bot display name in chat messages. |
| history_size | Optional. Maximum conversation turns to remember per room/user (default: 20). |
When running huskies --gateway, you can configure a single bot that receives pipeline
notifications from all registered projects. Events are prefixed with{' '}
[project-name] so you can tell them apart in one shared room.
The aggregated stream is configured entirely in the gateway's{' '}
.huskies/bot.toml — no per-project bot config is required and no per-project
files need to change when you add a new project to projects.toml.
Add or edit <gateway-config-dir>/.huskies/bot.toml and set{' '}
enabled = true. The gateway bot will automatically poll every project listed in{' '}
projects.toml and forward events to the configured rooms.
{`# /.huskies/bot.toml
enabled = true
transport = "matrix"
homeserver = "https://matrix.example.com"
username = "@gateway-bot:example.com"
password = "secret"
room_ids = ["!gateway-room:example.com"]
allowed_users = ["@you:example.com"]
# Gateway-specific: poll interval and on/off switch
aggregated_notifications_poll_interval_secs = 5 # default
aggregated_notifications_enabled = true # default`}
| Key | Type | Default | Description |
|---|---|---|---|
| aggregated_notifications_enabled | bool |
true
|
Set to false to disable the aggregated stream without disabling the gateway bot
entirely. Per-project configs are never consulted.
|
| aggregated_notifications_poll_interval_secs | integer |
5
|
How often (in seconds) the gateway polls each project's /api/events{' '}
endpoint. Lower values reduce notification latency.
|
Per-project bots and the gateway aggregated stream send to different rooms — they are independent. Events from a per-project bot go to that project's rooms; events from the gateway stream go to the gateway rooms. The same event will never appear twice in either room.
If a per-project server is temporarily unreachable, the gateway logs a warning and skips that project for the current poll cycle. All other projects continue to deliver notifications normally. No configuration change is required — the poller retries on the next interval.
The aggregated stream delivers the following event types, each prefixed with the project name: