diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index ea14b769..89d7831a 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -1,7 +1,16 @@
-# Builds the MkDocs site and deploys it with GitHub's official Pages Actions
-# flow (build once -> upload artifact -> deploy). This avoids the gh-pages
-# branch entirely, so there is no force-push race and the custom domain set in
-# Settings persists across deploys.
+# Docs-site split Phase 1 (docs/internal/specs/2026-07-03-docs-site-split.md):
+# docs.roboco.tech (the roboco-website repo) is now the canonical user-facing
+# docs site, so this workflow no longer builds MkDocs. It deploys the
+# already-generated, already-committed `docs-redirects/` directory — one
+# meta-refresh + rel=canonical stub per URL this repo's Pages site used to
+# publish, pointing at the docs.roboco.tech equivalent — with GitHub's
+# official Pages Actions flow (upload artifact -> deploy). No force-push
+# race, and the custom domain set in Settings persists across deploys.
+#
+# `docs-redirects/` was generated once by scripts/gen_docs_redirects.py while
+# mkdocs.yml still listed every published page; that script is not re-run
+# here. Regenerating it (e.g. to add a redirect) means re-running the script
+# against a restored copy of the old nav and committing the new output.
#
# One-time setup: Settings -> Pages -> Source = "GitHub Actions".
name: docs
@@ -10,8 +19,7 @@ on:
push:
branches: [master]
paths:
- - "docs/**"
- - "mkdocs.yml"
+ - "docs-redirects/**"
- ".github/workflows/docs.yml"
workflow_dispatch:
@@ -30,16 +38,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- - name: Install uv
- uses: astral-sh/setup-uv@v7
- - name: Build the site (strict)
- run: |
- uv sync --extra docs
- uv run mkdocs build --strict
- name: Upload Pages artifact
uses: actions/upload-pages-artifact@v5
with:
- path: site
+ path: docs-redirects
deploy:
needs: build
diff --git a/.pymarkdown.json b/.pymarkdown.json
deleted file mode 100644
index 0de756d7..00000000
--- a/.pymarkdown.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "extensions": {
- "front-matter": { "enabled": true }
- },
- "plugins": {
- "md013": { "enabled": false },
- "md033": { "enabled": false },
- "md007": { "enabled": false },
- "md030": { "enabled": false },
- "md032": { "enabled": false },
- "md041": { "enabled": false },
- "md046": { "enabled": false },
- "md025": { "enabled": false },
- "md036": { "enabled": false }
- }
-}
diff --git a/CLAUDE.md b/CLAUDE.md
index b77ece3c..03256fc0 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -571,4 +571,4 @@ ROBOCO_OLLAMA_BASE_URL=http://roboco-ollama:11434 # Native API
## Blueprint Reference
-The organizational structure, communication matrix, role descriptions, and access-control model are documented inline above and in the user-facing documentation site (MkDocs Material; source under `docs/`, built by `mkdocs.yml`, deployed by `.github/workflows/docs.yml` via GitHub Pages Actions and served at rennf93.github.io/roboco). `docs/rag/` remains the agent-facing RAG corpus (excluded from the published site); the old root `usage.md` / `deployment.md` are now redirect stubs into the site.
+The organizational structure, communication matrix, role descriptions, and access-control model are documented inline above and in the user-facing documentation site at **[docs.roboco.tech](https://docs.roboco.tech)** (the `roboco-website` repo — Next.js MDX, the canonical docs site as of the 2026-07-03 docs-site split: `docs/internal/specs/2026-07-03-docs-site-split.md`). This repo's old MkDocs-built user tree is gone; `.github/workflows/docs.yml` now only deploys the committed `docs-redirects/` stubs (meta-refresh + canonical) so every URL the old Pages site published keeps resolving, to docs.roboco.tech. `docs/rag/` remains the agent-facing RAG corpus (never published); `docs/map/` is the agent-facing exhaustive codebase map; `docs/internal/` holds specs and working notes; the old root `usage.md` / `deployment.md` now link straight to docs.roboco.tech.
diff --git a/Makefile b/Makefile
index 6d3b147c..f9fd4c2f 100644
--- a/Makefile
+++ b/Makefile
@@ -428,29 +428,13 @@ high-load-stress-test:
@docker compose down --rmi all --remove-orphans -v
@docker system prune -f
-# Serve docs
-.PHONY: serve-docs
-serve-docs:
- @uv run --extra docs mkdocs serve
- @find . | grep -E "(__pycache__|\.pyc|\.pyo|\.pytest_cache|\.ruff_cache|\.mypy_cache)" | xargs rm -rf
-
-# Build the documentation site (strict — fails on broken links / nav)
-.PHONY: build-docs
-build-docs:
- @uv run --extra docs mkdocs build --strict
- @find . | grep -E "(__pycache__|\.pyc|\.pyo|\.pytest_cache|\.ruff_cache|\.mypy_cache)" | xargs rm -rf
-
-# Lint documentation
-.PHONY: lint-docs
-lint-docs:
- @uv run --extra docs pymarkdownlnt --config .pymarkdown.json scan -r docs/index.md docs/get-started docs/company docs/how-to docs/panel docs/models docs/operations docs/optional docs/deploy docs/api docs/troubleshooting
- @find . | grep -E "(__pycache__|\.pyc|\.pyo|\.pytest_cache|\.ruff_cache|\.mypy_cache)" | xargs rm -rf
-
-# Fix documentation
-.PHONY: fix-docs
-fix-docs:
- @uv run --extra docs pymarkdownlnt --config .pymarkdown.json fix -r docs/index.md docs/get-started docs/company docs/how-to docs/panel docs/models docs/operations docs/optional docs/deploy docs/api docs/troubleshooting
- @find . | grep -E "(__pycache__|\.pyc|\.pyo|\.pytest_cache|\.ruff_cache|\.mypy_cache)" | xargs rm -rf
+# Regenerate the GitHub Pages redirect stubs (docs-redirects/) that replaced
+# the old MkDocs-built site — docs.roboco.tech is canonical now. Only needed
+# if a legacy URL is missing a stub; requires a restored copy of the old
+# nav-bearing mkdocs.yml (see git history) since the live one is gone.
+.PHONY: regen-docs-redirects
+regen-docs-redirects:
+ @uv run python scripts/gen_docs_redirects.py
# Prune
.PHONY: prune
@@ -514,16 +498,12 @@ help:
@echo " make test-all - Run tests (all Python versions)"
@echo " make stress-test - Run stress test"
@echo ""
- @echo "Documentation:"
- @echo " make serve-docs - Serve documentation"
- @echo " make lint-docs - Lint markdown files"
- @echo ""
@echo "Cleanup:"
@echo " make stop - Stop all containers"
@echo " make clean - Clean cache files"
@echo " make prune - Prune docker resources"
@echo ""
- @echo "Full docs: https://rennf93.github.io/roboco/ (preview locally: make serve-docs)"
+ @echo "Full docs: https://docs.roboco.tech"
# Python versions list
.PHONY: show-python-versions
diff --git a/README.md b/README.md
index bd2d5216..ec231551 100644
--- a/README.md
+++ b/README.md
@@ -22,9 +22,9 @@ AI Agents Company - A virtual organization of 25 AI agents + 1 human CEO, design
> [!WARNING]
@@ -73,9 +73,9 @@ One full loop, put simply:
**— Full circle —**
-**[See the full walkthrough, with screenshots →](docs/how-to/README.md)**
+**[See the full walkthrough, with screenshots →](https://docs.roboco.tech/docs/tour)**
-**[Or watch the full panel walkthrough (video) →](docs/videos/panel-full-walkthrough.mp4)**
+**[Or watch the full panel walkthrough (video) →](https://docs.roboco.tech/docs/videos/panel-full-walkthrough.mp4)**
## Project Structure
@@ -100,8 +100,8 @@ roboco/
├── agents/
│ └── prompts/ # Agent system prompts (roles, teams, identities)
├── docs/
-│ ├── how-to/ # Visual walkthrough — 5-chapter guide (start at README.md)
-│ └── rag/ # Agent knowledge base (indexed into RAG)
+│ ├── rag/ # Agent knowledge base (indexed into RAG)
+│ └── map/ # Exhaustive codebase map (agent-facing)
├── alembic/ # Database migrations
├── CLAUDE.md # Claude Code guidance
├── docker-compose.yml # Full stack, built from source
diff --git a/deployment.md b/deployment.md
index 1eaa67a8..7fe581c7 100644
--- a/deployment.md
+++ b/deployment.md
@@ -1,13 +1,11 @@
# RoboCo Deployment Guide
-> **This guide has moved.** Deploying RoboCo is now documented in the full docs site at **[rennf93.github.io/roboco](https://rennf93.github.io/roboco/)** (source under [`docs/`](docs/)).
+> **This guide has moved.** Deploying RoboCo is now documented in the full docs site at **[docs.roboco.tech](https://docs.roboco.tech)**.
Jump straight to:
-- **[Install & first run](docs/get-started/installation.md)** — the quickest path: clone, set two secrets, `docker compose up`.
-- **[Deployment](docs/deploy/deployment.md)** — the production guide: compose files, the single-origin nginx, host-path mounts, data persistence, secure mode, and startup ordering.
-- **[Environment reference](docs/deploy/env-reference.md)** — every `ROBOCO_*` setting with its default and purpose.
-- **[Data & migrations](docs/deploy/data-and-migrations.md)** — the schema, pgvector, and how the stack self-migrates.
-- **[Troubleshooting](docs/troubleshooting/common-issues.md)** — the common deploy snags and their fixes.
-
-Preview the site locally with `make serve-docs`.
+- **[Install & first run](https://docs.roboco.tech/docs/get-started/installation)** — the quickest path: clone, set two secrets, `docker compose up`.
+- **[Deployment](https://docs.roboco.tech/docs/deploy/deployment)** — the production guide: compose files, the single-origin nginx, host-path mounts, data persistence, secure mode, and startup ordering.
+- **[Environment reference](https://docs.roboco.tech/docs/deploy/env-reference)** — every `ROBOCO_*` setting with its default and purpose.
+- **[Data & migrations](https://docs.roboco.tech/docs/deploy/data-and-migrations)** — the schema, pgvector, and how the stack self-migrates.
+- **[Troubleshooting](https://docs.roboco.tech/docs/troubleshooting/common-issues)** — the common deploy snags and their fixes.
diff --git a/docs-redirects/api/auth/index.html b/docs-redirects/api/auth/index.html
new file mode 100644
index 00000000..d5d5d3b0
--- /dev/null
+++ b/docs-redirects/api/auth/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+Authentication
+
+
+
+
+
+
+
diff --git a/docs/api/auth.md b/docs/api/auth.md
deleted file mode 100644
index ec1d490e..00000000
--- a/docs/api/auth.md
+++ /dev/null
@@ -1,63 +0,0 @@
-# Authentication
-
-RoboCo's API identifies a caller by a small set of headers — `X-Agent-ID`, `X-Agent-Role`, and optionally `X-Agent-Team`. How much it *trusts* those headers depends on one flag. Out of the box the API runs in header-trust mode, which is fine on a private LAN and dangerous anywhere else. This page covers both modes and the WebSocket caveat.
-
-## The identity headers
-
-Every REST request carries:
-
-| Header | Required | Meaning |
-|--------|----------|---------|
-| `X-Agent-ID` | Yes | The agent's UUID or slug (e.g. `be-dev-1`). |
-| `X-Agent-Role` | Yes | The role the caller is acting as (e.g. `developer`, `cell_pm`, `ceo`). |
-| `X-Agent-Team` | No | The team (`backend`, `frontend`, `uxui`), when relevant. |
-| `X-Agent-Token` | Only in secure mode | The HMAC token that proves the headers above weren't forged. |
-
-These are resolved in `roboco/api/deps.py` (`get_agent_context`), and the role gates the action — so a request claiming `X-Agent-Role: ceo` can do CEO-only things like approving and merging.
-
-## Header-trust mode (default)
-
-By default `ROBOCO_AGENT_AUTH_REQUIRED` is unset/false. In this mode the API **accepts the role headers without verifying any token**. There is no proof of identity: whoever sets `X-Agent-Role: ceo` *is* the CEO for that request.
-
-!!! danger "Anyone who can reach the API can claim any role — including CEO"
- In header-trust mode there is no authentication. Any client that can open a connection to the orchestrator port can act as any agent, approve and merge work as the CEO, cancel tasks, or override task state. The app logs a loud startup warning to this effect. This is acceptable **only** on a trusted private network where nothing untrusted can reach the orchestrator — which is the default single-host LAN deployment behind nginx on `localhost:3000`. Do not expose the orchestrator to anything you don't control without first turning on secure mode.
-
-## Secure mode (HMAC tokens)
-
-Set `ROBOCO_AGENT_AUTH_REQUIRED=true` to require a signed token on every REST request. In this mode:
-
-- `X-Agent-Token` becomes mandatory; a request without it is rejected with **401**.
-- The token is an HMAC signed with `ROBOCO_AGENT_AUTH_SECRET` and **bound to the agent's id, role, and team**. The server recomputes the signature over the presented `X-Agent-ID` / `X-Agent-Role` / `X-Agent-Team` and compares it constant-time. If a caller swaps the role header to escalate to `ceo`, the signature no longer matches and the request is rejected with **401 — signature mismatch**.
-- The orchestrator issues each agent its token at spawn time, so delivery agents are authenticated by construction.
-- A presented token is **always** verified, even when auth isn't required — so you can roll out tokens before flipping the switch without breaking anything.
-
-| Flag | Default | Purpose |
-|------|---------|---------|
-| `ROBOCO_AGENT_AUTH_REQUIRED` | `false` | When `true`, REST requires a valid HMAC `X-Agent-Token`. |
-| `ROBOCO_AGENT_AUTH_SECRET` | (unset) | Shared secret the orchestrator uses to sign and the API uses to verify the per-agent token. |
-
-!!! tip "How the panel authenticates as the CEO"
- The control panel acts as the CEO agent. In secure mode, nginx injects the panel's CEO `X-Agent-Token` so your browser session is authenticated without you handling the secret — you just use the panel as normal.
-
-## The WebSocket + live-chat streams
-
-Secure mode extends beyond REST. When `ROBOCO_AGENT_AUTH_REQUIRED=true`:
-
-- The **per-resource WebSocket streams** (`/ws/channels|agents|sessions|notifications/{id}`) require the **CEO panel token** — the same signed `X-Agent-Token` nginx injects for the panel. An agent on the Docker network can no longer subscribe to another agent's notifications with no auth. They still validate `agent_id`/`viewer_id` against the DB and channel access on top.
-- The **`/api/v1/do/*` content routes** require a valid per-agent HMAC token bound to `X-Agent-ID` (the do router serves every role, so the gate is token-only, not role-specific).
-- The **live-chat bridges** (`/prompter/live/*`, `/secretary/live/*`) — the prompter/secretary intake chats — require the CEO panel token on their start/stream/status/messages/stop endpoints. They were the last panel-facing API surface that ran unauthenticated.
-- **`/ws/system`** stays operator-only and read-only by design (it carries system telemetry and accepts nothing from the client); it is not token-gated.
-
-A presented-but-forged token is rejected even in dev (header-trust) mode, so you can roll out tokens before flipping the switch without breaking anything. The container→relay internal callback is left ungated by design (internal Docker network, opaque session id).
-
-## What to do
-
-- **Single-host LAN, nothing untrusted on the network** → header-trust is fine; that's the default.
-- **Anything reachable beyond a trusted LAN** → set `ROBOCO_AGENT_AUTH_REQUIRED=true` and a strong `ROBOCO_AGENT_AUTH_SECRET`, and keep the orchestrator port off the public internet regardless.
-
-For the full hardening checklist — network exposure, the GitHub PAT handling, and the prompt/bash guards — see [Security](../troubleshooting/security.md).
-
-## Next
-
-- [REST API](./rest-api.md) — the route surface these headers authorize.
-- [WebSockets](./websockets.md) — the live streams and their separate auth model.
diff --git a/docs/api/index.md b/docs/api/index.md
deleted file mode 100644
index fd198a71..00000000
--- a/docs/api/index.md
+++ /dev/null
@@ -1,25 +0,0 @@
-# API Reference
-
-RoboCo is API-first: the control panel is just a client of the same REST and WebSocket surface you can drive yourself. This section is for integrators and the curious; the live, always-current schema is at **`/docs`** (Swagger UI) and **`/redoc`** on the orchestrator.
-
-
-
-- **[REST API](rest-api.md)**
-
- ---
-
- The `/api` domain routes, the agent gateway verbs, the error envelope, and where to find the live OpenAPI.
-
-- **[WebSocket streams](websockets.md)**
-
- ---
-
- The `/ws` live streams the panel consumes — per-resource feeds and the operator system stream.
-
-- **[Authentication](auth.md)**
-
- ---
-
- Header-trust mode versus secure token mode, and how the panel stays authenticated.
-
-
diff --git a/docs/api/rest-api.md b/docs/api/rest-api.md
deleted file mode 100644
index 9534b089..00000000
--- a/docs/api/rest-api.md
+++ /dev/null
@@ -1,119 +0,0 @@
-# REST API
-
-RoboCo's backend is a single FastAPI application (`roboco/api/app.py`, one `create_app()` factory). It mounts every domain router under the `/api` prefix, the agent-gateway intent verbs under `/api/v1`, and the live WebSocket streams under `/ws`. Everything is fronted by nginx on `localhost:3000`, so the panel and any integrator use relative URLs (`/api/...`, `/ws/...`) against one origin with no CORS to configure.
-
-!!! tip "The live OpenAPI docs are the source of truth"
- The fastest way to see the full, current REST surface — every path, request body, and response schema — is the interactive docs the app serves itself:
-
- - **Swagger UI** → [`http://localhost:3000/docs`](http://localhost:3000/docs)
- - **ReDoc** → [`http://localhost:3000/redoc`](http://localhost:3000/redoc)
-
- This page is a map of *where things live*; `/docs` is the authoritative reference for *exactly how to call them*.
-
-## The two prefixes
-
-There are two distinct API surfaces, and the prefix tells you which one you're on:
-
-| Prefix | Audience | What it is |
-|--------|----------|------------|
-| `/api/*` | You / the panel / integrators | The domain REST surface — tasks, agents, projects, git, usage, settings, and the rest. This is what the control panel calls. |
-| `/api/v1/flow/{role}/{verb}` and `/api/v1/do` | AI agents only | The [agent gateway](../company/agent-gateway.md). Agents never call the domain routes above — they POST intent verbs here through their MCP servers, and the server-side Choreographer enforces state, locks, and evidence. |
-
-Health and readiness probes sit at the root, not under `/api`: `GET /health` and `GET /ready`.
-
-## Domain route groups (`/api/*`)
-
-Every router is mounted under `/api`. The groups an operator or integrator hits:
-
-| Route group | Prefix | Purpose |
-|-------------|--------|---------|
-| Tasks | `/api/tasks` | The largest router: full task CRUD and lifecycle transitions (claim, submit, pass/fail, complete, escalate). The CEO god-mode override (`PATCH /api/tasks/{id}` with `X-Agent-Role: ceo`) lives here. |
-| Kanban | `/api/kanban` | Board view of tasks grouped by state. |
-| Agents | `/api/agents` | Agent roster, roles, teams, current state. |
-| Work sessions | `/api/work-sessions` | Git session records — branch, commits, files, PR. |
-| Projects | `/api/projects` | Repository config, CI/quality commands, git-token management. |
-| Products | `/api/products` | Product entities + CEO approve-and-start / cell-routing. |
-| Sessions | `/api/sessions` | Communication sessions and their messages. |
-| Channels | `/api/channels` | Team channels. |
-| Groups | `/api/groups` | Agent/channel grouping. |
-| Messages | `/api/messages` | Extracted messages from agent streams. |
-| Notifications | `/api/notifications` | Formal ack-required notifications. |
-| Stream | `/api/stream` | Agent output stream access. |
-| Journals | `/api/journals` | Agent journals and entries. |
-| Optimal | `/api/optimal` | RAG queries (in-house pgvector engine). |
-| Git | `/api/git` | Git operations surfaced for the panel. |
-| Providers | `/api/providers` | Model-provider routing config. |
-| Orchestrator | `/api/orchestrator` | Agent-runtime control (spawn/stop, dispatcher state). |
-| Dashboard | `/api/dashboard` | Aggregated dashboard data. |
-| Usage | `/api/usage` | Token/cost analytics (`GET /api/usage/summary?period=24h\|7d\|30d`). |
-| System | `/api/system` | Rate-limit introspection (`GET /api/system/rate-limits`). |
-| Settings | `/api/settings` | App settings, including feature-flag persistence. |
-| Company goals | `/api/company-goals` | The company charter. |
-| Cockpit | `/api/cockpit` | CEO read-only business summary. |
-| Research | `/api/research` | Web-research subsystem (flag-gated). |
-| Pitches | `/api/pitches` | Pitch provisioning (flag-gated). |
-| Secretary | `/api/secretary` | Secretary chief-of-staff + its live-chat bridge. |
-| Prompter | `/api/prompter` | Intake interviewer live chat (SSE relay). |
-| Docs | `/api/docs` | Project documentation file management. |
-| A2A | `/api/a2a` | Agent-to-agent messaging plumbing. |
-
-!!! info "Health vs readiness"
- `GET /health` is a liveness probe — it returns 200 once the app is up. `GET /ready` is a readiness probe — it checks PostgreSQL and Redis and returns a `degraded` payload if either is down. Wire your uptime monitor to `/ready` if you want it to react to a backing-store outage, `/health` if you only care that the process is alive. See [Health & metrics](../operations/health-and-metrics.md).
-
-## The agent gateway (`/api/v1`)
-
-Agents do not touch the domain routes. They go through the gateway, which exposes one POST endpoint per (role, verb) pair plus a shared content-tools endpoint:
-
-| Endpoint | Role |
-|----------|------|
-| `POST /api/v1/flow/developer/{verb}` | Developer |
-| `POST /api/v1/flow/qa/{verb}` | QA |
-| `POST /api/v1/flow/documenter/{verb}` | Documenter |
-| `POST /api/v1/flow/cell_pm/{verb}` | Cell PM |
-| `POST /api/v1/flow/main_pm/{verb}` | Main PM |
-| `POST /api/v1/flow/board/{verb}` | Board (Product Owner, Head of Marketing, Auditor) |
-| `POST /api/v1/flow/auditor/{verb}` | Auditor |
-| `POST /api/v1/flow/pr_reviewer/{verb}` | PR reviewer |
-| `POST /api/v1/do` | Content tools (`commit`, `note`, `say`, `dm`, `evidence`) for every role |
-
-The `roboco-flow` MCP server in each agent container is a thin shim: it reads the agent's spawn manifest, registers only the verbs that role may call, and POSTs each one here. The verb set per role and the structural sandboxing are documented in [How agents are sandboxed](../company/agent-gateway.md) — you generally won't call these endpoints yourself.
-
-## The error envelope
-
-Every gateway verb returns the same standardized **envelope** (`roboco/services/gateway/envelope.py`), so agents recover from a rejection instead of looping:
-
-- **Success** carries `status`, `task_id`, `next` (the verb to call next), an optional `evidence` block, a `context_briefing`, and introspection fields (`current_state`, `valid_next_verbs`).
-- **Error** carries an `error` flavor, a human `message`, a concrete `remediate` hint, and — for input gaps — a `missing` list and a `field_hints` answer-key.
-
-The error flavors:
-
-| `error` | Meaning |
-|---------|---------|
-| `tracing_gap` | A required tracing artifact (e.g. a commit, PR, or note) is missing. |
-| `incomplete_input` | A required input field was not supplied; `missing` + `field_hints` tell the agent exactly which. |
-| `invalid_state` | The verb isn't valid from the task's current state. |
-| `not_authorized` | The role isn't allowed to perform this action. |
-| `not_found` | The task or resource doesn't exist. |
-| `circuit_open` | The agent has hammered one failing verb too many times; the breaker points it at a graceful exit. |
-
-The domain routes (`/api/*`) use FastAPI's standard error model, with the exception-handler stack in `roboco/api/middleware.py` mapping domain and service errors to clean responses. Notably:
-
-- A provider rate-limit error becomes **HTTP 429 with a `Retry-After` header**.
-- A validation failure is a **422**, with a special remediation hint when an agent sends an 8-character short task id instead of a full UUID.
-- Every response echoes back an `X-Correlation-ID` (and the request's `X-Response-Time-Ms`), so one id threads through the panel, the API, and the logs.
-
-## Quick checks
-
-```bash
-curl -s localhost:3000/health
-curl -s localhost:3000/ready
-curl -s localhost:3000/api/system/rate-limits
-curl -s 'localhost:3000/api/usage/summary?period=7d'
-open http://localhost:3000/docs
-```
-
-## Next
-
-- [WebSockets](./websockets.md) — the live `/ws` streams the panel consumes.
-- [Authentication](./auth.md) — header-trust vs. secure mode, and who can claim which role.
-- [How agents are sandboxed](../company/agent-gateway.md) — the gateway, verbs, and envelope in depth.
diff --git a/docs/api/websockets.md b/docs/api/websockets.md
deleted file mode 100644
index 52a1a590..00000000
--- a/docs/api/websockets.md
+++ /dev/null
@@ -1,66 +0,0 @@
-# WebSockets
-
-RoboCo pushes live updates over WebSocket endpoints under `/ws`, served by the orchestrator (`roboco/api/websocket.py`) and routed through nginx alongside the REST API. A single in-process `ConnectionManager` holds per-resource connection sets and broadcasts events to them. The panel consumes all of these through its `useWebSocket("/", …)` hook — you rarely connect to them directly, but they're the same streams an integrator can subscribe to.
-
-## The endpoints
-
-There are four per-resource streams plus one operator-wide stream:
-
-| Endpoint | Stream | Auth |
-|----------|--------|------|
-| `/ws/channels/{channel_id}` | Live messages in a team channel | `agent_id` query param, validated against the DB + channel access; **CEO panel token required in secure mode** |
-| `/ws/agents/{agent_id}` | An agent's output and lifecycle events | `viewer_id`/`agent_id` query param, validated against the DB; **CEO panel token required in secure mode** |
-| `/ws/sessions/{session_id}` | Messages in a communication session | `agent_id` query param, validated; **CEO panel token required in secure mode** |
-| `/ws/notifications/{agent_id}` | An agent's notifications | `agent_id` query param, validated; **CEO panel token required in secure mode** |
-| `/ws/system` | Operator/system-wide stream — no per-agent keying | **Unauthenticated, read-only** (operator-only by design; not token-gated) |
-
-All sockets support a `ping`/`pong` keepalive: send `{"type": "ping"}` and you'll get a `pong` back.
-
-!!! info "Secure mode now covers the per-agent streams"
- When `ROBOCO_AGENT_AUTH_REQUIRED=true`, the four per-resource sockets require the **CEO panel token** (the signed `X-Agent-Token` nginx injects for the panel) on top of their `agent_id`/`viewer_id` DB validation — an agent on the Docker network can no longer subscribe to another agent's stream unauthenticated. `/ws/system` is intentionally left operator-only and read-only. A forged token is rejected even in dev mode. See [Authentication](./auth.md).
-
-## How events reach the sockets
-
-Server-side events are published to an in-process `StreamEventBus`. The bridge in `roboco/api/websocket_bridge.py` subscribes to it and registers a `_handle_*` forwarder per event type, mapping each `EventType` to the right socket broadcast.
-
-```mermaid
-flowchart LR
- S[Service / orchestrator] -->|publish EventType| B[StreamEventBus]
- B --> WB[websocket_bridge _handle_*]
- WB --> R[/ws/channels, /ws/agents, /ws/sessions, /ws/notifications/]
- WB --> SYS[/ws/system/]
- R --> P[Panel useWebSocket hook]
- SYS --> P
-```
-
-To add a new live event you define an `EventType`, publish it to the bus, add a `_handle_*` forwarder in `websocket_bridge`, and consume it on the panel via the same hook — you never stand up a parallel endpoint.
-
-## Event types
-
-| Event | Arrives on | What it carries |
-|-------|-----------|-----------------|
-| `RATE_LIMIT_HIT` | `/ws/system` | A provider just hit a rate limit / overload and was parked. Drives the panel's amber rate-limit banner. |
-| `RATE_LIMIT_LIFTED` | `/ws/system` | A parked provider recovered; queued work resumes. Clears the banner. |
-| `USAGE_SNAPSHOT` | `/ws/system` | A fresh token-usage/cost snapshot. Drives the live "Token Usage & Cost" dashboard. |
-| `NOTIFICATION_SENT` / `NOTIFICATION_ACKED` | `/ws/notifications/{agent_id}` | A notification was sent to or acknowledged by an agent. |
-| `MESSAGE_SENT` | `/ws/sessions/{session_id}` **and** `/ws/channels/{channel_id}` | A chat message was persisted. Forwarded as a `message.new` frame (carrying `message_id`, `agent_id`, `content`, `message_type`, `timestamp`) so the session transcript and channel view update live instead of waiting on a manual refresh. |
-| `SESSION_CREATED` / `SESSION_CLOSED` / `SESSION_TIMEOUT` | `/ws/sessions/{session_id}` | Communication-session lifecycle. |
-| `AGENT_SPAWNED` / `AGENT_STOPPED` / `AGENT_WAITING` / `AGENT_RESUMED` / `AGENT_ERROR` | `/ws/agents/{agent_id}` | Agent runtime lifecycle transitions. |
-
-Each forwarded message is a JSON object with a `type` field merged with the event's data. The `type` is the event-type name above, except the message forwarder, which sets `type: "message.new"` (the frame the panel's channel/session stream filters on).
-
-## REST fallbacks
-
-The two operator dashboards that ride `/ws/system` fall back to HTTP polling when the socket is down, so the panel keeps working without the stream:
-
-| Live event | HTTP fallback |
-|------------|---------------|
-| `RATE_LIMIT_HIT` / `RATE_LIMIT_LIFTED` | `GET /api/system/rate-limits` |
-| `USAGE_SNAPSHOT` | `GET /api/usage/summary?period=24h\|7d\|30d` |
-
-See [Cost & usage](../operations/cost-and-usage.md) and [Health & metrics](../operations/health-and-metrics.md) for what the panel does with these.
-
-## Next
-
-- [REST API](./rest-api.md) — the `/api/*` route map and the error envelope.
-- [Authentication](./auth.md) — the WebSocket-auth caveat in full.
diff --git a/docs/assets/logo.png b/docs/assets/logo.png
deleted file mode 100644
index ac66224b..00000000
Binary files a/docs/assets/logo.png and /dev/null differ
diff --git a/docs/company/agent-gateway.md b/docs/company/agent-gateway.md
deleted file mode 100644
index fd06e32c..00000000
--- a/docs/company/agent-gateway.md
+++ /dev/null
@@ -1,52 +0,0 @@
-# How agents are sandboxed
-
-The most important thing to understand about trusting RoboCo with your repository: **agents never touch your API, your database, or a shell directly.** Every action an agent can take goes through a narrow, server-side gateway that only exposes the handful of verbs that agent's *role* is allowed to use. Capability is decided by role at spawn time — not by the model's good behavior.
-
-## Agents speak in verbs, not API calls
-
-Each agent container talks to RoboCo through two thin MCP servers, both backed by a single server-side component (the **Choreographer**) that composes the real services behind the scenes:
-
-| Server | What it exposes |
-|--------|-----------------|
-| `roboco-flow` | **Intent verbs** — the lifecycle actions: `give_me_work`, `i_will_work_on`, `open_pr`, `i_am_done`, `claim_review`, `pass_review`, `complete`, `submit_up`, `submit_root`, `pr_pass`, … |
-| `roboco-do` | **Content tools** — `commit`, `note`, `say`, `dm`, `evidence`. |
-
-Two more read-only servers give agents a read-only view of git (`status`, `log`, `diff`) and access to the knowledge base. That's the entire surface. There is no "run arbitrary SQL," no "call any endpoint," no general shell.
-
-## A role can only call its own verbs
-
-At spawn, every agent is handed a **manifest** listing exactly the verbs its role may call — and nothing else. The manifest is built from a server-side role configuration and mounted read-only into the container. The result is that the lifecycle's role rules aren't just policy, they're *unreachable code* for the wrong role:
-
-- A **developer** can `give_me_work`, open a PR, mark itself done, and `sync_branch` (rebase its branch onto its base through the gate) — but there is no merge verb in its manifest.
-- **QA** can claim a review and pass or fail it — but it has no `commit`. QA and Documenters also get `i_am_blocked` as their escape hatch when they're stuck.
-- A **PR reviewer** can pass or fail an assembled PR and post its review on the PR — but it never gets agent chat verbs.
-- The **Auditor** is restricted to leaving a private note and reading evidence; it cannot `say` or `dm`. It observes; it does not participate.
-
-So when [the lifecycle](task-lifecycle.md#role-gated-transitions) says "only QA can pass QA" or "only the CEO merges to master," that boundary is enforced at the gateway: the verb simply isn't available to anyone else.
-
-## Every action returns a structured envelope
-
-Agents don't guess at state. Every verb returns a standardized **envelope**:
-
-- On success: `{ status, task_id, next, evidence?, context_briefing }` — where `next` tells the agent what to call next.
-- On error: `{ error, message, remediate, missing }` — where `remediate` tells the agent exactly how to fix it and retry.
-
-That `next` / `remediate` contract is why agents move through the lifecycle reliably instead of flailing: the gateway leads them, step by step, and rejects anything out of order with an explanation rather than a crash.
-
-## The other guardrails
-
-A few more protections run by construction, the same way on every backend (Claude or Grok):
-
-- **Claim-locking** serializes work, so two agents can't grab the same task or race a merge.
-- **Content posts require an active claim.** `commit`, `note`, `say`, `dm`, and `evidence` on a specific task are refused unless the agent holds that task's active claim — an agent can't write to a task it hasn't locked.
-- **Human-only roles are never spawned.** The CEO, the Intake (prompter), and the Secretary are human-driven, so `spawn_agent` structurally refuses them — a notification addressed to the CEO can never launch a CEO container that acts as the human. Intake and Secretary run through their own dedicated, guarded chat paths instead.
-- **Notifications can't target human-only roles.** `notify` rejects the CEO/prompter/secretary as recipients — there is no agent acknowledgement path for them, so a notification to them is a no-op rather than a stuck ack.
-- **The token never enters the container.** Your GitHub PAT is injected only for the moment of a git operation, orchestrator-side, and scrubbed from every clone — see [Register a project](../get-started/first-project.md#what-happens-under-the-hood).
-- **A prompt-injection guard** screens task prompts, and a bash guard blocks credential-exfiltration and identity-forgery patterns.
-- **Rate limits and overloads park, they don't crash-loop.** If a provider returns a 429 or a persistent overload, RoboCo *queues* that agent's work and probes for recovery instead of burning tokens retrying. You'll see an amber banner; the work resumes automatically when the provider does.
-
-The practical upshot for you as operator: the workforce is structurally constrained to do its job and only its job. You're not relying on twenty-five models all choosing to behave — you're relying on the fact that the misbehaving action isn't on the menu.
-
-## Next
-
-→ Watch it all in motion in [the Tour](../how-to/README.md), or head back to [the lifecycle](task-lifecycle.md).
diff --git a/docs/company/index.md b/docs/company/index.md
deleted file mode 100644
index dda9fe2e..00000000
--- a/docs/company/index.md
+++ /dev/null
@@ -1,35 +0,0 @@
-# The Company
-
-What keeps twenty-five agents from dissolving into noise is that RoboCo is relentlessly opinionated about *how* work happens. Everything is a task, no task moves without acceptance criteria, and every task walks the same strict, role-gated lifecycle — built, QA'd, documented, reviewed, approved. The structure is the point. It's what turns a roster of models into a company that actually ships.
-
-This section explains the machinery:
-
-
-
-- **[Org & roles](org-and-roles.md)**
-
- ---
-
- The twenty-five agents, the three cells, the Board, and the chain of command you sit on top of.
-
-- **[The task lifecycle](task-lifecycle.md)**
-
- ---
-
- The fifteen states every task moves through, who owns each step, and how rejected work loops back.
-
-- **[The merge model](merge-model.md)**
-
- ---
-
- How work flows up a cell → root → master pull-request chain — and why only you ever touch `master`.
-
-- **[How agents are sandboxed](agent-gateway.md)**
-
- ---
-
- Agents never touch your API or your shell. They act only through a narrow set of role-scoped verbs.
-
-
-
-If you'd rather see these ideas in motion than read about them, [the Tour](../how-to/README.md) follows one real feature through the whole company.
diff --git a/docs/company/megatask.md b/docs/company/megatask.md
deleted file mode 100644
index e318b125..00000000
--- a/docs/company/megatask.md
+++ /dev/null
@@ -1,50 +0,0 @@
-# MegaTask
-
-Most of the time you describe one piece of work and RoboCo builds it. Sometimes you have **several** things you want done at once — and they aren't always in the same repository. A **MegaTask** lets you describe the whole set in a single intake chat and hand it off as one batch that the company sequences and builds for you.
-
-The motivating example: you want to ship a change to a SaaS app, the open-source core engine it depends on, and a framework adapter — three repositories that don't share a codebase. That's one MegaTask.
-
-## Starting a MegaTask
-
-The intake modal has three scopes:
-
-- **Single cell** — one task in one project.
-- **Board-led** — a feature spanning the cells of one product.
-- **MegaTask** — several tasks across the projects you pick.
-
-Choose **MegaTask** and check every repository the work spans (pick at least two). The intake agent clones and reads all of them, interviews you exactly as usual, and then — instead of proposing one draft — proposes the **whole batch at once**: one task per piece of work, each already assigned to the project it belongs to.
-
-## How the batch is sequenced
-
-For each task it proposes, the agent declares a small **collision surface**: which files or directories it will touch, whether it adds a database migration, and whether it edits a widely-shared component. RoboCo turns those surfaces into conflict-free **waves** with a deterministic analyzer — no guesswork:
-
-- Tasks that touch the same files are **serialized** (the more important one first).
-- Tasks that add a migration run in a **serial chain**, never two at once.
-- A task that edits a shared surface runs **after** the tasks it overlaps.
-- Everything else runs **in parallel**.
-
-The waves are just ordinary task dependencies, so the same dependency-gate that already paces the rest of the company runs them: a wave starts only once the previous wave's tasks have reached a terminal state — normally each one's pull request is merged (a cancelled task releases the next wave too).
-
-The same collision-aware sequencing follows the work **down the chain**, not just at the top level. When a cell PM delegates a root-subtask into developer tasks, the dev-task collision surfaces flow through the same DAG — file-overlap serializes, migration-adders chain, shared-surface edits wait their turn — and cell tasks themselves wave-chain off their sibling root-subtasks. So a batch that spans a shared codebase stays ordered all the way to the leaves, not only at the umbrella. The task hierarchy is capped at four layers (umbrella → root → cell → dev) to fit this MegaTask shape.
-
-## What gets created
-
-When you confirm, RoboCo creates one **umbrella** task that groups the batch, and one **root-subtask** per piece of work:
-
-```mermaid
-graph TD
- U["MegaTask umbrella (no repo, no PR)"] --> A["Task A — project 1 own branch + PR"]
- U --> B["Task B — project 2 own branch + PR"]
- U --> C["Task C — project 3 own branch + PR"]
-```
-
-The **umbrella** is the batch's single review-and-approve unit. It does no git of its own — it spans repositories that have no common `master`, so there is no mega-PR. Each **root-subtask** is a normal piece of work in its own repository, with its own branch and its own pull request, coordinated by the Main PM down to the cells exactly like any other task. The umbrella finishes only when every task in it is done.
-
-## The two start buttons
-
-Like a single task, a MegaTask offers two start paths:
-
-- **Board review & Start** — the Product Owner and Head of Marketing review the **whole batch** first (they see every task and can adjust scope). The work is held until you approve the umbrella, then released wave by wave.
-- **Approve & Start** — the batch goes straight to the Main PM and the first wave dispatches immediately.
-
-Either way you review and approve the batch **once**, not task by task. After it launches, the umbrella and its tasks appear in your task views like any other work — you watch the waves progress, and each task lands as its own pull request for you to merge.
diff --git a/docs/company/merge-model.md b/docs/company/merge-model.md
deleted file mode 100644
index 42879f3b..00000000
--- a/docs/company/merge-model.md
+++ /dev/null
@@ -1,76 +0,0 @@
-# The merge model
-
-A feature in RoboCo isn't one commit on one branch — it's a small tree of work that converges, as real pull requests, up a fixed chain to your repository's default branch. The rule at the top is simple and absolute: **only you ever merge to `master`.**
-
-## Branches, commits, and PRs are traceable
-
-Every branch, commit, and pull request carries the task ID it belongs to, so your git history reads back to the work that produced it.
-
-- **Branches** follow `{type}/{team}/{task-hierarchy}`, where the hierarchy uses `--` between levels (a `/` would collide with git's ref storage). Types are `feature`, `bug`, `chore`, `docs`, `hotfix`.
-
- ```text
- feature/backend/ABC12345 # a root task
- feature/backend/ABC12345--DEF67890 # a subtask
- feature/backend/ABC12345--DEF67890--GHI11111 # a sub-subtask (max depth)
- ```
-
-- **Commits** are auto-prefixed with the short task ID: `[ABC12345] Add the auth endpoint`.
-- **Pull requests** are titled the same way: `[ABC12345] `.
-
-A branch is created automatically the moment an agent claims a task, and a **work session** tracks its branch, base, commits, files changed, and pull request from claim to merge.
-
-## Per-task worktrees
-
-An agent's clone is a single shared checkout, but a coordinator PM legitimately holds several in-progress roots at once. So instead of one checkout that each fresh claim `git reset --hard`s onto a new branch — destroying uncommitted work on the still-active first root — **each claimed task gets its own working tree** under the clone at `{clone}/.worktrees/{task-short}/`. The clone keeps the real `.git` object store and the shared `.venv`; each worktree symlinks that `.venv` so tools resolve without a per-task re-sync. The clone's `HEAD` is never moved by a claim, so a second task (or a PM's parallel roots) never overwrites a first task's uncommitted changes.
-
-Branch-by-name operations (`push`, `pull`, `merge`) run from the clone root as before; only the checkout/HEAD-moving operations (`create_branch`, `commit`, `rebase`) target the task's worktree. Exactly one active work session exists per task at a time, so a re-claim supersedes any stale prior session and re-points the worktree at the new claim. When a task reaches a terminal state (completed or cancelled), its worktree is removed best-effort; a task that bounces back through `needs_revision` keeps its worktree to keep working.
-
-## Work converges up a chain
-
-Each developer works in their **own clone** and opens a pull request from their branch. Those flow upward:
-
-```mermaid
-graph BT
- D1["dev branch"] --> C["cell branch"]
- D2["dev branch"] --> C
- C --> R["root / integration branch"]
- C2["other cell branch"] --> R
- R --> M["master"]
- M:::ceo
- classDef ceo fill:#1f6feb,color:#fff,stroke:#1f6feb;
-```
-
-1. **Developers → cell.** A cell's developers merge their work into the cell's branch.
-2. **Cell → root.** The **cell PM** runs `submit_up` to open the cell → root pull request. The Main PM keeps one integration (root) branch per repository.
-3. **Root → master.** The **Main PM** runs `submit_root` to open the final root → master pull request.
-
-Each of those assembled pull requests passes through the [in-path PR-review gate](task-lifecycle.md#the-in-path-pr-review-gate) before its PM merges it.
-
-## Submit gates that keep the chain clean
-
-Two gate-level checks stop a stale branch from sneaking through:
-
-- **Behind-base gate on `i_am_done`.** If a sibling's PR merged into the parent branch while the developer worked, the dev's branch is now behind its base and the assembled PR won't merge cleanly. The gate refuses `i_am_done` in that state and steers the developer to `sync_branch` — the gate-level rebase verb that rebases the branch onto its base (raw shell git is denied to agents, so the rebase goes through the gate, traced and evidenced). Conflicts abort with no force-push and point the dev at resolve-by-hand. The gate fails open on a flaky fetch so a transient git error can't strand a task at the submit gate.
-- **Unchanged-PR gate on `submit_root`.** When a Main-PM root PR is `pr_fail`'d and re-submitted byte-identical, the loop would repeat forever. The gate refuses the re-submit when the assembled root PR's head SHA is unchanged since the last `pr_fail` (no new cell work → identical diff); a different SHA means the branch advanced and the submit proceeds. Every ambiguous case fails open.
-
-PR operations are also **scoped per project** — `open_pr`, `pr_target`, `close_pull_request`, and `merge_pr` all require the project and resolve the PR number within it, so two tasks in different repos that happen to share a PR number can never collide and merge the wrong repository's PR.
-
-## Only the CEO merges to master
-
-The final pull request — root → master — is the one place the company stops and hands the decision back to you. It lands in your **CEO Approval Queue** and waits.
-
-- The agent-facing merge path **hard-refuses to target the default branch.** A PM can merge a cell PR up to the root, but the merge to `master` is reserved for the CEO action, taken from `awaiting_ceo_approval`.
-- **Force-push is CEO-only** too.
-
-From the queue you **Approve & Merge** (it ships to `master`), **Request Changes** (it loops back for another pass), or **Cancel**. This is the second of the only two moments the company needs you — the first being the green light that started the work.
-
-!!! info "Why a squash and one integration branch"
- Cell pull requests are squash-merged, so each cell's work lands as a single verified commit on the integration branch, co-authored by the agent that wrote it. The final pull request then carries one clean commit per cell — three streams of work folded into one reviewable history.
-
-## Pull requests you didn't open
-
-Not every pull request comes from inside the company. When an external contributor or a fork opens one against your repository, the read-only **PR Reviewer** reads the diff against your standards and posts a single change-request on the PR — it never chats, merges, or decides. The PR then surfaces in the **PR Review Queue** on the Command Center, where you **Supersede** it (the company cuts its own branch from the contributor's commits, hardens it, opens its own PR, and links back to the original once that merges) or **Dismiss** it. Either way the call is yours, and the org never pushes to anyone else's fork. *(This inbound-review flow is feature-flagged; see the optional-subsystems reference.)*
-
-## Next
-
-→ **[How agents are sandboxed](agent-gateway.md)** — why a developer agent literally cannot perform the merge.
diff --git a/docs/company/org-and-roles.md b/docs/company/org-and-roles.md
deleted file mode 100644
index 2503273d..00000000
--- a/docs/company/org-and-roles.md
+++ /dev/null
@@ -1,92 +0,0 @@
-# Org & roles
-
-RoboCo is **25 AI agents and one human — you, the CEO**. They're organized as a real company: a Board sets direction, a Main PM coordinates three delivery cells, and an Auditor watches everything. A few agents sit at your side on demand. You're on top of all of it.
-
-```mermaid
-graph TD
- CEO["👤 CEO — you (human)"]
-
- subgraph Support["At your side (on demand)"]
- INTAKE["Intake drafts tasks with you"]
- SEC["Secretary gated chief-of-staff"]
- PRR["PR Reviewer inbound + root→master gate"]
- end
-
- subgraph Board["Board"]
- PO["Product Owner"]
- HOM["Head of Marketing"]
- AUD["Auditor (silent)"]
- end
-
- MPM["Main PM coordinates the cells"]
-
- subgraph Cells["Delivery cells (6 agents each)"]
- BE["Backend cell"]
- FE["Frontend cell"]
- UX["UX/UI cell"]
- end
-
- CEO --- Support
- CEO --> Board
- Board --> MPM
- MPM --> BE & FE & UX
-```
-
-## The cells
-
-The three delivery cells — **Backend, Frontend, UX/UI** — are where code gets written. Each cell is a small, complete team of **six agents**:
-
-| Role | Count | What they do |
-|------|-------|--------------|
-| **Cell PM** | 1 | Runs the cell like an engineering manager: delegates, clears blockers, triages, and folds the cell's work up to the Main PM. |
-| **Developers** | 2 | Build the code in their own clones and open pull requests. |
-| **QA** | 1 | Reads the real diff and decides whether work ships or comes back. Doesn't rubber-stamp. |
-| **Documenter** | 1 | Writes down what was built, so the next agent — and you — don't start cold. |
-| **PR Reviewer** | 1 | Reviews the cell's assembled pull request at the in-path gate before the PM merges it up. |
-
-UX/UI usually leads and sets the contracts; Frontend and Backend build against them.
-
-## The Board and the Main PM
-
-| Role | Reports to | What they do |
-|------|-----------|--------------|
-| **Product Owner** | CEO | Turns your ask into requirements and acceptance criteria. |
-| **Head of Marketing** | CEO | Reviews work from the positioning / naming / user angle. |
-| **Auditor** | CEO | Silent observer with read access to *everything*; reports quality concerns to you and never interferes. |
-| **Main PM** | Board | Coordinates all three cells: fans a task out into per-cell subtasks, integrates the results, and opens the final pull request. |
-
-## At your side, on demand
-
-Three agents work directly with you rather than in the delivery flow. They run only while you're interacting with them or have given an explicit instruction:
-
-| Role | What they do |
-|------|--------------|
-| **Intake** | The conversational **Task Assistant** on the Prompter page. Reads your codebase and drafts a well-formed task with you. Chats only with you. |
-| **Secretary** | Your conversational chief-of-staff. Reads the whole company's state to advise you and executes your directives — but every high-impact action is **gated** for your explicit confirmation. It spends nothing and approves nothing on its own. |
-| **PR Reviewer** | The read-only main reviewer. Handles inbound external/fork pull requests and acts as the in-path gate on the final root → master pull request. It posts a review on the PR; it never chats, merges, or decides. |
-
-## The full roster
-
-25 agents, by their panel IDs:
-
-- **Backend:** `be-pm`, `be-dev-1`, `be-dev-2`, `be-qa`, `be-doc`, `be-pr-reviewer`
-- **Frontend:** `fe-pm`, `fe-dev-1`, `fe-dev-2`, `fe-qa`, `fe-doc`, `fe-pr-reviewer`
-- **UX/UI:** `ux-pm`, `ux-dev-1`, `ux-dev-2`, `ux-qa`, `ux-doc`, `ux-pr-reviewer`
-- **Coordination:** `main-pm`
-- **Board:** `product-owner`, `head-marketing`, `auditor`
-- **At your side:** `intake-1`, `secretary-1`, `pr-reviewer-1`
-
-## How agents talk
-
-Communication is constant and logged. Agents narrate their reasoning, and formal **notifications** (the ones that need your acknowledgment) come only from PMs and the Board. Channels are seeded automatically:
-
-- **Cell channels** — `#backend-cell`, `#frontend-cell`, `#uxui-cell`
-- **Cross-cell** — `#dev-all`, `#qa-all`, `#pm-all`, `#doc-all`
-- **Management** — `#main-pm-board`, `#board-private`
-- **Company-wide** — `#announcements` (read-only except Board / Main PM), `#all-hands`
-
-The **Auditor has silent read access to every channel.** You watch all of it from the **Communications** page.
-
-## Next
-
-→ **[The task lifecycle](task-lifecycle.md)** — the path every piece of work walks.
diff --git a/docs/company/task-lifecycle.md b/docs/company/task-lifecycle.md
deleted file mode 100644
index c62d95b0..00000000
--- a/docs/company/task-lifecycle.md
+++ /dev/null
@@ -1,92 +0,0 @@
-# The task lifecycle
-
-Everything in RoboCo is a task, and every task walks the same path. Each step is gated by role — only QA can pass QA, only the CEO can merge to `master` — so work can't skip a stage or land unreviewed. This is the backbone that makes the company trustworthy.
-
-```mermaid
-stateDiagram-v2
- direction LR
- [*] --> backlog
- backlog --> pending: PM activates
- pending --> claimed: agent claims
- claimed --> in_progress: start work
- in_progress --> verifying: self-verify
- verifying --> awaiting_qa: submit (PR is open)
- awaiting_qa --> awaiting_documentation: QA passes
- awaiting_qa --> needs_revision: QA fails
- needs_revision --> in_progress: rework
- awaiting_documentation --> awaiting_pm_review: docs done
- awaiting_pm_review --> completed: PM merges
- awaiting_pm_review --> awaiting_ceo_approval: escalate
- awaiting_ceo_approval --> completed: CEO approves & merges
- awaiting_ceo_approval --> needs_revision: CEO requests changes
- completed --> [*]
-
- in_progress --> blocked: external dependency
- in_progress --> paused: temporarily stopped
- blocked --> in_progress: unblocked
- paused --> in_progress: resumed
-```
-
-## The states
-
-| State | What it means | Who owns the next move |
-|-------|---------------|------------------------|
-| `backlog` | PM setup phase — dependencies or session setup still needed. | PM |
-| `pending` | Ready for work; the orchestrator can spawn an agent for it. | the matching role |
-| `claimed` | An agent has locked the task. | the assignee |
-| `in_progress` | Active development. | the assignee |
-| `blocked` | An external dependency is blocking progress. | whoever clears it |
-| `paused` | Temporarily stopped; can resume. | the assignee |
-| `verifying` | The developer is self-verifying before handing off. | the developer |
-| `awaiting_qa` | Submitted for QA — **a pull request is already open** so QA reviews the real diff. | QA |
-| `needs_revision` | QA, a PR reviewer, or the CEO asked for changes. | the developer |
-| `awaiting_documentation` | The Documenter writes up what was built (the PR is already open). | Documenter / Developer |
-| `awaiting_pr_review` | The in-path PR-review gate: a reviewer checks an assembled pull request before the PM merges it. | PR reviewer |
-| `awaiting_pm_review` | Docs are done; the PM reviews and merges. | PM |
-| `awaiting_ceo_approval` | A major task escalated to you for the final call. | **you** |
-| `completed` | Terminal — work done and merged. | — |
-| `cancelled` | Terminal — work cancelled. | — |
-
-!!! note "The PR comes *before* QA"
- A pull request is opened *before* QA review, not after. That lets QA read the actual PR diff on GitHub, and means the whole downstream approval chain — PM, then you — is signing off on a pull request that already exists.
-
-## When work is rejected
-
-Rejection isn't a dead end — it's a loop. When **QA fails** a task, or a **PR reviewer rejects** an assembled pull request, the task drops back to `needs_revision`, the developer reworks it, and it re-enters the flow. The same is true when *you* request changes from the CEO Approval Queue. Nothing is lost; the task carries its history, branch, and pull request with it the whole way around.
-
-A failed developer task is routed back to **the developer who worked it** (resolved from the work session), not the pool — so the revision lands with whoever has the context, rather than being re-claimed cold by a cell PM. Only a task no developer ever touched falls back to the pool.
-
-## The in-path PR-review gate
-
-Most leaf developer tasks are reviewed by QA and never need a separate PR review. But when work is **assembled and pushed up the chain as a pull request**, it stops for a dedicated review before any PM merges it:
-
-```mermaid
-stateDiagram-v2
- direction LR
- in_progress --> awaiting_pr_review: submit_up / submit_root
- awaiting_pr_review --> awaiting_pm_review: pr_pass
- awaiting_pr_review --> needs_revision: pr_fail
-```
-
-- A **cell PM** runs `submit_up` to open the cell → root pull request.
-- The **Main PM** runs `submit_root` to open the root → master pull request.
-- Both land in `awaiting_pr_review`, where a PR reviewer either **`pr_pass`es** it on to the PM merge or **`pr_fail`s** it back to `needs_revision`.
-
-This gives the merge step a real reviewer with the power to reject — the one thing a PM otherwise lacks. **Leaf dev tasks and branchless coordination roots skip the gate.**
-
-## Role-gated transitions
-
-Transitions aren't suggestions; they're enforced. A handful of the rules:
-
-- **Activating** a task (`backlog → pending`) is PM-only.
-- **Passing or failing QA** is QA-only, and a pass requires real review notes.
-- **`pr_pass` / `pr_fail`** are PR-reviewer-only.
-- **Merging** (`awaiting_pm_review → completed`) is PM-only; **escalating to the CEO** and the final **approve / request-changes / cancel** are CEO-only.
-- **Cancelling** is PM-only.
-- **A Main-PM coordination root can never be `task_type=code`.** The Main PM coordinates; it doesn't write code itself, so the combination is rejected at creation — a structural guard, not a hint.
-
-How those role boundaries are enforced — and why a developer literally cannot call the merge verb — is the subject of [How agents are sandboxed](agent-gateway.md).
-
-## Next
-
-→ **[The merge model](merge-model.md)** — how a task's branch travels up to `master`.
diff --git a/docs/deploy/bootstrap-and-seeds.md b/docs/deploy/bootstrap-and-seeds.md
deleted file mode 100644
index edde170f..00000000
--- a/docs/deploy/bootstrap-and-seeds.md
+++ /dev/null
@@ -1,56 +0,0 @@
-# Bootstrap & seeds
-
-A fresh RoboCo database isn't an empty shell — it comes pre-populated with the whole org chart: every agent, every communication channel, and the welcome messages that establish the channels. This page covers what `make db-init` seeds, and the console entry points that run the bootstrap.
-
-## `make db-init` — seed a fresh instance
-
-The one command you need to bring a clean database to life:
-
-```bash
-make db-init
-```
-
-This runs `python -m roboco.cli --db-only`, which enables the schema (the [migration chain](./data-and-migrations.md)) and then seeds the company in a single transaction.
-
-!!! tip "It's idempotent — safe to re-run"
- Every seed operation skips what already exists (agents and channels by slug; welcome messages are skipped if the channel already has any). Running `make db-init` against an already-seeded database is a harmless no-op, so you can re-run it any time without fear of duplicates.
-
-## What gets seeded
-
-| Seeded data | Detail |
-|-------------|--------|
-| **26 agent rows** | The 25 AI agents **plus the human CEO** ("Renzo"), each with a stable static UUID. A `system` sentinel row is also appended (it's the FK target for system-authored messages and lives outside the team enum). |
-| **11 channels** | The 3 cell channels (`#backend-cell`, `#frontend-cell`, `#uxui-cell`), the 4 cross-role channels (`#dev-all`, `#qa-all`, `#pm-all`, `#doc-all`), and the management/special channels (`#main-pm-board`, `#board-private`, `#announcements`, `#all-hands`). |
-| **Channel memberships** | Who can read and write each channel, plus the **Auditor's silent-observer access** to every channel. |
-| **Welcome messages** | An opening message seeded into `#announcements`, `#all-hands`, and the three cell channels (each first spins up the backing group and session). |
-
-The roster and the seeded UUIDs are derived from the foundation catalog (`roboco/foundation/identity.py` for agents, `roboco/foundation/policy/communications.py` for channels), so the seed data and the runtime role/permission rules can never drift apart. For the full org chart and who sits in which channel, see [Org & roles](../company/org-and-roles.md).
-
-## The console entry points
-
-`make db-init` is a thin wrapper over the CLI. The supported way to invoke RoboCo directly is the module form:
-
-```bash
-python -m roboco.cli --db-only # seed the DB and exit (what make db-init runs)
-python -m roboco.cli # seed + start the full orchestrator stack
-python -m roboco.cli --skip-db # start the stack against an already-seeded DB
-python -m roboco.cli --spawn be-dev-1 fe-dev-1 # also spawn the named agents on boot
-```
-
-`python -m roboco.cli` is what the orchestrator container runs and what `make db-init` / `make` targets call. Full system start does more than seed: it brings up the Redis event bus, constructs the orchestrator, starts the API under uvicorn, polls `/health` until the FastAPI lifespan finishes indexing (up to ~2 minutes), then begins dispatching.
-
-!!! note "`python -m roboco.cli` is the working invocation"
- `pyproject.toml` declares two console scripts, `roboco` and `roboco-bootstrap`. Use `python -m roboco.cli` (or `make db-init`) — that's the invocation the Makefile and the container use and the one that's verified to work. `roboco-bootstrap` maps to the same bootstrap routine; the bare `roboco` console script is not the supported path.
-
-## Required configuration before first boot
-
-Bootstrap itself needs almost nothing, but the orchestrator will refuse to start without two secrets:
-
-- **`ROBOCO_ENCRYPTION_KEY`** — the Fernet key that encrypts project GitHub tokens. Its config default is an empty string, but startup is mandatory: no key, no boot.
-- **`ROBOCO_AGENT_AUTH_SECRET`** — the HMAC secret that signs agent tokens. Unset, every token is treated as unsigned.
-
-Everything else has a sensible default. See the [environment reference](./env-reference.md) for the full list, and [Deployment](./deployment.md) for the compose host-path mounts.
-
-## Next
-
-→ [Data & migrations](./data-and-migrations.md) — the entities you just seeded, and how the schema stays current. → [Org & roles](../company/org-and-roles.md) — the workforce these seeds create.
diff --git a/docs/deploy/data-and-migrations.md b/docs/deploy/data-and-migrations.md
deleted file mode 100644
index 5c4130f1..00000000
--- a/docs/deploy/data-and-migrations.md
+++ /dev/null
@@ -1,74 +0,0 @@
-# Data & migrations
-
-RoboCo keeps all of its state in PostgreSQL. There is no separate document store, no schema you have to hand-build, and — in normal operation — no migration command you have to remember. This page gives you the operator's-eye view: the handful of entities worth understanding, the one hard database requirement (pgvector), and how the schema keeps itself up to date.
-
-## The entities you'll actually see
-
-The full data model spans about thirty Pydantic models in `roboco/models/` with matching SQLAlchemy tables in `roboco/db/tables.py`. You don't need most of them. These are the ones that show up across the panel and explain how work flows:
-
-| Entity | What it is |
-|--------|------------|
-| **Task** | The atomic unit of work. Carries its acceptance criteria, status (the 15-state [lifecycle](../company/task-lifecycle.md)), priority, branch name, PR number/URL, ownership (`created_by` / `assigned_to` / `team`), and its place in the tree (`parent_task_id`, `dependency_ids`, `blocker_ids`). A task points at **exactly one** of a `project_id` or a `product_id` — a single-repo task uses the project, a Board/fan-out coordination task uses the product. A validator enforces "one or the other, never both." |
-| **Project** | A git repository configuration: `git_url`, default branch, protected branches, the Fernet-encrypted GitHub PAT (`git_token_encrypted` — the API only ever returns `has_git_token`, never the token), the per-project CI/gate commands, and the assigned cell. See [Register your first project](../get-started/first-project.md). |
-| **WorkSession** | The link between an agent, a task, and a branch. One is created each time an agent claims a task. It tracks the base/target branches, the commits made, the files modified, the PR and merge outcome, and (when toolchain matching is on) the resolved Python version and toolchain status. |
-| **Agent** | One row per member of the workforce — role, team, status — plus the human CEO. See [Org & roles](../company/org-and-roles.md). |
-| **Session / Channel / Message** | The communication substrate. A `Channel` is a room; a `Session` is a live conversation inside it; a `Message` is one extracted line of an agent's stream. |
-| **Notification** | A formal signal that requires acknowledgment (sent by PMs and the Board), distinct from the constant message stream. |
-| **Journal** | Each agent's personal log of reflections and learnings, with `JournalEntry` rows underneath. |
-
-Two newer entities round out the company-in-a-box features: **Product** (with `ProductProject`, the per-cell repo-routing map for fan-out work) and **Pitch** (a Board proposal that the CEO approves and that can auto-provision a repo). You'll meet these on the [Business](../panel/business.md) page.
-
-## pgvector is required
-
-RoboCo's in-house RAG engine stores embeddings in PostgreSQL using the **pgvector** extension. The orchestrator enables it for you at startup (`CREATE EXTENSION IF NOT EXISTS vector`), so the bundled `postgres` image — which ships pgvector — works out of the box.
-
-!!! warning "If pgvector isn't installed"
- On a bring-your-own PostgreSQL where the `vector` extension isn't available, the orchestrator logs a warning and **RAG features silently disable** — agents lose the knowledge base and mentor lookups, but the rest of the system runs. If you point RoboCo at an external Postgres, make sure pgvector is installed there.
-
-Operationally, **PostgreSQL and Redis are the only two stateful services to back up.** Everything the company knows lives in Postgres; Redis holds the event bus and short-lived coordination state.
-
-!!! danger "The encryption key is not in the database"
- Each project's GitHub PAT is stored encrypted with `ROBOCO_ENCRYPTION_KEY`. A database backup **without that key is useless for the tokens** — you'll be able to restore every project except its credentials. Keep the key safe and separate. See the [environment reference](./env-reference.md).
-
-## The stack migrates itself on startup
-
-You almost never run a migration command by hand. When the orchestrator boots, `init_db()` enables pgvector and then `run_migrations()` runs `alembic upgrade head` in a worker thread:
-
-```mermaid
-flowchart LR
- A[Orchestrator starts] --> B[init_db: enable pgvector]
- B --> C[run_migrations: alembic upgrade head]
- C --> D[create_all gap-fill on existing DB]
- D --> E[dispose pool to refresh enum cache]
- E --> F[API ready]
-```
-
-The practical consequence: **a normal `docker compose up` / restart already applies any new migrations.** A fresh database is built entirely by the migration chain from base; an existing one runs only the pending steps (a pre-Alembic database is auto-stamped at the initial revision first, so it isn't re-built).
-
-!!! tip "The manual command is belt-and-suspenders"
- The documented manual step — after pulling a change that adds a migration —
-
- ```bash
- docker compose exec orchestrator alembic upgrade head
- ```
-
- is a safety net, not a routine requirement, since the orchestrator runs the same command on boot. In host-dev mode (no container) the equivalent is `uv run alembic upgrade head`, or `make migrate`.
-
-## A fresh DB is built by migrations, not `create_all` { #fresh-db-gotcha }
-
-This is the one gotcha that bites operators who try to reset state by hand. Several migrations embed **seed data** — most importantly the LLM provider rows (Anthropic, Ollama, self-hosted, Grok). The schema must be built by **running the migration chain**, never by a bare SQLAlchemy `create_all`.
-
-!!! warning "Don't reset a database with `create_all`"
- A `create_all`-only database has empty `provider_configs`, so the Settings → Providers endpoints return **404**. The fix is always the same: let the migrations run (restart the orchestrator, or run `alembic upgrade head`). The orchestrator's own startup uses `create_all` only as a *gap-fill* on an already-migrated database, never as the builder.
-
-## Contributor notes
-
-If you write or review custom migrations:
-
-- **Revision-id length is capped at 32 characters.** PostgreSQL stores `alembic_version.version_num` as `VARCHAR(32)`. A longer id breaks a live `upgrade` even though the test suite (which renders offline / uses `create_all`) never catches it. The chain currently has **54 revisions** (55 files — revision `026` is split into two consecutive steps); the head is `054_a2a_message_skill`, and the longest id in the tree is `015_drop_task_execution_outputs` at 31 characters, deliberately just under the limit.
-- **The chain is linear.** Every revision has a single `down_revision`; there are no branches or merges to reconcile.
-- **Models, tables, and migrations must stay in sync.** A Pydantic model in `roboco/models/`, its ORM table in `roboco/db/tables.py`, and the migration that creates the column are three layers that move together.
-
-## Next
-
-→ [Bootstrap & seeds](./bootstrap-and-seeds.md) — what `make db-init` puts into a fresh database. → [Environment reference](./env-reference.md) — every `ROBOCO_DATABASE_*` knob and the encryption key.
diff --git a/docs/deploy/deployment.md b/docs/deploy/deployment.md
deleted file mode 100644
index d859caed..00000000
--- a/docs/deploy/deployment.md
+++ /dev/null
@@ -1,178 +0,0 @@
-# Production deploy
-
-This is the operator reference for running RoboCo on a NAS or server. If you just want it up on your laptop, the [install quickstart](../get-started/installation.md) is faster — this page assumes you've done that once and now want the durable, server-side setup: the compose files, the host mounts agents need, where data lives, how to back it up, and how to harden it.
-
-!!! warning "Trusted network only"
- RoboCo is built for a private LAN or homelab. Do not expose it directly to the public internet. nginx is the single entry point, but the orchestrator's WebSocket streams and (in header-trust mode) its API assume a trusted network. Put it behind your own VPN if you need remote access.
-
-## The three compose files
-
-There are **three tracked compose files**, and they are not interchangeable:
-
-| File | What it does | Needs a build toolchain? |
-|------|--------------|--------------------------|
-| `docker-compose.yml` | Builds every image from the Dockerfiles in `docker/`. | Yes |
-| `docker-compose.yaml` | **Byte-identical** to `docker-compose.yml`. | Yes |
-| `docker-compose.registry.yml` | Pulls and runs the **pre-built published images**. | No |
-
-`docker-compose.yml` and `docker-compose.yaml` are the same file under two names — Docker Compose picks up either, and the NAS deployment runs the `.yaml`. If you fork RoboCo and change a service, keep all three in sync.
-
-### Which one to run
-
-For a server you don't intend to hack on, run the **registry** file — it pulls finished images and needs no source tree or compiler on the host:
-
-```bash
-docker compose -f docker-compose.registry.yml pull
-docker compose -f docker-compose.registry.yml up -d
-```
-
-Two variables choose what you pull (defaults shown):
-
-```bash
-ROBOCO_REGISTRY=ghcr.io/rennf93 # or docker.io/renzof93
-ROBOCO_VERSION=latest # or a pinned release, e.g. 0.15.0
-```
-
-The orchestrator then spawns the **matching** pre-built agent images on demand (it reads `ROBOCO_AGENT_IMAGE_REGISTRY` / `ROBOCO_AGENT_IMAGE_TAG`, which the registry compose wires to the same registry and version). Pin `ROBOCO_VERSION` to a release tag in production so an upstream `latest` push can't silently change your fleet.
-
-Build from source only when you're modifying RoboCo:
-
-```bash
-docker compose up -d # builds on first run
-```
-
-!!! note "Agent images are build/pull-only services"
- The `agent-*-image` services in every compose file are one-shot stubs — they exist so `docker compose build`/`pull` materializes each per-role agent image up front. They never run as long-lived containers. The orchestrator spawns the actual agent containers itself, on demand, over the mounted Docker socket, and tears them down when their work is done.
-
-## The single origin
-
-nginx (`docker/nginx.conf`, rendered from an envsubst template) is the only externally-exposed service. It listens on `localhost:3000` and routes by path:
-
-```mermaid
-flowchart LR
- B[Browser :3000] --> N[nginx]
- N -->|/| P[panel:3000]
- N -->|/api/, /ws/, /health, /ready| O[orchestrator:8000]
-```
-
-| Path | Upstream |
-|------|----------|
-| `/api/`, `/ws/`, `/health`, `/ready` | `roboco-orchestrator:8000` |
-| everything else | `roboco-panel:3000` |
-
-The browser only ever sees one origin (`:3000`), so there's no CORS to configure — the panel uses relative `/api` and `/ws` URLs and lets nginx dispatch. The panel container is never published directly; you reach it only through nginx. `/ws/` also gets a long (86400s) read timeout so live sockets stay open.
-
-The backing services *do* publish host ports for direct inspection — Postgres on **15432**, Redis on **16379**, Ollama on **11435**, and the orchestrator on **8000**. You don't route browser traffic at these; they're there for `psql`, `redis-cli`, and the like.
-
-## Required host-path mounts
-
-The orchestrator is Docker-in-Docker: it mounts `/var/run/docker.sock` and spawns agent containers itself. Because those agent bind-mounts resolve on the **host** daemon (not inside the orchestrator container), several paths must be given as **absolute host paths** — the orchestrator passes them straight through to `docker run -v` for each agent.
-
-| Variable | What it points at | Compose default |
-|----------|-------------------|-----------------|
-| `ROBOCO_HOST_PROJECT_DIR` | The RoboCo project directory on the host. | `/volume1/roboco` |
-| `ROBOCO_HOST_CLAUDE_DIR` / `CLAUDE_AUTH_DIR` | The host `~/.claude` Claude Code auth dir, mounted into the orchestrator and each agent. | `/home/renzof/.claude` / `${HOME}/.claude` |
-| `ROBOCO_HOST_DATA_DIR` | The host data dir handed to agents for shared volumes (workspaces, logs, grok-usage). | `/volume1/roboco/data` |
-| `ROBOCO_DATA_DIR` | Host root for all persistent volumes mounted into the *backing* services and orchestrator (see below). | `./data` |
-| `ROBOCO_HOST_GROK_DIR` | Host `~/.grok` SuperGrok auth — only needed if you run any agent on Grok. | `/home/renzof/.grok` |
-
-!!! danger "These must be real, absolute host paths"
- A relative path or a path that only exists *inside* the orchestrator container will make agent spawns fail, because the host Docker daemon resolves the bind. On a NAS the project and data dirs usually live on the RAID volume (e.g. `/volume1/roboco` and `/volume1/roboco/data`).
-
-The host `~/.grok` is mounted **read-write** into the orchestrator (it rewrites the short-lived token in place to keep agents from hanging on an expired login) and **read-only** into each Grok agent. Run `grok login` on the host once before enabling Grok. Provider routing and the Grok runtime are covered in the models section.
-
-## Data persistence and backup
-
-Everything durable lives under `ROBOCO_DATA_DIR` (default `./data`). On a server, point this at a RAID volume:
-
-```bash
-ROBOCO_DATA_DIR=/volume1/roboco/data
-```
-
-| Subdirectory | Holds |
-|--------------|-------|
-| `postgres/` | The entire database — tasks, projects, work sessions, journals, encrypted git tokens, the pgvector store. |
-| `redis/` | Append-only cache, sessions, rate-limit + event-bus state. |
-| `ollama/` | The local model cache (embedding model + local LLM) — large, but re-pullable. |
-| `workspaces/` | Each agent's git clone of each project. |
-| `logs/` | Per-agent run logs. |
-| `mcp-configs/`, `prompts-generated/`, `agent-settings/`, `briefings/`, `manifests/` | Per-agent spawn artifacts the orchestrator writes. |
-| `grok-usage/` | Per-agent Grok cost/usage capture. |
-
-For backup, the load-bearing directory is `postgres/` (everything that isn't re-derivable). `ollama/` and `workspaces/` are reconstructible — Ollama re-pulls models, agents re-clone repos — so they're optional in a backup. Take Postgres backups with `pg_dump` against the published port rather than copying the live data directory:
-
-```bash
-pg_dump -h localhost -p 15432 -U roboco roboco > roboco-backup.sql
-```
-
-!!! danger "Back up `ROBOCO_ENCRYPTION_KEY` with the database"
- Every per-project GitHub token in the database is Fernet-encrypted with `ROBOCO_ENCRYPTION_KEY`. **A database backup is useless without the key.** If you lose or change the key, every stored token becomes undecryptable and must be re-entered project by project. Store the key with your secrets, keep it stable across restarts, and never commit `.env`.
-
-## Secure mode
-
-On a trusted LAN RoboCo runs in **header-trust mode** by default (`ROBOCO_AGENT_AUTH_REQUIRED=false`): callers are identified by role headers, no token required. That's the intended homelab setup.
-
-To harden it so one agent can't spoof another's role, turn on fail-closed auth:
-
-```bash
-ROBOCO_AGENT_AUTH_REQUIRED=true
-ROBOCO_AGENT_AUTH_SECRET= # already required for docker compose
-ROBOCO_PANEL_AGENT_TOKEN=
-```
-
-With auth required, every API call must carry a valid `X-Agent-Token`. The panel runs in your browser and can't hold the signing secret, so nginx injects the CEO's token for it: generate the token with `make panel-token` (it signs one using your `ROBOCO_AGENT_AUTH_SECRET`), put it in `ROBOCO_PANEL_AGENT_TOKEN`, and nginx adds it as `X-Agent-Token` on `/api` and `/ws`. The panel keeps working; the secret never reaches the browser.
-
-`ROBOCO_ENCRYPTION_KEY` and `ROBOCO_AGENT_AUTH_SECRET` are both **required** for any docker compose run — the orchestrator service block guards them with compose `:?` so the stack refuses to start if either is unset. See [Security](../troubleshooting/security.md) for the full sandboxing model and [the env reference](./env-reference.md) for every knob.
-
-## Startup sequence
-
-`depends_on` conditions enforce a strict boot order; the effective sequence is:
-
-```mermaid
-flowchart LR
- PG[postgres] --> OL[ollama]
- RD[redis] --> OL
- OL --> OI[ollama-init]
- OI --> OR[orchestrator]
- AB[agent-base-image] --> OR
- OR --> PN[panel]
- PN --> NG[nginx]
- OR --> NG
-```
-
-- **postgres / redis / ollama** must each pass their healthcheck (`pg_isready`, `redis-cli ping`, `ollama list`) before anything downstream starts.
-- **ollama-init** is a one-shot that best-effort pulls the embedding model and the local LLM, then gates success on the models being **present** — a degraded model registry can't take down a fully-cached deployment.
-- **orchestrator** waits for postgres + redis + ollama healthy, ollama-init completed, and agent-base-image built. On startup it **runs the database migrations itself** (idempotently, to head) and indexes its knowledge base — you do not run `alembic upgrade head` by hand for the compose path.
-- **panel** waits for the orchestrator; **nginx** waits for both.
-
-First boot is the slow one: the model pulls (the LLM is a couple of minutes) plus knowledge-base indexing. Watch it come up:
-
-```bash
-docker compose logs -f orchestrator
-curl http://localhost:8000/health
-docker ps --filter name=roboco
-```
-
-When the orchestrator reports serving, open `http://localhost:3000`. A boot that hangs is almost always waiting on `ollama-init` (model pull) or a healthcheck — check `docker compose ps` to see which service is still `starting`. Migration and data details are in [Data & migrations](./data-and-migrations.md); recurring boot symptoms are in [Common issues](../troubleshooting/common-issues.md).
-
-## Operator-relevant Makefile targets
-
-The `Makefile` drives the **host** developer workflow (uv-based, for hacking on RoboCo itself) — it is separate from the Docker stack and needs `uv` on the host. The handful that matter operationally:
-
-| Target | Does |
-|--------|------|
-| `make panel-token` | Prints a signed CEO token for `ROBOCO_PANEL_AGENT_TOKEN` (secure mode). |
-| `make infra` | Brings up only postgres + redis (`make infra-down` stops them) — for host-side dev against the backing services. |
-| `make migrate` | Runs `alembic upgrade head` on the host (the compose stack self-migrates; this is the host-dev path). |
-| `make run` | Runs the API + orchestrator on the host (no `--reload`); `make api` is the reload dev server, `make dev` runs both. |
-| `make quality` | The full merge gate: ruff format-check + lint, mypy, pytest with 80% coverage floor, complexity, security, dependency, and migration checks. |
-| `make serve-docs` | Serves this documentation locally with `mkdocs serve`. |
-| `make status` / `make logs` | Orchestrator status / recent logs against a running instance. |
-
-Run `make help` for the full list.
-
-## Next
-
-- **[Environment reference](./env-reference.md)** — every `ROBOCO_*` setting, with defaults and on/off state.
-- **[Data & migrations](./data-and-migrations.md)** — the self-migrating schema and what to back up.
-- **[Security](../troubleshooting/security.md)** — the full agent sandboxing and auth model.
diff --git a/docs/deploy/env-reference.md b/docs/deploy/env-reference.md
deleted file mode 100644
index 2be563f0..00000000
--- a/docs/deploy/env-reference.md
+++ /dev/null
@@ -1,314 +0,0 @@
-# Environment reference
-
-This is the canonical list of every `ROBOCO_*` setting. They are all read by a single Pydantic-Settings class (`roboco/config.py`), loaded from the process environment and `.env`, prefixed with `ROBOCO_`, and case-insensitive. Most have a working default; the few that don't, and the ones the orchestrator refuses to start without, are flagged below.
-
-!!! tip "You rarely set most of these"
- For a working deploy you set the two required secrets, the host paths, and maybe a feature flag or two. The long tables here exist so that when you *do* need to tune a timeout or a window, you can find it. The defaults shown are RoboCo's config defaults; a few compose-only defaults differ and are called out.
-
-A feature flag set in `.env` takes effect on the next backend restart. The env-gated subsystems can also be toggled from the panel's **Settings → Feature Flags** card, which persists to the settings store and overrides the env default; an unset toggle falls back to the env/config default. See the [Optional capabilities](../optional/index.md) section for what each subsystem does.
-
-## Required secrets
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_ENCRYPTION_KEY` | *(empty — required)* | Fernet key encrypting every per-project git token at rest. The orchestrator **refuses to start** without it (compose `:?` guard). Generate with `python -c 'from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())'`. Keep it stable — losing it makes stored tokens undecryptable. |
-| `ROBOCO_AGENT_AUTH_SECRET` | *(empty — required for compose)* | HMAC secret signing the per-agent `X-Agent-Token`. Generate with `python -c 'import secrets; print(secrets.token_hex(32))'`. |
-
-## Security & auth
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_AGENT_AUTH_REQUIRED` | `false` | Fail-closed secure mode. When `true`, every API call must carry a valid token. Requires `ROBOCO_PANEL_AGENT_TOKEN` to keep the panel working. On a trusted LAN, leave `false` (header-trust mode). |
-| `ROBOCO_PANEL_AGENT_TOKEN` | *(empty)* | The CEO token nginx injects as `X-Agent-Token` on `/api` and `/ws` in secure mode, so the panel works without the browser holding the signing secret. Generate with `make panel-token`. |
-
-## Application & API server
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_APP_VERSION` | `0.15.0` | Reported app version. |
-| `ROBOCO_DEBUG` | `false` | Debug mode. |
-| `ROBOCO_ENVIRONMENT` | `development` | One of `development` / `staging` / `production`. Selects the JSON log renderer (prod) vs console renderer. The compose stack sets `production`. |
-| `ROBOCO_HOST` | `127.0.0.1` | Bind address. Use `0.0.0.0` in containers. |
-| `ROBOCO_PORT` | `8000` | API port. |
-| `ROBOCO_API_URL` | *(unset)* | Override base URL for containerized agents (e.g. `http://roboco-orchestrator:8000`); otherwise built from host/port. |
-| `ROBOCO_CORS_ORIGINS` | `["http://localhost:3000","http://localhost:5173"]` | Allowed CORS origins. The single-origin nginx setup means you rarely change this. |
-| `ROBOCO_CORS_ALLOW_CREDENTIALS` | `true` | Whether CORS allows credentials. |
-| `ROBOCO_PUBLIC_BASE_URL` | `http://127.0.0.1:8000` | Reachable base URL embedded in commit-trailer links — set to your LAN IP or domain so the links resolve. |
-
-## Database
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_DATABASE_HOST` | `localhost` | Postgres host (`roboco-postgres` in compose). |
-| `ROBOCO_DATABASE_PORT` | `5432` | Postgres port. |
-| `ROBOCO_DATABASE_USER` | `roboco` | Postgres user. |
-| `ROBOCO_DATABASE_PASSWORD` | `roboco` | Postgres password — change it for any real deployment. |
-| `ROBOCO_DATABASE_NAME` | `roboco` | Database name. |
-| `ROBOCO_DATABASE_ECHO` | `false` | Log every SQL statement. |
-| `ROBOCO_DATABASE_POOL_SIZE` | `10` | Connection pool size. |
-| `ROBOCO_DATABASE_MAX_OVERFLOW` | `20` | Extra connections beyond the pool. |
-| `ROBOCO_DATABASE_POOL_TIMEOUT` | `10` | Seconds to wait for a pooled connection. |
-| `ROBOCO_DATABASE_POOL_RECYCLE` | `1800` | Recycle a connection after this many seconds. |
-
-## Redis
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_REDIS_HOST` | `localhost` | Redis host (`roboco-redis` in compose). |
-| `ROBOCO_REDIS_PORT` | `6379` | Redis port. |
-| `ROBOCO_REDIS_DB` | `0` | Redis logical DB. |
-| `ROBOCO_REDIS_PASSWORD` | *(unset)* | Optional Redis password. |
-
-## RAG, embeddings & Ollama
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_RAG_PERSIST_DIR` | `.roboco` | Local RAG persistence dir. |
-| `ROBOCO_RAG_CHUNK_STRATEGY` | `fixed` | One of `fixed` / `semantic` / `hierarchical` / `contextual`. `fixed` recommended; `semantic` loads an extra model. |
-| `ROBOCO_RAG_CHUNK_SIZE` | `512` | Base chunk size. |
-| `ROBOCO_RAG_CHUNK_SIZE_DOCS` | `1536` | Chunk size for docs. |
-| `ROBOCO_RAG_CHUNK_SIZE_JOURNALS` | `1024` | Chunk size for journals/reflections. |
-| `ROBOCO_RAG_CHUNK_OVERLAP` | `128` | Chunk overlap. |
-| `ROBOCO_RAG_AUTO_UPDATE_ENABLED` | `true` | Whether the RAG index auto-refreshes. |
-| `ROBOCO_RAG_AUTO_UPDATE_INTERVAL` | `300` | Seconds between auto-updates. |
-| `ROBOCO_ANTHROPIC_API_KEY` | *(unset)* | Optional Anthropic key. Agents use the mounted Claude Code auth, not a metered key. |
-| `ROBOCO_DEFAULT_EMBEDDING_MODEL` | `qwen3-embedding:0.6b` | Embedding model (1024-dim). |
-| `ROBOCO_EMBEDDING_DIMENSIONS` | `1024` | Embedding dimensions — must match the model. |
-| `ROBOCO_LOCAL_LLM_MODEL` | `glm-5.2:cloud` | Local LLM for RAG answer synthesis. |
-| `ROBOCO_LOCAL_LLM_BASE_URL` | `http://roboco-ollama:11434/v1` | Ollama OpenAI-compatible endpoint. |
-| `ROBOCO_OLLAMA_BASE_URL` | `http://roboco-ollama:11434` | Ollama native endpoint (embeddings, model management). |
-
-## Workspaces & git timeouts
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_WORKSPACES_ROOT` | `/data/workspaces` | Root for all agent git clones. |
-| `ROBOCO_WORKSPACE_AUTO_CLONE` | `true` | Auto-clone a repo on first workspace access. |
-| `ROBOCO_WORKSPACE_CLONE_TIMEOUT` | `300` | Seconds for a `git clone`. |
-| `ROBOCO_WORKSPACE_REFRESH_FETCH_TIMEOUT_SECONDS` | `60` | Timeout for the best-effort `git fetch` on re-entry into a healthy clone. |
-| `ROBOCO_WORKSPACE_INSTALL_DEV_DEPS` | `true` | After cloning, install the project's dev dependencies into the workspace so `make quality` runs without re-downloading tooling. |
-| `ROBOCO_WORKSPACE_DEP_INSTALL_TIMEOUT_SECONDS` | `600` | Timeout for that post-clone dependency install. |
-| `ROBOCO_GIT_COMMAND_TIMEOUT_SECONDS` | `30` | Timeout for a single local git subprocess (status, log, checkout). |
-| `ROBOCO_GIT_COMMIT_TIMEOUT_SECONDS` | `180` | Timeout for staging + committing a changeset. |
-| `ROBOCO_GIT_NETWORK_TIMEOUT_SECONDS` | `120` | Timeout for git ops that talk to origin (fetch / pull / push). |
-| `ROBOCO_PROTECTED_GIT_URLS` | *(empty)* | Repo URL substrings a project may not point at — blocks agent commits/merges from reaching a protected repo. |
-| `ROBOCO_SESSION_IDLE_TIMEOUT_SECONDS` | `3600` | Idle seconds before a messaging session is swept closed. |
-
-## Agent images (spawn source)
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_AGENT_IMAGE_REGISTRY` | *(empty)* | Registry namespace for pre-built agent images (e.g. `ghcr.io/rennf93`). Empty = build locally. The registry compose wires this to `ROBOCO_REGISTRY`. |
-| `ROBOCO_AGENT_IMAGE_TAG` | *(empty)* | Tag for pre-built agent images (e.g. `0.9.0`). Empty = implicit `:latest`. The registry compose wires this to `ROBOCO_VERSION`. |
-
-!!! note "Deploy-time variables (compose, not config.py)"
- A few variables are consumed by the compose files and host-mount wiring rather than by `config.py`: `ROBOCO_REGISTRY`, `ROBOCO_VERSION`, `ROBOCO_DATA_DIR`, `ROBOCO_HOST_PROJECT_DIR`, `ROBOCO_HOST_CLAUDE_DIR` / `CLAUDE_AUTH_DIR`, `ROBOCO_HOST_DATA_DIR`, and `ROBOCO_HOST_GROK_DIR`. They are documented in the [production deploy reference](./deployment.md#required-host-path-mounts).
-
-## Transcript retention
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_TRANSCRIPT_RETENTION_DAYS` | `14` | Days to keep agent Claude Code transcripts. A stored panel setting overrides this default. |
-| `ROBOCO_TRANSCRIPT_PRUNE_ENABLED` | `true` | Whether the background sweep prunes old transcripts. |
-| `ROBOCO_TRANSCRIPT_PRUNE_INTERVAL_SECONDS` | `3600` | Minimum seconds between prune passes. |
-
-## Spawn pacing, SLAs & reaper windows
-
-The orchestrator's dispatcher uses these to pace spawns, detect loops, and reclaim stuck work. Defaults are tuned for real LLM latency — raise the reaper windows (not lower) if long agent tasks are being reaped mid-work.
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_AGENT_TOOL_CALL_WARN` | `50` | Soft warning threshold for per-session tool calls. |
-| `ROBOCO_AGENT_TOOL_CALL_HALT` | `150` | Hard cap on per-session tool calls; the orchestrator stops the container. |
-| `ROBOCO_AGENT_LOOP_THRESHOLD` | `3` | Identical tool+args repeats in the window that flag a loop. |
-| `ROBOCO_AGENT_LOOP_WINDOW` | `10` | How many recent tool calls to inspect for loop detection. |
-| `ROBOCO_AGENT_STOP_ATTEMPT_ALLOWANCE` | `1` | Stop-without-terminal attempts before auto-substitute. |
-| `ROBOCO_AGENT_SLA_DEVELOPER_IN_PROGRESS` | `7200` | SLA (s) for a developer in `in_progress`. |
-| `ROBOCO_AGENT_SLA_DEVELOPER_VERIFYING` | `1800` | SLA (s) for a developer in `verifying`. |
-| `ROBOCO_AGENT_SLA_QA_CLAIMED` | `1800` | SLA (s) for QA on a claimed review. |
-| `ROBOCO_AGENT_SLA_DOCUMENTER_CLAIMED` | `3600` | SLA (s) for a documenter on a claimed task. |
-| `ROBOCO_AGENT_SLA_CELL_PM_CLAIMED` | `14400` | SLA (s) for a cell PM on a claimed task. |
-| `ROBOCO_CLAIM_STALE_SECONDS` | `180` | Claim-heartbeat staleness used by the spawn trigger filter. |
-| `ROBOCO_STALE_CLAIM_REAP_SECONDS` | `600` | Reaper-only stale-claim threshold before releasing a claim back to pending. |
-| `ROBOCO_PM_CLOSURE_RECENTLY_PAUSED_SECONDS` | `45` | Debounce before respawning a PM to close a recently paused parent. |
-| `ROBOCO_NOTIFICATION_SPAWN_COOLDOWN_SECONDS` | `600` | Cross-tick damper for notification-triggered spawns (escalation/approval/audit/a2a): one spawn per (agent, notification) per window. The notification stays pending, so the next window retries if still unacknowledged; `0` restores the legacy every-tick respawn. |
-| `ROBOCO_GROK_IDLE_KILL_SECONDS` | `900` | Idle-container kill threshold for Grok agents (they emit no SDK heartbeat). |
-| `ROBOCO_GROK_MAX_COST_USD` | `0.0` | Per-agent Grok cost ceiling (USD) before kill; `0` disables. |
-| `ROBOCO_INTERACTIVE_IDLE_REAP_SECONDS` | `1800` | Idle-reap threshold for live intake/secretary chats; `0` disables. |
-| `ROBOCO_CLAIMED_NO_AGENT_GRACE_SECONDS` | `120` | Grace window before respawning/releasing a claimed task with no running agent. |
-| `ROBOCO_PM_DECISION_WINDOW_SECONDS` | `300` | Recency window for a PM `journal:decision` to satisfy gating verbs. |
-| `ROBOCO_SPAWN_COOLDOWN_SECONDS` | `60` | Per-task spawn-rate cooldown. |
-| `ROBOCO_ROLE_SPAWN_RATE_PER_MINUTE` | `6` | Per-role spawn-rate limit per minute. |
-
-## Gateway: manifests & tracing-gate minimums
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_MANIFEST_HOST_DIR` | `/app/manifests` | Orchestrator dir where per-agent tool manifests are written; must be a host-bind-mounted path so the daemon can mount each manifest into its agent. |
-| `ROBOCO_QA_NOTES_MIN_CHARS` | `80` | Minimum characters for QA notes. |
-| `ROBOCO_DOCS_NOTES_MIN_CHARS` | `20` | Minimum characters for docs notes. |
-| `ROBOCO_DEV_NOTES_MIN_CHARS` | `40` | Minimum characters for a developer's `dev_notes`. |
-| `ROBOCO_PR_REVIEWER_NOTES_MIN_CHARS` | `40` | Minimum characters for a PR reviewer's notes. |
-| `ROBOCO_QUICK_CONTEXT_MIN_CHARS` | `30` | Minimum characters for a PM's `quick_context` resumption section. |
-| `ROBOCO_COMMIT_SUBJECT_MIN_CHARS` | `20` | Minimum characters for a commit subject. |
-| `ROBOCO_COMMIT_BANNED_WORDS` | `wip,tmp,asdf,oops,fix,update,change,stuff,things` | Banned single-word commit subjects. |
-
-## Grok runtime
-
-Only relevant if you run any agent on Grok. See the [models section](../models/grok.md) for the full runtime.
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_HOST_GROK_DIR` | `/home/renzof/.grok` (compose) | Host `~/.grok` SuperGrok auth dir; mounted read-write into the orchestrator (token auto-refresh) and read-only into Grok agents. The same value is both the source and target path. |
-| `ROBOCO_GROK_AGENT_IMAGE` | `roboco-agent-grok:latest` | Image the orchestrator spawns for Grok agents. |
-| `ROBOCO_GROK_CLI_MODEL` | `grok-build` | Grok CLI model id. |
-| `ROBOCO_GROK_REASONING_EFFORT` | *(empty)* | `low`/`medium`/`high`/`xhigh`/`max` for all Grok agents; empty keeps the model default. |
-| `ROBOCO_GROK_MAX_TURNS` | `200` | Hard ceiling on agentic turns per Grok run (loop guard). |
-| `ROBOCO_GROK_IDLE_KILL_SECONDS` | `900` | (see reaper table) Idle-kill window for a wedged Grok container. |
-| `ROBOCO_GROK_MAX_COST_USD` | `0.0` | (see reaper table) Per-agent Grok cost ceiling. |
-
-## Optional subsystem flags (default-off unless noted)
-
-These gate the env-toggled capabilities. Each is inert when off. See [Optional capabilities](../optional/index.md).
-
-### Web research — default **on**
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_RESEARCH_ENABLED` | `true` | Master switch for web research. When `false`, the search MCP is not mounted into any agent. |
-| `ROBOCO_RESEARCH_PROVIDER` | `tavily` | `tavily` / `brave` / `exa` / `null`. |
-| `ROBOCO_RESEARCH_API_KEY` | *(unset)* | Provider key — **server-side only**, never reaches an agent. Unset = empty-result null provider. |
-| `ROBOCO_RESEARCH_MAX_RESULTS` | `5` | Cap on results per search (1–20). |
-| `ROBOCO_RESEARCH_FETCH_MAX_CHARS` | `20000` | Cap on extracted characters per fetch. |
-| `ROBOCO_RESEARCH_TIMEOUT_SECONDS` | `15.0` | Per-request outbound timeout. |
-| `ROBOCO_RESEARCH_DAILY_QUOTA_PER_AGENT` | `50` | Search+fetch calls per agent per UTC day. |
-
-### GitHub repo provisioning — default **on** (inert without token/org)
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_PROVISIONING_ENABLED` | `true` | Master switch for pitch auto-provisioning. Inert with no token/org regardless. |
-| `ROBOCO_PROVISIONING_TOKEN` | *(empty)* | GitHub PAT (repo + org admin) used to create repos — server-side only. |
-| `ROBOCO_PROVISIONING_ORG` | *(empty)* | GitHub org where new repos are created. |
-| `ROBOCO_GITHUB_API_BASE_URL` | `https://api.github.com` | Override for GitHub Enterprise. |
-| `ROBOCO_PROVISIONING_TIMEOUT_SECONDS` | `30.0` | Per-request provisioning timeout. |
-| `ROBOCO_PROVISIONING_REPO_PRIVATE` | `true` | Whether provisioned repos are private. |
-
-### Architectural conventions — **off** (config) / **on** (compose)
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_CONVENTIONS_ENABLED` | `false` (config) / `true` (compose) | Master switch for the per-project conventions standard (scaffold, ambient injection, baseline constraints, gate enforcement). The compose orchestrator block defaults this **on** (left off in `docker-compose.registry.yml`); fully inert when off. |
-
-### Toolchain matching — default **off**
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_TOOLCHAIN_MATCH_ENABLED` | `false` (config) / `true` (compose) | Provision the agent workspace with the target project's Python and block delivery gates when the suite can't run. The compose orchestrator block defaults this **on**. |
-
-### Provider overload break — default **on**
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_OVERLOAD_BREAK_ENABLED` | `true` | Park a provider on a persistent overload (HTTP 529/500/503) the way a 429 is parked, instead of crash-retrying. |
-| `ROBOCO_GATEWAY_HEALTH_ENABLED` | `true` | Probe a stale-heartbeat-but-live agent's gateway and kill + respawn it when the gateway is broken (a corrupted `/app` venv firing no verb), instead of the reaper protecting it forever. Off => spare live containers on verb-heartbeat liveness alone. |
-| `ROBOCO_GATEWAY_HEALTH_GRACE_SECONDS` | `180` | How long an agent gateway may probe as broken before recovery — tolerates a transient probe miss. |
-| `ROBOCO_IMAGE_PRUNE_ENABLED` | `true` | Background sweep prunes dangling (``) Docker images left by agent-image rebuilds, throttled ~6h. Only dangling images are removed — a tagged image or one backing a running container is never touched. Not a feature flag; disable to manage image cleanup yourself. |
-
-### Strategy engine — default **off**
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_STRATEGY_ENGINE_ENABLED` | `false` | Master switch for the autonomous strategy engine (notify-only). When off the loop never runs. |
-| `ROBOCO_STRATEGY_ENGINE_INTERVAL_SECONDS` | `1800` | Seconds between assessment passes. |
-| `ROBOCO_STRATEGY_STRANDED_BLOCKED_MINUTES` | `120` | A task blocked longer than this is surfaced as stranded. |
-
-### External / internal PR review — default **off**
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_EXTERNAL_PR_ENABLED` | `false` (config) / `true` (compose) | Master switch for inbound external/fork PR review. The compose orchestrator block defaults this on. |
-| `ROBOCO_EXTERNAL_PR_POLL_INTERVAL_SECONDS` | `300` | Seconds between inbound external-PR discovery passes. |
-| `ROBOCO_EXTERNAL_PR_AUTHOR_ALLOWLIST` | *(empty)* | GitHub usernames auto-trusted. Empty = every external PR needs human confirmation. |
-| `ROBOCO_EXTERNAL_PR_REQUIRE_HUMAN_CONFIRM` | `true` | Require explicit human confirmation before any agent fetches/checks-out/executes external code. |
-| `ROBOCO_INTERNAL_PR_ENABLED` | `false` | Also review org-repo (non-fork) PRs not tied to an active task. |
-
-### Self-healing CI loop — default **off**
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_SELF_HEAL_ENABLED` | `false` | Master switch for the self-heal loop (detect + notify the CEO). When off the loop never runs. |
-| `ROBOCO_SELF_HEAL_PROJECT_SLUG` | *(empty)* / `roboco-api` (compose) | The registered project that *is* RoboCo itself — the only repo the loop watches/originates into. |
-| `ROBOCO_SELF_HEAL_CI_WORKFLOW` | `ci.yml` | GitHub Actions workflow file to scope the CI signal to. |
-| `ROBOCO_SELF_HEAL_ORIGINATE_ENABLED` | `false` | Second opt-in: on a regression, also open a fix task and dispatch it to the Main PM automatically (no manual start). The loop never merges or deploys — the fix ships through the normal gates (QA, PR review, your merge). |
-| `ROBOCO_SELF_HEAL_INTERVAL_SECONDS` | `1800` | Seconds between telemetry passes. |
-| `ROBOCO_SELF_HEAL_MAX_OPEN_TASKS` | `3` | Rolling cap on concurrently-open self-heal tasks. |
-| `ROBOCO_SELF_HEAL_MAX_PER_CYCLE` | `1` | Max self-heal tasks originated in one cycle. |
-
-### Multi-repo CI-watch — default **off**
-
-The global switch arms the engine; each project opts in via `ci_watch_enabled` (+ optional `ci_watch_workflow`) in the edit-project dialog.
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_CI_WATCH_ENABLED` | `false` | Master switch for watching opted-in projects' CI. When off the engine never runs and no CI telemetry is fetched. |
-| `ROBOCO_CI_WATCH_DEFAULT_WORKFLOW` | `ci.yml` | Workflow file to scope the CI signal to when a project sets no `ci_watch_workflow` of its own. |
-| `ROBOCO_CI_WATCH_INTERVAL_SECONDS` | `1800` | Seconds between CI-watch passes. |
-| `ROBOCO_CI_WATCH_MAX_OPEN_TASKS` | `3` | Rolling cap on concurrently-open CI-watch fix tasks per repo. |
-| `ROBOCO_CI_WATCH_MAX_PER_CYCLE` | `1` | Max CI-watch fix tasks opened in one cycle. |
-
-### Dependency-update bot — default **off**
-
-The global switch arms the engine; each project opts in via `dep_update_command` (+ optional `dep_update_paths`) in the edit-project dialog. Detection is read-only — the command runs in a throwaway clone and only the lockfiles are diffed; the real repo is never mutated.
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_DEP_UPDATE_ENABLED` | `false` | Master switch for the dependency-update bot. When off nothing runs and no throwaway clone is made. |
-| `ROBOCO_DEP_UPDATE_INTERVAL_SECONDS` | `604800` | Seconds between dependency-update passes (default weekly). |
-| `ROBOCO_DEP_UPDATE_MAX_OPEN_TASKS` | `3` | Rolling cap on concurrently-open update-dependencies tasks per repo. |
-| `ROBOCO_DEP_UPDATE_MAX_PER_CYCLE` | `1` | Max update-dependencies tasks opened in one cycle. |
-
-### Gated release manager (default-off)
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_RELEASE_MANAGER_ENABLED` | `false` | Master switch for the gated release manager. When off the loop never runs and no release is proposed. Even on it only PROPOSES — the CEO approves before any publish. |
-| `ROBOCO_RELEASE_MIN_COMMITS` | `8` | Minimum unreleased commits since the last tag before a release is proposed (a feat/security change also qualifies). |
-| `ROBOCO_RELEASE_MANAGER_INTERVAL_SECONDS` | `3600` | Seconds between release-readiness assessment passes. |
-| `ROBOCO_RELEASE_CI_WORKFLOW` | `ci.yml` | GitHub Actions workflow file the release fail-closed CI gate scopes to. Decoupled from `ROBOCO_SELF_HEAL_CI_WORKFLOW` — the release gate always resolves a named workflow and never uses all-workflows mode. |
-
-### Organizational memory loop (default-off)
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_ORG_MEMORY_ENABLED` | `false` | Master switch for the org-memory loop. When off: legacy completion capture, no auto-inject, no playbook curation verbs. |
-| `ROBOCO_ORG_MEMORY_TOP_K` | `3` | Max institutional-memory items injected into a briefing on claim. |
-| `ROBOCO_ORG_MEMORY_MIN_SCORE` | `0.6` | Cosine-similarity floor for injected memory; below it, nothing is injected. |
-
-### Spawn preflight — **off** (config) / **on** (compose)
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_SPAWN_PREFLIGHT_ENABLED` | `false` (config) / `true` (compose) | Refuse to spawn a non-human delivery role that isn't in `GATEWAY_ENABLED_ROLES` — such a role gets no gateway manifest and could never claim its work, so the dispatcher would respawn it on the same task forever. On refusal the spawn is rejected (`AgentReadinessError`) and the overseer is alerted once. Inert in practice (every delivery role is gateway-enabled); a misconfiguration guardrail. Armed on the NAS composes, off in `docker-compose.registry.yml`. |
-
-### HTTP security (fastapi-guard)
-
-Default **off**. When off, `create_app` never mounts the middleware and the request path is byte-for-byte unchanged. See [HTTP security hardening](../optional/http-security.md) for the full picture. The NAS compose arms it in passive/log-only mode; enforcement (`ROBOCO_GUARD_PASSIVE_MODE=false`) is a deliberate later step after calibrating against real traffic.
-
-| Variable | Default | Purpose |
-|----------|---------|---------|
-| `ROBOCO_GUARD_ENABLED` | `false` | Master switch. On ⇒ `create_app` mounts `SecurityMiddleware` and the per-route guard decorators become active. |
-| `ROBOCO_GUARD_PASSIVE_MODE` | `false` | Detect-and-log without blocking — the calibration switch. Arm this first on live traffic to surface false positives, then set `false` to enforce. |
-| `ROBOCO_GUARD_FAIL_SECURE` | `true` | Fail **closed** when a security check itself errors (block the request). The personal/NAS compose overrides to `false` so a guard-internal bug never 500s your deploy. |
-| `ROBOCO_ENVIRONMENT` | `development` | Drives `enforce_https` — TLS is enforced only when set to `production`. |
-| `ROBOCO_GUARD_EMERGENCY` | `false` | Emergency lockdown: block every non-whitelisted IP. A flip-on-without-redeploy kill switch for an active attack. |
-| `ROBOCO_GUARD_EMERGENCY_WHITELIST` | *(empty)* | Comma-separated IPs / CIDRs always allowed during lockdown, in addition to loopback. |
-| `ROBOCO_GUARD_TELEMETRY_ENABLED` | `false` | Report security events/metrics to a guard-core platform via guard-agent. No data leaves the box while off. |
-| `ROBOCO_GUARD_AGENT_API_KEY` | *(empty)* | guard-core API key — telemetry only. |
-| `ROBOCO_GUARD_PROJECT_ID` | *(empty)* | guard-core project id — telemetry only. |
-
-## Next
-
-- **[Production deploy](./deployment.md)** — compose files, host mounts, secure mode, startup.
-- **[Optional capabilities](../optional/index.md)** — what each flag above turns on.
-- **[Settings panel](../panel/settings.md)** — toggling flags from the UI instead of `.env`.
diff --git a/docs/deploy/index.md b/docs/deploy/index.md
deleted file mode 100644
index 96f665ad..00000000
--- a/docs/deploy/index.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# Configure & Deploy
-
-The reference layer beneath [Get Started](../get-started/index.md): the full configuration surface, the production deployment story, and how RoboCo's data and schema are managed.
-
-
-
-- **[Deployment](deployment.md)**
-
- ---
-
- The compose files, the single-origin nginx, the host-path mounts, data persistence and backup, secure mode, and the startup sequence.
-
-- **[Environment reference](env-reference.md)**
-
- ---
-
- Every `ROBOCO_*` setting, by category, with its default and purpose — the canonical configuration reference.
-
-- **[Data & migrations](data-and-migrations.md)**
-
- ---
-
- The core data model, the pgvector requirement, and how the stack migrates itself on every boot.
-
-- **[Bootstrap & seeds](bootstrap-and-seeds.md)**
-
- ---
-
- What `make db-init` seeds — the agents, channels, and memberships a fresh company starts with.
-
-
diff --git a/docs/get-started/first-project.md b/docs/get-started/first-project.md
deleted file mode 100644
index 788f3e3e..00000000
--- a/docs/get-started/first-project.md
+++ /dev/null
@@ -1,57 +0,0 @@
-# Register your first project
-
-A **project** is a git repository RoboCo is allowed to work on, plus the configuration that tells the company how to build and check it. Until you register one, the agents have nowhere to put their work. You register projects in the panel under **Projects → New**.
-
-## What a project needs
-
-| Field | What it is |
-|-------|-----------|
-| **Name** | Human-readable label for the repo. |
-| **Slug** | URL-safe short name. It becomes the top of the workspace path (`{slug}/{team}/{agent}/`) and shows up in branch names. |
-| **Git URL** | The clone URL. HTTPS is the common case and **requires a token** (below). |
-| **GitHub token (PAT)** | A Personal Access Token, stored encrypted. Required for private or HTTPS repos — see [The GitHub token](#the-github-token). |
-| **Assigned cell** | Which delivery cell owns this repo: Backend, Frontend, or UX/UI. |
-| **Default branch** | The branch PRs ultimately target. **Read [the default-branch gotcha](#the-default-branch-gotcha) before you save.** |
-| **Gate commands** *(optional)* | Per-project test / lint / format / typecheck / build commands, and a fast pre-submit `quality_command`. See [Gate commands](#gate-commands). |
-
-## The GitHub token
-
-Agents clone your repository and open pull requests on it, so they need a **GitHub Personal Access Token** with permission to do that.
-
-- **Scopes:** the token needs repository **contents** access (to clone and push branches) and **pull request** access (to open and merge PRs). A classic `repo`-scoped token works; a fine-grained token needs *Contents: Read and write* and *Pull requests: Read and write* on the target repo.
-- **It's encrypted and write-only.** The token is encrypted at rest the moment you save it (with your `ROBOCO_ENCRYPTION_KEY`) and the API **never returns it** — the panel only shows whether a token is set, not its value.
-- **Rotating or clearing it:** in **Edit Project**, entering a new token replaces it, an empty field clears it, and leaving it untouched keeps the current one.
-
-!!! danger "HTTPS without a token fails"
- If you give an HTTPS Git URL and no token, the clone fails — agents can't reach the repo. Set the token when you create the project.
-
-!!! warning "The encryption key is load-bearing"
- Every stored project token is encrypted with `ROBOCO_ENCRYPTION_KEY`. If you ever change that key, all stored tokens become undecryptable and you'll have to re-enter every one. Pick it once at install and keep it backed up.
-
-## The default-branch gotcha { #the-default-branch-gotcha }
-
-The **Create Project** dialog defaults the branch to `main`, but several places in the backend assume `master`. **Set this field explicitly to match your repository's real default branch** (`main` or `master`) rather than trusting the pre-filled value. Getting it wrong is the most common first-run snag — branches get cut from, and PRs target, the wrong base.
-
-## Gate commands { #gate-commands }
-
-A developer agent runs a quality gate against its own work *before* it submits for QA. By default that's a sensible lint + typecheck pair, but you'll get far better results by pointing RoboCo at your repository's *real* checks:
-
-- **`quality_command`** — the fast pre-submit gate, run at the moment an agent says it's done (for example `make gate`). If you set this, it replaces the default lint/typecheck pair. Keep it fast; it runs on every submission.
-- **`test_command`, `lint_command`, `format_command`, `typecheck_command`, `build_command`** — the individual commands for the cell's QA and CI steps.
-
-Setting these so they mirror what *you* would run locally is the single biggest lever on output quality: the company gates itself exactly the way you would.
-
-## Sandboxing agents away from a repo
-
-If you want to make sure agents can never point a project at a particular repository — RoboCo's own source, say, during a test run — set `ROBOCO_PROTECTED_GIT_URLS` to a comma-separated list of URL substrings. Creating or updating a project whose Git URL matches one is rejected.
-
-## What happens under the hood
-
-You don't have to manage any of this, but it's worth knowing what registering a project sets in motion:
-
-- The first time an agent is assigned work on the project, RoboCo clones the repo into that agent's own workspace under `ROBOCO_WORKSPACES_ROOT` (default `/data/workspaces`). **Every agent gets its own clone**, so they work in parallel without stepping on each other. That directory is the disk to provision and back up.
-- Right after cloning, RoboCo **scrubs the token out of the clone's git config** and verifies no token byte survived anywhere under `.git/` — destroying the workspace if one did. Your PAT never lives inside an agent container.
-
-## Next
-
-→ **[Your first task](first-task.md)** — hand the company something to build.
diff --git a/docs/get-started/first-task.md b/docs/get-started/first-task.md
deleted file mode 100644
index 0a44c6c4..00000000
--- a/docs/get-started/first-task.md
+++ /dev/null
@@ -1,46 +0,0 @@
-# Your first task
-
-With a project registered, you can hand the company work. The way in is the **Task Assistant** — the Intake agent — on the **Prompter** page. You give it a rough idea; it reads your *actual* codebase, asks a few sharp questions, and hands back a properly-formed task with an objective, a per-cell breakdown, and the acceptance criteria that define "done."
-
-## Draft a task with the assistant
-
-1. Open the **Prompter** page (the **Task Assistant**).
-2. Point it at the **project** you just registered (or a **product**, if you've mapped several repos together), and describe what you want — a feature, a fix, anything.
-3. It spins up an agent that **clones the scope and reads the real code** before it says a word, then comes back with a grounded proposal: what to build, where it should live, and the acceptance criteria — citing your actual files and pages.
-4. Refine it over a turn or two until the spec is right.
-
-When the proposal is ready, you choose on a single card:
-
-- **Keep chatting** — keep refining the draft.
-- **Board review & Start** — send it to the Product Owner and Head of Marketing to sharpen the requirements before any code is written.
-- **Approve & Start** — hand it straight to the Main PM.
-
-!!! tip "You don't have to use the assistant"
- The assistant is the easiest path, but a task is just a record. You can also create one directly through the API (`POST /api/tasks`) if you're scripting RoboCo — every task needs a title, a description, at least one acceptance criterion, a team, and a target project. The API reference covers the full schema.
-
-## What happens after you approve
-
-The moment you approve, the company takes over:
-
-1. The **Main PM** breaks the task into per-cell subtasks and sets the cells running.
-2. Each **cell PM** delegates to its developers, clears blockers, and triages.
-3. **Developers** build it in their own clones and open pull requests; **QA** reads the real diff and passes or fails it; **Documenters** write down what was built.
-4. A **PR reviewer** checks each assembled pull request before a PM merges it up the chain.
-5. The **Main PM** opens the final pull request into `master` and notifies you it's done.
-
-You can watch all of this live — on the **Kanban** board, the **Tasks** table, the **Communications** stream, and the **Command Center**. Nothing happens in the dark.
-
-## The two moments you're needed
-
-A whole feature only needs you at **two points**:
-
-- **The green light at the start** — *Approve & Start* (or send it back).
-- **The last call at the end** — the finished pull request lands in your **CEO Approval Queue**, where you **Approve & Merge**, **Request Changes**, or **Cancel**. Only you ever merge to `master`.
-
-Everything between those two moments is the company doing its job.
-
-## See it for real
-
-The best way to understand the whole journey is to watch one happen. **[The Tour](../how-to/README.md)** follows RoboCo building one of its *own* features — the Prompter you just used — from this same starting point all the way to a merged pull request, with screenshots at every step.
-
-To understand the machinery behind it — the roles, the gated lifecycle, the merge chain — read **[The Company](../company/index.md)**.
diff --git a/docs/get-started/index.md b/docs/get-started/index.md
deleted file mode 100644
index fbc6a0ac..00000000
--- a/docs/get-started/index.md
+++ /dev/null
@@ -1,27 +0,0 @@
-# Get Started
-
-Three steps take you from a cloned repository to a company working on your code:
-
-1. **[Install & first run](installation.md)** — bring up the whole stack with Docker, set two secrets, and open the Command Center.
-2. **[Register your first project](first-project.md)** — point RoboCo at a git repository it's allowed to work on.
-3. **[Your first task](first-task.md)** — hand the company something to build and watch it go end to end.
-
-You don't need Python, Node, or a database on your machine — everything runs in Docker. The one thing you provide is a way for the agents to reach a model: by default that's the **Claude Code** session already on your host, so there's no API key to wire up.
-
-!!! tip "Prefer to watch first?"
- The [26-minute intro](https://www.youtube.com/watch?v=t1QNqJgBmkM) and the [full panel walkthrough](../how-to/README.md) are the fastest way to get the shape of the thing before you install it.
-
-## What you'll need
-
-| You need | Why |
-|----------|-----|
-| **Docker** + **Docker Compose** | The entire stack (PostgreSQL, Redis, Ollama, the orchestrator, the panel, nginx) runs as containers. |
-| **A Claude Code auth directory** (`~/.claude`) | Mounted into the orchestrator so agents can reach the model. Run `claude` once on the host to create it. *(Or run the workforce on [Grok](installation.md#optional-run-on-grok-instead) instead.)* |
-| **A GitHub Personal Access Token** | One per project you register, so agents can clone it and open pull requests. You add this in the panel later, not now. |
-| **~10 GB of disk** and a few GB of RAM | The image set and the per-agent git clones. RoboCo is light at runtime — see the [resource notes](installation.md#resources). |
-
-## The shape of the system
-
-Everything is served behind a single address — **`http://localhost:3000`** — by an nginx reverse proxy. The browser only ever sees one origin; nginx routes `/api` and `/ws` to the orchestrator (FastAPI) and everything else to the Next.js control panel. That panel is your one window into the company.
-
-When you're set up and looking at the **Command Center**, head into [The Company](../company/index.md) to understand the org and the lifecycle, or take [the Tour](../how-to/README.md) to watch a real feature get built.
diff --git a/docs/get-started/installation.md b/docs/get-started/installation.md
deleted file mode 100644
index 90235621..00000000
--- a/docs/get-started/installation.md
+++ /dev/null
@@ -1,160 +0,0 @@
-# Install & first run
-
-This page takes you from nothing to the **Command Center** open in your browser. The whole stack runs in Docker, so the only things you install on the host are Docker itself and (for the default Claude backend) the Claude Code CLI.
-
-## 1. Authenticate the model backend
-
-By default every agent runs on Anthropic Claude, using the **Claude Code** session on your host rather than a metered API key. Authenticate once:
-
-```bash
-npm install -g @anthropic-ai/claude-code
-claude # opens a browser to log in; creates ~/.claude
-```
-
-That `~/.claude` directory is mounted read-only into the orchestrator, which hands it to each agent container. If you'd rather run the workforce on Grok, skip this and see [Optional: run on Grok](#optional-run-on-grok-instead) below.
-
-## 2. Get the code
-
-```bash
-git clone https://github.com/rennf93/roboco.git
-cd roboco
-cp .env.example .env
-```
-
-## 3. Set the two required secrets
-
-Open `.env` and set these two — the orchestrator refuses to start without the first, and Docker deployments need the second:
-
-```bash
-# Encrypts every per-project GitHub token at rest (Fernet). REQUIRED.
-ROBOCO_ENCRYPTION_KEY=
-
-# Signs the per-agent auth tokens (HMAC). REQUIRED for docker compose.
-ROBOCO_AGENT_AUTH_SECRET=
-```
-
-Generate each one:
-
-```bash
-# ROBOCO_ENCRYPTION_KEY
-python -c 'from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())'
-
-# ROBOCO_AGENT_AUTH_SECRET
-python -c 'import secrets; print(secrets.token_hex(32))'
-```
-
-!!! danger "Keep `ROBOCO_ENCRYPTION_KEY` safe and stable"
- This key encrypts the GitHub tokens you'll store per project. If you lose it or change it later, **every stored token becomes undecryptable** and must be re-entered. Back it up with your other secrets, and never commit `.env`.
-
-Everything else in `.env.example` has a working default for a local Docker run. On a NAS or remote server you'll also set the host-path variables (`ROBOCO_HOST_PROJECT_DIR`, `ROBOCO_HOST_CLAUDE_DIR`, `ROBOCO_DATA_DIR`) — those are covered in the deployment reference.
-
-## 4. Bring up the stack
-
-You have two ways to get the images. Both start from the clone above.
-
-=== "Pre-built images (quickest)"
-
- Every release publishes all RoboCo images to both the GitHub Container Registry and Docker Hub, so you can run the full stack without building anything:
-
- ```bash
- docker compose -f docker-compose.registry.yml pull
- docker compose -f docker-compose.registry.yml up -d
- ```
-
- Pick the registry and version with two variables (defaults shown):
-
- ```bash
- ROBOCO_REGISTRY=ghcr.io/rennf93 # or docker.io/renzof93
- ROBOCO_VERSION=latest # or a pinned release, e.g. 0.9.0
- ```
-
- The orchestrator pulls and spawns the matching pre-built agent images on demand — no build toolchain on your host.
-
-=== "Build from source"
-
- The same stack, built locally from the Dockerfiles instead of pulled:
-
- ```bash
- docker compose up -d # builds images on first run, then starts everything
- ```
-
-The first start does real work: it pulls the local models into Ollama (the embedding model is quick; the local LLM is a couple of minutes), then the orchestrator waits for them, **runs the database migrations itself**, and indexes its knowledge base. You don't run migrations by hand — the stack brings its own schema up to date on every boot.
-
-## 5. Watch it come up
-
-```bash
-docker compose logs -f orchestrator
-```
-
-Wait until the orchestrator reports it's serving, then open:
-
-```text
-http://localhost:3000
-```
-
-That's the **Command Center** — per-cell health, the CEO approval queue, live metrics, and recent activity. The company is up; it's just idle because you haven't given it a repository or a task yet.
-
-!!! note "One address for everything"
- nginx is the only externally-exposed service. It serves the panel and proxies `/api` and `/ws` to the orchestrator, so the browser sees a single origin at `:3000`. You generally won't hit the orchestrator's own port directly.
-
-## Next
-
-→ **[Register your first project](first-project.md)** — point RoboCo at a repository it's allowed to work on.
-
----
-
-## Optional: run on Grok instead
-
-RoboCo can run the entire workforce on **xAI Grok** using xAI's official `grok` CLI on a **SuperGrok subscription** — no metered API key, so a run can't stall mid-task on exhausted credits.
-
-```bash
-grok login # once, on the host — creates ~/.grok/auth.json
-```
-
-Then in `.env`:
-
-```bash
-ROBOCO_HOST_GROK_DIR=/home/youruser/.grok # the real host ~/.grok to mount in
-# ROBOCO_GROK_AGENT_IMAGE=roboco-agent-grok:latest
-# ROBOCO_GROK_CLI_MODEL=grok-build
-# ROBOCO_GROK_REASONING_EFFORT= # low|medium|high|xhigh|max (empty = model default)
-```
-
-The orchestrator keeps the short-lived Grok token refreshed for you, so agents don't hang on an expired login. Which agents run on which backend is set on the **Settings → AI Providers** page — that, and the per-role model assignments, are covered in the models section.
-
-## Optional: secure mode
-
-On a trusted LAN, RoboCo runs in **header-trust mode** by default: requests identify the caller by role headers, with no token required. That's fine on a private network and is the intended setup.
-
-If you need to harden it so an agent can't spoof another's role, set `ROBOCO_AGENT_AUTH_REQUIRED=true`, keep your `ROBOCO_AGENT_AUTH_SECRET`, and generate the panel's CEO token with `make panel-token` into `ROBOCO_PANEL_AGENT_TOKEN`. nginx injects that token so the panel keeps working without the browser holding the signing secret. The full security model is in the Configure & Deploy reference.
-
-!!! warning
- Don't expose RoboCo to the public internet as-is. It's built to run on a trusted private network (homelab / LAN).
-
-## Resources { #resources }
-
-RoboCo is light at runtime. Agent containers are spawned on demand and torn down when their work is done, so you rarely have more than a handful live at once.
-
-| At idle (full stack, no task running) | RAM |
-|---------------------------------------|-----|
-| Ollama (models loaded) | ~2.2 GB |
-| Orchestrator | ~150 MB |
-| Postgres / Panel / Redis / nginx | ~120 MB combined |
-
-The whole standing stack idles around **~2.5 GB**, almost all of it Ollama. Under load — five agents working concurrently — the stack peaked around **~6.6 GB**; even at full-fleet peak you stay well under ~10 GB. **Storage is the larger footprint:** the agent images all build from a shared base layer, so on disk they cost far less than their nominal sizes summed. `docker system prune` reclaims old image versions, stopped containers, and build cache.
-
-```bash
-docker stats # live RAM / CPU per running container
-docker system df # image / container / build-cache disk usage
-```
-
-## Running on the host (for hacking on RoboCo itself)
-
-If you want to develop RoboCo's own code rather than just run it, you can run only the backing services in Docker and the app on your host. RoboCo's code needs **Python 3.13+** (`uv` fetches it if needed):
-
-```bash
-uv sync
-docker compose up -d postgres redis ollama # backing services only
-uv run alembic upgrade head # migrate the database
-uv run python -m roboco.cli # API + orchestrator
-```
diff --git a/docs/how-to/01-the-company.md b/docs/how-to/01-the-company.md
deleted file mode 100644
index 5991ea7b..00000000
--- a/docs/how-to/01-the-company.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# The shape of the company
-
-What keeps twenty-two agents from dissolving into noise is that RoboCo is relentlessly opinionated about *how* work happens: everything is a task, no task moves without acceptance criteria, and every task walks the same strict lifecycle — built, QA'd, documented, PM-reviewed, approved — each step gated by role. The structure is the point. It is what turns a roster of models into a company that actually ships.
-
-Work in RoboCo is always a **task**, and tasks nest into a tree that mirrors the org itself:
-
-```text
-CEO (you, the human)
- ├── Intake (on-demand interviewer — drafts a task with you)
- ├── Secretary (your chief-of-staff — acts only on your command)
- └── Board ── Product Owner · Head of Marketing · Auditor (silent) · PR Reviewer (inbound external PRs)
- └── Main PM (coordinates the cells)
- ├── UX/UI cell ── PM · 2 Devs · QA · Documenter
- ├── Frontend cell ── PM · 2 Devs · QA · Documenter
- └── Backend cell ── PM · 2 Devs · QA · Documenter
-```
-
-The walkthrough that follows traces the delivery path — Intake, the Board, the Main PM, the cells. The Secretary and the research and strategy engines sit one layer up, steering the company as a whole; they get their own chapter at the end.
-
-In practice, one feature becomes a small tree of work — a parent task at the top, a branch for each cell underneath, every node carrying its own status, git branch, and pull request:
-
-
-
-*A feature in motion. The parent task fans out to the UX/UI, Frontend, and Backend cells, and each child moves through its own lifecycle — in progress, awaiting review, completed — on its own branch.*
-
----
-
-Next: **[It starts with you →](02-it-starts-with-you.md)**
diff --git a/docs/how-to/02-it-starts-with-you.md b/docs/how-to/02-it-starts-with-you.md
deleted file mode 100644
index 03d75726..00000000
--- a/docs/how-to/02-it-starts-with-you.md
+++ /dev/null
@@ -1,61 +0,0 @@
-# It starts with you
-
-## 1 · It starts with you
-
-You describe what you want — a feature, a fix, an entire product. The way in is the **Task Assistant** — which is the **Prompter** itself, the very feature whose build the rest of this guide follows. (You're about to use the tool RoboCo built for itself; further on, you'll watch the company build it.) Instead of filling a form from memory, you give it a rough idea and it reads your *actual* codebase, asks a few sharp questions, and hands back a properly-formed task — an objective, a per-cell breakdown, and the acceptance criteria that define what "finished" really means.
-
-
-
-*Where it starts — point the assistant at a project (one repo) or a product (several), drop in a rough idea, and it spins up an agent that reads that code before it says a word.*
-
-There is a third scope, **MegaTask**, for when you want several tasks at once across projects that don't share a codebase — the assistant proposes the whole batch and the company sequences it into conflict-free waves. See [MegaTask](../company/megatask.md).
-
-
-
-*No canned questions. The agent clones the scope and reads the real surface first, so everything it asks and proposes is grounded in what your code actually does.*
-
-
-
-
-*It comes back having done the homework — naming the real pages, services, and files, laying out what to build and where, and refining with you over a couple of turns until the spec is right.*
-
-
-
-
-*The proposal, ready to launch. Keep chatting to refine it, send it to the **Board** for review, or approve it straight to the Main PM — your call, on one card.*
-
-
-
-
-
-*From a rough sentence to a real, scoped task in a single chat — acceptance criteria and all, already moving through the company.*
-
-From here, every task follows the path you chose for it. To show that journey end to end, the rest of this guide follows the **Prompter's own** trip through the company — from this same starting point to a merged pull request. Send a task to the **Board** and their job is to pin it down: the Product Owner and Head of Marketing turn the draft into a settled spec, sharpening the requirements and the acceptance criteria before anyone writes a line of code. The Auditor watches the whole time but never interferes.
-
-
-
-*The Product Owner working a task over — pinning down the requirements and the must-haves before anyone writes a line of code.*
-
-
-
-*Two seats at the table. The Product Owner and the Head of Marketing review the same task from their own angles and put their reasoning on the record — this is the Board building the actual spec for the Prompter, the feature this whole walkthrough follows.*
-
-## 2 · Nothing moves without your green light
-
-The Board hands the reviewed task back to you as a **notification** and waits. You make one call: send it forward, or send it back. Approve it, and the **Main PM** picks it up, splits it across the cells, and sets them running.
-
-
-
-*The Board's verdict lands in your notifications and pauses there. A single approval is what turns the whole company on.*
-
-
-
-*The notification itself, spelled out: the Board has finished, the task is recorded, and nothing happens until you say so — Approve & Start hands it to the Main PM; reject it and it goes back. This is the first of the only two moments the company needs you.*
-
-
-
-
-
----
-
-Previous: **[← The shape of the company](01-the-company.md)** · Next: **[The cells build it →](03-the-cells-build-it.md)**
diff --git a/docs/how-to/03-the-cells-build-it.md b/docs/how-to/03-the-cells-build-it.md
deleted file mode 100644
index 8b7cc8e1..00000000
--- a/docs/how-to/03-the-cells-build-it.md
+++ /dev/null
@@ -1,37 +0,0 @@
-# The cells build it
-
-## 3 · The cells take over
-
-Underneath the Main PM are three cells — **UX/UI, Frontend, Backend** — each a small team with its own PM. Those PMs run their cells like engineering managers: parcelling out the work, clearing blockers, and stepping in when something stalls. UX/UI usually leads and sets the contracts; Frontend and Backend build against them.
-
-
-
-*A cell at work, seen as a board — tasks flow from backlog to done, and the role tabs let you watch it from the developer's, QA's, or PM's seat.*
-
-## 4 · The work gets done — and checked
-
-This is where it's actually built. Developers write the code and open pull requests from their own branches. QA doesn't rubber-stamp — it reads the real diff and decides whether the work ships or comes back for another pass. Documenters write down what was built so the next agent (and you) aren't starting cold. None of it happens in the dark: agents narrate their reasoning as they go, and each keeps a running journal of what it learned and why it chose what it chose.
-
-
-
-*QA earning its seat. On this Prompter task it read the work, marked it **failed**, and sent it back — the developer's notes and the QA verdict sit side by side on the record, with the Auditor watching the whole exchange. Real review, not a rubber stamp; the gate only opens when the work is right.*
-
-
-
-*Every agent keeps a journal — reflections, decisions, and lessons. Between that and the Documenters, there's a paper trail for everything the company does.*
-
-## 5 · The work converges
-
-Once a cell's piece is green and documented, its PM folds those branches up into the Main PM's integration branch. Three independent streams of work come back together into one. Each task brings its branch, pull request, commits, and docs along with it:
-
-
-
-*One finished unit — branch, pull request, commits, and docs all attached. This is the thing that travels up the merge chain.*
-
-
-
-*Three streams becoming one history. Each cell's work lands as its own **verified** commit, co-authored by the agent that wrote it — the UX/UI design, the backend endpoint, the frontend page — folded together into the single pull request that comes back to you.*
-
----
-
-Previous: **[← It starts with you](02-it-starts-with-you.md)** · Next: **[The last call — and the loop →](04-the-last-call-and-the-loop.md)**
diff --git a/docs/how-to/04-the-last-call-and-the-loop.md b/docs/how-to/04-the-last-call-and-the-loop.md
deleted file mode 100644
index cd86353f..00000000
--- a/docs/how-to/04-the-last-call-and-the-loop.md
+++ /dev/null
@@ -1,45 +0,0 @@
-# The last call — and the loop
-
-## 6 · The last call is yours
-
-The cells' work is folded up, the Main PM opens the **final pull request** into `master`, and the company goes quiet. The decision comes back to exactly where it started — with you. You're the only one who ever touches `master`, and anything waiting on you sits in the **CEO Approval Queue** until you act.
-
-
-
-*The hand-off back to you. The integrated PR is open, every cell has delivered, QA is green — and it waits. Nothing reaches `master` without your word.*
-
-
-
-*And it is a real pull request, on the real repository — not a simulation. The company's work shows up exactly where any engineer would look for it.*
-
-
-
-*Open it and the whole brief is there — the objective, what was built, the board-led split across the three cells, and the company's own notes — written by RoboCo, for you to read before you decide.*
-
-
-
-*The real diff, laid out for you to inspect — the migrations, the endpoints, the panel components. This is the substance you are signing off on.*
-
-
-
-*Your two words. **Approve & Merge** and it ships to `master`; **Request Changes** and it goes around for another lap. The last call has the same shape as the first — one decision, yours alone.*
-
-## The other queue: PRs you didn't open
-
-Not every pull request comes from inside the company. When someone opens a PR against your repo — an external contributor, a fork — the read-only **PR Reviewer** picks it up, reads the diff against your standards, and posts a single change-request directly on the PR (it never chats, never merges, never decides). The PR then surfaces in the **PR Review Queue** on the Command Center — your second decision surface. There you **Supersede** it: the company cuts its own branch from the contributor's commits, hardens the work to your standards, opens its own PR, and — once that replacement merges — closes and links the original. Or you **Dismiss** it. Either way the call is yours, and the org never pushes to anyone else's fork.
-
----
-
-## And round it goes
-
-You handed the company a task; it scoped it, built it, failed and re-ran its own QA, documented it, and brought it back as a single pull request for your sign-off. That's one complete pass.
-
-
-
-*The whole tree in its final state — the parent waiting on your approval, every cell's task done beneath it. One feature, start to finish, with you at only the two ends.*
-
-And the feature in these screenshots is the proof. The **Prompter** wasn't built for a demo — it's a real page RoboCo's agents shipped to RoboCo's own control panel. A company building its own product, in front of you, is the whole point of RoboCo. What makes that hold together isn't a clever model or a lucky run; it's the **organization** — the roles, the gated lifecycle, the reviews and the sign-offs that keep twenty-two agents moving as a company instead of a crowd. Run as many of these passes as you like, across as many projects as you like.
-
----
-
-Previous: **[← The cells build it](03-the-cells-build-it.md)** · Next: **[The business workflow →](05-the-business-workflow.md)**
diff --git a/docs/how-to/05-the-business-workflow.md b/docs/how-to/05-the-business-workflow.md
deleted file mode 100644
index 9541294e..00000000
--- a/docs/how-to/05-the-business-workflow.md
+++ /dev/null
@@ -1,55 +0,0 @@
-# The business workflow
-
-The first four chapters follow one task through the company. But a company isn't only its task queue — it has a direction, a budget, and a reason every task exists. That layer lives in the **Business** tab, and it is how you steer the whole organization rather than one job at a time.
-
-## The charter
-
-The charter is the company's standing context: its **north star**, its **objectives**, the **constraints** it must respect, and the **operating policy** it works under. You write it once in the Business tab and revise it whenever the direction shifts. It isn't decoration — the charter is threaded into every agent's briefing, into the pitches the Board produces, and into what the Secretary is allowed to act on. Set it well and every agent inherits the same sense of what the company is for; leave it empty and they only know the task in front of them.
-
-
-
-## The Cockpit
-
-Where the charter says what the company *should* be doing, the Cockpit shows what it *is* doing — the company reflected back against its own charter. It surfaces spend against budget and the signals worth your attention: drift from the stated objectives, agents sitting idle, work that has been blocked too long. It is the one screen that answers "is the company on course?" without your having to read every task.
-
-
-
-## The Company Scorecard
-
-On the Business tab's Goals view sits the Company Scorecard — live performance against the charter in one card. Where the Cockpit surfaces signals to act on, the Scorecard is the one-glance answer to "how is the company actually doing?": what's been delivered, spend against budget, the median lead time from task to merge, and progress on the objectives you set. It is the company's vital signs, read off the same work the rest of the panel tracks.
-
-## The Secretary
-
-The Secretary is your conversational chief-of-staff. You chat with it the way you'd brief a human one — ask it where things stand, or dictate a change to the charter. What it never does is act on its own: every directive it derives from your instruction is **gated**, landing in a queue for your explicit confirmation before anything happens. It reads the whole company's state to advise you, but it spends nothing, builds nothing, and approves nothing until you say the word. It is leverage with a safety catch — your intent, executed, but only after you confirm it.
-
-
-
-## Web research and the strategy engine
-
-Two capabilities run above the day-to-day. Both are **off by default** and master-switched from **Settings → Feature Flags** in the panel — the switch persists and takes effect on the next backend restart. The environment variables below are the same toggles at the source, and still carry the parts the panel deliberately doesn't surface (the research provider and its API key, which never leave the server). Their effect shows up inside agent runs once enabled.
-
-### Web research
-
-Flip **Web research** on in Settings → Feature Flags (or set `ROBOCO_RESEARCH_ENABLED=true`), choose a provider with `ROBOCO_RESEARCH_PROVIDER` (`tavily`, `brave`, or `exa`), and supply `ROBOCO_RESEARCH_API_KEY`. With that in place, the Board and PM agents gain `web_search` and `web_fetch` through the `roboco-search` MCP server — so a Product Owner scoping a feature can ground it in the live web, not just your codebase. The API key stays server-side; the agents never see it and never make the external call themselves. Leave it off and the tools simply aren't there — a no-op.
-
-### The strategy engine
-
-Flip **the strategy engine** on in Settings → Feature Flags (or set `ROBOCO_STRATEGY_ENGINE_ENABLED=true`) and a background loop begins watching the company against its charter. When it spots drift from the objectives, agents gone idle, or work blocked for too long, it tells you. It is **notify-only by design**: it never spends, never builds, never approves — it raises the flag and leaves the decision where every decision belongs, with you. Off, it is fully dormant.
-
-### The self-healing CI loop
-
-The same shape, pointed inward: flip **self-healing** on in Settings → Feature Flags (or set `ROBOCO_SELF_HEAL_ENABLED=true`) and RoboCo begins watching its **own** repository's CI. When a run regresses it tells you. Turn on the second switch (`ROBOCO_SELF_HEAL_ORIGINATE_ENABLED=true`) and it goes one step further — it opens a fix task for the regression and hands it straight to the Main PM, who coordinates the repair. It never merges or deploys that work itself: the fix still flows through the normal gates — dev, QA, PR review, and **your** merge — so the company can repair its own build autonomously while the decision to ship stays yours. Both switches are off by default, and it watches only the one repo you name as RoboCo itself.
-
-## Feel the whole thing
-
-The cleanest way to understand this layer is to walk it once, end to end:
-
-1. Open the **Business** tab and set the charter — north star, a couple of objectives, your constraints, the operating policy.
-2. Open the **Cockpit** and watch the company reflected against it — spend against budget, and the signals as they appear.
-3. Chat the **Secretary** and dictate one change to the charter. Watch the gated directive land in the queue, and confirm it — that round trip, from your sentence to a confirmed action, is the whole shape of how you steer RoboCo from above.
-
----
-
-Previous: **[← The last call — and the loop](04-the-last-call-and-the-loop.md)** · Back to **[the index](README.md)**
-
-*RoboCo is early-stage, work-in-progress software (v0) — expect rough edges. The [Get Started guide](../get-started/index.md) covers setup, configuration, and the security model.*
diff --git a/docs/how-to/README.md b/docs/how-to/README.md
deleted file mode 100644
index c0b04826..00000000
--- a/docs/how-to/README.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# How RoboCo works
-
-
-
-RoboCo is a virtual software company — 25 AI agents and one human: you. Not a swarm of bots, not a framework to wire together — an **organization**, with roles, a chain of command, formal reviews, and sign-offs. You don't micromanage it; you run it like a CEO. Drop work in at the top and the company carries it all the way through planning, building, review, and documentation, then brings it back to your desk for the final word. You act at the two ends; the organization fills in everything between.
-
-And the proof is this guide. The screenshots throughout aren't a mock-up: they follow RoboCo building one of its *own* features — the **Prompter**, the task-authoring page now living in this very control panel. RoboCo's agents scoped it, built it across three cells, failed and re-ran its QA, documented it, and opened the real pull request you'll see at the end. RoboCo builds RoboCo — that is the whole proof of concept.
-
-> The panel is your one window into the company. Every task, agent, message, journal, and pull request is live in front of you.
-
-**Prefer video?** A [full screen-recording of the panel](../videos/panel-full-walkthrough.mp4) walks through every page and detail end-to-end — useful as a first tour before diving into the screenshots.
-
-
-
-*The **Command Center** — a glance tells you how each cell is doing, what's waiting on your approval, how fast work is moving, and what just happened.*
-
----
-
-## Read it in order
-
-This guide follows one task — the Prompter's own build — from a rough idea to a merged pull request, then steps back to the strategic layer you steer the whole company with.
-
-1. **[The shape of the company](01-the-company.md)** — the org, and how every piece of work is a task that nests into a tree.
-2. **[It starts with you](02-it-starts-with-you.md)** — drafting a task with the assistant, the Board review, and your first green light.
-3. **[The cells build it](03-the-cells-build-it.md)** — the three cells, the Dev Kanban, real QA, journals, and the integration branch.
-4. **[The last call — and the loop](04-the-last-call-and-the-loop.md)** — the final pull request, the CEO Approval Queue, the merge, and round it goes.
-5. **[The business workflow](05-the-business-workflow.md)** — the charter, the Cockpit, the Secretary, and the research and strategy engines that run above the day-to-day.
-
----
-
-*RoboCo is early-stage, work-in-progress software (v0) — expect rough edges. The [Get Started guide](../get-started/index.md) covers setup, configuration, and the security model.*
diff --git a/docs/images/all_tasks_final_state.png b/docs/images/all_tasks_final_state.png
deleted file mode 100644
index babafbb6..00000000
Binary files a/docs/images/all_tasks_final_state.png and /dev/null differ
diff --git a/docs/images/approve_button_merge_rework.png b/docs/images/approve_button_merge_rework.png
deleted file mode 100644
index e8b53809..00000000
Binary files a/docs/images/approve_button_merge_rework.png and /dev/null differ
diff --git a/docs/images/approve_task.png b/docs/images/approve_task.png
deleted file mode 100644
index bddb6e18..00000000
Binary files a/docs/images/approve_task.png and /dev/null differ
diff --git a/docs/images/approve_task_detail.png b/docs/images/approve_task_detail.png
deleted file mode 100644
index e9e302ea..00000000
Binary files a/docs/images/approve_task_detail.png and /dev/null differ
diff --git a/docs/images/ceo_approval_notif.png b/docs/images/ceo_approval_notif.png
deleted file mode 100644
index 84d91ea9..00000000
Binary files a/docs/images/ceo_approval_notif.png and /dev/null differ
diff --git a/docs/images/ceo_review_notif.png b/docs/images/ceo_review_notif.png
deleted file mode 100644
index 62d33aa7..00000000
Binary files a/docs/images/ceo_review_notif.png and /dev/null differ
diff --git a/docs/images/chat_session.png b/docs/images/chat_session.png
deleted file mode 100644
index 7c3e0da8..00000000
Binary files a/docs/images/chat_session.png and /dev/null differ
diff --git a/docs/images/journaling.png b/docs/images/journaling.png
deleted file mode 100644
index 4ae47c71..00000000
Binary files a/docs/images/journaling.png and /dev/null differ
diff --git a/docs/images/kanban.png b/docs/images/kanban.png
deleted file mode 100644
index ce757f5d..00000000
Binary files a/docs/images/kanban.png and /dev/null differ
diff --git a/docs/images/notifications.png b/docs/images/notifications.png
deleted file mode 100644
index 617f101b..00000000
Binary files a/docs/images/notifications.png and /dev/null differ
diff --git a/docs/images/opened_final_pr.png b/docs/images/opened_final_pr.png
deleted file mode 100644
index ab591a5a..00000000
Binary files a/docs/images/opened_final_pr.png and /dev/null differ
diff --git a/docs/images/opened_final_pr_body.png b/docs/images/opened_final_pr_body.png
deleted file mode 100644
index e7ba58bf..00000000
Binary files a/docs/images/opened_final_pr_body.png and /dev/null differ
diff --git a/docs/images/opened_final_pr_changes.png b/docs/images/opened_final_pr_changes.png
deleted file mode 100644
index ff6382e6..00000000
Binary files a/docs/images/opened_final_pr_changes.png and /dev/null differ
diff --git a/docs/images/opened_final_pr_commits.png b/docs/images/opened_final_pr_commits.png
deleted file mode 100644
index 3c0d9e00..00000000
Binary files a/docs/images/opened_final_pr_commits.png and /dev/null differ
diff --git a/docs/images/overview_dashboard.png b/docs/images/overview_dashboard.png
deleted file mode 100644
index b7b4b43f..00000000
Binary files a/docs/images/overview_dashboard.png and /dev/null differ
diff --git a/docs/images/po_hom_review.png b/docs/images/po_hom_review.png
deleted file mode 100644
index 2263f554..00000000
Binary files a/docs/images/po_hom_review.png and /dev/null differ
diff --git a/docs/images/prompter_draft_card.png b/docs/images/prompter_draft_card.png
deleted file mode 100644
index 655a6382..00000000
Binary files a/docs/images/prompter_draft_card.png and /dev/null differ
diff --git a/docs/images/prompter_run_1.png b/docs/images/prompter_run_1.png
deleted file mode 100644
index c12cdabf..00000000
Binary files a/docs/images/prompter_run_1.png and /dev/null differ
diff --git a/docs/images/prompter_run_2.png b/docs/images/prompter_run_2.png
deleted file mode 100644
index 289a6f15..00000000
Binary files a/docs/images/prompter_run_2.png and /dev/null differ
diff --git a/docs/images/prompter_task_accepted.png b/docs/images/prompter_task_accepted.png
deleted file mode 100644
index 88030023..00000000
Binary files a/docs/images/prompter_task_accepted.png and /dev/null differ
diff --git a/docs/images/prompter_task_created.png b/docs/images/prompter_task_created.png
deleted file mode 100644
index 2525b0b4..00000000
Binary files a/docs/images/prompter_task_created.png and /dev/null differ
diff --git a/docs/images/prompter_task_proposal_actions.png b/docs/images/prompter_task_proposal_actions.png
deleted file mode 100644
index 0b6e154a..00000000
Binary files a/docs/images/prompter_task_proposal_actions.png and /dev/null differ
diff --git a/docs/images/qa_fail.png b/docs/images/qa_fail.png
deleted file mode 100644
index 989fc290..00000000
Binary files a/docs/images/qa_fail.png and /dev/null differ
diff --git a/docs/images/run.png b/docs/images/run.png
deleted file mode 100644
index 36afa852..00000000
Binary files a/docs/images/run.png and /dev/null differ
diff --git a/docs/images/start_prompter.png b/docs/images/start_prompter.png
deleted file mode 100644
index 6284b54c..00000000
Binary files a/docs/images/start_prompter.png and /dev/null differ
diff --git a/docs/images/task_definition_1.png b/docs/images/task_definition_1.png
deleted file mode 100644
index 86b9d535..00000000
Binary files a/docs/images/task_definition_1.png and /dev/null differ
diff --git a/docs/images/task_definition_2.png b/docs/images/task_definition_2.png
deleted file mode 100644
index a2b24eb7..00000000
Binary files a/docs/images/task_definition_2.png and /dev/null differ
diff --git a/docs/images/task_details.png b/docs/images/task_details.png
deleted file mode 100644
index 9e8befc8..00000000
Binary files a/docs/images/task_details.png and /dev/null differ
diff --git a/docs/index.md b/docs/index.md
deleted file mode 100644
index ed26f7a7..00000000
--- a/docs/index.md
+++ /dev/null
@@ -1,77 +0,0 @@
----
-title: RoboCo
-hide:
- - navigation
----
-
-# RoboCo
-
-**RoboCo is a self-hosted AI software company.** Twenty-five AI agents and one human — you — organized as a real engineering org: roles, a chain of command, formal reviews, and sign-offs. You don't wire up a swarm of bots or babysit a prompt loop. You run a company. You drop work in at the top, and the organization carries it all the way through planning, building, QA, review, and documentation, then brings it back to your desk for the final word.
-
-You act at the two ends. The company fills in everything between.
-
-{ loading=lazy }
-
-!!! warning "Early-stage software (v0)"
- RoboCo is a working prototype under active development. It runs in a homelab, has rough edges, and its API and database schema are not stable yet. It is **not production-ready** — don't expose it to the public internet as-is. Issues and pull requests are very welcome.
-
-
-
-- :material-rocket-launch:{ .lg .middle } **Get Started**
-
- ---
-
- Go from a cloned repo to a running company looking back at you from the Command Center.
-
- [:octicons-arrow-right-24: Install & first run](get-started/index.md)
-
-- :material-sitemap:{ .lg .middle } **Understand the company**
-
- ---
-
- The org, the roles, the strict task lifecycle, and how every agent is structurally sandboxed.
-
- [:octicons-arrow-right-24: The Company](company/index.md)
-
-- :material-movie-open-play:{ .lg .middle } **Take the tour**
-
- ---
-
- Follow one feature — RoboCo building its own Prompter — from a rough idea to a merged pull request.
-
- [:octicons-arrow-right-24: The Tour](how-to/README.md)
-
-- :material-github:{ .lg .middle } **Read the source**
-
- ---
-
- RoboCo is open source under AGPL-3.0. The whole stack, agents included, is on GitHub.
-
- [:octicons-arrow-right-24: rennf93/roboco](https://github.com/rennf93/roboco)
-
-
-
-## What you're running
-
-A single `docker compose up` brings up the whole stack behind one address — `http://localhost:3000` — and that one window is the company. Underneath it:
-
-- **A virtual organization.** A Board sets direction, a Main PM coordinates three delivery cells (Backend, Frontend, UX/UI), and an Auditor watches everything. You sit above all of it as CEO. [See the org →](company/org-and-roles.md)
-- **A strict lifecycle.** Every piece of work is a task, no task moves without acceptance criteria, and each task walks the same gated path — built, QA'd, documented, reviewed, approved. The structure is what turns a roster of models into a company that ships. [See the lifecycle →](company/task-lifecycle.md)
-- **Real git, real pull requests.** Each agent works in its own clone; work flows up a cell → root → master merge chain as actual pull requests on your repository. **Only you ever merge to `master`.** [See the merge model →](company/merge-model.md)
-- **A hard trust boundary.** Agents never touch your API or your shell directly. They act only through a narrow set of role-scoped verbs, so a developer can't merge, QA can't commit, and the Auditor can't even speak. [See how agents are sandboxed →](company/agent-gateway.md)
-
-## Watch it first
-
-If you'd rather see it than read about it:
-
-- [**The 26-minute intro**](https://www.youtube.com/watch?v=t1QNqJgBmkM) — what RoboCo is, a walkthrough, and how to use it.
-- [**The 2.5-hour build session**](https://www.youtube.com/watch?v=xige_EUIjIA) — a single conversation taken all the way to a shipped feature.
-- [**The 2:33 panel walkthrough**](videos/panel-full-walkthrough.mp4) — every page of the control panel, end to end.
-
-## How models are powered
-
-Agents run on **Anthropic Claude** by default, authenticated from the Claude Code session you already have on the host — no metered API key to wire up. You can also run the whole workforce on **xAI Grok** (the official `grok` CLI on a SuperGrok subscription), or point roles at **local / self-hosted** models. [Choosing & running models →](get-started/index.md)
-
----
-
-RoboCo is licensed under the [GNU Affero General Public License v3.0](https://github.com/rennf93/roboco/blob/master/LICENSE). Contributions are welcome and require a signed [Contributor License Agreement](https://github.com/rennf93/roboco/blob/master/CLA.md), automated on your first pull request.
diff --git a/docs/models/grok.md b/docs/models/grok.md
deleted file mode 100644
index a03d9a24..00000000
--- a/docs/models/grok.md
+++ /dev/null
@@ -1,56 +0,0 @@
-# Run on xAI Grok
-
-RoboCo can run the entire workforce — or just some agents — on **xAI Grok**, using xAI's official `grok` CLI on a **SuperGrok subscription** rather than a metered API key. That matters operationally: a subscription can't run out of credits mid-task, so a Grok fleet won't stall halfway through a delivery the way a metered key can. Grok reaches full parity with the Claude path by construction: the same MCP gateway, the same per-role tool manifest, the same prompt-injection and bash guards, the same per-agent cost capture.
-
-## Set it up once
-
-Authenticate Grok on the host with the official CLI, then point RoboCo at the resulting directory:
-
-```bash
-grok login # once, on the host — creates ~/.grok/auth.json
-```
-
-Then in `.env`:
-
-```bash
-ROBOCO_HOST_GROK_DIR=/home/youruser/.grok # the REAL host ~/.grok to mount in
-```
-
-The orchestrator mounts that directory's `auth.json` **read-only** into each Grok agent container. On a NAS or any docker-in-docker deploy the orchestrator's home is not the host's home, so `ROBOCO_HOST_GROK_DIR` must point at the actual host path where `grok login` wrote `~/.grok` — otherwise agents start with no credential.
-
-Finally, on **Settings → AI Providers** set the routing mode to **Grok** (whole fleet) or pin individual agents to a Grok model in **Mix** mode. See [Choosing a provider](./provider-routing.md) for the modes and precedence. The [installation guide](../get-started/installation.md#optional-run-on-grok-instead) covers the same first-run steps inline.
-
-## The token refreshes itself
-
-The Grok access token has a fixed ~6-hour, server-set lifetime, and the CLI can't refresh it headlessly — on an expired token it would hang forever at an interactive login prompt. RoboCo handles this for you:
-
-- Once per dispatch tick the orchestrator mints a fresh token from the offline-access refresh token (xAI's OIDC `refresh_token` grant) before expiry and atomically rewrites the shared `auth.json` in place. The refresh fires `ROBOCO_GROK_AUTH_REFRESH_SKEW` seconds (default `1800`) ahead of expiry.
-- As a backstop, each agent's entrypoint runs `python -m roboco.llm.providers.grok_auth --check` and **refuses to start** on a missing or expired token instead of hanging.
-
-!!! warning "The orchestrator's `~/.grok` mount must be writable"
- The orchestrator rewrites `auth.json` when it refreshes the token, so the orchestrator's own mount of `~/.grok` must be **read-write**. (The per-agent mount stays read-only — agents only read the credential.) If the orchestrator can't write it, the token will expire and Grok agents will fail their start-up `--check`. If the host `auth.json` is missing entirely at spawn time, the orchestrator logs a loud warning — a missing credential is the most common Grok misconfiguration, so it's surfaced early rather than as a fleet of failed starts.
-
-## Per-fleet tuning
-
-Three optional knobs let you trade cost against quality across the whole Grok fleet. All are env-set and apply uniformly (no per-role reduction — that's parity with the Claude path):
-
-| Variable | Default | What it does |
-|----------|---------|--------------|
-| `ROBOCO_GROK_REASONING_EFFORT` | unset (model default) | The `grok --effort` level. Set `low` / `medium` / `high` / `xhigh` / `max` to dial cost vs quality; empty, `default`, or `full` keeps the model's own default. |
-| `ROBOCO_GROK_MAX_TURNS` | `200` | The per-agent turn cap for a `grok -p` run. |
-| `ROBOCO_GROK_MAX_COST_USD` | `0` (off) | A per-agent cost ceiling in USD. The grok CLI has no live usage hook, so the orchestrator reads each running container's captured cost and kills it once it crosses this ceiling — a backstop against a runaway loop. `0` disables the cap. |
-
-Two more variables exist mostly for staged rollouts and tests:
-
-| Variable | Default | What it does |
-|----------|---------|--------------|
-| `ROBOCO_GROK_AGENT_IMAGE` | `roboco-agent-grok:latest` | Override the Grok agent Docker image. |
-| `ROBOCO_GROK_CLI_MODEL` | `grok-build` | The grok CLI model id passed to agents. |
-
-!!! note "Usage and cost still show up"
- Each Grok agent gets a per-agent usage directory mounted read-write so its token/cost is read back when the session finalizes. Grok traffic therefore lands on the same [usage dashboard](../operations/cost-and-usage.md) as Claude, priced from the captured session totals.
-
-## Next
-
-- [Choosing a provider](./provider-routing.md) — set the Grok mode or pin agents in Mix.
-- [What keeps a run alive](./resilience.md) — Grok agents park-and-resume on a rate limit like any other provider.
diff --git a/docs/models/index.md b/docs/models/index.md
deleted file mode 100644
index 2cfef661..00000000
--- a/docs/models/index.md
+++ /dev/null
@@ -1,25 +0,0 @@
-# Choosing & Running Models
-
-RoboCo's agents are backend-agnostic. By default the whole workforce runs on **Anthropic Claude**, authenticated from the Claude Code session on your host — no API key to manage. You can route the company onto **xAI Grok** instead, or point individual agents and roles at **local / self-hosted** models, all from one page in the panel.
-
-
-
-- **[Provider routing](provider-routing.md)**
-
- ---
-
- The Settings → AI Providers page: the routing modes, agent-over-role-over-global precedence, saved keys, and the fail-soft fallback.
-
-- **[Running on Grok](grok.md)**
-
- ---
-
- The whole workforce on xAI Grok via the official CLI and a SuperGrok subscription — no metered key.
-
-- **[Resilience](resilience.md)**
-
- ---
-
- What keeps a run alive: crash auto-retry, and how rate limits and provider overloads park work instead of dropping it.
-
-
diff --git a/docs/models/provider-routing.md b/docs/models/provider-routing.md
deleted file mode 100644
index 486c1ace..00000000
--- a/docs/models/provider-routing.md
+++ /dev/null
@@ -1,60 +0,0 @@
-# Choosing a provider
-
-By default every agent runs on Anthropic Claude — no key, no config. The orchestrator mounts your host `~/.claude` session into each container and that's the whole setup. When you want something else — the whole fleet on Grok, a few agents on a self-hosted model, or a deliberate mix — you don't edit env files. You set it on **Settings → AI Providers** (`/settings/ai-providers`, linked from the sidebar footer), and the choice is stored server-side and resolved per agent at spawn.
-
-## The routing modes
-
-The page has one global **routing mode** that decides which backend every agent uses unless you override it per agent:
-
-| Mode | What it does | Needs |
-|------|--------------|-------|
-| **Anthropic** | Every agent runs on Claude via the mounted `~/.claude` auth. The default. | Nothing — the orchestrator's `~/.claude` mount |
-| **Grok** | Every agent runs on xAI Grok (`grok-build`). | A saved Grok key *or* a SuperGrok login — see [Run on Grok](./grok.md) |
-| **Ollama** | Every agent runs on Ollama Cloud. | A saved Ollama Cloud key |
-| **Self-Hosted** | Every agent runs against your own OpenAI-compatible endpoint. | A base URL with a successful **Test Connection** |
-| **Mix** | Pin individual agents to specific models; everything else inherits the global default. | Whatever the pinned models need |
-
-Anthropic, Ollama Cloud, and self-hosted models all speak the Anthropic Messages wire protocol, so they run *through* the same Claude Code runtime — the orchestrator just injects the endpoint and key. Only Grok speaks a different protocol and runs in its own agent image. You don't have to think about that distinction; it's just why Grok is the one mode with a separate setup page.
-
-!!! note "The CEO seat is not an agent"
- Mix mode shows a per-agent table mirroring the org chart, but you (the CEO) are intentionally excluded — there's no model to assign to the human seat. The Intake (Prompter) and Secretary chats *are* in the table.
-
-## How a route is resolved: agent > role > global
-
-When the orchestrator spawns an agent, it picks the model by a three-rung precedence ladder, most specific first:
-
-1. **Agent** — a model pinned to that exact agent (set in Mix mode).
-2. **Role** — a model assigned to the agent's role.
-3. **Global** — the global mode's default.
-
-The first rung that has an assignment wins. So in Mix mode you can pin `be-dev-1` to one model, leave the rest of the backend cell on the global default, and the dispatcher resolves each one independently at spawn time. Switching the global mode **clears all per-agent overrides** (the panel asks you to confirm), so flip to Mix *after* you've chosen your baseline, not before.
-
-## Saving keys and endpoints
-
-Three secrets live on this page, all stored **Fernet-encrypted** server-side and **never returned by the API** — the panel only ever sees a `has_key` / `has_token` boolean, so you re-enter (you can't read back) a key:
-
-- **Grok (xAI) key** — only needed if you authenticate Grok with a key rather than a SuperGrok login.
-- **Ollama Cloud key** — required before any agent can route to Ollama Cloud.
-- **Self-hosted endpoint** — a base URL plus an optional auth token. Hit **Test Connection** to confirm reachability and auto-discover the model list; **Refresh** re-discovers it. A self-hosted assignment won't save until the connection tests clean.
-
-The panel guards you client-side: it blocks saving a Grok / Ollama / self-hosted assignment when the matching key or connection is missing, and warns when an Ollama-routed agent has no key (see below).
-
-## Fail-soft: misconfig falls back to Anthropic
-
-Routing is deliberately fail-soft. A *stalled* spawn is worse than a *wrong* model, so on any of these the orchestrator silently degrades that agent to Anthropic Claude rather than refusing to start it:
-
-- no assignment found for the agent, its role, or the global default;
-- a self-hosted or Ollama endpoint that's unreachable (the orchestrator probes `/api/tags` before committing to it);
-- a stored key or token that fails to decrypt.
-
-!!! warning "A quiet fallback can look like success"
- Because the fallback is silent, an agent you *think* is on your self-hosted model may actually be running on Claude — for example if the endpoint went unreachable after you tested it. The fallback is logged in the orchestrator (`docker compose logs orchestrator` shows the warning). If you're routing away from Anthropic, watch the per-model breakdown on the [usage dashboard](../operations/cost-and-usage.md) to confirm the traffic is landing where you intended.
-
-!!! info "Providers are seeded by the migrations"
- The Anthropic, Grok, Ollama Cloud, and self-hosted provider rows are created by `alembic upgrade head`, which the stack runs for you on boot. The AI Providers page only sets keys, mode, and assignments — it never creates providers. If you skipped migrations you'll see "provider not seeded" errors here.
-
-## Next
-
-- [Run on Grok](./grok.md) — the SuperGrok path end to end.
-- [What keeps a run alive](./resilience.md) — crash retry and provider park-and-resume.
-- The same guardrails apply on every backend — see [how agents are sandboxed](../company/agent-gateway.md).
diff --git a/docs/models/resilience.md b/docs/models/resilience.md
deleted file mode 100644
index 0e979ae0..00000000
--- a/docs/models/resilience.md
+++ /dev/null
@@ -1,51 +0,0 @@
-# What keeps a run alive
-
-A long delivery run spans hundreds of spawned containers, and the things that can interrupt one — a model crash, a provider rate limit, a transient overload — are normal, not exceptional. RoboCo is built so none of those quietly kills the work or burns your tokens crash-looping. Two mechanisms do the heavy lifting: **crash auto-retry then escalate**, and **provider park-and-probe**. Both run server-side in the orchestrator, the same way on every backend.
-
-## Crash: auto-retry, then escalate once
-
-When an agent container stops, the orchestrator inspects how it exited:
-
-- **A clean exit** (the agent called `i_am_idle` — it ran out of work) resets that agent's error count. Nothing to do.
-- **A provider overload** (see below) parks the provider instead of treating it as a crash.
-- **A genuine crash** goes to retry-or-escalate.
-
-On a real crash the orchestrator bumps the agent's error count and **respawns it on the same task** — up to a cap of **3** retries. At exactly the cap it escalates **once** to a human notification (the agent is stranded), then stays quiet so a hard failure can't spam you. The respawn is cold (a fresh container), but it picks the task back up, so a one-off crash is invisible in practice.
-
-```mermaid
-flowchart LR
- A[Container stopped] --> B{How did it exit?}
- B -->|i_am_idle, clean| C[Reset error count]
- B -->|529 / 500 / 503 overload| D[Park the provider]
- B -->|crash| E{error_count < 3?}
- E -->|yes| F[Respawn on same task]
- E -->|no, == 3| G[Escalate once to a human]
-```
-
-## Rate limits & overloads: park, probe, resume
-
-When a provider pushes back, retrying immediately just burns tokens against a wall. So instead of crash-looping, RoboCo **parks** that provider and queues its work:
-
-- A **rate limit (HTTP 429)** parks the provider. The agent reports `i_am_blocked(reason="rate_limited")`, the spawn gate stops launching new work for that provider, and a background loop probes for recovery.
-- A **persistent overload (HTTP 529 / 500 / 503)** parks the same way. The model SDK already retries genuinely transient blips; a *persistent* overload is detected from the dead container's log markers and parked rather than crash-retried straight back into the overload. This is gated by `ROBOCO_OVERLOAD_BREAK_ENABLED`, which is **on by default**.
-- A **Claude session limit** — the org's rolling 5-hour usage window — parks the same way. Hitting it terminates the agent container with a 429 before the agent can report it, so RoboCo detects it from the dead container's exit (like an overload) and parks the provider instead of crash-respawning the whole fleet straight back into the limit; the queued work auto-revives when the window resets. Also covered by `ROBOCO_OVERLOAD_BREAK_ENABLED`.
-
-The crucial property: **work is queued, never dropped.** Parked tasks wait; the background probe-and-resume loop requires a real `2xx` from the provider before it lifts the park and revives the parked agents. When the provider recovers, the queued work flows again on its own — you don't restart anything.
-
-!!! info "The amber banner"
- While a provider is parked you'll see an amber banner across the panel: a per-provider countdown, how many agents are affected, and "operations paused — resuming automatically." It clears itself when the provider recovers. An empty banner means nothing is parked. The banner is driven live over the `/ws/system` WebSocket and re-syncs over HTTP if the socket drops — so a quiet provider reads as *paused, resuming*, not as a hang.
-
-!!! tip "Parked is not stuck"
- If a run goes quiet, check the banner before assuming something broke. A parked provider with a counting-down timer is RoboCo waiting out a rate limit on purpose. The work is held and will resume — there's nothing for you to do.
-
-!!! info "Escape hatch for a probe that never recovers"
- Park-and-probe assumes the provider comes back. If a provider's probe fails persistently (the secret was rotated, the endpoint moved), an escape hatch releases the parked work back to the pool instead of holding it forever — so a permanently-dead provider doesn't strand its tasks. Grok auth-missing (exit 78) is parked the same way rather than crash-retried straight back into the same missing-credential failure.
-
-## Disk housekeeping: dangling-image prune
-
-Every agent-image rebuild leaves the previous build behind as a dangling (``) Docker image. Left alone they pile up and eat disk. The orchestrator's background sweep prunes them on a throttle (~6h): it removes **only** dangling images — a tagged image, or one still backing a running container, is never touched. It is gated by `ROBOCO_IMAGE_PRUNE_ENABLED`, which is **on by default**. This isn't a feature flag you opt into; it's an always-on safety net you can disable if you'd rather manage image cleanup yourself.
-
-## Next
-
-- These guardrails are part of the broader [agent gateway](../company/agent-gateway.md) — agents are structurally constrained, not trusted to behave.
-- [Choosing a provider](./provider-routing.md) and [running on Grok](./grok.md).
diff --git a/docs/operations/cost-and-usage.md b/docs/operations/cost-and-usage.md
deleted file mode 100644
index 520d8bc1..00000000
--- a/docs/operations/cost-and-usage.md
+++ /dev/null
@@ -1,97 +0,0 @@
-# Cost & usage
-
-RoboCo measures what your workforce spends in tokens and dollars, and shows it to you live in the panel. This page explains where those numbers come from, how to read the dashboard, how each provider is priced, and what cost controls exist (and where they don't).
-
-## How spend is measured
-
-Spend is captured **per agent session** — one container, doing one stretch of work. Each spawned agent runs a small in-container SDK server that watches the agent's own transcript and exposes its running token counts (input, output, cache-read, cache-write). The orchestrator runs a background sweep every **~60 seconds**: for every active agent it pulls the live counts, writes a usage snapshot, and updates the open session row so the database reflects progress mid-run. When the container stops, the session is **finalized** — final token counts are resolved, priced through the built-in cost table, and written to the closed session row along with the exit reason.
-
-A separate daily rollup keeps a rolling per-day, per-agent, per-team, per-model tally that feeds the "today" figures.
-
-!!! note "Why mid-run numbers move, and why a crash can read $0"
- Because cost is computed per session and firms up only when the session ends, the figures for a still-running agent update roughly every minute and aren't final. A session that crashes or is abandoned before its transcript is read can finalize at a low or zero value. The dashboard is an accurate ledger of *closed* sessions plus a live estimate for the ones still open — not a real-time invoice.
-
-Grok agents have no live SDK hook; the orchestrator reads each Grok container's `usage.json` instead, and uses the same file to enforce the per-agent Grok cost cap (below).
-
-## The Token Usage & Cost dashboard
-
-Two panel surfaces show spend:
-
-- The **command center** carries a **Token Usage & Cost** card that streams live while agents work. It listens on the `/ws/system` WebSocket and shows a **Live** badge when connected; if the socket drops it falls back to HTTP polling and shows **Polling** (or **Connecting**). See [the command center](../panel/command-center.md).
-- The **Metrics** page has a dedicated **Token Usage** tab with the full breakdown. See [Metrics](../panel/metrics.md).
-
-A **24h / 7d / 30d** selector drives every panel. What you get:
-
-| Panel | What it shows |
-|-------|----------------|
-| Summary | Input, output, and total tokens for the period, plus total cost in USD |
-| Trend | Percent change vs the immediately prior window of equal length |
-| Time series | Hourly points for 24h; daily points for 7d/30d |
-| Per-model | Donut of cost share by model |
-| Per-agent / per-team | Bar charts of spend, each with its share of the total |
-| Monthly projection | Forecast spend (see below) |
-| Cache efficiency | Cache hit-rate and the dollars prompt-caching is saving |
-| Recent sessions | Raw recent spawn-session rows (default 50) |
-
-!!! info "Totals count all four token classes"
- The total-token and cost figures sum **input + output + cache-read + cache-write**. Prompt-caching reads are cheap but not free, so they show up in both the totals and the cache-savings panel.
-
-!!! warning "Projection and cache savings are estimates"
- The monthly projection is a naive extrapolation: the average daily cost over the last 7 days × 30. It's a planning forecast, not a bill, and it overstates if you spun up the fleet for a one-off burst. The cache-savings figure uses a single aggregate baseline rate to estimate what the cached tokens *would* have cost at the full input price — treat it as indicative, not exact.
-
-## How each provider is priced
-
-Pricing is provider-aware, from a built-in USD-per-million-token table (`roboco/billing/pricing.py`). Model names are matched on substring, longest fragment wins.
-
-| Provider / model | Input | Output | Priced? |
-|------------------|-------|--------|---------|
-| Claude Opus 4 | $5.00 | $25.00 | yes (cache read $0.50, write $6.25) |
-| Claude Sonnet (4 / 3.7 / 3.5) | $3.00 | $15.00 | yes (cache read $0.30) |
-| Claude Haiku 4 / 3.5 | $1.00 | $5.00 | yes |
-| xAI `grok-build` | $1.00 | $2.00 | yes (cache read $0.20) |
-| Local Ollama (`ollama/…` or bare tag) | — | — | **$0 by design** |
-| Ollama Cloud (`:cloud` tag) | — | — | **$0 by design** |
-
-!!! note "$0 for local and Ollama Cloud is not a bug"
- Self-hosted Ollama runs on hardware you own and Ollama Cloud is billed by flat subscription, so neither carries a per-token cost. RoboCo intentionally prices them at $0 — it is not undercounting, and you won't see a warning.
-
-!!! warning "A brand-new Claude model can silently undercount"
- If a `claude`-named model isn't in the pricing table, RoboCo logs a warning and returns $0 for it rather than crashing. That **is** real spend going uncounted. If you point an agent at a Claude model newer than this build and see $0 cost on a busy fleet, the table needs the new rate added — check the orchestrator logs for the pricing warning.
-
-## Cost controls (and the asymmetry)
-
-There is exactly one built-in dollar cap, and it only covers Grok:
-
-| Setting | Default | What it does |
-|---------|---------|--------------|
-| `ROBOCO_GROK_MAX_COST_USD` | `0.0` | Per-agent Grok cost ceiling in USD, read from the container's `usage.json`. The orchestrator kills a Grok container once it crosses this, catching runaway-loop token burn. `0` disables it. **Grok agents only.** |
-
-!!! danger "There is no built-in dollar cap for Claude agents"
- The Claude path is **observe-only** on cost. RoboCo will show you Claude spend live and historically, but it will not auto-kill a Claude agent for crossing a dollar threshold — there is no `ROBOCO_*_MAX_COST_USD` equivalent for it. Your protection against runaway Claude spend is the structural one: rate-limit and overload **park-and-probe** (a provider 429 or persistent overload queues the agent and probes for recovery instead of retrying in a hot loop — see [provider resilience](../models/resilience.md)), the per-task verb gateway, and watching the dashboard. Budget accordingly.
-
-A related guard reaps abandoned interactive chats so they don't leak a container:
-
-| Setting | Default | What it does |
-|---------|---------|--------------|
-| `ROBOCO_INTERACTIVE_IDLE_REAP_SECONDS` | `1800` | Reaps an idle live Intake/Secretary chat (by time since last turn) so it stops holding a container and burning tokens. `0` disables. |
-
-## Quick checks from the shell
-
-```bash
-# Period summary (totals + cost + trend)
-curl -s 'http://localhost:3000/api/usage/summary?period=7d'
-
-# Monthly projection
-curl -s http://localhost:3000/api/usage/projection
-
-# Container-level resource use (not token cost)
-docker stats
-docker system df
-```
-
-## Next
-
-- Read the live dashboard on [the command center](../panel/command-center.md) and the full breakdown on [Metrics](../panel/metrics.md).
-- See where the live stream comes from in [WebSockets](../api/websockets.md) and the `/api/usage/*` routes in the [REST API](../api/rest-api.md).
-- Understand the park-and-probe spend protection in [provider resilience](../models/resilience.md).
-- For operational (non-cost) health, see [health & metrics](./health-and-metrics.md).
diff --git a/docs/operations/health-and-metrics.md b/docs/operations/health-and-metrics.md
deleted file mode 100644
index a88a7091..00000000
--- a/docs/operations/health-and-metrics.md
+++ /dev/null
@@ -1,74 +0,0 @@
-# Health & metrics
-
-Two different questions an operator asks: *is the system up?* and *is the workforce productive?* RoboCo answers the first with two HTTP probes, and the second with an operational Metrics view. Neither has anything to do with token cost — for spend, see [cost & usage](./cost-and-usage.md).
-
-## Liveness and readiness probes
-
-The orchestrator exposes two probes behind nginx (so they're reachable at `localhost:3000/api/...`, or directly on the orchestrator):
-
-| Endpoint | Checks | Returns |
-|----------|--------|---------|
-| `GET /api/health` | The process is up | Always `200` with `{ status: "ok", version, environment }` once the app is serving |
-| `GET /api/ready` | Database (`SELECT 1`) **and** Redis (`PING`) | `200` with `{ status, database, redis }`; `status` is `ok` only when both pass, otherwise `degraded` |
-
-```bash
-curl -s http://localhost:3000/api/health
-curl -s http://localhost:3000/api/ready
-```
-
-!!! info "Readiness is the one to watch"
- `/api/health` is a liveness probe — it stays `200` as long as the process answers, so it can't tell you a dependency is down. `/api/ready` is the real readiness signal: it actively pings Postgres and Redis and reports `degraded` (still HTTP `200`, but `status: "degraded"` with the failing dependency's error in the `database`/`redis` field) when either is unreachable. Point your uptime monitor at `/api/ready` and alert on `degraded`.
-
-!!! note "Startup ordering"
- The app-level root `/health` used during container startup is additionally gated on the in-house RAG engine being operational, which is why the orchestrator can take a minute to report healthy after a cold start while it indexes documents. See [deployment](../deploy/deployment.md) for the full startup sequence.
-
-!!! note "Agent gateway recovery"
- Those probes cover the *infrastructure*; individual agents have their own liveness story. An agent whose MCP gateway breaks (a corrupted `/app` venv firing no verb) stays "up" as a container but does no work, and its verb-heartbeat goes stale. With `ROBOCO_GATEWAY_HEALTH_ENABLED` (default on) the reaper probes such a stale-but-live agent's gateway out-of-band and, once it's been broken past `ROBOCO_GATEWAY_HEALTH_GRACE_SECONDS`, kills and respawns it instead of protecting it forever — so a wedged agent self-heals without operator action. You don't monitor this directly; it shows up as a "broken-gateway agent killed and evicted" line in the orchestrator log.
-
-## The Metrics → Performance view
-
-The **Metrics** page has a **Performance** tab driven by tasks, messages, and notifications — your read on whether work is actually flowing. See the panel walkthrough in [Metrics](../panel/metrics.md).
-
-What it surfaces:
-
-| Group | Metrics |
-|-------|---------|
-| Velocity | Tasks completed vs created, average completion time (hours), completion rate |
-| Blockers | Active blockers, average and longest blocked time, blockers by team |
-| Team & agent | Per-team and per-agent performance |
-| Communication | Message/notification volume |
-
-### The ok / slow / critical health signal
-
-Org and per-team health roll up to a single status driven mainly by the **blocked-task ratio**:
-
-```mermaid
-flowchart LR
- A[blocked / total tasks] -->|ratio > 0.3| C[critical]
- A -->|ratio > 0.15| S[slow]
- A -->|otherwise| K[ok]
-```
-
-A team with more than 30% of its tasks blocked reads **critical**; over 15% reads **slow**; below that, **ok**. A heuristic also flags a team sitting on stale active tasks with zero completions. When you see **slow** or **critical**, the Blockers panel tells you where the work is jammed and which team owns it — chase the longest-blocked tasks first.
-
-!!! tip "Health is about flow, not errors"
- This status is computed from task state, not exceptions or crashes. A green org-health with a `degraded` `/api/ready` means the infrastructure is wobbling even though the backlog looks healthy — watch both signals, they answer different questions.
-
-## The Metrics → Delivery view
-
-Where Performance answers *is work flowing*, the **Delivery** tab answers *where the time goes and how clean the work is* — reconstructed from the recorded task-transition history, so it costs no extra bookkeeping. Use it when velocity dips and you need the *why*:
-
-| Panel | Operational read |
-|-------|------------------|
-| Cycle time by stage | Average dwell per lifecycle stage — a tall stage is where work waits (e.g. review vs coding) |
-| Bottlenecks | The single worst stage by total time absorbed + how many tasks are parked in each stage right now |
-| Rework | How often work bounces to `needs_revision`, by cell and by agent (the bounce charged to the QA/PR-reviewer who sent it back), plus its token cost |
-| Cell scorecards | Per-cell completed / avg cycle / rework / cost over 7 days |
-
-The full reading guide — especially how rework attribution works — is in the panel walkthrough at [Metrics → Delivery](../panel/metrics.md#delivery).
-
-## Next
-
-- Walk the panel surface in [Metrics](../panel/metrics.md) and [the command center](../panel/command-center.md).
-- For token spend and the cost dashboard, see [cost & usage](./cost-and-usage.md).
-- For the startup sequence and what each container needs, see [deployment](../deploy/deployment.md).
diff --git a/docs/operations/index.md b/docs/operations/index.md
deleted file mode 100644
index e887736b..00000000
--- a/docs/operations/index.md
+++ /dev/null
@@ -1,19 +0,0 @@
-# Cost & Observability
-
-RoboCo measures what the company spends and how it's performing, and shows both in the panel. This section explains the cost model and the operational signals.
-
-
-
-- **[Cost & usage](cost-and-usage.md)**
-
- ---
-
- How token spend is measured, the Token Usage & Cost dashboard, provider-aware pricing (local is $0 by design), and the cost caps.
-
-- **[Health & metrics](health-and-metrics.md)**
-
- ---
-
- The health and readiness probes, and the delivery-performance metrics — velocity, blockers, and team health.
-
-
diff --git a/docs/optional/autonomous-maintenance.md b/docs/optional/autonomous-maintenance.md
deleted file mode 100644
index c196f4b0..00000000
--- a/docs/optional/autonomous-maintenance.md
+++ /dev/null
@@ -1,118 +0,0 @@
-# Autonomous maintenance
-
-RoboCo can keep your projects healthy on their own schedule: it can watch each opted-in project's CI and open a fix task when it goes red, and it can periodically check whether a dependency upgrade would change a project's lockfiles and open an "update dependencies" task when it would. Both are per-project, both are **off by default**, and **neither ever auto-merges** — every task they open rides the normal `dev → QA → PR review → CEO merge` pipeline, exactly like any other task.
-
-These two engines generalize the [self-healing CI loop](self-heal.md), which watches only RoboCo's own repository. Multi-repo CI-watch extends the same idea to *any* project you opt in.
-
-## Multi-repo CI-watch
-
-CI-watch assesses each opted-in project's CI on its default branch. On a red conclusion it opens **one** fix task into that project and notifies that project's cell PM. It never starts that task, never merges it, and never deploys.
-
-### What it does
-
-On each pass (`ROBOCO_CI_WATCH_INTERVAL_SECONDS`, default 1800s) the engine checks each opted-in project's latest CI conclusion on its default branch. On a red conclusion it opens one fix task into that project and notifies the project's cell PM. The pass is resilient by construction:
-
-- A **missing CI signal** is treated as "unknown", never a false green — an absent run never masks a real failure.
-- One repo's **GitHub error never aborts the sweep** — the engine moves on to the next project.
-- Origination is **bounded and deduped per `(repo, workflow)`**: a same-workflow monorepo's cell-projects share one fix task, while two red workflows on one repo each get their own; the caps below stop a flapping CI from flooding the backlog.
-
-```mermaid
-flowchart TD
- A[Interval tick] --> B{For each opted-in project}
- B --> C{CI conclusion on default branch}
- C -->|green| B
- C -->|unknown / missing| B
- C -->|red| D[Open ONE fix task · notify the cell PM]
- D -.never auto.-> E[never merges · never deploys]
-```
-
-!!! danger "It never merges or deploys"
- A CI-watch fix task is an ordinary task. It flows through the normal delivery lifecycle — QA, the in-path PR-review gate, and your merge — exactly like work you create yourself. The engine never approves, merges, or deploys on its own.
-
-### Bounds on origination
-
-| Setting | Default | Meaning |
-|---------|---------|---------|
-| `ROBOCO_CI_WATCH_MAX_PER_CYCLE` | `1` | Most fix tasks the sweep may open in one cycle. |
-| `ROBOCO_CI_WATCH_MAX_OPEN_TASKS` | `3` | Rolling cap on concurrently-open CI-watch fix tasks per repo; the engine originates nothing more while this many are still open. |
-
-### Enable it
-
-=== "Panel"
-
- **Settings → Feature Flags** carries the global **"Multi-repo CI-watch"** toggle. Then opt each project in from the **edit-project dialog → "Autonomous Maintenance" section**: turn on `ci_watch_enabled` and optionally set `ci_watch_workflow` (the workflow file to scope the CI signal to, default `ci.yml`).
-
- !!! note "Takes effect on the next backend restart"
- The feature flag persists in the settings store and applies on the **next backend restart**. The per-project fields apply on the next sweep.
-
-=== "Environment"
-
- ```bash
- ROBOCO_CI_WATCH_ENABLED=true # global switch
- # ROBOCO_CI_WATCH_INTERVAL_SECONDS=1800 # default
- # ROBOCO_CI_WATCH_MAX_OPEN_TASKS=3 # default
- # ROBOCO_CI_WATCH_MAX_PER_CYCLE=1 # default
- ```
-
- The per-project opt-in (`ci_watch_enabled`, `ci_watch_workflow`) lives on the project, not in env — set it in the edit-project dialog.
-
-## Dependency-update bot
-
-The dependency-update bot periodically checks whether a dependency upgrade would change a project's lockfiles and, if so, opens **one** "update dependencies" task into that project. Detection is read-only: nothing in the real repo is ever mutated.
-
-### What it does
-
-On each pass (`ROBOCO_DEP_UPDATE_INTERVAL_SECONDS`, default 604800s — weekly) the bot runs the project's `dep_update_command` (e.g. `uv lock --upgrade` / `pnpm update`) in a **throwaway clone** and diffs the lockfiles. If the lockfiles would change it opens one "update dependencies" task; otherwise it opens nothing.
-
-- Detection is **read-only**: the command runs in a throwaway clone and only the lockfiles are diffed. The real repo is never mutated — nothing is committed or pushed.
-- It is **fail-safe**: a null `dep_update_command` or a command that fails opens nothing.
-- Origination is **bounded and deduped per repo**, with the caps below.
-
-```mermaid
-flowchart TD
- A[Interval tick] --> B{For each opted-in project}
- B --> C[Run dep_update_command in a throwaway clone]
- C --> D{lockfiles change?}
- D -->|no / null / fails| B
- D -->|yes| E[Open ONE update-dependencies task]
- E -.never auto.-> F[never merges · never deploys]
-```
-
-!!! danger "It never merges or deploys"
- The update-dependencies task is an ordinary task — QA, the in-path PR-review gate, and your merge all apply. The bot only ever *detects* and *opens*; it never commits, pushes, merges, or deploys.
-
-### Bounds on origination
-
-| Setting | Default | Meaning |
-|---------|---------|---------|
-| `ROBOCO_DEP_UPDATE_MAX_PER_CYCLE` | `1` | Most update-dependencies tasks the bot may open in one cycle. |
-| `ROBOCO_DEP_UPDATE_MAX_OPEN_TASKS` | `3` | Rolling cap on concurrently-open update-dependencies tasks per repo. |
-
-### Enable it
-
-=== "Panel"
-
- **Settings → Feature Flags** carries the global **"Dependency-update bot"** toggle. Then opt each project in from the **edit-project dialog → "Autonomous Maintenance" section**: set `dep_update_command` (e.g. `uv lock --upgrade` / `pnpm update`) and optionally `dep_update_paths` (comma-separated lockfile paths to watch; defaults to inferring `uv.lock` / `pnpm-lock.yaml`).
-
- !!! note "Takes effect on the next backend restart"
- The feature flag persists in the settings store and applies on the **next backend restart**. The per-project fields apply on the next sweep.
-
-=== "Environment"
-
- ```bash
- ROBOCO_DEP_UPDATE_ENABLED=true # global switch
- # ROBOCO_DEP_UPDATE_INTERVAL_SECONDS=604800 # default (weekly)
- # ROBOCO_DEP_UPDATE_MAX_OPEN_TASKS=3 # default
- # ROBOCO_DEP_UPDATE_MAX_PER_CYCLE=1 # default
- ```
-
- The per-project opt-in (`dep_update_command`, `dep_update_paths`) lives on the project, not in env — set it in the edit-project dialog.
-
-## What changes when each is on
-
-- With CI-watch on, a background sweep polls each opted-in project's CI on the configured interval; on a red conclusion a fix task appears in that project's backlog (bounded by the caps above) and its cell PM is notified. With the global flag off, nothing polls.
-- With the dependency-update bot on, a background sweep checks each opted-in project's lockfiles on the configured interval; when an upgrade would change them, an update-dependencies task appears. With the global flag off, nothing runs and no throwaway clone is made.
-
-## Next
-
-→ [Self-healing CI](self-heal.md) for the single-repo loop these generalize · [Task lifecycle](../company/task-lifecycle.md) for what an opened task does once you start it · [Environment reference](../deploy/env-reference.md) for the full env list · back to [Optional subsystems](index.md).
diff --git a/docs/optional/conventions.md b/docs/optional/conventions.md
deleted file mode 100644
index 185be886..00000000
--- a/docs/optional/conventions.md
+++ /dev/null
@@ -1,128 +0,0 @@
-# Architectural Conventions Standard
-
-The `make`-style gates you configure per project (ruff, mypy, eslint, your test suite) answer one question: *is the code valid?* They cannot answer a second one a senior reviewer would catch on sight: *does this code live where it belongs?* The Architectural Conventions Standard is RoboCo's answer to that second question. It gives each project a repo-canonical architecture map and a tree-sitter validator that **hard-gates** an agent from landing a model defined inside a router, a route handler that runs its own SQL, a React component that fetches its own data, or a `# noqa` / `# type: ignore` that quietly silences the linter.
-
-It is **off by default** behind `ROBOCO_CONVENTIONS_ENABLED`. Every hook — the auto-scaffold, the prompt injection, the per-task constraints, and the gates — is fully inert until you turn it on.
-
-## What it does
-
-When enabled, the standard reaches the work in two directions. It *guides* agents up front — an "Architectural Standard" block is injected into every agent's prompt at spawn, and a `## Constraints` section listing the project's block-level rules and module boundaries is auto-attached to every task. And it *enforces* the same rules at the gate — a `block`-level finding refuses `i_am_done` (the developer's pre-submit) and `pr_pass` (the [in-path PR gate](pr-review.md)) with the offending `file:line` and a fix hint, while QA sees the findings in its review evidence.
-
-The rules live in a per-project `.roboco/conventions.yml` with four curated parts plus a set of structural checks:
-
-| Part | What it is |
-|------|-----------|
-| **Module map** | Path prefixes mapped to a human purpose and the definition *kinds* forbidden there (`model`, `route`, `helper`, `business_logic`, `component`). "`routers/` is for HTTP routes — no models, no helpers." |
-| **Rules** | A toggleable rule set. Each rule fires at `warn` (advisory, never blocks) or `block` (refuses the gate). |
-| **Custom rules** | Project-specific regex rules — a pattern, a message, and a level, optionally scoped to languages. TypeScript-scoped custom rules apply to both `.ts` and `.tsx` files. |
-| **Waivers** | Accountable per-`(path, rule)` escape hatches with a written reason — the sanctioned way to relieve a false positive, reviewed in the PR. |
-
-### Placement, hygiene, and modularity checks
-
-The validator runs four check families over each changed file:
-
-- **Placement** — a definition whose *kind* is forbidden in its module (a model in a router). A misplaced **model**, **route**, or **component** is `block` by default; a misplaced **helper** only `warn`s — `helper` matches *any* top-level function, too blunt a signal to hard-block a route file's small private glue (the body-level `thin_routes` check is the real fat-handler guard).
-- **Hygiene** — the universal, stack-agnostic house-style rules seeded into every project: `no_lint_suppressions` (`block` by default — no `# noqa`, `# type: ignore`, `eslint-disable`) and `no_inline_comments` (`warn`). A small allowlist of *structurally unavoidable* framework codes is exempt from `no_lint_suppressions` — ruff's flake8-type-checking codes (`TC001`–`TC003`, for an import a framework needs at runtime) and pydantic's `prop-decorator` — so the rule keeps its teeth on genuine error-silencing without footgunning every pydantic/FastAPI project. A bare `# noqa` / `# type: ignore` or any other code is still flagged.
-- **Custom** — your project-specific regex rules.
-- **Modularity** — separation-of-concerns judgements the linters are blind to, inspecting a file's *composition* and a definition's *body*, not just its top-level kind:
-
-| Rule | Fires when | Default level |
-|------|-----------|---------------|
-| `modular_cohesion` | One file mixes architectural concerns (e.g. a model *and* a route *and* a component) | `block` |
-| `thin_routes` | A route handler does its own data access (SQLAlchemy `execute`/`scalars`/`add`/`select`…) instead of delegating to a service. Transaction-lifecycle calls (`commit`/`flush`/`refresh`) do **not** count — an explicit `await db.commit()` after delegating is a valid pattern | `block` |
-| `thin_components` | A React component fetches data in its body instead of through a hook | `block` |
-| `god_class` | A class grows past 15 methods (single-responsibility smell) | `warn` |
-
-!!! info "Precision over recall"
- Every check fires only on a confident, structural signal, and abstains when it is uncertain — so a `block`-level gate is never tripped by a guess. If the validator genuinely *cannot* run on a diff (a parse or grammar error), it is **fail-loud**: it exits non-zero and the gate blocks rather than passing silently. The validator is also **time-bounded** — a hung run (a tree-sitter deadlock, an enormous repo) is killed after 120s and treated as `could_not_run`, so a stuck subprocess can't hang the `i_am_done` / `pr_pass` gate forever or orphan a process on restart. And if the *effective map itself* can't be resolved (a conventions-service error), the gate **fails closed** rather than silently disabling the standard for that task.
-
-## The effective map: defaults, present, absent, or partial
-
-Consumers never read the raw committed file — they read the **effective map**, so behaviour is identical whether `.roboco/conventions.yml` is present, absent, or partial. `ConventionsService` (`roboco/services/conventions.py`) builds it by auto-deriving a baseline from a repo scan (it infers modules from directory names like `routers/`, `models/`, `services/`, `components/`, `hooks/`; **excludes test and documentation trees** — `tests/`, `docs/` — since those legitimately define fixtures and aren't enforced code; detects languages by file extension; seeds the universal hygiene rules) and then overlaying the committed file on top. The result is cached per `(project, HEAD sha)`.
-
-That is the load-bearing property: **the standard is enforced even before any file is committed.** A project with no `.roboco/conventions.yml` still gets sensible auto-derived rules and is gated by them. Resilience is built in — a missing file degrades to the auto-derived defaults, and an unparseable file falls back to the last-good cached map (status `degraded`) so the standard is never silently switched off by a typo.
-
-!!! info "Reads come from a dedicated clone — no setup needed for old projects"
- The committed file and the repo scan are read from a project-level **read clone** that the service ensures on demand (pinned to the default branch's HEAD), not from any agent's working clone. This is the backfill: a project created long before the standard existed — with no manually-configured workspace path — still resolves its committed `.roboco/conventions.yml` the first time the panel, a spawn, or a task asks for it. There is nothing to wire up.
-
-## The per-project Conventions editor
-
-Each project carries a **Conventions** tab in its edit dialog (panel component `panel/src/components/conventions/conventions-tab.tsx`). From there you manage the whole standard without hand-editing YAML:
-
-- **Module boundaries** — add/remove modules, set each one's path and purpose, and click a kind badge (`no model`, `no route`, `no helper`, `no business_logic`, `no component`) to toggle whether it is forbidden there.
-- **Rules** — flip each rule between `warn` and `block` with a switch.
-- **Custom rules** — add a regex `id`/pattern/message and set its level.
-- **Waivers** — exempt a file from a rule with a written reason.
-- **Recent violations** — the latest findings recorded across this project's tasks, each tagged with its rule and level.
-
-Two state banners keep you honest about what is in force:
-
-!!! note "Using auto-derived defaults"
- When no file is committed yet, the tab shows a neutral **"Using auto-derived defaults"** banner — *not* an error. These rules are already enforced. The Save button reads **"Save defaults to repo"**: one click backfills the canonical file. (The earlier read-only, "missing"-as-broken behaviour is gone — this is the full editor with one-click backfill.)
-
-!!! warning "Conventions degraded"
- If a committed file won't parse, an amber **"Conventions degraded"** banner appears. The effective map has fallen back to the last-good cache plus defaults; **Restore from last-good** re-commits the previous working file.
-
-### Save and Restore open a PR
-
-The standard is repo-canonical, so the editor never edits files behind your back. **Save to repo** and **Restore from last-good** each open a pull request against the project (via `GitService.open_conventions_pr`) carrying the new `.roboco/conventions.yml`. You review and merge it like any other change. If the project's workspace isn't cloned yet, the change is prepared on the branch and the toast tells you no remote PR was opened.
-
-## How agents are hard-gated
-
-```mermaid
-flowchart TD
- A[Developer finishes work] --> B[i_am_done]
- B --> C{conventions validator on changed files}
- C -->|block finding or could-not-run| D[REJECTED file:line + fix hint]
- C -->|warn-only / clean| E[proceeds to QA]
- D --> F[Dev fixes or commits a waiver]
- F --> B
- E --> G[QA sees findings in claim_review evidence]
- G --> H[PR assembled]
- H --> I[pr_pass at the in-path gate]
- I --> J{same validator}
- J -->|block / could-not-run| K[REJECTED back to needs_revision]
- J -->|clean| L[PM merges]
-```
-
-Enforcement is deterministic and lives at two gateway choke points (`roboco/services/gateway/choreographer/`):
-
-- **`i_am_done`** — the developer's pre-submit. A `block`-level finding refuses the verb with the offending `file:line` and a fix hint; the findings are also persisted to the project's violations feed (even the ones that blocked).
-- **`pr_pass`** — the [in-path PR-review gate](pr-review.md). The same validator runs on the assembled PR's changed files; a `block` finding fails it back to `needs_revision`.
-- **QA evidence** — when QA calls `claim_review`, the convention findings ride along in its review briefing so the human-style review sees them too.
-
-A false positive is relieved one way only: the developer commits a **waiver** in their branch — an accountable `(path, rule, reason)` entry reviewed in the PR — never a silent in-code `# noqa`.
-
-## Enable it
-
-You can turn the standard on two ways; the effect is the same.
-
-=== "Panel"
-
- Open **Settings → Feature Flags** and toggle **"Enforce a per-project architectural standard"** on.
-
- !!! note "Takes effect on the next backend restart"
- A feature-flag toggle persists in the settings store and is applied on the **next backend restart** — it is not a hot reload. Flip it, then restart the orchestrator.
-
-=== "Environment"
-
- Set the flag in your compose/env and restart:
-
- ```bash
- ROBOCO_CONVENTIONS_ENABLED=true
- ```
-
-An unset flag falls back to its config default (off). See the [environment reference](../deploy/env-reference.md) for the full flag list.
-
-## What changes when it's on
-
-- Every agent's prompt carries the project's "Architectural Standard" block, and every project task gets an auto-attached `## Constraints` section.
-- `i_am_done` and `pr_pass` block on `block`-level findings; QA sees findings in its review evidence.
-- The project's **Conventions** tab is live — view the effective map and health, edit it, and Save/Restore via a PR.
-- The validator CLI (`python -m roboco.conventions check --root --files …`) runs inside the agent image (the Python and TypeScript tree-sitter grammars are shipped there).
-
-When the flag is off, none of the above happens — no prompt block, no constraints, no gating, no scaffold.
-
-## Next
-
-→ [Toolchain matching](toolchain-matching.md) closes a different hollow-pass hole · [The in-path PR gate](pr-review.md) is where `pr_pass` runs · back to [Optional subsystems](index.md).
diff --git a/docs/optional/http-security.md b/docs/optional/http-security.md
deleted file mode 100644
index 58dd9ac7..00000000
--- a/docs/optional/http-security.md
+++ /dev/null
@@ -1,74 +0,0 @@
-# HTTP security hardening (fastapi-guard)
-
-RoboCo can front its API with a [fastapi-guard](https://pypi.org/project/fastapi-guard/) security layer — IP and rate controls, a signature WAF, security headers, cloud-provider and honeypot checks, an emergency kill switch, and three RoboCo-specific content validators — for when you expose the panel/API beyond a trusted LAN.
-
-The layer is **off by default**. When `ROBOCO_GUARD_ENABLED` is unset, `create_app` never mounts the middleware and the request path is byte-for-byte unchanged; the per-route guard decorators are harmless no-ops (`roboco/security.py`). A personal NAS deploy needs none of this — it's built for cloud/public hosting.
-
-## What it does
-
-Armed, the middleware sits outermost and applies, per route:
-
-- **Rate limiting & size caps** — a baseline throttle plus tighter per-endpoint limits on sensitive routes (provider-key writes, CEO release ops, agent verbs).
-- **A signature WAF** — SQLi/XSS/path-traversal/etc. detection on request bodies, headers, params, and path.
-- **Security headers** — HSTS, CSP, `X-Frame-Options`, `nosniff`, referrer and permissions policies on every response.
-- **Cloud-provider & honeypot checks** — block datacenter egress on the highest-value routes; form-trap honeypots on human-facing POSTs.
-- **Three RoboCo custom validators** the stock WAF cannot cover — **prompt-injection**, **secret-exfil**, and **internal-SSRF** scanning on the prompt-facing and agent-content surfaces.
-- **An emergency lockdown** (`ROBOCO_GUARD_EMERGENCY`) — a flip-on-without-redeploy switch that blocks every non-whitelisted IP during an active attack.
-
-Behind nginx, guard trusts the single proxy hop for the real client IP, excludes WebSocket upgrades and health/docs paths, and keeps RoboCo's own CORS.
-
-## Passive first, then enforce
-
-Guard has two enforcement postures, and the intended rollout is **passive → active**:
-
-| `ROBOCO_GUARD_PASSIVE_MODE` | Behaviour |
-|---|---|
-| `true` (calibrate) | **Log-only.** Detections are logged but **never block** — legit *and* malicious requests pass through. Safe to arm on live traffic to surface false positives first. |
-| `false` (enforce) | Detections **block** the request. |
-
-!!! warning "Calibrate before you enforce"
- RoboCo's request bodies *are* code, SQL, diffs, file paths, HTML, and URLs — task specs, agent notes and commits, RAG queries, git bodies, chat. A stock WAF reads that legitimate traffic as attacks. RoboCo ships a calibration (`excluded_detection_body_fields` in `build_security_config`, derived from the real request models) that excludes those free-text fields from WAF scanning so active mode does **not** false-positive — while the WAF stays active on every structured (id/enum/slug/branch) field and the prompt-injection / secret-exfil / SSRF validators keep firing regardless. Even so, arm **passive first** on your own deployment, watch the logs for any straggler false positive, then flip to active.
-
-The NAS composes arm the guard in passive/log-only mode by default (`ROBOCO_GUARD_PASSIVE_MODE=true`, `ROBOCO_GUARD_FAIL_SECURE=false`) so a deploy calibrates against real traffic before you enforce.
-
-## Scanner honeytrap & auto-ban
-
-Automated scanners probe every host for well-known soft spots (`/.env`, `/wp-login.php`, `/phpmyadmin`, `/.git/config`, …). RoboCo turns those probes against the scanner, in two layers matched to where the traffic actually lands — behind nginx only `/api`, `/ws`, `/health`, and `/ready` reach the orchestrator, so guard can only see probes on those paths:
-
-- **Guard adaptive ban (the `/api` surface).** The guard `threat_ban_config` carries `recon` / `sensitive_file` / `cms_probing` categories. A scanner probing those fingerprints on an `/api` path is detected on the URL-path scan, and repeated probes from one IP trip a per-IP auto-ban (redis-backed, 24h). This only bans in **active** mode (passive logs the recon hit) and requires redis (the 24h ban exceeds the in-memory cap).
-- **nginx edge-drop (the classic root paths).** The classic scanner paths never reach the orchestrator, so nginx drops them at the edge with `444` (closes the connection, returns nothing) before they touch the panel. It's anchored to known scanner fingerprints — `/.well-known` and every real panel/API route are untouched — and is always on, independent of `ROBOCO_GUARD_ENABLED`.
-
-## Fail-secure
-
-`ROBOCO_GUARD_FAIL_SECURE` decides what happens if a security check itself errors: `true` (default) fails **closed** — block the request — which is the right default for public hosting. The personal NAS compose overrides it to `false` so a guard-internal bug can never 500 your own deploy.
-
-## Enable it
-
-=== "Environment"
-
- ```bash
- ROBOCO_GUARD_ENABLED=true
- ROBOCO_GUARD_PASSIVE_MODE=true # calibrate first; flip to false to enforce
- ROBOCO_GUARD_FAIL_SECURE=true # false on a personal/NAS deploy
- ROBOCO_ENVIRONMENT=production # drives enforce_https (relaxed in development)
- # ROBOCO_GUARD_EMERGENCY=true # attack lockdown kill switch
- # ROBOCO_GUARD_EMERGENCY_WHITELIST=1.2.3.4 # extra allowed IPs during lockdown
- # ROBOCO_GUARD_TELEMETRY_ENABLED=true # + guard_agent_api_key + guard_project_id
- ```
-
-=== "Panel"
-
- **Settings → Feature Flags** exposes the master switch. The passive/fail-secure/environment knobs are environment settings, not flags — set them in env.
-
- !!! note "Takes effect on the next backend restart"
- The flag persists in the settings store and applies on the **next backend restart**.
-
-See the [environment reference](../deploy/env-reference.md#http-security-fastapi-guard) for the full flag list.
-
-## Telemetry (optional, off)
-
-`ROBOCO_GUARD_TELEMETRY_ENABLED` reports security events/metrics to a guard-core platform via guard-agent. It is **off by default** and **no data leaves the box** while off; flip it on and set `ROBOCO_GUARD_AGENT_API_KEY` + `ROBOCO_GUARD_PROJECT_ID` to enable.
-
-## Next
-
-→ [Environment reference](../deploy/env-reference.md#http-security-fastapi-guard) for every flag · [Deployment](../deploy/deployment.md) for where to set them · back to [Optional subsystems](index.md).
diff --git a/docs/optional/index.md b/docs/optional/index.md
deleted file mode 100644
index 581a66bd..00000000
--- a/docs/optional/index.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# Optional subsystems
-
-Beyond the core delivery loop, RoboCo ships a set of optional engines — most **off by default** — that you turn on when you want them. They're the "company-in-a-box" capabilities and the stricter quality gates. This page is the reference for all of them; each has its own page below.
-
-## The Feature Flags card
-
-You toggle these from **Settings → Feature Flags** in the panel rather than hand-editing environment variables. A toggle persists in the settings store and **takes effect on the next backend restart**. The matching `ROBOCO_*` environment variable is the same switch at the source — an unset flag falls back to its environment/config default, and some flags carry extra configuration (an API key, a project slug) that only lives in the environment.
-
-!!! info "The restart contract"
- Flipping a flag in the panel saves it immediately, but the subsystem it controls is wired up at startup — so the change lands on the **next backend restart**, not instantly.
-
-## What you can turn on
-
-| Subsystem | Flag | Default | What it does |
-|-----------|------|---------|--------------|
-| [Architectural Conventions](conventions.md) | `ROBOCO_CONVENTIONS_ENABLED` | off | Per-project rules for *where code lives*; hard-gates agents from misplaced code and lint suppressions. |
-| [Toolchain matching](toolchain-matching.md) | `ROBOCO_TOOLCHAIN_MATCH_ENABLED` | off (on in the personal compose) | Builds each project under its own declared Python and blocks gates when the suite can't run. |
-| [Web research](web-research.md) | `ROBOCO_RESEARCH_ENABLED` | off | Gives Board/PM agents gated web search & fetch through a provider you supply. |
-| [Strategy engine](strategy-engine.md) | `ROBOCO_STRATEGY_ENGINE_ENABLED` | off | Notify-only nudges when the company drifts, goes idle, or stalls. |
-| [Pitch provisioning](pitch-provisioning.md) | `ROBOCO_PROVISIONING_TOKEN` (+ org) | inert until set | On pitch approval, auto-creates repos and seeds a build task. |
-| [External / internal PR review](pr-review.md) | `ROBOCO_EXTERNAL_PR_ENABLED` / `ROBOCO_INTERNAL_PR_ENABLED` | off | Reviews inbound external/fork PRs and untied org-repo PRs. |
-| [Self-healing CI](self-heal.md) | `ROBOCO_SELF_HEAL_ENABLED` (+ originate) | off | Watches RoboCo's own CI and, optionally, queues a CEO-gated fix task. |
-| [Multi-repo CI-watch](autonomous-maintenance.md) | `ROBOCO_CI_WATCH_ENABLED` (+ per-project) | off | Watches each opted-in project's CI and opens one fix task when it goes red; never auto-merges. |
-| [Dependency-update bot](autonomous-maintenance.md) | `ROBOCO_DEP_UPDATE_ENABLED` (+ per-project) | off | Read-only checks whether an upgrade changes a project's lockfiles and opens an update task; never auto-merges. |
-| [HTTP security (fastapi-guard)](http-security.md) | `ROBOCO_GUARD_ENABLED` | off | Fronts the API with a WAF, IP/rate controls, security headers, and prompt-injection / secret-exfil / SSRF validators for public/cloud exposure — calibrated so active mode doesn't false-positive on agent traffic. |
-
-!!! note "Always-on resilience"
- Provider overload parking (`ROBOCO_OVERLOAD_BREAK_ENABLED`) and the dangling-image prune (`ROBOCO_IMAGE_PRUNE_ENABLED`) are **on by default** — they're not things you enable, they're safety nets you can disable. See [Resilience](../models/resilience.md).
diff --git a/docs/optional/pitch-provisioning.md b/docs/optional/pitch-provisioning.md
deleted file mode 100644
index d5357755..00000000
--- a/docs/optional/pitch-provisioning.md
+++ /dev/null
@@ -1,56 +0,0 @@
-# Pitch Auto-Provisioning
-
-Your Board can propose new products, not just deliver the ones you hand it. A **Pitch** (title, problem, proposed solution, target cells) is drafted by the Product Owner or Head of Marketing and lands in **Business → Pitches** for your decision. When you approve a pitch and provisioning is configured, RoboCo turns that approval into real infrastructure: one private GitHub repo per target cell, registered as Projects, with a Main-PM build task seeded into the normal delivery lifecycle. This is the only place in the whole system that *creates* GitHub repos — everywhere else clones, branches, and opens PRs against repos that already exist.
-
-## Default state
-
-The master switch `ROBOCO_PROVISIONING_ENABLED` defaults to `true`, but the capability is **inert unless a token and an org are both set**. With no `ROBOCO_PROVISIONING_TOKEN` and no `ROBOCO_PROVISIONING_ORG`, approving a pitch raises `ProvisioningDisabledError` and creates nothing. So out of the box, pitch approval is a no-op until you point it at a GitHub org. The Settings → Feature Flags card exposes the toggle ("Auto-provision projects from approved pitches"), but the toggle alone does nothing without the credentials.
-
-## Enable it
-
-1. **Create a GitHub PAT** with `repo` + org-admin scope, in the org you want repos created in.
-2. **Set the credentials** in your deploy environment:
-
- | Env var | Default | Purpose |
- |---------|---------|---------|
- | `ROBOCO_PROVISIONING_ENABLED` | `true` | Master switch. Inert regardless unless token + org are also set. |
- | `ROBOCO_PROVISIONING_TOKEN` | (empty) | GitHub PAT used to create repos. Needs `repo` + org-admin scope. **Server-side only.** |
- | `ROBOCO_PROVISIONING_ORG` | (empty) | GitHub organization where new repos are created. |
- | `ROBOCO_PROVISIONING_REPO_PRIVATE` | `true` | Whether provisioned repos are created private. |
- | `ROBOCO_GITHUB_API_BASE_URL` | `https://api.github.com` | REST API base — override for GitHub Enterprise. |
- | `ROBOCO_PROVISIONING_TIMEOUT_SECONDS` | `30.0` | Per-request timeout for GitHub provisioning calls. |
-
-3. Confirm the **Settings → Feature Flags** toggle is on (it falls back to the config default if unset).
-4. **Restart the backend.**
-
-The token and org live only in server-side config — like the research key, they are never injected into an agent container.
-
-## What changes when it's on
-
-When you approve a pitch in **Business → Pitches**, `PitchService` runs the provisioning sequence:
-
-```mermaid
-flowchart LR
- A[Board drafts Pitch] --> B[CEO approves]
- B --> C{token + org set?}
- C -->|no| D[ProvisioningDisabledError nothing created]
- C -->|yes| E[Create 1 private repo per target cell]
- E --> F[Register each as a Project + a Product if multi-cell]
- F --> G[Seed a Main-PM build task source=pitch, confirmed_by_human=true]
- G --> H[Normal delivery lifecycle]
-```
-
-A single-cell pitch produces one repo named after the slug; a multi-cell pitch produces one repo per cell (`{slug}-{cell}`) and a **Product** mapping each cell to its repo, which is what drives the Main-PM integration-branch model. The seeded task is a real PENDING task assigned to the Main PM and flows through the same lifecycle as any other work.
-
-## The partial-failure caveat
-
-!!! warning "A failed approval can leave orphan repos"
- GitHub repo creation is an un-rollback-able side effect. If provisioning fails partway — say it creates the first cell's repo and then errors on the second — the database writes roll back (the approval route does not commit), but **the repos already created on GitHub remain**. A re-approval will then collide on the repo name and fail. You resolve this manually: delete or rename the orphaned repo(s) on GitHub, or finish wiring them up by hand, before re-approving. RoboCo deliberately does not auto-delete repos it created, so it can never destroy work.
-
-## Required extra config
-
-A GitHub PAT (`repo` + org-admin scope) and the target org are mandatory — there is no provisioning without them. For GitHub Enterprise, also set `ROBOCO_GITHUB_API_BASE_URL`. Provisioning writes Project / Product / task rows, so make sure your migrations are current (`alembic upgrade head`).
-
-## Next
-
-→ **[Projects and products](../panel/projects-and-products.md)** — what a Project and a multi-cell Product are. → **[The merge model](../company/merge-model.md)** — how the Main PM cuts one integration branch per repo. → **[The business workflow](../how-to/05-the-business-workflow.md)** — drafting and reviewing pitches.
diff --git a/docs/optional/pr-review.md b/docs/optional/pr-review.md
deleted file mode 100644
index 064a47f0..00000000
--- a/docs/optional/pr-review.md
+++ /dev/null
@@ -1,53 +0,0 @@
-# External & Internal PR Review
-
-Not every pull request against your repos comes from inside the company. A contributor or a fork can open one, or a branch can land that no agent task owns. These two opt-in loops let the read-only **PR Reviewer** look at those PRs, post a single change-request, and surface them to you — without ever chatting, merging, or pushing to anyone else's fork. This is the inbound counterpart to the in-path PR gate that already reviews assembled cell→root and root→master PRs.
-
-## Default state
-
-Both loops are **off by default**:
-
-| Env var | Default | Purpose |
-|---------|---------|---------|
-| `ROBOCO_EXTERNAL_PR_ENABLED` | `false` | Inbound external/fork PR review. Off → the poll loop never runs and no inbound GitHub call is made. |
-| `ROBOCO_INTERNAL_PR_ENABLED` | `false` | Read-only safety reviewer for org-repo PRs not tied to a task. Off → those PRs are never picked up. |
-
-When both are off, no inbound discovery happens at all. The Settings → Feature Flags card exposes both ("Discover and review inbound external/fork pull requests" and "Run the read-only safety reviewer on internal branch PRs").
-
-## Enable it
-
-1. Set the flag(s) you want (`ROBOCO_EXTERNAL_PR_ENABLED` and/or `ROBOCO_INTERNAL_PR_ENABLED`), or flip the matching **Settings → Feature Flags** toggles.
-2. **Restart the backend.**
-
-## What changes when it's on
-
-A background poll lists open PRs per active project and routes them to the read-only PR Reviewer agent, which reads the diff against your standards and posts **one** change-request comment on the PR. It never converses, never decides, and never merges.
-
-**External PRs** (from outside contributors or forks) then land in the **PR Review Queue** on the Command Center, where the decision is yours:
-
-- **Supersede** — the company cuts its own branch from the contributor's commits, hardens it, opens its own PR, and links back to the original once that merges.
-- **Dismiss** — close the review and move on.
-
-Either way the org never pushes to someone else's fork, and untrusted contributor code is never fetched, checked out, or executed until a human confirms it.
-
-**Internal PRs** are org-repo (non-fork) PRs whose branch is **not** owned by an active task — branches pushed outside the agent task-flow. The reviewer runs the same read-only safety pass on them. The org's own in-flight integration PRs (whose branch a live task owns) are deliberately skipped, since those already pass QA and PM review in the normal lifecycle.
-
-!!! note "Read-only by design"
- The PR Reviewer's only output is the change-request it posts on the PR. It holds no merge authority — see [How agents are sandboxed](../company/agent-gateway.md). The accept/supersede/dismiss decision is always yours.
-
-## Tuning external review
-
-| Env var | Default | Purpose |
-|---------|---------|---------|
-| `ROBOCO_EXTERNAL_PR_POLL_INTERVAL_SECONDS` | `300` | Seconds between inbound external-PR discovery passes (minimum 60). |
-| `ROBOCO_EXTERNAL_PR_AUTHOR_ALLOWLIST` | (empty) | GitHub usernames trusted as known contributors. Empty → no author is auto-trusted; every external PR needs human confirmation. |
-| `ROBOCO_EXTERNAL_PR_REQUIRE_HUMAN_CONFIRM` | `true` | Require explicit human confirmation before any agent fetches, checks out, or executes external contributor code. |
-
-Leave `ROBOCO_EXTERNAL_PR_REQUIRE_HUMAN_CONFIRM` on unless you fully trust the inbound source — it is the gate that keeps untrusted code from running.
-
-## Required extra config
-
-The repos you want watched must be registered Projects with a valid git token (so the poll can list their PRs). No migration or provider key is needed beyond that.
-
-## Next
-
-→ **[The merge model](../company/merge-model.md#pull-requests-you-didnt-open)** — the operator-facing narrative of the Supersede / Dismiss flow. → **[How agents are sandboxed](../company/agent-gateway.md)** — why the reviewer cannot merge.
diff --git a/docs/optional/self-heal.md b/docs/optional/self-heal.md
deleted file mode 100644
index 8b2c0456..00000000
--- a/docs/optional/self-heal.md
+++ /dev/null
@@ -1,79 +0,0 @@
-# Self-healing CI loop
-
-RoboCo can watch its **own** repository's CI and heal itself: when its CI regresses, it notifies you, and — behind a second opt-in — queues a fix task into its own delivery lifecycle. It never starts that task, never merges it, and never deploys. Every downstream step stays a human decision.
-
-The loop is **dormant by default**. Nothing runs and no GitHub call is made until you arm it (`roboco/services/self_heal_engine.py`).
-
-## What it does
-
-On an interval (`ROBOCO_SELF_HEAL_INTERVAL_SECONDS`, default 1800s) the engine assesses the latest completed CI run on the target repo's default branch. On a detected regression — a failing run — it sends you an **acknowledgement notification** as the CEO. That is the entire behaviour of the first opt-in: **detect and notify**.
-
-With the second opt-in also on, a regression *additionally* opens a fix task into the regressed project's lifecycle — created at **`PENDING`** and held out of dispatch — and stops. It is layered so the loop can never run away with the backlog:
-
-```mermaid
-flowchart TD
- A[Interval tick] --> B{CI run on default branch}
- B -->|green| A
- B -->|regression| C[Notify the CEO]
- C --> D{originate enabled?}
- D -->|no| A
- D -->|yes| E[Open fix task at PENDING]
- E --> F[STOP — waits for your Approve-&-Start]
- F -.never auto.-> G[never merges · never deploys]
-```
-
-!!! danger "It never merges or deploys"
- The loop terminates at a human gate. An originated fix task sits at `PENDING`; once you Approve-&-Start it, it flows through the normal delivery lifecycle and ultimately escalates to `awaiting_ceo_approval` for your sign-off — exactly like any other task. The loop never approves, merges, or deploys on its own.
-
-### Bounds on origination
-
-Origination is capped so a flapping CI can't flood the backlog:
-
-| Setting | Default | Meaning |
-|---------|---------|---------|
-| `ROBOCO_SELF_HEAL_MAX_PER_CYCLE` | `1` | Most fix tasks the loop may open in one cycle. |
-| `ROBOCO_SELF_HEAL_MAX_OPEN_TASKS` | `3` | Rolling cap on concurrently-open self-heal tasks; the loop originates nothing more while this many are still open. |
-
-## Required configuration
-
-The loop watches exactly **one** project — RoboCo itself — and you must name it:
-
-| Setting | Required? | Notes |
-|---------|-----------|-------|
-| `ROBOCO_SELF_HEAL_ENABLED` | yes (first opt-in) | Master switch: detect + notify. Off ⇒ the loop never runs, no CI telemetry is fetched. |
-| `ROBOCO_SELF_HEAL_PROJECT_SLUG` | **yes** | The registered project slug that *is* RoboCo. Empty ⇒ the loop no-ops even when enabled. |
-| `ROBOCO_SELF_HEAL_ORIGINATE_ENABLED` | yes (second opt-in) | Adds task origination on top of notify. Off ⇒ notify-only. |
-| `ROBOCO_SELF_HEAL_CI_WORKFLOW` | no (default `ci.yml`) | Scopes the CI signal to one workflow file. |
-
-!!! warning "Set the CI workflow on a multi-workflow repo"
- `ROBOCO_SELF_HEAL_CI_WORKFLOW` defaults to `ci.yml`. Leave it empty *only* on a single-workflow repo — an empty value reads the latest completed run across **all** workflows on the default branch, which lets an unrelated green run mask a red CI run and makes the signal flicker.
-
-## Enable it
-
-=== "Panel"
-
- **Settings → Feature Flags** exposes both switches: **"Watch RoboCo's own CI and notify you when it regresses"** and the originate opt-in. Toggle the first to go notify-only, both to enable origination.
-
- !!! note "Takes effect on the next backend restart"
- Feature-flag toggles persist in the settings store and apply on the **next backend restart**. The project slug and CI workflow are environment settings, not flags — set them in env.
-
-=== "Environment"
-
- ```bash
- ROBOCO_SELF_HEAL_ENABLED=true
- ROBOCO_SELF_HEAL_PROJECT_SLUG=roboco # the project that IS RoboCo
- ROBOCO_SELF_HEAL_ORIGINATE_ENABLED=true # optional second opt-in
- # ROBOCO_SELF_HEAL_CI_WORKFLOW=ci.yml # default; set empty only if single-workflow
- ```
-
-See the [environment reference](../deploy/env-reference.md) for the full list.
-
-## What changes when it's on
-
-- A background loop polls the target repo's CI on the configured interval; with both opt-ins off, nothing polls.
-- On a regression you receive an acknowledgement notification as the CEO.
-- With originate on, a `PENDING` fix task appears in the backlog (bounded by the caps above), held for your Approve-&-Start — it never auto-runs.
-
-## Next
-
-→ [Health & metrics](../operations/health-and-metrics.md) for the CI/regression signal · [Task lifecycle](../company/task-lifecycle.md) for what an originated task does once you start it · back to [Optional subsystems](index.md).
diff --git a/docs/optional/strategy-engine.md b/docs/optional/strategy-engine.md
deleted file mode 100644
index 0b77e042..00000000
--- a/docs/optional/strategy-engine.md
+++ /dev/null
@@ -1,46 +0,0 @@
-# Strategy Engine
-
-The strategy engine is a background loop that watches the company against its charter and tells you when something has drifted — and that is all it does. It never spends, never builds, never approves, never merges. It only sends you a notification. Think of it as a quiet second pair of eyes on the whole org while you are not looking at the panel.
-
-## Default state
-
-The strategy engine is **off by default**, gated by `ROBOCO_STRATEGY_ENGINE_ENABLED` (config default `false`). When off, the background loop does not start at all — there is no cost, no assessment pass, and the delivery lifecycle is untouched. This is a genuinely dormant subsystem until you opt in.
-
-## Enable it
-
-1. Set `ROBOCO_STRATEGY_ENGINE_ENABLED=true` in your environment, or flip **Settings → Feature Flags → "Generate and maintain company strategy artifacts"** on.
-2. **Restart the backend** — the change takes effect on the next restart.
-
-That's the whole setup. There is no provider key, no migration, no extra service to wire up.
-
-## What changes when it's on
-
-A background loop wakes on an interval and runs an assessment pass against your charter (the north star, objectives, and operating policy you set in **Business → Goals**). It emits two kinds of observation and notifies the CEO when it sees one:
-
-| Signal | What it means |
-|--------|---------------|
-| `idle` | There is no in-flight work, but a charter exists — the company is sitting still while it has stated objectives. |
-| `stranded_blocked` | A task has been blocked longer than your threshold and needs a human decision to move. |
-
-Notifications are bounded and deduped: you get one notification per observation kind, and it is suppressed until you acknowledge it, so the engine can't spam you about the same standing condition every cycle. The signals also surface on the dashboard's strategy-signals panel and feed the Company Scorecard.
-
-!!! note "Notify-only by design"
- The engine has no authority. It cannot start a task, unblock work, approve a pitch, or spend a token. Every action it might prompt is still yours to take. That is the deliberate contract — it is a steering aid, not an autonomous operator.
-
-## Tuning the cadence and threshold
-
-| Env var | Default | Purpose |
-|---------|---------|---------|
-| `ROBOCO_STRATEGY_ENGINE_ENABLED` | `false` | Master switch. Off → the loop never runs. |
-| `ROBOCO_STRATEGY_ENGINE_INTERVAL_SECONDS` | `1800` | Seconds between assessment passes (minimum 60). |
-| `ROBOCO_STRATEGY_STRANDED_BLOCKED_MINUTES` | `120` | A task blocked longer than this is surfaced as `stranded_blocked` (minimum 5). |
-
-Lengthen the interval if you want quieter, less frequent checks; lower the stranded threshold if you want to hear about blocked work sooner.
-
-## Required extra config
-
-None beyond the flag and a restart. The signals are most useful once you have written a charter in **Business → Goals**, since `idle` is only meaningful relative to standing objectives.
-
-## Next
-
-→ **[Web research](./web-research.md)** — the other opt-in capability for the Board and PMs. → **[The business workflow](../how-to/05-the-business-workflow.md)** — the charter, Cockpit, and Scorecard the engine reads.
diff --git a/docs/optional/toolchain-matching.md b/docs/optional/toolchain-matching.md
deleted file mode 100644
index c05dfb5a..00000000
--- a/docs/optional/toolchain-matching.md
+++ /dev/null
@@ -1,72 +0,0 @@
-# Toolchain matching
-
-The agent image bakes one Python (RoboCo's own stack). But the repositories your agents build declare their *own* Python requirement — a target pinned to 3.14 cannot be honestly verified by an agent running 3.13. When the interpreters don't match, the suite fails to even *collect*, and a QA or PR-review pass degrades into "I read the source and it looks fine" — a **hollow pass** on a suite that never actually ran. Toolchain matching closes that hole.
-
-It is **off by default** in config (`ROBOCO_TOOLCHAIN_MATCH_ENABLED`). When off, workspace provisioning behaves exactly as before, against the system interpreter.
-
-## What it does
-
-When enabled, two things happen.
-
-**1. Provision against the target's declared Python.** When an agent's workspace is set up, RoboCo resolves the interpreter the *target* project needs and provisions the workspace's `.venv` with it (`uv sync --python `). The resolver (`roboco/services/toolchain.py`) reads both `.python-version` and `pyproject.toml`'s `requires-python`, and applies one load-bearing rule:
-
-!!! info "Why `.python-version` is not blindly trusted"
- uv lets a `.python-version` file override `requires-python` during interpreter selection — so a repo pinned to 3.13 whose packages actually need 3.14 silently gets the *wrong* interpreter. RoboCo therefore honours the `.python-version` pin **only when it satisfies `requires-python`**; otherwise it resolves a concrete version from `requires-python` and passes that to uv explicitly with `--python`, which overrides the pin. A target that declares nothing actionable leaves provisioning unchanged.
-
-**2. Write a runnability marker, then gate on it.** After provisioning, RoboCo runs a runnability smoke (`pytest --collect-only`) under the chosen interpreter and records the outcome to a per-workspace marker (`.git/.roboco-toolchain`):
-
-| Status | Meaning |
-|--------|---------|
-| `ok` | The suite collected cleanly (or there are no tests) — the interpreter can run it. |
-| `broken` | A collection / import error — the interpreter-mismatch signature. |
-| `unknown` | Inconclusive — provisioning ran but the smoke couldn't confirm the suite is collectable. |
-
-The delivery gates (`i_am_done`, `pass_review`, `pr_pass`) then read that status:
-
-- **`broken` blocks.** The verb is refused: *"the project's test suite cannot be executed in this workspace (interpreter mismatch) — verifying by reading source is hollow."* The remediation tells the agent to call `i_am_blocked(reason='toolchain')` so the environment is rebuilt against the right interpreter, rather than passing on a source read.
-- **`unknown` does not strand the task.** It fails *open* (precision over recall — a guess must never block a healthy task) but **never silently**: the orchestrator logs a `toolchain.unverified_gate_pass` warning so you can see the gate proceeded past an unconfirmed toolchain.
-- **`ok` (or no marker)** passes normally.
-
-```mermaid
-flowchart LR
- A[Workspace provisioned] --> B[resolve target Python .python-version vs requires-python]
- B --> C[uv sync --python <version>]
- C --> D[pytest --collect-only smoke]
- D --> E[write .git/.roboco-toolchain marker]
- E --> F{gate reads status}
- F -->|broken| G[BLOCK + i_am_blocked toolchain]
- F -->|unknown| H[pass, log warning]
- F -->|ok| I[pass]
-```
-
-## Enable it
-
-!!! tip "On in the personal compose"
- The config default is **off**, but this flag is turned **on** in the personal (non-registry) compose files. If you run from those, it is already active; the registry compose leaves it at the config default.
-
-=== "Panel"
-
- **Settings → Feature Flags** → toggle the toolchain-match flag on.
-
- !!! note "Takes effect on the next backend restart"
- Feature-flag toggles persist in the settings store and apply on the **next backend restart**, not as a hot reload.
-
-=== "Environment"
-
- ```bash
- ROBOCO_TOOLCHAIN_MATCH_ENABLED=true
- ```
-
-See the [environment reference](../deploy/env-reference.md) for all flags.
-
-## What changes when it's on
-
-- New agent workspaces are provisioned against the *target* repo's declared Python instead of the image's system interpreter.
-- Each workspace carries a `.git/.roboco-toolchain` marker recording its `(python, status)`.
-- `i_am_done`, `pass_review`, and `pr_pass` block on a `broken` status, and log a visible warning on `unknown`.
-
-When off, provisioning and the gates behave exactly as they did before — no resolution, no marker, no extra gating.
-
-## Next
-
-→ [Conventions](conventions.md) closes the *placement* hollow-pass hole · [The PR review gate](pr-review.md) is one of the gates this protects · back to [Optional subsystems](index.md).
diff --git a/docs/optional/web-research.md b/docs/optional/web-research.md
deleted file mode 100644
index bc08c3b9..00000000
--- a/docs/optional/web-research.md
+++ /dev/null
@@ -1,51 +0,0 @@
-# Web Research
-
-Web research lets your Board and PM agents ground their scoping in the live web instead of working from training data alone. When it is on, the Board (Product Owner, Head of Marketing) and the PM roles gain two tools — `web_search` and `web_fetch` — exposed through the `roboco-search` MCP server mounted into those agents. The provider's API key lives only on the server; it never enters an agent container, so the agent never sees or can exfiltrate it.
-
-## Default state
-
-Web research is **flag-gated by `ROBOCO_RESEARCH_ENABLED`**. The config default in `roboco/config.py` is `true`, but the Settings → Feature Flags card presents it as an operator toggle you turn on explicitly. The flag governs the mount: when it resolves to false, the `roboco-search` MCP server is not mounted into any agent and the `web_search` / `web_fetch` tools are simply absent.
-
-!!! info "Config default vs. the Feature Flags toggle"
- The two surfaces can disagree, and the resolution rule is simple: a flag you set in **Settings → Feature Flags** wins, and an *unset* flag falls back to the environment / config default. Because the config default for `ROBOCO_RESEARCH_ENABLED` is `true`, a fresh deploy that has never touched the toggle has research **on**. If you want it off, set the toggle off (or set `ROBOCO_RESEARCH_ENABLED=false` in your environment) — don't assume the panel's switch position alone reflects the live state until you've set it once.
-
-## Enable it
-
-You need both the capability on *and* a provider configured, or agents get an empty stub.
-
-1. **Set the flag.** Either set `ROBOCO_RESEARCH_ENABLED=true` in your deploy environment, or flip **Settings → Feature Flags → "Let the Board and PMs run web research"** on.
-2. **Choose a provider and supply its key** in your environment (see below).
-3. **Restart the backend.** Feature-flag changes take effect on the next backend restart — the panel toast says exactly this.
-
-## Pick a provider and supply a key
-
-| Env var | Default | Purpose |
-|---------|---------|---------|
-| `ROBOCO_RESEARCH_PROVIDER` | `tavily` | Search adapter: `tavily` \| `brave` \| `exa` \| `null`. Swapping providers is a config-only change. |
-| `ROBOCO_RESEARCH_API_KEY` | (unset) | API key for the selected provider. **Server-side only — never reaches an agent container.** Unset → the `null` provider is used (empty results, no error). |
-
-!!! warning "Brave has no `web_fetch`"
- Only `tavily` and `exa` support fetching page contents. The `brave` adapter is search-only — a `web_fetch` call against it raises "unsupported". If your agents need to read the pages they find, choose `tavily` or `exa`. The `null` provider always returns empty results and is the graceful fallback when no key is set, so a missing key degrades quietly instead of erroring mid-task.
-
-The provider's own API does the outbound web egress, not the agent — the agent calls the in-container MCP tool, the orchestrator-side `ResearchService` calls the provider with the server-held key, and only the cleaned results flow back.
-
-## What changes when it's on
-
-Board and PM agents can call `web_search` (a query → ranked results) and, on Tavily/Exa, `web_fetch` (a URL → extracted text). The service clamps every call so a provider can't run away with cost or context:
-
-| Env var | Default | Purpose |
-|---------|---------|---------|
-| `ROBOCO_RESEARCH_MAX_RESULTS` | `5` | Hard cap on `web_search` results per call (1–20). |
-| `ROBOCO_RESEARCH_FETCH_MAX_CHARS` | `20000` | Hard cap on characters returned by `web_fetch`. |
-| `ROBOCO_RESEARCH_TIMEOUT_SECONDS` | `15.0` | Per-request timeout for outbound provider calls. |
-| `ROBOCO_RESEARCH_DAILY_QUOTA_PER_AGENT` | `50` | Max `web_search` + `web_fetch` calls per agent per UTC day. |
-
-The daily quota is your main cost lever. It is tracked per agent per UTC day in Redis and is **fail-open**: if Redis is unreachable the call is allowed through, because the quota is cost-control, not a security boundary.
-
-## Required extra config
-
-The only hard requirement beyond the flag is a real provider key. With `ROBOCO_RESEARCH_API_KEY` unset (or `ROBOCO_RESEARCH_PROVIDER=null`), the tools mount but every search returns empty — useful for a dry run, useless for actual grounding. Nothing else (no migration, no panel setup) is needed.
-
-## Next
-
-→ **[Strategy engine](./strategy-engine.md)** — the other notify-only steering loop. → **[The business workflow](../how-to/05-the-business-workflow.md)** — where the Board and PMs use research in practice.
diff --git a/docs/panel/agents-and-work-sessions.md b/docs/panel/agents-and-work-sessions.md
deleted file mode 100644
index 8147b427..00000000
--- a/docs/panel/agents-and-work-sessions.md
+++ /dev/null
@@ -1,50 +0,0 @@
-# Agents & work sessions
-
-The **Agents** page (`/agents`) is your view of the workforce: who's running, who's idle, who's stuck, and what each one is costing in tokens. From an agent's detail page you can spawn or stop it and watch its reasoning live. The **Work Sessions** ledger (`/work-sessions`) is the read-only record of every branch-and-PR an agent has worked, tying git activity back to the agents that produced it.
-
-## The roster (`/agents`)
-
-Agents are grouped exactly the way the org chart is laid out:
-
-- **Board** — Product Owner, Head of Marketing, Auditor
-- **Main PM**
-- **Backend Cell**, **Frontend Cell**, **UX/UI Cell**
-- **Support** — the CEO-direct helpers (Intake/Prompter, Secretary, the root PR Reviewer), shown only when present
-
-Each card shows the agent's **live state** merged with its **token usage**, so health and cost sit together. States you'll see:
-
-| State | Meaning |
-|-------|---------|
-| `running` / `ready` / `starting` | the agent is alive and working (or coming up) |
-| `idle` | spawned but with no work in hand |
-| `waiting_long` | blocked, waiting on human input or an external resolution |
-| `error` | the container hit errors (the card shows the error count) |
-
-A **Waiting Agents** alert surfaces any agent stuck in `waiting_long` at the top of the page, so a blocked agent doesn't sit unnoticed.
-
-## Agent detail (`/agents/[id]`)
-
-Open an agent to control it and watch it think. The page gives you:
-
-- **Spawn** — bring the agent's container up.
-- **Stop** (graceful) and **Force Stop** — wind it down cleanly or kill it immediately.
-- **Resolve Wait** — when an agent is in `waiting_long`, this dialog is how you hand it the input or decision it's blocked on.
-- **Live stream viewer** — while the agent is active, a viewer streams its reasoning in real time over the agent WebSocket, so you can literally watch it work.
-
-!!! tip "Stop the bleeding"
- If an agent is crash-looping or burning tokens, **Force Stop** from its detail page is the fastest way to halt it. For provider rate-limits and overloads you don't need to intervene — those *park and auto-resume*; you'll see an amber banner instead (see [resilience](../models/resilience.md)).
-
-Per-agent token spend rolls up into the [Metrics](./metrics.md) page for cost analysis, and what agents say and learn is in [Communications & journals](./communications-and-journals.md).
-
-## Work Sessions (`/work-sessions`)
-
-A **WorkSession** links an agent's work to a task and tracks its git footprint — branch name, base and target branches, the PR number/URL, and merge status. The Work Sessions page is a **read-only ledger** of those sessions, with search-by-branch and a status filter (state, again, lives in the URL).
-
-!!! note "No sidebar link"
- Work Sessions has **no entry in the sidebar nav**. Reach it by typing `/work-sessions` directly or by following a link from elsewhere in the panel. It's a reference ledger, not a daily-driver page.
-
-For the lifecycle of a branch from cut to merge, see [the merge model](../company/merge-model.md).
-
-## Next
-
-→ [Git](./git.md) to operate on those branches directly, or [Tasks & Kanban](./tasks-and-kanban.md) to see the work the agents are running.
diff --git a/docs/panel/auditor.md b/docs/panel/auditor.md
deleted file mode 100644
index fdd86e11..00000000
--- a/docs/panel/auditor.md
+++ /dev/null
@@ -1,30 +0,0 @@
-# Auditor
-
-The Auditor is the company's silent quality conscience. It has read access to every channel, every task, and every piece of evidence — and it never participates. It can leave a private note and read evidence; it has no `say`, no `dm`, no merge verb. The `/auditor` page is your window into what it sees.
-
-## What the dashboard shows
-
-The Auditor dashboard is four panels plus two controls (**Refresh** and **Generate Report**).
-
-| Panel | What it surfaces |
-|-------|------------------|
-| **Live Feeds** | The activity the Auditor is watching right now across the company. |
-| **Quality Metrics** | Aggregate quality indicators rolled up from the work in flight. |
-| **Flagged Items** | The things the Auditor has flagged for attention — the unresolved-flag list that also feeds the Command Center's Auditor Alerts. |
-| **Reports** | Audit reports, newest first. |
-
-**Generate Report** produces an audit-summary report on demand and drops it into the Reports panel. **Refresh** re-pulls the live feeds and metrics.
-
-## How to read it
-
-Think of the Auditor as a continuous, read-only review running alongside the delivery pipeline — not a gate the work has to pass. Nothing here blocks a task; the lifecycle's own gates ([QA, the PR-review gate, PM and CEO approval](../company/task-lifecycle.md)) do that. The Auditor's job is to *notice* — drift in quality, a pattern across cells, a flag worth your eye — and surface it where you'll see it.
-
-!!! note "Flags surface in two places"
- An unresolved Auditor flag appears both here, in **Flagged Items**, and on the [Command Center](./command-center.md) as an Auditor Alert. The Command Center is your at-a-glance feed; this page is the full detail and the report history.
-
-!!! info "Silent by construction"
- The Auditor cannot post in any channel or message an agent — that restriction is enforced at the [agent gateway](../company/agent-gateway.md), not by convention. So the only way its observations reach the company is through *you*: you read the flags and reports here and decide what to act on.
-
-## Next
-
-→ [Communications & journals](./communications-and-journals.md) for the raw record the Auditor watches · [Metrics](./metrics.md) for velocity and cost analytics · [Org & roles](../company/org-and-roles.md) for where the Auditor sits in the company.
diff --git a/docs/panel/business.md b/docs/panel/business.md
deleted file mode 100644
index 8acd7fe4..00000000
--- a/docs/panel/business.md
+++ /dev/null
@@ -1,45 +0,0 @@
-# Business
-
-The Business page (`/business`) is the strategic layer above day-to-day delivery — the company's charter, its live scorecard against that charter, and the Board's pitches awaiting your decision. It's tabbed: **Goals**, **Secretary**, and **Pitches** (the active tab is in the URL as `?tab=`).
-
-For the *story* of how this layer drives work — how a north star shapes what the Board proposes and what the engines watch — see [The business workflow](../how-to/05-the-business-workflow.md). This page documents the panel surface.
-
-## Goals — the company charter
-
-The Goals tab is the CEO-owned charter. It's injected into every agent's briefing, so the whole company stays goal-aware. You edit it directly:
-
-| Field | What it is |
-|-------|-----------|
-| **North star** | The long-term vision in a sentence or two. |
-| **Objectives** | A list of objective rows (metric / target / status, add and remove freely). |
-| **Constraints** | Hard rules, one per line — e.g. "AGPL only", "No external data egress". |
-| **Operating policy** | Free-form policy keys the company operates under. |
-
-**Save charter** persists it; the card shows when it was last updated and by whom.
-
-### The Company Scorecard
-
-Below the charter sits the **Company Scorecard** — a live read of how the company is tracking against the charter, pulled from the cockpit summary. It groups into:
-
-- **Delivery** — tasks in flight, blocked, awaiting CEO, and completed in the last 30 days.
-- **Spend** — 30-day spend, projected monthly, and your **monthly budget cap** (`monthly_budget_cap_usd`). When a cap is set and spend exceeds it, the figure turns red with an "over budget" marker; with no cap it reads "No budget cap set."
-- **Speed** — median lead time against a target of under 24 hours.
-- **Objectives** — a placeholder section; per-objective tracking is not wired up yet.
-
-!!! info "The scorecard is the Cockpit, surfaced"
- The scorecard reads the same company snapshot the **Cockpit** API exposes (`/api/cockpit/summary`): a read-only roll-up of delivery, spend against the budget cap, lead time, pending pitches, and strategy signals. There is no separate Cockpit page — its data shows up here on the scorecard and as the Strategy Signals panel on the [Command Center](./command-center.md).
-
-## Secretary
-
-The Secretary tab is your on-demand chief-of-staff chat. It reads company state and can run gated CEO directives. It is a human-only seat — the Secretary has no agent chat verbs and runs only when you talk to it. It's part of the company-in-a-box layer; see the [optional subsystems index](../optional/index.md).
-
-## Pitches
-
-The Pitches tab is where Board-originated proposals land for your decision. Each pitch is a card you can **Approve** or **Reject** (both prompt for a required note). Approving a pitch can, with pitch provisioning enabled, auto-provision a project from it.
-
-!!! warning "Pitches need provisioning enabled to act"
- Pitch provisioning is a default-off subsystem. Flip `ROBOCO_PROVISIONING_ENABLED` on from [Settings → Feature Flags](./settings.md), and read [Pitch provisioning](../optional/pitch-provisioning.md) for what approving actually sets in motion. With it off, the tab still lists pitches but approval won't provision anything.
-
-## Next
-
-→ [The business workflow](../how-to/05-the-business-workflow.md) walks the whole strategic loop end to end · [Optional subsystems](../optional/index.md) covers the engines (strategy, research, provisioning) that this layer drives.
diff --git a/docs/panel/command-center.md b/docs/panel/command-center.md
deleted file mode 100644
index 884ca070..00000000
--- a/docs/panel/command-center.md
+++ /dev/null
@@ -1,63 +0,0 @@
-# Command Center
-
-The Command Center at **`/overview`** is the panel's home page — the one screen you open to see whether the company is healthy and to act on the two things only you can decide. It pulls everything onto a single board: per-cell health, your decision queues, live metrics and cost, the auditor's open flags, current blockers, and a recent-activity feed. The notifications bell in the top header rides along on every page.
-
-## Team Health
-
-The top section shows a **health card per cell** — Backend, Frontend, UX/UI, and the management line — so you can read the state of the whole workforce at a glance before you scroll into anything detailed. It comes from the CEO-overview endpoint and refreshes with the rest of the board.
-
-A **Quick Actions** bar sits directly under Team Health so the common jumps (author a task, open the kanban, and so on) are reachable without scrolling.
-
-## The two CEO decision surfaces
-
-The Command Center is where the company hands work *up to you*. Two panels exist specifically for that.
-
-### CEO Approval Queue
-
-Every task that a Main PM escalates lands in **`awaiting_ceo_approval`** and appears here. For each one you can:
-
-- **Approve & merge** — the PR is merged and the task moves to `completed`.
-- **Request changes** — the task drops to `needs_revision` and goes back to the cell.
-- **Cancel** — the task is cancelled.
-
-These are the same actions you'd take from the [Task Detail page](./tasks-and-kanban.md#ceo-god-mode), surfaced here so the day's approvals are in one list. See [the task lifecycle](../company/task-lifecycle.md) for how a task reaches this state.
-
-### PR Review Queue
-
-This panel lists **inbound external / fork pull requests** RoboCo discovered on your repositories. For each one you decide:
-
-- **Supersede** — let an internal task take the change forward.
-- **Dismiss** — close it out.
-
-!!! note "Hidden when empty"
- The PR Review Queue only renders when there's something to decide. An empty board means no external PRs are waiting — not that the feature is off. (Inbound external/internal PR review is itself flag-gated; see [PR review](../optional/pr-review.md).)
-
-## Metrics, alerts, and usage
-
-A three-up row gives you the operational pulse:
-
-- **Key Metrics** — the headline counts from the overview endpoint.
-- **Auditor Alerts** — currently *unresolved* flags raised by the [Auditor](./auditor.md). This is a read-only nudge; the full feed lives on the Auditor page.
-- **Usage overview** — a live token/cost summary. It updates off the `USAGE_SNAPSHOT` stream on `/ws/system` and falls back to polling when that socket is down. The full breakdown — 24h cost, monthly projection, cache savings — is on the [Metrics page](./metrics.md).
-
-### Strategy Signals
-
-Next to the Approval Queue sits a **Strategy Signals** panel. It surfaces charter/strategy-drift notices from the strategy engine, which is **off by default** and armed by `ROBOCO_STRATEGY_ENGINE_ENABLED` (toggled from [Settings → Feature Flags](./settings.md)). With the engine off, the panel simply has nothing to show. See [the strategy engine](../optional/strategy-engine.md).
-
-## Blockers and activity
-
-The bottom row pairs:
-
-- **Active Blockers** — tasks currently sitting in `blocked`, so a stuck dependency doesn't go unnoticed.
-- **Recent Activity** — a rolling feed of what the company did in the last 24 hours.
-
-## Notifications bell
-
-The bell in the top **Header** (present on every dashboard page, not just here) is your inbox for formal notifications — the acknowledgement-required signals PMs and the Board send. Clicking through takes you to the full [Notifications inbox](./communications-and-journals.md#notifications) at `/notifications`, where you can mark items read, acknowledge those that need it, and clear the unread count.
-
-!!! tip "Backend down?"
- If the orchestrator isn't running, the Command Center (like every page) renders a clear offline state with a **Retry** — it detects a refused connection rather than spinning. Bring the stack up and retry; see [common issues](../troubleshooting/common-issues.md).
-
-## Next
-
-→ [Tasks & Kanban](./tasks-and-kanban.md) to act on individual work, or [Agents & work sessions](./agents-and-work-sessions.md) to watch the workforce run.
diff --git a/docs/panel/communications-and-journals.md b/docs/panel/communications-and-journals.md
deleted file mode 100644
index 4fb7d12b..00000000
--- a/docs/panel/communications-and-journals.md
+++ /dev/null
@@ -1,39 +0,0 @@
-# Communications, Journals & Notifications
-
-Three pages are the company's audit trail of *what was said, what was learned, and what needs your attention.* Communications is the live message stream between agents. Journals are each agent's private reflections. Notifications is your inbox — the formal signals that require an acknowledgment. All three are read surfaces for you as operator; the work happens elsewhere, and these record it.
-
-## Communications
-
-`/communications` is a three-pane browser over the agent message stream: **Channels → Groups → Sessions.**
-
-- **Channels** (left pane) are grouped by kind: Cell channels (`#backend-cell`, …), Cross-cell (`#dev-all`, `#qa-all`, …), Management (`#main-pm-board`, `#board-private`), and Other. A lock icon marks a private channel; a hash marks a public one.
-- **Groups** (middle pane) sit inside a channel and carry a running message count.
-- **Sessions** (right pane) are individual conversation threads, each showing its linked task title, status, message count, and how long ago it started.
-
-Open a session to read its full transcript at `/communications/{session}`. The transcript is the message-by-message record of an agent conversation — the constant communication stream the company runs on, logged and replayable. An open session's transcript **updates live** as messages are posted (the view subscribes to the session's WebSocket stream); a closed session is read-only, so its composer is disabled rather than silently reopening the conversation elsewhere.
-
-!!! info "The Auditor sees all of this silently"
- Every channel — including the private management channels — is readable by the [Auditor](./auditor.md) with no participation. Communication is observed, not gated.
-
-## Journals
-
-`/journals` is the per-agent reflection log. Pick an agent from the searchable list on the left (your selection is remembered across visits), and the right pane shows that agent's journal entries.
-
-Journals are where an agent records **reflections, decisions, and learnings** as it works — distinct from the chat stream. Filter the entries by **type** and by **task** to trace how one agent reasoned through a specific piece of work. A single entry opens at `/journals/{entry}`.
-
-This is the closest you get to an agent's "why." When a piece of work went a surprising way, the journal is where the agent explains its thinking — useful both for trust and for [feeding the knowledge base](./knowledge-base.md), which indexes journals as a retrievable source.
-
-## Notifications
-
-`/notifications` is your acknowledgment-required inbox. Where communications and journals are an ambient record you browse, notifications are formal signals — sent by PMs and the Board — that may demand a response.
-
-- Three tabs with live counts: **All**, **Unread**, and **Pending** (awaiting your acknowledgment). The page opens on Unread, the most actionable view.
-- Each card renders a markdown body, a priority badge (Normal / High / Urgent), a **New** badge while unread, and a **Needs Ack** badge when an acknowledgment is required.
-- Actions per card: **Mark Read** and, where required, **Acknowledge**. **Mark All Read** clears the unread pile in one click.
-
-!!! warning "Acknowledge means you've seen it"
- A **Needs Ack** notification stays in your Pending tab until you acknowledge it. These are the signals the company expects a human to have read — a blocker escalation, a priority change, an approval request. Acknowledging records that you saw it; it is not the same as approving a task (that happens on the [task detail page](./tasks-and-kanban.md) or the Command Center approval queue).
-
-## Next
-
-→ [Tasks & Kanban](./tasks-and-kanban.md) for the work itself · [Agents & work sessions](./agents-and-work-sessions.md) to watch agents live · [Communication model](../company/org-and-roles.md) for the channel structure.
diff --git a/docs/panel/git.md b/docs/panel/git.md
deleted file mode 100644
index ee863954..00000000
--- a/docs/panel/git.md
+++ /dev/null
@@ -1,48 +0,0 @@
-# Git
-
-The **Git** page (`/git`) is a real working git client over any of your registered projects. You pick a project (and optionally a task), browse the live state of its workspace — status, branches, commit log, and diffs — and run git operations directly from the panel. It's how you inspect what the agents are doing in git, and step in by hand when you need to.
-
-## Picking a project
-
-Choose a project from the dropdown to load its repository. The selection is held in the URL, so a given project's git view is shareable and back-button-safe. Until you pick one, the page prompts you to choose. You can also scope to a specific task.
-
-!!! note "The orchestrator must be up"
- Git operations run server-side against the agent workspaces, so this page needs the orchestrator running. With the backend down it shows an offline state with a retry rather than failing silently.
-
-## Browsing the repository
-
-Once a project is loaded you get live, refreshable views:
-
-- **Status** — staged and unstaged changes in the workspace.
-- **Branches** — the branch list (including remotes).
-- **Log** — the recent commit history.
-- **Diff** — the staged/unstaged diff viewer for the working tree.
-
-A **Refresh** re-pulls status, log, and branches together.
-
-## Operations you can run
-
-The page wires up the full set of git operations against the selected project:
-
-| Operation | What it does |
-|-----------|--------------|
-| **Commit** | commit staged changes (returns the new commit hash) |
-| **Push** | push the current branch to the remote |
-| **Create branch** | cut a new hierarchical branch for a task (by branch type) |
-| **Checkout** | switch to an existing branch |
-| **Create PR** | open a pull request (returns the PR number) |
-| **Merge PR** | merge a PR into its target branch |
-| **Pull** | pull the current branch from the remote |
-| **Fetch** | fetch from the remote |
-| **Rebase** | rebase the current branch onto a target branch |
-
-Each action confirms with a toast on success (or a clear failure message) and refreshes the relevant view.
-
-!!! warning "This is the live repository"
- These operations act on the real workspace clone and your real remote — a merge here merges for real. The same branch/PR/merge actions are also available, task-scoped, from the [Task Detail page](./tasks-and-kanban.md#ceo-god-mode), where they run as agent id `ceo`. Remember that **only the CEO merges to master**; see [the merge model](../company/merge-model.md).
-
-Git authentication uses the project's encrypted GitHub token, which you set when you [register the project](../get-started/first-project.md#the-github-token) — the panel never holds or shows the PAT.
-
-## Next
-
-→ [Agents & work sessions](./agents-and-work-sessions.md) to tie branches back to the agents that cut them, or [Projects & products](./projects-and-products.md) to manage the repositories themselves.
diff --git a/docs/panel/index.md b/docs/panel/index.md
deleted file mode 100644
index 97482eb9..00000000
--- a/docs/panel/index.md
+++ /dev/null
@@ -1,22 +0,0 @@
-# Operating the Panel
-
-The control panel is your one window into the company — every task, agent, message, journal, and pull request is live in front of you, served at `http://localhost:3000`. This section is a reference: one short page per area, describing what you do there and what it shows.
-
-
-
-- **[Command Center](command-center.md)** — the home dashboard: cell health, your approval queues, live metrics, and the notifications inbox.
-- **[Tasks & Kanban](tasks-and-kanban.md)** — the task table, the task detail page (with CEO god-mode), and the dev board.
-- **[Agents & Work Sessions](agents-and-work-sessions.md)** — the live workforce and the branch/PR ledger.
-- **[Projects & Products](projects-and-products.md)** — the repositories the company works on, and multi-repo products.
-- **[Git](git.md)** — browse live git state and run operations per project.
-- **[Knowledge Base](knowledge-base.md)** — the in-house RAG: search, ask, and reindex.
-- **[Communications & Journals](communications-and-journals.md)** — the live message stream, agent journals, and your notifications.
-- **[Auditor](auditor.md)** — read-only quality oversight across the whole company.
-- **[Business](business.md)** — the charter, the Scorecard, the Cockpit, and pitches.
-- **[Metrics](metrics.md)** — delivery performance and the token-usage dashboard.
-- **[Settings](settings.md)** — feature flags, transcript retention, and configuration.
-
-
-
-!!! tip "Provider configuration lives in its own section"
- Picking which models power the agents is on the **Settings → AI Providers** page — see [Choosing & Running Models](../models/index.md).
diff --git a/docs/panel/knowledge-base.md b/docs/panel/knowledge-base.md
deleted file mode 100644
index d6459a32..00000000
--- a/docs/panel/knowledge-base.md
+++ /dev/null
@@ -1,43 +0,0 @@
-# Knowledge Base
-
-The **Knowledge Base** page (`/knowledge-base`) is your window into RoboCo's in-house RAG — the pgvector-backed retrieval engine the agents use to find prior context. From here you search the indexes, ask synthesized questions and get answers with citations, talk to the mentor, browse by category, and (in the Admin tab) reindex or clear the indexes. The page is organized into five tabs, with the active tab held in the URL.
-
-## Search
-
-Free-text search across the indexes, with an optional filter to scope the query to specific index types. This is the raw retrieval view — it returns the matching chunks so you can see exactly what the agents would find.
-
-## Ask
-
-The RAG question-and-answer surface. You ask a question in natural language and get a **synthesized answer with citations** back to the source documents, rather than a raw chunk list. This is the layer that turns the indexes into an answer.
-
-## Mentor
-
-A mentor chat — the same `roboco_ask_mentor` capability the agents reach through their gateway, exposed to you conversationally for asking about the codebase and accumulated knowledge.
-
-## Browse
-
-Browse the indexed content **by category** rather than by query, when you want to see what's in an index instead of searching for something specific.
-
-## Admin
-
-The control surface for the indexes themselves. The KB is split into several index types — Documentation, Conversations, Agent Journals, Error Solutions, Standards, Decisions, Code Reviews, and Learnings — and the Admin tab shows **per-index stats** and lets you maintain them:
-
-| Action | Effect |
-|--------|--------|
-| **Reindex all** | rebuild every index from source (force) |
-| **Refresh** *(per index)* | re-pull and re-embed that one index |
-| **Delete** *(per index)* | clear that index's contents |
-
-!!! warning "Delete and reindex are operational actions"
- Clearing an index removes its embeddings, and a full reindex re-embeds everything from scratch — both take real work and real Ollama time. Delete is guarded behind a confirmation dialog. Treat the Admin tab as a maintenance surface, not a daily one.
-
-## It depends on Ollama
-
-The whole page — search, ask, mentor, and especially reindexing — runs on the embedding model served by **Ollama** (`qwen3-embedding:0.6b`). If Ollama isn't healthy, queries return nothing useful and reindexing can't embed.
-
-!!! info "If results come back empty"
- A common first-run symptom is an empty or failing KB while Ollama is still pulling models, or when the embedding endpoint is unreachable. Check that the `ollama` service is up and the model is pulled — see [common issues](../troubleshooting/common-issues.md). The RAG engine and its configuration are covered under [deployment](../deploy/deployment.md).
-
-## Next
-
-→ [Communications & journals](./communications-and-journals.md) — the raw conversations and journals that feed several of these indexes — or [the Auditor](./auditor.md) for quality oversight.
diff --git a/docs/panel/metrics.md b/docs/panel/metrics.md
deleted file mode 100644
index 10d2a591..00000000
--- a/docs/panel/metrics.md
+++ /dev/null
@@ -1,51 +0,0 @@
-# Metrics
-
-The Metrics page (`/metrics`) is where you watch the company's throughput and its spend. Three tabs: **Performance**, **Token Usage**, and **Delivery** (the active tab is in the URL as `?tab=`).
-
-## Performance
-
-The Performance tab is a snapshot of velocity and pipeline health, computed from the live task list and the orchestrator's agent status.
-
-- **Velocity** — completed today, completed this rolling 7 days, total completed all-time, and a completion rate across all tasks.
-- **Task Status** — counts of tasks that are pending, in progress, blocked, awaiting QA, and completed.
-- **Agent Status** — how many agents are running, idle, waiting (need input), or in error.
-- **Team Health** — one card per cell with a health score and its active / blocked / done breakdown. The score is a simple read on blockers: more blocked tasks pulls a cell's health down. A healthy cell sits near 100%; blockers visibly degrade it, so a cell sliding toward red is the signal to look at its [blockers](./command-center.md).
-
-## Token Usage
-
-The Token Usage tab is the cost dashboard, scoped to the last 24 hours unless a panel says otherwise.
-
-- **Summary cards** — tokens in, tokens out, total tokens, total cost over 24h, the trend versus the prior period, and dollars saved by prompt caching.
-- **Time series + model donut** — usage over time, and the split across models.
-- **Per-agent and per-team bars** — who and which cell is spending.
-- **Monthly projection** — projected monthly cost from a rolling-average daily run rate.
-- **Cache efficiency** — cache hit rate and the cost it saved.
-- **Cost & cache by role** — cost and cache-hit-rate broken out per role (developer, main PM, QA, …), so you can see which roles are cheap-and-cached versus expensive.
-- **Spawn waste** — the share of spawns that produced no output (loaded a prompt, delivered nothing), per role, plus any wedged tasks with open respawn strikes.
-- **Sessions table** — the recent agent spawn sessions behind the numbers.
-
-!!! tip "These panels update live"
- The token panels subscribe to a live usage stream over `/ws/system` and update in place as agents spend, falling back to periodic HTTP polling when the socket is down. You don't need to refresh to watch cost accrue.
-
-### Where the dollar figures come from
-
-Cost is derived from per-session token counts using provider-aware pricing — and local / Ollama usage is intentionally priced at **$0**, so a self-hosted or Ollama-routed workforce shows tokens but no dollars. The full cost model, the budget cap, and where each number originates are documented in [Cost & usage](../operations/cost-and-usage.md); this page only shows the numbers.
-
-!!! note "Spend against budget lives on the scorecard"
- Metrics shows raw usage and projection. Your **monthly budget cap** and whether you're over it appear on the Company Scorecard in [Business](./business.md), not here.
-
-## Delivery
-
-The Delivery tab is the flow dashboard — not *what* the company shipped or what it cost, but *how the work moved*. Every panel is reconstructed from the task lifecycle history RoboCo already records (each status transition is logged), so it needs no extra bookkeeping. Cycle-time, bottlenecks, and rework look back 30 days; the scorecards look back 7.
-
-- **Cycle Time by Stage** — the average time a task sits in each lifecycle stage (claimed, in progress, awaiting QA, awaiting documentation, awaiting PR review, awaiting PM review, …). This is where you see *where the time actually goes* — a tall "awaiting QA" bar means work waits on review, not on coding.
-- **Bottlenecks** — the same data ranked by total time absorbed, with the single **worst stage** called out and a live count of how many tasks are **parked** in each stage right now, plus the current active-blocker count. It answers "what is holding the company up today?"
-- **Rework** — how often work bounces back to `needs_revision` (the headline rate = reworked ÷ completed), broken down by cell and by agent, plus the token cost of that rework. Crucially, a bounce is attributed to the **QA or PR-reviewer who sent it back**, not the developer who owns the task — so a high `QA fails` number against a reviewer is a signal about *that reviewer's* gate, and a high rate against a developer is a signal about *their* first-pass quality.
-- **Cell scorecards** — one card per cell (Backend / Frontend / UX-UI) with its completed count, average cycle time, rework rate, and cost over the last 7 days — the quick read on which cell is moving cleanly.
-
-!!! tip "Reading rework attribution"
- A bounce charges the reviewer who rejected it via the `task.qa_fail` / `task.pr_fail` events, while the *rate* (`reworked / completed`) is computed against the task's owner. So one agent can show a low rate (good first-pass work) while another shows many `QA fails` (an active, rejecting gate) — both are healthy. Watch for a developer with a high rate **and** a reviewer with near-zero fails: that's a gate letting work through that later needs revision.
-
-## Next
-
-→ [Cost & usage](../operations/cost-and-usage.md) for the pricing model and budget cap · [Health & metrics](../operations/health-and-metrics.md) for operational monitoring · [Command Center](./command-center.md) for the at-a-glance view.
diff --git a/docs/panel/projects-and-products.md b/docs/panel/projects-and-products.md
deleted file mode 100644
index ccadbda5..00000000
--- a/docs/panel/projects-and-products.md
+++ /dev/null
@@ -1,45 +0,0 @@
-# Projects & Products
-
-Two pages define *what* the company builds and *who* builds it. **Projects** (`/projects`) are the git repositories RoboCo is allowed to touch. **Products** (`/products`) group several repositories into one shipping unit and route each delivery cell to the repo it owns. You only need Products when a single thing you ship spans more than one cell.
-
-## Projects
-
-A project is one git repository plus the configuration that tells the company how to build and check it. The Projects page is where you register, search, and edit them.
-
-- **New** opens the create dialog — name, slug, git URL, GitHub token, assigned cell, default branch, and optional per-project gate commands.
-- The list supports **search**, a **cell filter**, and a **show-inactive** toggle so retired repos stay out of the way without being deleted.
-- **Edit** reopens the same form to rotate the token, change the gate commands, or flip the assigned cell. The edit dialog also hosts the per-project **Conventions** tab — see [Architectural conventions](../optional/conventions.md) — and an **Autonomous Maintenance** section to opt the project into CI-watch (with an optional workflow file) and the dependency-update bot (its command and optional lockfile paths) — see [Autonomous maintenance](../optional/autonomous-maintenance.md).
-
-The field-by-field detail — what each field means, the token scopes you need, the encryption guarantee, and the default-branch gotcha — lives in [Register your first project](../get-started/first-project.md). Read that page before you create a repo; this page doesn't repeat it.
-
-!!! tip "Set the gate commands"
- The single biggest lever on output quality is pointing a project's `quality_command` and per-step commands at the *real* checks you'd run locally. The company then gates itself the way you would. Details in [Gate commands](../get-started/first-project.md#gate-commands).
-
-## Products
-
-A **product** maps each delivery cell to the project (repository) it builds for that product. Use it when one deliverable spans multiple cells — a Backend repo and a Frontend repo, say, that ship together.
-
-The page is a straightforward table plus a **New** button. A product carries a name and a set of cell-to-project assignments: Backend → repo A, Frontend → repo B, UX/UI → repo C. A cell with no assignment simply doesn't participate in that product.
-
-### Why the mapping matters
-
-When the Main PM decomposes a product into work and fans it out to the cells, the branch and PR structure follows the mapping. **The Main PM cuts one integration branch per distinct repository in the product.** A cell's work lands on its repo's integration branch; the cell PM opens the cell→root PR within that repo, and the Main PM opens the root→master PR per repo. Two cells assigned the *same* repo share one integration branch; two cells on *different* repos get one each.
-
-```mermaid
-flowchart LR
- P[Product] --> B[Backend cell → repo A]
- P --> F[Frontend cell → repo B]
- A1[repo A: integration branch] --> MA[root→master PR · repo A]
- B1[repo B: integration branch] --> MB[root→master PR · repo B]
- B --> A1
- F --> B1
-```
-
-!!! note "Single-repo work needs no product"
- If everything you're shipping lives in one repo, you don't need a product at all — register the project and hand the Task Assistant or the Create Task dialog that project directly. Products exist purely to coordinate a multi-repo, multi-cell deliverable.
-
-For how branches assemble and merge once the cells are building, see the [merge model](../company/merge-model.md). For the lifecycle a single task moves through, see the [task lifecycle](../company/task-lifecycle.md).
-
-## Next
-
-→ [Tasks & Kanban](./tasks-and-kanban.md) to author and track the work · [Git](./git.md) to watch the branches and PRs land.
diff --git a/docs/panel/settings.md b/docs/panel/settings.md
deleted file mode 100644
index 06dba9d2..00000000
--- a/docs/panel/settings.md
+++ /dev/null
@@ -1,52 +0,0 @@
-# Settings
-
-The Settings page (`/settings`) holds two things that genuinely change how the company runs — the **Feature Flags** card and **Transcript Retention** — alongside a handful of cosmetic preferences and read-only connection info. Read the warning below before you trust a switch on this page.
-
-## Feature Flags
-
-The Feature Flags card is the operator's master switchboard for the optional, default-off subsystems. Instead of hand-editing environment variables, you flip a switch here. Each row shows the subsystem's label, a one-line description of what it gates, and a toggle.
-
-| Flag | Gates |
-|------|-------|
-| External PR review | Discovering and reviewing inbound external/fork PRs. |
-| Internal PR review | The read-only safety reviewer on internal branch PRs. |
-| Web research | Letting the Board and PMs run web research. |
-| Strategy engine | Generating and maintaining strategy artifacts (drives the Command Center's Strategy Signals). |
-| Self-healing | Watching RoboCo's own CI and notifying you on a regression. |
-| Self-heal originate | Also opening a *pending* fix task for a regression — needs self-healing on, and the task waits for your approval. |
-| Multi-repo CI-watch | Watching each opted-in project's CI and opening one fix task when it goes red. |
-| Dependency-update bot | Read-only checking whether an upgrade changes a project's lockfiles, and opening an update task when it would. |
-| Pitch provisioning | Auto-provisioning projects from approved [pitches](./business.md). |
-| Toolchain match | Provisioning each agent workspace with the target project's own Python and blocking gates when its tests can't run. |
-| Conventions | Enforcing the per-project architectural standard (`.roboco/conventions.yml`). |
-| RAG auto-update | Keeping the [knowledge base](./knowledge-base.md) index refreshed automatically. |
-| Transcript prune | Running the background sweep that prunes old transcripts. |
-
-Each subsystem has a full page in the [optional subsystems section](../optional/index.md) — what it does, the exact `ROBOCO_*` env var behind it, and what turning it on changes.
-
-!!! note "The Multi-repo CI-watch and Dependency-update flags are global switches"
- Both are off by default and need a per-project opt-in to do anything. The global flag here arms the engine; you then opt each project in from the **edit-project dialog → "Autonomous Maintenance" section**: turn on CI-watch and (optionally) name its workflow file (`ci_watch_workflow`, default `ci.yml`), and/or set the dependency-update command (`dep_update_command`, e.g. `uv lock --upgrade` / `pnpm update`) with optional comma-separated lockfile paths (`dep_update_paths`). See [Autonomous maintenance](../optional/autonomous-maintenance.md).
-
-!!! warning "Flags take effect on the next backend restart"
- Toggling a flag persists the choice server-side, but it does **not** hot-reload — the backend reads it at startup. The toast says as much: "takes effect on next restart." A flag you've never set falls back to its environment / config default. So: flip it here, then restart the orchestrator for it to take hold.
-
-## Transcript Retention
-
-The Transcript Retention card sets how many days agent transcripts are kept before the prune sweep removes them (default 14). This is a real, server-persisted setting. It only ever prunes *agent-owned* transcripts — never your own Claude sessions. The sweep itself is gated by the **Transcript prune** feature flag above.
-
-## Connection Info (read-only)
-
-This card displays the API and WebSocket base URLs the panel is using (`NEXT_PUBLIC_API_URL`, `NEXT_PUBLIC_WS_URL`) — relative by default so nginx dispatches them on a single origin. It's informational; you can't edit it here.
-
-## The cosmetic and mock-state controls
-
-!!! danger "Some switches on this page do nothing"
- The page also carries **Appearance** (theme, collapsed sidebar — these work and persist locally), a **User Info** card, and a **Data & Refresh** + **Notifications** block. The Auto Refresh, Refresh Interval, Enable Notifications, and Sound Alerts controls — and the page-level **Save Settings** button — are **local component state only.** They are *not* persisted or wired to anything; Save just shows a success toast. Don't rely on them to change runtime behavior. Only **Feature Flags**, **Transcript Retention**, and the **Appearance** preferences actually do something.
-
-## AI provider configuration lives elsewhere
-
-Choosing which model and provider backs each agent is **not** on this page — it's the **AI Providers** page (`/settings/ai-providers`), linked from the sidebar footer. There you set the global routing mode (Anthropic / Grok / Ollama / self-hosted), or pin individual agents in Mix mode, and store the encrypted provider keys. See [Provider routing](../models/provider-routing.md).
-
-## Next
-
-→ [Optional subsystems](../optional/index.md) for every feature flag in detail · [Provider routing](../models/provider-routing.md) for the AI Providers page · [Environment reference](../deploy/env-reference.md) for the `ROBOCO_*` variables behind the flags.
diff --git a/docs/panel/tasks-and-kanban.md b/docs/panel/tasks-and-kanban.md
deleted file mode 100644
index c0a16b0b..00000000
--- a/docs/panel/tasks-and-kanban.md
+++ /dev/null
@@ -1,59 +0,0 @@
-# Tasks & Kanban
-
-Tasks are the unit of work in RoboCo — nothing happens without one. The panel gives you three views of them: the **Tasks table** (`/tasks`) for searching and filtering everything, the **Task Detail** page (`/tasks/[id]`) for the full state of one task plus your god-mode overrides, and the **Dev Kanban** (`/kanban`) for a pipeline-style board of where work is in flight.
-
-## The Tasks table (`/tasks`)
-
-The master list of every task. It gives you full-text search and multi-select filters across **status, team, task type, project, and product**, with sortable, paginated, expandable rows. All of that filter/sort/page state lives in the URL query string, so a filtered view is shareable and survives the back button.
-
-The **Create Task** dialog lets you author a task by hand — title, acceptance criteria, project/product, type. If you'd rather describe a rough idea and have an agent read your code and draft a properly-formed task with acceptance criteria, use the conversational [Task Assistant](../get-started/first-task.md) at `/prompter` instead.
-
-## Task Detail (`/tasks/[id]`)
-
-The heaviest operator surface in the panel. The header carries the task's metadata; the body is tabbed (notes, commits, acceptance criteria, and more).
-
-### Clickable branch and PR
-
-When a task has a branch or a pull request, the git badges are **live links** into your repository's web host — the branch jumps to `…/tree/` and the PR to `…/pull/`, derived from the project's git URL. If the URL can't be parsed into a web link, it falls back to a plain label rather than a broken link, so you always see *something* useful.
-
-### Per-role note sections
-
-The **Notes** tab carries a separate, editable section for each role that touches a task, so the handoff trail is structured rather than a single free-text blob:
-
-| Section | Written by |
-|---------|-----------|
-| **Developer Notes** | the dev (`dev_notes`) |
-| **Documenter Notes** | the documenter (`doc_notes`) |
-| **QA Notes** | QA (`qa_notes`) — with a pass/fail verdict pill from `qa_verified` |
-| **PR Reviewer Notes** | the PR reviewer (`pr_reviewer_notes`) |
-| **Auditor Notes** | the Auditor (`auditor_notes`) |
-
-Empty sections still render so you can see what's expected — and add a note yourself if you need to.
-
-### CEO god-mode { #ceo-god-mode }
-
-The lifecycle is normally enforced role-by-role at the [gateway](../company/agent-gateway.md), but *you* are the CEO and can override any of it from this page. The action set covers the whole lifecycle: claim, start, pause, resume, block, unblock, verify, submit-qa, pass-qa / fail-qa, docs-complete, submit-pm-review, approve-and-merge, escalate-to-ceo, ceo-approve / ceo-reject, and cancel. You can also run git directly — **create a branch, create a PR, merge a PR** — and those operations are performed as agent id **`ceo`**.
-
-This page also exposes **Approve & Start** for a board-reviewed pending task and **Re-draft with board feedback**, which routes back to the Task Assistant (`/prompter?redraft=`).
-
-!!! warning "Every override forces an audit note"
- The state-changing actions — pass/fail QA, approvals, rejections, cancellation — open a dialog that requires you to type a note before they go through. That note is written permanently to the task's history. God-mode is powerful by design; it is never silent.
-
-See [the task lifecycle](../company/task-lifecycle.md) for what each transition means and [the merge model](../company/merge-model.md) for how PRs flow up to master.
-
-## Dev Kanban (`/kanban`)
-
-A swim-lane board of the delivery pipeline, switched with the `?view=` query param into four boards:
-
-| View | `?view=` | Shows |
-|------|----------|-------|
-| **Developer** | `dev` | tasks in the development states |
-| **QA** | `qa` | tasks awaiting / in QA review |
-| **PR Review** | `pr-review` | assembled PRs at the in-path review gate |
-| **PM** | `pm` | tasks awaiting PM review and merge |
-
-Each board is a read-at-a-glance view of where work sits in the [lifecycle](../company/task-lifecycle.md). Switching tabs updates the URL, so a specific board is shareable. A drag that would skip a lifecycle precondition (moving a task past a gate it hasn't passed) opens a confirmation dialog first, so an accidental drop can't silently bypass the flow.
-
-## Next
-
-→ [Agents & work sessions](./agents-and-work-sessions.md) to see who's working these tasks, or [Git](./git.md) to inspect the branches and PRs they produce.
diff --git a/docs/troubleshooting/common-issues.md b/docs/troubleshooting/common-issues.md
deleted file mode 100644
index 18e0dd0a..00000000
--- a/docs/troubleshooting/common-issues.md
+++ /dev/null
@@ -1,83 +0,0 @@
-# Common issues
-
-When something goes wrong, the failure is almost always one of a handful of things: a mount that didn't make it into the container, a model that isn't pulled, a token that expired, or a provider that's parked rather than hung. This page is the problem→cause→fix guide for the snags you'll actually hit, ordered by how often they bite on a fresh deployment.
-
-## Quick reference
-
-| Symptom | Most likely cause | Fix |
-|---------|-------------------|-----|
-| Agents spawn but do nothing useful (tool-discovery churn) | The role's tool-manifest didn't mount; the agent falls back to discovering verbs | Check the manifest mount (below) |
-| Agent containers respawn in a loop, MCP servers stuck "pending" | MCP server launched without `--no-sync` against a workspace clone | Already fixed in the orchestrator; verify your image is current (below) |
-| A provider's agents go quiet all at once | The provider is **parked-and-probing** after a 429 / overload / session-limit — not hung | Wait; it self-resumes. See [Resilience](../models/resilience.md) |
-| A task sits **blocked: "branch behind base / needs rebase"** | The agent's branch fell behind its base while it worked; devs now self-rebase via the `sync_branch` gate verb, so a leaf branch rarely blocks here. A **cell/root integration branch** behind its base still escalates (PMs have no rebase verb) | Rebase the integration branch from the panel **Git** tab (below) |
-| KB / `ask_mentor` returns nothing | Ollama unhealthy or models not pulled | Check `ollama-init` logs (below) |
-| Agent containers exit immediately | `~/.claude` not mounted, or a Grok token expired | Check the mount / refresh the token (below) |
-| Clone fails, agent can't reach the repo | Missing or invalid project PAT, or HTTPS URL with no token | Set the project token (below) |
-| Orchestrator won't start | `ROBOCO_ENCRYPTION_KEY` unset, or a pending migration | First-run checklist (below) |
-
-## Agents spawn but do nothing
-
-If agents come up but burn turns "looking for tools" instead of claiming work, the cause is almost always the **tool manifest**. At spawn the orchestrator writes a per-agent manifest and mounts it read-only at `/app/tool-manifest.json` (the mount is built in `roboco/runtime/orchestrator.py`, pointing `ROBOCO_TOOL_MANIFEST_PATH` at that path). The manifest lists exactly the verbs the agent's role may call — see [the gateway](../company/agent-gateway.md).
-
-If that file is missing inside the container, the agent has no allow-list to read and falls back to discovering the verb surface itself, which wastes turns and tokens. The mount source is `{DATA_HOST_PATH}/manifests/{agent_id}.json` on the host. Confirm the host directory exists and is writable, and that the data volume is mounted into the orchestrator so it can write manifests there in the first place.
-
-!!! tip "Verify the mount inside the container"
- Exec into a running agent container and check that `/app/tool-manifest.json` exists and is non-empty. If it's absent, the orchestrator couldn't write or mount the per-agent manifest — fix the host `manifests/` directory and the orchestrator's data-volume mount, then respawn.
-
-## Respawn loop with MCP servers stuck "pending"
-
-A historical failure mode: each agent's MCP servers (`roboco-flow`, `roboco-do`, the read-only git and KB servers) launch via `uv run` from inside the agent's workspace clone. If `uv` re-syncs that clone on launch it can collide with the clone's lock, the gateway servers never come up, the agent has zero verbs, and the orchestrator respawns it in a loop.
-
-The fix is already in the code: every MCP server is launched with `uv run --no-sync` (`roboco/runtime/orchestrator.py`), and the SDK startup hook pins `uv` to the pre-baked image venv. If you see this symptom, your running image predates the fix — rebuild and redeploy the agent images so the `--no-sync` launch is in effect.
-
-## A "quiet" provider is parked, not hung
-
-If every agent on one provider goes silent at the same moment, it is almost never a crash. On a provider 429, a persistent overload (HTTP 529/500/503), or a Claude session-limit (the rolling 5-hour usage window), RoboCo **parks** that provider's work and runs a background probe that resumes it the moment the provider recovers — it does not crash-retry into the wall and burn tokens. You'll see an amber banner in the panel; the work revives on its own.
-
-!!! note "Don't restart to 'unstick' it"
- Restarting the orchestrator throws away the park-and-probe state and the parked agents' context. Leave it alone — it self-heals. The full mechanism, the banner, and the `ROBOCO_OVERLOAD_BREAK_ENABLED` flag are documented in [Resilience](../models/resilience.md).
-
-## KB search / ask-mentor returns nothing
-
-The knowledge base and `roboco_ask_mentor` run on the in-house pgvector RAG, which depends on Ollama for embeddings and the local LLM. If the KB is empty or `ask` comes back blank, Ollama is the usual culprit:
-
-- **Models not pulled.** `ollama-init` pulls `qwen3-embedding:0.6b` (the embedder, ~30s) and the local LLM (~2min) on startup. Check `docker logs roboco-ollama-init` — if the pull failed or is still running, embeddings can't be produced and indexing/retrieval returns nothing.
-- **Ollama unhealthy.** The healthcheck is `ollama list`, not a curl. If the `ollama` service is unhealthy the orchestrator's document indexing (run during FastAPI lifespan) never completes.
-- **A `404 /api/embed`** in the logs means the embedding model isn't present — re-check `ollama-init`.
-
-See [Health and metrics](../operations/health-and-metrics.md) for where these surface in the panel.
-
-## Agent containers exit immediately
-
-A container that starts and dies within seconds is missing something it needs at boot:
-
-- **`~/.claude` not mounted (Claude agents).** Claude-backed agents mount the host's `~/.claude` (overridable via `ROBOCO_HOST_CLAUDE_DIR`) into the container so they can authenticate. If that directory is absent or unreadable on the host, the agent can't start. Confirm the host directory exists and the orchestrator user can read it.
-- **Grok token expired (Grok agents).** Grok's access token has a fixed ~6h TTL and the CLI can't refresh it headlessly — on an expired token it would otherwise hang forever at an interactive login prompt. The entrypoint runs `python -m roboco.llm.providers.grok_auth --check` as a preflight and **exits 78** immediately rather than hang (`docker/scripts/grok-cli-agent-entrypoint.sh`). An exit code of 78 means the Grok token is missing or expired. The orchestrator mints a fresh token before expiry on each dispatch tick; if you keep hitting 78, re-run `grok login` on the host to repopulate the shared `auth.json`.
-
-## Clone fails / agent can't reach the repo
-
-Cloning is the first thing an agent does on a project, and it fails for one reason in practice: the **project's GitHub token**. Git auth is per-project, not global.
-
-- An **HTTPS Git URL with no token fails** — the agent can't authenticate. Set the token when you create the project.
-- An **invalid or under-scoped token** fails the same way. The token needs repository contents access (clone/push) and pull-request access. See [Register a project](../get-started/first-project.md#the-github-token) for the exact scopes.
-
-Remember the API never returns a stored token, so the panel only shows whether one is set, not its value — if a clone fails, re-enter the token rather than assuming the stored one is good.
-
-!!! warning "If you rotated ROBOCO_ENCRYPTION_KEY"
- Every project PAT is Fernet-encrypted with `ROBOCO_ENCRYPTION_KEY`. Change that key and all stored tokens become undecryptable — clones will fail until you re-enter every token. See [Security](./security.md).
-
-## First-run and migration checks
-
-When the orchestrator won't come up at all on a fresh deploy:
-
-- **`ROBOCO_ENCRYPTION_KEY` must be set.** It defaults to empty in config, but the orchestrator refuses to start without it. Generate one with `python -c 'from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())'` and set it in your `.env`. It is load-bearing and must never change after first use.
-- **Migrations.** Schema changes ship as Alembic migrations under `alembic/versions/`. The API applies them on startup (and falls back to `create_all` on a fresh DB), but after pulling a change that adds a migration you can apply it explicitly with `docker compose exec orchestrator alembic upgrade head`.
-- **Startup is slow on purpose.** The FastAPI lifespan does ~30–60s of document indexing before the API answers, and the orchestrator polls `/health` for up to 120s before starting its dispatch loop. An "All connection attempts failed" early in the logs usually just means a dependent service hadn't finished its healthcheck yet — give the startup sequence time before treating it as an error.
-
-## A task is stuck on a branch behind its base
-
-A task branch is brought current with its base only at claim. If the base moves forward while the agent works, the branch falls behind. **Developer leaf branches** now self-rebase through the `sync_branch` gate verb — the dev calls `sync_branch(task_id)` (or `i_am_done` refuses a behind branch and points them at it), so a leaf rarely escalates to you. What still escalates is a **cell or root integration branch** behind its base: PMs have no rebase verb, so a PM `escalate_up`s and the task surfaces **blocked** with a reason like *"branch behind base — needs rebase."* That escalation is by design for an integration branch — bringing it current is your call, not a unit of work the company decomposes. Rebase it from the panel **Git** tab — select the branch and **Rebase** it onto its base (or master) — and the task resumes on the next dispatch. (Automatic rebase-at-spawn, so a stale branch never reaches you at all, is on the roadmap.)
-
-## Next
-
-→ [Security](./security.md) — the trust model and how to harden a deployment, or back to the [troubleshooting index](./index.md).
diff --git a/docs/troubleshooting/index.md b/docs/troubleshooting/index.md
deleted file mode 100644
index 6ec17236..00000000
--- a/docs/troubleshooting/index.md
+++ /dev/null
@@ -1,19 +0,0 @@
-# Troubleshooting & Security
-
-When something looks stuck, or before you put RoboCo anywhere near a network you don't fully trust, start here.
-
-
-
-- **[Common issues](common-issues.md)**
-
- ---
-
- The usual snags — agents that spawn but do nothing, a "quiet" provider that's actually parked, an empty knowledge base — with their causes and fixes.
-
-- **[Security](security.md)**
-
- ---
-
- The trust model: header-trust versus secure mode, how secrets and tokens are handled, and the one rule — don't expose it to the public internet.
-
-