diff --git a/host/skills/corral-api/SKILL.md b/host/skills/corral-api/SKILL.md index 01eed76..9974438 100644 --- a/host/skills/corral-api/SKILL.md +++ b/host/skills/corral-api/SKILL.md @@ -73,6 +73,43 @@ break the ask into tasks, kick off a worker per task, and keep going. running it inline. - Put ALL context the worker needs in `prompt` (it starts fresh in a neutral dir). - Give a short, human `title` — it's the worker's tab label. + +### CODE TASKS RUN IN A SANDBOX — the worker creates a project, it does NOT edit code on the host + +The architecture is **Conductor → Worker → Sandbox project** (which has its own +Claude). A worker runs **on the host and is NOT sandboxed** — so a worker must +**never write, run, or test a repo's code directly**. That would touch the +operator's real checkout with no isolation. Instead, a worker whose task is code +work is an *orchestrator*: it **creates a sandbox project and hands the actual +work to that project's own Claude** via the auto-submitted `prompt`. + +**If the task is a code task** — implement a feature, fix a bug, work a GitHub +issue, write/run/debug tests, get an app running, anything that edits or executes +a repo's code — the worker's job is to spin up the sandbox, not to do the coding: + +``` +# The worker (or you, when kicking one off) creates the sandbox and passes the +# real task as the sandbox's first prompt — that sandbox's Claude does the work. +corral api POST /projects/create -d '{ + "repoId": "", # from GET /repos (or "repos":[…] for multi-repo) + "branch": "", # optional; defaults to the repo default branch + "prompt": "" +}' +# → { "id": "", ... } — a sandbox is now running Claude on the task +``` + +So the usual shape for a code request is: **conductor** spawns a **worker** whose +prompt says "create a sandbox project for repo X on this task and drive it to +done"; the **worker** calls `POST /projects/create` (with the coding task as the +project `prompt`); the **sandbox project's Claude** does the isolated code work. +The worker then supervises — polls `GET /status` for that project, reads its +conversation (`GET /api/conversations?origin=sandbox&project=`), steers or +restarts it if needed — but the edits/builds/tests happen **inside the sandbox**. + +**Only skip the sandbox for NON-code work** — inspecting Corral state, reading +logs/PRs, running flows, triage/analysis, orchestration. Those are fine to do on +the host (in the worker or inline). When in doubt about whether a task will touch +a repo's code: route it through a sandbox project. - Workers, like merge jobs, are listed by `GET /merge-jobs`, streamed at `/merge-jobs//ws`, and removed with `DELETE /merge-jobs/`. - Workers run on the HOST and are **not sandboxed**; they use the operator's diff --git a/internal/dashboard/conductor_workers.go b/internal/dashboard/conductor_workers.go index 6783eff..e0697d1 100644 --- a/internal/dashboard/conductor_workers.go +++ b/internal/dashboard/conductor_workers.go @@ -45,6 +45,17 @@ func workerContractPreamble(jobID string) string { "no human at you to answer one. Use ONLY your granted tools: Read/Grep/Glob, plus Bash and " + "Monitor when you have act capability. Those cover waiting/polling; do not reach for an " + "ungranted tool, which would block on approval and strand you.\n" + + "CODE WORK GOES IN A SANDBOX, NOT ON THE HOST: if your task involves writing, running, " + + "building, or testing a repo's code (implementing a feature, fixing a bug, working an issue, " + + "getting an app running, or exploring code to plan such a change), do NOT edit or run that code " + + "here on the host. Instead CREATE A SANDBOX PROJECT and hand the actual work to its own Claude: " + + "`corral api POST /projects/create -d '{\"repoId\":\"\",\"prompt\":\"\"}'` " + + "(the project `prompt` is auto-submitted to the sandbox's Claude). Then supervise it — poll " + + "`corral api GET /status` and read its conversation " + + "(`corral api GET \"/api/conversations?origin=sandbox&project=\"`), steering or restarting if " + + "needed. You are the orchestrator; the edits/builds/tests happen inside the sandbox. Only pure " + + "host/orchestration work (inspecting Corral state, reading logs/PRs, running flows, analysis) " + + "stays on the host.\n" + "Two valid ways to handle a long step (image pull/transfer, build, install):\n" + " (a) BLOCK on it in-turn — run it in the foreground, or poll with Bash " + "(`until …; do sleep N; done`) / Monitor, then proceed once it's done.\n" +