Autonomous AI coding loop CLI. Feed it a PRD, and it implements each user story one iteration at a time using AI coding agents.
"I'm sorry Dave, I'm afraid I can't do that... without a proper PRD."
- PRD-driven development — Generate, convert, and validate Product Requirements Documents
- Autonomous execution — Each iteration picks the next story, implements it, commits, and updates progress
- Fresh context per iteration — Every story gets a clean context window, no memory pollution
- Pluggable engines — Works with Claude Code, OpenAI Codex, or Pi
- Project standards — Codify patterns into standards that are injected into every agent iteration
- Archive & restore — Switch between features without losing state
- Compound pipeline — Full automation from analysis to pull request
brew tap j-yw/tap
brew install --cask halgit clone https://github.com/j-yw/hal.git
cd hal
make install # Installs to ~/.local/bin- Go 1.25.7+ (for building from source)
- One of the following AI coding agents:
- Codex CLI (default engine)
- Claude Code CLI
- Pi CLI
# Initialize project
hal init
# Generate a PRD interactively
hal plan "add user authentication"
# Convert markdown PRD to JSON (auto-picks .hal/prd-*.md)
hal convert
# Validate the PRD
hal validate
# Run the autonomous loop
hal runhal init → hal plan → hal convert → hal validate → hal run
- init — Set up
.hal/directory with config, templates, skills, and commands - plan — Generate a PRD through clarifying questions
- convert — Transform markdown PRD to structured JSON (default no archive; use
--archive/--forcefor guarded canonical overwrites) - validate — Check stories against quality rules
- run — Loop through stories: pick next, implement, commit, repeat
hal report → hal auto → hal report → hal auto → ...
The compound pipeline creates a continuous development cycle:
-
hal report— Runs legacy session reporting (the behavior that previously lived underhal review). It analyzes completed work and generates a report with recommendations for next steps. Saves to.hal/reports/and updatesAGENTS.mdwith discovered patterns. -
hal auto— Reads the latest report, identifies the priority item, and runs the full pipeline:- Analyze → Branch → PRD → Explode → Loop → PR
-
Repeat — After the PR merges, run
hal reportagain to generate the next report.
For iterative branch-vs-branch review/fix loops, use:
hal review --base <base-branch> [iterations]
hal review --base <base-branch> --iterations <n> -e codexGetting started: Run the manual workflow first (hal plan → hal run), then hal report to generate your first report. Or place a report directly in .hal/reports/.
State is saved after each step — use hal auto --resume to continue from interruptions.
The old hal review reporting workflow moved to hal report.
- Use
hal reportfor legacy session reporting and report generation. - Use
hal review --base <base-branch> [iterations]for the new iterative review/fix loop (select engine with-e). hal review against <base-branch> [iterations]remains as a deprecated alias.hal explode --branch <name>is long-only (-bremoved) and sets output PRDbranchName.- Deprecation timeline: deprecated in
v0.2.0, removed inv1.0.0.
Generated CLI command reference docs are available in docs/cli/ with the main entry page at docs/cli/hal.md.
Stable JSON contracts for agent integration:
docs/contracts/status-v1.md— Workflow state machinedocs/contracts/doctor-v1.md— Health/readiness checksdocs/contracts/continue-v1.md— What to do next
| Command | Description |
|---|---|
hal init |
Initialize .hal/ directory with config, skills, and commands |
hal plan [description] |
Generate PRD (opens editor if no args) |
hal convert [markdown-prd] |
Convert markdown PRD to JSON (auto-discover source when omitted) |
hal validate [prd.json] |
Validate PRD against quality rules |
hal prd audit [--json] |
Audit PRD health and detect markdown↔JSON drift |
hal run [iterations] |
Execute stories autonomously (default: 10; do not combine positional iterations with -i/--iterations) |
| Command | Description |
|---|---|
hal status [--json] |
Show workflow state (manual, compound, review-loop) |
hal doctor [--json] |
Check environment health (engine-aware, detects broken links) |
hal continue [--json] |
Show what to do next (combines status + doctor) |
hal repair [--dry-run] [--json] |
Auto-fix safe issues detected by doctor |
| Command | Description |
|---|---|
hal links status [--json] |
Inspect engine skill links (per-engine health) |
hal links refresh [engine] |
Recreate skill links for all or specific engine |
| Command | Description |
|---|---|
hal report |
Generate summary report → .hal/reports/, update AGENTS.md |
hal review --base <base-branch> [iterations] |
Iterative review/fix loop against a base branch (use -e; do not combine positional iterations with -i/--iterations) |
hal auto |
Run full pipeline using latest report |
hal analyze [report] --format text|json |
Analyze a report to find priority item (--output is deprecated) |
hal explode <prd.md> --branch <name> |
Break PRD into 8-15 granular tasks and set output PRD branchName |
| Command | Description |
|---|---|
hal standards list |
List configured standards with index |
hal standards discover |
Guide for discovering standards interactively |
| Command | Description |
|---|---|
hal archive |
Archive current feature state (alias of hal archive create) |
hal archive create |
Archive current feature state explicitly |
hal archive list |
List all archived features (--name/-n is invalid here) |
hal archive restore <name> |
Restore an archived feature (--name/-n is invalid here) |
Archive contract details:
hal archiveis the create alias--name/-nis only valid forhal archiveandhal archive create- If no name is provided and stdin is non-interactive, the command fails and asks for
--name/-n
| Command | Description |
|---|---|
hal config |
Show current configuration |
hal config add-rule <name> |
Create a custom rule template (deprecated in v0.2.0, removed in v1.0.0; use standards workflow) |
hal cleanup |
Remove orphaned legacy files (supports --dry-run) |
hal version |
Show version information |
hal analyze --format text
hal analyze --format json
hal analyze --output json # deprecated in v0.2.0, removed in v1.0.0--output/-o and --format/-f cannot be used together.
hal uses one template snapshot contract:
- template snapshot name is fixed to
hal - template source is fixed to
sandbox/Dockerfilewith build context. hal sandbox start [-n NAME]always resolves snapshothal(reuse if active, create if missing)
hal sandbox snapshot create # create/reuse template snapshot "hal"
hal sandbox start -n my-box # start sandbox from template snapshot "hal"After changing sandbox/Dockerfile, refresh the template snapshot:
hal sandbox snapshot list
hal sandbox snapshot delete --id <hal-snapshot-id>
hal sandbox snapshot create--name/-n is available on:
hal sandbox starthal sandbox statushal sandbox stophal sandbox deletehal sandbox shellhal sandbox exec
For remote commands that start with flags, use --:
hal sandbox exec -n my-sandbox -- npm test
hal sandbox exec -- -n foo # passes '-n foo' to remote command unchangedhal planOpens your editor with a template. Write your feature spec, save, and quit. The AI will ask clarifying questions, then generate a complete PRD.
Editor resolution: $EDITOR → $VISUAL → nano → vim → vi
hal plan "add dark mode toggle to settings"Good for quick, well-defined features.
hal plan "notifications" # Outputs .hal/prd-notifications.md
hal plan "notifications" --format json # Outputs .hal/prd.json directlyhal convert now defaults to a non-destructive workflow and makes stateful behavior explicit.
hal convert(no args) scans.hal/prd-*.md, picks the newest file by modified time, and uses lexicographic filename ascending as the tie-break when mtimes are equal.hal convert <path>uses the explicit path as-is (and fails early if the file does not exist).- Once resolved, convert prints:
Using source: <path>.
- Default convert does not archive existing feature state.
--archivearchives existing feature state before writing canonical.hal/prd.json.--archiveis only supported when output is canonical.hal/prd.json(it is rejected with custom output paths).- Canonical writes are protected from accidental branch switches. If existing and incoming
branchNamevalues differ, convert stops with:branch changed from <old> to <new>; run 'hal convert --archive' or 'hal archive' first, or use --force
- Use
--forceto bypass that branch-mismatch guard without creating an archive.
# Default no-archive conversion (auto-select markdown source)
hal convert
# Explicit markdown source (still no archive unless requested)
hal convert .hal/prd-authentication.md
# Explicit archive flow before canonical overwrite
hal convert --archive
# Override canonical branch mismatch guard without archiving
hal convert .hal/prd-authentication.md --force
# Custom output path (archive disabled by design)
hal convert .hal/prd-authentication.md -o /tmp/prd.jsonhal run # Run 10 iterations (default)
hal run 5 # Run 5 iterations (positional)
hal run -i 5 # Run 5 iterations (flag)
hal run 1 -s US-001 # Run a specific story
hal run --base develop # Set base branch explicitly
hal run --timeout 30m # Raise the per-session engine timeout
hal run --dry-run # Preview without executing
hal run -e codex # Use Codex engine
hal run -e pi # Use Pi enginehal run [iterations] and hal run --iterations/-i <n> are mutually exclusive.
Each iteration:
- Reads
prd.jsonandprogress.txt - Loads project standards from
.hal/standards/and injects them into the prompt - Picks highest-priority incomplete story
- Spawns fresh engine instance
- Implements the story
- Commits changes
- Updates
prd.json(marks story complete) - Appends learnings to
progress.txt
Standards are concise, codebase-specific rules stored in .hal/standards/ as markdown files. They are automatically injected into the agent prompt on every hal run iteration, ensuring consistent code quality and pattern adherence across all AI-driven work.
hal initcreates.hal/standards/and installs discovery commands for all engines- Standards are
.mdfiles organized by domain (e.g.,config/,engine/,testing/) - On every
hal run, all.mdfiles are loaded, concatenated, and injected into the{{STANDARDS}}placeholder inprompt.md - The agent sees them as "## Project Standards — You MUST follow these..."
Standards discovery is interactive — it scans your codebase, identifies patterns, and walks through each one with you:
# See what's available
hal standards list
# Get instructions for your engine
hal standards discoverThe discovery commands are installed for all engines during hal init:
| Engine | Command |
|---|---|
| Claude Code | /hal/discover-standards |
| Pi | /hal/discover-standards |
| Codex | Ask agent to read .hal/commands/discover-standards.md |
# Init Idempotency
`hal init` is safe to run repeatedly. It never destroys existing state.
## Rules
- **Directories**: Use `os.MkdirAll` — idempotent by design
- **Default files**: Only write if file doesn't exist (`os.Stat` check first)
- **Skills**: Reinstalled every init (embedded files overwrite installed copies)
- **Template migrations**: Run every init via `migrateTemplates` (idempotent patches)
## Never Overwrite User Files
User customizations to `config.yaml`, `prompt.md`, and `progress.txt` are sacred.An optional index.yml catalogs all standards with descriptions:
config:
init-idempotency:
description: hal init never overwrites user files; uses MkdirAll and stat-before-write
template-constants:
description: All .hal/ paths defined in internal/template/template.go; never hardcode
engine:
process-isolation:
description: Setsid + process group kill for TTY detachment and orphan preventionStandards and commands in .hal/ are committed to git (not ignored), while runtime state (config.yaml, prd.json, progress.txt) stays ignored. This means your team shares the same standards and discovery commands across all clones.
{
"project": "MyProject",
"branchName": "hal/feature-name",
"description": "Feature description",
"userStories": [
{
"id": "US-001",
"title": "Add database schema",
"description": "As a developer, I want the schema defined...",
"acceptanceCriteria": [
"Migration creates users table",
"Typecheck passes"
],
"priority": 1,
"passes": false,
"notes": ""
}
]
}- Each story completable in one iteration (one context window)
- Ordered by dependency: schema → backend → frontend
- Every story includes "Typecheck passes" criterion
- UI stories include browser verification criteria
- Acceptance criteria are verifiable, not vague
.hal/ # Created by hal init
├── config.yaml # Engine, retries, auto settings (gitignored)
├── prompt.md # Agent instructions (gitignored, customizable)
├── progress.txt # Append-only progress log (gitignored)
├── prd.json # Current PRD (gitignored)
├── archive/ # Archived feature states
├── reports/ # Analysis reports for auto mode
├── skills/ # Installed skills (auto-generated)
│ ├── prd/ # PRD generation
│ ├── hal/ # PRD-to-JSON conversion
│ ├── explode/ # Task breakdown
│ ├── autospec/ # Non-interactive PRD generation
│ └── review/ # Work review and patterns
├── standards/ # Project standards (committed to git)
│ ├── index.yml # Standards catalog
│ ├── config/ # Config-related standards
│ ├── engine/ # Engine-related standards
│ ├── state/ # State management standards
│ └── testing/ # Testing standards
└── commands/ # Agent commands (committed to git)
├── discover-standards.md
├── index-standards.md
└── inject-standards.md
Engine-specific symlinks are created during hal init:
.claude/commands/hal→.hal/commands/.claude/skills/*→.hal/skills/*.pi/prompts/*.md→.hal/commands/*.md.pi/skills/*→.hal/skills/*~/.codex/commands/hal→.hal/commands/(absolute)~/.codex/skills/*→.hal/skills/*(absolute)
Edit .hal/config.yaml:
engine: codex # or claude, pi
maxIterations: 10
retryDelay: 30s
maxRetries: 3
auto:
reportsDir: .hal/reports
branchPrefix: compound/
maxIterations: 25
engines:
codex:
model: o3
timeout: 30m
pi:
model: anthropic/claude-sonnet-4-20250514
provider: openrouterUse a higher engines.codex.timeout when Codex sessions do long reasoning or large edits. You can also override it ad hoc with hal run --timeout 30m.
Note:
hal initpreserves existing.hal/config.yamlfiles. If your project was initialized earlier, it may still haveengine: claude. Update it toengine: codexif you want codex as the default runtime engine.
Engine resolution order:
- explicit
--engine(if provided) - top-level
enginein.hal/config.yaml - fallback to
codex
If an explicit --engine is blank (for example --engine " "), hal exits with a validation error.
Hal supports multiple AI coding agents:
| Engine | CLI Command | Install |
|---|---|---|
| Codex (default) | codex |
Codex repo |
| Claude | claude |
Claude Code docs |
| Pi | pi |
Pi repo |
Switch engines with -e:
hal run -e codex
hal run -e pimake build # Build binary with version metadata
make install # Install to ~/.local/bin
make test # Run tests
make vet # Run go vet
make fmt # Format code
make lint # Run golangci-lint (if installed)Hal release tags are standardized to vX.Y.Z (for example, v0.1.7).
# one-time per clone: ensure git-flow tags include "v" prefix
git config gitflow.prefix.versiontag v
# create and finish a release branch
git flow release start 0.1.7
git flow release finish -p 0.1.7Pushing a v* tag triggers .github/workflows/release.yml, which runs tests and publishes artifacts via GoReleaser.
The release workflow also requires a repository secret named HOMEBREW_TAP_TOKEN with write access to j-yw/homebrew-tap. The workflow validates that token before publishing so broken Homebrew credentials fail fast instead of leaving a partially successful release.
To rotate that secret from a local GitHub CLI session with access to the tap:
gh auth switch -u j-yw
gh auth token | gh secret set HOMEBREW_TAP_TOKEN --repo j-yw/hal