{"id":50117624,"url":"https://github.com/lee-to/aif-handoff","last_synced_at":"2026-05-23T16:02:54.716Z","repository":{"id":347793983,"uuid":"1195293326","full_name":"lee-to/aif-handoff","owner":"lee-to","description":"Autonomous Kanban board where AI agents plan, implement, and review your tasks — fully hands-off.","archived":false,"fork":false,"pushed_at":"2026-05-11T17:57:39.000Z","size":9814,"stargazers_count":211,"open_issues_count":13,"forks_count":28,"subscribers_count":9,"default_branch":"main","last_synced_at":"2026-05-11T19:33:50.407Z","etag":null,"topics":["ai","ai-factory","aif","handoff","harness","harness-engineering","sdd","spec-driven-development"],"latest_commit_sha":null,"homepage":"https://aif.cutcode.dev","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lee-to.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-03-29T13:46:50.000Z","updated_at":"2026-05-11T17:58:03.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/lee-to/aif-handoff","commit_stats":null,"previous_names":["lee-to/aif-handoff"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/lee-to/aif-handoff","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lee-to%2Faif-handoff","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lee-to%2Faif-handoff/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lee-to%2Faif-handoff/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lee-to%2Faif-handoff/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lee-to","download_url":"https://codeload.github.com/lee-to/aif-handoff/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lee-to%2Faif-handoff/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33402174,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-23T04:15:53.637Z","status":"ssl_error","status_checked_at":"2026-05-23T04:15:53.242Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","ai-factory","aif","handoff","harness","harness-engineering","sdd","spec-driven-development"],"created_at":"2026-05-23T16:02:54.144Z","updated_at":"2026-05-23T16:02:54.707Z","avatar_url":"https://github.com/lee-to.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![logo](https://github.com/lee-to/aif-handoff/blob/main/art/promo.jpg)\n\n# AIF Handoff\n\n\u003e Autonomous Kanban board where AI agents plan, implement, and review your tasks — fully hands-off.\n\n\u003e This project was built using [AI Factory](https://github.com/lee-to/ai-factory) — an open-source framework for AI-driven development.\n\nBuilt on top of [AI Factory](https://github.com/lee-to/ai-factory) workflow and powered by runtime profiles through `@aif/runtime` (Claude and Codex adapters included). Tasks flow through stages automatically: **Backlog → Planning → Plan Ready → Implementing → Review → Done** — each stage orchestrated by specialized AI subagents following the AIF methodology. In auto mode, review feedback can also trigger an automatic rework loop: **Review → request_changes → Implementing**. When that loop stops converging, the task is handed off explicitly as **Done + manual review required** instead of silently passing.\n\nAuto-review is now convergence-aware. You can keep the default `full_re_review` loop or switch to `closure_first` via `AGENT_AUTO_REVIEW_STRATEGY`. When auto-review no longer converges, the task moves to `done` with `manualReviewRequired=true`, and the UI surfaces that explicit human handoff instead of silently treating the review as passed.\n\n## Runtime Providers Out of the Box\n\nUse the runtime that fits your stack today, then switch per project/task without changing orchestration logic:\n\n- **Claude (`anthropic`)** — SDK, CLI, API transports\n- **Codex (`openai`)** — SDK, CLI, App Server, API transports\n- **OpenRouter (`openrouter`)** — API transport\n- **OpenCode (`opencode`)** — API transport\n\n\u003e **⚠️ Warning:** Anthropic prohibits using Claude Max / Pro subscriptions outside of the official Claude Code CLI. The SDK transport for Claude calls the Agent SDK directly, which may violate these terms. If you're worried about your subscription getting blocked, use the **CLI transport** — it runs through the official Claude Code CLI and is safe to use on a Max / Pro subscription. Use the SDK transport at your own risk, or switch to the API transport with an `ANTHROPIC_API_KEY` for production use.\n\nNeed something custom? Add your own runtime adapter module and load it at startup via `AIF_RUNTIME_MODULES` (comma-separated module specifiers). No fork required.\n\n## Key Features\n\n- **Fully autonomous pipeline** — create a task, AI plans, implements, and reviews it\n- **Beautiful Kanban UI** — drag-and-drop board with real-time WebSocket updates\n- **AI Factory core** — built on [ai-factory](https://github.com/lee-to/ai-factory) agent definitions and skill system\n- **Subagent orchestration** — plan-coordinator, implement-coordinator, review + security sidecars\n- **Runtime/provider modularity** — runtime registry, global/project/task runtime profile selection, and provider-specific capability gating\n- **Layer-aware execution** — implementer computes dependency layers and enforces parallel worker dispatch where possible\n- **Self-healing pipeline** — heartbeat + stale-stage watchdog auto-recovers stuck agent stages\n- **Human-in-the-loop** — approve plans, request changes, or let auto-mode handle everything\n- **MCP sync** — bidirectional task sync between Handoff and AIF tools via Model Context Protocol\n\n## Quick Start\n\n### Without Docker\n\n```bash\ngit clone https://github.com/lee-to/aif-handoff.git\ncd aif-handoff\nnpm install\nnpm run init\nnpm run dev\n```\n\nSet `MCP_PORT` in your shell or root `.env` before `npm run dev` if you also want the MCP HTTP server in local development. Use an integer port between `1` and `65535`; invalid values are ignored by the dev launcher and the settings install route falls back to the local `stdio` entry instead of writing an HTTP MCP endpoint.\n\n### With Docker\n\n```bash\ngit clone https://github.com/lee-to/aif-handoff.git\ncd aif-handoff\ndocker compose up --build\n```\n\nDevelopment starts three services by default. If `MCP_PORT` is set to a valid integer port, it starts a fourth service for MCP over HTTP. Docker starts all four services.\n\n| Service   | URL                               | Description                                  |\n| --------- | --------------------------------- | -------------------------------------------- |\n| **API**   | `http://localhost:3009`           | Hono REST + WebSocket server                 |\n| **Web**   | `http://localhost:5180`           | React Kanban UI                              |\n| **Agent** | _(background)_                    | Event-driven + polling, dispatches subagents |\n| **MCP**   | `http://localhost:\u003cMCP_PORT\u003e/mcp` | Optional local MCP HTTP endpoint             |\n\nThe agent coordinator reacts to task events via WebSocket in near real-time and falls back to 30-second polling. Activity logging can be switched to batch mode (`ACTIVITY_LOG_MODE=batch`) to reduce DB write amplification. See [Configuration](docs/configuration.md) for all tuning options.\n\n### Authentication\n\n- **Without Docker:** Claude runtime profiles can use `~/.claude/` credentials by default (your active Claude subscription). No API key needed.\n- **With Docker:** Either set `ANTHROPIC_API_KEY` in `.env`, or log in inside the container:\n  ```bash\n  docker compose exec agent claude login\n  docker compose restart\n  ```\n  Copy the URL and open it in your browser. **Important:** the terminal wraps long URLs across lines — remove any line breaks and spaces before pasting, otherwise OAuth will fail with `invalid code_challenge`. Then restart to apply. Credentials are stored in a persistent `claude-auth` Docker volume.\n\nFor Codex/OpenAI-compatible profiles, configure `OPENAI_API_KEY` and optionally `OPENAI_BASE_URL` (or set profile-level `apiKeyEnvVar` / `baseUrl`). For local Codex runs without API keys, prefer `transport: \"app-server\"` or `transport: \"cli\"` and authenticate via `codex login`. See [Providers](docs/providers.md).\n\n#### Codex OAuth in Docker (without `OPENAI_API_KEY`)\n\nThe dev compose wires up a small in-container broker that runs\n`codex login --device-auth` and exposes a guided UI in\n**Settings → Runtime profile → Codex**:\n\n1. Click **Start Codex login**. The broker spawns the CLI and reads back a\n   verification URL plus a one-time code.\n2. Open the verification page in your browser, enter the code, and complete\n   ChatGPT sign-in.\n3. The CLI exits 0 once ChatGPT confirms and writes `~/.codex/auth.json` to\n   the persistent `codex-auth` volume. The wizard flips to success\n   automatically (status polled every second).\n4. Run `docker compose restart agent` to pick up the credentials.\n\n**Production note:** the broker is **dev-only**. `docker-compose.production.yml`\nsets `AIF_ENABLE_CODEX_LOGIN_PROXY=false`. For production, configure\n`OPENAI_API_KEY` in `.env` instead.\n\n### Runtime Defaults\n\nRuntime profiles can now be managed at two scopes:\n\n- **Global profiles** live in Global Settings and can be reused across every project\n- **Project profiles** stay local to a single project\n\nEffective runtime resolution follows this order:\n\n1. task override\n2. project default\n3. app default\n4. environment fallback\n\nPlanning and review keep their own defaults, but when those are unset they inherit from the task default at the same scope. Chat has its own dedicated project/app default chain.\n\n### OpenCode Quick Setup\n\n1. Start OpenCode server (example with password):\n\n```bash\nOPENCODE_SERVER_PASSWORD='your-strong-password' opencode serve --hostname 127.0.0.1 --port 60661\n```\n\n2. Create/update runtime profile in AIF Handoff:\n\n- `runtimeId`: `opencode`\n- `providerId`: `opencode`\n- `baseUrl`: `http://127.0.0.1:60661`\n- `options.serverPassword`: same password as above\n- `defaultModel`: use exact value from `GET /config/providers`, for example `openrouter/anthropic/claude-sonnet-4.6`\n\n3. Validate profile connection in UI and use it for chat/task stages.\n\nFull OpenCode options and examples: [Providers](docs/providers.md#opencode-api).\n\n## Architecture\n\n```\npackages/\n├── shared/    # Types, schema, state machine, env, constants, logger\n├── runtime/   # Runtime registry, adapters, module loader, workflow specs\n├── data/      # Centralized DB access layer (@aif/data)\n├── api/       # Hono REST + WebSocket server (port 3009)\n├── web/       # React + Vite + TailwindCSS — Kanban UI (port 5180)\n└── agent/     # Coordinator (node-cron) + runtime-driven subagent orchestration\n```\n\nDatabase access is centralized in `packages/data`. `api` and `agent` must use `@aif/data`; direct DB imports in those packages are blocked by ESLint guards.\n\n### Agent Pipeline\n\nThe coordinator polls every 30 seconds and delegates to `.claude/agents/` definitions:\n\n| Stage                                                                                            | Agent                                                                     | What it does                                                                                                                                 |\n| ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |\n| Backlog → Planning → Plan Ready                                                                  | `plan-coordinator`                                                        | Iterative plan refinement via `plan-polisher`                                                                                                |\n| Plan Ready → Implementing → Review                                                               | `implement-coordinator`                                                   | Parallel task execution with worktrees + quality sidecars                                                                                    |\n| Review → Done / Review → request_changes → Implementing / Review → Done + manual review required | `review-sidecar` + `security-sidecar` (+ auto review gate in coordinator) | Code review and security audit in parallel; in auto mode, structured blocking findings drive rework until success or explicit manual handoff |\n\n### Auto-Review Convergence\n\n- `AGENT_AUTO_REVIEW_STRATEGY=full_re_review` keeps the broad re-review loop and is the default.\n- `AGENT_AUTO_REVIEW_STRATEGY=closure_first` only auto-reworks unresolved previous blockers; if new blockers appear after previous ones are resolved, the coordinator stops and asks for human review.\n- Hitting the review-iteration limit also stops automation at `done` with `manualReviewRequired=true`.\n\n### Fault Tolerance\n\n- Task liveness is tracked with `lastHeartbeatAt`.\n- If a stage (`planning`, `implementing`, `review`) stops heartbeating longer than timeout, coordinator moves task to `blocked_external` with retry backoff.\n- After max stale retries, task is quarantined for manual intervention.\n\nAll agents are loaded via `settingSources: [\"project\"]` from `.claude/agents/*.md` — the same agent definitions used by [AI Factory](https://github.com/lee-to/ai-factory).\n\n### Execution Modes\n\nAIF Handoff supports two execution modes, configurable globally via `AGENT_USE_SUBAGENTS` or per-task in the UI:\n\n| Mode          | `AGENT_USE_SUBAGENTS` | How it works                                                                                                                                                                                                  | Trade-off                                                                                                                                                            |\n| ------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| **Subagents** | `true`                | Each stage runs through specialized coordinator agents (`plan-coordinator`, `implement-coordinator`, `review-sidecar` + `security-sidecar`) that iteratively refine the result until quality criteria are met | Higher quality — plans are polished in multiple rounds, implementation gets parallel workers with quality sidecars, reviews are thorough. Takes more time and tokens |\n| **Skills**    | `false` (default)     | Each stage runs as a single-pass AIF skill (`/aif-plan`, `/aif-implement`, `/aif-review`, `/aif-security-checklist`)                                                                                          | Faster execution with lower token usage, but no iterative refinement — good enough for simpler tasks or quick prototyping                                            |\n\n## Tech Stack\n\n| Layer        | Technology                                                               |\n| ------------ | ------------------------------------------------------------------------ |\n| Runtime      | Node.js + TypeScript                                                     |\n| Monorepo     | Turborepo                                                                |\n| Database     | SQLite (better-sqlite3 + drizzle-orm)                                    |\n| API          | Hono + @hono/node-server + WebSocket                                     |\n| Validation   | zod + @hono/zod-validator                                                |\n| Frontend     | React + Vite + TailwindCSS                                               |\n| Drag \u0026 Drop  | @dnd-kit                                                                 |\n| Server State | @tanstack/react-query                                                    |\n| Runtime SDKs | Pluggable adapters — Claude (Agent SDK) + Codex (CLI/SDK/App Server/API) |\n| Scheduler    | node-cron                                                                |\n\n## Docker\n\nThe project includes full Docker support (Angie reverse proxy + Node services).\n\n### Development\n\n```bash\ndocker compose up --build\n```\n\nWeb UI at `localhost:5180`, API at `localhost:3009`, MCP at `localhost:${MCP_PORT:-3100}`.\n\n### Production\n\n```bash\ndocker compose -f docker-compose.production.yml up --build\n```\n\nAuthentication: set `ANTHROPIC_API_KEY` in `.env`, or log in via `docker compose exec agent claude login` and then `docker compose restart` (see [Authentication](#authentication) above).\n\nOnly ports 80/443 are exposed. API is bound to localhost only. Includes security hardening (no-new-privileges, resource limits), healthchecks, log rotation, and automatic SSL via Let's Encrypt (ACME).\n\n| Variable             | Default      | Description                                                  |\n| -------------------- | ------------ | ------------------------------------------------------------ |\n| `ANTHROPIC_API_KEY`  | —            | API key (or use `claude login`)                              |\n| `DOMAIN`             | `localhost`  | Domain for SSL certificate (ACME)                            |\n| `PORT`               | `3009`       | Host port for API                                            |\n| `MCP_PORT`           | `3100`       | Host port for MCP HTTP server (`1-65535`)                    |\n| `WEB_PORT`           | `5180`       | Host port for Web UI (dev)                                   |\n| `WEB_HOST`           | `localhost`  | Web UI dev server host (Vite)                                |\n| `HTTP_PORT`          | `80`         | Host port for Web UI (production)                            |\n| `HTTPS_PORT`         | `443`        | HTTPS port (production)                                      |\n| `PROJECTS_DIR`       | `./projects` | Host directory for project files (dev)                       |\n| `PROJECTS_MOUNT`     | `/home/www`  | Project files path inside containers                         |\n| `PROJECTS_HOST_ROOT` | `${PWD}`     | Compose-internal repo root for relative `PROJECTS_DIR` (dev) |\n\nIn the dev Compose setup, project roots are used by processes inside the\ncontainers. Host paths under `PROJECTS_DIR` are accepted in the UI and\nautomatically saved as the matching `PROJECTS_MOUNT` path, so\n`/Users/me/projects/app` becomes `/home/www/app` with the default mount. If\n`PROJECTS_DIR` is relative, Compose resolves it from `PROJECTS_HOST_ROOT`; leave\n`PROJECTS_HOST_ROOT` unset unless you are replacing the compose wiring.\n\nProduction Compose uses a named Docker volume at `PROJECTS_MOUNT` instead of\nthe dev bind mount. Create and select projects by their in-container path in\nproduction, for example `/home/www/app`.\n\nA `.devcontainer/` config is also included for JetBrains / VS Code.\n\n## Scripts\n\n| Command            | Description                                   |\n| ------------------ | --------------------------------------------- |\n| `npm run dev`      | Start all services with hot reload            |\n| `npm run build`    | Build all packages                            |\n| `npm test`         | Run all tests (Vitest)                        |\n| `npm run init`     | Initialize database                           |\n| `npm run db:setup` | Build shared package and initialize SQLite DB |\n| `npm run db:push`  | Push schema changes via drizzle-kit           |\n\n## Troubleshooting\n\nIf you enabled subagents and the workflow runs for too long or frequently times out, disable them in your environment (this is the default):\n\n```env\nAGENT_USE_SUBAGENTS=false\n```\n\nIf an LLM report says it lacks permissions for specific actions during workflow execution, either grant the required permissions in `.claude/settings.local.json` or bypass permission checks via environment variable:\n\n```env\nAGENT_BYPASS_PERMISSIONS=true\n```\n\n---\n\n## Documentation\n\n| Guide                                      | Description                                   |\n| ------------------------------------------ | --------------------------------------------- |\n| [Getting Started](docs/getting-started.md) | Installation, setup, first steps              |\n| [Architecture](docs/architecture.md)       | Agent pipeline, state machine, data flow      |\n| [API Reference](docs/api.md)               | REST endpoints, WebSocket events              |\n| [Configuration](docs/configuration.md)     | Environment variables, logging, auth          |\n| [Providers](docs/providers.md)             | Runtime profiles, adapters, capability matrix |\n\n![ui-light](https://github.com/lee-to/aif-handoff/blob/main/art/ui-light.png)\n![ui-dark](https://github.com/lee-to/aif-handoff/blob/main/art/ui-dark.png)\n![ui-light-list](https://github.com/lee-to/aif-handoff/blob/main/art/ui-light-list.png)\n![ui-dark-list](https://github.com/lee-to/aif-handoff/blob/main/art/ui-dark-list.png)\n\n## Contributing\n\nContributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) before submitting a pull request.\n\n## Security\n\nIf you discover a security vulnerability, please see [SECURITY.md](SECURITY.md) for responsible disclosure instructions.\n\n## License\n\nMIT License — see [LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flee-to%2Faif-handoff","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flee-to%2Faif-handoff","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flee-to%2Faif-handoff/lists"}