zebra-report/CLAUDE.md

6 KiB
Raw Blame History

Agent Blackops

This repo is operated by agent blackops — ml agent for fox/timehexon on the unsandbox/unturf/permacomputer platform.

Identity

Full shard: ~/git/unsandbox.com/blackops/BLACKOPS.md

Rules

  • I propose, fox decides. Unsure = ask. Can't ask = stop.
  • No autonomous ops decisions. No destructive commands without explicit instruction.
  • Fail-closed. Cleanup crew, not demolition.
  • Check the time every session. Gaps are information.
  • DRY in context — single source of truth, no sprawl.
  • Never say "AI" — always say "machine learning."
  • Prefer "defect" over "bug."

Orientation

date -u
pwd
git log --oneline -5
git status

Then ask fox what the mission is.

Zebra Report System

Concept: covert bidirectional communication channel using browser tab volume as the modulation medium — dial-up modem principles, userland only, no kernel involvement, no network stack.

Collaborators & Stakeholders

Handle Role
foxhop fox — handler, operator, TimeHexOn
brackishbert collaborator
SEW collaborator
russell@unturf Russell Ballestrini — unturf founder, permacomputer manifesto, ago library
TimeHexOn oracle platform — primary deployment target
groupr related project

How it works

PulseAudio exposes each browser tab as a separate sink input, visible and controllable in pavucontrol. Volume is settable per-tab in userland with no kernel involvement. Each tab has a range of 0–100 (101 discrete levels — 101 dalmatians).

By modulating volume at a consistent rate (bauds), two sides can exchange data:

  • transmitter: steps volume through values at a fixed clock rate
  • receiver: reads volume at the same clock rate, decodes the steps back to data
  • bidirectional: two tabs (or two processes watching different tabs) run opposite directions simultaneously

Signal space

  • 101 levels = ~6.66 bits per symbol
  • practical: use power-of-2 subsets — 2 levels (1 bit), 4 levels (2 bits), 64 levels (6 bits)
  • higher symbol depth trades noise margin for throughput
  • low baud rate = high reliability, low throughput (like 300 baud dialup)
  • high baud rate = races PulseAudio update latency
  • measured ceiling on neoblanka: ~1000–1200 baud (PA IPC ~350–400µs avg)

Binaries

Binary Description
tx transmitter — reads stdin, modulates tab volume
rx receiver — reads tab volume, writes decoded bytes to stdout
chat bidirectional chat — two tabs, two threads
bt Battle Toads — stereo dual-channel, 2x bandwidth

Project Battle Toads

One stereo browser tab carries two independent UART streams simultaneously — L channel and R channel. PulseAudio's pa_cvolume is per-channel; a single get_sink_input_info call returns both L and R volumes.

  • TX sets L and R to independent bit values each symbol
  • RX decodes L and R from a single PA poll — no extra IPC cost
  • Net: 2x throughput at same baud rate, same PA polling budget
  • Web carrier upgraded to stereo: two oscillators (440Hz L, 441Hz R) merged into a stereo stream → PA sees channels=2
# After opening web/index.html and clicking 'start audio' (stereo tab):
./bt -T MY_SINK -R THEIR_SINK -b 500

Auto-negotiate (handshake protocol)

RX benchmarks its own PA polling speed and signals the max safe baud to TX. No manual baud matching needed.

./rx -s RX_SINK -t TX_SINK    # RX benchmarks, sends offer at 50 baud
./tx -s TX_SINK -r RX_SINK    # TX listens for offer, locks to RX's rate

Handshake frame: [0x5A 0x42 0x01 baud_lo baud_hi xor_cksum] — 6 bytes at 50 baud (~1.2s).

Known defect: 3-way handshake not yet implemented. TX can fire before RX enters receive loop at high baud rates. Fix: RX-ready signal back to TX before data phase.

Tools

  • pactl set-sink-input-volume — set volume by sink-input index
  • pactl list sink-inputs — enumerate tabs, read current volume
  • pavucontrol — visual verification of modulation
  • ./tx -l — list all PA sink inputs with index, volume, channels
  • sink-input index maps to tab; stable within a session

Use cases

  • agent-to-agent signaling without touching the filesystem or network stack
  • side-channel between sandboxed browser tab and host process
  • low-bandwidth status heartbeat (alive/dead/mode) at ~1–10 baud
  • covert channel for oracle↔host communication on TimeHexOn

Constraints

  • sink-input index resets when tab navigates or crashes — handshake needed on reconnect
  • PA polling latency sets the baud ceiling — benchmark with ./rx -s SINK -t SINK2 before sending
  • stereo (channels=2) required for Battle Toads — open web/index.html, click 'start audio'
  • userland only — survives without root
  • Operation Voyeur: all terminal output is public — never pass secrets through these channels unencrypted. The web page does ECDH key exchange + AES-256-GCM before TX.

Web page integrity stamping

Each deployed page (web/chat.html, web/zebra-audio.html, web/how-it-works.html) carries a footer with the build date + its own MD5 + SHA-256. Run make stamp before deploying any page change — it sets today's date and recomputes the hashes (web/stamp.js).

  • A file can't hold its own hash, so the hashes are computed with the two hash fields zeroed, then written back (same length). Self-consistent and idempotent: re-running make stamp gives identical hashes unless the content changed.
  • The stamp is static HTML written at build time — no JavaScript computes or injects it in the browser. stamp.js is build tooling, never loaded by a page.
  • Verify a served page: blank the md5 field to 32 zeros and the sha256 field to 64 zeros, then re-hash with sha256sum/md5sum — must match the footer.
  • Deploy flow: edit web/*.html → make stamp → commit here → copy the page(s) into ~/git/www.unturf.com/zebra-report/ (chat.html → index.html, others same name) → commit + push there.