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

> Learn how Magnitude's ACN daemon manages the model lifecycle. Discover process supervision, binary acquisition, and runtime orchestration for efficient model deployment.

- Repository: [Magnitude/magnitude](https://github.com/magnitudedev/magnitude)
- Tags: internals
- Published: 2026-09-06

---

**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`](https://github.com/magnitudedev/magnitude/blob/main/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.

```ts
// 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`](https://github.com/magnitudedev/magnitude/blob/main/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:

```ts
// 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`](https://github.com/magnitudedev/magnitude/blob/main/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.

```ts
// 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 |

```ts
// 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`](https://github.com/magnitudedev/magnitude/blob/main/service-lifecycle.ts)
- **Binary acquisition** relies on the CLI wrapper in [`binary.ts`](https://github.com/magnitudedev/magnitude/blob/main/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`](https://github.com/magnitudedev/magnitude/blob/main/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.