Thank you for your interest in contributing to bd! This document provides guidelines and instructions for contributing.
- Go (see
go.modfor the required version; currently 1.26+) - Git
- A C compiler (CGO is required for the embedded Dolt database)
- (Optional) golangci-lint for local linting
- ICU headers are not required for building -- see engdocs/ICU-POLICY.md
# Clone the repository
git clone https://github.com/gastownhall/beads
cd beads
# Build the project (uses gms_pure_go tag via Makefile)
make build
# Run tests (uses correct build tags automatically)
make test
# Build and install locally to ~/.local/bin
make installbeads/
├── cmd/bd/ # CLI entry point and commands
├── internal/
│ ├── types/ # Core data types (Issue, Dependency, etc.)
│ └── storage/ # Storage interface and implementations
│ └── dolt/ # Dolt database backend
├── .golangci.yml # Linter configuration
└── .github/workflows/ # CI/CD pipelines
# Run all tests (recommended — uses correct build tags)
make test
# Run tests with coverage
go test -tags gms_pure_go -v -coverprofile=coverage.out ./...
go tool cover -html=coverage.out
# Run specific package tests
go test -tags gms_pure_go ./internal/storage/dolt/ -v
# Run tests with race detection
go test -tags gms_pure_go -race ./...We follow standard Go conventions:
- Use
gofmtto format your code (runs automatically in most editors) - Follow the Effective Go guidelines
- Keep functions small and focused
- Write clear, descriptive variable names
- Add comments for exported functions and types
We use golangci-lint for code quality checks:
# Install golangci-lint
brew install golangci-lint # macOS
# or
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
# Run linter
golangci-lint run ./...Note: The linter currently reports ~100 warnings. These are documented false positives and idiomatic Go patterns (deferred cleanup, Cobra interface requirements, etc.). See engdocs/LINTING.md for details. When contributing, focus on avoiding new issues rather than the baseline warnings.
CI will automatically run linting on all pull requests.
Before adding new feature surface area, read engdocs/PROJECT_CHARTER.md. Beads owns issue tracking primitives. It should not encode orchestration-layer policy, become a storage engine, or expand the database schema when issue metadata is sufficient.
- Fork the repository
- Create a feature branch (
git checkout -b feature/my-feature) - Make your changes
- Add tests for new functionality
- Run tests and linter locally
- Commit your changes with clear messages
- Push to your fork
- Open a pull request
Write clear, concise commit messages:
Add cycle detection for dependency graphs
- Implement recursive CTE-based cycle detection
- Add tests for simple and complex cycles
- Update documentation with examples
One issue per PR, and one PR per issue. No piggybacking or riders — each PR should address exactly one thing.
- Keep PRs focused on a single feature or fix
- Do not include unrelated changes, cleanup, or "while I'm here" improvements
- Do not include
.beads/data (database, JSONL) in your PR - Make sure there are no extra generated or garbage files in your diff
- Include tests for new functionality
- Update documentation as needed
- Ensure CI passes before requesting review
- Respond to review feedback promptly
- Lead the PR with a brief plain-language
WhatandWhyso reviewers can grasp the goal without reading the diff..github/PULL_REQUEST_TEMPLATE.mdis a starting scaffold — replace, expand, or delete sections to fit your change.
If you are contributing code that involves AI decision-making or orchestration, understand and follow the ZFC principles. In short: keep the smarts in the AI models, keep the code as dumb orchestration. Do not add heuristics, keyword matching, ranking logic, or semantic analysis in application code — delegate cognitive decisions to AI.
For how to run tests, see engdocs/TESTING.md. For what to test and why (the test pyramid and tiering we follow), see engdocs/TESTING_PHILOSOPHY.md.
- Run
make test(or./scripts/test.sh) locally and make sure it passes. - Add tests for new functionality; extend existing tests when fixing bugs.
- Write table-driven tests for multiple scenarios, use descriptive test
names, use
t.Run()for subtests, and clean up resources (database files, etc.) in test teardown. - If you hit a test failure unrelated to your change, don't silently skip
it -- check
.test-skipand file an issue if it's not already tracked (see engdocs/TESTING.md). - Ensure CI passes (
make ci-pr-core,make ci-pr-policy,make ci-pr-lint) before requesting review. - If your change touches ICU or build tags, see engdocs/ICU-POLICY.md for the policy and rationale.
- Update README.md for user-facing changes
- Update relevant .md files in the project root
- Add inline code comments for complex logic
- Include examples in documentation
Include in your bug report:
- Steps to reproduce
- Expected behavior
- Actual behavior
- Version of bd (
bd versionif implemented) - Operating system and Go version
When proposing new features:
- Explain the use case
- Describe the proposed solution
- Consider backwards compatibility
- Discuss alternatives you've considered
This project uses AI agents for maintenance. We've established strict rules to protect contributor work:
- Your PR has priority. If you've submitted a PR, agents must review and build on your work — not rewrite it from scratch.
- Your tests matter. Agents must preserve contributor tests unless they're actually wrong.
- You'll get attribution. Your commits and
Co-authored-by:will be preserved. - No silent closes. Your PR will never be auto-closed by a parallel rewrite. If changes are needed, they'll be discussed on your PR.
If any of this goes wrong, please open an issue — we take contributor experience seriously.
Maintainers and agents follow PR_MAINTAINER_GUIDELINES.md when triaging, landing, transforming, or closing PRs.
Before starting a rewrite, cleanup, or large refactoring pass, maintainers and agents must review open contributor PRs that touch the same area. Use this checklist to decide whether to merge, rebase, incorporate, or close each PR.
-
Identify overlap:
- Read the PR description, changed files, linked issues, and latest review comments.
- Compare the PR scope with the planned refactor and note any shared files, commands, migrations, tests, docs, or release paths.
- If the PR is unrelated, leave it alone unless the refactor would still create a merge conflict.
-
Prefer clean merges:
- If the PR is focused, passing CI, and aligned with current design, review it as the first option.
- Merge it before the refactor when that reduces conflict risk.
- Preserve the contributor's commits and attribution unless the contributor agrees to a squash or rework.
-
Request a rebase when needed:
- Ask for a rebase if the PR is still valid but conflicts with main or depends on code that has moved.
- Give concrete instructions about the new target files or APIs.
- Do not rewrite the same work in parallel while waiting unless there is a release blocker or security issue.
-
Preserve tests and intent:
- Treat contributor tests as part of the contribution, not optional scaffolding.
- If a refactor supersedes implementation code, port the tests or explain why they are invalid.
- Keep user-facing behavior, docs examples, and regression coverage intact unless the PR is explicitly changing the contract.
-
Close superseded PRs with explicit rationale:
- Close only after commenting with the replacement commit, PR, or issue.
- Explain what was preserved, what changed, and why the original branch will not be merged.
- Thank the contributor and invite follow-up if their use case was not fully covered.
-
Leave an audit trail:
- Link the intake decision from the refactor PR or Beads issue.
- Record any follow-up work as Beads issues instead of hidden notes.
- Call out contributor-owned tests or behavior in the refactor PR summary.
All contributions go through code review:
- Automated checks (tests, linting) must pass
- At least one maintainer approval required
- Address review feedback
- Maintainer will merge when ready
# Build and install your changes
make install
# Test specific functionality
bd init --prefix test
bd create "Test issue" -p 1 -t bug
bd dep add test-2 test-1
bd ready# Inspect the Dolt database directly
bd query "SELECT * FROM issues"
bd query "SELECT * FROM dependencies"
bd query "SELECT * FROM events WHERE issue_id = 'test-1'"The flake.lock file pins a specific nixpkgs revision. When go.mod bumps the Go version beyond what's in the pinned nixpkgs, the Nix CI job will fail. To update flake.lock without installing nix locally, use Docker:
# Update flake.lock
docker run --rm -v $(pwd):/workspace -w /workspace nixos/nix \
sh -c 'echo "experimental-features = nix-command flakes" >> /etc/nix/nix.conf && nix flake update'
# Verify the build works
docker run --rm -v $(pwd):/workspace -w /workspace nixos/nix \
sh -c 'echo "experimental-features = nix-command flakes" >> /etc/nix/nix.conf && nix build .#default && ./result/bin/bd version'If the build fails with a vendorHash mismatch, run ./scripts/update-nix-vendorhash.sh to recompute and update default.nix, or update it manually with the got: hash from the error message and rebuild.
The nix build CI job (.github/workflows/nix-build.yml) runs on any PR that touches go.mod, go.sum, default.nix, flake.nix, or flake.lock, so dependabot bumps that invalidate vendorHash fail loudly instead of silently breaking Nix users on main. For dependabot Go-module bumps specifically, .github/workflows/update-vendor-hash.yml runs the same update-nix-vendorhash.sh script and pushes the hash bump back to the dependabot branch automatically (note: GitHub does not retrigger pull_request workflows for GITHUB_TOKEN-authored commits, so a maintainer may need to re-run nix build .#default once after the auto-fix push to mark the gate green).
Use Go's built-in debugging tools:
# Run with verbose logging
go run ./cmd/bd -v create "Test"
# Use delve for debugging
dlv debug ./cmd/bd -- create "Test issue"(For maintainers)
- Update version in code
- Update CHANGELOG.md
- Tag release:
git tag v0.x.0 - Push tag:
git push origin v0.x.0 - GitHub Actions will build and publish
By contributing, you agree that your contributions will be licensed under the MIT License.
Be respectful and professional in all interactions. We're here to build something great together.
Thank you for contributing to bd! 🎉