Skip to content

Architecture

The application starts via Annihilation.Application.start/2, which boots a flat :one_for_one supervisor with 11 children. The order is significant — the event registry must start first since downstream processes depend on it.

Annihilation.Supervisor (strategy: :one_for_one)
|
+-- Annihilation.Event.Registry # Registry (keys: :duplicate)
| Event pub/sub backbone. All inter-process
| communication flows through this registry.
|
+-- Annihilation.Beads.Keeper # GenServer
| Owns the SQLite database connection.
| Single writer, concurrent readers via WAL mode.
| Schema: beads, bead_deps, bead_comments, pipelines,
| pipeline_stages, bead_pipelines. FTS5 search index.
|
+-- Annihilation.Session.Store # GenServer
| Manages append-only JSONL session files.
| Writer/Reader for session persistence.
|
+-- Annihilation.Agent.Tool.Registry # GenServer
| ETS-based tool registry. Maps tool names to modules.
| Auto-registers built-in tools on startup.
|
+-- Annihilation.Agent.Supervisor # DynamicSupervisor
| Raw DynamicSupervisor for child process management.
|
+-- Annihilation.Agent.DynamicSupervisor # GenServer
| Named supervisor wrapper. Spawns and monitors individual
| psychonaut (agent) processes on demand. Tracks agent_id -> pid
| mapping. Provides start_agent/stop_agent/list_agents/get_agent.
|
+-- Annihilation.Agent.RecursionSemaphore # GenServer
| Counting semaphore limiting global concurrent recursive
| children (default: 16). Prevents resource exhaustion from
| unbounded fan-out. Uses waiter queue when at capacity.
|
+-- Annihilation.Tether.QuestionQueue # GenServer
| Buffers questions from psychonauts that need human input.
| Priority-ordered (critical > high > normal > low).
| Timeout detection with automatic drift notification.
|
+-- Annihilation.Tether.AssumptionsLedger # GenServer
| Manages drift (assumption) lifecycle. JSONL persistence
| at .annihilation/assumptions.jsonl with in-memory index.
| Supports create/update/filter operations on drifts.
|
+-- Annihilation.Tether.LateBeaconHandler # GenServer
| Subscribes to tether:reaching and tether:drifts events.
| When the Tether answers a timed-out question, creates a
| correction bead and supersedes the original drift.
|
+-- Annihilation.Burst.Manager # GenServer
Orchestrates burst/wave lifecycle. State machine:
:idle -> :collecting -> :running -> :draining -> :collecting -> :done -> :idle
  1. Event.Registry starts first because every other process may subscribe to or broadcast events during initialization.
  2. Beads.Keeper starts next to make the persistence layer available. Runs SQLite migrations on init.
  3. Session.Store depends on the filesystem but is independent of beads.
  4. Agent.Tool.Registry populates the ETS table of available tools.
  5. Agent.Supervisor and Agent.DynamicSupervisor are the agent infrastructure layer.
  6. RecursionSemaphore provides the global concurrency limiter for recursive sub-calls.
  7. QuestionQueue, AssumptionsLedger, and LateBeaconHandler form the tether interaction layer.
  8. Burst.Manager provides the top-level orchestration.

The top-level supervisor uses :one_for_one, meaning if a child crashes, only that child is restarted. This is appropriate because the children are largely independent — a crash in Burst.Manager should not restart the Session.Store.

All inter-process communication uses Annihilation.Event, a wrapper around OTP’s Registry with :duplicate keys. This allows multiple processes to subscribe to the same topic.

# Subscribe the current process to a topic
Annihilation.Event.subscribe("agent:*")
# Broadcast an event to all subscribers
Annihilation.Event.broadcast("agent:*", {:agent_started, id, template})
# Unsubscribe
Annihilation.Event.unsubscribe("agent:*")
# List all subscribers for a topic
Annihilation.Event.subscribers("agent:*")

Events are delivered as messages in the format {:event, topic, payload}:

