Files
huskies/website/docs/cli.html
T
2026-04-28 00:22:29 +00:00

226 lines
10 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>CLI Reference — Huskies Docs</title>
<meta name="description" content="Command-line reference for huskies, huskies init, and related subcommands.">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:wght@400;500;600;700;800&family=Karla:ital,wght@0,300;0,400;0,500;1,300;1,400&display=swap" rel="stylesheet">
<link rel="stylesheet" href="docs.css">
</head>
<body>
<div class="shell">
<header class="reveal r1">
<a href="/" class="logo">huskies</a>
<nav>
<a href="/#how">How it works</a>
<a href="/#features">Features</a>
<a href="/docs/" class="active">Docs</a>
<a href="https://code.crashlabs.io/crashlabs/huskies">Source</a>
<a href="https://code.crashlabs.io/crashlabs/huskies/releases">Releases</a>
<a href="mailto:hello@huskies.dev" class="nav-cta">Get in touch</a>
</nav>
</header>
</div>
<div class="shell">
<div class="docs-layout">
<aside class="sidebar reveal r2">
<div class="sidebar-section">
<div class="sidebar-heading">Getting started</div>
<nav>
<a href="/docs/">Overview</a>
<a href="quickstart.html">Quickstart</a>
</nav>
</div>
<div class="sidebar-section">
<div class="sidebar-heading">Reference</div>
<nav>
<a href="configuration.html">Configuration</a>
<a href="commands.html">Bot commands</a>
<a href="cli.html" class="active">CLI</a>
</nav>
</div>
<div class="sidebar-section">
<div class="sidebar-heading">Guides</div>
<nav>
<a href="pipeline.html">Pipeline stages</a>
<a href="transports.html">Chat transports</a>
</nav>
</div>
</aside>
<main class="docs-main reveal r3">
<h1 class="page-title">CLI Reference</h1>
<p class="page-subtitle">Huskies ships as a single binary. Most interaction happens through the web UI or chat transports, but the CLI is used for initial setup and server control.</p>
<h2>huskies</h2>
<p>Start the huskies server.</p>
<pre><code>huskies [OPTIONS]</code></pre>
<h3>Options</h3>
<table>
<thead><tr><th>Flag</th><th>Default</th><th>Description</th></tr></thead>
<tbody>
<tr><td>--port &lt;PORT&gt;</td><td>3000</td><td>HTTP port to listen on. Set the <code>HUSKIES_PORT</code> environment variable as an alternative.</td></tr>
<tr><td>--project &lt;PATH&gt;</td><td>current dir</td><td>Path to the project directory. Huskies looks for <code>.huskies/</code> here.</td></tr>
<tr><td>--help</td><td></td><td>Print help and exit.</td></tr>
<tr><td>--version</td><td></td><td>Print version and exit.</td></tr>
</tbody>
</table>
<h3>Examples</h3>
<pre><code># Start on the default port
huskies
# Start on a custom port
huskies --port 3001
# Specify project directory explicitly
huskies --project /path/to/project --port 3000
# Using environment variable
HUSKIES_PORT=3002 huskies</code></pre>
<div class="note">
<strong>Multiple instances:</strong> Each worktree or project can run its own huskies instance on a different port. Use <code>HUSKIES_PORT</code> to avoid conflicts when running several instances simultaneously.
</div>
<h2>huskies init</h2>
<p>Initialise a project directory for use with huskies. Creates the <code>.huskies/</code> directory structure, default configuration files, and <code>.mcp.json</code>.</p>
<pre><code>huskies init [OPTIONS]</code></pre>
<h3>Options</h3>
<table>
<thead><tr><th>Flag</th><th>Default</th><th>Description</th></tr></thead>
<tbody>
<tr><td>--port &lt;PORT&gt;</td><td>3000</td><td>Port written into <code>.mcp.json</code> for MCP tool discovery.</td></tr>
<tr><td>--project &lt;PATH&gt;</td><td>current dir</td><td>Directory to initialise. Must be a git repository.</td></tr>
<tr><td>--help</td><td></td><td>Print help and exit.</td></tr>
</tbody>
</table>
<h3>What it creates</h3>
<table>
<thead><tr><th>Path</th><th>Description</th></tr></thead>
<tbody>
<tr><td><code>.huskies/project.toml</code></td><td>Project-wide settings (QA mode, agent limits, timezone, etc.).</td></tr>
<tr><td><code>.huskies/agents.toml</code></td><td>Agent definitions for coder, QA, and mergemaster roles.</td></tr>
<tr><td><code>.huskies/work/1_backlog/</code></td><td>Pipeline stage directories (1 through 6).</td></tr>
<tr><td><code>.huskies/specs/00_CONTEXT.md</code></td><td>Placeholder project context file for the setup wizard.</td></tr>
<tr><td><code>.huskies/specs/tech/STACK.md</code></td><td>Placeholder tech stack file for the setup wizard.</td></tr>
<tr><td><code>.mcp.json</code></td><td>MCP server config so Claude Code discovers huskies' tools automatically.</td></tr>
</tbody>
</table>
<div class="note">
<strong>Git required:</strong> The project directory must be a git repository. Run <code>git init</code> first if needed.
</div>
<h2>huskies agent</h2>
<p>Spawn a single agent process directly from the command line. This is the command the server uses internally when you run <code>start &lt;number&gt;</code> in chat — you rarely need to invoke it manually.</p>
<pre><code>huskies agent [OPTIONS]</code></pre>
<h3>Options</h3>
<table>
<thead><tr><th>Flag</th><th>Description</th></tr></thead>
<tbody>
<tr><td>--story &lt;ID&gt;</td><td>Story ID slug to work on (e.g. <code>42_story_add_login</code>).</td></tr>
<tr><td>--agent &lt;NAME&gt;</td><td>Agent name from <code>agents.toml</code> to use (e.g. <code>coder-1</code>, <code>qa</code>).</td></tr>
<tr><td>--worktree &lt;PATH&gt;</td><td>Path to the git worktree the agent should work in.</td></tr>
<tr><td>--port &lt;PORT&gt;</td><td>Huskies server port, so the agent can call MCP tools.</td></tr>
<tr><td>--help</td><td>Print help and exit.</td></tr>
</tbody>
</table>
<h2>Environment variables</h2>
<table>
<thead><tr><th>Variable</th><th>Description</th></tr></thead>
<tbody>
<tr><td><code>HUSKIES_PORT</code></td><td>Server port. Overrides the <code>--port</code> flag.</td></tr>
<tr><td><code>ANTHROPIC_API_KEY</code></td><td>Anthropic API key for agent sessions. Can also be set via the web UI on first use.</td></tr>
<tr><td><code>GITEA_TOKEN</code></td><td>Gitea API token used by the <code>script/release</code> script when publishing releases.</td></tr>
</tbody>
</table>
<h2>Gateway event-push protocol</h2>
<p>Project nodes can push pipeline status events to the gateway in real time over a WebSocket connection. The gateway fans each event out to all connected local subscribers.</p>
<h3>Connecting</h3>
<ol>
<li>Obtain a one-time join token: <code>POST /gateway/tokens</code><code>{"token":"…"}</code></li>
<li>Open a WebSocket upgrade to <code>GET /gateway/events/push?token=TOKEN&amp;project=PROJECT_NAME</code></li>
<li>The token is consumed on upgrade. The project name is attached to every event the server broadcasts downstream.</li>
</ol>
<h3>Sending events</h3>
<p>Each message must be a JSON-encoded <code>StoredEvent</code> frame:</p>
<pre><code>// Stage transition
{"type":"stage_transition","story_id":"42_story_login","from_stage":"2_current","to_stage":"3_qa","timestamp_ms":1700000000000}
// Merge failure
{"type":"merge_failure","story_id":"42_story_login","reason":"conflict in src/main.rs","timestamp_ms":1700000001000}
// Story blocked
{"type":"story_blocked","story_id":"42_story_login","reason":"retry limit exceeded","timestamp_ms":1700000002000}</code></pre>
<p>The server does not send frames back. Any other frames received by the project node indicate an error or server restart — treat them as a disconnect signal.</p>
<h3>Reconnect with exponential back-off</h3>
<p>Project nodes <strong>must</strong> reconnect on any disconnect. Use the following policy to avoid thundering herds after a gateway restart:</p>
<table>
<thead><tr><th>Parameter</th><th>Value</th></tr></thead>
<tbody>
<tr><td>Initial delay</td><td>1 s</td></tr>
<tr><td>Back-off multiplier</td><td>2× per attempt</td></tr>
<tr><td>Maximum delay</td><td>60 s</td></tr>
<tr><td>Jitter</td><td>±10 % of the computed delay</td></tr>
</tbody>
</table>
<p>Pseudocode:</p>
<pre><code>delay = 1.0 // seconds
max_delay = 60.0
loop:
token = POST /gateway/tokens
connect ws:/gateway/events/push?token=TOKEN&amp;project=NAME
while connected:
send StoredEvent frames
// disconnected — wait and retry
jitter = delay * (random(0.9, 1.1))
sleep(min(jitter, max_delay))
delay = min(delay * 2, max_delay)</code></pre>
<div class="note">
<strong>New token per connection:</strong> Each WebSocket upgrade consumes the join token. Request a fresh token for every reconnect attempt.
</div>
<h2>Building from source</h2>
<h3>Standard release build</h3>
<pre><code>cargo build --release
# Output: target/release/huskies</code></pre>
<h3>Static Linux binary (musl)</h3>
<p>Requires <code>cross</code>: <code>cargo install cross</code>.</p>
<pre><code>cross build --release --target x86_64-unknown-linux-musl</code></pre>
<h3>Docker image</h3>
<pre><code>docker compose -f docker/docker-compose.yml build</code></pre>
<h3>Release script</h3>
<p>Builds macOS arm64 and Linux amd64 binaries, bumps the version, tags the repo, and publishes a Gitea release with changelog and binaries attached.</p>
<pre><code>script/release 0.8.0</code></pre>
</main>
</div>
<footer class="reveal r3">
<span>&copy; 2026 Libby Labs Ltd.</span>
<a href="/privacy.html">Privacy Policy</a>
</footer>
</div>
</body>
</html>