Operators can register Anthropic-API-compatible endpoints (a local Qwen/Llama
behind LiteLLM or claude-code-router, an LLM gateway) on the dashboard's
Claude -> Models tab and pick one from a Model dropdown when spawning an agent.
The agent still launches as the same claude binary with the same hooks, skills,
connectors, plugins, and gates — only its ANTHROPIC_BASE_URL / ANTHROPIC_MODEL /
ANTHROPIC_AUTH_TOKEN env differs — and it stays pinned to its backend across
resumes. No selection keeps the worker's Claude subscription untouched.
- claude_models table (+ agents.model_id pin), migration 0012
- control.models resolves a row into the launch env (API keys Fernet-encrypted
at rest, decrypted only in the control container; placeholder key when none is
stored so the subscription OAuth token never reaches a local endpoint)
- /claude/models CRUD (admin-gated writes, key never returned), spawn route +
worker + CLI (--model) pass the selection through, fail-fast on missing or
disabled backends
- dashboard: Models tab, spawn-form dropdown, model badge in the agents table
- docs/local-models.md: why bare OpenAI-compatible servers break tool calling
with Qwen-Coder, and working vLLM/LiteLLM/llama.cpp stacks
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DzDofD7gP63WpeLG8vEdZu
Add a no-build, same-origin web frontend so an operator can open a URL,
see every agent's state, and answer a paused question with no terminal
(Phase 3 DoD). The UI is a client of the existing API — no endpoint,
schema, or auth change — so the 106 existing tests pass unchanged.
- app.py serves the bundled UI from / and /static, gated on UI_ENABLED
(default on); optional CORS_ORIGINS (default empty => no middleware)
for hosting the UI on a separate origin. Dedicated /static prefix +
explicit / route so API routes are never shadowed. Zero new runtime
deps (StaticFiles/CORSMiddleware ship with Starlette).
- static/: vanilla fetch + plain CSS + vendored alpine.min.js (v3.14.8,
no CDN). Token captured once into localStorage; all API values render
via x-text (never x-html) to block agent-authored markup injection.
Project switcher, agent list, checkmark panel, paginated log, shared
feed, and Answer / Answer & Resume. Polling scoped to the selected
agent to avoid an N+1 over the fleet.
- config.py: ui_enabled, cors_origins (+ cors_origin_list); documented
in .env.example.
- tests/test_api_ui.py: serving, unauthenticated shell, non-shadowing
401 regression, CORS toggle, UI_ENABLED=false. 114 tests, ruff clean.
The static assets ship in the wheel by default (they live inside the
packaged src/handler tree) — no force-include needed.
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.
Move the original plan-of-action out of README.md into docs/PLAN.md (verbatim,
with Phase 1 checkboxes ticked and MVP-resolved open questions annotated). Replace
the README with a proper project readme grounded in the implemented MVP: what it is,
architecture, install/configure/run, curl walkthrough, control CLI, API reference,
hooks, development, and layout.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W5ZuS5pV1NS6eKsRZHXonY