Files
box/docs/BOX-JOBS-HTTPS.md
operator 0065d11e97 feat(supervision): add choice watcher daemon, HTTPS spec docs, and test suites
- 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
2026-10-07 00:25:46 +00:00

4.2 KiB
Raw Permalink Blame History

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, 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) 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.trigger vs existing job.run: job.run shells straight to job-dispatch.py and relays raw output; job.trigger goes through box-ctl.py (existence check, 300s bound, audit trail, JSON contract). Prefer job.trigger for agent-driven dispatches.
  • job.next job ids look like <name>-YYYYMMDD-HHMMSS-<8hex>; with no success flag 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.put is the first op to pipe a request body to box-ctl.py stdin (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-delete are reachable only over the operator SSH path, by explicit scope decision.
  • 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 cron put|trigger|chain|next and timer stop|disable commands.
  • Non-goals: deletes, job-result ingestion, strat/loop writes, approvals — future expansions, same pattern.