agent

package
v0.5.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 3, 2026 License: MIT Imports: 66 Imported by: 0

Documentation

Overview

Package agent implements the agentic scan engine that powers the autopilot, swarm, and query modes. It owns prompt templates and rendering, context enrichment, the autopilot pipeline and swarm runners, structured output parsing (findings, HTTP records, attack plans, triage results, source analysis), and ingestion of results into the database. All AI dispatch is routed through the in-process olium engine via olium_adapter.go; there are no subprocess SDK backends. See docs/agentic-scan/agent-mode.md.

Index

Constants

View Source
const (
	AuditDriverAgentClaude = agenttypes.AuditDriverAgentClaude
	AuditDriverAgentCodex  = agenttypes.AuditDriverAgentCodex
)
View Source
const (
	// Evidence status
	EvidenceStatusExploited     = agenttypes.EvidenceStatusExploited
	EvidenceStatusBlocked       = agenttypes.EvidenceStatusBlocked
	EvidenceStatusFalsePositive = agenttypes.EvidenceStatusFalsePositive

	// InputType
	InputTypeURL        = agenttypes.InputTypeURL
	InputTypeCurl       = agenttypes.InputTypeCurl
	InputTypeBurp       = agenttypes.InputTypeBurp
	InputTypeRaw        = agenttypes.InputTypeRaw
	InputTypeBase64     = agenttypes.InputTypeBase64
	InputTypeRecordUUID = agenttypes.InputTypeRecordUUID
	InputTypeUnknown    = agenttypes.InputTypeUnknown

	// Intensity
	IntensityQuick    = agenttypes.IntensityQuick
	IntensityBalanced = agenttypes.IntensityBalanced
	IntensityDeep     = agenttypes.IntensityDeep

	// Triage confirm verdict + template identifiers
	TriageVerdictConfirmed     = agenttypes.TriageVerdictConfirmed
	TriageVerdictFalsePositive = agenttypes.TriageVerdictFalsePositive
	TriageConfirmTemplateID    = agenttypes.TriageConfirmTemplateID
	TriageConfirmOutputSchema  = agenttypes.TriageConfirmOutputSchema

	// SwarmPhase
	SwarmPhaseNormalize       = agenttypes.SwarmPhaseNormalize
	SwarmPhaseAuth            = agenttypes.SwarmPhaseAuth
	SwarmPhaseSourceAnalysis  = agenttypes.SwarmPhaseSourceAnalysis
	SwarmPhaseCodeAudit       = agenttypes.SwarmPhaseCodeAudit
	SwarmPhaseDiscover        = agenttypes.SwarmPhaseDiscover
	SwarmPhaseRecon           = agenttypes.SwarmPhaseRecon
	SwarmPhasePlan            = agenttypes.SwarmPhasePlan
	SwarmPhaseExtension       = agenttypes.SwarmPhaseExtension
	SwarmPhaseScan            = agenttypes.SwarmPhaseScan
	SwarmPhaseDiscoverReentry = agenttypes.SwarmPhaseDiscoverReentry
	SwarmPhaseReplanOnEmpty   = agenttypes.SwarmPhaseReplanOnEmpty
	SwarmPhaseTriage          = agenttypes.SwarmPhaseTriage
	SwarmPhaseRescan          = agenttypes.SwarmPhaseRescan

	RecordSourceDiscoverReentry = agenttypes.RecordSourceDiscoverReentry
)

Re-export constants. Go type aliases preserve constant compatibility for typed constants, but untyped string constants must be re-declared.

View Source
const (
	AuditDriverPiolium = "piolium"
	AuditDriverAudit   = "audit"
	AuditDriverBoth    = "both"
	// AuditDriverAuto is the default. A preflight picks the leg: when the
	// resolved coding-agent CLI (claude or codex) is on PATH, the audit
	// binary is embedded, and the mode chain holds at least one
	// audit-supported mode, audit runs and piolium is never consulted.
	// If any of those checks fails, audit is skipped without ever being
	// launched and piolium runs as the fallback.
	//
	// A mid-run audit failure is deliberately NOT a fallback trigger:
	// once audit starts, its outcome is the run's outcome. Because a
	// clean audit run never consults piolium, a missing piolium runtime
	// is not reported up front.
	AuditDriverAuto = "auto"
)

Audit driver IDs for the unified `vigolium agent audit` and `POST /api/agent/run/audit` dispatcher. The JSON `driver` field on `AgentAuditRequest` accepts these values verbatim, and `vigolium agent audit --driver=...` mirrors the same set, so they live here as the single source of truth shared by CLI and server packages.

View Source
const (
	SwarmPromptPlan       = "agent-swarm-plan"
	SwarmPromptExtensions = "agent-swarm-extensions"
	SwarmPromptCodeAudit  = "swarm-code-audit"
	SwarmPromptTriage     = "agent-swarm-triage"
	SwarmPromptAuth       = "agent-swarm-auth"
)

Prompt template constants for the agent swarm mode.

View Source
const AuditDedupTimeout = 30 * time.Second

AuditDedupTimeout caps the post-pass project-wide findings dedup so a large findings table can't stall the orchestrator's exit. Failure is logged-and-swallowed; the audit still reports completion.

View Source
const DefaultAuditSyncInterval = 30 * time.Second

DefaultAuditSyncInterval is the per-runner audit-state.json sync cadence used by every audit dispatcher entry point.

View Source
const PlatformAuditBin = "audit"

PlatformAuditBin identifies the embedded vigolium-audit binary as the audit runner. vigolium-audit dispatches to claude or codex internally; the per-run agent comes from AuditAgentConfig.AuditDriverInvocation.

View Source
const PlatformPi = "pi"

PlatformPi is the Pi runtime platform — runs piolium via `pi --mode json`.

Variables

View Source
var (
	NormalizeSwarmPhase         = agenttypes.NormalizeSwarmPhase
	PhaseSkipped                = agenttypes.PhaseSkipped
	WithSessionsDir             = agenttypes.WithSessionsDir
	ValidateIntensity           = agenttypes.ValidateIntensity
	NativeScanIntensityProfiles = agenttypes.NativeScanIntensityProfiles
)

Re-export functions with external consumers.

View Source
var (
	CleanupSessionDirs           = authsession.CleanupSessionDirs
	AgentSessionConfigToSessions = authsession.AgentSessionConfigToSessions
)

Re-export backend utilities with external consumers. These are session / auth-header helpers that survived the subprocess removal.

View Source
var (
	ParseFindings            = parsing.ParseFindings
	ParseHTTPRecords         = parsing.ParseHTTPRecords
	ParseTriageConfirmResult = parsing.ParseTriageConfirmResult
	ToDBFinding              = parsing.ToDBFinding
)

Re-export parsing functions with external consumers.

View Source
var (
	TargetURLFromInput = agentinput.TargetURLFromInput
	ParsePlanFile      = agentinput.ParsePlanFile
)

Re-export input functions with external consumers.

View Source
var (
	ListTemplates       = agentprompt.ListTemplates
	ResolveTemplatePath = agentprompt.ResolveTemplatePath
)

Re-export prompt functions with external consumers.

View Source
var (
	// WithCloneDepth sets the git clone depth for remote sources.
	WithCloneDepth = source.WithCloneDepth
	// ResolveSourceAndDiff resolves a --source and optional --diff into a local
	// path, changed-file list, and diff context.
	ResolveSourceAndDiff = source.ResolveSourceAndDiff
	// DetectTargetFromSource infers a running app URL from a source tree.
	DetectTargetFromSource = source.DetectTargetFromSource
)
View Source
var ErrPromptRefused = errors.New("prompt refused by guardrail")

ErrPromptRefused is returned when the safety classifier rejects a prompt. Wrapped with the verdict reason so callers can errors.Is + read the cause.

Functions

func ApplyAuthOverrideToAudit

func ApplyAuthOverrideToAudit(inv *agenttypes.AuditDriverInvocation, o agenttypes.AuthOverride)

ApplyAuthOverrideToAudit folds a BYOK override into an AuditDriverInvocation in-place. When the override is empty the invocation is unchanged (preserving the agent.olium.* derived auth). When set, the override REPLACES whatever the resolver derived from olium config — including clearing fields the override doesn't touch, so a half-set audit auth from olium (e.g. an OAuthCredFile) doesn't leak into a run where the operator passed --oauth-token.

func AuditDriverCLIAvailable

func AuditDriverCLIAvailable(a AuditDriverAgent) (string, bool)

