GuideDevelopment Guide

Development Guide

Complete developer documentation for contributing to Agor.

Quick Setup

Fastest way to start developing:

git clone https://github.com/preset-io/agor
cd agor
docker compose up
# Visit http://localhost:5173 → Login: admin@agor.live / admin

Pros:

  • ✅ No Node.js/pnpm installation required
  • ✅ Consistent environment across team
  • ✅ Easy to run multiple instances on different branches
  • ✅ Supports both SQLite (default) and PostgreSQL databases

Cons:

  • ❌ Docker-in-docker complexity if your worktree environments use Docker (e.g., docker compose up in environment configs)

Database Modes

Agor supports both SQLite (default) and PostgreSQL databases in Docker.

SQLite mode (default):

docker compose up
# Uses SQLite database at ~/.agor/agor.db (inside container)
# Perfect for single-user development

PostgreSQL mode:

# Single command - auto-starts postgres container
docker compose --env-file .env.postgres up
 
# Alternative: Copy env file for simpler workflow
cp .env.postgres .env
docker compose up  # Now defaults to PostgreSQL
 
# Switch back to SQLite
rm .env
docker compose up

What happens in PostgreSQL mode:

  • Postgres container starts automatically (via COMPOSE_PROFILES=postgres in .env.postgres)
  • Agor connects to postgresql://agor:agor_dev_secret@postgres:5432/agor
  • Database runs in a Docker volume (persisted across restarts)
  • Great for testing multi-user scenarios or production-like setups

Check which database you’re using:

Open Settings → About tab (admin only) to see:

  • 💾 SQLite - Shows database file path
  • 🐘 PostgreSQL - Shows connection URL (password masked)

Git Commits in Docker:

When using Docker, pnpm install installs Linux binaries (e.g., turbo-linux-arm64, eslint-linux), which won’t run on your host OS. If you commit from your host machine, pre-commit hooks will fail because Husky tries to execute these Linux binaries.

Two solutions:

  1. Commit inside the container (Recommended)

    docker compose exec agor-dev git add .
    docker compose exec agor-dev git commit -m "your message"

    Hooks run inside the container with correct Linux binaries.

  2. Reinstall node_modules on host

    pnpm install  # Get host-specific binaries (macOS/Windows)
    git commit -m "your message"  # Hooks use host binaries

    Note: This means you’ll have both host and Linux binaries in node_modules.

Running multiple instances in parallel:

If you’re developing across multiple branches, run each with unique ports:

# Main branch
cd ~/code/agor
docker compose up  # :3030 (daemon), :5173 (UI)
 
# Feature branch 1
cd ~/code/agor-feature-auth
PORT=4030 VITE_PORT=5174 docker compose -p agor-feature-auth up
 
# Feature branch 2
cd ~/code/agor-feature-payments
PORT=5030 VITE_PORT=5175 docker compose -p agor-feature-payments up

The -p flag ensures isolated volumes and no container naming conflicts.

Local Development with pnpm (For Environment Testing)

Use this if you’re working on:

  • Environment management (process spawning, health checks, port allocation)
  • Testing environments that use Docker (avoids docker-in-docker complexity)
  • Faster iteration with instant HMR/hot-reload

Setup:

git clone https://github.com/preset-io/agor
cd agor
pnpm install

Two-process workflow:

# Terminal 1: Daemon (watches @agor/core + daemon, auto-restarts)
cd apps/agor-daemon
pnpm dev
 
# Terminal 2: UI dev server (Vite HMR for instant updates)
cd apps/agor-ui
pnpm dev
 
# Visit http://localhost:5173

Why local for testing Environment features?

The Environment system spawns processes defined in your repo’s environment config (e.g., pnpm dev, docker compose up, etc.). If your environment commands use Docker, running Agor itself in Docker requires docker-in-docker setup. Local development avoids this complexity.

Project Structure

agor/
├── apps/
│   ├── agor-daemon/         # FeathersJS backend (REST + WebSocket)
│   ├── agor-cli/            # CLI tool (oclif-based)
│   ├── agor-ui/             # React UI (Ant Design + React Flow)
│   └── agor-docs/           # Documentation website (Nextra)
├── packages/
│   ├── core/                # Shared @agor/core package
│   │   ├── types/           # TypeScript types (Session, Task, Worktree, etc.)
│   │   ├── db/              # Drizzle ORM + repositories + schema
│   │   ├── git/             # Git utils (simple-git only, no subprocess)
│   │   ├── claude/          # Claude Code session loading utilities
│   │   └── api/             # FeathersJS client utilities
│   └── agor-live/           # Published npm package
└── context/                 # 📚 Architecture documentation (READ THIS!)
    ├── concepts/            # Core design docs
    └── explorations/        # Experimental designs

Monorepo & Development Tooling

Agor is a pnpm workspace monorepo with several automation tools:

pnpm Workspaces

Structure:

# pnpm-workspace.yaml
packages:
  - 'apps/*'
  - 'packages/*'

