/** 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>&quot;server&quot;</code>
            </td>
            <td>
              Default QA mode. One of <code>&quot;server&quot;</code> (automated gate run),{' '}
              <code>&quot;agent&quot;</code> (spawn a QA agent), or <code>&quot;human&quot;</code> (manual
              approval).
            </td>
          </tr>
          <tr>
            <td>default_coder_model</td>
            <td>string</td>
            <td>
              <code>&quot;sonnet&quot;</code>
            </td>
            <td>
              Default model for coder agents. Only agents matching this model are auto-assigned. Use{' '}
              <code>&quot;opus&quot;</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>&quot;UTC&quot;</code>
            </td>
            <td>
              IANA timezone for timer scheduling (e.g. <code>&quot;Europe/London&quot;</code>,{' '}
              <code>&quot;America/New_York&quot;</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&apos;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>&quot;coder-1&quot;</code>,{' '}
              <code>&quot;qa&quot;</code>).
            </td>
          </tr>
          <tr>
            <td>stage</td>
            <td>
              Pipeline stage this agent handles. One of <code>&quot;coder&quot;</code>,{' '}
              <code>&quot;qa&quot;</code>, or <code>&quot;mergemaster&quot;</code>.
            </td>
          </tr>
          <tr>
            <td>role</td>
            <td>
              Human-readable description of the agent&apos;s responsibilities (shown in status output).
            </td>
          </tr>
          <tr>
            <td>model</td>
            <td>
              Claude model to use. One of <code>&quot;sonnet&quot;</code> (claude-sonnet-4-6) or{' '}
              <code>&quot;opus&quot;</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&apos;s ID slug (e.g. <code>42_story_add_login</code>).
            </td>
          </tr>
          <tr>
            <td>{'{{worktree_path}}'}</td>
            <td>Absolute path to the agent&apos;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&apos;s front
        matter, or run <code>start &lt;number&gt; 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&apos;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 &mdash; 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 &mdash; 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 &mdash; 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>&quot;matrix&quot;</code>, <code>&quot;whatsapp&quot;</code>,{' '}
              <code>&quot;slack&quot;</code>, or <code>&quot;discord&quot;</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&apos;s</strong>{' '}
        <code>.huskies/bot.toml</code> &mdash; 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>&lt;gateway-config-dir&gt;/.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&apos;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 &mdash; they are
        independent. Events from a per-project bot go to that project&apos;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 &mdash; 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> &mdash; story created, agent started, QA requested, QA
          approved/rejected, merge succeeded (all pipeline stage moves)
        </li>
        <li>
          <strong>Merge failures</strong> &mdash; merge failed with a reason
        </li>
        <li>
          <strong>Story blocked</strong> &mdash; story blocked after exceeding retry limit
        </li>
      </ul>
    </>
  )
}
