Files
handler/.env.example
T
0xWheatyz 6fb26115ce feat(phase-2): forge integration — credentials, role skills, approval gate, CI poller
Phase 2 configures forge for the agents (operator only sets a credential_ref +
optional version pin) and lets them drive a junior→senior→deploy workflow:

- Credential resolution/injection (control/credentials.py): credential_ref pointers
  (env:/file:/cmd:) resolved only at spawn, injected as FORGE_TOKEN + host var, with a
  forge-host-scoped git credential helper reading the token from env (never on disk / in
  the DB). Resolution is a fail-fast spawn gate.
- Role-based forge skills committed into the managed repo (control/skills_gen.py,
  `handler forge-init`): forge-junior/senior/deploy + a workflow overview.
- Hard approval gate (hooks/gate.py, approvals table, migration 0002): merge/deploy —
  and direct pushes to protected branches — are denied unless a DIFFERENT agent has an
  `approved` record for the branch, pinned to the reviewed commit (approved_sha). Senior
  records verdicts via `handler approve`/`reject`.
- forge/git seams (control/forge.py, control/gitops.py) matching the Phase 1 seam pattern.
- CI status poller (control/poller.py, `handler poll-ci [--watch]`) backfilling
  ci_status/ci_checked_at via `forge ci list`.
- Fix: migrations/env.py commits explicitly after run_migrations — pysqlite on Py 3.12+
  was rolling back the final migration's DDL + alembic_version stamp (latent in Phase 1).

Reviewed via a separate code-reviewer pass; gate-bypass and credential-scoping findings
addressed. 106 tests, ruff clean, verified end-to-end against real git + migrations.
2026-07-08 22:05:49 -04:00

43 lines
2.0 KiB
Bash

# Handler configuration — copy to .env and fill in. Never commit real secrets.
# Database. SQLite fallback (single-node) or Postgres (centralized, default for real deploys).
# SQLite: sqlite:////absolute/path/to/handler.db
# Postgres: postgresql+psycopg://user:pass@host:5432/handler
DATABASE_URL=sqlite:////var/lib/handler/handler.db
# Single global bearer token gating every API route. Required for the API to start.
AUTH_TOKEN=change-me-to-a-long-random-string
# Optional higher-trust token gating PUT /shared/context/:key.
# Falls back to AUTH_TOKEN if unset.
# SHARED_CONTEXT_WRITE_TOKEN=
# Optional generic webhook target for the Notification hook (ntfy, Pushover, Slack, ...).
# Fully bring-your-own; the Notification hook is a no-op when unset.
# WEBHOOK_URL=https://ntfy.sh/my-topic
# Base directory under which per-project roots and agent worktrees live (isolation).
PROJECTS_ROOT=/var/lib/handler/projects
# Binary overrides (defaults shown). Point at fakes in tests/CI.
# CLAUDE_BIN=claude
# MISE_BIN=mise
# TMUX_BIN=tmux
# FORGE_BIN=forge
# GIT_BIN=git
# Phase 2 (forge integration). Pin the forge version your base image installs; spawn
# verifies the injected forge matches and warns on drift. Leave unset to skip the check.
# FORGE_VERSION=1.2.3
# Branches a direct `git push` may not reach without a standing approval (comma-separated).
# Closes the "merge locally, push to main" path around the forge-merge approval gate.
# PROTECTED_BRANCHES=main,master
# Per-project credentials are NOT set here — they live on each project's `credential_ref`
# as a POINTER (env:VAR / file:/path / cmd:...), resolved and injected only at spawn.
# The database never stores the raw token. Example, when registering a project:
# credential_ref = "env:LEEWORKS_TOKEN" (then export LEEWORKS_TOKEN where the control
# layer runs; it's injected as FORGE_TOKEN +
# the host-specific var, e.g. GITHUB_TOKEN)