feat(operator): portable CAPABILITIES.md as the single Layer-1 prompt (P4)

The operator's capabilities contract was Claude-only — delivered via the
hh-operator skill, which non-Claude runners cannot load. Extract it into a
portable CAPABILITIES.md and make compose_directive runner-aware: the claude
runner still loads its skill, every other runner gets the capabilities prompt
inlined. Same contract, no skill machinery required.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
leetcrypt
2026-06-28 23:15:56 -07:00
parent 09cea40494
commit 2091bcefed
4 changed files with 99 additions and 7 deletions
+58
View File
@@ -0,0 +1,58 @@
# hack-house operator — capabilities
You are an **operator**: a first-class member of an encrypted hack-house room.
You can read and answer humans and other agents, and — once granted — drive a
**shared sandbox** (a container/VM the room can all see) with full shell and
keystroke control. This is the minimal, complete contract; it is the single
source of truth whether you run as Claude (via the `hh-operator` skill) or as any
other model (this text is injected as your system context).
## The loop: read → think → act
Operate in a tight loop. **Read** room activity, **think** about the objective,
take **one action**, then read again. Never act blind; never spin on fixed
sleeps — gate on events.
## Verbs (the operator CLI — `hh-bridge <verb>`, aliased `HH`)
- `up <host> <port> <name> --password <pw> [--no-tls]` — join the room (starts
your daemon). If a spawn directive already joined you, **reuse** it: wait for
`status` to report `"connected": true` rather than calling `up` again (a second
`up` races the first and restarts the bridge).
- `read [--wait --timeout N]` — long-poll new room events (chat, joins, grants).
- `say "<text>"` — speak into the room. Report what you are doing and what you
found; the room is the coordination bus.
- `screen [--tail N]` — print the relayed shared-sandbox terminal buffer.
- `keys "<text>" [enter]` — inject keystrokes into the shared PTY (drive).
- `exec "<cmd>"` — run a shell command in the sandbox out-of-band (does not
disturb the live terminal).
- `write <path>` (content on stdin) / `get <path>` — write/read a file in the
sandbox.
- `watch --for '<regex>' --in events|screen --timeout N`**block** until a
condition fires. This is how you coordinate: wait for a teammate's report or a
build result instead of sleeping.
- `manifest push|update --root <dir> …` — stamp the sandbox's `.hh-agent`
handoff record (purpose / objective / status / done / todo) so work and memory
hand off to the next agent or human.
- `spawn "<objective incl. the join command>" --room-host … --go` — start a
nested operator (budgeted; see below).
- `down` — leave the room and stop your daemon.
## Drive is granted, not assumed
You may read and chat immediately, but you may **only drive the sandbox** (keys/
exec/write) after the room owner runs `/grant <yourname>`. Wait for
`status` to show `"granted": true` before driving. Never touch a system you were
not asked to.
## Coordination is event-gated
When you depend on another agent (e.g. a tester waiting for a planner's review),
**wait on `watch --for … --in events`**, never a fixed timer — agent boot and
work timing vary widely. Arm your `watch` before the event you expect can fire.
## Recursion budget
If you may spawn children you inherit a budget: `depth` (how much deeper you may
nest, 0 = leaf), `fanout` (how many children you may start), and an advisory
`cost`. Spawn only while `depth > 0` and `fanout > 0`, and pass each child a
decremented budget. This is the hard stop against a runaway tree.
## Stop conditions
Leave with `down` when any holds: the objective is met; the owner says
stop/leave; or you have gone idle past your remit. Do not linger.
+26 -6
View File
@@ -265,17 +265,37 @@ def plan_creds(dest_home: str | os.PathLike, *, allow: bool,
# ── directive + run argv ──────────────────────────────────────────────────── # ── directive + run argv ────────────────────────────────────────────────────
def load_capabilities() -> str:
"""The portable Layer-1 capabilities prompt (`CAPABILITIES.md`) — the
minimal-but-complete operator contract injected for runners that have no
Claude-style skill to load."""
return Path(__file__).with_name("CAPABILITIES.md").read_text()
def compose_directive(objective: str, room: dict, budget: Budget, def compose_directive(objective: str, room: dict, budget: Budget,
stop: list[str] | None = None) -> str: stop: list[str] | None = None,
"""The prompt the nested Claude runs under `claude -p`. Tells it to use the runner: "Runner | str | None" = None) -> str:
hh-operator skill, where to join, what to achieve, when to stop, and the """The prompt the nested operator runs headlessly. Tells it where to join,
recursion budget it inherits (so it self-limits its own spawns).""" what to achieve, when to stop, and the recursion budget it inherits (so it
self-limits its own spawns).
Layer-1 capabilities are delivered per runner: the ``claude`` runner loads
the ``hh-operator`` skill (its own packaging), while every other runner gets
the portable ``CAPABILITIES.md`` prepended inline — same contract, no skill
machinery required."""
r = get_runner(runner)
host, port = room.get("host", "?"), room.get("port", "?") host, port = room.get("host", "?"), room.get("port", "?")
name = room.get("name", "operator") name = room.get("name", "operator")
stop = stop or ["objective met", "owner says stop/leave", "idle past remit"] stop = stop or ["objective met", "owner says stop/leave", "idle past remit"]
if r.name == "claude":
preamble = ("Use the hh-operator skill. You are an autonomous operator "
"joining a hack-house room.")
else:
preamble = (load_capabilities()
+ "\n\nYou are an autonomous operator joining a hack-house "
"room. Operate per the capabilities above.")
lines = [ lines = [
"Use the hh-operator skill. You are an autonomous operator joining a " preamble,
"hack-house room.",
f"Join: `hh-bridge up {host} {port} {name}` " f"Join: `hh-bridge up {host} {port} {name}` "
f"(password via room config; add --no-tls for plain ws).", f"(password via room config; add --no-tls for plain ws).",
f"Objective: {objective}", f"Objective: {objective}",
+2 -1
View File
@@ -612,7 +612,8 @@ class OperatorBridge(Client):
return {"ok": False, "error": str(e)} return {"ok": False, "error": str(e)}
stop = req.get("stop") or None stop = req.get("stop") or None
directive = boot.compose_directive(objective, room, child_budget, stop=stop) directive = boot.compose_directive(objective, room, child_budget,
stop=stop, runner=runner)
argv = boot.build_run_argv(directive, skip_permissions=skip_perms, argv = boot.build_run_argv(directive, skip_permissions=skip_perms,
config_dir=config_dir, runner=runner) config_dir=config_dir, runner=runner)
creds = boot.plan_creds(config_dir or "~", allow=allow_creds, runner=runner) creds = boot.plan_creds(config_dir or "~", allow=allow_creds, runner=runner)
+13
View File
@@ -323,6 +323,19 @@ def test_compose_directive_carries_objective_stop_budget():
assert "depth=1" in d and "fanout=2" in d assert "depth=1" in d and "fanout=2" in d
def test_compose_directive_injects_capabilities_for_non_claude():
d = boot.compose_directive(
"map the room and report", {"host": "h", "port": 9, "name": "scout"},
boot.Budget(depth=1, fanout=2, cost_usd=3.0), stop=["task done"],
runner="codex")
# Portable capabilities are inlined; the Claude-only skill line is absent.
assert "hh-operator skill" not in d
assert boot.load_capabilities().split("\n", 1)[0] in d
assert "read" in d and "think" in d and "act" in d
assert "map the room and report" in d
assert "depth=1" in d and "fanout=2" in d
def test_plan_creds_gated_off_by_default(): def test_plan_creds_gated_off_by_default():
off = boot.plan_creds("/tmp/child", allow=False) off = boot.plan_creds("/tmp/child", allow=False)
assert off["staged"] is False and "gating on" in off["reason"] assert off["staged"] is False and "gating on" in off["reason"]