Understanding the Layered Architecture of the Magnitude Project
The Magnitude project implements a strict package layering model that organizes code into five distinct tiers—clients, client-common, SDK, and ACN daemon—enforcing unidirectional dependencies from UI down to core services.
The magnitudedev/magnitude repository structures its TypeScript codebase as a vertical stack where each layer exposes only the abstractions it owns. This layered architecture prevents circular dependencies and isolates the web and CLI front-ends from implementation details of the agent runtime, AI providers, and event-sourcing infrastructure.
Package Layering Overview
The architecture follows a strict dependency chain:
clients (cli/web) → client-common → sdk → acn (daemon)
This directional flow ensures that lower-level packages never import from higher-level ones. According to AGENTS.md at the repository root, violating this rule requires refactoring the functionality into a core Effect Query primitive declared in packages/acn-protocol/src/boundary/ and implemented under packages/acn/src/boundary/.
The Five Core Layers
Clients (CLI and Web)
The client layer contains the command-line (cli) and web (web) front-ends. These applications import only from @magnitudedev/client-common and @magnitudedev/sdk. They explicitly never reach into acn, agent, acn-protocol, ai, or providers packages. This constraint keeps the UI thin and prevents business logic from leaking into presentation code.
client-common
The client-common package houses shared state, React hooks, and display synchronization logic. It provides the AgentClient Effect Query—a connection-scoped interface that communicates with the daemon over the SDK-provided ACN transport. All reusable client-side atoms, query-derived values, and side-effect utilities reside here, as documented in packages/client-common/AGENTS.md.
SDK
The SDK layer implements the typed RPC surface and daemon lifecycle management. Located in packages/sdk/src/, it exports DaemonSpawner, ProviderClient, and binary resolution utilities. The SDK re-exports ACN protocol types and acts as the bridge between UI concerns in client-common and the server-side runtime in acn. The JIT-RPC system in packages/sdk/src/jit-rpc/* generates the client-side RPC stubs from the boundary definitions.
ACN Protocol
The acn-protocol package defines the wire contract shared by the SDK and daemon. It contains the AcnBoundary interface in packages/acn-protocol/src/boundary/—the single source of truth for all remote procedure calls. The AcnRpc system derives the complete RPC protocol from this boundary, ensuring type safety across the network boundary.
ACN Daemon
The acn package hosts the server daemon that runs the agent runtime. It manages sessions, file operations, display streams, and implements the ACN protocol RPCs in packages/acn/src/boundary/. This layer contains the concrete business logic for agents, workers, tools, and projection materialization.
Supporting Infrastructure Packages
Beyond the core stack, several specialized packages handle cross-cutting concerns:
- agent – Agent runtime, projections, workers, tools, and display materialization (
packages/agent/src/*). - event-core – Event-sourcing infrastructure and addressed state management (
packages/event-core/*). - storage – Persistent storage for sessions, configuration, and authentication (
packages/storage/*). - ai – Provider-agnostic contracts including
Provider,ModelCatalog,BoundModel, andBaseCallOptions. - providers – Concrete AI provider implementations and registry.
- roles – Role and slot definitions for worker specialization.
Dependency Flow and Communication Patterns
The following patterns demonstrate how data flows through the stack. Clients consume reactive queries and mutations through the Effect Query system, while new RPC boundaries extend the protocol at the acn-protocol layer.
Consuming the SDK from a Client
// Client (e.g., web UI) – only imports public packages
import { useAgentClient } from '@magnitudedev/client-common';
import { ProviderClient } from '@magnitudedev/sdk';
// Create a connection-scoped client
const client = useAgentClient();
// Query a server-side session (client-common atom)
const session = client.Sessions.GetSession({ sessionId: 'abc123' });
const sessionData = useAtomValue(session);
// Trigger a mutation
const sendMessage = useAtomSet(client.Agent.SendMessage);
sendMessage({ text: 'Hello, world!' });
Extending the RPC Boundary
When adding functionality, developers declare the contract in acn-protocol and implement it in acn:
// 1. Define boundary in acn-protocol
export interface NewFeatureBoundary {
/** Fetch data from the daemon */
fetchData: (input: { id: string }) => QueryAtom<DataResult>;
}
// 2. Implement handler in acn (daemon side)
export class NewFeatureService implements NewFeatureBoundary {
constructor(private readonly store: Store) {}
fetchData({ id }) {
return QueryAtom.make(() => this.store.get(id));
}
}
Accessing New RPCs from the SDK
The SDK automatically exposes new boundary methods through its generated RPC client:
import { createAcnRpc } from '@magnitudedev/sdk';
const rpc = createAcnRpc();
const data = await rpc.NewFeature.fetchData({ id: 'xyz' });
Summary
- Magnitude enforces a strict five-layer architecture: clients → client-common → SDK → acn-protocol → acn.
- Clients never import from
acn,agent, orproviders, ensuring UI layers remain isolated from runtime internals. - acn-protocol serves as the single source of truth for RPC contracts, located in
packages/acn-protocol/src/boundary/. - Effect Query primitives bridge layers, with
AgentClientproviding the primary interface for client-daemon communication. - ACN RPC derives TypeScript clients automatically from boundary definitions, maintaining type safety across the network.
Frequently Asked Questions
What is the dependency direction in Magnitude's architecture?
Dependencies flow strictly downward from UI packages toward infrastructure. The cli and web clients depend on client-common and the SDK, while the SDK depends on acn-protocol and communicates with the acn daemon. Lower layers never reference higher layers, preventing circular dependencies.
How does the SDK communicate with the ACN daemon?
The SDK uses a typed RPC system (AcnRpc) generated from the AcnBoundary interface defined in packages/acn-protocol/src/boundary/. The SDK's createAcnRpc() function builds a complete RPC client from these definitions, while the daemon implements the corresponding handlers in packages/acn/src/boundary/.
Where is the RPC protocol defined in Magnitude?
The wire contract lives in the acn-protocol package, specifically within packages/acn-protocol/src/boundary/. This directory contains TypeScript interfaces that define all remote procedure calls, ensuring both the SDK client and ACN daemon share a single source of truth for the API surface.
How can I add new functionality to the Magnitude daemon?
Declare a new Effect Query primitive in the appropriate domain group under packages/acn-protocol/src/boundary/, then implement its handler under packages/acn/src/boundary/. The SDK will automatically expose the new capability through the AcnRpc system without requiring changes to the client-common or client packages.
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 →