AuditDriverCLIAvailable reports whether the coding-agent CLI that vigolium-audit will drive (claude or codex) is on PATH for the given resolved agent. Empty defaults to claude (vigolium-audit's own default). Used by --driver=auto to skip the audit leg without launching the embedded binary when its required CLI is missing.

func CleanupOrphanedProcesses

func CleanupOrphanedProcesses(sessionsDir string) int

CleanupOrphanedProcesses scans session directories for run.pid files and cleans up orphaned agent processes.

A run.pid records the OWNING vigolium process's PID/PGID. An "orphan" is a run whose owner has DIED but which may have left agent subprocesses alive in its process group. So:

  • If the recorded PID is still ALIVE it is NOT an orphan — it is either a legitimately running concurrent vigolium instance or an unrelated process that reused the PID. Either way we must not kill it. (The previous logic killed alive PIDs, so starting a second run could terminate a live first run or an unrelated process after PID reuse.)
  • If the recorded PID is DEAD, the run is orphaned: reap any subprocesses that outlived it in its process group, then remove the stale PID file.

Returns the number of sessions cleaned up.

func CleanupStaleTempDirs

func CleanupStaleTempDirs()

CleanupStaleTempDirs removes orphaned vigolium temp directories older than 24 hours.

func CopySkillsToSessionDir

func CopySkillsToSessionDir(sessionDir string)

CopySkillsToSessionDir copies embedded skill files to the session directory so the agent can discover them from its working directory.

func DriverIncludesAudit

func DriverIncludesAudit(driver string) bool

DriverIncludesAudit reports whether the audit driver runs audit.

func DriverIncludesPiolium

func DriverIncludesPiolium(driver string) bool

DriverIncludesPiolium reports whether the audit driver may run piolium. For "auto" piolium only runs as an audit fallback, but it is still in the potential driver set, so mode/auth validation treats it as included.

func EnsureSessionDir

func EnsureSessionDir(baseDir, agenticScanUUID string) (string, error)

EnsureSessionDir creates the session directory for a given run ID under the specified base directory. If baseDir is empty, defaults to ~/.vigolium/agent-sessions/. Returns the absolute path to the created directory.

func ExtraHeadersFromAuth

func ExtraHeadersFromAuth(cfg *AgentSessionConfig) map[string]string

ExtraHeadersFromAuth returns the primary session's static headers as a map. Login entries are ignored — replaying logins is the auth phase's job, not recon's.

func FirstMode

func FirstMode(modes []string) string

FirstMode returns the first mode of a chain, or "" for an empty chain. Used to keep AuditAgentConfig.Mode populated alongside Modes for the single-mode consumers that never chain.

func ForceAuditDriverAgent

func ForceAuditDriverAgent(inv *AuditDriverInvocation, agentOverride string)

ForceAuditDriverAgent layers the CLI --agent flag on top of an already resolved invocation. It is a *pure agent selector*: when agentOverride is a valid audit agent (claude|codex) it replaces inv.Agent only, leaving the provider-derived auth on inv untouched. This is what makes `--provider <p> --agent <a>` keep <p>'s BYOK auth while running agent <a>. An empty or invalid override is a no-op, so the resolver's provider-derived agent stands (callers validate up front and surface a clear error for genuinely bad input).

func IsMultiDriverAudit

func IsMultiDriverAudit(driver string) bool

IsMultiDriverAudit reports whether the driver can dispatch both harnesses in one run (so per-driver auth overrides are allowed, the shared-mode restriction applies, and a missing single runtime is a warning rather than a hard error). True for "both" and "auto".

func IsProcessAlive

func IsProcessAlive(pid int) bool

IsProcessAlive checks whether a process with the given PID is still running.

func IsSharedAuditMode

func IsSharedAuditMode(mode string) bool

IsSharedAuditMode returns true when the given audit mode is supported by both audit and piolium harnesses. Used by the unified audit dispatcher to validate `--driver=both` runs, where the same mode is dispatched to each driver in turn.

func IsValidAuditDriver

func IsValidAuditDriver(driver string) bool

IsValidAuditDriver reports whether driver is a recognized audit driver.

func IsValidAuditDriverAgent

func IsValidAuditDriverAgent(s string) bool

IsValidAuditDriverAgent reports whether s is a recognized audit `--agent` value (claude|codex). Used by CLI / REST validation of the --provider override.

func IsValidAuditDriverMode

func IsValidAuditDriverMode(mode string) bool

IsValidAuditDriverMode reports whether mode is a recognized audit mode.

func IsValidAuditDriverPlatform

func IsValidAuditDriverPlatform(platform string) bool

IsValidAuditDriverPlatform reports whether platform is a recognized audit agent identifier. Same set as IsValidAuditDriverAgent plus the empty string, which is treated as "inherit agent from olium config" by the resolver.

func JoinModes

func JoinModes(modes []string) string

JoinModes renders a mode chain back to the comma-separated form audit's `--modes` flag expects and the audit banner / DB Mode column display.

func ParseModesCSV

func ParseModesCSV(s string) []string

ParseModesCSV splits a comma-separated --modes value into a clean, order-preserving, de-duplicated slice. Whitespace around each token is trimmed and empty tokens are dropped. A bare "" returns nil so callers can fall back to the single --mode / intensity-derived value.

func PiAuthEnv

func PiAuthEnv(o agenttypes.AuthOverride) []string

PiAuthEnv maps the BYOK override into the env vars `pi`'s provider drivers honor.

For api_key / oauth_token: returns one or two KEY=VALUE entries the caller should append to the pi subprocess env. The function never sets the env in-process — vigolium injects per-subprocess so concurrent runs don't trample one another.

For oauth_cred_file: returns nil. Codex doesn't read the file from an env var; vigolium stages it under <pi-agent-dir>/auth.json (handled by the launcher in pkg/agent/audit_agent.go) so the codex provider picks it up via its standard read path.

Returns nil for an empty override (no env injection needed).

func RecordsForPrefixes

func RecordsForPrefixes(records []*httpmsg.HttpRequestResponse, prefixes []string) []*httpmsg.HttpRequestResponse

func RefusalError

func RefusalError(verdict GuardrailVerdict) error

RefusalError wraps ErrPromptRefused with the verdict reason. Callers that want errors.Is(err, ErrPromptRefused) get it for free.

func RemoveRunPID

func RemoveRunPID(sessionDir string)

RemoveRunPID removes the run.pid file from the session directory. Best-effort: errors are logged but not returned.

func ResolveAuditAgentConfig

func ResolveAuditAgentConfig(noAudit bool, mode string, sourcePath string, agentCfg config.AuditAgentConfig) *config.AuditAgentConfig

Audit is enabled by default when source code is available. Pass noAudit=true to force-disable it (--no-audit flag). When the passed mode is empty it falls back to agentCfg.EffectiveMode() (balanced by default). Returns nil when the audit agent should not run.

func ResolveAuditDriverIntensity

func ResolveAuditDriverIntensity(intensity agenttypes.Intensity, current agenttypes.AuditDriverIntensityPreset, changed map[string]bool) agenttypes.AuditDriverIntensityPreset

ResolveAuditDriverIntensity merges intensity preset values with user-provided overrides. The changed map indicates which fields were explicitly set by the user (CLI flag or API field). Explicit values in current take precedence over the preset.

Note: audit also accepts operational modes (revisit, confirm, merge, diff, status, mock) that are not intensity-driven. Callers must pass changed["mode"]=true (or changed["modes"]=true for a chain) when the user supplied an explicit --mode / --modes field, which then bypasses the preset's chain entirely.

Mode and Modes are kept consistent on the result: Mode is always Modes[0] so single-mode consumers stay correct even when a chain preset is selected.

func ResolveAuthAgent

func ResolveAuthAgent(providerOrAgentOverride, oliumProvider string) string

ResolveAuthAgent picks the audit-style agent identity ("claude" or "codex") that BYOK creds should target, given the optional CLI/REST override and the configured olium provider. Centralized so the CLI, REST, and any future entry point all answer "is this a claude or codex key?" the same way.

CLI and REST feed semantically different inputs here:

  • CLI passes --provider, a provider name like "openai-codex-oauth" → mapped via auditAgentSelFromProvider.
  • REST passes req.Agent, a direct agent name ("claude" | "codex") validated upstream by IsValidAuditDriverPlatform.

We accept both forms: a direct agent name short-circuits the provider-prefix mapping, so REST's `agent:"codex"` correctly resolves to "codex" instead of falling through to the default ("claude") and silently bypassing the validator's oauth_token-needs-claude rule.

Precedence:

  1. providerOrAgentOverride (--provider or req.Agent)
  2. oliumProvider → auditAgentSelFromProvider
  3. Default → "claude"

func ResolveAutopilotIntensity

func ResolveAutopilotIntensity(intensity agenttypes.Intensity, current agenttypes.AutopilotIntensityPreset, changed map[string]bool) agenttypes.AutopilotIntensityPreset

ResolveAutopilotIntensity merges intensity preset values with user-provided overrides. The changed map indicates which fields were explicitly set by the user (CLI flag or API field). Explicit values in current take precedence over the preset.

func ResolveModulesFromPlan

func ResolveModulesFromPlan(tags []string, ids []string) []string

ResolveModulesFromPlan converts agent-suggested tags and IDs into a deduplicated module ID list. Falls back to ["all"] when no modules are resolved.

func ResolveNativeScanIntensity

func ResolveNativeScanIntensity(intensityStr string) (profileName string, resolvedIntensity string, err error)

ResolveNativeScanIntensity validates the intensity string and returns the corresponding scanning profile name. It also sets opts.Intensity for logging.

func ResolvePioliumAuditConfig

func ResolvePioliumAuditConfig(mode, sourcePath string) *config.AuditAgentConfig

ResolvePioliumAuditConfig is the piolium counterpart of ResolveAuditAgentConfig: returns nil when the audit should not run (mode empty/"off" or no source). The returned cfg is intentionally minimal — Platform and StreamDecoder are auto-installed inside StartAuditAgent based on the harness it receives.

func ResolveSwarmIntensity

func ResolveSwarmIntensity(intensity agenttypes.Intensity, current agenttypes.SwarmIntensityPreset, changed map[string]bool) agenttypes.SwarmIntensityPreset

ResolveSwarmIntensity merges intensity preset values with user-provided overrides. The changed map indicates which fields were explicitly set by the user (CLI flag or API field). Explicit values in current take precedence over the preset.

func RunAuditDriverInteractive

func RunAuditDriverInteractive(ctx context.Context, cfg AuditAgentConfig) error

RunAuditDriverInteractive launches the embedded vigolium-audit binary in interactive mode (`-i`) attached to the caller's terminal, then blocks until it exits.

This is the "drop into the coding agent" path: audit's `-i` installs its harness (agent defs + slash commands) into the coding agent and hands the terminal to the user, who drives the audit themselves inside Claude/Codex. Because the operator owns the session, vigolium does NOT decode an NDJSON stream, create an AgenticScan row, or auto-import findings here — audit writes its results to <source>/audit/ and the operator imports them afterward (`vigolium import <source>/audit`).

The command is built through the same buildAuditAgentCommand path as a headless run so --target / --mode|--modes / --agent / auth flags stay identical; the only differences are stream=false (no --json — interactive replaces the machine log) and the appended -i.

func SwarmPhaseDescription

func SwarmPhaseDescription(phase string) string

SwarmPhaseDescription returns a short description of what a swarm phase does.

func SwarmPhasePrompt

func SwarmPhasePrompt(phase string) string

SwarmPhasePrompt returns the prompt template name for a given swarm phase, if any.

func ToHTTPRequestResponse

func ToHTTPRequestResponse(rec AgentHTTPRecord) (*httpmsg.HttpRequestResponse, error)

ToHTTPRequestResponse converts an AgentHTTPRecord to an httpmsg.HttpRequestResponse.

func ValidateAuditDriverInvocation

func ValidateAuditDriverInvocation(inv AuditDriverInvocation) error

ValidateAuditDriverInvocation checks that the resolved auth is usable by the resolved agent. A pure agent selector — the `--agent` flag or agent.audit.default_agent — flips inv.Agent while deliberately keeping the provider/BYOK-derived auth, so it can pair codex with an Anthropic OAuth token (claude-only), which vigolium-audit rejects mid-run. Catching it here turns that into a clear pre-flight error.

Only the OAuthToken→claude rule is enforced, mirroring ValidateAuthOverride: API keys are agent-agnostic at this layer, and a codex cred file paired with claude is left to vigolium-audit so the documented "--agent keeps the resolved auth" contract is preserved. Returns nil when no auth is set or it is compatible.

func ValidateAuditDriverMode

func ValidateAuditDriverMode(driver, mode string, modeIsValidForPiolium, modeIsValidForAudit func(string) bool) error

ValidateAuditDriverMode returns an error when mode is not valid for the given audit driver. driver=both restricts to the shared set so both runners can dispatch the same mode without coercion surprises; single-driver invocations accept the driver's full mode set.

modeIsValidForPiolium and modeIsValidForAudit are injected to avoid dragging the piolium and audit driver-specific validators into pkg/agent's import graph.

func ValidateAuditDriverModes

func ValidateAuditDriverModes(driver string, modes []string, modeIsValidForPiolium, modeIsValidForAudit func(string) bool) (auditChain, pioliumChain []string, err error)

ValidateAuditDriverModes validates a mode chain for the given driver and returns the per-driver filtered chains (audit's modes first, then piolium's). A mode invalid for BOTH drivers is always an error (typo guard). For an explicit single driver every mode must be valid for that driver — silently dropping one the operator asked for would be surprising. For multi-driver paths (auto/both) each mode only has to be valid for at least one driver; per-driver-unsupported modes are skipped on that driver's leg.

func ValidateAuthOverride

func ValidateAuthOverride(o agenttypes.AuthOverride) error

ValidateAuthOverride enforces the BYOK rules shared by CLI and REST:

  1. At most one of APIKey / OAuthToken / OAuthCredFile is set. Mixing them is almost always an operator mistake and the harness can only honor one at a time anyway.
  2. OAuthToken requires the claude side. OpenAI/codex has no equivalent bearer token form (codex uses cred files), so this catches the cross-wire of pasting an Anthropic OAuth token into a codex run.

The Agent field on the override drives rule 2. Empty defaults to claude (matches audit's own default + the audit resolver's behavior).

Returns nil for an entirely-empty override, since "inherit ambient agent.olium.* config" is the documented no-op behavior.

func WrapProviderWithSemaphore

func WrapProviderWithSemaphore(cfg *config.OliumConfig, p provider.Provider) provider.Provider

WrapProviderWithSemaphore returns a provider.Provider that gates each Stream call through the shared oliumProviderSem. Use this around the resolved provider before passing it into long-running loops (autopilot) so their per-turn LLM calls participate in the same process-wide cap as the swarm/source-analysis paths — without this, autopilot bypasses the limiter and N concurrent sessions can flood the provider with 429s.

The slot is held only for the duration of one Stream (one model turn), not the whole run, so a multi-hour autopilot doesn't pin a slot.

func WriteAuthConfigYAML

func WriteAuthConfigYAML(sessionDir string, cfg *AgentSessionConfig) (string, error)

func WriteCheckpointToDir

func WriteCheckpointToDir(sessionDir string, cp *SwarmCheckpoint) error

WriteCheckpointToDir persists a SwarmCheckpoint to the session directory (exported for CLI use).

func WriteExtensionsToSessionDir

func WriteExtensionsToSessionDir(extensions []GeneratedExtension, sessionDir string) (string, error)

WriteExtensionsToSessionDir writes generated JavaScript extensions to <sessionDir>/extensions/ and returns the extensions subdirectory path.

func WriteExtensionsToTempDir

func WriteExtensionsToTempDir(extensions []GeneratedExtension, prefix string) (string, error)

WriteExtensionsToTempDir writes generated JavaScript extensions to a temporary directory and returns the directory path. Caller is responsible for cleanup.

func WriteRunPID

func WriteRunPID(sessionDir string) error

WriteRunPID writes a run.pid JSON file to the given session directory.

func WriteSwarmCoverageReport

func WriteSwarmCoverageReport(sessionDir string, report *SwarmCoverageReport) string

WriteSwarmCoverageReport writes the report to {sessionDir}/coverage.json and returns the path. I/O errors are logged and "" returned — a serialization hiccup must not fail a 12-hour scan.

Types

type AgentExpectResponse

type AgentExpectResponse = agenttypes.AgentExpectResponse

Pipeline types

type AgentExtensionsOutput

type AgentExtensionsOutput = agenttypes.AgentExtensionsOutput

Pipeline types

type AgentExtractRule

type AgentExtractRule = agenttypes.AgentExtractRule

Pipeline types

type AgentFinding

type AgentFinding = agenttypes.AgentFinding

Findings & HTTP records

type AgentFindingsOutput

type AgentFindingsOutput = agenttypes.AgentFindingsOutput

Findings & HTTP records

type AgentHTTPRecord

type AgentHTTPRecord = agenttypes.AgentHTTPRecord

Findings & HTTP records

type AgentHTTPRecordsOutput

type AgentHTTPRecordsOutput = agenttypes.AgentHTTPRecordsOutput

Findings & HTTP records

type AgentLoginFlow

type AgentLoginFlow = agenttypes.AgentLoginFlow

Pipeline types

type AgentRuntime

type AgentRuntime interface {
	// RunPrompt runs one prompt on a fresh session. When sourcePath is set it is
	// appended to the system prompt so the agent knows it has filesystem access
	// to local source. Text deltas mirror to streamWriter and reasoning deltas to
	// thinkingWriter when those are non-nil. When rec.SessionDir is set, the
	// fresh engine records a Pi-style JSONL transcript (flushed before return).
	RunPrompt(ctx context.Context, cfg *config.OliumConfig, prompt string, streamWriter, thinkingWriter io.Writer, sourcePath string, verbose bool, rec RecordSpec) (oliumRunOutput, error)

	// RunOnSession runs one prompt reusing an existing session's warm prefix.
	// Unlike RunPrompt it takes no RecordSpec: a reused session's transcript
	// recorder (if any) is attached once when the session is built
	// (NewSessionWithSpec with a RecordSpec) and spans all of its prompts, then
	// flushed by AgentSession.Close().
	RunOnSession(ctx context.Context, cfg *config.OliumConfig, sess AgentSession, prompt string, streamWriter, thinkingWriter io.Writer, verbose bool) (oliumRunOutput, error)

	// NewSession builds a reusable session without running anything. Equivalent
	// to NewSessionWithSpec with the standard tool-enabled spec.
	NewSession(cfg *config.OliumConfig, sourcePath string) (AgentSession, error)

	// NewSessionWithSpec builds a session from an explicit SessionSpec, for
	// specialized flows that need a custom system prompt, turn cap, or tool set.
	NewSessionWithSpec(cfg *config.OliumConfig, spec SessionSpec) (AgentSession, error)
}

AgentRuntime abstracts AI dispatch so the agent engine depends on an interface rather than the concrete olium runtime. The default implementation (oliumRuntime) is backed by the in-process olium engine; tests can substitute a fake. This is the single seam between agent orchestration and the LLM runtime: concrete olium types live behind it (here and in olium_adapter.go), keeping the rest of pkg/agent free of a hard dependency on one runtime.

type AgentSession

type AgentSession interface {
	Fork() AgentSession
	Close() error
}

AgentSession is an opaque, reusable agent conversation whose prefix (system prompt, tool definitions, prior turns) stays warm across prompts so the provider's prompt cache hits. Fork returns a child that shares the prefix but runs independently — used for parallel sub-runs such as the source-analysis fan-out.

Close flushes and releases any per-session artifact (notably the Pi-style JSONL transcript recorder): the recorder buffers the final assistant turn until the run ends, so a session built with a RecordSpec must be Closed for that turn to land. Sessions without a recorder Close to a no-op. Forks carry no recorder (concurrent sub-runs would interleave one file), so closing a fork is always a no-op.

type AgentSessionConfig

type AgentSessionConfig = agenttypes.AgentSessionConfig

Pipeline types

func RepairInvalidSessionConfig

func RepairInvalidSessionConfig(ctx context.Context, engine *Engine, original *AgentSessionConfig, targetURL string, cfg RepairConfig) *AgentSessionConfig

RepairInvalidSessionConfig uses an LLM to fix garbled session config entries. It stays in the root package because it depends on *Engine.

func SynthesizeAuthConfig

func SynthesizeAuthConfig(cookies []string, headers []string, loginCurl string) (*AgentSessionConfig, error)

SynthesizeAuthConfig builds a single-session AgentSessionConfig from operator-supplied cookies, headers, and/or a login-curl. Returns (nil, nil) when all inputs are empty so callers can fall through to browser-auth or no-auth.

type AgentSessionEntry

type AgentSessionEntry = agenttypes.AgentSessionEntry

Pipeline types

type AppIntent

type AppIntent = agenttypes.AppIntent

Intent types

type AttackPlan

type AttackPlan = agenttypes.AttackPlan

Pipeline types

type AuditAgentConfig

type AuditAgentConfig = agenttypes.AuditAgentConfig

Audit types

func BuildAuditDriverCfg

func BuildAuditDriverCfg(in AuditDriverCfgInput) AuditAgentConfig

BuildAuditDriverCfg assembles the AuditAgentConfig that drives an audit run. Used by every entry point that launches audit (CLI agent dispatcher, server combined dispatcher) so the platform / invocation plumbing stays in one place.

type AuditAgentStatus

type AuditAgentStatus = agenttypes.AuditAgentStatus

Audit types

type AuditAgenticScanner

type AuditAgenticScanner struct {
	// contains filtered or unexported fields
}

AuditAgenticScanner manages an vigolium-audit running as a background agent process. It launches the agent (Claude or Codex), periodically syncs audit-state.json and findings to the vigolium session dir, and imports findings into the database when complete.

func NewAuditAgenticScanner

func NewAuditAgenticScanner(cfg AuditAgentConfig, repo *database.Repository) *AuditAgenticScanner

NewAuditAgenticScanner creates a new runner for the background vigolium-audit.

The AgenticScan DB row's UUID is derived as follows:

  • Standalone audit (ParentAgenticScanUUID empty, SessionDir set): UUID is filepath.Base(cfg.SessionDir). This gives the invariant that `vigolium log <uuid>` and `vigolium log ls` resolve the session's runtime.log via the conventional `{sessions_dir}/{uuid}/` path.
  • Nested audit (ParentAgenticScanUUID set, e.g. spawned by autopilot/swarm): a fresh UUID is generated. The parent already owns a row at filepath.Base(SessionDir), so the child must differ to avoid a primary-key collision on create. Resolution back to runtime.log relies on the child row's persisted SessionDir column instead.
  • No SessionDir: a fresh UUID is generated.

func StartAuditAgent

func StartAuditAgent(ctx context.Context, agentCfg config.AuditAgentConfig, harness HarnessSpec, sourcePath, sessionDir, projectUUID, scanUUID, parentAgenticScanUUID string, repo *database.Repository, streamWriter io.Writer) (*AuditAgenticScanner, error)

StartAuditAgent creates and starts a background audit run for the given harness (audit or piolium). Returns nil runner when the cfg is disabled or sourcePath is empty. When streamWriter is non-nil, audit output is streamed in real-time. Harness-specific bits (Platform=pi + StreamDecoder for piolium) are auto-installed when harness.Name == "piolium".

func (*AuditAgenticScanner) AgenticScanUUID

func (r *AuditAgenticScanner) AgenticScanUUID() string

AgenticScanUUID returns the UUID of the AgenticScan row this runner owns. Useful for tests and callers that need to look up the row after Wait().

func (*AuditAgenticScanner) Cancel

func (r *AuditAgenticScanner) Cancel()

Cancel stops the audit process. Sends SIGTERM first, then SIGKILL after a grace period.

func (*AuditAgenticScanner) CostSummary

func (r *AuditAgenticScanner) CostSummary() ScanCost

CostSummary returns the priced token summary for this audit run. The zero value is returned when the run is still active, used an unsupported backend, or the backend transcript could not be parsed.

func (*AuditAgenticScanner) Done

func (r *AuditAgenticScanner) Done() <-chan struct{}

Done returns a channel that closes when the audit finishes.

func (*AuditAgenticScanner) FindingStats

func (r *AuditAgenticScanner) FindingStats() FindingStats

FindingStats returns the summary of findings parsed and imported by this audit run. Only populated after monitor() has completed.

func (*AuditAgenticScanner) Harness

func (r *AuditAgenticScanner) Harness() HarnessSpec

Harness returns the harness spec the runner was configured with. Lets callers label output and tag findings without re-reading config or hard-coding harness names like "piolium" / "audit".

func (*AuditAgenticScanner) ProcessStartedAt

func (r *AuditAgenticScanner) ProcessStartedAt() time.Time

ProcessStartedAt returns the wall time the audit subprocess was launched. Used to disambiguate codex rollouts (when multiple share a cwd) and to classify early-runtime failures for the audit fallback path. Returns the zero time if Start has not been called.

func (*AuditAgenticScanner) Start

func (r *AuditAgenticScanner) Start(ctx context.Context) error

Start launches the audit harness (vigolium-audit binary or piolium via `pi`) as a background process. The harness selection drives binary resolution, argv construction, and stream decoding.

On any failure path AFTER BYOK staging has run (codex auth.json copy) but BEFORE cmd.Start() succeeds, the staged file must be cleaned up here — monitor() never runs in that case. Past that point, monitor's deferred cleanup owns the restore.

func (*AuditAgenticScanner) Status

Status returns a summary of the current audit state.

func (*AuditAgenticScanner) Wait

func (r *AuditAgenticScanner) Wait() error

Wait blocks until the audit finishes.

type AuditDriverAgent

type AuditDriverAgent = agenttypes.AuditDriverAgent

Audit invocation

type AuditDriverAuthFlags

type AuditDriverAuthFlags = agenttypes.AuditDriverAuthFlags

Audit invocation

type AuditDriverCfgInput

type AuditDriverCfgInput struct {
	Mode                  string
	Modes                 []string
	SourcePath            string
	SessionDir            string
	ProjectUUID           string
	ScanUUID              string
	ParentAgenticScanUUID string
	Invocation            AuditDriverInvocation
	Stream                bool
	StreamWriter          io.Writer

	// ShowThinking opts into rendering agent thinking blocks (audit NDJSON
	// `thinking` events) in the live stream. Off by default; controlled by
	// `vigolium agent audit --show-thinking`.
	ShowThinking bool

	// KeepRaw maps to vigolium-audit's `--keep-raw`: opt out of the
	// deep/confirm auto-prune so raw scanner output, draft findings, and
	// intermediate workspaces stay on disk for manual review. Audit-only;
	// ignored for the piolium harness.
	KeepRaw bool

	// KeepSourceOutputDir suppresses the post-run cleanup of
	// <source>/vigolium-results/ from the source tree (a session copy is
	// always synced regardless). The CLI sets it from --keep-raw/--clean-raw
	// so the on-disk results can be reviewed or re-imported. Audit-only.
	KeepSourceOutputDir bool

	// AuthOverride carries the resolved BYOK bundle for this run. It is
	// already folded into Invocation.Auth by the caller (via
	// ResolveAuditDriverInvocation's variadic override or
	// ApplyAuthOverrideToAudit), so audit's argv reflects it. The
	// field is also stored on AuditAgentConfig so the launcher can match
	// audit's auth to whatever staging/env injection the piolium driver
	// would do (currently only piolium consumes it; audit stays argv-only).
	AuthOverride AuthOverride
}

AuditDriverCfgInput collects everything BuildAuditDriverCfg needs to produce a runnable AuditAgentConfig. The embedded vigolium-audit binary self-contains its content bundle, so there is no plugin-dir extraction step anymore. Invocation carries the resolved agent + auth (resolved from olium config / CLI override by the caller via ResolveAuditDriverInvocation). Stream toggles audit's `--json` mode so the streaming goroutine can capture the result event for cost reporting.

type AuditDriverIntensityPreset

type AuditDriverIntensityPreset = agenttypes.AuditDriverIntensityPreset

Intensity types

type AuditDriverInvocation

type AuditDriverInvocation = agenttypes.AuditDriverInvocation

Audit invocation

func ResolveAuditDriverInvocation

func ResolveAuditDriverInvocation(olium config.OliumConfig, providerOverride string, authOverride ...AuthOverride) AuditDriverInvocation

ResolveAuditDriverInvocation derives the vigolium-audit agent + auth tuple from the configured olium provider and an optional override.

Precedence:

  1. providerOverride (CLI flag like --provider) — wins outright.
  2. olium.Provider — anthropic-* → claude, openai-* → codex.
  3. Default — claude (matches vigolium-audit's own default).

Auth selection follows the resolved provider:

  • anthropic-api-key → APIKey from olium.LLMAPIKey
  • anthropic-oauth → OAuthToken from olium.OAuthToken
  • anthropic-cli → no override (subscription auth)
  • openai-api-key → APIKey from olium.LLMAPIKey
  • openai-codex-oauth → OAuthCredFile from olium.OAuthCredPath
  • vertex providers → no override (audit doesn't authenticate against Vertex itself; the user routes through Anthropic/OpenAI via audit's own provider-detection path)

authOverride (variadic for backwards compatibility) supplies a per-run BYOK bundle from the audit CLI/REST surface. When non-empty, it REPLACES the olium-derived auth wholesale (see ApplyAuthOverrideToAudit) — the resolved agent (claude/codex) still comes from providerOverride/olium. Only the first element is consulted; extras are ignored.

type AuditRunner

type AuditRunner interface {
	Start(ctx context.Context) error
	Wait() error
	Done() <-chan struct{}
	Cancel()
	Status() *AuditAgentStatus
	FindingStats() FindingStats
	CostSummary() ScanCost
	AgenticScanUUID() string
}

AuditRunner is the common surface the audit dispatchers (CLI driverPlan, REST driverResult, single-driver runner) consume. Both the single-subprocess *AuditAgenticScanner and the multi-mode *PioliumChainScanner satisfy it, so a piolium mode chain is a drop-in for a single piolium run.

func NewAuditRunner

func NewAuditRunner(cfg AuditAgentConfig, repo *database.Repository) AuditRunner

NewAuditRunner returns the right runner for cfg. audit owns its own chaining natively (`--modes` is rendered in buildAuditAgentCommand, one subprocess, one row), so only a multi-mode piolium run needs the Go loop. Everything else stays a plain single-subprocess scanner.

type AuthOverride

type AuthOverride = agenttypes.AuthOverride

Audit BYOK auth override (CLI/REST → audit flags + piolium env)

type AutopilotArtifactSpec

type AutopilotArtifactSpec struct {
	BriefPath            string `json:"brief_path"`
	ContextPath          string `json:"context_path"`
	PlanPath             string `json:"plan_path"`
	FindingsPath         string `json:"findings_path"`
	DismissedPath        string `json:"dismissed_path"`
	VisitedEndpointsPath string `json:"visited_endpoints_path"`
	ArtifactsPath        string `json:"artifacts_path"`
	SessionConfigPath    string `json:"session_config_path"`
	AuthStatePath        string `json:"auth_state_path"`
	AuthHeadersPath      string `json:"auth_headers_path"`
	BrowserSessionPath   string `json:"browser_session_path"`
	EvidenceDir          string `json:"evidence_dir"`
	VerificationPath     string `json:"verification_path"`
}

type AutopilotAuthFlow

type AutopilotAuthFlow struct {
	Name      string   `json:"name"`
	LoginPath string   `json:"login_path,omitempty"`
	Tokens    []string `json:"tokens,omitempty"`
}

type AutopilotContextBundle

type AutopilotContextBundle struct {
	Version              string                    `json:"version"`
	Mode                 string                    `json:"mode"`
	TargetURL            string                    `json:"target,omitempty"`
	SourcePath           string                    `json:"source_path,omitempty"`
	DiffRef              string                    `json:"diff_ref,omitempty"`
	ChangedFiles         []string                  `json:"changed_files,omitempty"`
	Routes               []AutopilotRouteSummary   `json:"routes,omitempty"`
	AuthFlows            []AutopilotAuthFlow       `json:"auth_flows,omitempty"`
	Findings             []AutopilotFindingSummary `json:"findings,omitempty"`
	Priorities           []string                  `json:"priorities,omitempty"`
	AuditDriverAvailable bool                      `json:"audit_available"`
	AuditDriverStatus    string                    `json:"audit_status,omitempty"`
	PreparedAuth         *AutopilotPreparedAuth    `json:"prepared_auth,omitempty"`
	BrowserDecision      string                    `json:"browser_decision,omitempty"`
	BrowserReason        string                    `json:"browser_reason,omitempty"`
	Warnings             []string                  `json:"warnings,omitempty"`
}

type AutopilotExecutionPlan

type AutopilotExecutionPlan struct {
	AuthRequired   bool                  `json:"auth_required"`
	AuthPrepared   bool                  `json:"auth_prepared,omitempty"`
	BrowserMode    string                `json:"browser_mode,omitempty"`
	BrowserReason  string                `json:"browser_reason,omitempty"`
	Budgets        map[string]int        `json:"budgets,omitempty"`
	Tasks          []AutopilotPlanTask   `json:"tasks,omitempty"`
	StopCriteria   []string              `json:"stop_criteria,omitempty"`
	Warnings       []string              `json:"warnings,omitempty"`
	ArtifactPolicy AutopilotArtifactSpec `json:"artifact_policy"`
}

type AutopilotFindingSummary

type AutopilotFindingSummary struct {
	ID         string   `json:"id,omitempty"`
	Title      string   `json:"title"`
	Severity   string   `json:"severity,omitempty"`
	Confidence string   `json:"confidence,omitempty"`
	Action     string   `json:"action,omitempty"`
	Kind       string   `json:"kind,omitempty"`
	Route      string   `json:"route,omitempty"`
	Locations  []string `json:"locations,omitempty"`
}

type AutopilotIntensityPreset

type AutopilotIntensityPreset = agenttypes.AutopilotIntensityPreset

Intensity types

type AutopilotPipelineConfig

type AutopilotPipelineConfig struct {
	TargetURL   string
	SourcePath  string
	Files       []string
	Instruction string
	Focus       string

	// Skill selection forwarded to the operator agent's planner-driven
	// loading. SkillNames/SkillTags force-include; NoSkillFilter loads the
	// full set; AlwaysOnSkills are kept regardless of selection.
	SkillNames     []string
	SkillTags      []string
	NoSkillFilter  bool
	AlwaysOnSkills []string

	// SystemPrompt, when non-empty, fully replaces the built-in autopilot
	// system prompt at the olium runtime layer. Empty falls back to
	// agent.olium.system_prompt in settings, then to the embedded persona.
	SystemPrompt string

	AgentName   string
	MaxCommands int

	DryRun     bool
	ShowPrompt bool

	// Triage, when true, runs an AI triage pass over the findings after the
	// operator loop completes — classifying each as confirmed (→ "triaged")
	// or "false_positive" and writing the verdict back, scoped to this run.
	// Pure classification: no native rescan.
	Triage bool

	SessionsDir string
	SessionDir  string

	ProjectUUID           string
	ScanUUID              string
	ParentAgenticScanUUID string

	StreamWriter     io.Writer
	ProgressCallback func(phase string, message string)

	// Audit is the audit-cfg slot — backed by either audit or piolium per
	// AuditHarness. Field name is legacy; the runtime is harness-agnostic.
	Audit *config.AuditAgentConfig

	// AuditHarness selects which harness backs the Audit cfg. Zero-valued
	// defaults to audit for backward compat.
	AuditHarness HarnessSpec

	// BrowserEnabled indicates whether agent-browser is available for the agent.
	BrowserEnabled bool
	// BrowserBinaryPath is agent.browser.binary_path for the typed browser_auth
	// adapter; empty resolves agent-browser on PATH.
	BrowserBinaryPath string
	// BrowserRequested preserves explicit user intent even when heuristics are weak.
	BrowserRequested bool
	// RequiresBrowser means auth/setup should prefer browser assistance over HTTP-only preparation.
	RequiresBrowser bool
	// KeepBrowserEnabled forces the browser tool to stay available even when the
	// browser-usage heuristic would deprioritize it (browser_unneeded). Unlike
	// BrowserRequested it does NOT signal explicit user intent, so it only guards
	// tool availability and never arms the browser-auth preflight or changes the
	// planning hint. Set by the CLI autopilot path (browser is always-on for
	// autopilot); the server leaves it false to keep its opt-in behavior.
	KeepBrowserEnabled bool
	// Credentials carries compact credentials extracted from the prompt or flag input.
	Credentials string
	// CredentialSets carries structured role/account pairs extracted from prompt input.
	CredentialSets []agenttypes.IntentCredentialSet
	// AuthRequired means auth should be prepared before operator launch.
	AuthRequired bool
	// BrowserStartURL is an explicit login/start URL for browser-based flows.
	BrowserStartURL string
	// FocusRoutes are protected or browser-focused routes named by the user.
	FocusRoutes []string
	// SessionConfig is the prepared session config for authenticated scanning.
	SessionConfig *AgentSessionConfig
	// AuthHeaders are hydrated headers ready for immediate use.
	AuthHeaders map[string]string
	// PreparedAuth summarizes the auth preparation outcome.
	PreparedAuth *AutopilotPreparedAuth

	// DiffContext holds parsed diff information for focused scanning.
	// When set, the agent prompt includes changed file list and patch content.
	DiffContext *agenttypes.DiffContext

	ContextBundle *AutopilotContextBundle
	Plan          *AutopilotExecutionPlan
	Artifacts     AutopilotArtifactSpec

	// PreflightDiscovery enables a discovery + Swagger/OpenAPI ingestion
	// pass before the operator agent starts. The records land in the
	// project DB so the agent's first turn can `list_findings` and
	// `query_records` against real attack surface instead of starting
	// blank. Skipped silently when TargetURL is empty. Default true via
	// the CLI/API wirers; explicitly settable to false to disable.
	PreflightDiscovery bool

	// PostHaltVerify enables the autopilot's post-halt coverage
	// verification loop. After the model calls halt_scan, the runner
	// runs another discovery + spec ingest pass, diffs new routes
	// against the pre-halt snapshot, and re-enters the agent once if
	// the gap meets PostHaltGapThreshold. Default true via the wirers.
	PostHaltVerify bool

	// PostHaltGapThreshold is the minimum number of new (method, URL)
	// signatures the post-halt probe must turn up before the agent is
	// re-entered. 0 = autopilot default (5).
	PostHaltGapThreshold int
}

AutopilotPipelineConfig configures the autopilot pipeline.

type AutopilotPipelineResult

type AutopilotPipelineResult = agenttypes.AutopilotPipelineResult

Autopilot types

type AutopilotPipelineRunner

type AutopilotPipelineRunner struct {
	// contains filtered or unexported fields
}

AutopilotPipelineRunner orchestrates the autopilot pipeline.

func NewAutopilotPipelineRunner

func NewAutopilotPipelineRunner(engine *Engine, repo *database.Repository) *AutopilotPipelineRunner

NewAutopilotPipelineRunner creates a new autopilot pipeline runner.

func (*AutopilotPipelineRunner) RunAutonomous

RunAutonomous executes the autopilot pipeline: 1. Run vigolium-audit first when source context is available 2. Freeze context into native plan + artifacts 3. Launch the autonomous operator agent with full tool access

type AutopilotPlanTask

type AutopilotPlanTask struct {
	ID       string `json:"id"`
	Type     string `json:"type"`
	Priority int    `json:"priority"`
	Reason   string `json:"reason"`
}

type AutopilotPreparedAuth

type AutopilotPreparedAuth struct {
	Requested       bool     `json:"requested"`
	Source          string   `json:"source,omitempty"`
	SessionConfig   string   `json:"session_config_path,omitempty"`
	SessionCount    int      `json:"session_count,omitempty"`
	Hydrated        bool     `json:"hydrated"`
	HeaderCount     int      `json:"header_count,omitempty"`
	AuthRequired    bool     `json:"auth_required"`
	RequiresBrowser bool     `json:"requires_browser,omitempty"`
	BrowserStartURL string   `json:"browser_start_url,omitempty"`
	FocusRoutes     []string `json:"focus_routes,omitempty"`
	ProtectedRoutes []string `json:"protected_routes,omitempty"`
	Notes           []string `json:"notes,omitempty"`
}

type AutopilotRouteSummary

type AutopilotRouteSummary struct {
	Path   string `json:"path"`
	Method string `json:"method,omitempty"`
	Source string `json:"source,omitempty"`
}

type AutopilotTriageParams

type AutopilotTriageParams struct {
	TargetURL       string
	SourcePath      string
	ScanUUID        string
	ProjectUUID     string
	AgenticScanUUID string // verdicts are written back scoped to this run
	SessionDir      string
	StreamWriter    io.Writer
	Verbose         bool
}

AutopilotTriageParams configures the post-scan triage pass.

type AutopilotVerificationReport

type AutopilotVerificationReport struct {
	ConfirmedCount int      `json:"confirmed_count"`
	DismissedCount int      `json:"dismissed_count"`
	Warnings       []string `json:"warnings,omitempty"`
}

type BatchProvenance

type BatchProvenance = agenttypes.BatchProvenance

Pipeline types

type BurpBridgeToolSpec

type BurpBridgeToolSpec struct {
	ProjectUUID string
}

BurpBridgeToolSpec registers only the live, read-only Burp bridge tools. It is separate from VigToolSpec so ordinary query agents do not receive replay_request or attack_kit merely because the bridge is available.

type CoverageProbe

type CoverageProbe struct {
	// Target is the URL/hostname to probe. Required.
	Target string

	// ProjectUUID scopes the resulting http_records to the same project as
	// the autopilot run. Required.
	ProjectUUID string

	// AgenticScanUUID, when set, is recorded on the underlying Scan rows so
	// coverage-pass artifacts can be traced back to the parent autopilot
	// run.
	AgenticScanUUID string

	// ConfigPath optionally overrides the path to vigolium-configs.yaml so
	// the pass uses the same settings as the surrounding scan.
	ConfigPath string

	// Repo is the DB handle used for the snapshot diff. Required.
	Repo *database.Repository

	// Concurrency overrides the worker count. 0 = settings default.
	Concurrency int
}

CoverageProbe runs a single deterministic discovery + OpenAPI/Swagger ingestion pass against a target, then snapshots the resulting http_record signatures. Used in two places:

  1. Pre-flight (pipeline runner, before the agent starts) — populates the project DB so the agent inherits known surface instead of starting blank.
  2. Post-halt verification (autopilot.Run, after the model calls halt_scan) — re-runs the probe to surface any routes/specs the agent missed, then diffs against the pre-halt snapshot to decide whether a re-entry is warranted.

All probe activity goes through runner.LaunchScan, which writes records to the project DB using the same model the agent's own tools use. The agent's query_records / inspect_record tools see them transparently on the next turn.

func (*CoverageProbe) Run

func (*CoverageProbe) SnapshotSignatures

func (p *CoverageProbe) SnapshotSignatures(ctx context.Context) ([]string, error)

SnapshotSignatures captures the current set of (method, URL) signatures for the probe's target host without running any scans. Used by callers that need a pre-run baseline independent of Run() — e.g. the autopilot post-halt loop snapshots when the agent starts so it can compare against what the model + the post-halt probe produced.

func (*CoverageProbe) Validate

func (p *CoverageProbe) Validate() error

Validate returns nil iff the probe has the minimum information needed to run. Caller-side check so the higher-level pipeline can short-circuit rather than enter LaunchScan and fail mid-stream.

type CoverageProbeResult

type CoverageProbeResult struct {
	// DiscoveryScanUUID is the Scan row created by the discovery pass. Empty
	// on a probe that skipped discovery (e.g. snapshot-only call).
	DiscoveryScanUUID string

	// SpecIngestScanUUID is the Scan row created by the OpenAPI/Swagger
	// ingestion pass. Empty when ingestion was skipped or no spec was
	// found.
	SpecIngestScanUUID string

	// SignaturesBefore is the set of (method, URL) signatures present in
	// the project for Target's hostname when Run() started.
	SignaturesBefore []string

	// SignaturesAfter is the same set after both passes completed.
	SignaturesAfter []string

	// NewSignatures = SignaturesAfter - SignaturesBefore. Sorted for
	// stable output.
	NewSignatures []string
}

CoverageProbeResult summarizes a single coverage pass.

type CoverageReportInputs

type CoverageReportInputs struct {
	AgenticScanUUID    string
	TargetURL          string
	Intensity          string
	Plan               *SwarmPlan
	Records            []*httpmsg.HttpRequestResponse
	TotalFindings      int
	FindingsByModule   map[string]int
	FindingsByEndpoint map[string]int
	Warnings           []string
}

type Engine

type Engine struct {
	// contains filtered or unexported fields
}

Engine orchestrates AI agent runs: context gathering, prompt rendering, agent execution, output parsing, and result ingestion. Dispatch happens through the in-process olium engine; no subprocess pools are involved.

func NewEngine

func NewEngine(settings *config.Settings, repo *database.Repository) *Engine

NewEngine creates a new agent engine backed by the in-process olium runtime.

func (*Engine) InvalidateContextCache

func (e *Engine) InvalidateContextCache()

InvalidateContextCache clears the context cache. Call after phases that modify scan data (native scan, rescan).

func (*Engine) Preflight

func (e *Engine) Preflight(agentName string) error

Preflight verifies the olium provider is resolvable AND that credentials actually work by issuing a tiny ping prompt. Call this before starting a multi-phase pipeline so credential / network problems fail fast (within ~5 seconds) instead of after a minute of normalize + discovery work. agentName is retained for call-site compatibility; it no longer affects dispatch.

The ping is bounded by a hard 5s timeout; transient ping failures are returned as errors so the caller can decide whether to bail or continue (CLI usually bails, server endpoints typically continue and let the real first-call failure surface in the run record).

func (*Engine) ResetTokenUsage

func (e *Engine) ResetTokenUsage()

ResetTokenUsage zeroes the accumulator. Useful for tests; production callers get a fresh accumulator from NewEngine.

func (*Engine) Run

func (e *Engine) Run(ctx context.Context, opts Options) (*Result, error)

Run executes a full agent pipeline: resolve prompt → render → execute → parse → ingest. Each call constructs a fresh in-process olium engine.

func (*Engine) RunOnOliumEngine

func (e *Engine) RunOnOliumEngine(ctx context.Context, opts Options, sess AgentSession) (*Result, error)

RunOnOliumEngine is like Run but reuses an existing AgentSession so the caller's prior conversation history (system prompt, tool defs, earlier turns) remains in the provider request and can hit prompt caches. Use with AgentSession.Fork() for parallel sub-runs that share a prefix — e.g., the source-analysis explore phase forks to 3 format/extension goroutines that don't need to re-append the explore notes.

func (*Engine) RunSourceAnalysisParallel

func (e *Engine) RunSourceAnalysisParallel(ctx context.Context, cfg SourceAnalysisConfig) (saResult *SourceAnalysisResult, rawOutput string, renderedPrompt string, err error)

RunSourceAnalysisParallel executes consolidated source analysis in 4 LLM calls across 2 waves:

Wave 1 (single call):
  Call 1: swarm-source-explore   (reads source → notes on routes + auth + sinks)
Wave 2 (parallel, consumes Wave 1 output):
  Call 2a: swarm-source-format-routes     (route notes → JSONL http_records)
  Call 2b: swarm-source-format-session    (auth notes → session_config JSON)
  Call 3:  swarm-source-extensions         (combined notes → JS scanner extensions)

The single explore call reads the codebase once and produces two labeled sections (routes + auth/session) that are split for the format calls. When SDK pool is available, format-routes reuses the explore session (multi-turn) for full context.

func (*Engine) RunWithExtra

func (e *Engine) RunWithExtra(ctx context.Context, opts Options, extra map[string]string) (*Result, error)

RunWithExtra executes an agent run with additional extra template data injected. This is used by swarm mode to pass request context and vuln type to the template.

func (*Engine) RunWithExtraSkills

func (e *Engine) RunWithExtraSkills(ctx context.Context, opts Options, extra map[string]string, reg *skill.Registry) (*Result, error)

RunWithExtraSkills merges extra template data (like RunWithExtra) and also surfaces the given skill registry to the agent. Used by the swarm plan phase to give the planner the full skill menu.

func (*Engine) RunWithSkills

func (e *Engine) RunWithSkills(ctx context.Context, opts Options, reg *skill.Registry) (*Result, error)

RunWithSkills is Run with a skill registry surfaced to the agent: the fresh-per-call engine gets an <available_skills> block and the load_skill tool for exactly the skills in reg. A nil/empty reg behaves like Run.

func (*Engine) SetContextCache

func (e *Engine) SetContextCache(cache *agentprompt.ContextCache)

SetContextCache sets a context cache for DB enrichment results. Used by swarm runs to avoid redundant queries across phases.

func (*Engine) TokenUsage

func (e *Engine) TokenUsage() agenttypes.TokenUsage

TokenUsage returns the cumulative token usage of every Engine.Run call made on this Engine instance. SwarmRunner reads this at finalize time.

type ExploitationEvidence

type ExploitationEvidence = agenttypes.ExploitationEvidence

Exploitation evidence

type ExtensionMergeResult

type ExtensionMergeResult struct {
	Extensions []GeneratedExtension
	Renames    map[string]string // original filename -> renamed filename
}

ExtensionMergeResult holds the merged extensions plus any rename tracking info.

type FindingStats

type FindingStats struct {
	Parsed     int            // total findings parsed from the session dir
	Saved      int            // findings successfully persisted to the database
	BySeverity map[string]int // count by normalized severity (critical/high/medium/low/info)

	// Reported is the count reported by the audit binary's own NDJSON
	// `result` event. It is only consulted when the on-disk findings tree
	// could not be parsed (Parsed == 0) and serves as a display-only
	// fallback so the CLI summary mirrors the streamer's `[result]` line
	// even when persistence didn't run. Severity keys are normalized to
	// lowercase to match BySeverity.
	Reported           int
	ReportedBySeverity map[string]int
}

FindingStats summarises the audit findings imported by a single audit run.

func (FindingStats) SeverityBreakdownString

func (s FindingStats) SeverityBreakdownString() string

SeverityBreakdownString renders a colored "critical:N high:N ..." string in descending severity order. Buckets with zero count are skipped. Falls back to the audit-reported breakdown when the on-disk parse yielded nothing. Returns "" when no findings were counted at all.

type FollowUpScan

type FollowUpScan = agenttypes.FollowUpScan

Pipeline types

type GeneratedExtension

type GeneratedExtension = agenttypes.GeneratedExtension

Pipeline types

func RepairExtensionsWithLLM

func RepairExtensionsWithLLM(ctx context.Context, engine *Engine, invalids []InvalidExtension, cfg RepairConfig) []GeneratedExtension

RepairExtensionsWithLLM attempts to fix invalid extensions by sending each one to the configured LLM agent with the error context. Repairs run in parallel with bounded concurrency. Extensions that compile after repair are returned; those that still fail are dropped.

type GuardrailVerdict

type GuardrailVerdict struct {
	Allowed    bool     `json:"allowed"`
	Reason     string   `json:"reason"`
	Categories []string `json:"categories,omitempty"`
}

GuardrailVerdict is the structured response from the prompt-safety classifier.

func ClassifyPromptSafety

func ClassifyPromptSafety(ctx context.Context, settings *config.Settings, userPrompt string) GuardrailVerdict

ClassifyPromptSafety runs a single olium-backed classification call against the user prompt. Reuses settings.Agent.Olium for provider/model.

Fails open: provider, network, or parse errors return Allowed=true with a Reason describing the degradation. A transient LLM outage shouldn't brick legitimate scans; the warning is logged so operators can notice.

type HarnessSpec

type HarnessSpec = agenttypes.HarnessSpec

Audit types

func DefaultAuditHarness

func DefaultAuditHarness() HarnessSpec

DefaultAuditHarness returns the canonical audit harness spec used by `vigolium agent audit` and the autopilot/swarm background audit. The zero value of AuditAgentConfig.Harness is treated as this for backward compat.

func PickAuditHarness

func PickAuditHarness(pioliumMode, auditModeLocal string, auditNoAudit bool, sourcePath string, settingsAudit config.AuditAgentConfig) (*config.AuditAgentConfig, HarnessSpec)

PickAuditHarness picks the audit cfg + harness pair to run from already- resolved mode strings. Piolium wins when its mode is non-empty/"off" (callers do their own auto-pick before invoking this — see the CLI's post-intensity switch and the server's resolveAutopilotAuditCfgServer). Returns (nil, zero-spec) when no audit should run.

type InputType

type InputType = agenttypes.InputType

Input types

type Intensity

type Intensity = agenttypes.Intensity

Intensity types

type IntentCredentialSet

type IntentCredentialSet = agenttypes.IntentCredentialSet

Intent types

type IntentParseConfig

type IntentParseConfig = agenttypes.IntentParseConfig

Intent types

type IntentParseOption

type IntentParseOption = agenttypes.IntentParseOption

Intent types

type InvalidExtension

type InvalidExtension = agenttypes.InvalidExtension

Extension validation types

type Options

type Options = agenttypes.Options

Core types

type PioliumChainScanner

type PioliumChainScanner struct {
	// contains filtered or unexported fields
}

PioliumChainScanner runs a piolium mode chain (e.g. deep,confirm) as a sequence of `pi` subprocesses against the same source dir, collapsing them into a single aggregated AgenticScan row. The chain stops at the first mode that does not complete cleanly — matching audit's native `--modes` semantics.

Why the per-mode aggregation rules differ: piolium's picost windows each cost summary to that subprocess's own run, so per-mode costs are disjoint and summed. Findings, by contrast, are NOT summed — piolium's findings/ dir is cumulative across chained modes in the same source tree, so the last completed mode's snapshot already reflects (and may have pruned) the whole chain; summing would double-count.

func NewPioliumChainScanner

func NewPioliumChainScanner(cfg AuditAgentConfig, repo *database.Repository) *PioliumChainScanner

NewPioliumChainScanner builds a chain runner. The mode chain is read from cfg.EffectiveModes() and filtered to the modes piolium supports (callers normally pre-filter via ValidateAuditDriverModes; this is a defensive second pass so an unsupported mode in the chain is skipped rather than failing the whole driver).

func (*PioliumChainScanner) AgenticScanUUID

func (p *PioliumChainScanner) AgenticScanUUID() string

func (*PioliumChainScanner) Cancel

func (p *PioliumChainScanner) Cancel()

func (*PioliumChainScanner) CostSummary

func (p *PioliumChainScanner) CostSummary() ScanCost

func (*PioliumChainScanner) Done

func (p *PioliumChainScanner) Done() <-chan struct{}

func (*PioliumChainScanner) FindingStats

func (p *PioliumChainScanner) FindingStats() FindingStats

func (*PioliumChainScanner) Start

func (p *PioliumChainScanner) Start(ctx context.Context) error

Start creates the single aggregated child row and launches the chain loop in the background. It returns once the first mode's subprocess has started (or immediately with the error if it could not).

func (*PioliumChainScanner) Status

Status reports the live phase progress of the mode currently running; once the chain is done it returns the last mode's snapshot with the full chain string as the mode label.

func (*PioliumChainScanner) Wait

func (p *PioliumChainScanner) Wait() error

type PioliumSweepEntry

type PioliumSweepEntry struct {
	Dir        string
	LockPath   string
	BackupPath string
	Holder     pioliumLockBreadcrumb
}

PioliumSweepEntry captures one swept or held lock + backup pair.

type PioliumSweepResult

type PioliumSweepResult struct {
	Swept    []PioliumSweepEntry // backup → target restored, lock removed
	Held     []PioliumSweepEntry // active run holds the lock; left alone
	Orphaned []string            // backup files without a matching restore target
}

PioliumSweepResult summarizes what SweepStalePioliumAuth did per agent directory. Returned so the caller can log a single structured line.

func SweepStalePioliumAuth

func SweepStalePioliumAuth(piAgentDirs []string) PioliumSweepResult

SweepStalePioliumAuth restores credentials left orphaned by a crashed BYOK run. For each candidate piAgentDir:

  • If `.vigolium-auth.lock` is missing → look for stray `auth.json.vigolium-bak-*` files and report them as orphaned (the operator must resolve, since we can't tell which one was active).
  • If the lock is present but its PID is alive → record as held and leave everything intact.
  • If the lock is present but its PID is dead → restore the matching `auth.json.vigolium-bak-<runUUID>` over `auth.json` and remove the lock. Non-matching backups are reported as orphaned for manual resolution.

Returns a structured summary so the caller can log a single line. Never errors — sweep is best-effort by design (a stuck cred file is an operator problem, not a vigolium-must-fail-boot problem).

type PlanCoverage

type PlanCoverage struct {
	MissingPrefixes []string
	TotalPrefixes   int
	CoveredPrefixes int
}

PlanCoverage describes how well a SwarmPlan's focus areas + notes blanket the record set. MissingPrefixes is ordered by first appearance in records.

func AnalyzePlanCoverage

func AnalyzePlanCoverage(plan *SwarmPlan, records []*httpmsg.HttpRequestResponse) PlanCoverage

AnalyzePlanCoverage returns the URL-prefix clusters in records that no FocusArea or Notes substring references (directly or via a parent/child path match).

type PlannedEndpoint

type PlannedEndpoint = agenttypes.PlannedEndpoint

Pipeline types

type PrefixCoverage

type PrefixCoverage struct {
	Prefix      string `json:"prefix"`
	RecordCount int    `json:"record_count"`
	InFocus     bool   `json:"in_focus"`
}

type ProbeConfig

type ProbeConfig struct {
	Concurrency int                        // max parallel probe requests; 0 = default 10
	Timeout     time.Duration              // per-request probe timeout; 0 = default 10s
	MaxBodySize int                        // max response body bytes; 0 = default 2MB
	OnProgress  func(completed, total int) // optional progress callback
}

ProbeConfig holds tuning parameters for HTTP record probing.

type ProgressEvent

type ProgressEvent = agenttypes.ProgressEvent

Pipeline types

type PromptTemplate

type PromptTemplate = agenttypes.PromptTemplate

Core types

type QuickCheck

type QuickCheck = agenttypes.QuickCheck

Pipeline types

type QuickCheckLintIssue

type QuickCheckLintIssue = agenttypes.QuickCheckLintIssue

Extension validation types

type QuickCheckMatch

type QuickCheckMatch = agenttypes.QuickCheckMatch

Pipeline types

type QuickCheckRequest

type QuickCheckRequest = agenttypes.QuickCheckRequest

Pipeline types

type RecordSpec

type RecordSpec struct {
	// SessionDir is the directory the transcript-*.jsonl file is written to.
	// Empty disables recording (the common one-off CLI case).
	SessionDir string
	// Template is the phase/template name; it seeds the per-phase filename
	// (transcript-<template>.jsonl) and the concurrency-dedup key so parallel
	// same-template calls (swarm plan batches) never share a file.
	Template string
	// SessionID is the transcript header's session id; empty falls back to the
	// SessionDir base name.
	SessionID string
}

RecordSpec configures a per-run Pi-style JSONL transcript written under SessionDir. The zero value (empty SessionDir) disables recording. It is plain data on purpose so the AgentRuntime seam never leaks olium's EventRecorder type — the adapter builds the concrete sessionlog.Recorder from these fields inside buildOliumEngineWithSpec.

type RepairConfig

type RepairConfig = agenttypes.RepairConfig

Pipeline types

type Result

type Result = agenttypes.Result

Core types

type RetryConfig

type RetryConfig = agenttypes.RetryConfig

Core types

type RunPID

type RunPID struct {
	PID       int       `json:"pid"`
	PGID      int       `json:"pgid"`
	StartTime time.Time `json:"start_time"`
}

RunPID holds process lifecycle metadata written to session directories. Used for orphan detection: if vigolium crashes, the next startup can find and kill orphaned agent subprocesses by scanning for stale PID files.

func ReadRunPID

func ReadRunPID(pidPath string) *RunPID

ReadRunPID reads and parses a run.pid file. Returns nil if not found or invalid.

type ScanCost

type ScanCost struct {
	Backend      string                 // "audit" | "pi"
	Model        string                 // model id reported by the harness
	InputTokens  int64                  // total input tokens across the run
	OutputTokens int64                  // total output tokens across the run
	CostUSD      float64                // priced total in USD
	Note         string                 // CLI-facing one-line annotation
	Blob         map[string]interface{} // payload for the TokenUsage JSONB column
}

ScanCost is vigolium's normalized view of an audit harness's token usage and USD cost, produced by the per-harness cost adapter and consumed by the CLI summary and the DB writer.

Note is a short human-readable annotation the CLI renders after the dollar figure (e.g. "(model gpt-5.5, 3 sessions)" for piolium, "(agent codex, status complete)" for audit). It is populated by the adapter that converts from the harness-specific summary, not by the CLI, so each harness can render its own details without the CLI having to branch on harness type.

func (ScanCost) IsZero

func (c ScanCost) IsZero() bool

IsZero reports whether no usage was recorded. Applied by the CLI and the DB writer to skip rendering/persisting empty summaries.

type ScanFunc

type ScanFunc = agenttypes.ScanFunc

Pipeline types

type ScanIntent

type ScanIntent = agenttypes.ScanIntent

Intent types

func ParseAndResolveIntent

func ParseAndResolveIntent(ctx context.Context, engine *Engine, prompt string, opts ...IntentParseOption) (*ScanIntent, error)

ParseAndResolveIntent is a convenience that calls ParseScanIntent followed by ResolveIntentApps. It returns an error if no apps could be extracted.

func ParseScanIntent

func ParseScanIntent(ctx context.Context, engine *Engine, prompt string, opts ...IntentParseOption) (*ScanIntent, error)

ParseScanIntent uses a quick LLM call to extract structured scan parameters from a natural language prompt. Falls back to structured input detection if the prompt looks like a URL, curl command, etc. When the prompt requires environment setup (git clone, docker), it delegates to ParseScanIntentWithSetup for full Bash-powered olium agent setup.

func ParseScanIntentWithSetup

func ParseScanIntentWithSetup(ctx context.Context, engine *Engine, prompt string, sessionsDir string) (*ScanIntent, error)

ParseScanIntentWithSetup runs the olium agent with full tool access to clone repos, start containers, and detect running targets before returning a structured scan intent.

func ResolveIntentApps

func ResolveIntentApps(intent *ScanIntent) *ScanIntent

ResolveIntentApps processes a ScanIntent by auto-detecting targets for apps that have source paths but no target. Returns the modified intent.

type ScanRequest

type ScanRequest = agenttypes.ScanRequest

Pipeline types

type SessionSpec

type SessionSpec struct {
	System            string // explicit system prompt; empty falls back to cfg/default
	SourcePath        string // appended to the system prompt when set
	MaxTurns          int    // 0 = engine default
	IncludeTools      bool   // register the builtin tool set
	EnablePromptCache bool
	// Skills, when non-nil and non-empty, injects an <available_skills> block
	// into the system prompt and registers the load_skill tool (requires
	// IncludeTools). Used by swarm plan/triage phases for planner-driven skill
	// loading; nil for phases that don't surface skills.
	Skills *skill.Registry
	// VigTools, when non-nil with a Repo (and IncludeTools), registers the
	// vigolium read+replay tool subset so a skill can actually confirm/escalate
	// against scan records. nil for phases that only reason over prompt context.
	VigTools *VigToolSpec
	// BurpBridgeTools, when non-nil (and IncludeTools), registers only
	// search_burp_items and inspect_burp_item. Both tools are read-only.
	BurpBridgeTools *BurpBridgeToolSpec
	// Record, when its SessionDir is set, attaches a Pi-style JSONL transcript
	// recorder to the built engine so the session's turns (including model
	// reasoning) persist for debugging. Zero value = no transcript.
	Record RecordSpec
}

SessionSpec configures a session built via AgentRuntime.NewSessionWithSpec for specialized one-off flows (the guardrail classifier, intent setup) that need a custom system prompt, turn cap, or tool set. The combination used by the default NewSession — {SourcePath: ..., IncludeTools: true} — reproduces the standard engine: builtin tools, the config's system prompt (or the package default), and the engine's default turn cap.

type SetupCleanup

type SetupCleanup = agenttypes.SetupCleanup

Intent types

type Snippet

type Snippet = agenttypes.Snippet

Pipeline types

type SourceAnalysisConfig

type SourceAnalysisConfig = agenttypes.SourceAnalysisConfig

Pipeline types

type SourceAnalysisResult

type SourceAnalysisResult = agenttypes.SourceAnalysisResult

Pipeline types

type SwarmCheckpoint

type SwarmCheckpoint = agenttypes.SwarmCheckpoint

Pipeline types

type SwarmConfig

type SwarmConfig struct {
	// Inputs: raw input strings (URL, curl, raw HTTP, Burp XML, or record UUID)
	Inputs    []string  // raw input strings
	InputType InputType // explicit type (auto-detected if empty)

	// Source analysis
	SourcePath  string                  // path to application source code (triggers source analysis phase)
	Files       []string                // specific files to include (relative to SourcePath)
	DiffContext *agenttypes.DiffContext // non-nil when --diff or --last-commits was provided

	// Custom instruction
	Instruction string // user-provided custom instruction appended to agent prompts

	// ForceExtensions forces the Phase-2 extension agent to run even when the
	// plan agent decides built-in modules are sufficient. Bound to --with-extensions
	// on the CLI. Has no effect when DryRun is true (DryRun still skips Phase 2).
	ForceExtensions bool

	// Skill selection (planner-driven loading overrides)
	SkillNames    []string // --skill: force-include these skills, bypassing planner judgement
	SkillTags     []string // --skill-tag: force-include every skill carrying one of these tags
	NoSkillFilter bool     // --no-skill-filter: load the full skill set, ignore planner selection

	// Scanning parameters
	VulnType         string   // optional: focus on specific vulnerability type
	Focus            string   // optional: broad strategic hint (e.g. "API injection", "auth bypass")
	ModuleNames      []string // optional: explicit module IDs to use
	OnlyPhase        string   // isolate a single phase (empty = all phases)
	SkipPhases       []string // skip specific phases (empty = skip none)
	MaxIterations    int      // max triage-rescan loops (default 3)
	BatchConcurrency int      // max parallel master agent batches (0 = default 3)
	MaxMasterRetries int      // max master agent retries on parse failure (0 = default 3)
	SAMaxConcurrency int      // max parallel source analysis sub-agents (0 = default 3)

	// Agent
	AgentName          string
	DryRun             bool
	ShowPrompt         bool   // print rendered prompts to stderr before executing
	SourceAnalysisOnly bool   // run only source analysis phase and exit
	CodeAudit          bool   // enable AI security code audit phase (--code-audit)
	Browser            bool   // enable agent-browser integration (always on for swarm; no --browser flag)
	Auth               bool   // run browser-based auth phase before discovery (--browser-auth)
	Credentials        string // optional credentials for the browser auth phase (extracted from the prompt)
	CredentialSets     []agenttypes.IntentCredentialSet
	AuthRequired       bool
	RequiresBrowser    bool
	BrowserStartURL    string
	FocusRoutes        []string

	// Context truncation
	MaxResponseBodyBytes int // max response body size in context; 0 = default 4096
	MaxPlanRecords       int // max records sent to plan agent; 0 = no cap (ship the full surface)

	// Tuning: batching, probing, retries
	MasterBatchSize  int           // max records per master agent batch; 0 = default 5
	ProbeConcurrency int           // max parallel probe requests; 0 = default 10
	ProbeTimeout     time.Duration // per-request probe timeout; 0 = default 10s
	MaxProbeBodySize int           // max response body bytes during probing; 0 = default 2MB

	// ReconExtraHeaders, when set, is injected onto every recon probe
	// (and into the prompt-context's TechStack rendering). Populated by
	// the CLI from --cookie / --header / --auth-config so that recon
	// fingerprints authenticated pages instead of the public landing.
	ReconExtraHeaders map[string]string

	ProjectUUID string
	ScanUUID    string

	// Session directory base path for agent artifacts
	SessionsDir string

	// SessionDir is the pre-created session directory for this run.
	// When set, the swarm runner uses it directly instead of creating one.
	SessionDir string

	// AgenticScanUUID overrides the auto-generated agent run UUID.
	// When set (e.g. by CLI), the swarm runner uses this UUID for the DB record,
	// ensuring it matches the pre-created session directory name.
	AgenticScanUUID string

	// ResumeDir is the session directory of a previous run to resume from.
	// When set, the swarm runner loads the checkpoint and skips completed phases.
	ResumeDir string

	// Streaming
	StreamWriter     io.Writer
	Verbose          bool // when true, agent calls render a per-tool result preview alongside the standard one-liner
	ProgressCallback func(ProgressEvent)

	// ScanFunc runs the scan with the given module filters and extensions.
	ScanFunc ScanFunc

	// DiscoverFunc runs native discovery+spidering before master agent planning.
	// When set, the swarm runner executes discovery and feeds discovered records
	// into the master agent alongside the original inputs.
	DiscoverFunc func(ctx context.Context) error

	// SourceAnalysisCallback is called after source analysis completes to allow
	// the caller to process session config (e.g., convert to auth-config.yaml)
	// and extensions before the scan phase.
	SourceAnalysisCallback func(result *SourceAnalysisResult) error

	// BrowserAuthCallback is fired after the browser-based auth phase writes
	// an auth-config.yaml to the session dir. The CLI uses this to thread
	// the captured session into the discovery + scan funcs so the native
	// spider (and downstream scan) crawl post-login surface. Empty path =
	// auth phase ran but produced no config; the caller may treat that as
	// a soft failure.
	BrowserAuthCallback func(authConfigPath string) error

	// PhaseCallback is called when a swarm phase starts.
	PhaseCallback func(phase string)

	// Audit is the background-audit cfg slot — backed by either audit or
	// piolium per AuditHarness. Requires SourcePath to be non-empty. Field
	// name is legacy; the runtime is harness-agnostic.
	Audit *config.AuditAgentConfig

	// AuditHarness selects which harness backs the Audit cfg. Zero-valued
	// defaults to audit for backward compat.
	AuditHarness HarnessSpec
}

SwarmConfig configures an agent swarm run.

type SwarmCoveragePlan

type SwarmCoveragePlan struct {
	ModuleTags []string `json:"module_tags,omitempty"`
	ModuleIDs  []string `json:"module_ids,omitempty"`
	// False when the scan ran against the full registry rather than a
	// plan-filtered subset — explicit so "no filter" isn't mistaken for
	// a misconfig.
	ModuleFilterApplied bool     `json:"module_filter_applied"`
	FocusAreas          []string `json:"focus_areas,omitempty"`
	Notes               string   `json:"notes,omitempty"`
	ExtensionsCount     int      `json:"extensions_count"`
	NeedsExtensions     bool     `json:"needs_extensions"`
	ExtensionAgentError string   `json:"extension_agent_error,omitempty"`
}

type SwarmCoverageReport

type SwarmCoverageReport struct {
	GeneratedAt     time.Time `json:"generated_at"`
	AgenticScanUUID string    `json:"agentic_scan_uuid,omitempty"`
	TargetURL       string    `json:"target_url,omitempty"`
	Intensity       string    `json:"intensity,omitempty"`

	TotalRecords int              `json:"total_records"`
	Prefixes     []PrefixCoverage `json:"prefixes,omitempty"`

	Plan SwarmCoveragePlan `json:"plan"`

	FindingsByModule   map[string]int `json:"findings_by_module,omitempty"`
	FindingsByEndpoint map[string]int `json:"findings_by_endpoint,omitempty"`
	TotalFindings      int            `json:"total_findings"`

	Warnings []string `json:"warnings,omitempty"`
}

SwarmCoverageReport is the JSON document written to {sessionDir}/coverage.json. Every list is sorted deterministically so reports are diffable across runs.

func BuildSwarmCoverageReport

func BuildSwarmCoverageReport(in CoverageReportInputs) *SwarmCoverageReport

type SwarmIntensityPreset

type SwarmIntensityPreset = agenttypes.SwarmIntensityPreset

Intensity types

type SwarmPlan

type SwarmPlan = agenttypes.SwarmPlan

Pipeline types

type SwarmResult

type SwarmResult = agenttypes.SwarmResult

Pipeline types

type SwarmRunner

type SwarmRunner struct {
	// contains filtered or unexported fields
}

SwarmRunner orchestrates AI-guided targeted vulnerability scanning.

func NewSwarmRunner

func NewSwarmRunner(engine *Engine, repo *database.Repository) *SwarmRunner

NewSwarmRunner creates a swarm runner.

func (*SwarmRunner) Run

func (s *SwarmRunner) Run(ctx context.Context, cfg SwarmConfig) (*SwarmResult, error)

Run executes the full agent swarm pipeline.

type TemplateData

type TemplateData = agenttypes.TemplateData

Core types

type TokenUsage

type TokenUsage = agenttypes.TokenUsage

Pipeline types

type TriageConfirmResult

type TriageConfirmResult = agenttypes.TriageConfirmResult

Pipeline types

type TriageLoopConfig

type TriageLoopConfig struct {
	Engine     *Engine
	Repository *database.Repository // optional: used for early exit on high-confidence findings

	// Agent options for triage calls
	AgentName       string
	PromptTemplate  string // e.g. "pipeline-triage" or "agent-swarm-triage"
	TargetURL       string
	Hostname        string
	SourcePath      string
	Files           []string
	Instruction     string
	DryRun          bool
	ShowPrompt      bool
	ScanUUID        string
	ProjectUUID     string
	AgenticScanUUID string // when set, triage verdicts are written back to Finding.Status
	StreamWriter    io.Writer
	Verbose         bool // forwarded to agent.Options.Verbose for the per-tool result preview

	// Skills, when non-nil and non-empty, is the planner-filtered skill set the
	// triage agent loads (via load_skill) to confirm/escalate findings. Built
	// by the swarm triage step from the plan's recommended_skills + always-on
	// set. nil → triage runs without skills (e.g. the pipeline triage path).
	Skills *skill.Registry

	// Loop control
	MaxRounds                 int
	MaxFindingsPerTriageBatch int // if >0, split findings into batches of this size for triage
	BatchConcurrency          int // max triage batches run concurrently per round; 0 = default 3 (mirrors master-agent batches)
	MaxFindingsPerRound       int // max findings loaded per triage round; 0 = default 5000
	ResumeFromRound           int // skip triage rounds before this (0 = start from beginning)
	ProgressCallback          func(ProgressEvent)
	InitialFindingIDFloor     int64 // when >0, only findings newer than this ID are triaged in follow-up rounds

	// Scan callback for rescans
	ScanFunc ScanFunc

	// Session artifacts (optional)
	SessionDir   string
	ExtensionDir string // extension dir from the initial scan, carried into rescans

	// OnRescan is called before each rescan phase starts (optional).
	OnRescan func()

	// OnTriageRoundComplete is called after each triage round completes (optional).
	// The round number (0-indexed) is passed so callers can update checkpoints.
	OnTriageRoundComplete func(round int)
}

TriageLoopConfig configures a shared triage+rescan loop used by both Pipeline and Swarm.

type TriageLoopResult

type TriageLoopResult struct {
	TriageResults  []*TriageResult
	Confirmed      int
	FalsePositives int
	RescanRounds   int
}

TriageLoopResult holds the accumulated results from a triage+rescan loop.

func RunAutopilotTriage

func RunAutopilotTriage(ctx context.Context, engine *Engine, repo *database.Repository, p AutopilotTriageParams) (*TriageLoopResult, error)

RunAutopilotTriage runs a single AI triage pass over the project's findings after an autopilot scan completes. Each finding is classified as confirmed (→ status "triaged") or a false positive (→ "false_positive") and the verdict is written back, scoped to this run's AgenticScanUUID so only findings this scan produced are touched.

It is a pure classification pass: ScanFunc is nil and MaxRounds is 1, so triage never kicks off native rescans (that remains swarm's job). It reuses the shared RunTriageLoop machinery and the agent-swarm-triage prompt.

Callers should treat a returned error as non-fatal — a triage failure must not fail an otherwise-completed scan.

func RunTriageLoop

func RunTriageLoop(ctx context.Context, cfg TriageLoopConfig) (*TriageLoopResult, error)

RunTriageLoop executes the triage agent in a loop, optionally rescanning based on the agent's verdict. This is the shared implementation used by both Pipeline and Swarm.

type TriageResult

type TriageResult = agenttypes.TriageResult

Pipeline types

type TriagedFinding

type TriagedFinding = agenttypes.TriagedFinding

Pipeline types

type VerifyCandidatesConfig

type VerifyCandidatesConfig struct {
	Repo            *database.Repository
	Provider        provider.Provider
	Model           string
	ProjectUUID     string
	ScanUUID        string
	AgenticScanUUID string
	Target          string
	SessionDir      string
	Mode            string // config.AutopilotMode{Shadow,Enforced}
	Concurrency     int    // 0 = defaultVerifyConcurrency
	StreamWriter    io.Writer
}

VerifyCandidatesConfig configures a verify-before-promote pass.

type VerifyCandidatesResult

type VerifyCandidatesResult struct {
	Total         int
	Confirmed     int
	Rejected      int
	NeedsEvidence int
	Promoted      int // findings written (confirmed & promotion succeeded)
}

VerifyCandidatesResult summarizes a verify pass.

func VerifyCandidates

func VerifyCandidates(ctx context.Context, cfg VerifyCandidatesConfig) (*VerifyCandidatesResult, error)

VerifyCandidates runs the fresh-context verifier over every proposed candidate for the run, promoting the confirmed ones. It is a no-op (nil, nil) in legacy mode, without a repo/provider, or when there are no proposed candidates. Best-effort: an individual verifier failure marks that candidate needs_evidence and continues; the pass never fails the whole autopilot run.

type VigToolSpec

type VigToolSpec struct {
	Repo        *database.Repository
	ProjectUUID string
}

VigToolSpec, when set on a SessionSpec built with IncludeTools, registers the vigolium read+replay tool subset — query_records, inspect_record, replay_request, attack_kit — so a skill-driven agent (swarm triage) can run an explore → inspect → craft → replay confirmation loop against prior scan records. Requires Repo. OAST tools are intentionally excluded: oast_mint owns an interactsh Service that needs an explicit Shutdown the per-call engine can't manage.

Directories

Path Synopsis
Package agenttypes defines shared data types used across the agent subsystem.
Package agenttypes defines shared data types used across the agent subsystem.
Package recon performs a lightweight, conservative reconnaissance sweep against a target host before the swarm plan agent runs.
Package recon performs a lightweight, conservative reconnaissance sweep against a target host before the swarm plan agent runs.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL