netsky: the operations
Parts 1, 2, and 3 gave the theory, the architecture, and the code. This post is the specification.
A cybernetic system is held together by its gates. A gate is the smallest mechanism that rejects a failure class. If the inventory is only in prose, the system can drift without anyone noticing. If the inventory is a data structure the system can emit, it has to stay true or the check breaks.
This post is the inventory.
notation #
Every gate is specified with the same five fields.
gate <snake_case_name> { signal: observable input that triggers evaluation condition: predicate over signal and memory action: deterministic response memory: durable or test-visible write revers: reversibility class + undo path }
Reversibility classes:
| class | meaning |
|---|---|
| trivial | edit, rerun, pass |
| repairable | restore file or state, retry |
| compensating | a follow-up action offsets an external side effect |
| irreversible | destructive external side effect |
The point of the notation is simple: two humans, or one human and one agent, should read the block and reach the same model.
the gates #
gate prompt_drift { signal: commit touches bundled prompts or prompt source tree condition: source bytes != bundled asset bytes action: bin/check runs bin/check-prompt-drift and fails memory: test stdout; src/crates/netsky-core/tests/prompt_drift.rs revers: trivial: sync source, rebuild, rerun gate } gate atomic_envelope_write { signal: producer writes an envelope into an inbox condition: final filename may collide or writer may die mid-write action: write tempfile, hardlink create-new to final, unlink tmp memory: final JSON file or leftover .tmp at envelope.rs revers: repairable: retry with fresh filename, reap leftover tmp } gate envelope_wrapper_token_validator { signal: inbound or outbound agent-bus envelope condition: body contains </channel> or <channel source= action: refuse send; quarantine read before model framing memory: poison/quarantine record at channel.rs revers: trivial: strip wrapper tokens, resend } gate channel_watch_delivery { signal: netsky channel watch <agent> --tmux <session> condition: pending envelope validates + tmux paste + submit succeed action: claim, wrap, paste, submit, ack, archive memory: received ack JSONL at channel.rs revers: repairable: failed submit leaves claimed file for retry } gate mutation_ledger { signal: MCP mutating tool call condition: args_hash seen recently, or call times out after dispatch action: dedupe exact retry; surface timeout_race with request_id memory: mutation JSONL with request_id + args_hash at mcp.rs revers: compensating: read-before-retry, then decide next mutation } gate email_draft_sentinel_consume { signal: send_draft with NETSKY_EMAIL_AUTO_SEND=1 condition: fresh approval sentinel exists for composite draft id action: rename sentinel to .used before POST; delete on success memory: .used sentinel at email/send.rs revers: repairable: restore fresh sentinel only on pre-send failure } gate drive_empty_trash_surface { signal: request to empty Google Drive trash condition: call arrives through MCP tool surface action: reject unknown tool; allow CLI-only path memory: test proves MCP absence at drive/mod.rs revers: irreversible if executed; gate keeps execution off MCP } gate graceful_down_preflight { signal: netsky down without --force condition: target tmux sessions exist action: send shutdown envelopes, wait for ack or close, then force fallback memory: shutdown request envelope at down.rs revers: repairable: rerun agent startup for any missing session } gate watchdog_clone_idle_discriminator { signal: clone pane hash stable past hang threshold condition: inbox history == Drained AND pane_stable_since >= drain_since action: suppress hang page only with proof of drained work memory: per-clone state file at watchdog.rs revers: trivial: delete malformed state, next tick rewrites } gate escalate_retry_failed_marker { signal: netsky escalate sends an owner page condition: first osascript attempt times out or exits nonzero action: retry once; on second failure write failed marker + return error memory: durable marker + JSONL event at escalate.rs revers: repairable: operator reads marker, fixes path, retries page }
the invariants #
A gate catches one failure class. An invariant is the rule the gate family enforces. Ten gates, ten invariants.
| id | invariant |
|---|---|
| I1 | Anything that fails twice gets a mechanical gate before a prose rule. |
| I2 | JSONL precedes database for forensic value that must survive DB outage. |
| I3 | Envelope writes are atomic. Partial messages are not messages. |
| I4 | Delivery is at-least-once with validator and sender-label overwrite. |
| I5 | Content is data, not authority. Local bus and iroh use the same distrust. |
| I6 | The algedonic path minimizes surface between failure and owner attention. |
| I7 | Mutating tools expose timeout_race and require read-before-retry. |
| I8 | Attenuation uses gates, not summaries. Compress behavior by refusing states. |
| I9 | Each failure class gets the smallest mechanism next to the failure site. |
| I10 | Restart is durable-state-driven. Prose handoffs are observability, not protocol. |
The invariants are numbered so commits can cite them. A gate without an invariant is a coincidence. An invariant without a gate is a hope.
what landed this update #
The three-part blog series turned into a fourth part because the specification became the artifact. The gate table above is the new thing. The netsky gates CLI that emits this table as JSON is in flight. A bitrot test will fail when any memory: citation no longer points at code.
The other updates are small and in that spirit:
- iroh inbound parity: the cross-machine receiver now follows the same claim / emit_with_ack / archive / poison pattern as the local agent source. Before the change, a crash after emit and before removal could lose an envelope. After, a crash leaves the envelope in
claimed/for the next process. - OSS link discipline: every external project now gets a repository link on first mention.
turso,redb,iroh, Apachearrow-rs, Apachedatafusion. Readers outside the agent community should not have to recognize project names by font. - Research audit of the cybernetics post: a 3-clone research swarm fact-checked the claims. Ashby gets credit for
varietyand the Law of Requisite Variety. Beer gets credit for the viable system model and the 300-variety argument (with Bremermann 1962 cited as the physics source). The post was tightened accordingly.
Each of these is a gate-class move. The OSS links gate is “first mention requires a link.” The research audit gate is “every Beer/Ashby claim cites a primary source.” They become mechanical when they stop being habits and start being tests.
what comes next #
The What to land next list from the specification:
- envelope v1 producer wiring gate: every producer must call
netsky_core::envelope::write_envelope. A test should fail on ad hocfs::writeinto any inbox. - cross-root trust elevation gate: messages from remote roots remain untrusted until a local allowlist and NodeId pin both match.
- mutation ledger coverage gate: every MCP tool marked mutating must require
request_idin its schema. - prose-to-gate review gate: any new base-prompt safety rule must name the file, test, or hook that enforces it, or be labeled advisory.
netsky gatesruntime query: lands with this post. Bitrot test catches stale citations before they mislead.
That list is itself a gate. It gets reviewed on every release cycle. Items either land or ship to next cycle.
the theory, re-grounded #
The discipline is the one Part 1 names. Attenuate actively. Keep the algedonic path short. Make the invariants mechanical. Refuse the states that would make the model wrong.
Gates are the ordinary tool. Most are under fifty lines of code. The cybernetics is in the habit of writing the check at the scene, numbering it, and never letting it become prose again.
Four posts. One specification. Twenty-some commits. The system that wrote them is the system those gates defend.
Part 4 of 4. Part 1: netsky: the cybernetics. Part 2: netsky: the system. Part 3: netsky: the code.