AEGIS
— docs

Architecture

How the orchestrator, TUI, and tool layer fit together.

This is the doc to read before you start building on top of AEGIS — adding a new tool, a new verification probe, a new phase, or a custom backend.

Process model

┌─ aegis run <engagement-dir>  (Python, asyncio main thread)        ┐
│                                                                    │
│  ┌─ TUI bridge ──────────────────────────────────────────────┐    │
│  │  spawns: node tui/dist/index.js                            │    │
│  │   • stdin  ← ServerEvent NDJSON   (Python writes)         │    │
│  │   • stdout → ClientCommand NDJSON (Python reads)          │    │
│  │   • /dev/tty ↔ Ink draws + keys (bypasses pipes)          │    │
│  └────────────────────────────────────────────────────────────┘    │
│                                                                    │
│  ┌─ EngagementRunner ─────────────────────────────────────────┐   │
│  │   state machine over 7 PTES phases                          │   │
│  │   ↓                                                          │   │
│  │   Backend (Claude API / Claude Code / Ollama)               │   │
│  │   ↓                                                          │   │
│  │   MCP tool surface — Python tool wrappers + verification    │   │
│  │   probes + Knowledge Base + Findings DB                     │   │
│  └─────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────┘

Components

src/aegis/orchestrator/

  • loop.pyEngagementRunner. State machine over the 7 phases. Owns the LLM call loop, the operator-message queue, the audit log.
  • events.pyEngagementEvent and EventKind: every signal that flows from runner → on_event callbacks (LLM_THINKING, LLM_DECISION, PHASE_START, PHASE_ADVANCE, TOOL_DONE, FINDING, …).
  • planner.py — strategic decisions: which tools to queue next, which phase to advance to.

src/aegis/methodology/

  • phases.pyMethodologyPhase enum and PHASE_CONFIGS. Each phase has an objective, default budget, prompt template, exit criteria, and the set of MCP tools it’s allowed to call.
  • engine.py — phase advance / change logic.

src/aegis/mcp_server/

The MCP server surface. When AEGIS is run as aegis serve (Claude Code as orchestrator) or when EngagementRunner runs Claude Code in subprocess mode, this is what the LLM talks to.

  • server.py — FastMCP server. Defines every tool the LLM can call: subfinder_enum, nuclei_scan, aegis_verify, aegis_record_finding, etc.
  • __main__.pypython -m aegis.mcp_server entry.

src/aegis/tools/

  • catalog.pyTOOL_CATALOG: every external binary AEGIS knows about, with its install spec (pacman, yay, go install, pipx, npm, binary, manual).
  • executor.pyToolExecutor. Routes run_tool(name, target, **kwargs) to the right wrapper. Enforces scope, rate limit, environment.
  • base.pyBaseTool abstract class. Subclasses implement run(target, **kwargs) -> ToolResult.
  • wrappers/ — one file per tool: nmap.py, nuclei.py, subfinder.py, … 14 wrappers cover the high-frequency tools; the rest run through generic subprocess invocations.
  • parsers/ — per-tool output parsers that convert raw output into Observation objects.

src/aegis/verify/

  • probes.py — 33 verification probe types: timing oracle, CSRF, SSTI, prototype pollution, race condition, header injection, OAuth flow… Called by the aegis_verify MCP tool after a candidate finding is identified.

src/aegis/analysis/

  • adaptive.py — adaptive escalation: takes findings and queues follow-up tool runs.
  • chains.py — attack chain detection across services.
  • port_profiles.py — port-based attack profiles for ACTIVE_RECON.

src/aegis/kb/

Local knowledge bases:

  • nvd.py — NVD CVE feed sync + lookup.
  • ghsa.py — GitHub Security Advisories.
  • nuclei_index.py — local index of nuclei templates by CVE / tech.
  • template_selector.py — given a tech stack, return the most relevant templates.

src/aegis/scope/

  • guard.pyScopeGuard. Every HTTP request, every tool target, every probe destination passes through is_in_scope(). Out-of-scope is a hard exception, not a warning.

src/aegis/cli/

  • main.py — Typer CLI: aegis run, aegis report, aegis engagement new, etc.
  • tui_bridge.py — spawn the Node TUI, translate runner events to ServerEvent NDJSON, translate operator commands back into inject_operator_message() / flag flips.
  • shells.pyShellTracker: process-scoped registry of every tool subprocess so the TUI can show streaming output.

tui/

Node + React + Ink terminal UI. Strict TypeScript, esbuild ESM bundle to a single 38 KB file.

  • src/protocol/types.ts — wire protocol (ServerEvent / ClientCommand) shared with Python.
  • src/protocol/bridge.ts — NDJSON line buffer over stdin/stdout.
  • src/hooks/useEngagement.ts — single useReducer that turns ServerEvents into UI state.
  • src/components/ — StatusBar, ActivityFeed, ThinkingPane, InputBar, ShimmerText.

Backend selection

aegis.llm.factory.create_backend() picks in order:

  1. ANTHROPIC_API_KEY set → AnthropicAPIBackend.
  2. claude on PATH and authenticated → ClaudeCodeBackend (uses your subscription, no API costs).
  3. OLLAMA_HOST set → OllamaBackend.

Override with --backend <name> or via ~/.config/aegis/config.toml.

Adding a new tool

  1. Write a wrapper in src/aegis/tools/wrappers/your_tool.py. Subclass BaseTool, implement run().
  2. Add an entry to TOOL_CATALOG in src/aegis/tools/catalog.py with install spec.
  3. Add a parser in src/aegis/tools/parsers/ if the tool’s output is structured.
  4. Surface it as an MCP tool in src/aegis/mcp_server/server.py so Claude can call it.
  5. Add a phase mapping in src/aegis/methodology/phases.py so the right phase can use it.

See wrappers/nuclei.py end-to-end — it’s the canonical example.

Adding a verification probe

  1. Add a new function _probe_yourcheck(target, **kwargs) -> dict in src/aegis/verify/probes.py.
  2. Register it in the PROBE_TYPES dict at the top of that file.
  3. The MCP tool aegis_verify(probe_type='yourcheck', target=...) will route to it automatically.

Wire protocol

The TUI talks to Python over NDJSON. See tui/src/protocol/types.ts for exact types. The interesting events:

EventCarries
helloengagement ID, client, model, scope
phase_startphase name, objective description
llm_thinkingheartbeat status string
llm_decisiontool name + label
tool_startid, name, command tokens
tool_outputid, single output line
tool_doneid, status, rc, elapsed
findingseverity, title, target
agent_noteClaude’s analytical commentary
phase_donephase name, cost
completescan summary

Commands the TUI sends back:

guidance, stop, pause, resume, focus, hunt, quit.