Contributing
Thanks for your interest in contributing to Warden! This guide covers everything you need to get started.
Finding something to work on
Section titled “Finding something to work on”- Good first issues are labeled
good first issueon GitHub. - Feature requests and bugs are tracked in GitHub Issues. Comment on an issue to claim it before starting work.
- If you have an idea that isn’t tracked yet, open an issue first to discuss the approach.
Prerequisites
Section titled “Prerequisites”- Go 1.26+
- Node.js 24+
- Docker (for running containers locally)
- Dev Container CLI (for E2E tests)
- just (optional task runner — see
justfilefor available recipes)
git clone https://github.com/thesimonho/warden.gitcd wardengo mod downloadnpm --prefix web installStart the dev servers (Go + Vite):
just devOpen http://localhost:5173 (Vite proxies /api/* to Go on :8090).
Database isolation
Section titled “Database isolation”The dev server uses a separate database (/tmp/warden-dev/warden.db) so development and testing don’t interfere with your production Warden data at ~/.config/warden/. E2E tests use their own database at /tmp/warden-e2e-db/.
| Environment | DB location | Port |
|---|---|---|
Production (warden-desktop) | ~/.config/warden/ | :8090 |
Development (just dev) | /tmp/warden-dev/ | :8090 |
| E2E tests (standalone) | /tmp/warden-e2e-db/ | :8090 |
| E2E tests (piggybacking) | Same as dev server | Dev server port |
Note: dev and production both use :8090, so they cannot run simultaneously. If you need to use Warden as a user, stop the dev server first.
E2E tests will piggyback on a running dev server if one is available, otherwise they start their own. Test projects are cleaned up automatically after each run.
Local container image
Section titled “Local container image”The container image is built on CI when changes to container/ are pushed to main. For faster iteration during development, build the image locally:
docker build -t ghcr.io/thesimonho/warden:latest ./containerNew containers created from the dashboard will use the locally built image. Existing containers need to be recreated to pick up the changes.
Testing
Section titled “Testing”go test ./... # Go unit testsnpm --prefix web run test # Frontend unit tests (Vitest)npm --prefix web run typecheck # TypeScript type checkingnpm --prefix web run test:e2e # E2E tests (Playwright)Run a single test:
go test ./engine/ -run TestParseGitWorktreeList # Single Go testnpm --prefix web run test -- --run lib/cost.test.ts # Single frontend testnpm --prefix web run test:e2e -- --grep "should connect terminal" # Single E2E testCode quality checks
Section titled “Code quality checks”Run these before submitting a PR:
# Gogolangci-lint run ./... # Linting
# Frontendnpm --prefix web run format # Prettier formattingnpm --prefix web run lint # ESLintnpm --prefix web run typecheck # TypeScript type checkingGo formatting is handled automatically by gofmt via gopls.
Architecture
Section titled “Architecture”For architecture diagrams, project structure, and how the engine, API, and clients fit together, see the Architecture page.
Key directories for contributors:
| Directory | What lives here |
|---|---|
engine/ | Container engine API wrapper (Docker) |
service/ | Business logic layer |
api/ | API contract types (request/response structs) |
db/ | SQLite database store |
eventbus/ | File-based event system (watcher, SSE broker) |
agent/ | Multi-agent abstraction (registry, parsers, status providers) |
internal/server/ | HTTP server, API routes, middleware |
internal/terminal/ | WebSocket-to-PTY proxy |
web/ | React + Vite frontend |
container/ | Project container image and devcontainer feature |
For detailed code maps, see docs/developer/codemaps/README.md for an index of all maps.
Key architectural rules
Section titled “Key architectural rules”These rules are important to follow when contributing:
- The web SPA must only use HTTP calls to
/api/v1/*— it serves as a reference implementation for developers building their own frontends. - The TUI must be written against a
Clientinterface — satisfiable by both the embedded service and the HTTP client. - API routes include agentType as a path segment — all project-scoped routes follow the pattern
/api/v1/projects/{projectId}/{agentType}/...to enforce the compound primary key (projectID + agentType). - New API types go in
api/— shared byservice/,client/, and the TUI. internal/packages stay internal —server/andterminal/are HTTP plumbing, not public API.- All audit writes go through
db.AuditWriter— never calldb.Store.Write()directly for audit events. - PRs touching
agent/should include tests for both parsers — Claude Code and Codex each have their own JSONL parser inagent/claudecode/andagent/codex/. Changes to shared parsing logic must be validated against both. - Agent CLIs are installed at container startup, not in the image —
install-agent.shinstalls the correct CLI using pinned versions fromagent/versions.go. Agent-specific event scripts live incontainer/scripts/claude/andcontainer/scripts/codex/.
Submitting a pull request
Section titled “Submitting a pull request”Branch strategy
Section titled “Branch strategy”Trunk-based. Branch off main for features/fixes, PR back in when ready. Squash merged to main.
Merges to main trigger release-please PR and changelog generation. Merging the release-please PR cuts a release and triggers builds/deployments/tags.
PR checklist
Section titled “PR checklist”Before opening a PR:
- Code compiles and passes all tests (
go test ./...,npm --prefix web run test) - Frontend type checks pass (
npm --prefix web run typecheck) - Linting passes (
golangci-lint run ./...,npm --prefix web run lint) - Frontend code is formatted (
npm --prefix web run format) - New API endpoints have OpenAPI annotations (see
internal/server/routes.go) - Documentation is updated if behavior changed
Commit messages
Section titled “Commit messages”Use Conventional Commits:
feat: add cost export to CSVfix: resolve WebSocket reconnection racerefactor: extract symlink resolver from enginedocs: update integration guide for Go clienttest: add E2E tests for worktree lifecycleYour PR will be checked by these workflows:
| Workflow | Trigger | What it does |
|---|---|---|
ci.yml | PRs targeting main | Go tests, TS typecheck, TS tests |
release-please.yml | Push to main | Automated release creation and version tagging |
release-build.yml | Release published, or manual dispatch | Cross-platform builds, installers (DMG/deb/rpm/Arch/AppImage/Inno Setup), checksums, SBOM |
container.yml | Push to main (container/**), release | Build container image + devcontainer feature (:latest on push, semver on release) |
container-scheduled.yml | Daily schedule (5 AM UTC) | Validates container image, builds CLIs, validates JSONL parsers, pushes only on success |
| Layer | Technology |
|---|---|
| Backend | Go (net/http), Docker Engine API |
| Frontend | React 19, Vite 7, TypeScript |
| UI | shadcn/ui, Tailwind CSS v4 |
| Terminal | xterm.js via WebSocket to Go proxy |
| Container | Ubuntu 24.04, tmux, Claude Code CLI, Codex CLI |
| Dev tools | just (task runner) |
More resources
Section titled “More resources”- Architecture — system diagrams, communication pathways, and data flow funnels
- Integration Paths — how the engine, API, and clients fit together
- HTTP API Reference — all API endpoints
- Go Package Reference — Go package documentation