Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.vigolium.com/llms.txt

Use this file to discover all available pages before exploring further.

vigolium agent swarm is the AI-guided agentic scan mode. The master agent reads the target’s request/response surface (and optionally its source code), picks the right scanner modules, generates custom JavaScript extensions when needed, runs the native scanner, and optionally triages the results in a verify-and-rescan loop. It sits between two extremes: it is more directed than autopilot (which gives the agent free reign with full tool access) and more flexible than a hand-tuned vigolium scan (modules and extensions are chosen by the model, not the user). This document covers what the pipeline looks like, how data flows between phases, and where the AI / native boundary sits.

When to use swarm

ScenarioUse
You have a target URL, raw request, or HTTP record and want the agent to pick modules + write payloadsswarm
You also have the application source — want routes + auth + extensions inferred from codeswarm --source <path>
You want false-positive verification and targeted re-scans on the model’s say-soswarm --triage
You’d rather hand the agent a shell + the codebase and let it decide everythingautopilot
You want a one-shot prompt with no scanningagent query
Swarm is the right mode when you want the AI to drive the native scanner, not replace it.

Pipeline at a glance

Ten phases run in strict order. Each phase is either native (deterministic Go) or AI (LLM call via the olium engine). Most phases are conditional — they only fire when their inputs are present or the user opts in.
┌────────────────────────────────────────────────────────────────────────────┐
│                          swarm pipeline                                     │
│                                                                             │
│  [N] native-normalize ─────────────────────────────── always                │
│         │                                                                   │
│  [A] auth ─────────────────────────── if --browser-auth and --browser       │
│         │                                                                   │
│  [A] source-analysis ─────────────── if --source  (4-call wave)             │
│  [A] code-audit ──────────────────── if --code-audit and --source           │
│         │                                                                   │
│  [N] native-discover ─────────────── if --discover                          │
│         │                                                                   │
│  [A] plan         ────────────────── always (master agent, may batch)       │
│  [N] native-extension ────────────── if plan declared extensions            │
│  [N] native-scan  ────────────────── always (hands off to scanner)          │
│         │                                                                   │
│  [A] triage       ────────────────── if --triage                            │
│  [N] native-rescan ───────────────── per round, when triage requests it     │
│         │                                                                   │
│  [N] finalize     ────────────────── always                                 │
└────────────────────────────────────────────────────────────────────────────┘

[A] = AI call    [N] = native Go

Data flow

The pipeline is driven by a single swarmPipelineState that all phases read from and write to. The two main payloads that move through it are records (HTTP request/response pairs) and the plan (module selection + extensions spec).
                 ┌────────────────────┐
   inputs ──────►│  normalize         │──► []*HttpRequestResponse
   (curl/HTTP/   └────────────────────┘            │
    burp/url/                                      │
    record uuid/                                   ▼
    stdin)                              ┌────────────────────┐
                                        │ source-analysis    │ if --source
                                        │  (4-call wave)     │──► +routes
                       ┌────────────────┤                    │   +session_cfg
                       │                │                    │   +extensions
                       │                └────────────────────┘
                       │                          │
                       │                          ▼
                       │                ┌────────────────────┐
                       │                │ native-discover    │ if --discover
                       │                └────────────────────┘
                       │                          │
                       │                          ▼   merged []records
                       │                ┌────────────────────┐
                       │                │  plan (master)     │
                       │                │  - select modules  │
                       │                │  - focus areas     │
                       │                │  - extensions spec │
                       │                └────────────────────┘
                       │                          │
                       │                          ▼ SwarmPlan
                       │                ┌────────────────────┐
                       │                │ extension          │
                       │                │ validate + persist │
                       │                └────────────────────┘
                       │                          │
                       │                          ▼ extensions/*.js
                       │                ┌────────────────────┐
                       └───────────────►│ native-scan        │
                            ScanFunc    │ runner.RunNative…  │
                          (callback)    └────────────────────┘

                                                  ▼ findings → DB
                                        ┌────────────────────┐
                                        │ triage (loop)      │ if --triage
                                        │ verdict per finding│
                                        │ + rescan request   │
                                        └────────────────────┘


                                        ┌────────────────────┐
                                        │ finalize           │
                                        │ aggregate results  │
                                        └────────────────────┘
Records grow as the pipeline runs: source analysis appends discovered routes, and native discovery merges crawl/spider results before planning. The plan, once produced, is the single source of truth for what the native scanner will run.

Phase reference

#PhaseTypePurposeTrigger
1native-normalizeNativeParse --input/stdin/record-uuid into HttpRequestResponseAlways
2authAI/NativeBrowser-driven login, writes auth headers/cookies--browser-auth + --browser
3source-analysisAI4-call wave: explore → routes / session / extensions--source
4code-auditAICode-level security audit, findings → DB--code-audit (auto with --source at balanced/deep)
5native-discoverNativeCrawl/spider/JS-scan to discover endpoints--discover
6planAIMaster agent: pick modules, focus areas, extensions specAlways
7native-extensionNativeValidate generated JS, write to extensions/Plan declared extensions
8native-scanNativeHand off to runner.RunNativeScan()Always
9triageAIVerify findings; mark confirmed / FP / rescan--triage
10native-rescanNativeTargeted rescan on triage request (loops)Triage verdict = “rescan”
Skipping/resuming is honored via --skip-phases and --start-from, which read the checkpoint file.

Source-aware mode: the 4-call wave

When --source <path> is given, source analysis runs as a single explore call followed by three parallel format calls.
                 ┌──────────────────────────────────┐
                 │ Call 1  swarm-source-explore     │
                 │ reads source once → notes:       │
                 │   • routes notes                 │
                 │   • auth notes                   │
                 └────────────────┬─────────────────┘
                                  │ session history reused
                                  │ (provider-cached, not resent in full)
              ┌───────────────────┼───────────────────┐
              ▼                   ▼                   ▼
   ┌────────────────────┐ ┌────────────────────┐ ┌──────────────────────┐
   │ Call 2a            │ │ Call 2b            │ │ Call 3               │
   │ format-routes      │ │ format-session     │ │ source-extensions    │
   │ notes → JSONL      │ │ notes →            │ │ notes → JS files     │
   │ http_records       │ │ session_config     │ │                      │
   └────────────────────┘ └────────────────────┘ └──────────────────────┘
              │                   │                   │
              └─────────────┬─────┴───────┬───────────┘
                            ▼             ▼
                    appended to     written to
                    ps.records      auth-config.yaml
Why split it this way: explore output is large (capped at 64 KB), per-topic format calls only see a 48 KB slice. Provider session caching keeps the explore context cheap to reuse across the three follow-ups instead of re-paying for it. The discovered session config can come back malformed; the engine round-trips invalid entries through the LLM for repair before hydration into auth headers and persistence to auth-config.yaml.

Master agent and batching

The plan phase is two sub-calls:
  1. Plan agent — analyses the records, returns a SwarmPlan with module tags/IDs, focus areas, and an extensions spec. Markdown-section output, retried up to MaxMasterRetries (default 3) on parse or transient errors.
  2. Extension agent (conditional) — only fires if the plan declared extensions. Generates JS scanner code. If this call fails, the plan from step 1 is still valid (graceful degradation).
When len(records) > MasterBatchSize (default 5), planning fans out:
   records ─► partition into batches of MasterBatchSize

                   ├─► batch 1 ┐
                   ├─► batch 2 │  parallel, up to BatchConcurrency (default 3)
                   ├─► batch 3 │  goroutines via errgroup
                   └─► batch N ┘

                          plan_1, plan_2, … plan_N

                         merge once at the end
                          • module tags/IDs: set union
                          • focus areas: deduplicated
                          • extensions: merged by filename;
                            collisions with different code → renamed
                          • provenance: which batch contributed what

                              SwarmPlan
The first batch error cancels the rest; partial-success merge is only attempted if the caller chooses to continue. When records are filtered for the prompt, a compact summary table of all endpoints is appended so the agent still sees the full surface even if only the top-N have full headers/bodies.

Triage and rescan loop

Triage is off by default. Pass --triage to enable.
   for round in 1..MaxIterations:
       ┌──────────────────────────────────┐
       │  query findings from DB           │  filter by severity / module
       │  (resume from last_finding_id)    │
       └─────────────┬────────────────────┘

       ┌──────────────────────────────────┐
       │  triage agent (AI)                │  per finding:
       │                                   │   confirmed | false-positive | rescan
       └─────────────┬────────────────────┘

            verdict == rescan?
              │              │
              │ yes          │ done / no-rescan
              ▼              ▼
       ┌──────────────┐    break
       │ native-rescan│
       │ OnlyPhase =  │
       │ dynamic-     │
       │ assessment   │
       └──────┬───────┘

       checkpoint round, continue
MaxIterations defaults to 1 (quick), 3 (balanced), 5 (deep). Triage processes findings in batches of 25 per round. Rescans set IsRescan=true on the ScanRequest, which forces OnlyPhase = "dynamic-assessment" and SkipIngestion = true so only the targeted modules execute.

Native scanner handoff

The swarm runner does not call modules itself — it hands off via callbacks the CLI installs on SwarmConfig:
CallbackSet whenWhat it does
ScanFuncalwaysRuns runner.RunNativeScan() with modules/extensions from the plan
DiscoverFunc--discoverCrawl/spider/JS-scan; merges discovered records before planning
SourceAnalysisCallback--sourceWrites auth-config.yaml from session config
ScanFunc is built like:
opts.Modules     = ResolveModulesFromPlan(req.ModuleTags, req.ModuleIDs)
opts.AuthConfigs = []string{generatedAuthConfigYAML} // from source analysis
opts.AuthConfigBestEffort = true                     // tolerate partial AI output
if req.IsRescan {
    opts.OnlyPhase     = "dynamic-assessment"
    opts.SkipIngestion = true
}
runner := runner.New(opts)
return runner.RunNativeScan()
This is the AI / native boundary: everything above is AI-shaped (prompt, plan, JS code, verdicts), everything below this call is the standard executor running the registered modules.

Session artifacts and checkpoints

A swarm run creates a session directory (default ~/.vigolium/agent-sessions/<run-id>/):
<sessionDir>/
├── swarm-plan.json            ← merged SwarmPlan from master agent
├── swarm-checkpoint.json      ← phase progress, plan, triage round
├── source-analysis-prompt.md
├── source-analysis-output.md
├── source-analysis-sections.json
├── source-extensions.json
├── auth-config.yaml           ← hydrated from session_config
├── code-audit-{prompt,output}.md
├── master-{prompt,output}.md
├── auth-{prompt,output}.md
├── extensions/*.js            ← validated, persisted
├── triage/triage-round-N-{prompt,output}.md
└── runtime.log                ← tee'd LLM stream; replay with `vigolium log`
swarm-checkpoint.json is rewritten after every phase. Combined with --start-from, it lets a partial run resume without re-paying for earlier phases.

CLI cheat sheet

# Minimum: target only — model picks modules from probed responses
vigolium agent swarm --target https://app.example.com

# Source-aware: 4-call source analysis + code audit
vigolium agent swarm --target https://app.example.com --source ./repo

# With triage and rescans (verifies findings, retries)
vigolium agent swarm --target https://app.example.com --triage --max-iterations 3

# Full-scope sweep — discovery + planning + scanning
vigolium agent swarm --target https://app.example.com --discover

# Use a preset
vigolium agent swarm --target https://app.example.com --intensity deep

# Start from a specific phase using an existing session
vigolium agent swarm --resume <run-id> --start-from plan

# Pipe a curl command — input auto-detected
echo "curl -X POST https://app.example.com/api/login -d '{\"u\":\"a\"}'" | vigolium agent swarm

# Force extension generation even when the master returns none
vigolium agent swarm -t https://app.example.com --force-extensions

# Render prompts without calling the LLM
vigolium agent swarm --target https://app.example.com --dry-run --show-prompt

# Use a different olium provider for this run
vigolium agent swarm -t https://app.example.com \
  --provider anthropic-api-key --model claude-opus-4-7

Important flags

FlagEffect
-t, --targetTarget URL for dynamic phases
--inputRaw input (curl, HTTP, Burp XML, base64, URL) — auto-detected
--record-uuidUse an HTTP record from the database as the seed input
--sourceSource-code path (or git URL); enables source analysis + code-audit
--code-auditForce code audit (auto-on with --source for balanced/deep)
--discoverRun native discovery before planning
--triageEnable verify-and-rescan loop
--max-iterationsTriage rounds (preset-driven default)
--master-batch-sizeRecords per master-agent batch (default 5)
--batch-concurrencyParallel master batches (default 3)
--intensityquick / balanced / deep preset bundle
--archonlite / balanced / deep / mock / off (parallel source audit)
--skip-phases, --start-fromPhase control / resume
--source-analysis-onlyStop after source analysis
--force-extensionsForce the extension agent even when the plan returned none
-m, --modulesExplicit module IDs to merge with the agent’s selection
--vuln-typeVulnerability focus (e.g. sqli, xss, ssrf)
--focusBroad strategic focus area hint
--instruction / --instruction-fileCustom instructions appended to prompts
--upload-resultsUpload session bundle to cloud storage on completion
--provider, --model, --oauth-cred, --oauth-token, --llm-api-keyOlium provider overrides

API

POST /api/agent/run/swarm
{
  "input": "curl -X POST https://example.com/api/login -d '{\"user\":\"admin\"}'",
  "vuln_type": "sqli",
  "focus": "auth bypass",
  "module_names": ["sqli-error-based"],
  "discover": true,
  "code_audit": true,
  "triage": true,
  "max_iterations": 3,
  "intensity": "balanced",
  "archon": "lite",
  "stream": true,
  "timeout": "15m"
}
At least one of input, inputs, target, record_uuid, or http_request_base64 is required. See API Reference — Agent for the full schema.

Where things live

ConcernFile
CLI flags + callback wiringpkg/cli/agent_swarm.go
Phase dispatch + statepkg/agent/swarm_pipeline.go
Master agent, batching, triagepkg/agent/swarm.go
4-call source analysispkg/agent/engine.go (RunSourceAnalysisParallel)
Phase constants + presetspkg/agent/agenttypes/constants.go
Native scanner entrypkg/core/executor.go, internal/runner/runner.go
For the broader architecture (olium runtime, providers, common engine), see How It Works.