Architecture
Technical architecture documentation covering 13+ components of the Prismatic Platform.
|
Component
|
Action |
|---|---|
|
|
View |
No architecture components match your search.
Technical deep-dive into Prismatic Platform's deterministic, fault-tolerant architecture built on Elixir/OTP. The platform runs as 93 OTP applications on a single BEAM node, coordinated through supervision trees, PubSub event buses, and a pluggable storage adapter layer -- achieving microsecond inter-service latency without the operational complexity of distributed microservices.
Abstract
This section documents the architectural decisions, runtime characteristics, and design patterns that underpin the Prismatic Platform. The architecture is organized around three core principles: fault tolerance through OTP supervision (every stateful component lives in a supervised process tree with automatic restart), data consistency through event sourcing (system state is derived from an append-only event log, enabling full auditability and temporal queries), and cognitive reliability through the NABLA epistemic pipeline (all beliefs formed by the system pass a formal Trinity Gate before influencing decisions).
The platform rejects the microservice-over-HTTP pattern in favour of a monolithic deployment of 93 OTP applications sharing a single BEAM virtual machine. This design eliminates network serialization overhead between components while preserving modularity through Elixir's umbrella project structure and compile-time dependency enforcement.
Introduction
Why Elixir/OTP
The choice of Elixir on the BEAM VM is not incidental -- it directly addresses three requirements that disqualify most runtime environments:
-
Soft real-time guarantees: The BEAM scheduler provides preemptive scheduling across lightweight processes with sub-millisecond context switching, ensuring that no single computation starves others. This matters when 434+ AI agents, web dashboard connections, and background crawl jobs share the same runtime.
-
Fault isolation without containers: Each Erlang process has its own heap and garbage-collects independently. A crash in one process does not corrupt another's memory. OTP supervisors automatically restart failed processes according to configurable strategies, making the system self-healing at the process level.
-
Hot code loading: The BEAM supports replacing module code in a running system without dropping connections or losing process state. While not used in production today, this capability enables zero-downtime deployments for future production scenarios.
Architectural Layers
The platform's architecture follows four distinct layers, each with clear responsibilities:
block-beta
columns 1
L4["Layer 4 — Web & API<br/>Phoenix LiveView (4000) · REST API (4004) · WebSocket"]
L3["Layer 3 — Domain Applications<br/>Perimeter · DD · Hawkeye · AI Drift · OSINT · Agents"]
L2["Layer 2 — Platform Services<br/>Auth · Audit · Cache · PubSub · Compression · Search"]
L1["Layer 1 — Core Infrastructure<br/>Storage Adapters · Kernel · 3NL · Core Types · Config"]
L0["Layer 0 — BEAM Runtime<br/>Erlang VM · OTP · Schedulers · ETS · Distribution"]
style L4 fill:#1e293b,stroke:#a855f7,color:#fff
style L3 fill:#0f172a,stroke:#3b82f6,color:#fff
style L2 fill:#1e293b,stroke:#10b981,color:#fff
style L1 fill:#0f172a,stroke:#f59e0b,color:#fff
style L0 fill:#1e293b,stroke:#dc2626,color:#fff
Dependencies flow strictly downward. Layer 4 may call Layer 3 and below; Layer 3 may call Layer 2 and below. Circular dependencies are rejected at compile time.
Core Architecture Components
This section provides an overview of the 12 architectural subsystems documented in detail on their individual pages.
OTP Supervision Trees
Every stateful application defines a supervision tree rooted in its Application.start/2 callback. The platform uses three OTP restart strategies depending on process coupling:
| Strategy | Count | Pattern |
|---|---|---|
:one_for_one | 67 apps | Independent workers -- restart only the failed child |
:rest_for_one | 14 apps | Sequential dependencies -- restart failed child and all started after it |
:one_for_all | 12 apps | Tightly coupled -- restart all children when any fails |
The top-level supervisor for the entire platform uses :one_for_one, meaning a failure in the Perimeter application does not restart the Web application. This isolation is critical for operational stability.
# Platform-level supervision structure (simplified)
defmodule Prismatic.Application do
use Application
@impl true
def start(_type, _args) do
children = [
Prismatic.Config,
{Phoenix.PubSub, name: Prismatic.PubSub},
Prismatic.Repo,
PrismaticWeb.Endpoint
]
Supervisor.start_link(children, strategy: :one_for_one)
end
end
Deep dive: Supervision Trees
Umbrella Application Structure
The 93 OTP applications are organized as an Elixir umbrella project. Each application resides in apps/<name>/ with its own mix.exs, lib/, test/, and priv/ directories. Inter-application dependencies are declared explicitly:
# apps/prismatic_perimeter/mix.exs
defp deps do
[
{:prismatic_core, in_umbrella: true},
{:prismatic_storage_core, in_umbrella: true},
{:prismatic_osint_core, in_umbrella: true}
]
end
The umbrella structure provides microservice-like modularity (independent compilation, isolated testing) without microservice operational overhead (no service discovery, no network serialization, no distributed tracing).
Deep dive: Umbrella Applications
Storage Adapter Architecture
The storage layer implements a behaviour-based adapter pattern. All storage operations route through the PrismaticStorage.Adapter behaviour, allowing the platform to swap backends without changing domain code:
| Adapter | Backend | Latency | Use Case |
|---|---|---|---|
| ETS | Erlang Term Storage | ~1 μs | Caches, sessions, hot data |
| Ecto | PostgreSQL | ~2-10 ms | Persistent records, transactions |
| Meilisearch | Meilisearch | ~5-20 ms | Full-text search, faceted queries |
| KuzuDB | KuzuDB | ~3-15 ms | Graph queries, relationship traversal |
| Redis | Redis | ~1-5 ms | Distributed cache, rate limiting |
The adapter protocol enforces a uniform API across all backends:
@callback store(key, value, opts) :: {:ok, term()} | {:error, term()}
@callback fetch(key, opts) :: {:ok, term()} | {:error, :not_found}
@callback delete(key, opts) :: :ok | {:error, term()}
@callback list(prefix, opts) :: {:ok, [term()]} | {:error, term()}
Deep dive: Storage Adapters
Event Sourcing
Critical subsystems use event sourcing for auditability and temporal queries. Rather than storing current state directly, the system persists an ordered sequence of domain events. Current state is derived by replaying events through a projection function:
flowchart LR
E1["UserCreated"]
E2["RoleAssigned"]
E3["PermissionGranted"]
E4["..."]
P1["%User{id: 1}"]
P2["%User{role: :admin}"]
P3["%User{perms: [:read, :write]}"]
E1 --> E2 --> E3 --> E4
E1 -.->|project| P1
E2 -.->|project| P2
E3 -.->|project| P3
classDef event fill:#1e293b,stroke:#3b82f6,color:#fff
classDef projection fill:#0f172a,stroke:#10b981,color:#e2e8f0
class E1,E2,E3,E4 event
class P1,P2,P3 projection
This pattern provides complete audit trails, enables temporal queries ("what was the state at timestamp T?"), and supports retroactive bug fixes by re-projecting events through corrected logic.
Deep dive: Event Sourcing
Phoenix LiveView
Web interfaces are built with Phoenix LiveView, delivering real-time server-rendered UI without client-side JavaScript frameworks. Each LiveView process maintains a WebSocket connection and pushes DOM diffs to the browser:
| Dashboard | Route | Function |
|---|---|---|
| Main Dashboard | / | Platform overview, metrics, navigation |
| DD Cases | /dd/cases | Due diligence case management |
| Graph Explorer | /dd/graph | Entity relationship visualization |
| Perimeter EASM | /perimeter | Security ratings, asset discovery |
| AI Drift Monitor | /drift | AI decision drift detection |
| Jobs Dashboard | /jobs | Oban background job monitoring |
LiveView's process model means each connected user gets a dedicated Erlang process with its own state, crash isolation, and garbage collection -- no shared mutable state between sessions.
Deep dive: Phoenix LiveView
PubSub Event Bus
Inter-application communication for event-driven workflows uses Phoenix.PubSub backed by the Erlang pg module for local distribution:
# Publisher (any application)
Phoenix.PubSub.broadcast(Prismatic.PubSub, "perimeter:scan_complete", {:scan, result})
# Subscriber (any application)
Phoenix.PubSub.subscribe(Prismatic.PubSub, "perimeter:scan_complete")
# handle_info in subscriber GenServer
def handle_info({:scan, result}, state) do
# React to scan completion
{:noreply, update_state(state, result)}
end
PubSub events are fire-and-forget with at-most-once delivery within the local BEAM node. For guaranteed delivery, the platform uses Oban jobs.
Deep dive: PubSub
Telemetry & Observability
The platform uses Erlang's :telemetry library for metrics emission. Every significant operation emits telemetry events that are consumed by handlers for logging, metrics aggregation, and alerting:
:telemetry.execute(
[:prismatic, :perimeter, :scan],
%{duration: duration_ms, assets_found: count},
%{domain: domain, scan_type: :full}
)
Key telemetry dimensions: request latency, query duration, cache hit rates, agent response times, queue depths, error rates.
Deep dive: Telemetry
NABLA Epistemic Pipeline
The NABLA Infinity (∇∞) framework implements a 16-level epistemic pipeline ensuring that beliefs formed by the platform's AI agents meet formal consistency requirements before influencing decisions:
flowchart TD
L0["L0 — Raw Signal"]
L1["L1 — Validated Signal"]
L2["L2 — Correlated Evidence"]
L3["L3 — Synthesized Belief"]
L13["L13 — Decision-Ready Intelligence"]
Meta["Meta Level<br/>Pipeline Self-Assessment"]
Cons["Consciousness Level<br/>System Self-Awareness"]
L0 --> L1 --> L2 --> L3
L3 -. "L4 – L12" .-> L13
L13 --> Meta --> Cons
classDef raw fill:#0f172a,stroke:#475569,color:#e2e8f0
classDef synth fill:#1e293b,stroke:#3b82f6,color:#fff
classDef ready fill:#1e293b,stroke:#10b981,color:#fff
classDef meta fill:#1e293b,stroke:#a855f7,color:#fff
class L0,L1,L2 raw
class L3 synth
class L13 ready
class Meta,Cons meta
Every belief must pass the Trinity Gate -- three independent consistency checks that must all succeed:
- Structural Consistency: Graph-theoretic validation of the belief's logical structure
- Logical Consistency: Rule-based evaluation against known axioms
- Formal Necessity: Modal logic verification with optional Lean4 proof
Deep dive: NABLA Framework
PostgreSQL & KuzuDB
The platform uses PostgreSQL as its primary relational store (via Ecto) and KuzuDB as an embedded graph database for relationship-heavy queries:
- PostgreSQL: Entity records, audit logs, configuration, Oban job queues
- KuzuDB: Entity relationship graphs, influence networks, ownership chains
The dual-database architecture avoids forcing graph queries into SQL joins or flattening relational data into graph structures.
Deep dive: PostgreSQL & KuzuDB
Ollama Local AI
Local AI inference via Ollama provides <3 second response times for code generation, content analysis, and decision support without external API dependencies:
| Model | Parameters | Response Time | Use Case |
|---|---|---|---|
| qwen3-coder | 7B | <3s | Code generation, refactoring |
| gpt-oss:20b | 20B | <5s | Complex reasoning, analysis |
| deepseek-coder | 6.7B | <3s | Code review, documentation |
The architecture includes automatic fallback to cloud APIs when local models are unavailable or when tasks exceed local model capabilities.
Deep dive: Ollama Integration
Meilisearch
Full-text search across platform data uses Meilisearch, an embedded search engine providing typo-tolerant, faceted search with sub-50ms query times:
- Indexed content: Agents, commands, OSINT sources, applications, documentation
- Features: Typo tolerance, faceted filtering, ranking rules, synonym support
- Deployment: Embedded in the platform, no external service dependency
Deep dive: Meilisearch
GraphQL
The platform exposes a GraphQL API alongside REST for complex, nested data queries where clients need control over response shape:
- Schema: Auto-generated from Ecto schemas and domain types
- Subscriptions: Real-time updates via WebSocket for dashboard widgets
- DataLoader: N+1 query prevention through batched data loading
Deep dive: GraphQL
Cross-Cutting Concerns
3NL (Three Nested Levels) Framework
All architectural components are organized according to the 3NL framework:
- Level 1 (Strategic): Public APIs, facade modules, external interfaces
- Level 2 (Tactical): Inter-application coordination, pipeline orchestration, agent messaging
- Level 3 (Operational): OTP process internals, ETS operations, BEAM optimizations
The 3NL framework ensures that consumers at each level interact only with appropriate abstractions, preventing implementation details from leaking across boundaries.
Error Handling Philosophy
The platform follows Erlang's "let it crash" philosophy, augmented with structured error tuples at API boundaries:
- Internal processes: Let supervisors handle crashes and restarts
- API boundaries: Return
{:ok, result}/{:error, reason}tuples - Web interfaces: Convert error tuples to appropriate HTTP status codes and user-facing messages
This hybrid approach provides the self-healing benefits of OTP supervision while maintaining predictable error handling at system edges.
Configuration Architecture
Configuration follows a layered precedence model:
flowchart TD
Env["Runtime Environment<br/><i>highest precedence</i>"]
Runtime["config/runtime.exs"]
EnvCfg["config/{env}.exs<br/><i>dev.exs · prod.exs · test.exs</i>"]
Cfg["config/config.exs"]
App["Application defaults<br/><i>lowest precedence</i>"]
Env --> Runtime --> EnvCfg --> Cfg --> App
classDef high fill:#1e293b,stroke:#dc2626,color:#fff
classDef mid fill:#0f172a,stroke:#3b82f6,color:#fff
classDef low fill:#0f172a,stroke:#475569,color:#e2e8f0
class Env high
class Runtime,EnvCfg,Cfg mid
class App low
Sensitive configuration (database credentials, API keys) is loaded exclusively from environment variables at runtime, never committed to source control.
Performance Characteristics
Runtime Metrics
| Metric | Value | Context |
|---|---|---|
| BEAM Schedulers | 10 | Matches physical CPU cores |
| Process Count (idle) | ~2,500 | Supervised processes at startup |
| Memory (idle) | ~350 MB | All 93 apps loaded |
| Boot Time | ~8s | Cold start to all apps ready |
| ETS Tables | ~180 | Active tables at runtime |
| GC Pauses | <1ms | Per-process garbage collection |
Compilation Performance
| Operation | Duration | Parallelism |
|---|---|---|
| Full compile (clean) | ~45s | Up to 10 parallel compilers |
| Incremental compile | ~2-5s | Single module recompilation |
| Full test suite | ~90s | Concurrent test processes |
| Dialyzer analysis | ~120s | Incremental PLT updates |
| Credo analysis | ~15s | Parallel file checking |
Security Architecture
Process-Level Isolation
The BEAM VM provides natural security boundaries:
- Memory isolation: Processes cannot access each other's heap
- Message-based communication: All inter-process data is copied, not shared
- Scheduler fairness: No process can monopolize CPU time (reduction counting)
- Port isolation: External program interaction through controlled ports
Network Security
- TLS everywhere: All external connections use TLS 1.3
- API authentication: JWT tokens with configurable TTL and refresh
- Rate limiting: Per-endpoint and per-client rate limiting via Token Bucket
- CORS: Strict origin whitelisting for browser clients
- CSP: Content Security Policy headers on all HTML responses
Data Protection
- Encryption at rest: PostgreSQL TDE for sensitive tables
- Encryption in transit: TLS for all inter-service and client-facing connections
- PII suppression: Automated PII detection and removal in logs and exports
- Audit trails: Immutable, append-only audit log for all state-changing operations
Conclusion
The Prismatic Platform's architecture demonstrates that a monolithic Elixir/OTP deployment can scale to 93 applications and 2.8 million lines of code while maintaining the modularity, testability, and fault-tolerance properties typically associated with distributed microservice architectures. The BEAM VM's process model, combined with OTP supervision trees and Elixir's umbrella project structure, provides a foundation that is simultaneously scalable, maintainable, and operationally simple.
The architectural components documented in this section -- supervision trees, storage adapters, event sourcing, PubSub, telemetry, the NABLA epistemic pipeline, and the various data stores -- compose into a coherent whole through the 3NL framework's layered abstraction model and the platform's strict dependency graph.
References
Architecture Pages
- Supervision Trees -- OTP supervision patterns and restart strategies
- Umbrella Applications -- Project structure and dependency management
- Storage Adapters -- Pluggable storage backend architecture
- Event Sourcing -- Append-only event logs and projections
- Phoenix LiveView -- Real-time server-rendered UI
- PubSub -- Event-driven inter-application messaging
- Telemetry -- Metrics, tracing, and observability
- NABLA Framework -- Epistemic pipeline and Trinity Gate
- PostgreSQL & KuzuDB -- Dual-database architecture
- Ollama -- Local AI inference integration
- Meilisearch -- Full-text search engine
- GraphQL -- Query API and subscriptions
Platform Documentation
- Applications -- Complete application catalog
- Technologies -- Technology stack reference
- Platform Capabilities -- Doctrines and quality enforcement
External References
Architecture documentation reflects the platform state as of 2026-02-06. Component counts and performance metrics are measured on a 10-core development machine running macOS.
Connect & Contribute
Created by Tomas Korcak (korczis) | Open Source under GHL
Dive deeper into the Prismatic Platform -- explore our architecture, agents, and epistemic framework.