Thank you for your interest in contributing to ThreeDoors! This guide will help you get started.
ThreeDoors uses a solo maintainer + AI agent team development model. The human maintainer (arcaven) directs a team of AI agents that handle most implementation work. All PRs are reviewed by the maintainer before merge.
You don't need to use AI agents to contribute — just follow this guide and submit a PR like any other open-source project.
All work is story-driven. Every code change should have a corresponding story file in docs/stories/. If you're working on something new, create a story file as part of your PR. See existing story files for the format.
- Go 1.25.4+ — install
- make — for build commands
- gofumpt —
go install mvdan.cc/gofumpt@latest(stricter than gofmt) - golangci-lint — install
git clone https://github.com/arcavenae/ThreeDoors.git
cd ThreeDoors
make build # Build the binary
make test # Run tests
make lint # Run linter (must pass with zero warnings)
make fmt # Format code with gofumptOpen a Bug Report and include:
- ThreeDoors version (
threedoors --version) - Operating system
- Steps to reproduce
- Expected vs actual behavior
Open a Feature Request.
Please read SOUL.md first. ThreeDoors is opinionated by design — "three doors, not three hundred." Features that add complexity need strong justification. Features that conflict with the project philosophy will be declined.
- Fork the repo and create a feature branch (
git checkout -b feat/your-feature) - Ensure a story file exists in
docs/stories/(or create one as part of your PR) - Write tests — table-driven, using stdlib
testingonly (no testify) - Run the full quality gate:
make fmt make lint make test - Run the race detector for TUI or CLI changes:
go test -race ./internal/tui/... ./internal/cli/... - Create a PR using the PR template
- Update your story file status to
Done (PR #NNN)
feat|fix|docs|refactor: description (Story X.Y)
Examples:
feat: add keyboard shortcut display (Story 39.1)fix: prevent crash on empty task file (Story 12.3)docs: update installation guide (Story 0.43)
ThreeDoors follows strict Go coding standards. Key rules:
- Formatting: gofumpt (not gofmt) — run
make fmt - Linting: golangci-lint with zero warnings — run
make lint - Testing: Table-driven tests using stdlib
testing. Uset.Helper(),t.Cleanup(), andt.Parallel()where appropriate. - Errors: Always handle errors. Wrap with
%wfor context. Define sentinel errors as package-level vars. - Context:
context.Contextis always the first parameter. - Timestamps: Always use
time.Now().UTC(). - No
init()functions — pass dependencies explicitly. - No panics in user-facing code — Bubbletea
Update()andView()must never panic.
See the "Go Quality Rules" section in CLAUDE.md for the complete list.
- Features that conflict with SOUL.md philosophy (local-first, privacy-always, minimal complexity)
- Heavy dependencies — prefer the standard library
- Telemetry, analytics, or phone-home features
- Testify or other test framework dependencies
- Cloud sync or account features (unless the user explicitly opts in)
cmd/threedoors/ # Entry point (main.go)
internal/tasks/ # Task domain: models, providers, persistence, analytics
internal/tui/ # Bubbletea views and UI components
docs/ # Architecture docs, stories, PRD
The key abstraction is the TaskProvider interface (internal/tasks/provider.go). New storage backends are added by implementing this interface.
- TUI framework: Bubbletea + Lipgloss + Bubbles
- Data format: YAML task files, JSONL session logs
- All TUI output goes through Bubbletea
View()methods — neverfmt.Println - File persistence uses atomic writes (write to
.tmp, sync, rename)
ThreeDoors is MIT licensed. By contributing, you agree that your contributions will be licensed under the same license.