Skip to main content
olium is the in-process AI agent runtime that powers every agentic feature in Vigolium. It ships as both:
  • A user-facing command: vigolium agent olium (aliases: vigolium olium, vigolium ol), for interactive chat in a TUI or scripted one-shot prompts.
  • A library: pkg/olium/, that the autopilot, swarm, query, vigolium-audit-prep, and source-analysis paths all dispatch through. There are no subprocess SDK or ACP backends; every AI call in vigolium goes through this engine.
For a higher-level comparison against the other agent subcommands, see Agent Mode.

What it is

A turn-based, tool-using LLM agent written in Go. Components:

What it does

Each invocation runs one multi-turn loop:
  1. Append the user prompt to history.
  2. Stream a single provider response (text deltas, thinking deltas, tool calls).
  3. Append the assistant turn to history; emit EventTurnDone with token usage.
  4. If there are no tool calls → emit EventRunDone and exit.
  5. Otherwise dispatch the tool calls. If all calls are read-only the engine fans them out in parallel (cap = 8); otherwise it runs them strictly serially so writes can’t race reads. Tool results are appended to history in the model’s original order regardless.
  6. Loop back to step 2, capped by MaxTurns (default 32 for chat / headless, 200 for autopilot).
Surrounding behavior:
  • Tool result truncation / spill: results larger than MaxToolResultBytes (default 16 KiB) get head+tail truncation with an elision marker. If SpillDir is set (autopilot does this), the full payload spills to <SpillDir>/tool-results/ and the model gets a head excerpt plus an on-disk path it can read_file.
  • Per-tool timeout: each tool invocation gets its own deadline (default 5 minutes). A runaway bash curl can’t hang the whole session.
  • Prompt caching: opt-in via EnablePromptCache. Autopilot turns it on; the Anthropic providers write cache_control: ephemeral markers and the Codex OAuth provider writes prompt_cache_key headers, cutting repeated-prefix tokens by ~90 % across long runs. openai-api-key, openai-responses, openai-compatible (Ollama / OpenRouter / LM Studio / vLLM / Groq / …), anthropic-compatible, and google-vertex do not emit cache markers, so the flag is silently ignored for them. (anthropic-claude-sdk-bridge manages caching inside the Claude Code Agent SDK.)
  • Skills: when a registry is loaded the engine injects an <available_skills> block into the system prompt at construction, and registers a load_skill tool the model can call to fetch a skill body on demand.

Modes

Interactive TUI (default)

Bubble Tea inline mode (no alt-screen, output appends to scrollback as it streams). Live partial line, fenced code-block highlighting via chroma, and a one-line “tool exec” card while a tool runs. Slash chooser opens on /:
  • /clear: clear conversation history.
  • /skill:<name> [args]: inline expansion of a loaded skill; the body is pasted into the prompt so the model doesn’t have to spend a tool call to load_skill.
The model id, provider, and reasoning effort are shown in the banner header.

One-shot non-interactive

Passing -p / --prompt runs a single prompt non-interactively and streams to stdout, the TUI is skipped automatically.
Prints assistant text to stdout; thinking deltas, tool start/end cards, and per-turn [turn done in= out= cached=] summaries go to stderr. Exits non-zero on engine error.

Library use (autopilot, swarm, query)

pkg/agent/olium_adapter.go is the single dispatch path every other agent feature funnels through:
  • runOliumPrompt(ctx, cfg, prompt, streamWriter, sourcePath): fresh engine per call.
  • runOliumOnEngine(ctx, cfg, eng, prompt, streamWriter): reuses an engine so the conversation prefix stays warm (used by source-analysis to fork an explore phase into 3 parallel format calls).
  • acquireProviderSlot(ctx, cfg): global semaphore (size = agent.olium.max_concurrent, default 4) that bounds in-flight provider calls process-wide so swarm phase fan-out can’t trigger 429s on tier-1 plans.
  • EffectiveCallTimeout(): default 10 min per provider call; 0 → default, negative → no timeout.

