Do not abort the entrypoint when the shared volume is not writable; log a
warning and continue so the worker can still start.
Co-authored-by: Cursor <cursoragent@cursor.com>
- Added Phase 5: ACP Harness & Runtime Agnosticism to roadmap
- Created docker/docker-compose.agent-server.yml for CT 102 deployment
- Updated worker default AGENT_SERVER_URL to internal Docker DNS (http://agent-server:8001)
- Worker now runs OpenHands sessions directly on the server, no laptop/Traefik needed
- Extract WorkerExecutorOptions from inline type in shared executor
- Use WorkerExecutorOptions throughout remote-ag-ui.ts and index.ts
instead of loose any types
- Extend WorkerExecutor.run return to include outcome
- Add 8 test cases in executor.test.ts covering:
- Registry dispatch for all harness types
- Missing config returns null
- Auth token missing returns failed
- POST + poll roundtrip behavior
Replaces the hardcoded createMinimalSession in handle-job.ts with a registry
lookup via getExecutor(harnessConfig). The 'minimal' harness still wraps
createMinimalSession; 'remote-ag-ui' POSTs the task payload to a remote agent
endpoint (OpenHands / Open Code / etc.) and polls for completion.
Worker-side completion of Brief 3 (harness-registry-adapter). Pairs with the
already-built AG-UI inbound route at /api/ag-ui/[workspace] and the
harness_providers / role_harness_routes tables.
Add epics 10–12 (plans UI, completion artifacts, ops copilot), worker
draft-PR and live E2E verify tasks, and phase A–E execution order after
A1 gap review.
Co-authored-by: Cursor <cursoragent@cursor.com>
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>
Introduce public /landing and /pricing pages for the SBMTR brand with
bento features, convoy product demo, motion reveals, and scoped marketing
tokens. Unauthenticated visitors route to the landing page.
Co-authored-by: Cursor <cursoragent@cursor.com>
Avoid Coolify OOM crashes by documenting and scripting sequential service builds, and make Docker builds resilient to local-only .env symlinks and missing .cursor agent paths.
Co-authored-by: Cursor <cursoragent@cursor.com>
Disable inherited incremental compilation for tsup DTS in orchestrator and worker, and align Dockerfile entrypoints with dist/index.js output.
Co-authored-by: Cursor <cursoragent@cursor.com>
Inlining yaml into the MCP ESM bundle caused dynamic require("process") crashes in production. Externalize yaml for mcp-server, orchestrator, and worker builds.
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(worker): minimal agent runtime for orchestrator jobs (Epic 7)
Adds apps/worker to consume Redis dispatch jobs, run a tool loop with model registry resolution, and record claim/complete + convoy role_complete events.
Co-authored-by: Cursor <cursoragent@cursor.com>
* chore(deploy): add orchestrator and worker to Coolify compose
Fix CI pnpm setup conflict and ship Docker targets for the automation stack alongside web/collab/mcp.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Adds mission control UI with human gate actions via tRPC, kanban columns from
the shared lifecycle enum, and gate co-pilot using resolveModel('gate-copilot').
Co-authored-by: Cursor <cursoragent@cursor.com>
Workspace admins connect git remotes via settings UI; forge type is inferred
from the URL, API tokens stay env-var references, and test connection fetches
default branch for orchestrator/worker consumers.
Co-authored-by: Cursor <cursoragent@cursor.com>
Installs .convoys/README.md, log-convoy-event.sh, convoy-planning Cursor rule,
and gitignored metrics JSONL. Documents Echodo dogfood kickoff and adds a
shipped convoy record for Epic 1 model provider registry.
Co-authored-by: Cursor <cursoragent@cursor.com>
Webpack resolves workspace packages without Node ESM .js suffixes; extensionless
paths match the rest of packages/shared and fix middleware build failures.
Co-authored-by: Cursor <cursoragent@cursor.com>
Adds ai.models tRPC router with provider CRUD, role routes, testProvider, and
resolveForRole; Vercel AI SDK client factory in packages/ai; Settings pages
for providers and role routing; agent_runs model metadata columns with MCP
complete_task fields and runs UI column.
Co-authored-by: Cursor <cursoragent@cursor.com>
Implements Epic 1 task 1 per docs/adr-model-routing.md: zod schemas for
providers and role routes, pipeline default aliases, legacy Cursor slug map,
and a pure resolveModel() with brief → convoy → workspace → default order.
Co-authored-by: Cursor <cursoragent@cursor.com>
Documents the automation foundation plan (nine epics, Epic 1 taskified) and
the accepted model-provider registry contract. Updates .env.example for backlog
import workspace id and local/cloud AI provider env guidance.
Co-authored-by: Cursor <cursoragent@cursor.com>
Coolify's builder fails the build at parse time with:
"cannot copy from stage 'collab-build', it needs to be defined before
current stage 'web-build'"
The previous commit introduced forward COPY --from references that work
on newer BuildKit DAG builders but not on the legacy Docker builder
Coolify uses. Move `collab-build` and `mcp-build` above `web-build` in
lexical order so the references resolve. Functionally identical — the
DAG ordering effect is the same — just expressed in a way the older
builder accepts.
Added a NOTE comment above the stages so the next person who tries to
"clean up" the file order doesn't reintroduce the same regression.
Co-authored-by: Cursor <cursoragent@cursor.com>
Coolify deploys were failing with exit 255 (kernel OOM, no Docker error)
around the 73s mark of `next build`. Root cause: docker/Dockerfile's three
build stages (web-build, collab-build, mcp-build) all `FROM deps`, and
BuildKit was running them in parallel. The web-build alone wants ~3 GB
heap (capped at 5120 MB) and was racing tsup workers + buildkit + dockerd
on an 8 GB host until the kernel reaped it.
docker-compose.coolify.yml already had a comment claiming `depends_on:
[collab, mcp]` on `web` would serialize the builds. It doesn't —
`depends_on` only orders runtime startup, not `docker compose build`.
Fix: enforce ordering inside the Dockerfile DAG by COPYing one trivial
artifact from each lighter stage into web-build. BuildKit now waits for
collab-build and mcp-build to finish before starting the heavy Next.js
compile, which then gets the host effectively to itself. The copied
files land in /tmp and are never read by the runtime web image.
Also updated the compose comment to reflect the new (and accurate)
ordering mechanism.
Co-authored-by: Cursor <cursoragent@cursor.com>
The Create Workspace button in the top-header dropdown was still calling
`window.alert("Create workspace (placeholder)")` instead of opening the
real CreateWorkspaceDialog. Wires it to the same dialog the sidebar
workspace switcher uses.
Also clarifies in .env.example and AGENTS.md that the canonical Postgres
database name is `echodo` everywhere (local, Coolify, drizzle ledger,
docker-compose POSTGRES_DB). A stale `tasks` database on CT 102 from the
pre-rename era was the root cause of the 2026-06 Authentik "Configuration"
SSO outage: Coolify correctly pointed at `echodo` (which was empty), while
the only initialized schema lived in the relic `tasks` DB.
Co-authored-by: Cursor <cursoragent@cursor.com>
Written by the exporter itself during the dogfood run — final dogfood
evidence that the two-way sync loop closes correctly. See run
0bace0aa-ef6e-4aca-a041-e7f2343ba854 in agent_runs for the trail.
Co-authored-by: Cursor <cursoragent@cursor.com>
Until now the markdown importer was one-way (plans/*.md → DB). Any
agent-driven status flip via claim_task / complete_task would be
clobbered on the next importer sweep. This change closes the loop: the
DB now projects status, priority, agent_prompt, and updated_at back
into the file's frontmatter, preserving body bytes, key order, and
every other frontmatter key.
New: packages/database/src/markdown-backlog/export.ts
- `rewriteFrontmatter()` — pure function, covered by 10 Vitest cases
(round-trip identity, status flip, priority flip, agent_prompt
null/block-scalar/single-line variants, body preservation,
trailing-newline preservation, idempotent re-application).
- `exportBacklogItemToMarkdown()` — DB-loading wrapper with atomic
write (tmp + rename) and tenant fencing. Returns a structured
result so callers can surface what happened in their response.
Wired into:
- `claim_task` MCP tool — exports on the ready → in_progress flip.
- `complete_task` MCP tool — exports on any finalStatus transition.
- `backlog.updateWorkflowPrompt` tRPC mutation — exports on prompt
edits made through the app UI.
Robust repo-root resolution (`apps/{mcp-server,web}/src/lib/repo-root.ts`,
plus a copy in `import-markdown-backlog.ts`): walk up from the source
file looking for `pnpm-workspace.yaml`, falling back to env var or cwd.
This fixes a class of bug where `pnpm --filter <pkg>` cd's into the
package directory and breaks naive cwd-based path resolution — the
importer was deleting all 44 rows during smoke testing before this fix
because it found zero files in `packages/database/plans/`.
`config/CursorSync.md`: documents the new two-way contract, the
DB-wins-on-allow-list conflict policy, and the
MARKDOWN_BACKLOG_REPO_ROOT=off escape hatch for production deployments
where `plans/` isn't checked out.
Smoke verified end-to-end against the homelab DB: claim flips file
status to in_progress, complete flips it back to ready, importer
round-trips with stable content_hash (true no-op), agent identity
preserved throughout.
Co-authored-by: Cursor <cursoragent@cursor.com>
Adds level-B agent attribution: every MCP tool call can identify itself
with a `client` (e.g. cursor-ide, codex, echodo-orchestrator) and `model`
(e.g. claude-4.6-sonnet) string. Both optional, both stored in
agent_runs.metadata as JSONB so the schema doesn't move.
- claim_task: new optional `client` + `model` args. Written into the
inserted agent_runs row's metadata, and mirrored into the audit log
entry. On idempotent re-claim, incoming values are merged into
existing metadata (existing keys override only when explicit), so a
mid-session model switch updates attribution without losing earlier
context.
- complete_task: same optional args, with merge-on-close semantics —
late-bound values override the earlier claim's values so the run row
reflects whichever model actually closed the session. Audit row also
carries the merged identity.
- /settings/runs UI: stack the client/model under the actor name in the
table so attribution is visible at a glance without adding a column.
Smoke-tested: claim with {cursor-ide, claude-4.6-sonnet} then complete
with only model={claude-4.6-sonnet-medium-thinking} yields final
metadata {client: cursor-ide, model: claude-4.6-sonnet-medium-thinking}
on both the run row and the task.completed audit entry.
Co-authored-by: Cursor <cursoragent@cursor.com>