| name | sandboxed-sh-missions |
| description | Delegate coding/automation tasks to sandboxed.sh missions via the mcp_sandboxed_assistant_* MCP. Each mission runs in an isolated container (workspace) with a chosen agent profile and a self-contained prompt. Use this skill whenever the user wants to 'launch a mission', 'sandboxed', 'spawn a worker', or delegate a multi-step coding/research task that should run in a clean environment. |
| license | MIT |
| metadata | {"hermes":{"tags":["Sandboxed","Missions","MCP","Coding-Agent","Delegation","Isolation","Workspace"],"related_skills":["ai-coding-agents","github-workflow"]}} |
Sandboxed.sh Missions
Delegate coding/automation tasks to isolated containerised missions via the mcp_sandboxed_assistant_* MCP. Each mission runs in a chosen workspace (a fresh container with a known set of init scripts and pre-installed tools) and executes the prompt autonomously via a configured agent. Intermediate tool calls stay in the mission's own context.
A conversational start_mission is a worker of this chat. Hermes stamps origin_session_id, enrolls the mission, and the terminal webhook folds the result back here. End the turn after dispatch — do not poll, and do not invent a cron just to wait. Controller/cron ticks are different: they pass project and report on the next tick / project route.
When dispatching against a project roadmap, also pass the declared track,
its acceptance_criteria, and a stable retry-safe idempotency_key. The
server reserves the track owner and links the mission as one durable intent;
reusing the key returns the original launch instead of duplicating work.
Mission completion alone does not satisfy the track. Accepted criterion
evidence at the governed artifact version must be recorded separately.
This is not the same as delegating to a CLI coding agent (Claude Code, Codex, OpenCode) via the terminal tool. The MCP runs an entire conversation loop inside the container; the CLI agents are interactive programs you spawn in a single terminal() call. Use this skill for isolated multi-step research/coding, or work that needs a specific pre-baked workspace (e.g. tailscale-ubuntu, minecraft, dgx-spark).
When to use
- User says "lance une mission", "sandboxed", "spawn a worker", "delegate to a coder in a clean room".
- Task is non-trivial: a project to scaffold, a refactor, a test suite, a multi-file code review.
- You want isolation: the work must not touch the host's working state, dependencies, or secrets.
- The task benefits from a specific workspace's pre-installed tools (Python/uv, Node/bun, gh CLI, Tailscale, etc.).
When NOT to use:
- Single trivial edit →
patch / write_file is faster and cheaper.
- Task needs back-and-forth with the user → subagents can't use
clarify.
- You need a long-running daemon → use
cronjob or terminal(background=true) instead. Missions terminate when the agent emits its final message.
- Task is purely a tool call with no reasoning →
execute_code is more direct.
The MCP surface
| Tool | Purpose |
|---|
mcp_sandboxed_assistant_list_workspaces | List all workspaces (containers) you can target. |
mcp_sandboxed_assistant_start_mission | Launch a new mission: pick workspace + agent + prompt. |
mcp_sandboxed_assistant_get_mission | Fetch a mission's current status and metadata. |
mcp_sandboxed_assistant_get_mission_events | Read transcript/trace of what the agent did. |
mcp_sandboxed_assistant_list_missions | List recent missions (optionally filtered by status). |
mcp_sandboxed_assistant_list_active_missions | Only the in-flight ones (pending/active/blocked/awaiting-user). |
mcp_sandboxed_assistant_send_message_to_mission | Resume a mission with a follow-up prompt (for awaiting_user missions). |
mcp_sandboxed_assistant_cancel_mission | Stop a mission. Returns "not found" if the mission is already gone — that's normal. |
Terminology: backend, workspace, host, and remote node are different layers
When a user asks which “servers/backends” sandboxed.sh uses, answer by layer instead of conflating them:
- Control-plane host — runs sandboxed.sh production and orchestrates mission state.
- Workspace — container/host execution environment selected by
workspace_id; examples include project workspaces and the dedicated dgx-spark workspace.
- LLM backend — the
backend field (codex, claudecode, opencode, gemini, grok); this selects the agent/model transport, not a physical machine.
- Remote node/build worker — extra compute reached through sandboxed-node or
/api/remote-build; current documented general runners are babylon, nippur, and ashur, while the Lean build fleet also includes dgx-spark.
- Adjacent runner — e.g. a GitHub Actions self-hosted runner. This is not automatically a sandboxed.sh remote node even if it runs on the same machine.
For inventory questions, report all SSH-reachable machines separately from the subset registered as sandboxed.sh compute. Date any “currently deployed” claim unless live state was checked via GET /api/remote-nodes and GET /api/health/fleet.
Production DGX routing incident rule. If disk-sentinel reports only dgx-spark unreachable, check systemctl is-enabled tailscaled, systemctl is-active tailscaled, and tailscale ping -c 2 100.77.4.93 on agent-core before changing keys or topology. The expected recovery is systemctl enable --now tailscaled, followed by strict-host-key SSH and a silent sentinel run. Do not recreate an old-agent tunnel: old-agent is compute-only.
Picking the agent
The agent field is one of the agent names registered on the platform. The two universal agents are build and plan. Some setups also offer ana (audit) and paloma (coordinator), but availability varies per installation and workspace — do NOT assume all four are available. The right one depends on the work:
build — general implementation agent. Use for "build this project", "scaffold this repo", "implement feature X". Default for coding tasks.
plan — research/planning agent. Use for "investigate options", "draft an architecture", "compare libraries", "write a draft", "research and summarize". No code (or minimal code). Default for research/article/analysis tasks.
ana — analytical/audit agent. May not be available — check first or use build if you just need code review.
paloma — coordinator/operator agent. May not be available.
Pitfall — agent availability and naming vary by deployment. agent is a registered platform profile and backend selects the execution backend; they are logically separate, but current deployments may register backend-aligned agent IDs such as codex in addition to profiles such as build and plan. Do not hard-code a universal agent list. Use the live tool schema/catalog or a previously verified route. For Codex, always set backend="codex" and the exact OpenAI model ID in model_override; use the deployment's accepted agent profile (codex, build, or plan) and verify the created mission records the requested agent, backend, model_override, and model_effort. A mission merely reaching pending is not enough—re-read it after startup and require execution evidence before calling the route healthy.
The backend parameter (opencode, claudecode, codex, gemini, grok) selects the LLM backend, not the agent — this is the underlying model the agent uses.
User-mandated model runs: bound, verify, then independently gate
When the user explicitly requests a particular non-default model, honor the request with the exact backend/model identifier and verify the created mission records that identifier plus an active status shortly after dispatch. Treat that worker as a bounded implementation or investigation lane, not as the sole merge or architecture authority:
- Give it a concrete scope, reproduction/validation criteria, and explicit no-go boundaries (for example: no merge, no legal attestation, no secrets).
- Require it to distinguish source evidence from assumptions and return verifiable handles for every external change.
- Independently verify pushed commits, tests, PR state, and any production claim before reporting success.
- Route material architecture decisions or merge readiness through the normal stronger/latest-head review gate unless the user explicitly waives it.
This keeps a user-requested model useful without converting its self-report into an unverified operational decision.
Codex /goal objective length limit
Codex goal mode has a strict objective-size limit: if the prompt starts with /goal and the objective is too long, the mission can immediately fail with:
codex thread/goal/set failed: goal objective must be at most 4000 characters
Recovery pattern:
- Keep
/goal itself short (under ~3500 characters to leave margin).
- Put only the durable objective, constraints, and final-output schema in the
/goal text.
- Move bulky context into linked repo docs, a branch issue, project files, or a follow-up non-goal prompt if the platform supports it.
- Relaunch a fresh mission with the shortened
/goal; do not keep retrying the same oversized objective.
This limit is separate from model context size. A model can handle the information, but the Codex goal API rejects overlong goal objectives before execution starts.
Backend tiering for cost optimisation (multi-provider routing)
The opencode backend is the universal router — it can target ANY provider model via model_override, including non-OpenAI/Anthropic providers that the other backends can't reach (Z.AI GLM, Minimax, Kimi/Moonshot, Cerebras, Spark, Virtuals). The other backends (claudecode, codex, gemini, grok) are locked to their respective providers.
This enables a cost-tiering strategy when the user has "unlimited" quota on alternative providers:
| Tier | Backends | Use for |
|---|
| Premium (subscription-limited) | codex (approved GPT-5.6 Terra/Sol routes), claudecode (current approved Claude route) | Critical code, hard proofs, deep reasoning — tokens are scarce, use them where they matter |
| Alternative (often unlimited) | opencode + model_override=glm-5.2 / MiniMax-M3 / moonshotai-kimi-k2-7-code | Research, article drafting, investigation, documentation — tasks that benefit from a model but don't need frontier-tier reasoning |
How to dispatch on an alternative provider:
mcp_sandboxed_assistant_start_mission(
agent="plan",
backend="opencode",
model_override="glm-5.2",
...
)
Discovering available providers and their model IDs:
Fable 5.1 via claudecode only. Virtuals is deprecated and no longer available. For demanding reasoning and long-horizon agentic work, launch via backend="claudecode" with the exact catalog ID model_override="claude-fable-5-1". The older claude-fable-5 remains available only for explicit compatibility. Do NOT use opencode + virtuals/claude-fable-5-1 — Virtuals has been removed from the provider catalog.
Model ID gotchas:
- Z.AI:
glm-5.2, glm-5.1, glm-5-turbo (lowercase, hyphenated)
- Minimax:
MiniMax-M3, MiniMax-M2.7 (camelCase as in catalog)
- Kimi:
moonshotai-kimi-k2-7-code (not bare kimi-k2.7)
- If
model_override fails, the error message lists valid IDs — copy from there
User-mandated model that produces no output: do not silently replace it with another model and present the substitute as its opinion. Retry once with a sharply bounded, direct-output prompt (for example: no tools/web, explicit word cap and output schema). If the same model again reaches an idle/stall timeout without content, report that it was successfully addressed but returned no usable answer, then synthesize only from workers that actually produced output. Preserve the distinction between provider failure and research conclusions.
The routing mental model: opencode is a superset of the provider surface. If a provider's use_for_backends includes opencode, you can route to it. If it only lists a specialised backend (e.g. codex for OpenAI), you MUST use that backend and cannot reach it via opencode.
Pitfall — model_override needs the exact catalog ID. To override which LLM a backend uses, pass model_override — but it must match the provider's catalog ID exactly. Anthropic uses claude-<family>-<ver> with hyphens, not the shorthand leaderboard name: claude-opus-4-8 ✅, NOT opus-4.8 ❌ (the leaderboard/website may call it "opus-4.8", but the API catalog does not). If you get Model 'X' not found in <provider> catalog, the error message lists every valid ID — copy the exact string from there. Other providers (OpenAI, etc.) generally accept their public model names directly.
Pitfall — model_effort caps differ per backend and may change by model/backend version. The model_effort field accepts low/medium/high/xhigh/max, but not all backends honor all values. Historically codex rejected "max"; recent codex + gpt-5.5 missions have accepted "xhigh" and moved to active successfully. If a user explicitly requests codex + xhigh, pass it through and verify the mission status immediately with get_mission / list_active_missions. If launch fails with an effort-related error, drop one level ("max" → "xhigh" → "high") until accepted. When no model/effort is specified, "high" remains the safest cross-backend default.
Pitfall — opencode backend can crash on non-standard model_override values with ProviderModelNotFoundError. Seen in the Beal campaign (June 2026): launching opencode with model_override="glm-5.2" or model_override="MiniMax-M3" (passed as if they were model IDs) returned awaiting_user status with ProviderModelNotFoundError. The opencode routing treats the override as a provider identifier for some configurations, not a model name, even though the same model_override is documented to work as a model name in other contexts. Workaround: use an approved reliable route for critical work (for Verity: codex + gpt-5.6-terra), and always verify the dispatch succeeded by checking get_mission status within 30s. If it is terminal before repo work, do not treat it as a model result or burn a cache build on a doomed mission.
Pitfall — a shared OpenCode adapter crash is an infrastructure incident, not three independent bad-model results. A launch can pass creation, run the one-time OpenCode database migration, then terminate before any repository command with fn3 is not a function (observed identically for glm-5.2 and MiniMax-M3). When two or more alternative-provider scopes fail at that same initialization boundary: (1) classify them as failed transport attempts with no proof/review evidence; (2) stop further OpenCode launches rather than serially burning surplus quota; (3) start exactly one bounded sandboxed-sh-dev repair mission on a reliable route, requiring an alternative-override regression test and a PR; and (4) keep critical work moving only on approved reliable routes, respecting Codex OAuth launch staggering. After the fix is merged/deployed, validate with one narrow no-push alternative-provider probe before relaunching deferred workers.
Picking the workspace
list_workspaces returns the full set. The right choice depends on what tools the task needs. Key workspace properties to check:
init_scripts — e.g. base, uv-python, bun-mcp, github-cli, tailscale, browser-x11. These are the only things pre-installed.
mcps — additional MCPs the agent gets in-container (e.g. google-calendar, orchestrator).
env_vars — secrets/tokens injected at start (e.g. GH_TOKEN, GOOGLE_OAUTH_CREDENTIALS).
tailscale_mode — if you need network reach through the tailnet.
status — ready is what you want; pending means the container hasn't been started yet and may take minutes to initialise.
Secret-safe workspace discovery. Treat a workspace record as potentially secret-bearing, even for a read-only REST lookup: some control-plane responses can include env_vars values rather than just their names. For selection, reduce the response at the source to only id, name, status, init_scripts, skills, and an array of environment-variable names. Never print or retain the env_vars map. If an inspection nevertheless exposes a credential-like value, stop expanding that output, do not copy it into prompts/reports/other calls, and report only the exposure class and endpoint to the security owner for normal rotation/remediation.
Backend-specific workspace-visibility canary
A mission record carrying workspace_id / workspace_name does not prove that its selected backend sees the intended workspace mount or project checkout. This matters for MCP canaries: one backend can reach the project while another starts in an isolated empty mission directory.
Before declaring a workspace-dependent canary successful, require all of:
- the expected checkout/project path exists in that mission's execution scope;
- its Git ref and project pin (
lean-toolchain, when relevant) can be read there;
- an actual registered MCP tool resolves a file from that checkout, not merely that its tool name is callable.
If the route sees only an ephemeral mission directory and MCP calls report project/file-not-found, classify it as a workspace-mount/configuration defect, not a Lean or MCP semantic failure. Keep the canary read-only and retain only concise path/tool-result evidence. When authorized, dispatch at most one bounded no-deploy control-plane repair on a reliable route; require a regression covering backend mount/project-path propagation and prohibit it from modifying the target workspace, checkouts, credentials, or permissions. Re-run the canary only after the repair is independently verified.
Stored GitHub auth may not appear in workspace env_vars
A workspace inventory with no GH_TOKEN / GITHUB_TOKEN does not by itself prove authenticated GitHub access is unavailable: it may have valid stored gh and git credentials. Before recording an auth blocker for an existing-branch repair, run this secret-safe probe in the same workspace and retain only booleans:
env -u GH_TOKEN -u GITHUB_TOKEN gh api user --jq .login >/dev/null
gh repo view <owner>/<repo> --json nameWithOwner >/dev/null
git ls-remote https://github.com/<owner>/<repo>.git HEAD >/dev/null
echo 'github_api_capability=ok; git_read_capability=ok'
This proves authenticated API/read transport in that execution scope and prevents a false external-auth blocker. It does not prove normal push transport; require the worker to re-check that immediately before a guarded non-force push. It also does not waive any controller policy that explicitly requires propagation of a named environment secret: record that distinction rather than inventing a secret name or exposing stored credentials.
Known workspace init-script matrix (June 2026)
| Workspace | Base | Python | gh CLI | Tailscale | Browser | Notable extra |
|---|
assistant | ubuntu-noble | uv | yes | no | no | google-calendar MCP, bun-mcp, bitwarden-secrets skill |