AGENT_INSTRUCTIONS.md
For project overview and quick start, see AGENTS.md
This document contains detailed operational instructions for AI agents working on beads development, testing, and releases.
golangci-lint run ./... (baseline warnings documented in docs/LINTING.md)make test for the normal local/CI path, make test-icu-path only when intentionally exercising the opt-in ICU regex path)beads/
├── cmd/bd/ # CLI commands
├── internal/
│ ├── types/ # Core data types
│ └── storage/ # Storage layer
│ └── dolt/ # Dolt implementation
├── examples/ # Integration examples
└── *.md # Documentation
IMPORTANT: Never pollute the production database with test issues!
For manual testing, use the BEADS_DB environment variable to point to a temporary database:
# Create test issues in isolated database
BEADS_DB=/tmp/test.db bd init --quiet --prefix test
BEADS_DB=/tmp/test.db bd create "Test issue" -p 1
# Or for quick testing
BEADS_DB=/tmp/test.db bd create "Test feature" -p 1
For automated tests, use t.TempDir() in Go tests:
func TestMyFeature(t *testing.T) {
tmpDir := t.TempDir()
testDB := filepath.Join(tmpDir, ".beads", "beads.db")
s := newTestStore(t, testDB)
// ... test code
}
Git test isolation: For tests that create temporary git repos, force repo-local hooks:
git config core.hooksPath .git/hooks
Do not rely on the developer's global git config. Global core.hooksPath can leak
into temp repos and produce flaky test behavior.
Warning: bd will warn you when creating issues with "Test" prefix in the production database. Always use BEADS_DB for manual testing.
make test (or ./scripts/test.sh)
make test-icu-pathgolangci-lint run ./... (ignore baseline warnings)bd hooks install), Dolt changes are auto-committedWhen committing work for an issue, include the issue ID in parentheses at the end:
git commit -m "Fix auth validation bug (bd-abc)"
git commit -m "Add retry logic for database locks (bd-xyz)"
This enables bd doctor to detect orphaned issues - work that was committed but the issue wasn't closed. The doctor check cross-references open issues against git history to find these orphans.
bd uses Dolt as its primary database. Changes are committed to Dolt history automatically (one Dolt commit per write command).
Install git hooks for automatic sync:
bd hooks install
Dolt sync: Dolt handles sync natively via bd dolt push / bd dolt pull. No JSONL export/import needed.
Protected branches: Dolt stores data under refs/dolt/data, separate from standard Git refs. See docs/PROTECTED_BRANCHES.md.
Git worktrees: Work directly with Dolt — no special flags needed. See docs/ADVANCED.md.
Merge conflicts: Rare with hash IDs. Dolt uses cell-level 3-way merge for conflict resolution.
Crew workers use a PR-based workflow. Beads is a dependency of Gas City, so we defer to the standard PR flow to keep changes reviewable.
maingh pr create is the normal path to land workRead CONTRIBUTING.md — it contains promises we've made to contributors. Violating them damages trust and community.
Run the read-only preflight before implementing related work, opening a PR, or merging/closing a PR:
scripts/pr-preflight.sh --search "<topic keywords>" --repo gastownhall/beads
scripts/pr-preflight.sh <pr-number> --repo gastownhall/beads
Before implementing any feature or fix, check for existing open PRs on the same topic:
gh pr list --repo gastownhall/beads --state open --search "<topic keywords>" --json number,title,author,headRefName
Contributor work gets priority. If an external PR already exists:
Co-authored-by: in commits, reference their PR numberIf you must rewrite (e.g., fundamentally different approach needed), explain why on the original PR and credit the contributor's design/tests in your commits.
Do not rely on auto-discovery of CONTRIBUTING.md; the preflight is the agent gate for PR handling.
When the user says "let's land the plane", you MUST complete ALL steps below. The plane is NOT landed until git push succeeds. NEVER stop before pushing. NEVER say "ready to push when you are!" - that is a FAILURE.
MANDATORY WORKFLOW - COMPLETE ALL STEPS:
File beads issues for any remaining work that needs follow-up
Ensure all quality gates pass (only if code changes were made):
make lint or golangci-lint run ./... (if pre-commit installed: pre-commit run --all-files)make test (and make test-icu-path only if you intentionally need the ICU regex path)Update beads issues - close finished work, update status
PUSH TO REMOTE - NON-NEGOTIABLE - This step is MANDATORY. Execute ALL commands below:
# Pull first to catch any remote changes
git pull --rebase
# MANDATORY: Push everything to remote
# DO NOT STOP BEFORE THIS COMMAND COMPLETES
git push
# MANDATORY: Verify push succeeded
git status # MUST show "up to date with origin/main"
CRITICAL RULES:
git push completes successfullygit push - that leaves work stranded locallygit push fails, resolve the issue and retry until it succeedsClean up git state - Clear old stashes and prune dead remote branches:
git stash clear # Remove old stashes
git remote prune origin # Clean up deleted remote branches
Verify clean state - Ensure all changes are committed AND PUSHED, no untracked files remain
Choose a follow-up issue for next session
REMEMBER: Landing the plane means EVERYTHING is pushed to remote. No exceptions. No "ready when you are". PUSH IT.
Example "land the plane" session:
# 1. File remaining work
bd create "Add integration tests for sync" -t task -p 2 --json
# 2. Run quality gates (only if code changes were made)
go test -short ./...
golangci-lint run ./...
# 3. Close finished issues
bd close bd-42 bd-43 --reason "Completed" --json
# 4. PUSH TO REMOTE - MANDATORY, NO STOPPING BEFORE THIS IS DONE
git pull --rebase
git push # MANDATORY - THE PLANE IS STILL IN THE AIR UNTIL THIS SUCCEEDS
git status # MUST verify "up to date with origin/main"
# 5. Clean up git state
git stash clear
git remote prune origin
# 6. Verify everything is clean and pushed
git status
# 7. Choose next work
bd ready --json
bd show bd-44 --json
Then provide the user with:
CRITICAL: Never end a "land the plane" session without successfully pushing. The user is coordinating multiple agents and unpushed work causes severe rebase conflicts.
WARNING: DO NOT use bd edit - it opens an interactive editor ($EDITOR) which AI agents cannot use. Use bd update with flags instead:
bd update <id> --description "new description"
bd update <id> --title "new title"
bd update <id> --design "design notes"
bd update <id> --notes "additional notes"
bd update <id> --acceptance "acceptance criteria"
Use stdin for descriptions with special characters (backticks, !, nested quotes):
# Pipe via stdin to avoid shell escaping issues
echo 'Description with `backticks` and "quotes"' | bd create "Title" --stdin
echo 'Updated description with $variables' | bd update <id> --description=-
# Or use --body-file for longer content
bd create "Title" --body-file=description.md
Example agent session:
# Make changes (each write auto-commits to Dolt)
bd create "Fix bug" -p 1
bd create "Add tests" -p 1
bd update bd-42 --claim
bd close bd-40 --reason "Completed"
# Push Dolt data to remote if configured
bd dolt push
# Now safe to end session
This installs:
Note: Hooks are embedded in the bd binary and work for all bd users (not just source repo users).
Minimize cognitive overload. Every new command, flag, or option adds cognitive burden for users. Before adding anything:
Recovery/fix operations → bd doctor --fix: Don't create separate commands like bd recover or bd repair. Doctor already detects problems - let --fix handle remediation. This keeps all health-related operations in one discoverable place.
For git hook marker migration specifically: use bd migrate hooks --dry-run to preview operations, and bd doctor --fix for the standard apply path.
Prefer flags on existing commands: Before creating a new command, ask: "Can this be a flag on an existing command?" Example: bd list --stale instead of bd stale.
Consolidate related operations: Related operations should live together. Version control uses bd vc {log,diff,commit}, not separate top-level commands.
Count the commands: Run bd --help and count. If we're approaching 30+ commands, we have a discoverability problem. Consider subcommand grouping.
New commands need strong justification: A new command should represent a fundamentally different operation, not just a convenience wrapper.
cmd/bd/cmd/bd/main.go--json flag for agent usecmd/bd/*_test.gointernal/storage/dolt/internal/types/types.go if new typesinternal/storage/dolt/ (queries, issues, etc.)cmd/bd/export.go and cmd/bd/import.goexamples/examples/README.md# Build and install bd to ~/.local/bin (the canonical location)
make install
# Test (local baseline)
make test
# Optional ICU regex path smoke (maintainer-only, not normal validation)
make test-icu-path
# Coverage run
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out
# Verify installed binary
bd init --prefix test
bd create "Test issue" -p 1
bd ready
WARNING: Do NOT use
go build -o bd ./cmd/bd,go install ./cmd/bd, or rawgo run ./cmd/bd .... These bypass the canonical build path, can create stale binaries in the working directory or~/go/bin/, and rawgo runmay miss the requiredgms_pure_gobuild tag. Always usemake install,./bd, orgo run -tags gms_pure_go ./cmd/bd ...when you explicitly needgo run.
IMPORTANT: When the user asks to "bump the version" or mentions a new version number (e.g., "bump to 0.9.3"), use the version bump script:
# Preview changes (shows diff, doesn't commit)
./scripts/bump-version.sh 0.9.3
# Auto-commit the version bump
./scripts/bump-version.sh 0.9.3 --commit
git push origin main
What it does:
User will typically say:
You should:
./scripts/bump-version.sh <version> --commitFiles updated automatically:
cmd/bd/version.go - CLI versionclaude-plugin/.claude-plugin/plugin.json - Plugin version.claude-plugin/marketplace.json - Marketplace versionintegrations/beads-mcp/pyproject.toml - MCP server versionREADME.md - Documentation versionPLUGIN.md - Version requirementsWhy this matters: We had version mismatches (bd-66) when only version.go was updated. This script prevents that by updating all components atomically.
See scripts/README.md for more details.
Automated (Recommended):
# One command to do everything (version bump, tests, tag, Homebrew update, local install)
./scripts/release.sh 0.9.3
This handles the entire release workflow automatically, including waiting ~5 minutes for GitHub Actions to build release artifacts. See scripts/README.md for details.
Manual (Step-by-Step):
./scripts/bump-version.sh <version> --commitmake test (and make test-icu-path only if you intentionally need the ICU regex path)git push origin maingit tag v<version> && git push origin v<version>./scripts/update-homebrew.sh <version> (waits for GitHub Actions)brew update && brew upgrade beads && bd versionSee docs/RELEASING.md for complete manual instructions.
IMPORTANT: When asked to check GitHub issues or PRs, use command-line tools like gh instead of browser/playwright tools.
Preferred approach:
# List open issues with details
gh issue list --limit 30
# List open PRs
gh pr list --limit 30
# View specific issue
gh issue view 201
Then provide an in-conversation summary highlighting:
Why this matters:
Do NOT use: browser_navigate, browser_snapshot, or other playwright tools for GitHub PR/issue reviews unless specifically requested by the user.
bd listgit log --oneline -20bd create "Question: ..." -t task -p 2