Workspace protocol:

  • Packages reference each other via workspace:*
  • Example: @agor/cli depends on @agor/core@workspace:*
  • pnpm symlinks workspace packages (no need to rebuild on every change)

Turbo

Parallel builds and task orchestration:

# Build all packages in dependency order
pnpm build
 
# Run typecheck across all packages in parallel
pnpm typecheck
 
# Run dev servers (daemon + UI)
pnpm dev

How it works:

  • Reads turbo.json for task definitions
  • Understands package dependencies
  • Runs tasks in parallel when possible
  • Caches build outputs for speed

Git Hooks (Husky + lint-staged)

Pre-commit checks:

  • Runs automatically before git commit
  • Only checks staged files (fast!)
  • Runs: biome (linting), prettier (formatting), typecheck

Setup:

pnpm prepare  # Installs git hooks

Code Quality

Linting:

  • biome - Fast linter and formatter
  • Config: biome.json
  • Run: pnpm lint or pnpm lint:fix

Formatting:

  • prettier - Code formatter
  • Config: .prettierrc
  • Run: pnpm format

Root Scripts

Common commands from root directory:

# Development
pnpm dev              # Start daemon + UI
pnpm docs:dev         # Start docs site
 
# Code quality
pnpm typecheck        # Type check all packages
pnpm lint             # Lint all packages
pnpm lint:fix         # Lint and auto-fix
pnpm format           # Format all files
pnpm check            # typecheck + lint + build
pnpm check:fix        # lint:fix + typecheck + build
 
# Building
pnpm build            # Build all packages
pnpm clean            # Clean all build artifacts
 
# CLI (from root)
pnpm agor <command>   # Run CLI without global install

Tech Stack

See the Architecture Guide for the complete tech stack (FeathersJS, Drizzle, React, Ant Design, etc.).

Development Patterns

Code Standards

  1. Type-driven - Use branded types for IDs, strict TypeScript
  2. Centralize types - ALWAYS import from packages/core/src/types/ (never redefine)
  3. Read before edit - Always read files before modifying
  4. Prefer Edit over Write - Modify existing files when possible
  5. Git operations - ALWAYS use simple-git (NEVER subprocess execSync, spawn, etc.)
  6. Error handling - Clean user-facing errors, no stacktraces in CLI

Important Rules

Git Library:

  • ✅ Use simple-git for ALL git operations
  • ❌ NEVER use execSync, spawn, or bash for git commands
  • Location: packages/core/src/git/index.ts

Watch Mode:

  • User runs pnpm dev in daemon (watches core + daemon)
  • DO NOT run builds unless explicitly asked or you see compilation errors
  • DO NOT start background processes

Type Reuse:

  • Import types from packages/core/src/types/
  • Sessions, Tasks, Worktrees, Messages, Repos, Boards, Users, etc.
  • Never redefine canonical types

Worktree-Centric Architecture:

  • Boards display Worktrees as primary cards (NOT Sessions)
  • Sessions reference worktrees via required FK
  • Read context/concepts/worktrees.md before touching boards

Key Documentation

Before diving into code, familiarize yourself with the architecture:

Testing

Database Operations

SQLite:

# Query database directly
sqlite3 ~/.agor/agor.db "SELECT COUNT(*) FROM messages"
sqlite3 ~/.agor/agor.db "SELECT * FROM sessions LIMIT 5"

PostgreSQL:

# Connect to postgres container
docker compose exec postgres psql -U agor -d agor
 
# Example queries
docker compose exec postgres psql -U agor -d agor -c "SELECT COUNT(*) FROM messages"
docker compose exec postgres psql -U agor -d agor -c "SELECT * FROM sessions LIMIT 5"

Health Checks

# Daemon health
curl http://localhost:3030/health
 
# Check which database is active (admin auth required)
curl -H "Authorization: Bearer YOUR_JWT_TOKEN" http://localhost:3030/health

CLI Commands

# Test CLI (ensure clean exit, no hanging)
pnpm agor session list
pnpm agor repo list
 
# CLI auto-detects database from environment
# Works with both SQLite and PostgreSQL

Troubleshooting

”Method is not a function” after editing @agor/core

Should NOT happen with new 2-process workflow (daemon watches core and auto-restarts).

If it still happens:

cd packages/core && pnpm build
cd apps/agor-daemon && pnpm dev

tsx watch not picking up changes

cd apps/agor-daemon
rm -rf node_modules/.tsx
pnpm dev

Daemon hanging

lsof -ti:3030 | xargs kill -9
cd apps/agor-daemon && pnpm dev

What to Contribute

Browse the roadmap issues for contribution ideas, or propose your own!

Next Steps

  • Architecture - System design and internals
  • Run agor --help for complete CLI documentation
  • API Reference - REST endpoints and WebSocket events
  • AGENTS.md - Development patterns and project structure
BSL 1.1 © 2025 Maxime Beauchemin