(حشد = Arabic for "crowd")
The disciplined, auditable software factory for spec-driven development. Every change goes spec -> story -> implement -> review -> merge through governed gates, with a full audit trail of why every line of merged code exists.
Requirements
- git
- A working AI agent — Claude Code by default, or Codex, Gemini, OpenCode, Kimi, Qwen, or Copilot. Install and authenticate an agent →, you can also set different agents for different stages.
hashd installs everything else — Python, the forge CLIs (gh/glab/bkt/tea), diff tools — on its own.
Install
curl -fsSL https://raw.githubusercontent.com/codr1/hashd-code/main/install.sh | bashThe installer is the supported path. Release wheels are published as GitHub
assets rather than to PyPI, and hashd depends on hashd-client, which is
published the same way -- so pip install hashd or uv tool install hashd
cannot resolve and fails inside the resolver rather than with an explanation.
The installer also brings the Temporal server and the external tools a wheel
does not carry.
New to hashd? QUICKSTART takes you from here to your first merged change. (wf and ha are aliases for hashd.)
Hashd is an orchestration system for AI coding agents. It plans the work, runs agents in isolated worktrees, grounds them in verified code structure, gates each change through review, and records the full lineage of every commit.
Hashd is the first coding platform designed to enhance the team. Everyone else is going after individual developers. We recognize that the AI era changes the way teams build software -- so hashd is built to run as a shared server where different people work together: every request attributed to a person, every workstream owned by one, every member running agents on their own credentials, and every merge governed by the same gates. Solo use is the default and stays first-class; the team is the point.
10x developer throughput. 10x fewer tokens spent on exploration. 15%+ accuracy improvement from grounded context.
AI coding agents are powerful but unaccountable. They generate code without explaining why, re-discover the codebase on every run, and make decisions you can't trace later. Hashd adds the structure that makes AI-generated code trustworthy enough to ship -- and fast enough to change how much you ship in a day.
Spec-driven development is an established category. Generation-only spec tools stop at producing code from a spec; hashd governs the whole path to a merged, attested commit -- the implement/test/review loop, the human-approval gates between steps, and a verifiable provenance chain that records every one of them.
Work flows through four entities, each backed by a validated state machine:
Requirement -> Suggestion -> Story (+ acceptance criteria) -> Workstream -> micro-commits -> merged commit
- A Suggestion is a candidate piece of work discovered from your requirements (
REQS.md). - Claiming it creates a Story: a feature or bug with acceptance criteria -- the source of truth for what the change should do.
- Running an accepted Story creates a Workstream: one git branch in one isolated worktree, holding a plan of micro-commits (the smallest planned units of work).
- Each micro-commit runs the governed loop --
implement -> test -> review -> human approval -> commit-- where every arrow is a gate. When all micro-commits land, the branch gets a holistic final review and a merge gate (tests, conflict check, secrets scan), then merges. - Whether a gate stops for a human is set by the project's autonomy mode (supervised / gatekeeper / autonomous). Unresolved failures still require intervention in every mode.
- Every state change is dual-written: pushed live over the event bus and recorded durably in SQLite. That durable log is the spine of the audit trail --
hashd lineagereconstructs why any line of code exists, all the way back to the requirement and the human who approved it.
The bottleneck in shipping AI-written code is not typing speed -- it is trust: knowing a change does what was asked, that it was reviewed, that a human signed off where it mattered, and that you can reconstruct the decision chain later. Hashd is a process and provenance layer over raw agents. It does not make the agent faster; it makes the agent's output accountable -- governed by gates, recorded as it happens, and auditable after the fact. That is the half generation-only tools lack.
Start here
- QUICKSTART.md - install to your first merged change.
- docs/how-hashd-works.md - the mental model: entities, the governed gates, the event log, and the provenance chain.
- docs/walkthrough.md - one feature start-to-finish, from spec to a merged commit.
Everyday use
- docs/watch.md - the
hashd watchterminal UI: the three views and the keys that move between them. - docs/AGENT_MANAGEMENT.md - choose and switch AI agents, including per stage.
- docs/CODE_TOOLS.md - the
hashd codeintelligence commands. - docs/HOOKS.md - workspace lifecycle hooks.
- docs/CONNECTORS.md - external integrations (GitHub Issues, Figma).
- docs/TROUBLESHOOTING.md - when something breaks.
Running a server
- docs/REMOTE.md - remote and team servers: TLS trust, account setup, tokens, pairing.
Reference
- WF.md - authoritative workflow states, transitions, guards and recovery. See the command reference and TUI keybindings for interface usage.
- docs/glossary.md - canonical definitions: Suggestion, Story, Workstream, micro-commit, stage vs runtime_status vs runner_stage.
- docs/provenance.md - the audit story:
hashd lineage, SLSA/in-toto export, hash-chain verify. - docs/ARCHITECTURE.md - client/server boundaries, state, events, diagnostics.
- RELEASE_NOTES.md - version-by-version release notes.
Plans the work. Stories, suggestions, and workstreams are first-class entities with state machines. A story flows from drafting through review to acceptance; a workstream loops through breakdown, implement, test, review, and human gate for each micro-commit. You always know what stage a piece of work is in and what comes next.
Grounds the agents. Agents query a pre-computed Context Graph instead of re-discovering the codebase on every run. AST structure, dependency edges, and project knowledge are extracted once and made available to every agent in every workstream. Published research on systems like Aider shows tool-based exploration consumes 54-70% of the context window for orientation alone; pre-computed structural maps reduce this to 4-6%. That's a 10-15x reduction in tokens spent discovering what static analysis already knows -- and a corresponding reduction in cost, latency, hallucinated file paths, and first-pass review failures.
Records the lineage. Every commit traces through its workstream, its story, its reviews, its clarifications, and the human decisions that gated it. hashd lineage <file|sha|STORY-xxx> reconstructs the chain. hashd lineage export --format slsa|in-toto produces machine-readable provenance for supply-chain compliance. hashd lineage verify validates the hash chain integrity. AI-generated code becomes auditable.
file -> git log -> commit message (COMMIT-XX-NNN)
-> workstream -> STORY_ID -> story
-> transcript, reviews, clarifications, human decisions
Runs in parallel, safely. Multiple workstreams execute against the same project concurrently. Each gets its own git worktree. A Temporal workflow singleton rejects a second run while that workstream's run is still open, and server FSM and lifecycle guards gate competing operator actions. hashd conflicts reports recorded file overlap between workstreams. With grounded agents and parallel execution working together, hashd users routinely ship 10x more debugged code per day than they would driving an agent by hand.
Works with any agent. Use Claude Code, Codex, Copilot, Gemini, OpenCode, Kimi, or Qwen -- any combination, any stage. Stages declare their required invocation shape; any agent that supports the shape can fill the slot. You're not locked to one vendor.
Spans multiple repositories. A single project can include a backend repo, a frontend repo, and an infra repo. Planning happens at the project level; execution happens in the right repo automatically.
Multiple interfaces. A TUI (hashd watch) for real-time monitoring with status-adaptive keybindings, a CLI for power users and scripting, and a Telegram bot for mobile workflow management.
Keeps you in the loop where it matters. Three autonomy modes -- supervised, gatekeeper, and autonomous -- with confidence-threshold gating. A clarification queue holds work until you answer agent questions. Structured approve and reject flows.
Hashd is a client (hashd, hashd watch) talking to a server (hashd-server). How you deploy that pair is a choice, and all three shapes are supported:
Solo, local (the default). Client and server run on your machine as one implicit user, no auth ceremony. This is what QUICKSTART.md sets up and what most single developers use -- if that's you, nothing below is required.
Server-backed (local or remote clients). Run hashd-server on a box and point clients at it -- your laptop driving a server in the closet, or a shared team server. Off-loopback the server serves TLS with an auto-generated certificate and every request needs a bearer token, and a client pairs in one command:
- You own the server -- mint a token with
hashd auth create, thenhashd server set <url> --token <token>. - Your admin runs the server -- they run
hashd admin user add you@co.com, which prints a one-time access token; you runhashd server set <url> --token <token>and you're connected, attributed as yourself.
Either way the token carries the server's certificate fingerprint, so pairing needs no separate trust step. Full walkthrough, trust model, and troubleshooting: docs/REMOTE.md.
Working together on one server. A shared server is multi-user for real: every request is attributed to the person who made it, and a workstream belongs to the user who started it. Agent credentials are per-user too -- each member registers their own agent login (hashd agents login claude, or the web dashboard's Settings -> Agent logins panel), stored encrypted at rest and injected only into runs that member owns; a run whose owner has no live credential refuses to start rather than borrowing someone else's account. Team mode (hashd config set deployment_mode team) makes per-user identity mandatory on every request. The server also serves a browser dashboard alongside the TUI -- workstream monitoring, change review, chat, and settings -- so teammates can observe and act without a terminal.
Solo shared-repo (advanced, not recommended). Several developers each run their own solo hashd against the same git repository, their per-project state living side by side under .hashd, with no server coordinating them. Git is the only shared substrate. It works, but there is no shared workstream registry or multi-user gate -- prefer a server for real collaboration.
Team coordination extras. Working together on one server ships today -- identity, tokens, attribution, workstream ownership, and per-user agent credentials (see Running hashd above). Still landing on top: attestations exported per merge.
Desktop app. A native Electron client for users who prefer a windowed UI over the terminal.
The Context Graph that grounds the agents (above) is built in three layers:
Layer 1: Structural analysis. AST parsing extracts a deterministic map of the codebase -- modules, classes, functions, and their signatures -- with zero LLM calls. Every symbol is verified to exist; every relationship is a real reference, not a retrieval approximation. This is grounding in the formal sense: constraining generation with verified facts.
Layer 2: Dependency edges. Import graphs, call sites, and type references promote the structural tree into a full graph. When an agent needs to modify a function, the graph answers "what depends on this?" in constant time rather than O(n) tool-call rounds.
Layer 3: Project knowledge. Full-text search over project artifacts -- stories, review decisions, clarifications, conversation history -- connects code nodes to the business decisions that motivated them. The graph becomes heterogeneous: code structure and project intent in a single queryable system.
Install shell completion for your shell:
# Bash (managed automatically by setup.sh and dist/install.sh)
source <(hashd completion bash)
# Zsh (managed automatically by setup.sh for source installs)
autoload -Uz compinit && compinit
source <(hashd completion zsh)
# Fish
hashd completion fish > ~/.config/fish/completions/hashd.fishExamples:
hashd r<TAB> # -> hashd run
hashd run o<TAB> # -> hashd run open_play_rules
hashd run STORY-<TAB> # -> hashd run STORY-0001
hashd show <TAB> # Shows both stories and workstreamsHashd supports running multiple workstreams simultaneously. Each workstream gets its own git worktree. Runs use the Temporal singleton run:{project}:{workstream}, which refuses a second run dispatch while the first is still open:
# Terminal 1
hashd run feature_auth --loop
# Terminal 2 (at the same time)
hashd run feature_api --loop
# Terminal 3
hashd run bugfix_123 --loopChoose how many workstreams to run based on machine capacity and provider rate limits. Use hashd conflicts [id] to inspect recorded file overlap with other active workstreams; omit the ID to use the current workstream.
Hashd sends desktop notifications at three levels:
| Level | Urgency | Expires | When |
|---|---|---|---|
| Needs you | critical | stays until dismissed | Review parks, final review concerns, blocked runs, runs closed outside workflow control, merges stopped on work in progress, raised clarifications, Arc proposals awaiting a decision |
| Failure | critical | 20s | Run failure, merge failure, PR create/push failure, workstream creation failure, engine degraded |
| Good news | low | 5s | Ready to merge, merged, story implemented, suggestion reverted |
Works with any freedesktop-compliant notification daemon (mako, dunst, GNOME, KDE).
Requires notify-send to be installed:
# Debian/Ubuntu
sudo apt install libnotify-bin
# Arch
sudo pacman -S libnotifySet a current workstream to avoid typing it repeatedly:
hashd use my_feature # Set current workstream
hashd run --loop # Operates on my_feature
hashd approve # Still my_feature
hashd show # Still my_feature
hashd use # Show current workstream
hashd use --clear # Clear current workstreamWhen a workstream context is set, you can still override it explicitly:
hashd use my_feature
hashd show other_feature # Operates on other_feature, context unchangedhashd chat opens an AI pair programmer with persistent conversation history. Use @ syntax to inject context:
hashd chat # Auto-detect context from current directory
hashd chat STORY-0001 # Explicit story context
hashd chat my-workstream # Explicit workstream context
hashd chat --history # View past conversation as markdownAvailable @ artifacts:
| Artifact | Description |
|---|---|
@diff |
Current git diff |
@log |
Latest stage log |
@review |
Review feedback |
@story |
Story details + criteria |
@timeline |
Story/workstream timeline |
@file:path |
Specific file content |
@clq |
Clarification history |
@reqs |
REQS.md content |
@spec |
SPEC.md content |
@commits |
Commit history |
@stories |
List of project stories |
@workstreams |
List of active workstreams |
@STORY-xxxx |
Cross-reference another story |
@BUG-xxxx |
Cross-reference a bug |
For full artifact inspection or manual edits, use the server-backed project
artifact commands: hashd project reqs / hashd project reqs edit and
hashd project spec / hashd project spec edit. The @reqs and @spec references
are prompt/chat context shortcuts.
@file:path is project-scoped. The path must resolve inside the project
directory. Planning treats file references as metadata only and never loads file
contents into prompts; agents read reachable project files on demand. A
planning-time warning is emitted when REQS or a story description references an
outside-project path so the operator can move the file into the project tree.
In TUI mode, press C from any screen to open chat. Type @ to see autocomplete.
Actionable chat: When chatting in a story context, the AI can propose edits to story artifacts (acceptance criteria, title, problem statement, non-goals) and run safe read-only hashd commands. Each proposed action appears in a confirmation bar -- press y to apply or n to skip. Actions are logged to the story transcript.
Directives are operator guidance included in agent prompts at three levels:
~/.config/hashd/directives.md # Global user preferences
{repo}/directives.md # Project rules
workstream directives # Stored in hashd; managed through the commands below
Why directives.md not AGENTS.md? We want hashd to control when directives are passed to agents, not have agents auto-read them. This ensures agents only see these rules when we explicitly include them in prompts.
Shared engineering rules belong in prompt includes, not local directives. Use directives for operator-specific constraints.
Unmarked text applies wherever directives are loaded. Restrict a block with:
<!-- STAGE: review, final_review -->
Preserve the documented public API.
<!-- END STAGE -->Labels are planning, implement, fix_generation, review, final_review,
and edit_flow. These are directive groups, not the full agent-stage list;
breakdown uses planning, concern triage uses review, and conflict resolution
uses implement. Blocks cannot nest. Malformed blocks warn and render without
stage restriction rather than silently dropping guidance.
# Project Directives
- No backward compatibility. We have zero users.
- Use sync.Once pattern for handler initialization
- Follow existing templ component patterns in internal/templates
- HTMX handlers should set HX-Trigger for related component updateshashd directives # View global directives
hashd directives all # View all (global + project)
hashd directives all -w <ws> # View all including workstream
hashd directives project # View project only
hashd directives workstream <ws> # View workstream's only
hashd directives edit # Edit global in $EDITOR
hashd directives edit project # Edit project in $EDITOR
hashd directives edit workstream <ws> # Edit workstream's in $EDITOR
hashd directives ai-edit # AI-assisted edit of global
hashd directives ai-edit project # AI-assisted edit of project
hashd directives ai-edit workstream <ws> # AI-assisted edit of workstream'sDirectives are automatically included in implementation prompts.
| Command | Description |
|---|---|
hashd plan |
Plan stories from REQS.md (saves suggestions) |
hashd plan list |
View current suggestions |
hashd plan story "title" |
Quick feature story (skips REQS discovery) |
hashd plan bug "title" |
Quick bug fix (skips REQS discovery, conditional SPEC update) |
hashd story clone STORY-xxx |
Clone a locked story to edit |
hashd story edit STORY-xxx |
Edit existing story (if unlocked) |
hashd plan reset |
Reclaim suggestions stranded by a dead flow or deleted story (unblocks discovery) |
hashd run [id] |
Run workstream or create from story |
hashd list [--mine] |
List all stories and workstreams (--mine: only your own in team mode; solo mode lists everything) |
hashd show <id> |
Show story or workstream details |
hashd approve <id> |
Accept story or approve workstream gate |
hashd pr create [id] |
Create PR/MR on forge (for external review) |
hashd pr feedback <ws> |
View PR/MR review comments |
hashd merge [id] [--confirm|-y] [--pr] [--no-push] [--fix] [--ai-resolve] |
Merge to main (--pr: via forge PR instead of direct merge) |
hashd close <id> |
Close story or workstream (abandon) |
hashd watch [id] |
Interactive TUI (dashboard, or detail for workstream/STORY-xxxx). A pure viewer: connects to running services, never starts them -- if the stack is down it says what to run |
The hashd watch TUI adapts keybindings to workstream status:
| Status | Key Actions |
|---|---|
awaiting_human_review |
[a] approve, [r] reject, [R] reset |
complete |
[P] create PR, [m] merge, [e] edit microcommit |
pr_open / pr_approved |
[r] reject (review findings and add guidance), [o] open PR, [a] merge |
In PR states, [r] opens a draft with internal findings included and forge findings
excluded. Edit, exclude or restore each source, and add separate human guidance;
submission saves exactly that selection into the FIX.
Diff mode ([d] to enter): [s] side-by-side, [I] lineage, [h] hunk selection, [space] select hunk, [f] fullscreen, Enter lineage detail (in lineage).
The Telegram bot covers the full workflow from mobile. Send / for the button menu or type commands directly:
| Category | Commands |
|---|---|
| Inspect | /status, /list, /show <id>, /log <id> |
| Execute | /run <id>, /review <id> |
| Gate | /approve <id>, /reject <id> [feedback] |
| Lifecycle | /merge <id>, /close <id>, /pr <id> |
| Plan | /plan, /story <title>, /bug <title>, /answer [id] |
| Utility | /search <query>, `/use [id |
Setup:
- Create a bot via @BotFather (
/newbot), copy the token:hashd telegram bot <YOUR_TOKEN>
- Get your user ID from @userinfobot, then allow it and set as chat target:
hashd telegram allow <YOUR_USER_ID> hashd telegram chat-id <YOUR_USER_ID>
- Start the bot:
hashd telegram start
The bot also auto-starts when you run hashd run.
| Command | Description |
|---|---|
hashd use [id] |
Set/show current workstream context |
hashd run [id] --loop |
Run until blocked or complete |
hashd run [id] --yes |
Skip confirmation prompts |
hashd run [id] --verbose |
Show implement/review exchange |
hashd log [id] |
Show workstream timeline |
hashd review [id] |
Show the current review (pending micro-commit/FIX, or the current final verdict) |
hashd lineage <target> |
Trace code lineage (file, SHA, or STORY/BUG ID) |
hashd lineage export <sha|STORY-xxxx|BUG-xxxx> --format slsa|in-toto |
Export attestation JSON for a tracked commit or story |
hashd lineage verify |
Validate commit hash chain integrity |
hashd reject [id] -f "..." |
Reject with additive human guidance (context-aware) |
hashd review findings ID [--include-forge] |
Export editable Markdown without rejecting |
hashd reject ID --findings-file FILE |
Replace the complete findings set (- reads stdin) |
hashd reject [id] --reset |
Discard changes, start fresh (human gate only) |
hashd workstream resolve-oscillation <id> -f "..." |
Record an operator ruling on the latest FIX commit; does not resume execution |
hashd diff [id] |
Show workstream diff |
hashd test [--] <command...> |
Run a test command in the current worktree and record its verdict |
hashd skip [id] |
Mark commit as done without changes |
hashd reset [id] |
Keep the plan, reset the worktree to baseline, redo the implementation |
hashd replan [id] [-f "..."] |
Regenerate the plan from a clean base |
hashd refresh [id] |
Refresh touched files |
hashd conflicts [id] |
Check for file conflicts |
hashd archive work |
List archived workstreams |
hashd archive stories |
List archived stories |
hashd open <id> [--force] |
Resurrect archived workstream |
hashd answer list |
List entities with pending clarifications |
hashd answer show <entity> |
Show pending questions for a story or workstream |
hashd answer <entity> "<text>" |
Bundle-answer pending clarifications and dispatch the next agent run |
hashd directives |
View/edit project directives |
hashd workstream add-commit <ws> "title" |
Add AI-generated micro-commit to plan |
hashd workstream edit-commit <ws> <id> |
Edit a micro-commit's title/description |
hashd workstream feedback <ws> "text" |
Append guidance to the workstream's standing directives and print the saved text |
hashd workstream remove <ws> |
Remove orphaned workstream |
hashd story retry STORY-xxx |
Retry failed planning run |
hashd docs [workstream] |
Dispatch an update to the configured SPEC artifact |
Use hashd answer list, then hashd answer show <entity> to inspect the pending
questions. hashd answer <entity> "<text>" submits one answer covering that set.
Answer the workstream once a story has one. --wait is supported only for
workstream answers; monitor story answers with hashd flow status <story>.
| Command | Description |
|---|---|
hashd project add <path> |
Register a new project (wizard by default; investigate-then-execute also supported) |
hashd project add <path> --no-interview |
Register a new project without prompts, using stored defaults or explicit overrides |
hashd project list |
List registered projects |
hashd project use [name] [--clear] |
Set/show/clear current project context |
hashd project show [name] |
Show a project's configuration (defaults to the current project) |
hashd project interview |
Reconfigure project (build/test commands, merge mode, autonomy) |
hashd project remove <name> -y |
Remove a project without confirmation prompt |
hashd project config list |
List effective project config, highlighting project overrides in TTY output |
hashd project config diff |
Show project overrides against inherited system/default config |
hashd project config show <key> |
Show effective value, source, override stack, and schema description |
hashd project config get <key> |
Print one effective config value |
hashd project config set <key> <value> |
Set config value |
hashd project config reset <key> |
Remove one project override |
hashd project config reset --all |
Remove all project overrides while preserving project identity |
hashd project describe |
Show current project description |
hashd project describe --suggest |
AI-generate and save a description suggestion |
hashd project tech |
Show current project tech stack |
hashd project tech --suggest |
AI-analyze and save a tech stack suggestion |
hashd project reqs [show] |
Show configured REQS artifact content through hashd-server |
hashd project reqs edit |
Edit configured REQS in $EDITOR; WIP sections are protected |
hashd project spec [show] |
Show configured SPEC artifact content through hashd-server |
hashd project spec edit |
Edit configured SPEC in $EDITOR through the server-side commit flow |
hashd project repo list [--json] |
List repos registered under the current project |
hashd project repo show <name> [--json] |
Show one registered repo |
hashd project repo add <path> --status <status> |
Add a repo to the current project |
hashd project repo set-status <name> <status> |
Reclassify a repo as primary, active, reference, or ignore |
hashd project repo set-path <name> <new-path> |
Update a repo's relative path within the project |
hashd project repo edit <name> ... |
Update per-repo commands and metadata |
hashd project repo remove <name> |
Soft-delete a repo entry (status=ignore) |
hashd project repo prune |
Hard-delete ignored repos whose paths no longer exist |
hashd project describe --suggest and hashd project tech --suggest persist the AI result to
config.yaml by default. Use --no-save for a dry run, or -y to skip the interactive
save prompt. hashd project show, hashd project describe, hashd project tech, and
hashd project list warn when saved AI-generated metadata may be stale relative to the
current reqs_path or fallback source files.
hashd project reqs and hashd project spec read the configured artifacts through
hashd-server, so remote CLI clients do not need local filesystem access to the
repository. Their edit subcommands open the current artifact in $EDITOR, send
the replacement back with a compare-and-swap head SHA, and let the server commit
and push exactly that artifact change. The server rejects stale edits, dirty
repos, symlink artifact paths, and any REQS edit that changes text between
BEGIN WIP and END WIP markers owned by active stories.
| Command | Description |
|---|---|
hashd system-log |
View system event log |
hashd prompts list |
List prompt templates |
hashd prompts show <name> |
Show prompt content |
hashd prompts edit <name> |
Edit prompt override |
hashd agents |
Show installed AI agents and credential health |
hashd doctor |
Validate setup and diagnose issues |
hashd restart [component] [--force] [-y] [--auto-rebuild] |
Restart infrastructure (server, Temporal sidecar, event forwarder, messengers). Restarting the server first holds new work and waits, with no limit and with progress, until running work reaches a stopping point; Ctrl-C cancels and stops nothing. --force interrupts instead (asks first; --yes skips the question and is required without a terminal); --yes alone never forces. --in-place-upgrade takes no component, --reclaim-port takes none or server, --force takes none or server |
hashd stop [--force] [-y] |
Stop this machine's hashd-server and Temporal sidecar, waiting for a stopping point the same way; the hold is released when the server next starts |
hashd search <query> [--kind kind] [-n limit] |
Full-text search across stories, events, reviews, chat (default limit: 20) |
Commands automatically route based on ID prefix:
STORY-xxx- Routes to story commands (e.g.,hashd show STORY-0001)lowercase_id- Routes to workstream commands (e.g.,hashd show my_feature)
Commands marked with [id] use the current workstream context if no ID is provided.
When reopening archived workstreams, hashd open analyzes staleness by comparing file changes on the branch against the default branch. It prints commits-behind, overlapping files, default-branch line churn, and a low/moderate/high/critical severity score. High and critical reopens require interactive confirmation, or --force for non-interactive use.
Stories flow: drafting -> draft -> accepted -> implementing -> implemented (also: draft_failed, editing, abandoned)
Workstreams loop: breakdown -> implement -> test -> review -> human_review -> commit (repeat for each micro-commit)
See WF.md for detailed lifecycle documentation.
The hashd reject command adapts its behavior based on workstream state:
When status is awaiting_human_review (mid-micro-commit):
hashd reject my_feature -f "Fix the null check" # Iterate with feedback
hashd reject my_feature --reset # Discard, start freshThis writes a rejection file and continues the run loop.
Rejection appends one FIX task and resumes the existing implementation loop. It includes the latest applicable internal final-review findings by default. The existing PR and its metadata are preserved.
hashd reject my_feature # Include internal findings
hashd reject STORY-0042 --include-forge -f "Keep the public API" # Also include open forge findings
hashd review findings STORY-0042 --include-forge > findings.md # Export only; edit this file
hashd reject STORY-0042 --findings-file findings.md -f "Human ruling"
hashd reject my_feature --findings-file - < findings.mdBoth commands accept workstream IDs or story IDs. A story must have a linked
workstream. --findings-file replaces the complete findings set; an empty
file excludes all findings. It cannot be combined with --include-forge.
Explicitly requested forge-fetch failures are reported before rejection.
-f adds human guidance, which takes precedence over findings. A FIX needs
findings or guidance; if both are empty, rejection is refused.
Web and TUI load a rejection draft when it opens: internal findings start included, forge findings start excluded. Each source has a collapsible Markdown editor, inclusion control, edited status, and a restore-original action. Viewing forge findings does not include them. Guidance stays separate. Failed submission preserves the draft. Telegram offers view, exclude/restore, guidance, submit, and cancel buttons; typing guidance only updates the draft.
The submitted selection and guidance are saved in the FIX task description. Excluded findings are not restored into its fresh implementer prompt. Original reviews remain unchanged, and excluding a forge finding does not resolve its thread. Review feedback produced within that FIX's normal retry loop continues to reach the implementer.
Hashd uses Temporal for workflow orchestration. The Temporal sidecar and the in-server worker start automatically when needed:
# Run a workstream (Temporal starts automatically)
hashd run my_feature # Dispatches the run workflow, returns immediately
# Monitor progress
hashd watch my_feature # Interactive TUI
hashd show my_feature # Status snapshotThe hashd run command dispatches a Temporal workflow and returns immediately. Use hashd watch or hashd show to monitor execution.
Transient failures are retried automatically in two layers: the agent runner retries classified-transient agent failures (API timeouts, rate limits) within an attempt, and each agent stage runs as a Temporal activity whose retry policy retries infrastructure failures (worker death, DB faults) across attempts. Agent outcomes -- review verdicts, failing tests -- are data, never auto-retried as errors.
See QUICKSTART.md for full installation instructions including platform-specific commands. Building from source instead? See DEVELOPMENT.md.
- Git - the only OS-level prerequisite. (Python 3.11+ is handled by the installer; it bootstraps a runtime via uv when your system has none.)
- At least one AI coding agent - Claude Code by default (see Agent Configuration). Agent CLIs are npm packages, so installing one needs Node.js 20+; that is the agent's prerequisite, not hashd's.
hashd doctorprints the exact OS-correct install commands. - A forge CLI for your host: gh (GitHub), glab (GitLab), bkt (Bitbucket), or tea (Gitea). The curl installer auto-installs pinned prebuilt versions; links are manual fallbacks.
- delta (git-delta) - bundled TUI side-by-side, syntax-highlighted, word-level diff renderer (auto-installed by the installer /
setup.sh) - gitleaks - secrets scanning at project setup (auto-installed by the installer /
setup.sh) - codebase-memory-mcp - bundled code intelligence backend (auto-fetched by the installer /
setup.sh; setup fails if the pinned binary cannot be fetched or executed) - A project with tests (Makefile, package.json, Taskfile, etc.)
Authenticate the forge you use:
gh auth login # GitHub
glab auth login # GitLab
bkt auth login --kind cloud --web # Bitbucket OAuth
bkt auth login --kind cloud --web-token # Bitbucket API-token alternative
tea login add --name work --url https://git.example.com --token $TOKEN # GiteaFor GitHub and GitLab PR operations, solo mode uses an authenticated local CLI
first, then a stored credential. Team mode uses the workstream owner's stored
credential for the target repository's host; it never falls back to the server's
CLI account. Store credentials with hashd forge login --host <host> or in the
web's Settings > Forge panel. Stored credentials remain encrypted and are
never returned by the listing API. Bitbucket and Gitea PR operations currently
use local CLI authentication in solo mode; stored-token PR authentication for
those providers is not supported.
Minimum agent/tool versions verified for this release:
| Tool | Minimum | Notes |
|---|---|---|
| Claude Code | 2.1.220 | required - the default agent for every stage |
| Codex CLI | 0.145.0 | optional - swap in per stage if you want it |
| uv | 0.11+ | |
| Go | 1.26+ |
Run hashd doctor to check your setup.
All project configuration lives in a single config.yaml per project. Generated by hashd project add or hashd project interview. You can also edit it manually. See config.sample.yaml for all available settings with documentation.
# --- Project Identity ---
name: "myproject"
repo_path: "/path/to/repo"
default_branch: "main"
reqs_path: "REQS.md"
spec_path: "SPEC.md"
# --- Build & Test ---
test_cmd: "make test" # impl-phase tests; falls through to merge_gate_test_cmd if empty
build_cmd: ""
merge_gate_test_cmd: "make test" # merge-time tests; the visible failure surface
test_timeout: 300
merge_mode: "local" # "local" or "pr"
forge: "" # auto-detected from remote; "github", "bitbucket", "gitlab", "gitea"
# Build artifacts written into the TRACKED tree that must never land on a
# branch (compiler doc output, say). The merge-gate heal still proves the
# build owns each one -- a path it does not own blocks as before -- and then
# discards it instead of committing it, so the gate proceeds and nothing
# enters git. Project scope only: the right answer differs per repository.
# merge_gate_discard_paths:
# - "Docs/Api.xml"
# --- Autonomy ---
autonomy: "gatekeeper" # "supervised", "gatekeeper", or "autonomous"
# --- Optional Overrides ---
# workflow:
# max_review_attempts: 5
# stages:
# implement:
# timeout: 2400Run hashd doctor --show-defaults to see all available settings and their default values.
Run hashd doctor --reset-to-defaults to strip behavioral overrides and restore defaults while preserving identity and build settings.
Use hashd config ... for system-wide overrides and hashd project config ... for project overrides. list shows the effective config and marks overridden values on TTYs, diff shows only overrides with their baseline values, and show <key> prints the effective value plus its Default/System/Project provenance. reset --all clears all overrides at the invoked scope. Shell completion includes config verbs and schema-backed key names.
Each project (or each repo, in multi-repo mode) has two test command fields:
test_cmd— runs during implementation, before review and commit.merge_gate_test_cmd— runs at merge time, before changes land. Final validation.
Set either command to run the same tests at both gates: each falls back to the other when unset.
Set test_cmd explicitly only when you want a faster subset for per-commit feedback (e.g. test_cmd: "pytest -m fast" and merge_gate_test_cmd: "pytest" for fast-vs-full split).
For per-commit checks scoped to what the branch changed, set the project-level
fast_test_cmd. hashd runs it in place of the full per-commit test command and
hands it the files the branch touched against its merge base: HASHD_TOUCHED_FILES
names a file listing them one per line. Mapping files to tests is the command's
job. gates.commit_check chooses the per-commit check: fast runs
fast_test_cmd, full runs the full test command, and unset runs fast_test_cmd
when one is set. Push and merge gates still run the full suite.
This repository ships scripts/ci-fast.sh as its fast check. It selects the Go
packages, pytest suites and shell tests the touched files reach, and runs the
full suite through scripts/ci-local.sh for any file it cannot attribute.
Enable it on a project with:
hashd project config set fast_test_cmd scripts/ci-fast.sh
hashd project config set gates.commit_check fasttests_skipped: true skips both test gates, even with a command configured.
With both commands empty and no opt-out, implementation skips tests but merge
is blocked. A configured build_cmd still runs before implementation tests;
tests_skipped is not a build opt-out.
Configure with:
hashd project repo edit <repo-name> --test-cmd "..." --merge-gate-test-cmd "..."Setup and teardown commands run automatically during workstream lifecycle:
hooks:
setup: "npm install && cp ../.env .env"
teardown: "docker-compose -p hashd-${HASHD_WORKSTREAM_ID} down"
timeout_seconds: 600 # default: 300 (5 min)- setup runs in the worktree after creation, before baseline tests. Failure records
provision_errorand keeps the workstream atprovisioning;runtime_statusreportsprovisioning / failed. Retry by re-dispatching withhashd run(the next provisioning attempt clearsprovision_erroron success). - teardown runs in the worktree before removal (close, merge, workstream remove). Failure is logged but doesn't block cleanup.
- timeout_seconds applies to both hooks. Hooks killed after the timeout get an actionable diagnostic pointing at the config key.
Hook subprocesses inherit the full parent environment plus these HASHD_* context variables:
| Variable | Description |
|---|---|
HASHD_PROJECT_NAME |
Project name |
HASHD_WORKSTREAM_ID |
Workstream identifier |
HASHD_STORY_ID |
Story ID (e.g., STORY-0042) |
HASHD_WORKTREE_PATH |
Path to git worktree |
HASHD_BASE_BRANCH |
Default branch (e.g., main) |
See docs/HOOKS.md for the full reference -- lifecycle details, more examples, the REST call flow, and troubleshooting recipes are in docs/TROUBLESHOOTING.md#workspace-hook-failures.
hashd supports projects that span multiple git repositories (e.g., a Go backend + React frontend in separate repos). The principle: project-level planning, repo-level execution.
Supported shapes:
- Single repo: one Git repo, including monorepos for now.
- Multi-repo container: a non-repo directory containing child Git repos;
hashd project addcan initialize a local-only control repo at the container root. - Superproject: a parent Git repo with submodules; treated as a multi-repo variant.
Directory layout:
platform/ # project root (git repo, may be local-only)
REQS.md # requirements live here
backend/ # sub-repo (its own git history + remote)
SPEC.md
go.mod
frontend/ # sub-repo (its own git history + remote)
SPEC.md
package.json
Setup: hashd project add /path/to/platform detects whether the path is a single repo, a multi-repo container, or a superproject and then prompts for the right setup flow. For agent-driven onboarding, the canonical pattern is hashd project add /path --no-interview --suggest followed by hashd project add /path --no-interview; see QUICKSTART.md for the full two-flag walkthrough. Use --primary <repo> to pin the primary sub-repo, --active <repo> (repeatable) or --all-active to mark non-primary repos active, --repo-skip-test <repo> to explicitly acknowledge a repo with no test command, and --repo-skip-build <repo> to explicitly acknowledge a repo with no build command. For container bootstrap, root-level files are committed into the local control repo by default; root-level directories require an explicit --commit-root-dirs in non-interactive mode. Each registered repo gets its own test command, build command, merge mode, default branch, and status.
Config: project-level settings live in config.yaml; per-repo state for multi-repo projects lives in SQLite project_repos, not in a repos: block in YAML.
Repo management after setup: use hashd project repo list, hashd project repo show <name>, hashd project repo add <path> --status <status>, hashd project repo set-status <name> <status>, hashd project repo edit <name> ..., hashd project repo set-path <name> <new-path>, hashd project repo remove <name>, and hashd project repo prune.
How it works:
- During planning, stories are automatically routed to the correct repo based on content
- Each workstream targets one repo -- worktrees, branches, and merges happen in that repo
- REQS.md stays at the project root; SPEC.md is per-repo
- Inspect or edit the configured REQS and SPEC paths with
hashd project reqsandhashd project spec; the server applies those paths and commits successful manual edits hashd run,hashd merge,hashd watchall work the same -- they resolve the target repo automatically
When you run hashd project add or hashd project interview, the CLI detects your build system (Makefile, Taskfile, package.json, etc.) and prompts you to confirm or customize the commands:
Detected: Taskfile
Test command: task test
Build command: task build
Test command [task test]:
Build command (optional, press Enter to skip) [task build]:
Merge gate test command [task test]:
The server runs exactly what you configure:
- BUILD_CMD (if set) - runs before tests
- TEST_CMD - runs the test suite
If your project uses code generation (sqlc, templ, protobuf, OpenAPI, etc.), your build and test commands must trigger generation first. Wire generation as a dependency in your build system:
Taskfile:
tasks:
generate:
cmds:
- sqlc generate
- templ generate
build:
deps: [generate]
cmds:
- go build ./...
test:
deps: [generate]
cmds:
- go test ./...Then enter task build and task test when prompted.
Makefile:
.PHONY: generate build test
generate:
sqlc generate
templ generate
build: generate
go build ./...
test: generate
go test ./...Then enter make build and make test when prompted.
npm (package.json):
{
"scripts": {
"generate": "openapi-generator generate -i spec.yaml -o src/api",
"prebuild": "npm run generate",
"build": "tsc",
"pretest": "npm run generate",
"test": "jest"
}
}Then enter npm run build and npm test when prompted.
The key is ensuring generated code exists before compilation, whether it's a fresh worktree or an existing checkout.
Autonomy is configured per-project via hashd project interview or directly in config.yaml:
| Mode | Behavior |
|---|---|
| supervised | Human approves at each gate |
| gatekeeper (default) | Auto-continue if AI confidence >= 90%; human decides final-review concerns and merge |
| autonomous | Auto-continue commits; human decides final-review concerns; no local-merge confirmation |
Each micro-commit, including an authorized FIX, gets up to five implement/test/review
attempts (workflow.max_review_attempts). Retrying does not add another FIX.
Final-review concerns require an operator decision before a new FIX is added.
Completing a run does not itself dispatch a merge.
Override per-run: hashd run --supervised, hashd run --gatekeeper, or hashd run --autonomous
# In config.yaml
autonomy: "gatekeeper"
modes:
gatekeeper:
commit_threshold: 0.85 # Override default 0.90When using the PR workflow (hashd merge --pr or merge_mode: pr), PRs may become conflicting if main moves ahead. The merge command handles this automatically:
- Fetches latest main
- Attempts rebase of the PR branch
- Force-pushes rebased branch (using
--force-with-lease) - Re-checks PR status
If rebase fails due to merge conflicts, blocks for human resolution with instructions.
| Risk | Mitigation |
|---|---|
| Force push loses work | --force-with-lease prevents overwriting if branch changed |
| Infinite rebase loop | Max 3 attempts before blocking for human |
| Forge API timing | 2s delay after push; worst case run hashd merge again |
| Review bypass | Checks for REVIEW_REQUIRED status from forge |
The merge respects the forge's configured review requirements:
- APPROVED - Merge proceeds
- PENDING/None - Merge proceeds (assumes no review required)
- CHANGES_REQUESTED - Blocks; use
hashd rejectto generate fix commit from PR feedback - REVIEW_REQUIRED - Blocks until required reviews complete
- success - Merge proceeds
- pending - Merge proceeds (for slow bots like CodeRabbit)
- failure - Blocks until checks pass
Hashd supports seven CLI coding agents. Any agent can be assigned to any workflow stage, as long as it supports the stage's required invocation shape.
| Agent | Binary | Status | Shapes | Install | Auth |
|---|---|---|---|---|---|
| Claude Code | claude |
active | print, json, edit, review, review_resume, implement, implement_resume | npm i -g @anthropic-ai/claude-code |
Anthropic API key |
| Codex | codex |
active | print, json, edit, review, review_resume, implement, implement_resume | npm i -g @openai/codex |
OpenAI API key |
| GitHub Copilot | copilot |
available | print, json, edit, review, review_resume, implement, implement_resume | npm i -g @github/copilot |
GitHub Copilot subscription |
| Gemini CLI | gemini |
available | print, json, edit, review, review_resume, implement, implement_resume | npm i -g @google/gemini-cli |
Google account (free) |
| OpenCode | opencode |
available | print, json, review, review_resume, implement, implement_resume | npm install -g opencode-ai |
Depends on model |
| Kimi Code | kimi |
available | print, json, edit, review, review_resume, implement, implement_resume | uv tool install kimi-cli |
Moonshot (~$19/mo) |
| Qwen Code | qwen |
available | print, json, edit, review, review_resume, implement, implement_resume | npm i -g @qwen-code/qwen-code |
Qwen OAuth (free) |
Status: active = tested and verified. available = config defined, not yet verified (assign with --force).
By default, Claude handles every stage -- planning, implementation, and review. Any supported agent can be swapped in per stage.
hashd agents # See installed agents and credential health
hashd agents --suggest # Scan agents and apply a default for all stages
hashd config stages-use codex # Use one agent for every stage system-wide
hashd project config set coder codex # Use Codex for implementation (this project)
hashd project config set planner gemini # Planning stages (see the agent guide for each role)
hashd project config set stage.review gemini # Single stage overrideSee the agent guide for stage definitions and live assignments. Resume stages inherit their base stage's agent.
Command templates support these variables:
| Variable | Description | Used In |
|---|---|---|
{prompt} |
The prompt text | All stages |
{worktree} |
Path to git worktree | implement, implement_resume |
{session_id} |
Session UUID for resuming | review_resume, implement_resume |
If {prompt} is in the command template, it's passed as a CLI argument. Otherwise, the prompt is passed via stdin (useful for multi-line prompts).
If a required tool isn't installed, hashd will fail early with a clear error:
ERROR: Required tool 'codex' is not installed.
Stages that need it: implement, implement_resume
To fix this, either:
1. Install codex: npm i -g @openai/codex
2. Add stage overrides to config.yaml in your project directory:
...
See docs/AGENT_MANAGEMENT.md for agent switching, prompt management, and per-project overrides.
Hashd works without a git remote configured. When no origin remote exists:
- Rebase checks are skipped (no fetch/rebase against remote main)
- Conflict detection against remote is skipped
- PR features are unavailable
- Workstreams complete locally after tests pass
This is useful for:
- Local experimentation before pushing
- Air-gapped development environments
- Learning hashd without setting up a remote
To enable full features later:
git remote add origin <url>Connectors are hashd's plugin system for external integrations. They're auto-discovered at startup from packages that register the hashd.connectors entry point group. Install or remove a connector package and core keeps working without hard references.
| Connector | What it does | CLI | Docs |
|---|---|---|---|
| GitHub | Resolve GitHub issue references -- @github:42 in stories, ACs, chat |
hashd github setup, hashd github status |
docs |
| Jira | Resolve Jira issue references -- @jira:PROJ-123 in stories, ACs, chat |
hashd jira setup, hashd jira status |
docs |
| Confluence | Read Cloud page artifacts -- @confluence:123456 in reference-enabled inputs |
None; existing project configuration editors | docs |
| Azure | Read Azure DevOps Services work items -- @azure:123 and shared reference search |
None; existing project configuration editors | docs |
| ClickUp | Read ClickUp tasks -- @clickup:86a4xte6z and shared browsing of one configured List |
None; existing project configuration editors | docs |
| Figma | Import and reference Figma designs -- @figma:frame in stories, ACs, chat |
hashd figma connect, hashd figma list, hashd figma import, hashd figma show, hashd figma status, hashd figma sync, hashd figma profile |
docs |
The GitHub and Jira connectors are reference resolvers: they read issue details on demand, cache them, and unfold the reference into agent context. Neither creates hashd stories, creates upstream issues, nor runs a background sync daemon.
None yet. If you build a connector for Linear, Shortcut, or another tool, open a PR or publish it as a pip package with an hashd.connectors entry point.
See docs/TROUBLESHOOTING.md for common issues: baseline test failures, stale flows, worktree cleanup, and missing tools.
BSL 1.1 (Business Source License)
See LICENSE for details.