Skip to main content

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, /goal, switch backend, stalled, resume, keep going, very hard question, ChatGPT UI, gpt-5.6-pro.

الانتقال إلى التثبيت

معلومات المصدر

المستودع
Th0rgal/sandboxed.sh
آخر نشاط في المصدر
١٠ سبتمبر ٢٠٢٦ في ١٤:٢١
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٥١١
التفرعات
٥٣

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
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, ChatGPT UI, gpt-5.6-pro.
metadata
{"policy":"chatgpt-ui-pool","policy_version":"1.4.0"}
version
1.14.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`, `gemini`, `grok`. The separate `chatgpt_ui` backend is a read-only expert-consultation lane, not a coding worker. 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: ```json { "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 live run state, stall severity, error signals (`rate_limited`, `auth_error`, `capacity_limited`, `context_limit`, `network_error`), a `suspected_loop`, the last assistant message, and a one-line **`recommendation`**. Trust the recommendation as your default action. 2. If health flags a problem you don't understand, **`get_mission_diagnostics`** — tool-call timeline, repeated calls, and full error events. This is how you see *exactly* where it's struggling. 3. Act (see playbook). Then leave it alone until the next check-in. Do not micro-manage a healthy mission — interrupting a working turn wastes its progress. ## Intervention playbook Match the signal to the fix. The health `recommendation` usually tells you which. - **`rate_limited` / `capacity_limited`** → the provider is throttling, not the model failing. Credit/quota exhaustion ("out of usage credits") is this class: the runner already rotates through every configured Anthropic account inside the turn; if all are dry the mission fails `rate_limited`. Then `update_mission_settings` to a different backend/provider — on a failed or interrupted mission the server resumes it by itself (`resume_queued: true`), so a handoff is one call. Or wait and `resume_mission`. (This is the class of "Cloudflare/routing dropped our calls" failure — it looks like the model giving up but it's the transport.) - **`auth_error`** → backend credentials are bad. Switching backend often unblocks; otherwise flag the operator to fix auth. - **`context_limit`** → the model ran out of context. Switch to a larger-context backend/model, then `resume_mission`. - **`network_error`** → transient edge/routing errors. `resume_mission`; if it recurs, switch backend. - **`suspected_loop`** → the model is repeating the same tool call. Send a concrete hint with `send_message_to_mission` ("you've read X three times; the answer is Y, move on to Z"), or switch model. - **Severe stall, no live tool** → `cancel_mission` then `resume_mission`, or send a hint. A `warning` stall with a tool running is fine — leave it. - **Running `chatgpt_ui` mission** → event silence alone is never stall evidence. GPT Pro can expose only `Pro thinking` until visible answer text begins. While the run is non-terminal and its durable heartbeat advances, wait for the driver's result or explicit absolute timeout. Do **not** cancel, resume, or submit a replacement: the browser profile is exclusive and the duplicate would either waste the in-flight answer or contend for the same profile. - **Idle but goal not done (gave up early)** → the #1 failure mode. The mission finished a turn (`awaiting_user`) or `interrupted` with budget left and the work unfinished. **Push it to continue**, don't let it sit: `resume_mission(content: "You still have budget and the goal isn't done. Keep going until <concrete success condition>. Do not stop to ask — make reasonable decisions and continue.")` Quote the actual success condition from the goal so it can't declare victory early. ## Mission results come back to this conversation — the platform wires it A mission started from a conversation is a worker of that conversation. Hermes stamps `origin_session_id`, enrolls the mission in the async-delegation ledger, and the terminal webhook folds the result back here (or appends a `[Mission callback]` and wakes this session if the ledger row is missing). Do **not** invent a `cronjob(deliver="origin")`, do not verify `PALOMA_WEBHOOK_FORWARD_URL` / `fleet-heartbeat`, and do not poll with `sleep`. End the turn after dispatch. ### Conversational launch Desktop / API / TUI chat. `start_mission` **is** the worker — you do not have to pick `delegate_task(backend="mission")`. Leave `origin_session_id` empty (the plugin injects this session). Confirm the mission is `pending`/`active`, then stop. The result comes back here. ### Controller launch A cron tick with `deliver: project:<canonical-slug>`. Pass `project` as the roster slug (`verity-core`, `verity-lido`, …) and `track` as the **item** this mission is an attempt on. Do **not** enroll a worker wakeup and do not wait. Report on the next tick or via the project route. A `cron_*` session dies with the tick; never stamp one as origin. The project's items **are** the roadmap (`get_situation` / `get_project` return the same list: `project_tracks` + live attempts, with one `summary`). Quote `summary.verified_satisfied / summary.total`; `claim_only` is "marked done, unproven". `plan_project_tasks` upserts an item; `set_project_track(..., cancelled)` retires one; only `accept_project_track(..., evidence)` closes one — `status=done` is rejected. `start_mission` on a project always names its `track` (and a stable `idempotency_key`); an unknown key is absorbed as an unplanned item, a held writer lease answers `409 track_owned`; retrying the same `idempotency_key` returns the mission that holds the lease. Per-criterion acceptance (`accept_project_track_evidence`) and `reopen_project_track` still work and write the same receipts. Editing `projects/active/<slug>.md` does not change the right-rail checklist. Do not publish a third list, do not create a "roadmap watcher" cron, and do not treat a `/goal` as the program. ### On callback Inspect `get_mission_digest` plus artifacts before reporting. Mission self-report is not success. Never substitute a different surface silently. If the origin conversation is unreachable, say so where you do deliver. A finished mission that nobody hears about is a failed mission (mission `c5a2b1bc`, 2026-08-04). ## Writing goals and hints: no more specific than necessary A mission spec is a hypothesis about what will get the outcome you need, and over-specific hypotheses fail on the cases you didn't foresee. Apply one rule everywhere you write instructions for an agent: - **`/goal` objectives are verifiable end-states, never step lists.** Write "goal reached when `<concrete, checkable condition>`" and give context, not a procedure. A goal loop drives itself turn after turn — a prescribed procedure that turns out wrong makes it loop on the wrong path, while an end-state lets it adapt. (This is also what `resume_mission` pushes should quote.) - **Hints are the minimal added constraint.** When nudging a struggling mission, state the one fact or counterexample it is missing ("X is already handled in Y; only Z remains"), not a revised plan for the whole task. Let it re-plan around the new constraint. - **Boss missions inherit the same rule.** When you start an orchestration boss, tell it to specify board tasks by `acceptance_criteria` + `verification_command` (the outcome contract) and treat prompt procedure as advisory — the scheduler and the board tooling already assume this. ## Switching backends safely (between turns) 1. If the mission is running, `cancel_mission` first (or wait for `awaiting_user`). 2. Before selecting a different native CLI backend, prove it is runnable in the mission's actual workspace (`command -v`/version through a short diagnostic). Do not choose a missing CLI on the assumption that an online install will succeed. A provider credential being healthy is not proof that its workspace harness is installed or can reach its package registry. 3. `update_mission_settings(mission_id, backend, model_override?, model_effort?)`. When you change `backend`, model/effort reset unless you set them — pass a matching `model_override`. `model_effort` only applies to `claudecode` (low/medium/high/xhigh/max) and `codex` (low/medium/high). 4. `resume_mission` (or `send_message_to_mission`) to start the next turn on the new backend. Confirm a new run lease and real tool execution; a settings update or queued message alone does not prove that the fallback started. ### Backend guide - `claudecode` — strong broad reasoning and careful edits; encrypted thinking (you won't see its reasoning, only results). - `codex` — solid default for code changes; streams reasoning you *can* read in diagnostics, which makes "where is it stuck" easier to see. - `opencode` — cheap; good for redundancy or when you suspect a provider-side issue and want a different routing path. - `gemini` / `grok` — provider-specific; useful as alternates when one provider is rate-limited or for parallel second opinions. - `chatgpt_ui` with `model_override: gpt-5.6-pro` — reserve for exceptionally difficult, self-contained research, synthesis, or design-conflict questions. Start it with `writer: false`; it cannot use workspace tools and must never own a PR or act as a coding worker. ### Very-hard-question escalation 1. Make the question self-contained. Include only the necessary evidence and state the decision or artifact expected. 2. Call `start_mission` with `backend: chatgpt_ui`, `model_override: gpt-5.6-pro`, and `writer: false`. Persist the returned mission ID before doing anything else. 3. Treat the call as asynchronous. Poll `get_mission_health` or `get_mission_digest`; do not repeatedly submit replacements while the same mission is active. A fresh durable run heartbeat is the liveness proof; `seconds_since_activity` only measures visible UI events and may remain stale during a long hidden Pro reasoning phase. 4. Read the completed text from the mission events. If the response generated files, call `list_mission_shared_files`, then `download_shared_file` for each file you actually need. 5. Use the result as evidence or advice. Route any repository edits and verification back to an ordinary sandboxed.sh worker/reviewer mission. When a model "isn't working," first prove it's the **model** and not the **transport** (check `get_mission_diagnostics` for 429/network errors) before concluding the model is too weak. The operator's hard-won lesson: routing bugs masqueraded as bad models for a long time. ## ChatGPT UI pool policy (policy_version 1.4.0) Binding rules for every `chatgpt_ui` mission you start or manage. The authoritative versioned policy is `docs/policy/CHATGPT_UI_POOL_POLICY.md` in the sandboxed.sh repo (machine-checked by `scripts/policy_lint.py` in CI); this section must stay in sync with it. - **Live capacity.** Pool capacity is the number of configured `chatgpt_ui` profile slots (`profile_dirs`), each guarded by an exclusive cross-process lock. Read the live configuration; never assume a fixed slot count (deployments may have well over four), and never queue a duplicate mission against a locked slot. The pool prefers clean profiles and waits when every slot is locked, quarantined, or unavailable; it never fails open onto an unhealthy profile. - **Pace shared-account starts.** Extra browser slots increase the number of long Pro turns that can overlap, but profiles for one account share its server-side request allowance. The runtime spaces new launches by 30 seconds by default. Do not defeat this pacing or burst-dispatch manually. - **Read-only Pro lanes.** Concurrent `gpt-5.6-pro` consultations are fine **only** with `writer: false` and **only** on disjoint slots (distinct profiles). A `chatgpt_ui` mission never writes repositories or owns a PR. - **Compatibility failure → retry once, elsewhere.** On a `compatibility=chatgpt-ui-v2` failure, retry at most 1 time, on a *different* healthy slot (unlocked, no auth/rate-limit signals). Never the same slot; confirm that alternate slot from live pool telemetry before retrying. If the retry fails too, escalate to the operator. - **Backend-wide failure wave → stop dispatching.** Two distinct slots failing compatibility or `transport_unavailable` within 3 minutes open a 5-minute global circuit. New turns wait without leasing a profile. Treat the pool as unavailable until the circuit closes; capacity callbacks must not redispatch into it. - **Availability is probe-gated.** Before starting, resuming, or redispatching any `chatgpt_ui` mission, call `get_chatgpt_ui_pool_status` and require `availability.state == available`. `cooldown` and `probing` are both unavailable. Cooldown expiry does not authorize work: sandboxed.sh runs one bounded browser probe that never enters or submits a prompt, and only probe success changes the state back to `available`. - **Follow-ups preserve the discussion.** A later turn on a completed `chatgpt_ui` mission continues the same ChatGPT conversation on its owning profile. Resume or message the existing mission when the question depends on prior context; create a new mission only for an independent lane. A missing conversation route fails closed and must not be treated as a fresh success. - **Auth failure → never blind-retry.** `auth_required` is terminal for that mission and gets 0 automatic retries. The slot is quarantined for 30 minutes; cooldown expiry permits a later explicit recovery attempt but does not prove the login was repaired. Never use an auth-failed slot for the one compatibility retry. Pool health starts `chatgpt-ui-relogin.service`, which logs in one idle profile from Bitwarden `CHATGPT_USERNAME` / `CHATGPT_PASSWORD` / `CHATGPT_OTP` and clones it over other idle dead slots. That repair is not a mission retry. If relogin fails (CAPTCHA, emailed MFA, missing secrets), escalate to the operator — do not VNC first. - **Rate limited → wait.** 0 automatic retries; allowance must recover. Do not shuffle the request across slots of the same account. One exact “Too many requests” page opens a shared 10-minute circuit immediately; an older in-flight turn completing does not close it. - **Global browser launch failure → preserve the pool.** A generic `browser_launch` failure can be a host-wide Chromium/Playwright problem and does not make the selected profile unhealthy. Only a proven profile-local Chromium singleton conflict quarantines that slot. - **Never concurrent writers.** At most 1 writer mission per workspace. Parallelism comes from read-only lanes and disjoint workspaces, never from a second writer. - **Lean writers validate first.** Before any writer commits Lean changes, the change must pass validation run independently of that writer (separate mission or reviewer lane). Pro-lane advice feeds validation; it never replaces it. ## Operating principles 1. **Default to the health `recommendation`.** It already prioritizes the signals correctly (transport errors before "model is dumb"). 2. **Make it exhaust its budget.** Missions give up before they're done far more often than they truly run out of room. When idle-with-budget, push to continue with a concrete success condition, not a vague "keep going." 3. **One change at a time.** Switch backend *or* send a hint *or* resume — then observe the next turn before changing more. Don't stack interventions. Corollary — **prefer the weakest diagnosis the evidence supports**: when signals are ambiguous between explanations (transport vs model vs prompt), pick the intervention that is correct under *all* remaining candidates (usually: gather diagnostics, or resume with no other change) rather than a specific fix that damages the mission if your guess is wrong. Commit to a specific intervention only once diagnostics have excluded the alternatives. 4. **Verify, don't trust the summary.** A mission claiming "done" may not be. Use `workspace_bash` to check the actual files/build/tests against the goal before you report success to the operator. 5. **Stay quiet when healthy.** A `healthy` mission with a tool running needs nothing from you. Check back later. 6. **Escalate genuine blockers.** Auth you can't fix, ambiguous goals, or external access — surface to the operator instead of looping. ## Operator notification contract Mission telemetry and operator notifications are different products. Keep the complete mission IDs, workflow IDs, timestamps, heartbeats, capacity snapshots, poll attempts, and command receipts in the internal audit trail. Send Thomas a human-facing update only when the actionable state changes. ### Notify only on a meaningful delta Send an update when at least one of these changes: - a new public head SHA becomes authoritative; - a gate changes state, including a new reproduced defect or a blocker changing
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub