> ## 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.

# Agent Swarm

> AI-guided multi-phase scan: master agent reads requests, picks modules, generates JS extensions, runs the native scanner, and optionally triages findings.

`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

| Scenario                                                                                               | Use                     |
| ------------------------------------------------------------------------------------------------------ | ----------------------- |
| You have a target URL, raw request, or HTTP record and want the agent to pick modules + write payloads | `swarm`                 |
| You also have the application source, want routes + auth + extensions inferred from code               | `swarm --source <path>` |
| You want false-positive verification and targeted re-scans on the model's say-so                       | `swarm --triage`        |
| You'd rather hand the agent a shell + the codebase and let it decide everything                        | `autopilot`             |
| You want a one-shot prompt with no scanning                                                            | `agent 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

| #  | Phase              | Type      | Purpose                                                      | Trigger                                                |
| -- | ------------------ | --------- | ------------------------------------------------------------ | ------------------------------------------------------ |
| 1  | `native-normalize` | Native    | Parse `--input`/stdin/record-uuid into `HttpRequestResponse` | Always                                                 |
| 2  | `auth`             | AI/Native | Browser-driven login, writes auth headers/cookies            | `--browser-auth` + `--browser`                         |
| 3  | `source-analysis`  | AI        | 4-call wave: explore → routes / session / extensions         | `--source`                                             |
| 4  | `code-audit`       | AI        | Code-level security audit, findings → DB                     | `--code-audit` (auto with `--source` at balanced/deep) |
| 5  | `native-discover`  | Native    | Crawl/spider/JS-scan to discover endpoints                   | `--discover`                                           |
| 6  | `plan`             | AI        | Master agent: pick modules, focus areas, extensions spec     | Always                                                 |
| 7  | `native-extension` | Native    | Validate generated JS, write to `extensions/`                | Plan declared extensions                               |
| 8  | `native-scan`      | Native    | Hand off to `runner.RunNativeScan()`                         | Always                                                 |
| 9  | `triage`           | AI        | Verify findings; mark confirmed / FP / rescan                | `--triage`                                             |
| 10 | `native-rescan`    | Native    | Targeted 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`:

| Callback                 | Set when     | What it does                                                        |
| ------------------------ | ------------ | ------------------------------------------------------------------- |
| `ScanFunc`               | always       | Runs `runner.RunNativeScan()` with modules/extensions from the plan |
| `DiscoverFunc`           | `--discover` | Crawl/spider/JS-scan; merges discovered records before planning     |
| `SourceAnalysisCallback` | `--source`   | Writes `auth-config.yaml` from session config                       |

`ScanFunc` is built like:

```go theme={null}
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
├── 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`
```

`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

```bash theme={null}
# 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

| Flag                                                                      | Effect                                                                                                   |
| ------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| `-t, --target`                                                            | Target URL for dynamic phases                                                                            |
| `--input`                                                                 | Raw input (curl, HTTP, Burp XML, base64, URL), auto-detected                                             |
| `--record-uuid`                                                           | Use an HTTP record from the database as the seed input                                                   |
| `--source`                                                                | Source-code path (or git URL); enables source analysis + code-audit                                      |
| `--code-audit`                                                            | Force code audit (auto-on with `--source` for balanced/deep)                                             |
| `--discover`                                                              | Run native discovery before planning                                                                     |
| `--triage`                                                                | Enable verify-and-rescan loop                                                                            |
| `--skill`                                                                 | Force-load these skills by name into triage, bypassing planner selection (repeatable or comma-separated) |
| `--skill-tag`                                                             | Force-load every skill carrying one of these tags into triage (e.g. `xss,idor`)                          |
| `--no-skill-filter`                                                       | Load the full skill set into triage; ignore planner selection                                            |
| `--db-isolate`                                                            | Scan into a private temp DB, then merge results into `--db` at the end (SQLite only)                     |
| `--max-iterations`                                                        | Triage rounds (preset-driven default)                                                                    |
| `--master-batch-size`                                                     | Records per master-agent batch (default 5)                                                               |
| `--batch-concurrency`                                                     | Parallel master batches (default 3)                                                                      |
| `--intensity`                                                             | `quick` / `balanced` / `deep` preset bundle                                                              |
| `--audit`                                                                 | `lite` / `balanced` / `deep` / `mock` / `off` (parallel source audit)                                    |
| `--skip-phases`, `--start-from`                                           | Phase control / resume                                                                                   |
| `--source-analysis-only`                                                  | Stop after source analysis                                                                               |
| `--force-extensions`                                                      | Force the extension agent even when the plan returned none                                               |
| `-m, --modules`                                                           | Explicit module IDs to merge with the agent's selection                                                  |
| `--vuln-type`                                                             | Vulnerability focus (e.g. `sqli`, `xss`, `ssrf`)                                                         |
| `--focus`                                                                 | Broad strategic focus area hint                                                                          |
| `--instruction` / `--instruction-file`                                    | Custom instructions appended to prompts                                                                  |
| `--upload-results`                                                        | Upload session bundle to cloud storage on completion                                                     |
| `--provider`, `--model`, `--oauth-cred`, `--oauth-token`, `--llm-api-key` | Olium provider overrides                                                                                 |

***

## API

```
POST /api/agent/run/swarm
```

```json theme={null}
{
  "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",
  "audit": "lite",
  "stream": true,
  "timeout": "12h"
}
```

At least one of `input`, `inputs`, or `http_request_base64` is required (`url` is an optional hint). `timeout` defaults to **12h** when omitted. See [API Reference, Agent](/api-references/agent) for the full schema.

***

## Where things live

| Concern                        | File                                                |
| ------------------------------ | --------------------------------------------------- |
| CLI flags + callback wiring    | `pkg/cli/agent_swarm.go`                            |
| Phase dispatch + state         | `pkg/agent/swarm_pipeline.go`                       |
| Master agent, batching, triage | `pkg/agent/swarm.go`                                |
| 4-call source analysis         | `pkg/agent/engine.go` (`RunSourceAnalysisParallel`) |
| Phase constants + presets      | `pkg/agent/agenttypes/constants.go`                 |
| Native scanner entry           | `pkg/core/executor.go`, `internal/runner/runner.go` |

For the broader architecture (olium runtime, providers, common engine), see [How It Works](/agentic-scan/how-it-works).
