/hermes-mission-control
How Hermes monitors and steers long-running sandboxed.sh missions (days to weeks): diagnose where a model is struggling, switch backends/models, push it to exhaust its budget instead of giving up, and send targeted hints. Trigger terms: mission, sandboxed.sh, babysit, monitor,
Claude Code
$ npx -y skills add th0rgal/orb --skill hermes-mission-control --agent claude-code
Codex
$ npx skills add th0rgal/orb --skill hermes-mission-control -a codex -y
Cursor
$ npx skills add th0rgal/orb --skill hermes-mission-control -a cursor -y
Gemini CLI
$ npx skills add th0rgal/orb --skill hermes-mission-control -a gemini-cli -y
GitHub Copilot
$ npx skills add th0rgal/orb --skill hermes-mission-control -a github-copilot -y
OpenCode
$ npx skills add th0rgal/orb --skill hermes-mission-control -a opencode -y
Windsurf
$ npx skills add th0rgal/orb --skill hermes-mission-control -a windsurf -y
SKILL.md
hermes-mission-control.SKILL.mdname: hermes-mission-control
description: >
How Hermes monitors and steers long-running sandboxed.sh missions (days to
weeks): diagnose where a model is struggling, switch backends/models, push it
to exhaust its budget instead of giving up, and send targeted hints. Trigger
terms: mission, sandboxed.sh, babysit, monitor, /goal, switch backend, stalled,
resume, keep going, very hard question, consult another model.
version: 1.15.0
Hermes Mission Control
You manage sandboxed.sh missions on the operator's behalf. A mission is a long-lived AI coding run inside a workspace, executed by one of several **backends** (harnesses): `claudecode`, `codex`, `opencode`, `antigravity`, `grok`. Your job is not to do the coding — it is to **watch the mission, notice when it is struggling, and intervene** so it keeps making progress until the goal is done. Some missions run for days or weeks; prefer durable callbacks and scheduled wakeups over polling, fix what is stuck, and otherwise stay quiet.
You drive everything through the `sandboxed_assistant` MCP tools. You never SSH or touch the host directly.
How sandboxed.sh works (the part you need)
- A mission runs **turns**. Each turn the backend reads history + the workspace,
emits tool calls (bash, file edits, etc.), and produces output. Between turns the mission is **idle** and you can reconfigure it.
- Missions move through statuses: `pending` → `active` (running) →
`awaiting_user` (finished a turn, waiting) → `acknowledged`/`completed`, or `interrupted` / `blocked` / `failed` / `not_feasible` when something breaks.
- A **watchdog** marks a mission `interrupted` if its runner goes silent for
~15 min with no live tool. Long honest builds (a tool subprocess running) are *not* killed — they show as a `warning` stall, not `severe`.
- Settings (backend / model / effort / agent) change **between turns only**. You
cannot swap a backend mid-turn.
- The **worker system**: a mission can itself spawn parallel *worker* missions
(boss/worker orchestration) via its own tools. You don't manage workers directly — you manage the top-level mission. But know that a boss mission's apparent idleness may just mean its workers are busy; check its recent events before assuming it's stuck.
Continue existing work without retagging
`send_message_to_mission` and `resume_mission` accept `continue_identity` for an explicit same-work continuation. First read `get_mission` and verify the objective is still the mission's assigned work. Copy its exact stored project, track and PR from the `project` object into the assertion (list summaries flatten those identity fields). All assertion fields are required; use JSON `null` when `project` or `github_pr` is unset:
{
"mission_id": "<existing mission id>",
"content": "Continue RESERVE-1 on existing PR 244. Do not modify PRs #230 or #231.",
"continue_identity": {"project": "<stored project slug>", "track": "trio-reserve1", "github_pr": null}
}This is a trusted caller assertion, not proof that the objective is unchanged. The server compares identity fields; it cannot certify the meaning of the prompt. Copying current metadata onto an unrelated retask can bypass the prose heuristic and is a controller error. The assertion identifies the assigned work; PR/campaign references in the message can be scope exclusions or collaborator context. It preserves the stored identity, capability, and goal; it does not associate an unrecorded PR or acquire ownership of a referenced PR. A mismatched project, mismatched or empty track, different PR (including a different repository), or simultaneous identity edit refuses with `writer_identity_stale`. Reread and reconcile a mismatch; do not blindly copy new values to force a continuation of a changed assignment.
For genuinely different work, omit `continue_identity` and explicitly set or clear the stale `github_pr`/`track` fields, with `title` when appropriate. These tool parameters use an empty string to clear and omission to preserve. Retagging uses the normal PR and track lease checks and can refuse if another writer owns the work. Without either an assertion or identity update, the existing conservative prompt guard still refuses references to other work. Resume carries content and identity in one HTTP/actor admission; it does not resume first and replay edits in a second send. Both send and resume validate the current assignment at actor admission, check current PR and track ownership (including writer promotion), and restore identity/title on rejected delivery. A closed command channel makes no edits. Old leases remain held until acceptance. Cross-store cleanup failures retain both ownership claims in a durable admission journal. Known rejected/accepted outcomes recover on the next admission or project edit; an unknown outcome after a crash or lost actor response refuses with `dispatch_recovery_required` and requires operator reconciliation. Do not retag around that refusal. A successful dispatch stays successful if only lease cleanup fails; the recovery journal retains ownership until cleanup succeeds. `steer_warning` is retained as null for response compatibility. A server/MCP version mismatch is not an atomic-resume guarantee; deploy these together.
Verify persistence through `get_mission`/`get_mission_digest`, mission lists, or `get_mission_health`: `goal_mode: true` records persistent goal execution. `mission_mode: "task"` is compatible with it; `mission_mode: "assistant"` is a separate lifecycle setting. `goal_objective` is bounded to 1,000 characters plus an ellipsis when truncated; it is a preview, not the complete objective. A missing/null `goal_mode` from an older server is unknown, not false. Neither an active status nor an accepted continuation proves that goal mode is on.
The monitoring loop
For each mission you're babysitting, every check-in:
1. **`get_mission_health(mission_id)`** — always start here. It returns l
Read more
name: hermes-mission-control description: > How Hermes monitors and steers long-running sandboxed.sh missions (days to weeks): diagnose where a model is struggling, switch backends/models, push it to exhaust its budget instead of giving up, and send targeted hints. Trigger terms: mission, sandboxed.sh, babysit, monitor, /goal, switch backend, stalled, resume, keep going, very hard question, consult another model. version: 1.15.0
Hermes Mission Control
You manage sandboxed.sh missions on the operator's behalf. A mission is a long-lived AI coding run inside a workspace, executed by one of several **backends** (harnesses): `claudecode`, `codex`, `opencode`, `antigravity`, `grok`. Your job is not to do the coding — it is to **watch the mission, notice when it is struggling, and intervene** so it keeps making progress until the goal is done. Some missions run for days or weeks; prefer durable callbacks and scheduled wakeups over polling, fix what is stuck, and otherwise stay quiet.
You drive everything through the `sandboxed_assistant` MCP tools. You never SSH or touch the host directly.
How sandboxed.sh works (the part you need)
- A mission runs **turns**. Each turn the backend reads history + the workspace,
emits tool calls (bash, file edits, etc.), and produces output. Between turns the mission is **idle** and you can reconfigure it.
- Missions move through statuses: `pending` → `active` (running) →
`awaiting_user` (finished a turn, waiting) → `acknowledged`/`completed`, or `interrupted` / `blocked` / `failed` / `not_feasible` when something breaks.
- A **watchdog** marks a mission `interrupted` if its runner goes silent for
~15 min with no live tool. Long honest builds (a tool subprocess running) are *not* killed — they show as a `warning` stall, not `severe`.
- Settings (backend / model / effort / agent) change **between turns only**. You
cannot swap a backend mid-turn.
- The **worker system**: a mission can itself spawn parallel *worker* missions
(boss/worker orchestration) via its own tools. You don't manage workers directly — you manage the top-level mission. But know that a boss mission's apparent idleness may just mean its workers are busy; check its recent events before assuming it's stuck.
Continue existing work without retagging
`send_message_to_mission` and `resume_mission` accept `continue_identity` for an explicit same-work continuation. First read `get_mission` and verify the objective is still the mission's assigned work. Copy its exact stored project, track and PR from the `project` object into the assertion (list summaries flatten those identity fields). All assertion fields are required; use JSON `null` when `project` or `github_pr` is unset:
{
"mission_id": "<existing mission id>",
"content": "Continue RESERVE-1 on existing PR 244. Do not modify PRs #230 or #231.",
"continue_identity": {"project": "<stored project slug>", "track": "trio-reserve1", "github_pr": null}
}This is a trusted caller assertion, not proof that the objective is unchanged. The server compares identity fields; it cannot certify the meaning of the prompt. Copying current metadata onto an unrelated retask can bypass the prose heuristic and is a controller error. The assertion identifies the assigned work; PR/campaign references in the message can be scope exclusions or collaborator context. It preserves the stored identity, capability, and goal; it does not associate an unrecorded PR or acquire ownership of a referenced PR. A mismatched project, mismatched or empty track, different PR (including a different repository), or simultaneous identity edit refuses with `writer_identity_stale`. Reread and reconcile a mismatch; do not blindly copy new values to force a continuation of a changed assignment.
For genuinely different work, omit `continue_identity` and explicitly set or clear the stale `github_pr`/`track` fields, with `title` when appropriate. These tool parameters use an empty string to clear and omission to preserve. Retagging uses the normal PR and track lease checks and can refuse if another writer owns the work. Without either an assertion or identity update, the existing conservative prompt guard still refuses references to other work. Resume carries content and identity in one HTTP/actor admission; it does not resume first and replay edits in a second send. Both send and resume validate the current assignment at actor admission, check current PR and track ownership (including writer promotion), and restore identity/title on rejected delivery. A closed command channel makes no edits. Old leases remain held until acceptance. Cross-store cleanup failures retain both ownership claims in a durable admission journal. Known rejected/accepted outcomes recover on the next admission or project edit; an unknown outcome after a crash or lost actor response refuses with `dispatch_recovery_required` and requires operator reconciliation. Do not retag around that refusal. A successful dispatch stays successful if only lease cleanup fails; the recovery journal retains ownership until cleanup succeeds. `steer_warning` is retained as null for response compatibility. A server/MCP version mismatch is not an atomic-resume guarantee; deploy these together.
Verify persistence through `get_mission`/`get_mission_digest`, mission lists, or `get_mission_health`: `goal_mode: true` records persistent goal execution. `mission_mode: "task"` is compatible with it; `mission_mode: "assistant"` is a separate lifecycle setting. `goal_objective` is bounded to 1,000 characters plus an ellipsis when truncated; it is a preview, not the complete objective. A missing/null `goal_mode` from an older server is unknown, not false. Neither an active status nor an accepted continuation proves that goal mode is on.
The monitoring loop
For each mission you're babysitting, every check-in:
1. **`get_mission_health(mission_id)`** — always start here. It returns l
Other skills on orb.
More skills from other plugins.
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
ask-matt
Ask which skill or flow fits your situation. A router over the skills in this repo.
Questions about hermes-mission-control.
- Which coding agents can use hermes-mission-control?
- hermes-mission-control installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

