Artifacts

What the agent captures as evidence, and what it does not.

An artifact is a single piece of captured evidence from a run. Each one is hashed with SHA-256 the moment it is produced and stored under that hash, with the phase it came from, its position in the run, and the finding it supports if it supports one.

The kinds written during a run

Stored kind Written when
command_log The agent runs a shell command. The artifact is JSON holding the command, its stdout and stderr, the exit code, the start and end times and the duration.
req_resp The agent makes an HTTP request with its request tool, and again for the navigation behind a browser screenshot. The artifact is JSON holding the request and the response.
screenshot The agent takes a browser screenshot. The artifact is the PNG, with filename set to screenshot.png.
other The model attaches evidence to a finding and declares it as a payload or a file.

The first three come from tool calls the agent makes directly. other comes only from the fourth path below.

Evidence the model attaches to a finding

When the model records a finding, or adds to one, it supplies evidence items alongside the description. Each item declares a kind, and the tool schema offers six: command_output, screenshot, payload, request, response and file. That is the model's vocabulary, not the stored one. Each declared kind is translated before the capture is written:

  • command_output becomes command_log
  • screenshot becomes screenshot
  • request and response both become req_resp
  • payload and file both become other

The item's content is stored as UTF-8 bytes, hashed like any other artifact, and linked to the finding. A payload or a file is not dropped and does not raise; it lands in the locker under the kind other, which carries no information about what the model meant by it beyond the content itself.

A kind outside those six never reaches the translation. The evidence item fails validation as the finding is being built, the tool call raises, and the run loop counts a failed step: no artifact is written, and on a new finding the finding itself is discarded. On an update, the status, severity and CVSS changes made earlier in the same call survive; the new evidence does not. Five consecutive failed steps abort the run.

What the store permits

The artifact schema permits five kinds — the four above plus json_manifest. Nothing in the product writes json_manifest.

The manifest and the signature block are written into the same content-addressed store at seal time, under their own hashes, so an export can copy the exact signed bytes. They are not artifacts: they have no artifact row, no kind and no position in the chain.

Content addressing

An artifact's name is the hex SHA-256 of its bytes. The agent computes it at capture time; the server recomputes it on receipt and refuses bytes that do not hash to the value claimed for them. Accepted bytes are written to a temporary file, made read-only, and renamed into place, so a stored blob is written once and never modified.

A database row pairs that hash with the engagement, under a unique constraint on the pair. One distinct byte string is one row per engagement. Capturing identical bytes a second time within a run is a no-op: the existing row is returned and linked to the new finding if there is one. Two different engagements that produce identical bytes get separate rows and separate files, because the storage path includes the engagement id.

Sequence numbers come from a counter in the agent that starts at zero and advances on every capture, including ones that turn out to be duplicates. A run's stored sequence numbers can therefore have gaps. Order is what the chain depends on, not contiguity.

What each artifact records

Beside the kind, the hash and the size, an artifact records:

  • phase — which of the seven phases the agent was in when it captured this.
  • seq — its position in the run, and the order the hash chain is built in.
  • filename — set for screenshots, absent for the JSON kinds.
  • Findings it supports — a many-to-many link, so one artifact can back several findings. The link is written when the artifact arrives and is idempotent.
  • control_ids — empty on arrival, filled at seal time with the union of the framework control identifiers of every finding the artifact is linked to. That union is built from the framework's ATT&CK and WSTG tables only, not from the keyword fallback the report uses elsewhere.

The finding link is what lets the report put a hash beside a claim. For a sealed run, the report reads the manifest rather than the database, groups the manifest's entries by the finding ids recorded in them, and prints each supporting artifact's hash, kind, position and size under the finding. Every hash printed is by construction one the signature covers. An unsealed run has no manifest, so the report renders with no per-finding hashes and says so.

The 10 MiB ceiling

One artifact cannot exceed 10 MiB — 10,485,760 bytes exactly, checked as len(data) > 10 * 1024 * 1024 at both ends, in the agent and again in the store. The check runs before anything is emitted, so an oversized capture produces no bytes, no hash and no row; it is dropped, not truncated.

An oversized capture fails the step that produced it

Nothing on the agent's path catches the error. It propagates out of the tool handler and out of the step, where the run loop records an error event and increments the consecutive-error counter. What else is lost depends on which handler was running:

  • Shell command. The capture is attempted before the command's output is given back to the model, so the model never sees the output either. The step is lost whole.
  • Browser screenshot. The request/response pair is captured first, so an oversized PNG leaves that pair recorded and the image absent.
  • Finding evidence. The finding has already been collected and still appears in the results, and any evidence items before the oversized one were captured. The oversized one is not, and the model is not told the call succeeded.

A single failed step does not end a run. Five consecutive ones do.

Last updated 2026-09-22