Community
Architecture
Ghost Security Agent's architecture separates deterministic tools from AI judgment. This page covers the technical design and how everything fits together.
Design principles
Tools are standalone. Each tool is a self-contained Go binary that does one job. No tool depends on another tool, the skills layer, or any external service. You can use Poltergeist, Wraith, or Reaper independently without installing Ghost Security Agent.
Skills are composable. Each skill can run independently or as part of a pipeline. Skills read artifacts from previous skills when available (e.g., scan-code reads the repo context from repo-context) but degrade gracefully when they're missing.
Everything is local. No telemetry, no cloud services, no data leaving your machine. Tools download their databases locally (Wraith's OSV database, Poltergeist's embedded rules). Skills cache results to the local filesystem.
Output is auditable. Every finding traces back to specific tool output and specific criteria. You can always inspect the raw Poltergeist matches, the raw Wraith CVE data, or the specific criteria that triggered an Exorcist finding.
Tool architecture
All three Go tools follow similar patterns:
CLI structure
- Poltergeist -- single command with flags (
poltergeist [flags] <path>) - Wraith -- subcommands (
wraith scan,wraith download-db,wraith version) - Reaper -- subcommands via Cobra (
reaper start,reaper search,reaper get,reaper stop)
Output formats
All tools support multiple output formats:
| Format | Use case |
|---|---|
| Text (colored) | Interactive terminal use |
| JSON | Programmatic consumption, skill integration |
| Markdown | Reports, documentation, issue tracking |
JSON is the primary integration format. Skills parse JSON output from tools.
Binary distribution
Tools are distributed as precompiled binaries via GitHub Releases and installed to ~/.ghost/bin/. The skills layer handles automatic binary download and verification during initialization.
Skill architecture
Skill definition format
Each skill is a SKILL.md file that defines:
- Tool restrictions -- which Claude Code tools the skill can use (Read, Write, Glob, Grep, Bash, Task)
- Execution pipeline -- numbered steps the skill follows
- Input/output contracts -- what the skill reads and what it produces
- Sub-agent definitions -- for multi-agent skills, references to agent prompt files
Multi-agent patterns
Skills use three architectural patterns:
Orchestrator + sub-agents (scan-deps, scan-secrets) -- a read-only orchestrator spawns sub-agents via the Task tool. Each sub-agent reads its instructions from a prompt file in the skill directory. The orchestrator coordinates but doesn't do the work directly.
Orchestrator (SKILL.md)
├── Task -> Init agent (agents/init/agent.md)
├── Task -> Discover agent (agents/discover/agent.md)
├── Task -> Scan agent (agents/scan/agent.md)
├── Task -> Analyze agent (agents/analyze/agent.md)
└── Task -> Summarize agent (agents/summarize/agent.md)
Loop-based funnel (scan-code) -- a single agent executes all steps directly, using a loop script for resumability. Progress is tracked in checkpoint files (plan.md, nominations.md, analyses.md) so work can resume after timeouts.
Interactive workflow (validate) -- a single agent with step-by-step execution and optional user interaction. Reads findings, traces code, and optionally uses Reaper for live testing.
Data Structure
Cache and Results
~/.ghost/
├── bin/ # Tool binaries
│ ├── poltergeist
│ ├── wraith
│ └── reaper
└── repos/
└── <repo_id>/ # Per-repository
├── cache/
│ └── repo.md # Repository context (shared)
└── scans/
└── <commit_sha>/ # Per-commit
├── deps/
│ ├── lockfiles.json
│ ├── candidates.json
│ ├── findings/
│ └── report.md
├── secrets/
│ ├── candidates.json
│ ├── findings/
│ └── report.md
├── code/
│ ├── plan.md
│ ├── nominations.md
│ ├── analyses.md
│ └── findings/
└── report.md # Combined report
repo_id is computed from the repository name and remote URL hash, ensuring unique caching per repository.
commit_sha (short) provides per-commit isolation. Scanning the same commit twice returns cached results. A new commit triggers fresh scans.
Data flow between skills
The repo-context output is shared context that informs all scans. It's required for scan-code (to plan which vulnerability vectors to check) and opportunistically loaded when present by the other skills to enrich context (but isn't required for basic operation).
Reaper internals
Reaper has a distinct architecture due to its daemon-based design:
Components
CLI ──── Unix socket (IPC) ──── Daemon
├── HTTP proxy server
├── TLS interception (in-memory CA)
├── Scope filter
└── SQLite storage
IPC protocol
The CLI and daemon communicate via JSON messages over a Unix domain socket at ~/.reaper/reaper.sock:
- Request:
{"command": "search", "params": {"method": "POST", "limit": 50}} - Response:
{"ok": true, "data": [...]}
Commands: logs, search, get, req, res, shutdown, ping
TLS interception
- Client sends CONNECT request to proxy
- If in-scope: proxy hijacks TCP connection, responds with 200, starts TLS with generated cert
- If out-of-scope: proxy blindly relays bytes between client and server (transparent pass-through)
- Per-host certificates are cached in a
sync.Mapfor performance
Design rationale
Go for tools. Single-binary distribution, fast startup, cross-platform compilation. No runtime dependencies.
Markdown for skills. Skills are prompts. Markdown is human-readable, version-controllable, and doesn't require a build step.
YAML for criteria. Structured enough to be machine-parseable, readable enough to be human-reviewed. The AI reads criteria during analysis, and humans review them for correctness.
Local-only. Security tools that send your code to external services create a trust problem. Ghost Security Agent runs entirely on your machine. The only network calls are to the OSV vulnerability database (and even that supports offline mode).
Tool/skill split. Deterministic tools provide a reliable foundation. Pattern matches, CVE lookups, and traffic captures produce the same output every time. The AI layer adds judgment and context, but the underlying data is always verifiable.