2026-04-03 16:12:52 +01:00
# Huskies
2026-03-22 19:07:07 +00:00
2026-04-13 17:22:54 +01:00
A story-driven development server that manages work items, spawns coding agents, and runs them through a pipeline from backlog to done. Ships as a single Rust binary with an embedded React frontend. Can also be run in WhatsApp, Matrix, and Slack chats.
2026-03-28 14:03:23 +00:00
## Getting started with Claude Code
2026-04-03 16:12:52 +01:00
1. Download the huskies binary (or build from source — see below).
2026-03-28 14:34:45 +00:00
2. From your project directory, scaffold and start the server:
2026-03-28 14:03:23 +00:00
``` bash
2026-04-03 16:12:52 +01:00
huskies init --port 3000
2026-03-28 14:03:23 +00:00
```
2026-04-03 16:12:52 +01:00
This creates a `.huskies/` directory with the pipeline structure, `project.toml` , and `.mcp.json` . The `.mcp.json` file lets Claude Code discover huskies' MCP tools automatically.
2026-03-28 14:34:45 +00:00
2026-04-04 11:53:10 +01:00
Huskies also ships an embedded React frontend. Once the server is running, open `http://localhost:3000` to see the pipeline board, agent status, and chat interface.
3. Open a Claude Code session in the same project directory, or visit http://localhost:3000/.
2026-03-28 14:34:45 +00:00
2026-04-03 16:12:52 +01:00
4. Tell Claude: "help me set up this project with huskies." Claude will walk you through the setup wizard — generating project context, tech stack docs, and test/release scripts. Review each step and confirm or ask to retry.
2026-03-28 14:03:23 +00:00
2026-03-28 14:34:45 +00:00
Once setup is complete, Claude can create stories, start agents, check status, and manage the full pipeline via MCP tools — no commands to memorize.
2026-03-28 14:03:23 +00:00
## Chat transports
2026-04-03 16:12:52 +01:00
Huskies can be controlled via bot commands in **Matrix ** , **WhatsApp ** , and **Slack ** . Configure a transport in `.huskies/bot.toml` — see the example files:
2026-03-28 14:03:23 +00:00
2026-04-03 16:12:52 +01:00
- `.huskies/bot.toml.matrix.example`
- `.huskies/bot.toml.whatsapp-meta.example`
- `.huskies/bot.toml.whatsapp-twilio.example`
- `.huskies/bot.toml.slack.example`
2026-03-22 19:07:07 +00:00
2026-04-04 11:53:10 +01:00
## Prerequisites for building
2026-03-22 19:07:07 +00:00
2026-03-28 10:56:36 +00:00
- Rust (2024 edition)
- Node.js and npm
- Docker (for Linux cross-compilation and container deployment)
2026-04-04 11:53:10 +01:00
- `cross` (`cargo install cross` ) optional, for Linux static builds. Only needed if you are building for a different architecture, e.g. if you want to build a Linux binary from a Mac.
You only need these installed if you want to build Huskies yourself. Alternately, you can just download and run the `huskies` binary for your system from https://code.crashlabs.io/crashlabs/huskies/releases
2026-03-22 19:07:07 +00:00
2026-03-28 10:56:36 +00:00
## Building for production
2026-03-22 19:07:07 +00:00
``` bash
cargo build --release
```
2026-04-03 16:12:52 +01:00
The release binary embeds the frontend via `rust-embed` . Output: `target/release/huskies` .
2026-03-22 19:07:07 +00:00
2026-03-28 10:56:36 +00:00
For a static Linux binary (musl, zero dynamic deps):
2026-03-22 19:07:07 +00:00
``` bash
2026-03-28 10:56:36 +00:00
cross build --release --target x86_64-unknown-linux-musl
2026-03-22 19:07:07 +00:00
```
2026-03-28 10:56:36 +00:00
Docker:
2026-03-22 19:07:07 +00:00
``` bash
2026-04-09 18:00:20 +01:00
script/docker_rebuild
# or
script/docker_restart
2026-03-22 19:07:07 +00:00
```
2026-03-28 10:56:36 +00:00
## Running in development
2026-03-22 19:07:07 +00:00
``` bash
2026-03-28 10:56:36 +00:00
# Run tests
script/test
2026-03-22 19:07:07 +00:00
2026-03-28 10:56:36 +00:00
# Run the server
cargo run -- --port 3000
2026-03-22 19:07:07 +00:00
2026-03-28 10:56:36 +00:00
# In another terminal, run the frontend dev server
cd frontend && npm install && npm run dev
2026-03-22 19:07:07 +00:00
```
2026-04-03 16:12:52 +01:00
Configuration lives in `.huskies/project.toml` . See `.huskies/bot.toml.*.example` for transport setup.
2026-03-22 19:07:07 +00:00
## Releasing
2026-03-28 10:56:36 +00:00
Requires a Gitea API token in `.env` (`GITEA_TOKEN=your_token` ).
2026-03-22 19:07:07 +00:00
``` bash
2026-03-28 14:03:23 +00:00
script/release 0.7.1
2026-03-22 19:07:07 +00:00
```
2026-03-28 10:56:36 +00:00
This bumps version in `Cargo.toml` and `package.json` , builds macOS arm64 and Linux amd64 binaries, tags the repo, and publishes a Gitea release with changelog and binaries attached.
2026-03-28 14:03:23 +00:00
2026-04-10 16:41:01 +00:00
## Multi-node CRDT sync (rendezvous)
Huskies nodes can replicate pipeline state in real-time over WebSocket. Add a
`rendezvous` field to `.huskies/project.toml` to configure a peer:
``` toml
rendezvous = "ws://other-host:3001/crdt-sync"
```
On startup, this node opens an outbound WebSocket connection to the configured
URL and exchanges CRDT ops bidirectionally. The connection is fully symmetric:
both sides send a bulk state dump on connect, then stream individual ops as they
are applied locally.
### Reconnect behaviour
If the peer is unreachable on startup (or the connection drops mid-session), the
client retries with exponential backoff starting at 1 s and capping at 30 s.
Failures are logged at **WARN ** ; after 10 consecutive failures the level escalates
to **ERROR ** to surface persistent connectivity problems.
### Deployment topologies
**Peer-to-peer (two nodes pointing at each other): **
```
Node A ←→ Node B
```
Configure each node with the other's `/crdt-sync` URL. Both nodes exchange ops
directly. Supported by this story — ops propagate in both directions and both
nodes converge to the same state. Works well for two machines collaborating on
the same project.
**Hub-and-spoke (many clients → one central rendezvous): **
```
Client 1 ──┐
Client 2 ──┤── Hub node
Client 3 ──┘
```
Point multiple client nodes at a single "hub" node. The hub receives ops from
all clients and re-broadcasts them. Clients do * not * connect to each other —
convergence is mediated through the hub. The hub itself runs a normal huskies
instance with `rendezvous` unset (it only accepts inbound connections).
> **Caveat:** Hub-to-client relay depends on the hub's `/crdt-sync` inbound
> WebSocket handler re-broadcasting every received op to all other connected
> peers. That broadcast happens automatically via the shared `SYNC_TX` channel
> (each locally-applied remote op is re-emitted), so hub-and-spoke works today
> but has not been load-tested. Follow-up work may be needed for large fan-out
> (many spoke clients) to avoid broadcast-channel lag.
2026-04-10 10:12:54 +00:00
## Startup reconcile pass
On startup, after CRDT replay and database initialisation, huskies runs a
**reconcile pass ** that compares pipeline state across three sources:
1. **In-memory CRDT ** — the primary source of truth, reconstructed from
`crdt_ops` on startup.
2. * * `pipeline_items` table** — a shadow/materialised view written alongside
CRDT updates, used for fast DB queries.
3. **Filesystem shadows ** (`.huskies/work/N_stage/*.md` ) — legacy rendering
still written by some paths and read by agent worktrees.
Any disagreement between these sources is **drift ** . The reconcile pass logs a
structured line for each drifted item:
```
[reconcile] DRIFT story=X crdt_stage=Y db_stage=Z fs_stage=W
```
(`MISSING` is used where a source has no record for that story.)
### Drift types
| Type | Meaning |
|------|---------|
| `CRDT-only` | Story present in CRDT but absent from `pipeline_items` |
| `DB-only` | Story present in `pipeline_items` but absent from CRDT |
| `FS-only` | Story on the filesystem but absent from both CRDT and DB |
| `stage-mismatch` | Story present in both CRDT and DB but with different stage values |
Note: a filesystem shadow that lags behind the CRDT/DB stage (both of which
agree) is **not ** treated as drift — the FS is a best-effort rendering and is
allowed to lag.
If any drift is detected, the Matrix/Slack/WhatsApp bot startup announcement
includes a count and a suggestion to check the server logs.
### Opt-out
Set `reconcile_on_startup = false` in `.huskies/project.toml` to disable the
pass during the migration window if it produces noise.
2026-04-10 10:20:41 +00:00
## Debugging
### Inspecting the in-memory CRDT state
When diagnosing state issues, use the `dump_crdt` MCP tool or the `/debug/crdt` HTTP endpoint to inspect the raw in-memory CRDT state directly. These surfaces show the ground truth that the running server holds — not a summarised pipeline view and not the persisted SQLite ops.
**MCP tool ** (from Claude Code or any MCP client):
```
mcp__huskies__dump_crdt
# dump everything
{}
# restrict to a single item
{"story_id": "42_story_my_feature"}
```
**HTTP endpoint ** (browser or curl):
``` bash
# dump everything
curl http://localhost:3001/debug/crdt
# restrict to a single item
curl "http://localhost:3001/debug/crdt?story_id=42_story_my_feature"
```
Both return a JSON document with:
- **`metadata` ** — `in_memory_state_loaded` , `total_items` , `total_ops_in_list` , `max_seq_in_list` , `persisted_ops_count` , `pending_persist_ops_count`
- **`items` ** — one entry per CRDT list item (including tombstoned/deleted entries), each with `story_id` , `stage` , `name` , `agent` , `retry_count` , `blocked` , `depends_on` , `content_index` (hex OpId for cross-referencing with `crdt_ops` ), and `is_deleted`
> **This is a debug tool.** For normal pipeline introspection use `get_pipeline_status` or `GET /api/pipeline` instead.
2026-04-10 10:12:54 +00:00
2026-04-12 13:11:23 +00:00
## Source Map
2026-04-15 18:08:16 +00:00
See `.huskies/specs/tech/STACK.md` for the full source map.
2026-03-28 14:03:23 +00:00
GPL-3.0. See [LICENSE ](LICENSE ).