- bin/muse_choice_watcher.py + systemd/muse-choices-reconcile.*: automatic choice answering and timer reconciliation - bin/digest.py: fleet log and health summarization - docs/BOX-*-HTTPS.md: comprehensive HTTPS execution contracts and API documentation - docs/MUSE-CHOICES-POLICY.md & docs/SUPERVISION-SPEC.md: autonomous execution specs - tests/test_*.py: unit test suites for HTTPS API, choice watcher, fleet heal, and swarm pruning
4.0 KiB
Box Approvals over HTTPS (No SSH)
Box is the main surface. All operator work goes through Box (box.muse-dev.online). The web UI,
boxCLI, 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 fast node validation and
quality-validate branches; approvals.py untouched)
Scope: approval visibility (check) + governed decisions (deny, auto,
one-shot allow). Persistent/forced allow (--always/--force) stays
SSH-only.
1. Why
Agents blocked on browser approvals needed SSH to see fleet approval
state, deny a bad prompt, auto-resolve trusted prompts, or allow a
known-good one. All of this now rides the agent HTTPS path
(https://exec.muse-dev.online/exec, signature or Bearer [REDACTED], named-op
allowlist, audit log).
2. New ops
| Op | Args | Backend | Access |
|---|---|---|---|
approval.check |
{node?} (default fleet) |
box-ctl.py approval-check |
read-only, in DEFAULT_PERMS |
approval.deny |
{node!, message!, allow_main_chat?} |
box-ctl.py approval-deny |
known-identities-only |
approval.auto |
{node?} (default fleet) |
box-ctl.py approval-auto |
known-identities-only |
approval.allow |
{node!, message!, allow_main_chat?} |
box-ctl.py approval-allow (one-shot) |
known-identities-only |
New box-relay.sh client commands:
box approvals check [node]
box approvals allow <node> --message <text> [--allow-main-chat]
box approvals deny <node> --message <text> [--allow-main-chat]
box approvals auto [node]
Raw op calls (signature auth, no token):
exec-sign.sh approval.check '{}'
exec-sign.sh approval.check '{"node": "646"}'
exec-sign.sh approval.allow '{"node": "646", "message": "trusted deploy script"}'
exec-sign.sh approval.auto '{"node": "opm"}'
3. What the decisions do
approval.allowclicks Allow once on the node's active prompt. There is deliberately no remote--always(persistent site allow) or--force.approval.denyclicks Deny on the node's active prompt.approval.autoscans (fleet or one node) and allows only TRUSTED non-key prompts. Key/passkey approvals are never auto-approved; they need an explicit allow/deny, which notifies the waiting agent.- All three are audited with identity + op + node.
4. Safety notes (same posture as existing ops)
- Attribution is mandatory. The allow/deny flows DM the waiting
agent, historically with an
[operator]prefix. A remote caller is an agent, not the operator — so the exec layer requires a non-emptymessage(≤2000 chars, no controls) on both allow and deny. (box-ctl.pystill permits omitting--messagefor SSH callers; the HTTPS layer is the narrower gate.) - One-shot only. The allow argv never carries
--alwaysor--force; the validators reject those keys. Persistence stays an SSH-side decision. - Sidechat-first.
allow_main_chatdefaults to false; Main Chat delivery needs the explicit flag, same asnotify/dm.ack. - Fixed argv, validated values. Nodes must be fleet members (fast
BAD_NODEbefore any CDP probe —approval-check/approval-autogained the same node check allow/deny already had); unknown arg keys rejected. - Timeouts. Check 180s (fleet CDP scan), auto 300s (scan plus one click per trusted prompt), allow/deny 120s.
- Retry-safe reads.
approval-check/approval-listjoinedIDEMPOTENT_ACTIONS; all six approval verbs havequality-validatedry-run branches.
5. Rollout notes
- Restart
exec-constrained.pyafter deploy for the 4 new ops to appear inGET /ops(repo total becomes 83). box-relay.shis served from bl (GET /box); agents re-fetch to get theapprovalsgroup.- While fleet browsers crash-loop, decision ops fail honestly
(
APPROVAL_FAILED/ CDP errors) instead of hanging; check still reports per-node state includingUNREACHABLE. - Non-goals: deletes,
main-loopenable/disable, policy writes, swarm kill/prune — future expansions, same pattern.