clones are managers. clis are workers.

Netsky draws a hard line between judgment and execution. Clones hold context, pick the next move, and watch the return path. Programs perform the side effect. That split is why the same system shape works across Claude Code and Codex instead of collapsing into one policy per harness (src/crates/netsky-core/src/consts.rs:134-169, src/crates/netsky-cli/src/cli.rs:725-837).

flowchart LR
    A[inbound event] --> B[clone]
    B --> C{decide}
    C --> D[MCP read path]
    C --> E[netsky CLI worker]
    E --> F[durable state or envelope]

MCP stays on the left side of that diagram. It delivers inbound events. The CLI owns work. The current .mcp.json exposes four sources and nothing else: agent, imessage, email, and iroh (.mcp.json:1-20). The channel CLI comment says the same thing in plainer terms: the agent MCP surface is emit-only now, and shell sends route through netsky channel (src/crates/netsky-cli/src/cmd/channel.rs:1-18).

That boundary is not style. It is control.

the manager boundary #

A clone does not need a giant toolbag. It needs enough local surface to inspect state, edit files, run programs, and read the web. ALLOWED_TOOLS_CLONE is eight tools wide: Bash,Edit,Glob,Grep,Read,WebFetch,WebSearch,Write. The clone deny set blocks Agent,NotebookEdit,Task (src/crates/netsky-core/src/consts.rs:134-140). The integration hook proves the block is real. tests/integration/test-clone-tool-deny-hook.sh feeds a fake Task call into a clone session and expects clone tool policy: Task is blocked (tests/integration/test-clone-tool-deny-hook.sh:40-70).

The broader agent surfaces are still narrow where it matters. agent0 and agentinfinity get more harness tools, but the code denies Agent,CronCreate,CronDelete,CronList,RemoteTrigger,ScheduleWakeup for both (src/crates/netsky-core/src/consts.rs:145-169). The source comment explains why. Claude-side self-scheduling leaks across sessions. Scheduling belongs in netsky loop and netsky cron. Sub-clone recursion belongs in netsky clone (src/crates/netsky-core/src/consts.rs:153-167).

That is the manager rule in executable form. The clone decides. The repo owns the verbs.

surfacealloweddenied
cloneBash,Edit,Glob,Grep,Read,WebFetch,WebSearch,WriteAgent,NotebookEdit,Task
agent0orchestration plus shell and file toolsAgent,CronCreate,CronDelete,CronList,RemoteTrigger,ScheduleWakeup
agentinfinityagent0 plus WebFetch,WebSearchsame deny set

The point of that table is not austerity. It is portability. If a clone can only complete useful work by reaching into one harness-specific mutation surface, the architecture is already off the rails.

the worker surface #

The worker surface is the netsky binary. src/crates/netsky-cli/src/cli.rs wires imessage, email, calendar, tasks, drive, channel, cron, loop, ai, and clone as first-class commands (src/crates/netsky-cli/src/cli.rs:263-286, src/crates/netsky-cli/src/cli.rs:320-367, src/crates/netsky-cli/src/cli.rs:618-837). The concrete subcommands do the obvious things: netsky imessage send requires exactly one of --chat or --owner (src/crates/netsky-cli/src/cmd/imessage.rs:4-47), netsky email send and draft own email mutations (src/crates/netsky-cli/src/cmd/email.rs:4-123), netsky loop tick writes loop envelopes with from=agentloop (src/crates/netsky-cli/src/cmd/loop_cmd.rs:140-185), and netsky cron tick writes cron envelopes with from=agentcron and kind=cron (src/crates/netsky-cli/src/cmd/cron.rs:149-208).

netsky clone brief briefs/session5.md --type codex --workspace session5 --agent 7
netsky channel send agent7 "tighten the diagram labels" --from agent0
netsky imessage send --owner "wave landed"
netsky email send --from cody@example.com --to cody@example.com --subject "canary" --text "ok"
netsky loop create 15m "check the next merge window"
netsky cron add morning-brief "0 11 * * *" agent0 /morning-brief
netsky ai run --model codex-gpt-5.4 --detach "summarize this diff"

Those are not decorative examples. test-clone-brief-codex-delivery.sh verifies that netsky clone brief starts a resident Codex pane and delivers the brief into it (tests/integration/test-clone-brief-codex-delivery.sh:71-104). test-netsky-ai-status-wait-cat.sh follows a detached netsky ai run handle across status, wait, and cat (tests/integration/test-netsky-ai-status-wait-cat.sh:16-51). docs/cron.md documents the same cron surface operators use in the repo (docs/cron.md:3-34).

one bus, two runtimes #

The bus stays boring on purpose. netsky channel drain claims inbox files, emits them, and archives them. netsky channel send writes one envelope into the target inbox. netsky channel forward-outbox watches a Codex outbox, rewrites from to the owning agent id, synthesizes to=agent0 if needed, and forwards the normalized envelope into agent0’s inbox (src/crates/netsky-cli/src/cmd/channel.rs:7-24, src/crates/netsky-cli/src/cmd/channel.rs:142-257, src/crates/netsky-cli/src/cmd/channel.rs:1142-1168).

That is the runtime story in one paragraph. Claude and Codex do not expose the same harness features. Netsky does not try to make them identical. It gives both runtimes the same bus and the same worker binary. The policy stays in repo code instead of evaporating into prompt folklore (src/crates/netsky-cli/src/cmd/channel.rs:31-58, src/crates/netsky-core/src/consts.rs:153-169).

sequenceDiagram
    participant S as source
    participant C as clone
    participant N as netsky CLI
    participant B as bus/state
    S->>C: inbound envelope
    C->>N: netsky <verb>
    N->>B: write effect
    B-->>C: next visible state

The payoff is smaller than “general intelligence” and larger than “tool cleanup”. There is one mutation surface to test. There is one place to audit retries and timeouts. There is one operator vocabulary. The prompt can be shorter because the program is stronger.

If you want the historical arc behind that cut, past, present, future system architecture owns it. This post is just the current rule.

what this is not #

This is not a claim that clones are passive routers. They still read, decide, critique, and coordinate. netsky clone brief|status|wait|kill|ls exists because orchestration is real work (src/crates/netsky-cli/src/cli.rs:806-837). The claim is narrower. A manager should not also be the transport, the scheduler, and the mutation API. Netsky keeps those roles separate so the system can survive a runtime swap without a rewrite.