Skip to main content
Architecture series: Overview · Native Scan · Agentic Scan · Data & Storage · Server & API
Vigolium’s agent mode runs AI-driven security scans on top of the native scanner. This document explains the architecture, the moving parts, and the flow of a typical agent run.
Recent shift: the previous subprocess-based SDK backends (claudesdk, codexsdk) have been removed. All AI dispatch now goes through an in-process Go runtime called olium (pkg/olium/). One unified provider interface, one conversation state, one place to reason about timeouts and retries.

1. Subcommand surface

vigolium agent is a parent command with informational flags only (--list-templates, --list-agents). Real work happens in subcommands. query is the only mode that does not orchestrate a scan, it’s a one-shot prompt with optional source-code context. autopilot and swarm are the two agentic scan modes.

2. Architecture layers

2.1 Engine (pkg/agent/engine.go)

The engine is the seam between orchestrators and the olium runtime. Its job is to:
  1. Preflight: validate provider/model selection (Preflight(agentName)).
  2. Build the prompt: load template, parse frontmatter, render with TemplateData.
  3. Enrich context: pull DB context (previous findings, discovered endpoints, high-risk endpoints, module list, scan stats) through a thread-safe LRU cache (agentprompt.ContextCache) that lives for one swarm/autopilot run.
  4. Dispatch: call runOliumOnEngineWithThinking() against an olium engine instance.
  5. Retry: exponential backoff on transient errors (retry.go, default 2 retries, 2-30s backoff) with jitter.
  6. Parse: schema-aware JSON extraction tolerating fences, prose, and type coercion (string ↔ int, object ↔ string body).
  7. Ingest: write parsed findings/HTTP records to the DB repository.
Key entry points:
  • Engine.Run(ctx, opts): one-shot prompt execution; creates a fresh olium engine.
  • Engine.RunOnOliumEngine(ctx, opts, eng): runs against a shared engine instance, preserving conversation prefix for prompt-cache hits across phases.
  • Engine.RunSourceAnalysisParallel(ctx, cfg): fan-out source analysis (single explore call → parallel format/extension sub-calls on the same engine).
A global semaphore caps in-flight provider calls; a positive agent.olium.max_concurrent is the cap, 0/unset resolves to the default of 4, and a negative value disables the cap.

2.2 Olium runtime (pkg/olium/)

Native, in-process replacement for the old SDK pool.
  • pkg/olium/engine: Engine.Run(ctx, prompt) <-chan Event returns a stream of events: EventTextDelta, EventThinkingDelta, EventToolCall, EventTurnDone (with token usage), EventError. Conversation state (system prompt, tool definitions, prior turns) lives on the engine and is reused across calls when phases share an engine.
  • pkg/olium/tool: registry of built-in tools (bash, file ops, grep, fetch, …) registered via tool.NewRegistry() + tool.RegisterBuiltins(). Autopilot exposes the full set; swarm uses a smaller set per phase.
  • pkg/olium/skill: optional skill files (Markdown SKILL.md packages) that augment the system prompt; loaded from embedded assets and ~/.vigolium/skills/.
  • pkg/olium/provider: provider dispatch:
Configured in agent.olium of vigolium-configs.yaml. Per-call deadline defaults to 10m (call_timeout_sec). The openai-compatible provider speaks the OpenAI Chat Completions wire format and works with any backend that does too, Ollama, OpenRouter, LM Studio, vLLM, Together, Groq, LocalAI, custom proxies. Set base_url to the endpoint (/v1 root or full /v1/chat/completions URL, both work); leave api_key empty for unauthenticated local servers. extra_headers are applied after the standard headers, so they can override Authorization for backends that use a non-Bearer scheme.
Tool-calling caveat. OpenAI-style function tools are supported by the wire format but not by every model. Local instruction-tuned models that work well: qwen2.5-coder, llama3.1 instruct, mistral-nemo. Smaller models often silently ignore tool definitions and reply in prose. If the agent never calls tools, that’s the likely cause, switch to a tool-trained model.

2.3 Prompt templates

