Configuration
Huskies is configured via three TOML files in your .huskies/ directory. All files are created by huskies init with sensible defaults.
project.toml
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. |
Component setup
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 = []
Story front matter overrides
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
---
agents.toml
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. |
Template variables
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. |
Example: adding an opus coder
[[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.
Project-local agent prompt (.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.
How it works
- Huskies reads
.huskies/AGENT.mdeach time an agent is spawned — no caching, no restart required. - The file content is appended after the baked-in agent prompt, so project guidance refines core instructions without overriding them.
- Applies to all agent roles: coder, QA, mergemaster, and supervisor.
- If the file is missing or empty, agents spawn normally — no warnings, no errors.
- When the file exists and is non-empty, a single
INFOlog line is emitted showing the file path and byte count.
Ordering
- Baked-in agent prompt (from
agents.tomlorproject.toml) - Project-local content from
.huskies/AGENT.md - Resume context (only on agent restart after a gate failure)
Example
# .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.
bot.toml
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.
Common fields
| 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). |
Gateway: aggregated chat stream
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.
Enabling the aggregated stream
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.
# <gateway-config-dir>/.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
Aggregated stream settings
| 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. |
No-duplicate guarantee
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.
Unreachable projects
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.
Supported event types
The aggregated stream delivers the following event types, each prefixed with the project name:
- Stage transitions — story created, agent started, QA requested, QA approved/rejected, merge succeeded (all pipeline stage moves)
- Merge failures — merge failed with a reason
- Story blocked — story blocked after exceeding retry limit