# How Dependencies Are Managed Across Magnitude's Package Layers

> Discover how Magnitude enforces strict vertical dependency management across its package layers using workspace-level packages and `workspace:*` references for robust code organization. Learn more!

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

---

**Magnitude enforces strict vertical dependency management through workspace-level packages that form a four-layer stack, where each layer only imports from layers directly below it using `workspace:*` references in [`package.json`](https://github.com/magnitudedev/magnitude/blob/main/package.json) files.**

Magnitude is organized as a monorepo of workspace-level packages that maintain a strict vertical hierarchy. This architecture prevents circular imports and minimizes the public API surface by ensuring that higher-level layers like the CLI and web clients never depend on implementation details from lower-level daemon or protocol layers.

## The Four-Layer Architecture

Magnitude's dependency management relies on a strict vertical stack of four distinct layers. Each layer only depends on the layers directly below it, preventing circular imports and keeping the public API surface minimal.

| Layer | Purpose | Allowed imports (dependencies) |
|-------|---------|--------------------------------|
| **clients** (CLI / web) | UI entry points | `@magnitudedev/client-common`, `@magnitudedev/sdk` only |
| **client-common** | Shared UI state, hooks, display sync | Depends on `@magnitudedev/sdk` and utility libs |
| **sdk** | Typed RPC client, daemon lifecycle, provider helpers | Depends on low-level protocol & core libraries (`acn-protocol`, `ai`, `providers`, …) |
| **acn** (daemon) | Server-side agent runtime, file ops, display streams | Depends on `acn-protocol`, `agent`, `storage`, `roles`, … |

The layering rules are documented in the project's central guide in [`AGENTS.md`](https://github.com/magnitudedev/magnitude/blob/main/AGENTS.md) (lines 6-16). According to this documentation, higher layers cannot reach into lower-level implementation details, ensuring clear separation of concerns across the codebase.

## Workspace References and Layer Enforcement

Each package in the monorepo uses **workspace references** (`"workspace:*"`) to declare dependencies on other internal packages. This approach allows package managers like Bun, PNPM, or Yarn to resolve them to the exact local version, guaranteeing that the layer hierarchy stays consistent across the whole codebase.

In [`packages/sdk/package.json`](https://github.com/magnitudedev/magnitude/blob/main/packages/sdk/package.json) (lines 29-40), the SDK declares its runtime dependencies on the core Effect ecosystem and lower-level packages it needs to expose RPC types:

- `@magnitudedev/acn-protocol`
- `@magnitudedev/ai`
- `@magnitudedev/providers`

Similarly, [`packages/client-common/package.json`](https://github.com/magnitudedev/magnitude/blob/main/packages/client-common/package.json) (lines 25-33) reflects its constrained import scope, only listing `@magnitudedev/sdk` and UI-related libraries. The protocol layer at [`packages/acn-protocol/package.json`](https://github.com/magnitudedev/magnitude/blob/main/packages/acn-protocol/package.json) (lines 21-28) sits just below the SDK, bringing in Effect platform and `@magnitudedev/icn-protocol` without any dependencies on `sdk` or `client-common`.

The daemon layer at [`packages/acn/package.json`](https://github.com/magnitudedev/magnitude/blob/main/packages/acn/package.json) (lines 14-30) depends on `acn-protocol` plus domain-specific packages like `agent`, `storage`, and `roles`, but strictly excludes any dependencies on the SDK or client layers above it.

## Adding Dependencies Across Package Layers

When extending Magnitude's functionality, developers must follow the **dependency management workflow** to maintain architectural integrity:

1. **Create a new shared library** under `packages/` (e.g., `utils`).
2. **Export it** in its [`package.json`](https://github.com/magnitudedev/magnitude/blob/main/package.json) with proper entry points.
3. **Reference it** from any higher layer by adding a `"workspace:*"` entry to that layer's [`package.json`](https://github.com/magnitudedev/magnitude/blob/main/package.json).
4. **Run the workspace installer** (`bun install` or `pnpm install`) to rewrite the import graph.

Because each layer only lists lower-layer packages in its dependencies, the package manager enforces the architecture automatically. Attempting to import from a higher layer will result in a resolution error.

## Practical Implementation Examples

### Creating a New Utility Package

To add a new utility to the SDK layer, first initialize the package:

```bash
mkdir -p packages/my-utils && cd packages/my-utils
pnpm init -y

```

Configure the [`package.json`](https://github.com/magnitudedev/magnitude/blob/main/package.json) with workspace-compatible exports:

```json
{
  "name": "@magnitudedev/my-utils",
  "version": "0.0.1",
  "private": true,
  "type": "module",
  "main": "src/index.ts",
  "exports": { ".": "./src/index.ts" },
  "scripts": { "typecheck": "tsc --noEmit" },
  "dependencies": {
    "effect": "^3.21.2"
  }
}

```

Then add the workspace reference to the SDK layer:

```bash
cd ../sdk
pnpm add @magnitudedev/my-utils@workspace:*

```

The resulting entry in [`packages/sdk/package.json`](https://github.com/magnitudedev/magnitude/blob/main/packages/sdk/package.json) shows:

```json
{
  "dependencies": {
    "@magnitudedev/my-utils": "workspace:*"
  }
}

```

Now the SDK can import utilities while `client-common` and `clients` layers remain unchanged until explicitly updated.

### Consuming Lower-Layer Services in the Daemon

The `acn` daemon demonstrates strict adherence to layer ordering by only importing from lower-level packages:

```typescript
// packages/acn/src/main.ts
import { Agent } from "@magnitudedev/agent"
import { Storage } from "@magnitudedev/storage"
import { AcnRpc } from "@magnitudedev/acn-protocol"

export const runDaemon = Effect.gen(function* (_) {
  const storage = yield* _(Storage)
  const rpc = yield* _(AcnRpc)
  const agent = new Agent({ storage, rpc })
  return agent.start()
})

```

All imports follow the hierarchy: `acn` → `acn-protocol` → `agent`/`storage`, never the reverse direction.

## Key Source Files and Configuration

| File | Role | Location |
|------|------|----------|
| [`AGENTS.md`](https://github.com/magnitudedev/magnitude/blob/main/AGENTS.md) | Defines the high-level layering policy (lines 6-16) | [`AGENTS.md`](https://github.com/magnitudedev/magnitude/blob/main/AGENTS.md) |
| [`packages/sdk/package.json`](https://github.com/magnitudedev/magnitude/blob/main/packages/sdk/package.json) | Shows SDK dependencies on lower layers (lines 29-40) | [`packages/sdk/package.json`](https://github.com/magnitudedev/magnitude/blob/main/packages/sdk/package.json) |
| [`packages/client-common/package.json`](https://github.com/magnitudedev/magnitude/blob/main/packages/client-common/package.json) | Demonstrates client-common's limited imports (lines 25-33) | [`packages/client-common/package.json`](https://github.com/magnitudedev/magnitude/blob/main/packages/client-common/package.json) |
| [`packages/acn-protocol/package.json`](https://github.com/magnitudedev/magnitude/blob/main/packages/acn-protocol/package.json) | Illustrates the protocol layer's low-level deps (lines 21-28) | [`packages/acn-protocol/package.json`](https://github.com/magnitudedev/magnitude/blob/main/packages/acn-protocol/package.json) |
| [`packages/acn/package.json`](https://github.com/magnitudedev/magnitude/blob/main/packages/acn/package.json) | Shows daemon layer's dependencies (lines 14-30) | [`packages/acn/package.json`](https://github.com/magnitudedev/magnitude/blob/main/packages/acn/package.json) |

These configuration files together reveal the strict, top-down dependency model that keeps Magnitude modular, testable, and easy to evolve.

## Summary

- **Strict vertical stack**: Magnitude uses four distinct layers (clients, client-common, sdk, acn) where each layer only depends on layers directly below it.
- **Workspace references**: All internal dependencies use `"workspace:*"` syntax to ensure deterministic builds and eliminate version drift.
- **Architectural enforcement**: The [`package.json`](https://github.com/magnitudedev/magnitude/blob/main/package.json) configurations in each layer physically prevent imports from higher layers, eliminating circular dependencies.
- **Clear upgrade paths**: When lower-level packages change their public API, only the immediately-above layer requires updates, preserving stability for all other layers.
- **Documented constraints**: The [`AGENTS.md`](https://github.com/magnitudedev/magnitude/blob/main/AGENTS.md) file explicitly defines the layering rules that govern how dependencies are managed across Magnitude's package layers.

## Frequently Asked Questions

### How does Magnitude prevent circular dependencies between packages?

Magnitude prevents circular dependencies through its strict vertical layer architecture enforced by workspace [`package.json`](https://github.com/magnitudedev/magnitude/blob/main/package.json) configurations. Each layer explicitly lists only lower-layer packages in its dependencies, and the package manager resolves `workspace:*` references locally. If a developer attempts to import from a higher layer (e.g., `acn` importing from `sdk`), the module resolution fails immediately because the higher-layer package is not listed in the lower layer's dependencies.

### What package managers support Magnitude's workspace dependency management?

Magnitude supports Bun, PNPM, and Yarn for workspace dependency resolution. All three package managers correctly interpret the `"workspace:*"` protocol used throughout the monorepo, rewriting these imports to point to the exact local package versions during installation. This ensures consistent builds regardless of which tool a developer chooses.

### How do I add a new shared utility that multiple layers can use?

Create a new package under `packages/` (e.g., `packages/shared-utils`), configure its [`package.json`](https://github.com/magnitudedev/magnitude/blob/main/package.json) with the name `@magnitudedev/shared-utils`, and add it to the lowest layer that needs it. If only the SDK and above require it, add `"@magnitudedev/shared-utils": "workspace:*"` to [`packages/sdk/package.json`](https://github.com/magnitudedev/magnitude/blob/main/packages/sdk/package.json). The utility will then be available to the SDK layer and can propagate upward to `client-common` and `clients`, but it will remain inaccessible to lower layers like `acn-protocol` or `acn` unless explicitly added to their dependencies.

### Why can't the client layer import directly from `acn-protocol`?

The **clients** layer (CLI and web interfaces) is restricted to importing only from `@magnitudedev/client-common` and `@magnitudedev/sdk` to maintain architectural boundaries. This restriction prevents UI entry points from becoming coupled to low-level protocol implementation details or daemon-specific logic. By forcing all communication through the SDK layer, Magnitude ensures that protocol changes only require updates in the SDK and below, leaving the client interfaces stable and reducing the public API surface area.