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
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
# Box Md Drive Files 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 traversal hardening, output caps,
|
||||
`--stdin` content plumbing, and hyphenated amend/append/pull aliases)
|
||||
**Scope:** md reads (audit/list/read/diff) + governed writes
|
||||
(amend/append/pull/inject-drive/sync-all). Raw container writes
|
||||
(`md-write`) stay SSH-only by design.
|
||||
|
||||
## 1. Why
|
||||
|
||||
Agents shaping fleet behavior could see drive scores but needed SSH to
|
||||
read an agent's `SOUL.md`, diff it against the canonical template, or
|
||||
push updated operator files. 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
|
||||
|
||||
Reads (all `side_effecting: false`, all in `DEFAULT_PERMS`):
|
||||
|
||||
| Op | Args | Backend |
|
||||
|---|---|---|
|
||||
| `md.audit` | `{accounts?}` (default all) | `box-ctl.py md-audit [accounts...]` |
|
||||
| `md.list` | `{account!, path?}` | `box-ctl.py md-list` (capped, see §4) |
|
||||
| `md.read` | `{account!, filename!}` | `box-ctl.py md-read` (capped, see §4) |
|
||||
| `md.diff` | `{account!, filename!}` (shared template only) | `box-ctl.py md-diff` (capped, see §4) |
|
||||
|
||||
Governed writes (all known-identities-only, none in the read-only subset):
|
||||
|
||||
| Op | Args | Backend |
|
||||
|---|---|---|
|
||||
| `md.pull` | `{account!, filename!}` (shared template only) | `box-ctl.py md-pull` |
|
||||
| `md.inject_drive` | `{account!}` | `box-ctl.py md-inject-drive` |
|
||||
| `md.sync_all` | `{}` | `box-ctl.py md-sync-all` |
|
||||
| `md.amend` | `{filename!, content!, author?, reason?}` | `box-ctl.py md-amend --stdin` (content on stdin) |
|
||||
| `md.append` | `{filename!, text!, author?, section?}` | `box-ctl.py md-append --stdin` (text on stdin) |
|
||||
|
||||
New `box-relay.sh` client commands:
|
||||
|
||||
```bash
|
||||
box md audit [accounts...]
|
||||
box md list <account> [path]
|
||||
box md read <account> <filename>
|
||||
box md diff <account> <filename>
|
||||
box md pull <account> <filename>
|
||||
box md inject-drive <account>
|
||||
box md sync-all
|
||||
box md amend <filename> (--content <text>|--file <path>) [--author <name>] [--reason <why>]
|
||||
box md append <filename> (--content <text>|--file <path>) [--author <name>] [--section <header>]
|
||||
```
|
||||
|
||||
Raw op calls (signature auth, no token):
|
||||
|
||||
```bash
|
||||
exec-sign.sh md.audit '{"accounts": ["646", "opm"]}'
|
||||
exec-sign.sh md.read '{"account": "646", "filename": "SOUL.md"}'
|
||||
exec-sign.sh md.diff '{"account": "pip", "filename": "HEARTBEAT.md"}'
|
||||
exec-sign.sh md.append '{"filename": "AGENTS.md", "text": "lesson ...", "author": "646"}'
|
||||
```
|
||||
|
||||
## 3. What the governed writes do
|
||||
|
||||
- `md.amend` rewrites a `shared/operators/` template after the
|
||||
drive-safety checks (HEARTBEAT checklist not gutted,
|
||||
PROACTIVE_PREFERENCES not blanked, SOUL not reverted to stock),
|
||||
then git-commits it. Full-file content rides stdin (up to 256KB).
|
||||
- `md.append` appends a timestamped, attributed note (optional section)
|
||||
via the same validated + committed path (up to 64KB).
|
||||
- `md.pull` / `md.inject_drive` / `md.sync_all` push canonical
|
||||
templates *out* to containers; no agent-supplied content crosses.
|
||||
Injection always overwrites (AGENTS.md preserves remote `## Lessons`).
|
||||
|
||||
## 4. Safety notes (same posture as existing ops)
|
||||
|
||||
- **Traversal hardening (single-copy in `agent_md.py`).** Account,
|
||||
filename, and list-path validation now lives in `agent_md.py`
|
||||
(`MDValidationError`, raised before any gateway call or write);
|
||||
`box-ctl.py` maps it to `BAD_NAME`, and exec ops + quality-validate
|
||||
mirror the same shapes. Previously `md-read 646 ../x` reached the
|
||||
gateway and `md amend ../../x` could escape `shared/operators/`.
|
||||
Template flows (diff/amend/append/pull) additionally require one of
|
||||
the 8 known template names.
|
||||
- **Fixed argv, validated values.** Unknown arg keys rejected; author /
|
||||
reason / section are control-char-free with length caps; amend
|
||||
content must be non-empty.
|
||||
- **Caps with `truncated` flags.** Reads cap at 64KB, diffs at 64KB,
|
||||
listings at 200 entries — same convention as git/tests verbs.
|
||||
- **No raw `md-write` op.** Arbitrary content-to-container stays
|
||||
SSH-only; remote writes go through the validated template flows.
|
||||
- **Timeouts.** Audit 300s, sync-all 600s, single-file ops 120s.
|
||||
- **Audited.** Every execution records identity + op; `box-ctl.py`
|
||||
additionally audits each verb with its target.
|
||||
- **Retry-safe reads.** `md-audit` / `md-list` / `md-read` / `md-diff`
|
||||
joined `IDEMPOTENT_ACTIONS`; all ten md verbs have
|
||||
`quality-validate` dry-run branches.
|
||||
|
||||
## 5. Rollout notes
|
||||
|
||||
- Restart `exec-constrained.py` after deploy for the 9 new ops to
|
||||
appear in `GET /ops` (repo total becomes 79).
|
||||
- `box-relay.sh` is served from bl (`GET /box`); agents re-fetch to
|
||||
get the `md` group.
|
||||
- Non-goals: deletes, `main-loop` enable/disable, policy writes,
|
||||
swarm kill/prune — future expansions, same pattern. (Approvals
|
||||
shipped separately; see BOX-APPROVALS-HTTPS.md.)
|
||||
Reference in New Issue
Block a user