def handle_info({:event, "agent:*", {:agent_started, id, template}}, state) do
# handle the event
{:noreply, state}
end
Topic PatternPayloadsPublishers
"agent:#{id}"{:phase_change, old, new, state}, {:delta, delta}, {:tool_results, results}, {:tool_update, call_id, partial}, :done, {:error, reason}Agent.Server
"agent:mail:#{id}"%{type: :new_message, from, subject, message_id, priority}Agent.Mailbox
"agent:mail:broadcast"%{type: :broadcast_message, from, subject, message_id}Agent.Mailbox
"tether:reaching"{:question_asked, q}, {:question_answered, q}, {:question_timed_out, q}, {:late_answer, q, text}QuestionQueue
"tether:drifts"{:drift_created, assumption}, {:drift_confirmed, info}, {:drift_rejected, info}, {:drift_noted, info}, {:drift_superseded, info}, {:pipeline_drift, info}AssumptionsLedger, DriftReview, LateBeaconHandler, GroundingQueue
"tether:questions"{:pipeline_mutation_submitted, entry}, {:pipeline_mutation_responded, entry}Pipeline.GroundingQueue
"burst:events"{:burst_start, info}, {:burst_complete, info}, {:wave_complete, stats}Burst.Manager
"reflection:*"%{burst_id: id} for started/extracting/proposing/evaluating/curating/completed/cached/errorReflection.Pipeline

Single SQLite database at .annihilation/beads.db managed by Beads.Keeper. WAL mode for concurrent reads with single-writer pattern. Schema tables:

  • beads — task/issue tracking with status, type, priority, labels
  • bead_deps — dependency graph between beads
  • bead_comments — comments on beads
  • pipelines — pipeline definitions with match rules
  • pipeline_stages — ordered stages within pipelines
  • bead_pipelines — per-bead pipeline overrides
  • FTS5 virtual table for bead full-text search

Append-only JSONL files in .annihilation/sessions/. One file per session (typically per burst). Session.Writer appends events, Session.Reader replays them.

Separate SQLite database at .annihilation/search.db with FTS5 virtual table (session_search) over session content. Porter stemming with unicode61 tokenization. Supports boolean operators, phrase matching, prefix matching, and column-specific queries.

JSONL file at .annihilation/assumptions.jsonl tracking all drifts. AssumptionsLedger GenServer maintains an in-memory index loaded from file on startup.

YAML files at .annihilation/playbook.yaml (project) and ~/.annihilation/playbook.yaml (global). Atomic writes via temp file + rename.

YAML file at .annihilation/skills.yaml. Stores reusable prompt/code templates with Thompson sampling parameters.

