How Magnitude's ACN Daemon Manages the Model Lifecycle: Process Supervision, Binary Acquisition, and Runtime Orchestration Explained

Magnitude's ACN (Agent Control Node) daemon uses a finite-state machine-driven service lifecycle to enforce single-process ownership, validates bundled dependencies like ripgrep, and orchestrates model discovery, download, and inference through a slot-based controller architecture.

The Magnitude ACN daemon is the core runtime that hosts authoritative service lifecycle management for the entire platform. Written in TypeScript and built on Effect-TS, it combines process supervision, dependency validation, and model lifecycle orchestration into a tightly-coupled, self-healing system. This article breaks down exactly how the daemon handles admission, health tracking, binary acquisition, and model serving—based on the actual source code in magnitudedev/magnitude.

Process Supervision and Ownership Admission

The ACN daemon implements a JIT (Just-In-Time) admission protocol to prevent split-brain scenarios and ensure only one process instance controls the service lifecycle at any time.

The Ownership Check: makeAcnServiceLifecycle

Before initializing expensive subsystems, a candidate daemon performs an atomic ownership claim in packages/acn/src/service-lifecycle.ts:

  • Reads the current owner row from the SQLite owner store
  • Proves the predecessor process group is absent (process death detected)
  • Atomically claims ownership via makeAcnServiceLifecycle

If ownership has already moved to another process, the candidate exits immediately—avoiding wasted initialization of the ICN pipe, model loading, and RPC handlers.

Health State Machine: AcnServiceLifecycleFsm

The daemon tracks its runtime state through a strict finite-state machine with four states:

State Behavior
Starting RPC returns 503 unavailable; subsystems initializing
Ready Full RPC dispatch to live AcnRpcApplication
Stopping Graceful shutdown in progress; no new requests accepted
Exited Process termination; external manager may acquire ownership

Transitions are guarded by AcnServiceLifecycleFsm.transition, ensuring single-flight semantics for critical operations like beginStopping.

Graceful Shutdown Sequence

Any component may trigger shutdown by calling beginStopping. The first caller wins (transition lock), then the daemon executes:

  1. Commits Stopping state to the owner store
  2. Aborts active RPC handling and closes subscriptions
  3. Shuts down the private ICN pipe inter-process communication
  4. Exits the process

External supervisors observe the exact process exit through the owner store and can safely spawn the next generation.

// From packages/acn/src/service-lifecycle.ts
const commitStopping = (current, request) => Effect.gen(function* () {
  if (current.lifecycle._tag === "Stopping") return false
  const next = AcnServiceLifecycleFsm.transition(
    current.lifecycle,
    "Stopping",
    { reason: request.reason, safeDetail: Option.fromNullable(request.detail) },
  )
  yield* Ref.set(runtime, { lifecycle: next, rpc: Option.none() })
  yield* Deferred.succeed(stopping, next)
  return true
})

Binary Acquisition and Runtime Bootstrapping

The ACN daemon executable at packages/acn/src/binary.ts serves as a thin CLI wrapper responsible for dependency validation and server launch.

CLI Structure and Commands

The binary exposes several subcommands through Effect-TS's Command API:

Command Purpose
doctor Validates bundled runtime dependencies
serve / server Starts the ACN RPC server
version Reports build version
coordination-revision Exposes consensus state

Dependency Verification with doctor

The daemon bundles ripgrep for log search operations. The doctor subcommand verifies functionality:

// From packages/acn/src/binary.ts
const doctor = Command.make("doctor", {}, () =>
  verifyRipgrep.pipe(
    Effect.flatMap(({ rgPath, version }) => Console.log(`ripgrep: ${version}\npath: ${rgPath}`)),
  ),
).pipe(Command.withDescription("Verify packaged ACN runtime dependencies"))

Server Launch: launchAcnServer

When serve is invoked, the CLI:

  1. Parses flags: --debug, --parent-bound, --data-dir
  2. Calls launchAcnServer from packages/acn/src/server.ts
  3. Constructs the AcnServiceLifecycle
  4. Binds HTTP listener to 127.0.0.1:10100
  5. Wires the RPC dispatcher to the lifecycle state

The resulting process owns the ACN daemon binary itself; model binaries are acquired separately through the model-slot controller.

// From packages/acn/src/binary.ts
const acn = Command.make(ACN_EXECUTABLE_NAME, { parentBound, debug, dataDir }, launchServer).pipe(
  Command.withDescription("Magnitude Agent Control Node"),
  Command.withSubcommands([serve, server, version, coordinationRevision, doctor]),
)

