Skip to content

Agent Loop

0 runs assessments by putting a model in a loop with tools. The model reads the task, proposes tool calls, receives their results, and decides what to do next. Deterministic tool policies, budget checks, and verification constrain that process; model reasoning alone is not evidence.

runNativeAgentLoop in packages/core/src/agent/native-loop.ts exchanges structured messages and tool calls through the configured runtime. Provider adapters translate its tool_use / tool_result representation to the appropriate wire protocol. Applicable process runtimes use a legacy text loop.

Each iteration is one turn. The caller supplies maxTurns; budgets differ by workflow, role, and depth. The loop can finish on done, a qualifying text-only completion, a limit, cancellation, or an error. Optional compaction, loop detection, and budget warnings operate around this cycle.

Strategy racing and EGATS are separate opt-in orchestration paths, not steps every normal loop executes. scan --race is benchmark/CTF-oriented, not a recommended setting for ordinary live-target audits.

The system prompt defines the role, available tools, and target approach:

  • shellPentestPrompt (web) — emphasizes bash, save_finding and done, with curl/python3/CLI probing. The caller can still expose structured network tools; a prompt’s preferred approach is not the executor’s complete tool list.
  • discoveryPrompt / attackPrompt (LLM/AI) — probing endpoints, extracting system prompts, testing jailbreaks.
  • researchPrompt (source) — map the codebase, trace input → sink, write PoCs.

The prompt includes concrete target details: URL, known endpoints, detected features, and (for attack agents) discovery results.

Tool results append stdout/stderr, HTTP responses, or structured output as tool_result messages.

Budget prompts continue a turn after a text-only response, escalating with the budget consumed:

Budget usedPrompt
< 30%Role-specific nudge: interact with the target, or use scoped source tools for review/audit
30-50%“Summarize what you learned. Top hypothesis?“
50-70%“HALFWAY. List every approach tried. Most promising untested vector?“
70-85%“URGENCY. If the current approach isn’t working, SWITCH NOW.”
85-100%“FINAL PUSH. Highest-confidence exploit path ONLY.”

Strategy changes depend on the model. Feature-gated warnings also apply during tool-call turns. See Budget Management.

ToolExecutor in packages/core/src/agent/tools.ts handles tool calls. Web mode uses:

  • bash — runs shell commands and returns execution output. It is subject to scope and tool policy; by default it executes on the host, not in an OS sandbox.
  • save_finding — records a candidate and its evidence; where database persistence is configured the finding survives beyond the loop. Saving alone is not independent verification.
  • done — signals completion with a summary; sets state.done = true and exits.

Other tools by mode: http_request/submit_form (structured HTTP), send_prompt (LLM), read_file/run_command (source), crawl (spidering), browser (Playwright). spawn_agent creates one sub-agent with fresh context to dig into a specific vuln; spawn_agents launches a bounded batch of such sub-agents with bounded concurrency and their own turn budgets. Their successful findings merge into the parent after the batch joins. Child errors do not erase sibling results. Descendants can delegate recursively while retaining the parent’s role, scope, advertised tool restrictions, shared accounting, and cancellation tree. They inherit root policy plus their own task, not an accumulating stack of ancestor tasks. Separate contexts do not mean isolated host filesystems or providers.

Cross-run hunt memory is off by default for local native runs. Embedded callers can explicitly opt in through codebaseLearning or an injected memory store; ZERO_DISABLE_HUNT_MEMORY=1 or true vetoes either. Managed source research opts in only with a configured Cloud sink; managed verification does not. Ordinary conversation/session history is separate from cross-run learning.

When Jev browser assistance is explicitly enabled, browser action observe exposes a compact link snapshot and assist can follow a bounded sequence of operator-approved read-only URLs. It requires scope and the exact URL allowlist; the evaluator cannot invent actions, approve a write, fill forms, handle MFA or confirm a vulnerability. Changed pages, uncertain choices and unavailable evaluation return a handoff to the main agent. See Features for setup and data-egress limits.

The workflow selects the main runtime; child role-model overrides remain subject to that runtime’s supported route and single-model policy. A fresh child context is not an automatic switch of provider credentials.

Tool completion and task success are different signals. A child lifecycle completed event means its loop returned normally, which can include reaching a turn budget; inspect its findings and result rather than treating that event as verified exploit success.

The model chooses hypotheses and actions within the task and available tools. Deterministic policy, scope, playbooks, and evidence gates constrain execution.

Illustrative sequence in an authorized disposable lab at http://target:8080 (not a recorded run or a promised turn count):

  1. Recon. curl -i http://target:8080/ returns a login form and a footer: “Demo credentials: demo / demo”.
  2. Auth. curl -c /tmp/jar -b /tmp/jar -d 'username=demo&password=demo' -L .../login → 302 to /dashboard with a session cookie.
  3. Enumerate. /profile loads /api/users/1, showing "id": 1, "username": "demo".
  4. IDOR probe. curl -b /tmp/jar .../api/users/2 returns another user: "id": 2, "username": "admin", …, "flag": "FLAG{idor_1a2b3c}".
  5. Save + finish. save_finding with the request, the leaking response, and analysis; then done.

Verify cross-user access under known test identities before accepting the finding.

Use supported --verbose flags for progress and tool detail. Output varies by workflow and can omit provider-transcript details. Redact logs before sharing.

Common patterns:

  • Loops on one payload — inspect repeated tool results, scope denials, and access failures before increasing the budget.
  • Provider errors or empty responses — check the reported provider/model, credentials, availability, and rate limits; see Troubleshooting.
  • Exits too early — text-only completion requires at least min(4, maxTurns) turns, nonempty text and end_turn. An accepted done can finish sooner; errors, cancellation and limits can also stop the loop. Do not infer a premature done from turn count alone.
  • No findings saved — the agent may be finding vulns but not calling save_finding. Check verbose output.

Saved history and timeline — list runs, then inspect the event timeline for a known scan ID:

Terminal window
0 history --limit 10
0 timeline <scan-id> --db-path ~/.0/runs/<scan-id>/state.db

timeline reads the selected database; it does not search every run-local database by scan ID. Adjust the path if you use a different state directory.

The native loop checkpoints SQLite session state every 2 turns when a database is configured, and persists again at completion. Journal-backed continuation and console transcript resume are different mechanisms. Follow Scan Workflows for scan recovery and Console for chat-session resume; do not assume an interrupted tool can be safely rerun.