Skip to content

Architecture

Last updated 2 days ago Β· d13fa3c

↑ Updated 2 days ago

"fix(debt): Wave 3 (round 1) β€” delete orchestration package + dead RA_ flags" Β· d13fa3c Β· 2026-07-20

Reactive Agents uses a layered, composable architecture built on Effect-TS.

The reasoning kernel was reorganized in v0.10 to group code by capability. If you’re contributing or reading the source, this is the layout:

  • Directorypackages/reasoning/src/kernel/
    • Directorycapabilities/
      • Directoryact/ tool execution, gating, parsing, healing pipeline
        • …
      • Directoryattend/ context utils + tool formatting
        • …
      • Directorycomprehend/ task intent
        • …
      • Directorydecide/ arbitrator (single-owner termination)
        • …
      • Directoryreason/ think Β· think-guards Β· stream parser
        • …
      • Directoryreflect/ loop detector Β· reactive observer Β· strategy evaluator
        • …
      • Directorysense/ step utils
        • …
      • Directoryverify/ evidence grounding Β· quality utils Β· verifier
        • …
    • Directoryloop/
      • runner.ts main 12-phase orchestrator
      • react-kernel.ts ReAct strategy kernel
      • terminate.ts single-owner termination helper
      • auto-checkpoint.ts
      • output-assembly.ts
      • output-synthesis.ts
    • Directorystate/ kernel-state Β· kernel-hooks Β· kernel-constants
      • …
    • Directoryutils/ diagnostics Β· ICS coordinator Β· lane controller
      • …

The single-owner termination invariant (M9 mechanism, 100% path coverage) is enforced by kernel/loop/terminate.ts plus a CI lint guard at scripts/check-termination-paths.sh β€” no path bypasses the arbitrator.

Internally the reasoning harness is a one-directional loop β€” a small DAG where each stage reads only from the stage before it, with no back-edges. This is what makes a run’s decisions replayable: given the same ledger, every downstream read is a pure function.

Contract β†’ Ledger β†’ Assessment β†’ Control β†’ Actuators β†’ Projector
StageRole
ContractThe typed goal β€” β€œwhat does DONE mean for this run?” Compiled once at run start from the task (plus any declared .withContract()) and then frozen: requirements, deliverables, constraints, horizon, acceptance policy.
LedgerThe append-only event store everything else projects from β€” tool invocations, artifacts (path + content digest), verifier verdicts, evidence claims (twelve fact families). It is the single source of run history and rides crash-resume. Full entry taxonomy + honest-compaction rules: The evidence ledger.
AssessmentA pure, per-iteration read of where the run stands, derived from contract Γ— ledger: requirements satisfied/outstanding, deliverables produced/missing, evidence delta, run phase (orient / gather / execute / synthesize / verify), pace band, health. Emitted as an AssessmentEmitted trace event every iteration. Default-on; opt-in levers (.withLongHorizon() / .withAdaptiveHarness()) only react to it. Field-by-field: Run assessment.
ControlOne proposal β†’ resolver that picks a single action per iteration from a documented total order (continue, nudge, switch strategy, redirect, escalate, terminate). No two subsystems race to steer the loop.
ActuatorsThe effects that carry out the chosen action β€” guards, strategy switch, the terminal gate (which consults contract requirement satisfaction against the ledger).
ProjectorThe single authority that renders the prompt window each turn β€” deciding what context, references, and outstanding requirements the model sees. One reference grammar is shared by the projector, the recall gate, and step references, so every reference rendered into the prompt is resolvable via recall(...).

Each subsystem is fenced by a grep-able enforcement script in scripts/, so a change that reintroduces a back-edge (e.g. Assessment reading loop state directly, or a second termination owner) fails CI rather than drifting silently. The receipt’s deliverables[] and the rax diagnose replay view are both projections of this same ledger.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ ReactiveAgentBuilder β”‚ Public API
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ ExecutionEngine β”‚ 12-phase lifecycle
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ β”‚ β”‚
β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”
β”‚ Memory β”‚ β”‚ Reasoning β”‚ β”‚ Tools β”‚
β”‚ (L2) β”‚ β”‚ (L3) β”‚ β”‚ (L8) β”‚
β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
β”‚ β”‚ β”‚
β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”
β”‚ LLM Provider (L1.5) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Core Services (L1) β”‚
β”‚ EventBus Β· AgentService Β· TaskService β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

These can be enabled independently:

LayerPackageWhat It Does
Guardrails@reactive-agents/guardrailsInput/output safety
Verification@reactive-agents/verificationFact-checking, semantic entropy
Cost@reactive-agents/costModel routing, budget enforcement
Identity@reactive-agents/identityAgent certificates, RBAC
Observability@reactive-agents/observabilityTracing, metrics, logging
Interaction@reactive-agents/interaction5 autonomy modes
Prompts@reactive-agents/promptsTemplate engine
A2A@reactive-agents/a2aAgent-to-Agent protocol (JSON-RPC, Agent Cards, SSE)
Gateway@reactive-agents/gatewayPersistent autonomous harness: heartbeats, crons, webhooks, policy engine
Reactive Intelligence@reactive-agents/reactive-intelligenceEntropy sensor, reactive controller, local learning, optional telemetry; integrates with kernel + EventBus
Core ← LLM Provider ← Memory
← Reasoning
← Tools
Core ← Guardrails (standalone)
← Verification (standalone)
← Cost (standalone)
← Identity (standalone)
← Observability (standalone)
← Interaction (needs EventBus)
← Orchestration (standalone)
← Prompts (standalone)
← A2A (needs Core + Tools)
← Gateway (needs Core EventBus)

Every layer is an Effect Layer β€” a recipe for building a service. Layers compose through Layer.merge and Layer.provide:

import { createRuntime } from "@reactive-agents/runtime";
// The runtime composes all enabled layers into a single Layer
const runtime = createRuntime({
agentId: "my-agent",
provider: "anthropic",
enableGuardrails: true,
enableReasoning: true,
enableCostTracking: true,
});
// This Layer provides ALL services needed by the ExecutionEngine

This means:

  • No singletons β€” Each agent gets its own service instances
  • No global state β€” Everything is scoped to the Layer
  • Testable β€” Swap any layer with a test implementation
  • Tree-shakeable β€” Disabled layers aren’t loaded