# Box Loop + Strategy Writes over HTTPS (No SSH) > **Box is the main surface.** All operator work goes through Box (box.muse-dev.online). The web UI, `box` CLI, and agents share the same API endpoints. No UI-only powers. **Date:** 2026-10-06 **Status:** implemented on bl (`exec-constrained.py` + `box-relay.sh`; `box-ctl.py` verbs pre-existed, plus a vars-name validator fix) **Scope:** safe loop/strategy/variable mutations. Reads (`loop-status`, `loop-health`, `loop-breaks`, `strat-get`, `vars-get`, ...) already ride `box.exec` or typed read ops and are unchanged here. ## 1. Why Agents watching loop health could see breaks but needed SSH to remediate them, resolve stale followups, tune strategy overrides, or undo variable changes. All of this now rides the agent HTTPS path (`https://exec.muse-dev.online/exec`, signature or bearer auth, named-op allowlist, audit log). ## 2. New ops (all known-identities-only, none in the read-only subset) | Op | Args | Backend | |---|---|---| | `loop.remediate` | `{dry_run?}` (default false) | `box-ctl.py loop-remediate [--dry-run]` | | `loop.resolve` | `{dm_id, note?}` | `box-ctl.py loop-resolve` | | `strat.set` | `{type!, subtype?, agent?, track?, priority?, timeout_s?, nudges?, escalate?}` | `box-ctl.py strat-set` (payload as argv JSON) | | `strat.reset` | `{type!, subtype?, agent?}` | `box-ctl.py strat-reset` | | `vars.reset` | `{name}` | `box-ctl.py vars-reset` (restore default) | | `vars.rollback` | `{name, revision?}` (int step or timestamp) | `box-ctl.py vars-rollback` | New `box-relay.sh` client commands: ```bash box loop remediate [--dry-run] box loop resolve [note...] box strat set [--subtype S] [--agent A] [--track true|false] [--priority p] [--timeout N] [--nudges N] [--escalate E] box strat reset [subtype] [--agent ] box vars reset box vars rollback [revision] ``` Raw op call (signature auth, no token): ```bash exec-sign.sh loop.remediate '{"dry_run": true}' exec-sign.sh strat.set '{"type": "job", "priority": "important", "nudges": 3}' ``` ## 3. What remediate does (non-dry) `loop.remediate` delegates to `gravity.remediate_breaks`: resolves followups already answered in logs, re-arms expired followups with nudges remaining (runs the followup sweeper once), auto-allows TRUSTED (non-key) browser approvals, and on hard breaks appends a `hard_break_alert` to job-log plus one DM to opm. Use `{"dry_run": true}` first to preview the `remediated` / `escalated` lists with zero side effects. ## 4. Safety notes (same posture as existing ops) - **Fixed argv, validated values.** Strategy types are a strict enum (`wake|job|siphon|manual|health|heartbeat`) — the backend silently maps typos to MANUAL, so the op rejects them instead. Priorities are a strict enum; timeouts/nudges must be integers (backend clamps); dm ids must be 6–64 hex; variable names mirror the engine identifier rule. All checks run before any side effect. - **Stdin-free.** Unlike `job.put`, `strat.set` passes its JSON payload as an argv token (`strat-set [JSON]`), so no new stdin plumbing was needed. - **Vars-name validator fix.** `quality-validate` for all five vars verbs used the job-name regex (`^[a-z0-9-]{1,64}$`), rejecting every real variable name (`max_nudge_count`, ...). They now share `qv_var_name` (`^[A-Za-z0-9_.-]{1,64}$`), mirroring the `exec-constrained.py` rule. - **Audited.** Every execution records identity + op + args hash; `box-ctl.py` additionally audits each mutation with its target. ## 5. Rollout notes - Restart `exec-constrained.py` after deploy for the new ops to appear in `GET /ops`. - `box-relay.sh` is served from bl (`GET /box`); agents re-fetch to get the `loop` / `strat` groups and `vars reset|rollback`. - Non-goals: approvals, deletes, `main-loop` enable/disable — future expansions, same pattern. (md drive files shipped separately; see BOX-MD-HTTPS.md.)