# Magnitude Agent Runtime Projection Types: Regular vs Forked Explained

> Discover Magnitude's agent runtime projection types: RegularProjection for single states and ForkedProjection for branched state evolution. Understand which to use.

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

---

**The Magnitude agent runtime uses two primary projection types—RegularProjection for single-state snapshots and ForkedProjection for branched, parallel state evolution.**

Magnitude's event-driven agent architecture relies on **projections** to model and query state across its runtime. Understanding the different projection types is essential for building complex, branching agent behaviors. In this guide, we'll explore the two core projection families defined in the `magnitudedev/magnitude` repository and their practical implementations.

## What Are Projections in Magnitude?

Projections in Magnitude are **read-only, event-sourced state containers** that derive their data from a stream of domain events. They provide a typed, reactive interface for agents to observe and respond to state changes without directly mutating shared data.

The projection system lives primarily in [`packages/event-core/src/surface/index.ts`](https://github.com/magnitudedev/magnitude/blob/main/packages/event-core/src/surface/index.ts), where the two public projection types are exported for use throughout the agent runtime.

## Regular Projection: Single-State Snapshots

**RegularProjection** is the default projection type for linear, non-branching state. It maintains exactly one state object per projection ID, making it ideal for straightforward agent tracking.

### Definition and Implementation

In [`packages/event-core/src/surface/index.ts`](https://github.com/magnitudedev/magnitude/blob/main/packages/event-core/src/surface/index.ts) at line 91, the `RegularProjection` type is defined as:

```typescript
export interface RegularProjection<TId, TStateSchema> {
  readonly id: TId;
  readonly state: TStateSchema;
}

```

The factory function `Projection.define` creates these projections. Its implementation resides in [`packages/event-core/src/projection/define.ts`](https://github.com/magnitudedev/magnitude/blob/main/packages/event-core/src/projection/define.ts) at line 365:

```typescript
// packages/event-core/src/projection/define.ts#L365
export const define = <TEvent>() => <TDef extends ProjectionDefinition<TEvent>>(
  definition: TDef
): RegularProjection<InferId<TDef>, InferState<TDef>> => {
  // Projection factory implementation
};

```

### Practical Example

Here's a concrete `ChatTitleProjection` used in the agent runtime:

```typescript
import { Projection } from '@magnitude/event-core';
import { Schema } from '@effect/schema';
import type { AppEvent } from '../events.js';

export const ChatTitleProjection = Projection.define<AppEvent>()({
  name: 'ChatTitle',
  state: {
    title: Schema.String
  },
  signals: {
    setTitle: (title: string) => ({ title })
  }
});

```

**When to use RegularProjection:**
- Tracking conversation metadata (titles, timestamps, participant lists)
- Maintaining agent goals or current task status
- Storing configuration or routing state that doesn't branch

## Forked Projection: Parallel State Branches

**ForkedProjection** extends the projection model with **fork semantics**, allowing multiple independent branches of state to coexist and evolve separately. This enables speculative execution, parallel plan evaluation, and complex agent reasoning workflows.

### Definition and Implementation

Also in [`packages/event-core/src/surface/index.ts`](https://github.com/magnitudedev/magnitude/blob/main/packages/event-core/src/surface/index.ts) at line 98, the `ForkedProjection` type adds fork management capabilities:

```typescript
export interface ForkedProjection<TId, TStateSchema> {
  readonly id: TId;
  readonly forks: ReadonlyMap<ForkId, TStateSchema>;
  createFork(parentForkId?: ForkId): ForkId;
  mergeFork(forkId: ForkId): void;
  abandonFork(forkId: ForkId): void;
}

```

The factory `Projection.defineForked` is implemented in [`packages/event-core/src/projection/defineForked.ts`](https://github.com/magnitudedev/magnitude/blob/main/packages/event-core/src/projection/defineForked.ts) at line 385:

```typescript
// packages/event-core/src/projection/defineForked.ts#L385
export const defineForked = <TEvent>() => <TDef extends ProjectionDefinition<TEvent>>(
  definition: TDef
): ForkedProjection<InferId<TDef>, InferState<TDef>> => {
  // Fork-aware projection factory with branch management
};

```

### Practical Example

A `TaskGraphProjection` for parallel task planning:

```typescript
import { Projection } from '@magnitude/event-core';
import { Schema } from '@effect/schema';
import type { AppEvent } from '../events.js';

const TaskSchema = Schema.Struct({
  id: Schema.String,
  description: Schema.String,
  status: Schema.Literal('pending', 'in_progress', 'completed')
});

export const TaskGraphProjection = Projection.defineForked<AppEvent>()({
  name: 'TaskGraph',
  state: {
    tasks: Schema.Array(TaskSchema)
  },
  signals: {
    addTask: (task: typeof TaskSchema.Type) => ({ 
      tasks: [task] 
    }),
    updateTaskStatus: (taskId: string, status: string) => ({ 
      tasks: [] // Merged by projection logic
    })
  }
});

```

### Fork Lifecycle Operations

Agents interact with forked projections through three core operations defined in the interface:

| Operation | Purpose | Typical Usage |
|-----------|---------|-------------|
| `createFork(parentForkId?)` | Spawns a new state branch from an optional parent | Exploring alternative execution paths |
| `mergeFork(forkId)` | Integrates a completed fork back into its parent | Committing a successful plan variant |
| `abandonFork(forkId)` | Discards a fork without merging | Canceling failed or irrelevant branches |

**When to use ForkedProjection:**
- Evaluating multiple candidate plans in parallel
- Implementing backtracking or speculative reasoning
- Managing hierarchical or recursive task decomposition
- Running A/B or multi-variant agent behaviors

## Projection Type Comparison

| Aspect | RegularProjection | ForkedProjection |
|--------|-------------------|------------------|
| **State cardinality** | One state per ID | Multiple forks per ID |
| **Branching** | None | Native fork/merge/abandon |
| **Memory footprint** | Minimal | Scales with active forks |
| **API surface** | `define()` | `defineForked()` |
| **Source file** | [`define.ts`](https://github.com/magnitudedev/magnitude/blob/main/define.ts) | [`defineForked.ts`](https://github.com/magnitudedev/magnitude/blob/main/defineForked.ts) |
| **Best for** | Linear, temporal state | Exploratory, parallel state |

## Agent Runtime Integration

Both projection types are consumed through Magnitude's **surface layer**, which provides dependency injection tags for worker initialization. In `packages/agent/src/projections/`, concrete projections are wired into the agent runtime:

```typescript
// packages/agent/src/projections/index.ts
import { ChatTitleProjection } from './chatTitle.js';
import { TaskGraphProjection } from './taskGraph.js';
import { GoalProjection } from './goal.js';

export const agentProjections = [
  ChatTitleProjection,
  TaskGraphProjection,
  GoalProjection
] as const;

```

The runtime automatically manages projection lifecycle, event sourcing, and fork synchronization based on the projection type declared at definition time.

## Summary

- **RegularProjection** provides single-state, linear state tracking via `Projection.define()` in [`packages/event-core/src/projection/define.ts`](https://github.com/magnitudedev/magnitude/blob/main/packages/event-core/src/projection/define.ts)
- **ForkedProjection** enables parallel state branches via `Projection.defineForked()` in [`packages/event-core/src/projection/defineForked.ts`](https://github.com/magnitudedev/magnitude/blob/main/packages/event-core/src/projection/defineForked.ts)
- Both types share a common definition schema with signals, but differ in their runtime semantics and fork management capabilities
- The surface layer in [`packages/event-core/src/surface/index.ts`](https://github.com/magnitudedev/magnitude/blob/main/packages/event-core/src/surface/index.ts) exposes typed interfaces for both projection families
- Agent developers choose between these types based on whether their use case requires linear state evolution or exploratory branching

## Frequently Asked Questions

### What determines whether to use a regular or forked projection?

Use **RegularProjection** when your state follows a single timeline without alternatives—conversation history, current goals, or configuration. Use **ForkedProjection** when agents need to explore multiple possibilities simultaneously, such as evaluating different plans or speculating about outcomes. The overhead of fork management is only justified when branching semantics are required.

### How are forked projections garbage collected?

Abandoned forks are dereferenced and eligible for cleanup, though the exact timing depends on the runtime's event sourcing configuration. The `abandonFork()` operation explicitly signals that a branch will never merge, allowing the projection engine to release associated resources. Merged forks are compacted into their parent state history.

### Can a regular projection be converted to forked later?

No—projection type is fixed at definition time through the choice of `define()` versus `defineForked()`. However, you can model similar behavior by creating a new forked projection and migrating state through events. The type system enforces this distinction to prevent accidental complexity in simple state cases.

### Where are projection implementations tested in the codebase?

Core projection logic is tested in `packages/event-core/test/projection/`, with separate suites for regular projections ([`define.test.ts`](https://github.com/magnitudedev/magnitude/blob/main/define.test.ts)) and forked projections ([`defineForked.test.ts`](https://github.com/magnitudedev/magnitude/blob/main/defineForked.test.ts)). These tests verify event sourcing correctness, fork lifecycle operations, and merge semantics under concurrent access patterns.