How Netsky Leverages the Codex Fork

The Codex fork is not a tool Netsky occasionally shells out to. It is the thread engine underneath the current manager and worker system.

That is the distinction that matters now. Codex CLI joins the constellation covered getting Codex into Netsky. iMessage for Codex CLI (and Claude Code) covered getting phone-originated input into a session. This post is about the current split after that: Netsky owns orchestration, durable state, and routing; the Codex fork owns live thread execution (src/crates/netsky-codex/src/lib.rs:81-165, src/crates/netsky-agent/src/lib.rs:141-178, src/crates/netsky-db/src/lib.rs:91-229).

flowchart LR
    daemon[netsky-daemon]
    db[(meta.db)]
    agent[netsky-agent]
    fork[netsky-codex fork runtime]
    thread[Codex thread]
    events[event stream]
    web[netsky-web]
    comms[netsky-comms]

    daemon --> agent
    agent --> fork
    fork --> thread
    thread --> events
    events --> daemon
    agent --> db
    daemon --> db
    comms --> db
    web --> db

What Netsky Hands to the Fork #

Netsky decides that an actor exists, what directory it should work in, what prompt it should start with, and whether it is a manager or a worker.

The handoff to the fork is compact. netsky-agent builds an ActorLaunchSpec, creates the actor and session records, ensures the channel and attach directories exist, and then calls ForkCodexRuntime::start_session(...) with three important pieces of context: actor id, cwd, and initial prompt (src/crates/netsky-agent/src/lib.rs:339-378, src/crates/netsky-agent/src/lib.rs:406-460, src/crates/netsky-codex/src/lib.rs:118-159).

That is the boundary in one move. Netsky does not reimplement a model loop. It hands the fork a configured thread and keeps the surrounding system state on its own side.

What the Fork Gives Back #

The fork gives Netsky a durable Codex thread id, an input channel for new turns, and an event stream for what happened inside the session.

ForkCodexSession is intentionally small: submit(...) pushes new text into the thread, and subscribe() exposes a broadcast receiver of summarized Codex events. Underneath, spawn_thread_loop turns each inbound text into Op::UserInput and forwards thread events back out as a normalized CodexEvent structure (src/crates/netsky-codex/src/lib.rs:168-240).

That is why Netsky can stay focused on orchestration. The fork is doing the live conversational and tool-execution work. Netsky just needs a clean way to feed it turns and observe results.

How Managers and Workers Use It #

Managers and workers are not special runtimes. They are different prompts and different ownership records on top of the same forked thread substrate.

Starting a manager upserts the actor record, builds the manager prompt, ensures a session, and optionally submits the stated objective into that thread. Starting a worker goes one step further: it creates a real task record, marks it in-progress, upserts both manager and worker actors, and then submits the task text into the worker session (src/crates/netsky-agent/src/lib.rs:141-178, src/crates/netsky-agent/src/lib.rs:203-260).

That is an important division of labor. The fork does not know what a priority is, who owns a task, or whether work should be delegated. Netsky does. The fork only has to run the thread it was given.

How Restart and Resume Work #

Restart behavior is another place where the boundary is clearer in code than in diagrams.

On daemon startup, Netsky reconciles managed actors, decides which ones should be resumed, recreates sessions when needed, and explicitly resumes manager0. If the restart happened after owner input was already queued, Netsky replays those pending inputs into the new manager0 thread instead of relying on terminal memory (src/crates/netsky-daemon/src/lib.rs:286-390, src/crates/netsky-daemon/src/lib.rs:758-799).

On the agent side, ensure_actor_session and recovery_message_for_actor decide what a resumed actor should be told when its session comes back. That is Netsky policy sitting above Codex execution again: resume the worker with its active task, or resume the manager with its coordination objective and queue state (src/crates/netsky-agent/src/lib.rs:263-275, src/crates/netsky-agent/src/lib.rs:391-404).

The fork is not coordinating recovery. It is receiving a fresh thread plus fresh instructions from the orchestration layer that already knows what durable work was open.

How Channel Integration Works Now #

The current channel story is not a sidecar hack. It is part of the normal manager input path.

When Netsky routes a recorded input to an actor, it first writes an actor_inputs row keyed to the current Codex thread, then renders a plain channel envelope block and submits that block into the session. If the submit fails, the pending queue item is cancelled instead of silently drifting (src/crates/netsky-agent/src/lib.rs:278-315, src/crates/netsky-db/src/lib.rs:746-814).

The return path uses the same separation. The daemon subscribes to agent output events, matches them back against consumed inputs, and if the original source was iMessage it bridges the resulting manager reply back out through netsky-comms (src/crates/netsky-daemon/src/lib.rs:694-755).

That is what “Netsky leverages the fork” means in practical terms. Netsky does not need the fork to understand iMessage, tasks, or actor queues natively. It only needs the fork to keep a stable thread alive and accept the next envelope.

Where the Boundary Actually Sits #

Netsky owns:

  • actor, session, task, message, delivery, note, and log records
  • restart and resume policy
  • owner-message routing and replay
  • manager and worker prompt selection
  • web and CLI surfaces over the shared state

The fork owns:

  • thread creation
  • thread-local user input submission
  • tool execution inside the Codex loop
  • event emission back out of the thread

That is a better split than treating Codex as a black-box command or trying to bury orchestration inside the model runtime. Each side carries the job it is actually good at.

Older live Codex posts explained how Codex got into the system or how one bridge around it worked. This is the follow-on: once the fork is inside Netsky, it becomes the execution substrate, while Netsky remains the orchestrator that keeps work durable, resumable, and inspectable.