Package Layering Architecture from Clients to ACN in Magnitude: Complete Guide
The package layering architecture in magnitudedev/magnitude enforces a strict four-tier hierarchy—clients (cli/web) → client-common → sdk → acn (daemon)—with each layer exposing only its public API and prohibiting direct imports from lower levels.
Magnitude is built on a hierarchical package structure that separates concerns and maintains strict import boundaries from the user interface down to the server daemon. This package layering architecture from clients to ACN is explicitly documented in the project's AGENTS.md file and implemented across the packages/ directory to ensure clean, maintainable, and testable code.
The Four-Layer Hierarchy
The core architectural relationship is defined in the root AGENTS.md file:
clients (cli/web) → client-common → sdk → acn (daemon)
Each layer has distinct responsibilities and strict export boundaries that prevent circular dependencies or implementation leakage.
Clients (CLI and Web)
The Clients layer contains UI-level code for both command-line and web interfaces. Client code may only import from @magnitudedev/client-common and @magnitudedev/sdk. Direct imports from lower layers—including acn, agent, or ai—are strictly prohibited by architectural convention.
Public API: @magnitudedev/client-common, @magnitudedev/sdk
client-common
The client-common layer provides shared state management, React hooks, and display synchronization components. It maintains a single connection-scoped Effect Query (AgentClient) that operates over the SDK instance, serving as the bridge between UI concerns and the portable RPC client.
Responsibilities: State management, hook implementations, display synchronization.
sdk
The sdk layer implements a private, portable Effect RPC client that handles fixed-endpoint admission, connection recovery, and optional service-starter capabilities. The SDK re-exports only pure protocol contracts from acn-protocol and contains no SQLite logic, process supervision, or query caching. It serves as the public RPC façade that completely hides ACN implementation details.
Public API: @magnitudedev/sdk
The SDK defines RPC methods using protocol schemas without importing the daemon:
// packages/sdk/src/rpc/session.ts
import { Rpc } from '@magnitudedev/acn-protocol';
export const startSession = Rpc.make('session.start', {
request: SessionStartRequestSchema,
response: SessionStartResponseSchema,
});
acn (daemon)
The acn layer hosts the server daemon that implements the Agent Control Network protocol. It manages the agent runtime, session handling, file operations, and display streams. This layer implements the RPC handlers defined in acn-protocol but exposes no public API to upper layers.
Responsibilities: Daemon runtime, session management, RPC handler implementation.
RPC handlers are implemented in the ACN package:
// packages/acn/src/handlers/session.ts
import { RpcHandler } from '@magnitudedev/acn-protocol';
export const startSessionHandler: RpcHandler = async (req) => {
// Daemon-level session creation logic
return { sessionId: createSession(req) };
};
Supporting Packages Outside the Core Chain
Several packages support the architecture without being part of the direct client-to-ACN import chain:
- daemon-management – Handles owner store, process supervision, binary acquisition, and OS-service implementation. Used only by privileged composition roots.
- acn-protocol – Defines wire contracts shared by SDK and ACN. Never imported directly by client code.
- ai – Contains provider-agnostic contract definitions for LLM interactions.
- providers – Implements concrete provider implementations and registries.
- agent, event-core, roles, storage – Provide runtime execution, event sourcing, role specialization, and persistent storage layers.
Data Flow Through the Architecture
When adding a new backend operation, developers must follow a strict path to maintain architectural integrity:
- Declare the RPC in
packages/acn-protocol/src/boundary/ - Implement the handler in the acn package
- Expose a method in the sdk package
- Optionally add caching or synchronization logic in client-common
This ensures a single source of truth and consistent replay policies across the entire stack.
Client Usage Pattern
Client code remains isolated from implementation details:
// packages/cli/src/commands/start.ts
import { useAgent } from '@magnitudedev/client-common';
import { startSession } from '@magnitudedev/sdk';
const session = await startSession({ name: 'test-run' });
SDK Facade Implementation
The client-common layer consumes the SDK without exposing RPC internals:
// packages/client-common/src/operations/start.ts
import { sdk } from '@magnitudedev/sdk';
export const start = sdk.makeRpc('session.start');
Strict Import Boundaries and Enforcement
The architecture enforces import direction through convention and documentation. The root AGENTS.md file explicitly defines the layering, while individual package AGENTS.md files (located in packages/client-common/, packages/sdk/, packages/acn-protocol/, and packages/acn/) provide detailed implementation notes for each layer.
Forbidden Pattern: Clients cannot import directly from acn or agent packages. All communication must flow through the SDK's RPC façade, ensuring that UI code remains agnostic to daemon implementation details, database schemas, or process management.
Summary
- The package layering architecture from clients to ACN follows a strict four-tier hierarchy: clients → client-common → sdk → acn.
- Clients (CLI/Web) may only import from
client-commonandsdk, never fromacnor internal runtime packages. - client-common manages state and synchronization using a single Effect Query over the SDK instance.
- sdk provides a portable RPC façade that hides daemon complexity and re-exports only pure protocol contracts from
acn-protocol. - acn implements the server daemon, session management, and RPC handlers without exposing internal APIs upward.
- New features must follow the declaration path:
acn-protocol→acn→sdk→client-common(optional).
Frequently Asked Questions
What is the exact import order from clients to ACN in Magnitude?
The exact import hierarchy is clients (cli/web) → client-common → sdk → acn (daemon). Each layer may only import from the layer immediately below it or from shared protocol packages like acn-protocol. Direct imports that skip layers—such as a client importing from acn—are prohibited by architectural convention.
Can clients in Magnitude import directly from the ACN daemon layer?
No. Clients are explicitly forbidden from importing directly from the acn package or any internal runtime packages (agent, ai, storage). All communication must occur through the @magnitudedev/sdk RPC façade, which isolates UI code from daemon implementation details and database dependencies.
Where are RPC contracts defined in the Magnitude architecture?
RPC contracts are defined in the acn-protocol package, specifically within packages/acn-protocol/src/boundary/. This package serves as the source of truth for wire contracts shared between the SDK and ACN layers, ensuring type safety across the client-server boundary without creating circular dependencies.
How does Magnitude handle state synchronization between layers?
State synchronization is handled primarily in the client-common layer, which runs a connection-scoped Effect Query (AgentClient) over the SDK instance. This layer manages hooks and display synchronization, ensuring that UI components receive consistent state updates while the underlying SDK handles RPC communication with the ACN daemon.
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 →