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.

KeyTypeDefaultDescription
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.

KeyDescription
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:

VariableDescription
{{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.md each 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 INFO log line is emitted showing the file path and byte count.

Ordering

  1. Baked-in agent prompt (from agents.toml or project.toml)
  2. Project-local content from .huskies/AGENT.md
  3. 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

KeyDescription
enabledSet to true to activate the bot. Set to false to disable without removing the file.
transportTransport type: "matrix", "whatsapp", "slack", or "discord".
display_nameOptional. Bot display name in chat messages.
history_sizeOptional. 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

KeyTypeDefaultDescription
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