Local development setup¶
This page covers running the bot on your laptop against a real GitHub App. For first-time GitHub App creation, see github-app.md. For production deployment, see deployment.md.
Prerequisites¶
| Tool | Version | Purpose |
|---|---|---|
| Bun | from .tool-versions (currently 1.3.14) |
Runtime and package manager. |
| Git | any | Repository checkout during agent execution. |
| Docker | any recent | Local Postgres + Valkey via docker-compose.dev.yml. |
| GitHub account | none | Admin access to the org or personal account where the App is registered. |
| Webhook relay | none | A smee.io channel to relay GitHub webhook deliveries to your local server. |
| AI provider credentials | none | One of: Anthropic API key, Claude Code OAuth token, AWS credentials for Bedrock. |
First run¶
git clone https://github.com/chrisleekr/github-app-playground.git
cd github-app-playground
bun install
# Start Postgres + Valkey in the background
bun run dev:deps
# Copy and fill .env
cp .env.example .env
# Edit .env: see configuration.md for every variable.
# Run database migrations
bun run db:migrate
# Run in watch mode
bun run dev
The HTTP server binds to PORT (default 3000). Hit http://localhost:3000/healthz to confirm it's up; http://localhost:3000/readyz confirms the data layer is reachable.
Relay webhooks to your local server¶
GitHub delivers webhooks to a public smee.io channel URL (not to your laptop directly); a local client subscribes to that channel and relays each delivery to your server, so no inbound tunnel is needed.
- Create a channel at smee.io and copy its URL.
- Put it in the GitHub App's webhook URL field, and set
SMEE_URL=https://smee.io/<your-channel>in.env. - Run the relay:
# Wrapped script: forwards SMEE_URL -> http://localhost:$PORT/api/github/webhooks (PORT default 3000).
# Override the whole target with SMEE_TARGET in .env.
bun run dev:smee
The local trigger phrase is conventionally @chrisleekr-bot-dev (set TRIGGER_PHRASE in .env) so the dev installation does not collide with the production bot's mention.
Common dev commands¶
bun run dev # Watch mode
bun run start # Production binary (after bun run build)
bun run build # Compile to dist/
bun run check # Unified gate: typecheck + lint + format + tests + no-destructive
bun run typecheck # tsc --noEmit
bun run lint # ESLint
bun run lint:fix # ESLint auto-fix
bun run format # Prettier check
bun run format:fix # Prettier auto-fix
bun test # Run tests via scripts/test-isolated.sh (Bun mock isolation)
bun run test:fast # Direct bun test (no isolation)
bun run test:watch # Watch mode
bun run test:coverage # With coverage report
bun run audit:ci # Severity-gated bun audit (used by CI)
bun run db:migrate # Run migrations against DATABASE_URL
bun run dev:deps # Up Postgres + Valkey
bun run dev:deps:down # Tear down
bun run dev:daemon # Run a daemon locally against the running orchestrator
bun run docs:install # Install MkDocs Python deps (one-time)
bun run docs:serve # Live-reload preview at http://localhost:8000
bun run docs:build # Strict build (CI also runs this)
bun run check is the single command to run before opening a PR.
Running a daemon locally¶
The webhook server embeds an orchestrator that talks to daemons over WebSocket. To exercise the full pipeline locally:
# Terminal 1: orchestrator (webhook server)
bun run dev
# Terminal 2: local daemon
bun run dev:daemon
The daemon connects back to ws://localhost:3002 (WS_PORT) using DAEMON_AUTH_TOKEN from .env. From there, every @chrisleekr-bot-dev mention exercises the full webhook → orchestrator → daemon → pipeline path.
Testing webhook delivery¶
- Open an issue or PR in a repository where your dev App is installed.
- Comment
@chrisleekr-bot-dev triage this. - The bot creates a tracking comment within ~2 s.
If nothing happens, check:
| Symptom | Likely cause |
|---|---|
| 401 / 403 in tunnel logs | GITHUB_WEBHOOK_SECRET mismatch with the App settings (no trailing newline). |
| 200 OK but no comment | ALLOWED_OWNERS excludes the repo owner; or MAX_CONCURRENT_REQUESTS is saturated. |
GITHUB_APP_PRIVATE_KEY parse error |
Set the full PEM including -----BEGIN… / -----END… lines (literal \n is normalised). |
ANTHROPIC_API_KEY is required |
CLAUDE_PROVIDER defaults to anthropic; set the key or switch to bedrock. |
| Bot mention ignored locally | TRIGGER_PHRASE is unchanged from the default @chrisleekr-bot; the dev App expects @chrisleekr-bot-dev. |