Model Lifecycle: Discovery, Acquisition, Loading, and Serving

The ACN daemon manages the complete model lifecycle through five coordinated subsystems in packages/acn/src/.

1. Catalog and Discovery: ProviderModelCatalogLive

Merges remote provider catalogs with local model entries to produce ProviderModelCatalogEntry records. This unified view enables consistent selection across cloud-hosted and on-premise models.

2. Local Model Sources: LocalModelSourcesLive

  • Scans the filesystem for downloaded model binaries
  • Registers discovered models with metadata
  • Watches for changes (file system events)
  • Downloads missing binaries when requested by the controller

3. Model Slot Controller: ModelSlotControllerLive

The central orchestrator for model execution. It manages slot actions (Load, Unload, Stop, Restart) and enforces:

  • Single-process-per-slot invariant: Only one inference child runs per slot
  • Action validity checking: Prevents invalid transitions (e.g., Load on an already-loading slot)
  • Projection state synchronization: Maintains authoritative view of slot status

4. Model Selection: ModelSelectionLive

Records which model a session actually uses. This feeds:

  • Usage telemetry
  • Ranking policies for model recommendations
  • Cost and performance optimization

5. RPC Commands: ModelCommandsLive

Exposes endpoints that clients invoke to trigger lifecycle changes:

Endpoint Action
/model/load Download if needed, verify, spawn inference process
/model/unload Terminate child process, clean temporary state
/model/stop Hard stop with optional cleanup
/model/restart Orchestrated stop-then-load with freshness check
// From packages/acn/src/model-commands.ts (simplified)
export const loadModel = (modelId: ModelId) =>
  Effect.flatMap(
    ModelSlotController,  // reference the live controller
    controller => controller.load(modelId) // triggers download if needed, then spawns the binary
  )

Complete Model Acquisition Flow

  1. Client request hits /model/load via RPC
  2. ModelCommandsLive delegates to ModelSlotControllerLive
  3. Controller checks LocalModelSourcesLive for binary presence
  4. If missing: LocalModelSourcesLive downloads from provider URL, validates hash/architecture
  5. Binary verified: Controller spawns icn (inference engine) child process
  6. Process registered in slot projection; health monitored
  7. If failure: Controller triggers Stopping transition via service lifecycle

All operations are guarded by the service lifecycle state—model actions are rejected if the daemon is not Ready, and any critical failure cascades to graceful shutdown to prevent orphaned processes.

Summary

  • Process supervision uses JIT admission and a four-state FSM (Starting → Ready → Stopping → Exited) to guarantee single-process ownership, implemented in service-lifecycle.ts
  • Binary acquisition relies on the CLI wrapper in binary.ts to validate ripgrep and launch the server; model binaries are fetched on-demand by LocalModelSourcesLive
  • Model lifecycle is slot-based: ProviderModelCatalogLive discovers, LocalModelSourcesLive acquires, ModelSlotControllerLive orchestrates, and ModelCommandsLive exposes RPC control
  • Failure handling is unified: any component can trigger beginStopping, which single-flights shutdown, closes the ICN pipe, and exits cleanly

Frequently Asked Questions

How does the ACN daemon prevent multiple instances from running simultaneously?

The daemon uses a SQLite-based ownership store and JIT admission protocol. Each candidate reads the owner row, verifies the predecessor process is dead, and performs an atomic compare-and-swap to claim ownership. If ownership changed between read and write, the candidate exits immediately without initializing subsystems.

What happens if model download fails during a load request?

The model-slot controller treats download failure as a terminal error for that action. The controller cleans up partial state, and if the failure is critical, propagates to the service lifecycle which may trigger a full daemon shutdown via beginStopping to ensure no orphaned processes remain.

How does the doctor command validate dependencies?

In binary.ts, verifyRipgrep executes ripgrep --version against the bundled binary and extracts the version string. This confirms the binary is present, executable, and functional. Currently ripgrep is the only bundled dependency; the daemon acquires model binaries dynamically through the local model sources subsystem.

What is the ICN pipe and why does it close during shutdown?

ICN (Internal Control Network) is the private inter-process communication channel between the ACN daemon and spawned inference processes. Closing it during Stopping state ensures clean termination semantics: inference children detect pipe closure and exit gracefully, preventing zombie processes and resource leaks when the daemon restarts.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →