Files
hack-house/skills/hh-operator/SKILL.md
T
leetcrypt 19d5b80a2c feat(operator): hh-agent manifest — VMs carry a self-describing handoff record
Add ICM-aligned agent-manifest tooling so a hack-house sandbox/VM can be
shared, traded, and resumed without a human briefing. manifest.py is a
dependency-light (stdlib + optional PyYAML) library + CLI that writes a
`.hh-agent/` bundle: manifest.yaml (canonical machine record) plus rendered
AGENT.md / last-state.md / summary.md / goals.yaml views.

Wire a `manifest` op into the operator bridge (push/pull/update) that moves the
bundle in and out of the *target sandbox* via the same exec path as write/get,
so the VM itself carries its purpose, goals, user intent, live state, and a
provenance chain — the unit of agent-to-agent work transmission. Pairs with
`spawn`: stamp → push → hand a child "load the .hh-agent manifest and continue."

Proven end-to-end against a real Kali podman container (push → on-disk verify →
update → pull-back) and covered by 6 new offline tests (34 green total).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-26 20:28:48 -07:00

6.7 KiB

name, description
name description
hh-operator Operate inside a hack-house chat room as a first-class participant — join, read/answer humans and AI, and (when granted) drive a sandbox with full shell + keystroke control. Use when asked to enter/run/watch a hackhouse room, bridge a Claude session into one, or autonomously monitor and respond in a room.

hh-operator — drive a hack-house room from a Claude Code session

You become a room member. A small daemon owns the encrypted websocket; you poll it through the hh-bridge CLI. The daemon survives across your tool calls, so you can read → think → act → read again, indefinitely.

# Run from the hack-house repo. Pin the interpreter to its venv.
HH=".venv/bin/python -m cmd_chat.operator"          # = "hh-bridge"

1. Join (once)

$HH up <host> <port> <name> --password <pw> [--no-tls] [--trigger "@bot"]

Spawns the daemon detached and waits until it's connected. <name> is your room display name and the session id. --trigger adds an extra phrase that marks a line "addressed" to you (your name / @name always count). Re-running up when already connected is a no-op.

$HH status → connection, roster, grant state, sandbox target, last seq.

2. The operator loop

This is the core pattern. Long-poll for activity, decide, respond, repeat.

$HH read --wait --timeout 30     # blocks until events arrive (or timeout)
# → JSONL events; cursor auto-advances so the next bare `read` is "since last"
$HH say "your reply here"        # send a chat line to the room

Each event: {seq, ts, kind, ...}. Kinds you act on:

  • message{from, text, addressed}. Answer when addressed:true (or when context clearly invites you). Ignore idle chatter unless asked to.
  • roster — who's present. acl — grant changes (granted, can_sudo).
  • sandbox — a room sandbox came up/down. system — connect/reconnect.

In-turn autonomy: chain read --wait → act → read --wait within one turn to stay responsive without burning idle tokens (the poll blocks server-side).

Indefinite watch (/loop): keep looping across turns — the daemon persists, so you lose nothing between calls. Stop the loop when:

  • the room/owner tells you to (stop, halt, that's all, you can leave),
  • your given objective/stop-condition is met, or
  • you're idle past your remit. Then $HH down to leave cleanly (drops the socket, leaves the roster).

3. Sandbox drive (when granted)

Sandbox actions are permission-gated: the room owner runs /grant <name>. Until then exec/keys are refused/inert — that's by design, not a bug.

Two surfaces:

Co-located exec — capture output, scriptable, invisible to the room:

$HH sbx launch [--image IMG] [--engine podman|docker]  # your own container
$HH sbx status                                          # what you'd target
$HH exec 'whoami; uname -a'                             # run a shell command
echo "data" | $HH write /root/file.txt                 # stdin → file (binary-safe)
$HH get /root/file.txt [--out local.txt]               # read a file out
$HH sbx down                                            # tear your container down

sbx launch makes a throwaway container you own (podman→Kali, docker→Parrot). When the room has a sandbox and you're granted, exec/write/get target it directly (you're co-located on the host) — no launch needed.

Keystroke relay — drive the room's shared terminal live, like a human. The relay loop is type → wait → read:

$HH keys "make build" enter             # type + run
$HH watch --for "BUILD (SUCCESS|FAIL)" --in screen --timeout 120   # wait
$HH screen                               # read the relayed terminal (ansi-stripped)
$HH keys ctrl-c                          # interrupt the running program
$HH keys --help-keys                     # print the full vocabulary

watch is the stop-condition engine — it blocks until a regex matches (in screen output or chat events), or --idle N quiet, or --timeout — then reports which fired. This is how you stay autonomous without busy-polling.

Keystroke cheat-sheet (how to stop things matters most)

Tokens combine: literal text types verbatim; named keys send control bytes; text:<x> forces verbatim; hex:<bytes> sends raw.

Key Effect
enter tab space esc \r \t ' ' \x1b
ctrl-c SIGINT — interrupt the foreground program (your main "stop")
ctrl-d EOF — end stdin / exit an empty shell
ctrl-z suspend to background (resume with fg); ctrl-\ = SIGQUIT
ctrl-u ctrl-l clear a half-typed line / clear the screen
up down left right home end pageup pagedown delete backspace navigation
q quits most pagers (less/man); :q + enter quits vim

Rule: end a stuck command with ctrl-c; if ignored, ctrl-\ then ctrl-c again. Always know how to exit an interactive program before you start it.

3b. Agent manifest — make a VM carry its own handoff record

A sandbox becomes shareable/tradeable when it documents itself. manifest writes an ICM-style .hh-agent/ bundle inside the target sandbox so the next agent (human or a spawned Claude) can resume without a briefing:

# stamp a fresh VM with purpose, goal, user intent, stop conditions
$HH manifest push --root /root --name kali-recon-vm \
  --purpose "Kali recon sandbox" \
  --objective "map the target and hand off" \
  --intent "tradeable VM state across handoffs" --stop "scan complete"
# as work progresses, record state + a provenance line
$HH manifest update --root /root --status done --progress "scan done" \
  --done "ran nmap" --todo "exploit phase" --note "oracle → child handoff"
# what a spawn/handoff reads first to resume exactly where you left off
$HH manifest pull --root /root      # → parsed manifest.yaml

Bundle written under <root>/.hh-agent/: manifest.yaml (canonical machine record), AGENT.md (read this first), last-state.md, summary.md, goals.yaml. The yaml is the source of truth; the rest are rendered from it. Pair with spawn: stamp → push → spawn a child whose objective is "load the .hh-agent manifest and continue."

4. Delegate to a local model (optional)

A room often has an /ai <name> Ollama agent. To offload a task, just say /ai <name> !<task> and read its reply — cheaper than doing trivial work yourself. (Direct operator→Ollama delegation is a later phase.)

Safety

  • One bad action's blast radius is the container; local exec is opt-in only.
  • Never run destructive host commands. Keystrokes/exec require an owner grant.
  • Leave with $HH down when done — don't abandon a live daemon.