docs(plans): add Autensa benchmark tasks to automation foundation roadmap

Map reliability, operator UX, and spend-control follow-ons onto epics 1–9
so worker, webhooks, and fleet work have bead-scale task briefs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Randall Stillwell 2026-08-03 10:48:36 -05:00
parent 2f6adf4382
commit 35def387ae
20 changed files with 886 additions and 34 deletions

View file

@ -7,7 +7,7 @@ status: done
priority: P1
tenant_id: global
cursor_epic_id: null
updated_at: "2026-07-03"
updated_at: "2026-08-03"
---
# Epic objective
@ -55,6 +55,12 @@ Each job calls `resolveModel(workspace, roleId, convoy, brief)` and passes `Reso
- [x] [Task-shared-orchestrator-driver](./Task-shared-orchestrator-driver.md)
- [x] [Task-apps-orchestrator-service](./Task-apps-orchestrator-service.md)
## Follow-on tasks (Autensa benchmark)
| Task | Link |
|------|------|
| Agent health auto-nudge & zombie recovery | [Task-orchestrator-auto-nudge](./Task-orchestrator-auto-nudge.md) |
## Note
Supersedes [Epic-optional-orchestrator](../../Plan-agent-coordination/Epic-optional-orchestrator/Epic-optional-orchestrator.md) deferred stub with a concrete Echodo-native design.

View file

@ -0,0 +1,64 @@
---
kind: task
slug: orchestrator-auto-nudge
title: Orchestrator agent health — auto-nudge and zombie recovery
plan_slug: automation-foundation
epic_slug: apps-orchestrator
status: draft
priority: P2
tenant_id: global
owner: unassigned
cursor_todo_id: null
updated_at: "2026-08-03"
---
# Task summary
Extend stall detection beyond marking convoys `blocked`: detect zombie agent runs, optionally re-dispatch or nudge, and emit health events for mission control / fleet feed.
## Description
**Benchmark:** Autensa agent health monitoring with auto-nudge and convoy health panel. Echodo already has `ORCHESTRATOR_STALL_MINUTES` and `detectStalledConvoys` — this task adds **recovery actions** and observability.
### Health states
| State | Trigger | Default action |
|-------|---------|----------------|
| **Stalled** | No heartbeat on open `agent_run` for N minutes | Mark convoy `blocked`; surface in gate inbox sidebar |
| **Zombie** | Run open but worker process gone | Re-enqueue job with `resume_from_checkpoint` when Epic 7 checkpoint task ships |
| **Nudge** | Soft stall (configurable) | Log `convoy_events` health event; optional Redis ping to worker |
### Config (env)
- `ORCHESTRATOR_NUDGE_MINUTES` (optional, < stall threshold)
- `ORCHESTRATOR_AUTO_REDISPATCH` (default false — opt-in for unattended dogfood)
### Events
Append `convoy_events` with `event_type: health` and metadata `{ reason, action, agent_run_id }` for activity feed (Epic 9).
## Dependencies
- Epic 6 orchestrator service (shipped)
- [Task-worker-checkpoint-resume](../Epic-apps-worker-v1/Task-worker-checkpoint-resume.md) for meaningful re-dispatch
## Subtasks
- [ ] Extend `detectStalledConvoys` with nudge vs hard-stall tiers
- [ ] Optional re-dispatch path on zombie detection
- [ ] `convoy_events` health event writer
- [ ] Document in `docs/orchestrator.md`
## Estimation
M
## Acceptance criteria
- [ ] Stalled run moves convoy to `blocked` and writes health event
- [ ] With `ORCHESTRATOR_AUTO_REDISPATCH=1`, zombie run triggers new job enqueue
- [ ] No unbounded re-dispatch loops (max retries per brief configurable)
## Links
- Epic: `./Epic-apps-orchestrator.md`

View file

@ -7,7 +7,7 @@ status: in_progress
priority: P1
tenant_id: global
cursor_epic_id: null
updated_at: "2026-07-03"
updated_at: "2026-08-03"
---
# Epic objective
@ -25,11 +25,13 @@ Role prompt = `.cursor/agents/role-*.md` + brief path. Model endpoint points at
- `WorkerSession` adapter interface (for future optional OpenHands plug-in).
- `pnpm lint && pnpm test` in allowlisted commands.
- Branch + PR draft output (forge adapter from Epic 3).
- Checkpoint/resume and operator mid-build notes (Autensa benchmark — see tasks below).
**Out of scope**
- Browser automation, multi-agent delegation.
- Feature parity with OpenHands.
- OpenClaw Gateway coupling.
## Dependencies
@ -43,7 +45,12 @@ Role prompt = `.cursor/agents/role-*.md` + brief path. Model endpoint points at
- [ ] One brief from `.convoys/` completes unattended on connected repo.
- [ ] `complete_task` includes model alias + token totals.
- [ ] Crashed worker can resume from checkpoint (follow-on task).
## Tasks
_To be decomposed when epic graduates to `ready`._
| Task | Link | Status |
|------|------|--------|
| Minimal tool loop + worktree | [Task-worker-minimal-tool-loop](./Task-worker-minimal-tool-loop.md) | ready |
| Checkpoint & crash recovery | [Task-worker-checkpoint-resume](./Task-worker-checkpoint-resume.md) | draft |
| Operator notes mid-build | [Task-worker-operator-notes](./Task-worker-operator-notes.md) | draft |

View file

@ -0,0 +1,66 @@
---
kind: task
slug: worker-checkpoint-resume
title: Worker checkpoint and crash recovery
plan_slug: automation-foundation
epic_slug: apps-worker-v1
status: draft
priority: P1
tenant_id: global
owner: unassigned
cursor_todo_id: null
updated_at: "2026-08-03"
---
# Task summary
Persist worker session progress at configurable checkpoints so a crashed or stalled job resumes from the last checkpoint instead of restarting the brief from scratch.
## Description
**Benchmark:** [Autensa mission-control](https://github.com/crshdn/mission-control) checkpoint & crash recovery — study their checkpoint restore API and per-task history UX; implement Echodo-native equivalents on Postgres.
### Schema
Add `worker_checkpoints` (or JSONB on `agent_runs`) workspace-scoped:
- `agent_run_id`, `convoy_id`, `brief_id`
- `checkpoint_seq`, `tool_history` (bounded), `files_touched`, `branch`, `worktree_path`
- `occurred_at`
### Worker behavior
- Save checkpoint after each tool round (configurable via `WORKER_CHECKPOINT_EVERY_N_STEPS`, default 1).
- On job start: if open run has latest checkpoint, resume tool loop from saved state.
- Orchestrator stall detector can trigger re-dispatch with `resume_from_checkpoint: true`.
### Operator surface (minimal v1)
- Mission control detail panel: checkpoint count + last checkpoint time (full history deferred).
## Dependencies
- [Task-worker-minimal-tool-loop](./Task-worker-minimal-tool-loop.md) (baseline loop must exist).
## Subtasks
- [ ] Zod schemas in `packages/shared/worker`
- [ ] Drizzle migration + workspace-scoped queries
- [ ] Checkpoint write in `minimal-session` / `handle-job`
- [ ] Resume path on re-dispatch
- [ ] Env docs in `docs/worker.md`
## Estimation
M
## Acceptance criteria
- [ ] Kill worker mid-brief; re-dispatch resumes from last tool step without re-cloning
- [ ] Checkpoints filtered by `workspace_id`
- [ ] Checkpoint payload does not store API keys or full file contents (paths + hashes only)
## Links
- Epic: `./Epic-apps-worker-v1.md`
- Blocks: reliable unattended dogfood for Epic 8

View file

@ -0,0 +1,67 @@
---
kind: task
slug: worker-minimal-tool-loop
title: apps/worker — minimal tool loop and worktree-per-brief
plan_slug: automation-foundation
epic_slug: apps-worker-v1
status: ready
priority: P1
tenant_id: global
owner: unassigned
cursor_todo_id: null
updated_at: "2026-08-03"
agent_prompt: |
Epic: apps/worker v1. Read docs/worker.md and docs/adr-model-routing.md.
Consume orchestrator jobs from Redis; resolve model via workspace registry.
claim_task / complete_task parity with MCP. Run pnpm lint && pnpm type-check
&& pnpm test before done.
---
# Task summary
Ship the baseline `apps/worker` consumer: dequeue `role_dispatch` jobs, run `WorkerSession` tool loop against a git worktree, and close with model + token metadata on `complete_task`.
## Description
Core v1 scope from [Epic-apps-worker-v1](./Epic-apps-worker-v1.md). Builds on existing package skeleton (`handle-job.ts`, `minimal-session.ts`, allowlisted tools, worktree helpers).
### Worker loop
- `BLPOP` on `echodo:orchestrator:jobs` (same key as orchestrator).
- Load brief path + role from job payload; resolve model via shared resolver.
- `claim_task` on matching backlog item; run `read_file` / `write_file` / `grep` / `run_command` (allowlist: `pnpm lint`, `pnpm type-check`, `pnpm test`, `git status`, `git diff`).
- `complete_task` with `modelAlias`, token totals, outcome.
### Git
- One worktree per brief under `WORKER_WORKTREE_BASE`.
- Branch naming convention documented for Epic 8 PR linking.
### PR output
- Open draft PR via forge adapter from connected repo (Epic 3).
## Subtasks
- [ ] Wire live dequeue loop (non-dry-run) end-to-end
- [ ] Role prompt = `.cursor/agents/role-*.md` + brief markdown path
- [ ] Worktree create/teardown on success and failure
- [ ] Draft PR via forge adapter when implementer completes
- [ ] `docs/worker.md` matches shipped behavior
## Estimation
L
## Acceptance criteria
- [ ] One implementer brief from `.convoys/` completes unattended on a connected repo
- [ ] `complete_task` includes model alias + token totals
- [ ] Failed runs tear down worktree and mark run `failed`
- [ ] `WORKER_DRY_RUN=1` still exits cleanly without Redis
## Links
- Epic: `./Epic-apps-worker-v1.md`
- Plan: `../Plan-automation-foundation.md`
- Design reference: Autensa convoy build phase (concepts only — no OpenClaw dependency)

View file

@ -0,0 +1,73 @@
---
kind: task
slug: worker-operator-notes
title: Operator notes — mid-build context injection
plan_slug: automation-foundation
epic_slug: apps-worker-v1
status: draft
priority: P2
tenant_id: global
owner: unassigned
cursor_todo_id: null
updated_at: "2026-08-03"
---
# Task summary
Let operators send **queued notes** and **direct messages** to an active worker session without waiting for a human gate.
## Description
**Benchmark:** Autensa Operator Chat — two delivery modes:
| Mode | Delivery | Use case |
|------|----------|----------|
| **Queued note** | Injected at next checkpoint / tool round | "Use the existing auth middleware" |
| **Direct message** | Prepended to very next model call | Urgent course correction |
Echodo scope is convoy-scoped (not per arbitrary task board). Gate co-pilot (Epic 5) stays gate-focused; this extends intervention to `in_progress` convoys.
### Data model
`convoy_operator_messages` table (workspace-scoped):
- `convoy_id`, `brief_id` (optional), `agent_run_id` (optional)
- `delivery`: `queued` | `direct`
- `body`, `author_user_id`, `delivered_at`, `created_at`
### APIs
- tRPC `convoys.postOperatorNote` (workspace member)
- Worker polls or receives note via job metadata on each tool round
### UI
- Mission control detail panel: chat thread when convoy status is `in_progress`
- Distinct from gate co-pilot (separate tab or section)
## Dependencies
- [Task-worker-minimal-tool-loop](./Task-worker-minimal-tool-loop.md)
- Epic 5 mission control detail panel (extend, do not rewrite)
## Subtasks
- [ ] Schema + tRPC mutations/list
- [ ] Worker consumes queued notes between tool steps
- [ ] Worker consumes direct messages before next `generateText`
- [ ] Mission control UI thread for `in_progress` convoys
## Estimation
M
## Acceptance criteria
- [ ] Operator posts queued note; worker sees it on next tool round
- [ ] Direct message arrives before next model call when run is active
- [ ] Messages are workspace-scoped and auditable in convoy detail
## Links
- Epic: `./Epic-apps-worker-v1.md`
- Related: [Task-mission-control-ui](../Epic-mission-control-gates-ui/Task-mission-control-ui.md)

View file

@ -7,7 +7,7 @@ status: done
priority: P1
tenant_id: global
cursor_epic_id: null
updated_at: "2026-07-03"
updated_at: "2026-08-03"
---
# Epic objective
@ -49,3 +49,9 @@ See automation foundation discussion: Vercel/Coolify-style “show me your repo.
- [x] [Task-db-connected-repos-migration](./Task-db-connected-repos-migration.md)
- [x] [Task-forge-adapters-trpc](./Task-forge-adapters-trpc.md)
- [x] [Task-settings-connected-repos-ui](./Task-settings-connected-repos-ui.md)
## Follow-on tasks (Autensa benchmark)
| Task | Link |
|------|------|
| Repo setup preflight tab | [Task-repo-setup-preflight](./Task-repo-setup-preflight.md) |

View file

@ -0,0 +1,70 @@
---
kind: task
slug: repo-setup-preflight
title: Connected repo setup preflight — readiness before automation
plan_slug: automation-foundation
epic_slug: connected-repos
status: draft
priority: P2
tenant_id: global
owner: unassigned
cursor_todo_id: null
updated_at: "2026-08-03"
---
# Task summary
**Repo Setup** tab on connected repos: verify a remote is automation-ready before orchestrator/worker dispatch (git access, default branch, CI permissions, required secrets).
## Description
**Benchmark:** Autensa v2.5.1 Repo Setup tab — preflight checks with in-UI fixes where the forge API allows. Echodo adapts this to multitenant `repo_links` and forge adapters (Forgejo + GitHub minimum).
### Preflight checks
| Check | Pass criteria |
|-------|---------------|
| Git clone | Shallow clone with stored credentials |
| Default branch | API-detected default matches stored value |
| Forge API | PR list/create permission |
| CI visibility | Latest workflow run status readable |
| Actions token (GitHub) | `contents` + `pull-requests` write if applicable |
| Required secrets | Names present (values never stored in Echodo DB) |
### UI
- Settings → Connected repos → per-repo **Setup** tab
- Traffic-light checklist with expandable failure reasons
- Block convoy **Go** when critical checks fail (soft warning vs hard block — configurable per workspace)
### Fixes (where API supports)
- GitHub: suggest/set workflow token permissions; link to docs for secret creation (do not write secret values through Echodo — operator pastes in forge UI)
## Dependencies
- Epic 3 connected repos (shipped)
- Epic 6 orchestrator should read preflight status before enqueue
## Subtasks
- [ ] `repoPreflightStatus` zod schema in `packages/shared`
- [ ] Forge adapter methods: `getDefaultBranch`, `listWorkflowRuns`, `getRepoPermissions`
- [ ] tRPC `connectedRepos.runPreflight`
- [ ] Settings UI Setup tab
- [ ] Orchestrator skips dispatch when repo link `preflight_ok` is false
## Estimation
L
## Acceptance criteria
- [ ] Repo with wrong default branch shows failing check with detected branch name
- [ ] Private repo without token shows auth failure (no silent pass)
- [ ] Preflight re-runnable without reconnecting repo
- [ ] No forge secret values persisted in Postgres
## Links
- Epic: `./Epic-connected-repos.md`

View file

@ -7,14 +7,16 @@ status: draft
priority: P2
tenant_id: global
cursor_epic_id: null
updated_at: "2026-07-03"
updated_at: "2026-08-03"
---
# Epic objective
Top-level **fleet** view: all `convoys-<repo>` workspaces (or connected repos) in one screen. Roll up convoys by status, gate inbox count, active `agent_runs`, recent spend by model alias.
Answers: “What needs me across all projects?”
Live **activity feed** (SSE) from `convoy_events` — Autensa benchmark for operator situational awareness.
Answers: “What needs me across all projects?” and “What just happened?”
## In scope / out of scope
@ -23,10 +25,12 @@ Answers: “What needs me across all projects?”
- Route `/fleet` or home dashboard for operator account.
- Cross-workspace tRPC (membership-scoped).
- Links into per-repo mission control (Epic 5).
- SSE activity stream (workspace + fleet scope).
**Out of scope**
- Multi-tenant fleet across unrelated customers (operator's own repos only for v1).
- Autopilot research/ideation feeds.
## Dependencies
@ -36,7 +40,11 @@ Answers: “What needs me across all projects?”
## Acceptance criteria
- [ ] Operator with two connected repos sees combined “3 awaiting approval” badge.
- [ ] New convoy event appears in activity feed without page refresh.
## Tasks
_To be decomposed when epic graduates to `ready`._
| Task | Link | Status |
|------|------|--------|
| Fleet rollup dashboard | [Task-fleet-rollup-dashboard](./Task-fleet-rollup-dashboard.md) | ready |
| Live activity feed (SSE) | [Task-convoy-activity-feed-sse](./Task-convoy-activity-feed-sse.md) | draft |

View file

@ -0,0 +1,63 @@
---
kind: task
slug: convoy-activity-feed-sse
title: Live convoy activity feed (SSE)
plan_slug: automation-foundation
epic_slug: fleet-dashboard
status: draft
priority: P2
tenant_id: global
owner: unassigned
cursor_todo_id: null
updated_at: "2026-08-03"
---
# Task summary
Real-time activity stream from `convoy_events` for mission control and fleet dashboard — research/build/gate/health events without full page refresh.
## Description
**Benchmark:** Autensa live activity feed (SSE). Echodo already appends `convoy_events` for role completion, transitions, and (future) health events — this task exposes them as a **subscription surface**.
### Transport
- Prefer Next.js Route Handler `GET /api/convoys/activity/stream` with SSE (workspace-scoped via session)
- Alternative: tRPC subscription if infra already supports it — pick one, document in ADR addendum
### Event types surfaced
- `role_complete`, `transition`, `health`, `gate_action`
- Payload: `convoy_id`, `title`, `event_type`, `role`, `outcome`, `occurred_at`, `estimated_cost_usd` (when present)
### UI
- Mission control: collapsible **Activity** strip (last 20 events for current workspace)
- Fleet dashboard: global feed with product/repo filter
- Fallback: React Query poll every 30s when SSE unavailable
## Dependencies
- Epic 4 `convoy_events` (shipped)
- [Task-orchestrator-auto-nudge](../Epic-apps-orchestrator/Task-orchestrator-auto-nudge.md) for health events (soft — feed works without it)
## Subtasks
- [ ] SSE route with workspace membership check
- [ ] `convoy_events` tail query + fan-out on insert (LISTEN/NOTIFY or short poll server-side)
- [ ] `ActivityFeed` client component
- [ ] Rate limit / connection cap per user
## Estimation
M
## Acceptance criteria
- [ ] New `role_complete` event appears in mission control within 5s without refresh
- [ ] User cannot subscribe to another workspace's events
- [ ] Connection closes cleanly on navigation
## Links
- Epic: `./Epic-fleet-dashboard.md`

View file

@ -0,0 +1,58 @@
---
kind: task
slug: fleet-rollup-dashboard
title: Fleet dashboard — cross-repo convoy rollup
plan_slug: automation-foundation
epic_slug: fleet-dashboard
status: ready
priority: P2
tenant_id: global
owner: unassigned
cursor_todo_id: null
updated_at: "2026-08-03"
---
# Task summary
Operator home at `/fleet` (or authenticated landing): rollup gate inbox counts, convoys by status, and active `agent_runs` across all workspaces the user belongs to.
## Description
Core Epic 9 scope. Answers: **"What needs me across all projects?"**
### UI
- Card per connected repo / convoy workspace
- Badge: N awaiting approval (sum of `GATE_INBOX_STATUSES`)
- Quick links into `/{workspaceSlug}/mission-control?convoy=...`
- Active runs count + blocked count
### API
- tRPC `fleet.summary` — membership-scoped cross-workspace query (no client-provided workspace_id trust)
- Reuse `MISSION_CONTROL_KANBAN_COLUMNS` counts per workspace
## Dependencies
- Epic 4, 5 (shipped)
## Subtasks
- [ ] `fleet` tRPC router with membership joins
- [ ] `/fleet` route (app layout)
- [ ] Icon rail / top-header link when user has ≥2 workspaces
- [ ] Empty state for single-workspace operators
## Estimation
M
## Acceptance criteria
- [ ] Operator with two connected repos sees combined "3 awaiting approval" badge
- [ ] Clicking badge navigates to correct workspace mission control with inbox focused
- [ ] Query performs one round-trip (no N+1 per workspace in UI)
## Links
- Epic: `./Epic-fleet-dashboard.md`

View file

@ -7,13 +7,15 @@ status: draft
priority: P2
tenant_id: global
cursor_epic_id: null
updated_at: "2026-07-03"
updated_at: "2026-08-03"
---
# Epic objective
Webhook receivers on Echodo for connected forges: PR opened → `pr_review`; PR merged → trigger doc-writer job + `merged`; CI failed → optional `blocked` or notify. Supports Forgejo and GitHub adapters minimum.
PR checks recovery UI in mission control when CI fails (Autensa benchmark).
## In scope / out of scope
**In scope**
@ -21,6 +23,7 @@ Webhook receivers on Echodo for connected forges: PR opened → `pr_review`; PR
- `POST /api/webhooks/forge/:repoLinkId` with signature verification.
- Map events to `transition_convoy_status(actor: automation)`.
- Link PR branch to convoy/brief via branch naming convention or PR body marker.
- PR checks recovery panel (classify failures, rerun where API allows).
**Out of scope**
@ -33,7 +36,11 @@ Webhook receivers on Echodo for connected forges: PR opened → `pr_review`; PR
## Acceptance criteria
- [ ] Merge on Forgejo moves convoy from `pr_review` to `merged` when Gate 2 approved.
- [ ] Mission control shows PR check failures with recovery actions for `pr_review` convoys.
## Tasks
_To be decomposed when epic graduates to `ready`._
| Task | Link | Status |
|------|------|--------|
| Webhook receiver | [Task-forge-webhook-receiver](./Task-forge-webhook-receiver.md) | ready |
| PR checks recovery panel | [Task-pr-checks-recovery-panel](./Task-pr-checks-recovery-panel.md) | draft |

View file

@ -0,0 +1,59 @@
---
kind: task
slug: forge-webhook-receiver
title: Forge webhook receiver — PR and CI events
plan_slug: automation-foundation
epic_slug: forge-webhooks
status: ready
priority: P2
tenant_id: global
owner: unassigned
cursor_todo_id: null
updated_at: "2026-08-03"
---
# Task summary
`POST /api/webhooks/forge/:repoLinkId` with HMAC signature verification; map forge events to `transition_convoy_status(actor: automation)`.
## Description
Core Epic 8 scope. Link PRs to convoys via branch naming convention (`convoy/<slug>/brief-N`) or PR body marker (`echodo-convoy: <uuid>`).
### Events (minimum)
| Forge event | Convoy transition |
|-------------|-------------------|
| PR opened | Ensure convoy in `pr_review` (if Gate 2 not yet human-approved, notify only) |
| PR merged | `pr_review` → `merged` when Gate 2 already approved |
| CI completed (failure) | Optional `blocked` or `convoy_events` notify |
### Security
- Per-repo webhook secret in `repo_links` metadata (reference env var name, not value)
- Zod-validated payload per `forge_type`
## Dependencies
- Epic 3, 4, 7
## Subtasks
- [ ] Route handler + signature verification
- [ ] GitHub + Forgejo payload parsers
- [ ] Convoy lookup by branch/body marker
- [ ] Register webhook URL helper on connect (optional UX)
## Estimation
M
## Acceptance criteria
- [ ] Merge webhook moves convoy from `pr_review` to `merged` when Gate 2 approved
- [ ] Invalid signature returns 401
- [ ] Unknown branch logs and returns 200 (no retry storm)
## Links
- Epic: `./Epic-forge-webhooks.md`

View file

@ -0,0 +1,62 @@
---
kind: task
slug: pr-checks-recovery-panel
title: PR checks recovery panel in mission control
plan_slug: automation-foundation
epic_slug: forge-webhooks
status: draft
priority: P2
tenant_id: global
owner: unassigned
cursor_todo_id: null
updated_at: "2026-08-03"
---
# Task summary
When a convoy is in `pr_review`, show linked PR CI status in mission control with classified failures and recovery actions (rerun jobs, link to repo setup).
## Description
**Benchmark:** Autensa v2.5.1 PR checks recovery panel — classify failures as retryable, repo setup, or external provider; offer rerun where forge API supports it.
### UI (convoy detail panel)
- PR link + check run list (name, status, conclusion)
- Failure classification badge per check
- Actions: **Rerun failed jobs** (GitHub Actions API), **Open repo setup** (Epic 3 follow-on task)
### Backend
- tRPC `convoys.getPrChecks` — workspace-scoped, uses forge adapter
- `convoys.rerunFailedChecks` — admin only; audit log in `convoy_events`
### Webhook integration
- CI `completed` webhook refreshes cached check status on convoy metadata
## Dependencies
- [Task-forge-webhook-receiver](./Task-forge-webhook-receiver.md)
- [Task-repo-setup-preflight](../Epic-connected-repos/Task-repo-setup-preflight.md) (link target for setup failures)
## Subtasks
- [ ] Forge adapter: list check runs for PR
- [ ] Failure classifier (heuristics: permissions → setup, timeout → retryable, external → informational)
- [ ] Mission control PR checks section when status is `pr_review`
- [ ] Rerun action + event logging
## Estimation
M
## Acceptance criteria
- [ ] Failed lint CI shows retryable with working rerun (GitHub fixture or manual dogfood)
- [ ] Missing Actions permission links to repo setup tab with failing check highlighted
- [ ] No recovery action exposed without workspace admin role
## Links
- Epic: `./Epic-forge-webhooks.md`

View file

@ -7,7 +7,7 @@ status: done
priority: P1
tenant_id: global
cursor_epic_id: null
updated_at: "2026-07-03"
updated_at: "2026-08-03"
---
# Epic objective
@ -48,3 +48,12 @@ Echodo UI for human gates and convoy visibility:
- [x] [Task-trpc-convoys-router](./Task-trpc-convoys-router.md)
- [x] [Task-mission-control-ui](./Task-mission-control-ui.md)
## Follow-on tasks (Autensa benchmark)
| Task | Link |
|------|------|
| Convoy DAG visualization | [Task-convoy-dag-visualization](./Task-convoy-dag-visualization.md) |
| Automation tiers (supervised / semi-auto) | [Task-automation-tiers](./Task-automation-tiers.md) |
Operator mid-build chat is tracked under Epic 7: [Task-worker-operator-notes](../Epic-apps-worker-v1/Task-worker-operator-notes.md).

View file

@ -0,0 +1,68 @@
---
kind: task
slug: automation-tiers
title: Automation tiers — supervised, semi-auto, full-auto gate policy
plan_slug: automation-foundation
epic_slug: mission-control-gates-ui
status: draft
priority: P2
tenant_id: global
owner: unassigned
cursor_todo_id: null
updated_at: "2026-08-03"
---
# Task summary
Per-convoy (or per-workspace default) **automation tier** controlling which human gates auto-advance when CI and review agents pass.
## Description
**Benchmark:** Autensa automation tiers (Supervised / Semi-Auto / Full Auto). Maps onto Echodo's explicit gate model without removing human override.
| Tier | Gate 1 (plan) | Gate 2 (merge) | Gate 3 (prod) |
|------|---------------|----------------|---------------|
| **Supervised** | Human | Human | Human |
| **Semi-auto** | Human | Auto when CI green + review agent pass | Human |
| **Full-auto** | Human | Auto when CI green | Auto when deploy webhook fires (future) |
### Schema
- `convoys` metadata field `automation_tier`: `supervised` | `semi_auto` | `full_auto` (default `supervised`)
- Workspace default in settings (optional)
### Behavior
- Orchestrator / webhook handlers consult tier before calling `transition_convoy_status` with `actor: automation`
- Mission control shows tier badge on convoy card; editable before **Go**
### Out of scope
- Auto-approving Gate 1 (plan always human in v1)
- Autopilot research/ideation (Autensa-specific)
## Dependencies
- Epic 5 gates UI
- Epic 8 webhooks for semi-auto Gate 2
## Subtasks
- [ ] Zod enum in `packages/shared/convoy-lifecycle`
- [ ] Create convoy dialog + detail panel tier selector
- [ ] Orchestrator respects tier on CI webhook path
- [ ] Document tier semantics in `docs/orchestrator.md`
## Estimation
S
## Acceptance criteria
- [ ] Semi-auto convoy auto-transitions `pr_review` → `merged` on merge webhook only when CI was green at merge time
- [ ] Supervised convoy never auto-merges
- [ ] Tier visible on kanban card tooltip
## Links
- Epic: `./Epic-mission-control-gates-ui.md`

View file

@ -0,0 +1,58 @@
---
kind: task
slug: convoy-dag-visualization
title: Convoy DAG visualization for parallel briefs
plan_slug: automation-foundation
epic_slug: mission-control-gates-ui
status: draft
priority: P2
tenant_id: global
owner: unassigned
cursor_todo_id: null
updated_at: "2026-08-03"
---
# Task summary
Read-only dependency graph in mission control showing brief/subtask relationships and `multitask_group` parallel lanes.
## Description
**Benchmark:** Autensa Convoy Mode DAG — visual dependency graph for parallel subtasks. Echodo already has `multitask_group` on `convoy_events` and parallel implementer fan-out in the orchestrator ADR; this task adds **visibility**, not new scheduling logic.
### Data source
- Parse brief frontmatter / `slice_dependencies` from `.convoys/<slug>/brief-*.md` (via convoy object metadata or file reconcile)
- Overlay live status from `agent_runs` + convoy status per brief
### UI
- Mission control detail panel tab: **Graph**
- Nodes = briefs; edges = dependencies; color = run status (pending, running, done, blocked)
- Click node selects brief in detail panel
## Dependencies
- Epic 5 mission control (shipped)
- Epic 6 orchestrator parallel dispatch (shipped)
## Subtasks
- [ ] Shared zod type `ConvoyDag` in `packages/shared`
- [ ] tRPC `convoys.getDag`
- [ ] React graph component (lightweight — e.g. layered layout, no heavy graph lib unless justified)
- [ ] Empty state when single-brief convoy
## Estimation
M
## Acceptance criteria
- [ ] Two-brief convoy with dependency shows correct edge direction
- [ ] Parallel briefs without dependency appear in same column/lane
- [ ] Blocked brief visually distinct from pending
## Links
- Epic: `./Epic-mission-control-gates-ui.md`

View file

@ -7,7 +7,7 @@ status: done
priority: P1
tenant_id: global
cursor_epic_id: null
updated_at: "2026-07-03"
updated_at: "2026-08-03"
agent_prompt: |
Epic: model provider registry (docs/adr-model-routing.md). Server-only change —
no UI component library inventing; reuse components/ui/. Admin-only mutations.
@ -32,12 +32,9 @@ This epic is the first shipped piece of the automation-foundation plan and unblo
- `complete_task` optional model logging fields.
- `.env.example` env var documentation.
**Out of scope**
**Out of scope (moved to follow-on task)**
- Orchestrator dispatch (consumes resolver later).
- Worker inference loop.
- Parsing `model_policy` from `.convoys/*.md` files (orchestrator reads later).
- Billing/budget enforcement.
- Billing/budget enforcement → [Task-cost-budget-ui-and-caps](./Task-cost-budget-ui-and-caps.md)
## Related tasks
@ -47,9 +44,15 @@ This epic is the first shipped piece of the automation-foundation plan and unblo
| DB schema and migration | `./Task-db-model-providers-migration.md` |
| tRPC models router | `./Task-trpc-models-router.md` |
| Settings — providers UI | `./Task-settings-ai-providers-ui.md` |
| Settings — role routing UI | `./Task-settings-role-routing-ui.md` |
| Settings — role routing UI | `./Task-settings-ai-role-routing-ui.md` |
| agent_runs model fields + MCP | `./Task-agent-runs-model-logging.md` |
## Follow-on tasks (Autensa benchmark)
| Task | Link |
|------|------|
| Cost visibility & dispatch budget caps | [Task-cost-budget-ui-and-caps](./Task-cost-budget-ui-and-caps.md) |
## Dependencies
- Depends on: existing auth + workspace admin patterns in `apps/web`.
@ -57,11 +60,11 @@ This epic is the first shipped piece of the automation-foundation plan and unblo
## Acceptance criteria
- [ ] Admin can create `claude-planning` (anthropic) and `qwen-coder` (openai_compatible + base URL) in a workspace.
- [ ] Admin can map `role-implementer` → `qwen-coder`, `role-architect` → `claude-planning`.
- [ ] `testProvider` returns success/failure without exposing API keys.
- [ ] `resolveModel()` unit tests cover override order and missing-alias error.
- [ ] At least one task in this epic completed via `claim_task` → `complete_task` with model metadata.
- [x] Admin can create `claude-planning` (anthropic) and `qwen-coder` (openai_compatible + base URL) in a workspace.
- [x] Admin can map `role-implementer` → `qwen-coder`, `role-architect` → `claude-planning`.
- [x] `testProvider` returns success/failure without exposing API keys.
- [x] `resolveModel()` unit tests cover override order and missing-alias error.
- [x] At least one task in this epic completed via `claim_task` → `complete_task` with model metadata.
## Proposed timeline
@ -71,6 +74,7 @@ This epic is the first shipped piece of the automation-foundation plan and unblo
| API | Session 3 | tRPC router |
| UI | Session 4–5 | Both settings pages |
| Logging | Session 6 | agent_runs + MCP |
| Usage & caps | Future | Follow-on task |
## Pipeline / convoy mapping

View file

@ -0,0 +1,63 @@
---
kind: task
slug: cost-budget-ui-and-caps
title: Cost visibility and dispatch budget caps
plan_slug: automation-foundation
epic_slug: model-provider-registry
status: draft
priority: P2
tenant_id: global
owner: unassigned
cursor_todo_id: null
updated_at: "2026-08-03"
---
# Task summary
Surface spend from `convoy_events.estimated_cost_usd` and `agent_runs` token metadata; add optional workspace budget caps that pause orchestrator dispatch when exceeded.
## Description
**Benchmark:** Autensa per-task/product cost tracking and daily/monthly budget caps. Epic 1 deferred billing — this follow-on uses data already on `convoy_events` and run completion.
### Read path (UI)
- Settings → AI → **Usage & budgets**
- Rollups: today / this month by `model_alias`, by convoy, by role
- Mission control convoy detail: spend to date for selected convoy
### Write path (enforcement)
- `workspace_budget_caps` table: `period` (`daily` | `monthly`), `cap_usd`, `action` (`pause_dispatch` | `warn_only`)
- Orchestrator tick: sum `estimated_cost_usd` for period; if over cap and `pause_dispatch`, skip new `role_dispatch` enqueue and write health event
### Cost estimation
- Worker/orchestrator populate `estimated_cost_usd` on `convoy_events.role_complete` using provider-reported usage × static price table in shared config (v1 — no live pricing API)
## Dependencies
- Epic 1 model registry + `convoy_events` cost column (shipped)
- Epic 7 worker records token totals on complete
## Subtasks
- [ ] Price table stub in `packages/shared` (document as operator-editable later)
- [ ] tRPC usage queries (workspace-scoped aggregates)
- [ ] Settings usage page
- [ ] Budget cap schema + orchestrator guard
## Estimation
M
## Acceptance criteria
- [ ] Settings shows month-to-date spend grouped by model alias
- [ ] With cap set and exceeded, orchestrator logs skip reason and does not enqueue new jobs
- [ ] Warn-only cap emits event but does not block dispatch
## Links
- Epic: `./Epic-model-provider-registry.md`
- Unblocks: Epic 9 fleet spend rollup

View file

@ -6,7 +6,7 @@ status: ready
priority: P1
tenant_id: global
cursor_plan_id: null
updated_at: "2026-07-07"
updated_at: "2026-08-03"
agent_prompt: |
You are implementing Echodo's automation foundation. Read docs/adr-model-routing.md
before touching model routing code. This repo uses pnpm, Drizzle, tRPC, zod in
@ -28,7 +28,7 @@ agent_prompt: |
Echodo is evolving from a multitenant task app with MCP coordination into **mission control** for an agent pipeline: fleet view, human gates, per-role model routing, and (later) a built-in orchestrator and worker. This plan delivers the **first concrete slice** — the model provider registry and role routing system defined in [docs/adr-model-routing.md](../../docs/adr-model-routing.md).
Later epics in this plan (2–9) add convoy scaffolding, connected repos, lifecycle MCP, gates UI, orchestrator, worker, webhooks, and fleet dashboard. Epic 1 gives them a stable `resolveModel()` contract.
Epics 1–6 and the mission-control UI are **shipped**. Epic 7 (worker) is **in progress** — skeleton exists in `apps/worker`. Epics 8–9 remain draft with decomposed tasks. Follow-on tasks from the [Autensa benchmark](#autensa-benchmark-2026-08) are injected into epics 1, 3, 5, 6, 7, 8, and 9 (concepts only — no OpenClaw dependency).
## Dogfooding the agent pipeline
@ -115,7 +115,8 @@ Start with **`Task-shared-schemas-resolve-model`** — no DB migration, pure `pa
**In scope (full plan)**
- Nine epics — see [Epic roadmap](#epic-roadmap-complete) below.
- Epic 1 (model registry) is **ready** with six tasks; epics 2–9 are **draft** stubs for architect decomposition.
- Epics 1–6 **done**; Epic 7 **in progress**; Epics 8–9 **draft** with bead-scale tasks.
- [Autensa benchmark](#autensa-benchmark-2026-08) follow-ons: reliability (checkpoints, auto-nudge), operator UX (activity feed, DAG, PR recovery), cost caps.
- ADR at `docs/adr-model-routing.md`.
**Out of scope (separate future plans)**
@ -133,7 +134,7 @@ Start with **`Task-shared-schemas-resolve-model`** — no DB migration, pure `pa
## Epic roadmap (complete)
Sequential order with parallel opportunities noted. Only **Epic 1** has bead-scale tasks today; epics 2–9 are draft stubs ready for architect decomposition when the prior epic lands.
Sequential order with parallel opportunities noted. **Current focus: Epic 7** (worker end-to-end dogfood), then Epic 8 → 9. Follow-on tasks on done epics can run in parallel when they do not block the critical path.
```mermaid
flowchart LR
@ -162,15 +163,15 @@ flowchart LR
| # | Epic | Status | Delivers | Depends on |
|---|------|--------|----------|------------|
| 1 | [Model provider registry](./Epic-model-provider-registry/Epic-model-provider-registry.md) | **ready** (6 tasks) | `resolveModel()`, Settings AI pages, run model logging | — |
| 1 | [Model provider registry](./Epic-model-provider-registry/Epic-model-provider-registry.md) | done (+1 follow-on) | `resolveModel()`, Settings AI pages, run model logging; cost caps task | — |
| 2 | [Pipeline convoy scaffolding](./Epic-pipeline-convoy-scaffolding/Epic-pipeline-convoy-scaffolding.md) | done | `.convoys/`, `log-convoy-event.sh`, `convoy-planning.mdc` — dogfood metrics | — (parallel with 1) |
| 3 | [Connected repos](./Epic-connected-repos/Epic-connected-repos.md) | done | `repo_links` table, “paste remote URL”, forge adapter interface | — |
| 3 | [Connected repos](./Epic-connected-repos/Epic-connected-repos.md) | done (+1 follow-on) | `repo_links` table, paste URL, forge adapters; repo setup preflight | — |
| 4 | [Convoy lifecycle MCP](./Epic-convoy-lifecycle-mcp/Epic-convoy-lifecycle-mcp.md) | done | `create_convoy`, `transition_convoy_status`, state machine §7, `convoy_events` | 2, 3 |
| 5 | [Mission control gates UI](./Epic-mission-control-gates-ui/Epic-mission-control-gates-ui.md) | done | Convoy kanban, gate inbox, approve/deny/revise, gate co-pilot chat | 4 |
| 6 | [Orchestrator](./Epic-apps-orchestrator/Epic-apps-orchestrator.md) | done | `apps/orchestrator`, Redis queue, role dispatch, pause at gates | 1, 3, 4 |
| 7 | [Worker v1](./Epic-apps-worker-v1/Epic-apps-worker-v1.md) | draft | `apps/worker` minimal tool loop, worktree-per-brief, MCP claim/complete | 1, 3, 6 |
| 8 | [Forge webhooks](./Epic-forge-webhooks/Epic-forge-webhooks.md) | draft | PR opened/merged/CI webhooks → convoy transitions | 3, 4, 7 |
| 9 | [Fleet dashboard](./Epic-fleet-dashboard/Epic-fleet-dashboard.md) | draft | Cross-repo home, `convoys-*` workspaces, “needs you” rollup | 4, 5 |
| 5 | [Mission control gates UI](./Epic-mission-control-gates-ui/Epic-mission-control-gates-ui.md) | done (+2 follow-ons) | Kanban, gate inbox, co-pilot; DAG viz + automation tiers | 4 |
| 6 | [Orchestrator](./Epic-apps-orchestrator/Epic-apps-orchestrator.md) | done (+1 follow-on) | `apps/orchestrator`, Redis queue, role dispatch; auto-nudge | 1, 3, 4 |
| 7 | [Worker v1](./Epic-apps-worker-v1/Epic-apps-worker-v1.md) | **in progress** (3 tasks) | Tool loop, checkpoints, operator notes | 1, 3, 6 |
| 8 | [Forge webhooks](./Epic-forge-webhooks/Epic-forge-webhooks.md) | draft (2 tasks) | Webhooks + PR checks recovery panel | 3, 4, 7 |
| 9 | [Fleet dashboard](./Epic-fleet-dashboard/Epic-fleet-dashboard.md) | draft (2 tasks) | Cross-repo rollup + SSE activity feed | 4, 5 |
### Overlap with existing plans
@ -183,7 +184,26 @@ flowchart LR
### End-state (what “done” looks like for the full plan)
Operator opens Echodo fleet view → starts convoy chat → hits **Go** → orchestrator runs pipeline roles with per-role models → worker executes briefs against connected repos → gates surface in inbox with AI co-pilot → approve → repeat until `released`.
Operator opens Echodo fleet view → starts convoy chat → hits **Go** → orchestrator runs pipeline roles with per-role models → worker executes briefs against connected repos → gates surface in inbox with AI co-pilot → approve → repeat until `released`. Live activity feed, spend rollups, and PR recovery are visible without leaving mission control.
### Autensa benchmark (2026-08)
Studied [crshdn/mission-control](https://github.com/crshdn/mission-control) (Autensa) as a UX/reliability benchmark — **not** as a runtime dependency. Ideas mapped to tasks:
| Autensa concept | Echodo task | Epic |
|-----------------|-------------|------|
| Checkpoint & crash recovery | [Task-worker-checkpoint-resume](./Epic-apps-worker-v1/Task-worker-checkpoint-resume.md) | 7 |
| Operator chat mid-build | [Task-worker-operator-notes](./Epic-apps-worker-v1/Task-worker-operator-notes.md) | 7 |
| Agent health / auto-nudge | [Task-orchestrator-auto-nudge](./Epic-apps-orchestrator/Task-orchestrator-auto-nudge.md) | 6 |
| Repo setup preflight | [Task-repo-setup-preflight](./Epic-connected-repos/Task-repo-setup-preflight.md) | 3 |
| PR checks recovery | [Task-pr-checks-recovery-panel](./Epic-forge-webhooks/Task-pr-checks-recovery-panel.md) | 8 |
| Convoy DAG visualization | [Task-convoy-dag-visualization](./Epic-mission-control-gates-ui/Task-convoy-dag-visualization.md) | 5 |
| Automation tiers | [Task-automation-tiers](./Epic-mission-control-gates-ui/Task-automation-tiers.md) | 5 |
| Cost tracking & budget caps | [Task-cost-budget-ui-and-caps](./Epic-model-provider-registry/Task-cost-budget-ui-and-caps.md) | 1 |
| Live activity feed (SSE) | [Task-convoy-activity-feed-sse](./Epic-fleet-dashboard/Task-convoy-activity-feed-sse.md) | 9 |
| Fleet rollup | [Task-fleet-rollup-dashboard](./Epic-fleet-dashboard/Task-fleet-rollup-dashboard.md) | 9 |
**Explicitly not adopted:** OpenClaw Gateway, autopilot research/ideation/swipe, preference learning, agent skills learner, SQLite single-tenant model.
## Epics (links)
@ -212,6 +232,20 @@ Operator opens Echodo fleet view → starts convoy chat → hits **Go** → orch
| M6 Automation | 6–7 | Orchestrator dispatches one implementer brief unattended |
| M7 PR loop | 8 | Merge webhook moves convoy to `merged` |
| M8 Fleet | 9 | Single view across ≥2 connected repos |
| M9 Reliability | 7 | Worker completes brief; checkpoint resume after kill |
| M10 Observability | 9 | Activity feed shows role_complete without refresh |
| M11 Spend control | 1 follow-on | Month-to-date spend + dispatch pause on cap |
## Recommended execution order (post-benchmark)
1. **Epic 7 critical path** — [Task-worker-minimal-tool-loop](./Epic-apps-worker-v1/Task-worker-minimal-tool-loop.md) → live dogfood with orchestrator
2. **Epic 7 reliability** — checkpoint/resume, then operator notes
3. **Epic 8** — webhook receiver → PR checks panel (needs worker PR output)
4. **Epic 6 follow-on** — auto-nudge (pairs with checkpoints)
5. **Epic 3 follow-on** — repo preflight (before unattended prod dogfood)
6. **Epic 9** — fleet rollup → SSE feed
7. **Epic 5 follow-ons** — DAG viz, automation tiers (after Epic 8 for semi-auto)
8. **Epic 1 follow-on** — cost caps (after worker records token totals)
## Risks and mitigations