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:
- Commits
Stoppingstate to the owner store - Aborts active RPC handling and closes subscriptions
- Shuts down the private ICN pipe inter-process communication
- 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:
- Parses flags:
--debug,--parent-bound,--data-dir - Calls
launchAcnServerfrompackages/acn/src/server.ts - Constructs the
AcnServiceLifecycle - Binds HTTP listener to
127.0.0.1:10100 - 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.,
Loadon 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
- Client request hits
/model/loadvia RPC - ModelCommandsLive delegates to ModelSlotControllerLive
- Controller checks
LocalModelSourcesLivefor binary presence - If missing:
LocalModelSourcesLivedownloads from provider URL, validates hash/architecture - Binary verified: Controller spawns
icn(inference engine) child process - Process registered in slot projection; health monitored
- If failure: Controller triggers
Stoppingtransition 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 inservice-lifecycle.ts - Binary acquisition relies on the CLI wrapper in
binary.tsto validate ripgrep and launch the server; model binaries are fetched on-demand byLocalModelSourcesLive - Model lifecycle is slot-based:
ProviderModelCatalogLivediscovers,LocalModelSourcesLiveacquires,ModelSlotControllerLiveorchestrates, andModelCommandsLiveexposes 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →