460 lines
15 KiB
TypeScript
460 lines
15 KiB
TypeScript
|
|
/** 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 (
|
||
|
|
<>
|
||
|
|
<h1 className="page-title">Configuration</h1>
|
||
|
|
<p className="page-subtitle">
|
||
|
|
Huskies is configured via three TOML files in your <code>.huskies/</code> directory. All files are
|
||
|
|
created by <code>huskies init</code> with sensible defaults.
|
||
|
|
</p>
|
||
|
|
|
||
|
|
<h2 id="project-toml">project.toml</h2>
|
||
|
|
<p>
|
||
|
|
Project-wide settings. Lives at <code>.huskies/project.toml</code>.
|
||
|
|
</p>
|
||
|
|
|
||
|
|
<table>
|
||
|
|
<thead>
|
||
|
|
<tr>
|
||
|
|
<th>Key</th>
|
||
|
|
<th>Type</th>
|
||
|
|
<th>Default</th>
|
||
|
|
<th>Description</th>
|
||
|
|
</tr>
|
||
|
|
</thead>
|
||
|
|
<tbody>
|
||
|
|
<tr>
|
||
|
|
<td>default_qa</td>
|
||
|
|
<td>string</td>
|
||
|
|
<td>
|
||
|
|
<code>"server"</code>
|
||
|
|
</td>
|
||
|
|
<td>
|
||
|
|
Default QA mode. One of <code>"server"</code> (automated gate run),{' '}
|
||
|
|
<code>"agent"</code> (spawn a QA agent), or <code>"human"</code> (manual
|
||
|
|
approval).
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
<tr>
|
||
|
|
<td>default_coder_model</td>
|
||
|
|
<td>string</td>
|
||
|
|
<td>
|
||
|
|
<code>"sonnet"</code>
|
||
|
|
</td>
|
||
|
|
<td>
|
||
|
|
Default model for coder agents. Only agents matching this model are auto-assigned. Use{' '}
|
||
|
|
<code>"opus"</code> on individual stories for complex tasks.
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
<tr>
|
||
|
|
<td>max_coders</td>
|
||
|
|
<td>integer</td>
|
||
|
|
<td>
|
||
|
|
<code>3</code>
|
||
|
|
</td>
|
||
|
|
<td>
|
||
|
|
Maximum concurrent coder agents. Stories wait in <code>2_current/</code> when all slots are
|
||
|
|
full.
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
<tr>
|
||
|
|
<td>max_retries</td>
|
||
|
|
<td>integer</td>
|
||
|
|
<td>
|
||
|
|
<code>3</code>
|
||
|
|
</td>
|
||
|
|
<td>
|
||
|
|
Maximum retries per story per pipeline stage before marking it as blocked. Set to{' '}
|
||
|
|
<code>0</code> to disable.
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
<tr>
|
||
|
|
<td>base_branch</td>
|
||
|
|
<td>string</td>
|
||
|
|
<td>auto-detected</td>
|
||
|
|
<td>
|
||
|
|
Base branch for merges and agent prompts. When unset, huskies reads the current HEAD branch.
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
<tr>
|
||
|
|
<td>rate_limit_notifications</td>
|
||
|
|
<td>bool</td>
|
||
|
|
<td>
|
||
|
|
<code>false</code>
|
||
|
|
</td>
|
||
|
|
<td>
|
||
|
|
Send chat notifications when API soft rate limits are hit. Hard blocks and story-blocked
|
||
|
|
notifications are always sent.
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
<tr>
|
||
|
|
<td>timezone</td>
|
||
|
|
<td>string</td>
|
||
|
|
<td>
|
||
|
|
<code>"UTC"</code>
|
||
|
|
</td>
|
||
|
|
<td>
|
||
|
|
IANA timezone for timer scheduling (e.g. <code>"Europe/London"</code>,{' '}
|
||
|
|
<code>"America/New_York"</code>). Timer HH:MM inputs are interpreted in this
|
||
|
|
timezone.
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
</tbody>
|
||
|
|
</table>
|
||
|
|
|
||
|
|
<h3>Component setup</h3>
|
||
|
|
<p>
|
||
|
|
The <code>[[component]]</code> 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.
|
||
|
|
</p>
|
||
|
|
<pre>
|
||
|
|
<code>{`[[component]]
|
||
|
|
name = "frontend"
|
||
|
|
path = "frontend"
|
||
|
|
setup = ["npm ci", "npm run build"]
|
||
|
|
teardown = []
|
||
|
|
|
||
|
|
[[component]]
|
||
|
|
name = "server"
|
||
|
|
path = "."
|
||
|
|
setup = ["mkdir -p frontend/dist", "cargo check"]
|
||
|
|
teardown = []`}</code>
|
||
|
|
</pre>
|
||
|
|
|
||
|
|
<h3>Story front matter overrides</h3>
|
||
|
|
<p>Individual stories can override project defaults using YAML front matter:</p>
|
||
|
|
<pre>
|
||
|
|
<code>{`---
|
||
|
|
name: "My Complex Story"
|
||
|
|
qa: agent # override default_qa
|
||
|
|
agent: opus # use the opus coder agent
|
||
|
|
---`}</code>
|
||
|
|
</pre>
|
||
|
|
|
||
|
|
<h2 id="agents-toml">agents.toml</h2>
|
||
|
|
<p>
|
||
|
|
Agent definitions. Lives at <code>.huskies/agents.toml</code>. Each <code>[[agent]]</code> block
|
||
|
|
defines one agent slot.
|
||
|
|
</p>
|
||
|
|
|
||
|
|
<table>
|
||
|
|
<thead>
|
||
|
|
<tr>
|
||
|
|
<th>Key</th>
|
||
|
|
<th>Description</th>
|
||
|
|
</tr>
|
||
|
|
</thead>
|
||
|
|
<tbody>
|
||
|
|
<tr>
|
||
|
|
<td>name</td>
|
||
|
|
<td>
|
||
|
|
Unique identifier for this agent slot (e.g. <code>"coder-1"</code>,{' '}
|
||
|
|
<code>"qa"</code>).
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
<tr>
|
||
|
|
<td>stage</td>
|
||
|
|
<td>
|
||
|
|
Pipeline stage this agent handles. One of <code>"coder"</code>,{' '}
|
||
|
|
<code>"qa"</code>, or <code>"mergemaster"</code>.
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
<tr>
|
||
|
|
<td>role</td>
|
||
|
|
<td>
|
||
|
|
Human-readable description of the agent's responsibilities (shown in status output).
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
<tr>
|
||
|
|
<td>model</td>
|
||
|
|
<td>
|
||
|
|
Claude model to use. One of <code>"sonnet"</code> (claude-sonnet-4-6) or{' '}
|
||
|
|
<code>"opus"</code> (claude-opus-4-6).
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
<tr>
|
||
|
|
<td>max_turns</td>
|
||
|
|
<td>Maximum conversation turns before the agent is forcefully stopped.</td>
|
||
|
|
</tr>
|
||
|
|
<tr>
|
||
|
|
<td>max_budget_usd</td>
|
||
|
|
<td>Maximum API spend in USD before the agent is stopped.</td>
|
||
|
|
</tr>
|
||
|
|
<tr>
|
||
|
|
<td>prompt</td>
|
||
|
|
<td>
|
||
|
|
The initial user-turn prompt sent to the agent. Supports template variables (see below).
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
<tr>
|
||
|
|
<td>system_prompt</td>
|
||
|
|
<td>The system prompt sent to the agent session.</td>
|
||
|
|
</tr>
|
||
|
|
</tbody>
|
||
|
|
</table>
|
||
|
|
|
||
|
|
<h3>Template variables</h3>
|
||
|
|
<p>
|
||
|
|
The following variables are interpolated into <code>prompt</code> and <code>system_prompt</code> at
|
||
|
|
agent start time:
|
||
|
|
</p>
|
||
|
|
<table>
|
||
|
|
<thead>
|
||
|
|
<tr>
|
||
|
|
<th>Variable</th>
|
||
|
|
<th>Description</th>
|
||
|
|
</tr>
|
||
|
|
</thead>
|
||
|
|
<tbody>
|
||
|
|
<tr>
|
||
|
|
<td>{'{{story_id}}'}</td>
|
||
|
|
<td>
|
||
|
|
The story's ID slug (e.g. <code>42_story_add_login</code>).
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
<tr>
|
||
|
|
<td>{'{{worktree_path}}'}</td>
|
||
|
|
<td>Absolute path to the agent's git worktree.</td>
|
||
|
|
</tr>
|
||
|
|
<tr>
|
||
|
|
<td>{'{{base_branch}}'}</td>
|
||
|
|
<td>
|
||
|
|
The base branch name from <code>project.toml</code>.
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
</tbody>
|
||
|
|
</table>
|
||
|
|
|
||
|
|
<h3>Example: adding an opus coder</h3>
|
||
|
|
<pre>
|
||
|
|
<code>{`[[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 ..."`}</code>
|
||
|
|
</pre>
|
||
|
|
<p>
|
||
|
|
To use this agent for a specific story, add <code>agent: opus</code> to the story's front
|
||
|
|
matter, or run <code>start <number> opus</code> in chat.
|
||
|
|
</p>
|
||
|
|
|
||
|
|
<h2 id="agent-md">
|
||
|
|
Project-local agent prompt (<code>.huskies/AGENT.md</code>)
|
||
|
|
</h2>
|
||
|
|
<p>
|
||
|
|
Place a file at <code>.huskies/AGENT.md</code> in your project root to append project-specific
|
||
|
|
guidance to every agent's initial prompt at spawn time.
|
||
|
|
</p>
|
||
|
|
|
||
|
|
<h3>How it works</h3>
|
||
|
|
<ul>
|
||
|
|
<li>
|
||
|
|
Huskies reads <code>.huskies/AGENT.md</code> each time an agent is spawned — no caching, no
|
||
|
|
restart required.
|
||
|
|
</li>
|
||
|
|
<li>
|
||
|
|
The file content is appended <em>after</em> the baked-in agent prompt, so project guidance
|
||
|
|
refines core instructions without overriding them.
|
||
|
|
</li>
|
||
|
|
<li>Applies to all agent roles: coder, QA, mergemaster, and supervisor.</li>
|
||
|
|
<li>
|
||
|
|
If the file is missing or empty, agents spawn normally — no warnings, no errors.
|
||
|
|
</li>
|
||
|
|
<li>
|
||
|
|
When the file exists and is non-empty, a single <code>INFO</code> log line is emitted showing the
|
||
|
|
file path and byte count.
|
||
|
|
</li>
|
||
|
|
</ul>
|
||
|
|
|
||
|
|
<h3>Ordering</h3>
|
||
|
|
<ol>
|
||
|
|
<li>
|
||
|
|
Baked-in agent prompt (from <code>agents.toml</code> or <code>project.toml</code>)
|
||
|
|
</li>
|
||
|
|
<li>
|
||
|
|
Project-local content from <code>.huskies/AGENT.md</code>
|
||
|
|
</li>
|
||
|
|
<li>Resume context (only on agent restart after a gate failure)</li>
|
||
|
|
</ol>
|
||
|
|
|
||
|
|
<h3>Example</h3>
|
||
|
|
<pre>
|
||
|
|
<code>{`# .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.`}</code>
|
||
|
|
</pre>
|
||
|
|
<p>
|
||
|
|
Edit the file at any time — the next agent spawn picks up the latest content automatically.
|
||
|
|
</p>
|
||
|
|
|
||
|
|
<h2 id="bot-toml">bot.toml</h2>
|
||
|
|
<p>
|
||
|
|
Chat transport configuration. Lives at <code>.huskies/bot.toml</code>. This file is gitignored as
|
||
|
|
it contains credentials. Copy the appropriate example file to get started:
|
||
|
|
</p>
|
||
|
|
<pre>
|
||
|
|
<code>cp .huskies/bot.toml.matrix.example .huskies/bot.toml</code>
|
||
|
|
</pre>
|
||
|
|
<p>
|
||
|
|
Only one transport can be active at a time. See the{' '}
|
||
|
|
<a href="/docs/transports">Chat transports</a> guide for setup instructions for each platform.
|
||
|
|
</p>
|
||
|
|
|
||
|
|
<h3>Common fields</h3>
|
||
|
|
<table>
|
||
|
|
<thead>
|
||
|
|
<tr>
|
||
|
|
<th>Key</th>
|
||
|
|
<th>Description</th>
|
||
|
|
</tr>
|
||
|
|
</thead>
|
||
|
|
<tbody>
|
||
|
|
<tr>
|
||
|
|
<td>enabled</td>
|
||
|
|
<td>
|
||
|
|
Set to <code>true</code> to activate the bot. Set to <code>false</code> to disable without
|
||
|
|
removing the file.
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
<tr>
|
||
|
|
<td>transport</td>
|
||
|
|
<td>
|
||
|
|
Transport type: <code>"matrix"</code>, <code>"whatsapp"</code>,{' '}
|
||
|
|
<code>"slack"</code>, or <code>"discord"</code>.
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
<tr>
|
||
|
|
<td>display_name</td>
|
||
|
|
<td>Optional. Bot display name in chat messages.</td>
|
||
|
|
</tr>
|
||
|
|
<tr>
|
||
|
|
<td>history_size</td>
|
||
|
|
<td>
|
||
|
|
Optional. Maximum conversation turns to remember per room/user (default: 20).
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
</tbody>
|
||
|
|
</table>
|
||
|
|
|
||
|
|
<h2 id="gateway-aggregated-stream">Gateway: aggregated chat stream</h2>
|
||
|
|
<p>
|
||
|
|
When running <code>huskies --gateway</code>, you can configure a single bot that receives pipeline
|
||
|
|
notifications from <strong>all</strong> registered projects. Events are prefixed with{' '}
|
||
|
|
<code>[project-name]</code> so you can tell them apart in one shared room.
|
||
|
|
</p>
|
||
|
|
<p>
|
||
|
|
The aggregated stream is configured entirely in the <strong>gateway's</strong>{' '}
|
||
|
|
<code>.huskies/bot.toml</code> — no per-project bot config is required and no per-project
|
||
|
|
files need to change when you add a new project to <code>projects.toml</code>.
|
||
|
|
</p>
|
||
|
|
|
||
|
|
<h3>Enabling the aggregated stream</h3>
|
||
|
|
<p>
|
||
|
|
Add or edit <code><gateway-config-dir>/.huskies/bot.toml</code> and set{' '}
|
||
|
|
<code>enabled = true</code>. The gateway bot will automatically poll every project listed in{' '}
|
||
|
|
<code>projects.toml</code> and forward events to the configured rooms.
|
||
|
|
</p>
|
||
|
|
<pre>
|
||
|
|
<code>{`# <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`}</code>
|
||
|
|
</pre>
|
||
|
|
|
||
|
|
<h3>Aggregated stream settings</h3>
|
||
|
|
<table>
|
||
|
|
<thead>
|
||
|
|
<tr>
|
||
|
|
<th>Key</th>
|
||
|
|
<th>Type</th>
|
||
|
|
<th>Default</th>
|
||
|
|
<th>Description</th>
|
||
|
|
</tr>
|
||
|
|
</thead>
|
||
|
|
<tbody>
|
||
|
|
<tr>
|
||
|
|
<td>aggregated_notifications_enabled</td>
|
||
|
|
<td>bool</td>
|
||
|
|
<td>
|
||
|
|
<code>true</code>
|
||
|
|
</td>
|
||
|
|
<td>
|
||
|
|
Set to <code>false</code> to disable the aggregated stream without disabling the gateway bot
|
||
|
|
entirely. Per-project configs are never consulted.
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
<tr>
|
||
|
|
<td>aggregated_notifications_poll_interval_secs</td>
|
||
|
|
<td>integer</td>
|
||
|
|
<td>
|
||
|
|
<code>5</code>
|
||
|
|
</td>
|
||
|
|
<td>
|
||
|
|
How often (in seconds) the gateway polls each project's <code>/api/events</code>{' '}
|
||
|
|
endpoint. Lower values reduce notification latency.
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
</tbody>
|
||
|
|
</table>
|
||
|
|
|
||
|
|
<h3>No-duplicate guarantee</h3>
|
||
|
|
<p>
|
||
|
|
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.
|
||
|
|
</p>
|
||
|
|
|
||
|
|
<h3>Unreachable projects</h3>
|
||
|
|
<p>
|
||
|
|
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.
|
||
|
|
</p>
|
||
|
|
|
||
|
|
<h3>Supported event types</h3>
|
||
|
|
<p>
|
||
|
|
The aggregated stream delivers the following event types, each prefixed with the project name:
|
||
|
|
</p>
|
||
|
|
<ul>
|
||
|
|
<li>
|
||
|
|
<strong>Stage transitions</strong> — story created, agent started, QA requested, QA
|
||
|
|
approved/rejected, merge succeeded (all pipeline stage moves)
|
||
|
|
</li>
|
||
|
|
<li>
|
||
|
|
<strong>Merge failures</strong> — merge failed with a reason
|
||
|
|
</li>
|
||
|
|
<li>
|
||
|
|
<strong>Story blocked</strong> — story blocked after exceeding retry limit
|
||
|
|
</li>
|
||
|
|
</ul>
|
||
|
|
</>
|
||
|
|
)
|
||
|
|
}
|