DependencyVersionPurpose
exqlite~> 0.23SQLite3 NIF for beads persistence and FTS5 search
jason~> 1.4JSON encoding/decoding
yaml_elixir~> 2.11YAML parsing for pipelines, playbook, skills
mint~> 1.6HTTP client for SSE streaming to LLM APIs
castore~> 1.0CA certificates for TLS
stream_data~> 1.0Property-based testing (dev/test only)
ex_doc~> 0.34Documentation generation (dev only)
lib/annihilation/
+-- application.ex # OTP application entry point, 11-child supervision tree
+-- config.ex # Project root detection
+-- event.ex # Registry-based PubSub wrapper
+-- beads/ # Bead persistence layer
| +-- keeper.ex # GenServer: single-writer SQLite, bead/pipeline CRUD
| +-- bead.ex # Bead struct and validation
| +-- db.ex # Low-level SQLite wrapper (open, execute, query)
| +-- migrations.ex # Schema migrations for beads, deps, comments, pipelines
| +-- comment.ex # Comment struct
| +-- dependency.ex # Dependency struct
+-- session/ # Session persistence
| +-- store.ex # GenServer for JSONL session management
| +-- writer.ex # Append-only JSONL writer
| +-- reader.ex # Session replay reader
| +-- event.ex # SessionEvent struct
| +-- meta.ex # SessionMeta struct
+-- agent/ # Psychonaut core
| +-- server.ex # GenServer with phase machine
| +-- state.ex # Agent.State struct (phase, messages, tools, config)
| +-- provider.ex # Provider behaviour (stream, format_messages, format_tools)
| +-- provider/anthropic.ex # Anthropic Messages API via Mint HTTP/2
| +-- provider/anthropic/sse_parser.ex # SSE stream parser -> Delta structs
| +-- provider/mock.ex # Mock provider for testing
| +-- tool.ex # Tool behaviour (name, description, parameters_schema, execute)
| +-- tool/ # 20+ built-in tools
| +-- tool/registry.ex # ETS-based tool name -> module registry
| +-- message.ex # Message struct (role, content, tool_calls, metadata)
| +-- delta.ex # Delta struct for streaming
| +-- delta_accumulator.ex # Accumulates deltas into complete Messages
| +-- tool_call.ex # ToolCall struct
| +-- tool_result.ex # ToolResult struct
| +-- identity.ex # AgentIdentity struct
| +-- dynamic_supervisor.ex # Named supervisor for agent lifecycle
| +-- recurse.ex # Recursive sub-call engine (call + fan_out)
| +-- recursion_guard.ex # Depth limits, tool resolution, lease checks
| +-- recursion_semaphore.ex # Global counting semaphore (default 16 slots)
| +-- mailbox.ex # ETS-based inter-agent messaging
| +-- agent_message.ex # AgentMessage struct
| +-- file_lease.ex # File lease helpers
| +-- schema.ex # JSON schema validation
+-- tether/ # Human-agent tether
| +-- question_queue.ex # Priority-ordered question queue with timeouts
| +-- question.ex # Question struct (id, agent_id, text, priority, timeout)
| +-- assumptions_ledger.ex # Drift lifecycle management (JSONL + in-memory)
| +-- assumption_made.ex # AssumptionMade struct
| +-- drift_review.ex # Ground/Reject/Note actions on drifts
| +-- late_beacon_handler.ex # Late answers -> correction beads
| +-- events.ex # Tether event helpers
| +-- pipeline.ex # Tether pipeline override API
| +-- pipeline_drift.ex # Pipeline drift struct
| +-- pipeline_drift_review.ex # Ground/Reject pipeline drifts
+-- burst/ # Burst orchestration
| +-- manager.ex # GenServer state machine (idle/collecting/running/draining/done)
| +-- bead_run.ex # BeadRun struct (bead + pipeline tracking)
| +-- stage_executor.ex # Fan-out and sequential stage preparation
+-- pipeline/ # Pipeline system
| +-- pipeline.ex # Pipeline struct (name, match_labels, match_types, stages)
| +-- stage.ex # Stage struct (agents, fan_out, condition, retries)
| +-- bead_pipeline.ex # Per-bead pipeline override struct
| +-- seed_loader.ex # YAML pipeline loading from config files
| +-- grounding_queue.ex # Pipeline mutation grounding with timeout/drift
+-- memory/ # Memory system
| +-- diary_entry.ex # DiaryEntry struct (accomplishments, decisions, challenges, learnings)
| +-- diary_writer.ex # JSONL diary writer
| +-- playbook_rule.ex # PlaybookRule struct with confidence scoring
| +-- playbook.ex # YAML storage for playbook rules (project + global)
| +-- confidence.ex # Decay, feedback, maturity promotion/demotion, sweep
| +-- anti_pattern.ex # Detection (failure_count >= 3 && > 2x successes) and inversion
| +-- context.ex # Rule relevance scoring and prompt injection
+-- skills/ # Skill catalog
| +-- skill.ex # Skill struct (template, alpha/beta, usage tracking)
| +-- catalog.ex # YAML storage for skills
| +-- ranking.ex # Thompson sampling, UCB, mean-based ranking
+-- search/ # Session search
| +-- index.ex # FTS5 search index (session_search virtual table)
| +-- writer.ex # Index events on session append
+-- security/ # Security layer
| +-- command_guard.ex # Three-tier risk classification (:danger/:caution/:safe)
| +-- command_guard_integration.ex # Shell tool integration
| +-- trauma_guard.ex # Experience-based escalation from past incidents
| +-- trauma_record.ex # TraumaRecord struct
| +-- trauma_store.ex # Trauma record persistence
+-- file/ # File management
| +-- lease_manager.ex # Cooperative file locking (exclusive/shared_read, TTL, sweep)
| +-- lease_integration.ex # file_write tool integration
+-- reflection/ # Post-burst reflection
| +-- pipeline.ex # 6-stage reflection pipeline orchestrator
| +-- agent_template.ex # Reflection psychonaut template
| +-- diary_extractor.ex # Extract diary entries from session transcripts
| +-- playbook_proposer.ex # Propose playbook rule changes
| +-- playbook_delta.ex # PlaybookDelta struct (add/update/deprecate)
| +-- evidence_gate.ex # Validate proposals against session search
| +-- curator.ex # Dedup, conflict detection, anti-pattern inversion
+-- tui/ # Terminal UI
+-- terminal.ex # Raw mode, ANSI escape codes, screen buffer rendering
+-- layout.ex # Panel layout system
+-- input.ex # Key event parsing (CSI, SS3, control, printable)
+-- event_bridge.ex # System events -> TUI panel updates (30fps batching)
+-- mode.ex # Mode behaviour (init, handle_key, handle_events, render)
+-- mode_manager.ex # Mode switching (Tab, number keys 1-6), state preservation
+-- modes/overview.ex # All psychonauts + activity log
+-- modes/focus.ex # Single psychonaut conversation view
+-- modes/tether.ex # Questions + drifts panel
+-- modes/grounding.ex # Code review / pipeline mutation approval
+-- modes/beads.ex # Bead management
+-- modes/shell.ex # Embedded command runner