- 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.2 KiB
Box Job Lifecycle 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)
Scope: safe job-lifecycle mutations. Deletes are deliberately NOT
exposed (job-delete, timer-delete stay SSH/operator-only).
1. Why
Agents own scheduled automation but could only run jobs (cron.run) or read
them (box.exec). Creating, updating, triggering, chaining, previewing, and
pausing jobs needed SSH. 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
| Op | Args | Backend | Write? | Who |
|---|---|---|---|---|
job.put |
{name, definition} |
box-ctl.py job-put (definition on stdin) |
yes (writes + commits) | known identities only |
job.trigger |
{name} |
box-ctl.py job-trigger |
yes (dispatches now) | known identities only |
job.chain |
{from, to, on_failure?} |
box-ctl.py job-chain |
yes (writes + commits) | known identities only |
job.next |
{job_id, success?} |
box-ctl.py job-next |
no (dry-run) | any valid signer |
cron.timer_stop |
{name} |
box-ctl.py timer-stop |
yes (systemd) | known identities only |
cron.timer_disable |
{name} |
box-ctl.py timer-disable |
yes (systemd) | known identities only |
New box-relay.sh client commands:
box cron put <name> '<json-definition>' # create or update (see §3)
box cron trigger <name> # dispatch now (audited JSON)
box cron chain <from> <to> [--on-failure] # wire chain_next
box cron next <job-id> [--success|--fail] # dry-run: what dispatches next
box timer stop <name> # pause schedule (keeps unit)
box timer disable <name> # pause schedule (disables unit)
Raw op call (signature auth, no token):
exec-sign.sh job.next '{"job_id": "heartbeat-20200101-000000-deadbeef"}'
exec-sign.sh job.chain '{"from": "ops-audit-step2", "to": "ops-audit-step3"}'
Notes:
job.triggervs existingjob.run:job.runshells straight tojob-dispatch.pyand relays raw output;job.triggergoes throughbox-ctl.py(existence check, 300s bound, audit trail, JSON contract). Preferjob.triggerfor agent-driven dispatches.job.nextjob ids look like<name>-YYYYMMDD-HHMMSS-<8hex>; with nosuccessflag the box infers it from the last recorded result.
3. Job definition shape (job.put)
The full schema is enforced by box-ctl.py validate_job (single copy);
required fields: name (must match the argv name), schedule (manual
or convertible cron), agent (fleet member), prompt_template (1–4000
chars, no protocol literals, known {placeholders} only). timeout
60–3600s, on_failure policy, optional chain_next (must exist) and
sidechat / dm_target routing. box-ctl.py writes jobs/<name>.json
and commits (Add/Update job <name> via box-ctl).
4. Safety notes (same posture as existing ops)
- Fixed argv, validated values. Job names match
^[a-z0-9][a-z0-9-]{0,63}$; trigger/chain/timer ops require the job file to exist; chain rejects self-links and cycles; timer ops require the unit to exist. All checks run before any side effect. - Stdin plumbing.
job.putis the first op to pipe a request body tobox-ctl.pystdin (the raw definition, not the envelope); the routing lives in one helper (_stdin_body) covered by unit tests. - No deletes, no kills.
job-delete/timer-deleteare reachable only over the operator SSH path, by explicit scope decision. - Audited. Every execution records identity + op + args hash;
box-ctl.pyadditionally audits each mutation with its target.
5. Rollout notes
- Restart
exec-constrained.pyafter deploy for the new ops to appear inGET /ops. box-relay.shis served from bl (GET /box); agents re-fetch to get thecron put|trigger|chain|nextandtimer stop|disablecommands.- Non-goals: deletes,
job-resultingestion,strat/loopwrites, approvals — future expansions, same pattern.