Providers

Eleven drivers in pkg/olium/provider/. The provider ID is vendor-first so it’s obvious which credential field applies: With no --provider flag and no YAML override, vigolium defaults to openai-compatible with gemma4:latest against a local Ollama endpoint, so a freshly initialized config works out of the box without any cloud credentials. The anthropic-oauth provider also prepends a Claude Code preamble to the system prompt and adds the oauth-2025-04-20 beta header so it’s accepted on the same endpoint as anthropic-api-key. Codex auth refreshes itself: it parses the JWT, checks expiry with a 60 s skew, and posts to /oauth/token with the stored refresh token, rewriting ~/.codex/auth.json (mode 0o600).
Note: the REST API falls back to agent.olium.* in vigolium-configs.yaml (which keeps warm sessions and prompt caches stable across requests), but every agent run endpoint also accepts per-request BYOK credentials (api_key, oauth_token, oauth_cred_file, oauth_cred_json). The audit dispatcher additionally accepts audit_auth / piolium_auth for per-driver overrides.

Tools

Built-in tool registry, eight tools registered in this order: * web_fetch is only read-only in the no-capture variant (TUI chat / query, no DB wired). Under autopilot the capture-enabled variant persists every fetch as an http_recordhttp mode returns a record_uuid, browser mode captures every XHR/fetch during render (many records per call) — so it can issue state-changing methods, is not read-only, and does not join the parallel read-only fan-out (concurrent capturing fetches would race the shared record store). The IsReadOnly() flag is what the engine uses to decide whether to fan out a turn’s tool calls in parallel. bash runs without an approval prompt (yolo mode), only the catastrophic-pattern guard prevents disasters.

Autopilot adds more

When the engine runs under vigolium agent autopilot, the registry also gets:
  • halt_scan: model-driven exit. Sets a halt signal; the run loop exits after the current turn.
  • report_finding (legacy/shadow): persists a finding to the database and accepts record_uuids linking its proving http_records. Shadow mode also mirrors a candidate for independent grading. It soft-warns at 50 saved findings and hard-caps at 200.
  • propose_candidate (enforced): persists a claim and its evidence for a fresh-context skeptic verifier. Only confirmed candidates are promoted to findings.
  • load_skill: fetch a skill body by name (registered whenever the skill registry is non-empty).
  • update_plan / remember: durable scratchpad plan + notes that survive section rotation and resume (registered unconditionally, seeded from the pipeline’s frozen plan when present).
  • Vigtool (registered when Repo is non-nil): scanner- and record-aware tools —
    • Scan / modules: run_native_scan, run_module, run_extension, list_modules.
    • Record surface: query_records, inspect_record, replay_request, send_raw_http.
    • OAST: oast_poll, oast_mint.
    • Sessions / findings: list_sessions, get_session, list_findings, update_finding.
    • Auth: list_auth_sessions, auth_session_lookup, browser_auth (only when agent-browser is on $PATH).
    • Payloads: attack_kit.
    • Live Burp bridge (server runs, operator-enabled listener): search_burp_items, inspect_burp_item.
    • Capture-enabled web_fetch + browser_probe replace their built-in variants (need Repo + ProjectUUID), persisting every fetch as an http_record.
A few of these are worth calling out:
  • attack_kit returns a curated starter-payload set per attack class (xss, sqli, ssrf, cmd-injection, path-traversal, ssti, xxe, open-redirect, crlf) — read-only and non-mutating. Its SSRF Redis gopher PoC is a harmless PING probe (v0.2.5 changed it from a destructive FLUSHALL), so an autonomous agent can’t wipe a target’s data; intrusive commands are left to explicit operator authorization. Pair it with replay_request to actually send payloads.
  • replay_request sends a mutated stored record and persists the exact sent request + received response as an olium-replay http_record, returning its UUID as replay_record_uuid — pass that to report_finding or propose_candidate via record_uuids as reproducible proof.
  • search_burp_items / inspect_burp_item are read-only tools (server runs only) that search / inspect the live Burp Target site map or Proxy history over an operator-enabled read-only bridge listener; they never modify Burp.

Skills

Skills are Markdown workflow files with YAML frontmatter, following the agentskills.io convention so files written for Claude Code or pi work in olium verbatim. Format:
name must match [a-z0-9-]+ (≤64 chars); description ≤1024 chars.

Discovery

The skill registry walks four scopes, first-found-by-name wins:
  1. Project: .agent/skills/ and .claude/skills/ in the working directory and every ancestor, closest first.
  2. User: ~/.vigolium/skills/ (only when IncludeUserSkills=true).
  3. Embedded: shipped in the binary under public/presets/skills/ via go:embed.
Two on-disk layouts are accepted: <root>/<name>/SKILL.md (directory skill, the agentskills.io standard) or <root>/<name>.md (single-file shorthand; frontmatter name must match the filename stem). Generic chat (vigolium agent olium, headless) loads scopes 1 + 3 only. Autopilot and swarm load all three so security-specific workflows in ~/.vigolium/skills/ don’t pollute casual chat.

Use

The engine writes an <available_skills> block into the system prompt listing every skill’s name + description + location. The model fetches bodies on demand via the load_skill tool, progressive disclosure, so unused skills don’t burn tokens. In the TUI, type /skill:<name> [args] to inline-expand a skill body into your prompt directly, no tool call needed.

CLI flags

Precedence for the initial prompt: positional args → -p/--prompt → stdin (auto-detected when piped, or forced with --stdin). Values flow CLI → YAML → env: every CLI flag falls back to its agent.olium.* YAML field, which in turn falls back to the documented default or env var.

Configuration

The full agent.olium block:
autopilot_mode is legacy by default. shadow and enforced enable durable section rotation; enforced additionally gates finding promotion through a fresh-context verifier. A negative max_concurrent removes the provider-call cap, while 0 keeps the default cap of 4. Adjacent config blocks worth knowing:
  • agent.sessions_dir: where per-run session directories go. Default ~/.vigolium/agent-sessions/.
  • agent.browser: toggles agent-browser integration (the binary web_fetch shells out to in mode: browser).
  • agent.audit: controls the optional vigolium-audit / piolium prep step that autopilot/swarm can stack ahead of the olium loop.

Sessions and on-disk state

Every agent run gets a session directory under agent.sessions_dir (default ~/.vigolium/agent-sessions/<run-uuid>/). Bare vigolium agent olium chat doesn’t write a session, it’s only autopilot/swarm/query that materialise one. Inside a session dir you may find:
  • runtime.log: per-turn event log (text deltas, tool start/end, turn-done summaries).
  • tool-results/<tool>-<call-id>.txt: spilled oversized tool outputs (when the engine’s SpillDir is set).
  • session-config.json: run metadata (project / scan UUIDs, options).
  • swarm-plan.json, master-output.md, audit-stream.jsonl, checkpoint.json, produced by the higher-level modes that wrap olium (swarm, vigolium-audit, autopilot).
Browse past runs with vigolium agent session list / --full / --tail.

Stream events

The engine emits a unified Event channel regardless of provider: Token counts on EventTurnDone are accumulated by every higher-level caller (autopilot for budget enforcement, the adapter for agenttypes.TokenUsage, the swarm for cost reporting).

When to use what

Olium itself is the general-purpose chat / dev surface and the engine every other mode reuses, it is not a security scan on its own.

See also

  • Agent Mode, the full agent subcommand map.
  • Autopilot, autonomous scan mode built on the olium engine.
  • Swarm, AI-guided multi-phase scan that drives the native scanner.
  • How It Works, provider list and the high-level dispatch story.