Markdown files with YAML frontmatter, loaded from (in order):
  1. agent.templates_dir (config dir)
  2. ~/.vigolium/prompts/
  3. Embedded (public/presets/prompts/ baked into the binary)
Frontmatter declares the output schema the agent is expected to produce: Templates render against TemplateData (pkg/agent/agenttypes/types.go), which carries: source code snippets, directory tree, target URL, hostname, previous findings (DB), discovered endpoints (DB), module list/tags, scan stats, and a free-form Extra map for orchestrator-injected hints.

3. Swarm pipeline

vigolium agent swarm --target ... [--source ...] runs a state-machine pipeline. Each step implements swarmPhaseStep.Run(ctx, *swarmPipelineState).
Phase names prefixed native- are pure-Go (no LLM). The pipeline is gated by:
  • --only / --skip / --start-from flags (with legacy aliases via NormalizeSwarmPhase)
  • intensity preset (SwarmPresets[Quick|Balanced|Deep] in agenttypes/constants.go)
  • cfg.SourcePath: empty source skips source-analysis and code-audit
  • cfg.Discover, cfg.CodeAudit, cfg.Triage toggles
  • checkpoint state for observability; --start-from creates a new run with earlier phases marked complete
A parallel vigolium-audit subprocess can run in the background (cfg.Audit != "") when source is provided, contributing source-code audit findings without blocking the swarm. Swarm uses the embedded vigolium-audit harness directly; the multi-driver agent audit command layers piolium support on top.

Plan & extension phases

The master agent receives input records (chunked into MasterBatchSize, default 5) and returns a SwarmPlan:
The extension phase compiles every JS extension through the Sobek engine. Syntax errors trigger RepairExtensionsWithLLM(), which fans out repair calls (max 5 parallel). Surviving extensions are written to <session>/extensions/ with sanitized filenames; an extensionRenames map preserves original→renamed mapping for downstream result attribution.

Triage loop

After the native scan, if findings exist and triage is enabled, the triage agent receives a fixture (truncated by detail tiers, 15 full-detail / 40 table-with-top-10 / etc.) and emits:
If FollowUpScans is non-empty and rescan is enabled, the pipeline loops back to native-scan with targeted modules. Loop bounded by MaxIterations (default 3); early-exits when all findings have “certain” confidence.

4. Autopilot pipeline

vigolium agent autopilot --target ... [--source ...] is simpler, no plan/extension phases. The agent itself decides what to run.
The default agent.olium.autopilot_mode: legacy preserves direct report_finding behavior. shadow rotates context while mirroring candidates; enforced replaces direct reports with propose_candidate and promotes only verifier-confirmed claims. Durable runs can continue with autopilot --resume <agentic-scan-uuid>.

Intensity presets (autopilot)


5. Session directories

Every swarm and autopilot run writes a session dir under agent.sessions_dir (default ~/.vigolium/agent-sessions/<run-uuid>/). Layout:
EnsureSessionDir(baseDir, agenticScanUUID) in pipeline_types.go is the canonical creator.

6. Configuration

All agent settings live under agent in vigolium-configs.yaml:
CLI flags (--provider, --model, --oauth-token, --llm-api-key, --base-url) override the config at runtime.

7. Where things live


8. Quick mental model

  • Engine turns a prompt template + DB context into a structured result. One LLM call.
  • Orchestrator sequences many engine calls plus native steps (discovery, scan), checkpoints state, and writes a session directory.
  • Olium is the agent runtime, it holds conversation state and dispatches to a provider. One olium engine can serve many engine calls cheaply (prompt cache hits).
  • Swarm phases are controlled by --only, --skip, and --start-from; swarm has no public --resume flag.
  • Autopilot resume takes an AgenticScan UUID and restores durable scratchpad/candidate state; it is not phase-based.
  • Intensity is a single knob that hydrates a bundle of toggles (commands, timeout, vigolium-audit mode, discover/audit/triage flags, browser/auth).

Agent Mode

Task-oriented guide to the agent subcommands.

Autopilot

Autonomous operator mode in practice.

Swarm

The multi-phase AI + native pipeline.

Olium

Use the agent runtime directly (TUI / headless).