The JSON emitter is the source of truth. SARIF, JUnit, Markdown and PDF are all derived from the sameDocumentation Index
Fetch the complete documentation index at: https://docs.agentguardian.io/llms.txt
Use this file to discover all available pages before exploring further.
Scan model that --output json
serialises. When in doubt, read the JSON. Source:
reports/json_report.py.
When to use this page
- You want the raw machine-readable scan output for a custom dashboard or threshold checker.
- You’re writing a parser and need the canonical-form guarantees (sorted keys, deterministic shape).
- You need a signed artifact for an audit trail.
Generate one
~/.agentguardian/scans/<scan_id>/scan.json regardless of which
--output you ask for — even a --output pdf run writes the canonical
JSON alongside the PDF. --output json --output-path scan.json just
adds a second copy at the path you name.
You can also regenerate the JSON from a stored scan:
What you get
The schema isagentguardian-scan-v1 (SCHEMA_VERSION in
reports/json_report.py:52). Top-level keys, in canonical (sorted)
order:
| Key | Type | Notes |
|---|---|---|
aivss | int 0–100 | The headline score. |
aivss_formula_version | str | aivss-v1. Bumps on any scoring change. |
asi_scores | {str: float} | Per-category 0–100, keyed by ASI01–ASI10. |
band | str | EXCELLENT / GOOD / WARNING / POOR / CRITICAL / not_evaluated. |
budget | object | null | Runtime USD outcome. |
completeness | object | null | How much of the planned attack work ran. |
cost_usd | float | Actual LLM spend. |
coverage | object | Counters reconstructed from memory.jsonl. |
coverage_grade | str | A–F. A = every ASI category covered by real evidence. |
created_at | str (ISO 8601) | UTC if no tzinfo, else local-with-offset. |
duration_seconds | float | Wall-clock runtime. |
engine | object | null | LLM model spec per role ({commander, attacker, evaluator} → model id). |
evaluation_mode | str | real ⇔ a real LLM judged turns; stub forces band: not_evaluated. |
findings | Finding[] | One entry per landed attack. See Evidence timeline. |
findings_summary | object | Pre-aggregated counts by ASI / severity. |
mode | str | fast / smart / full. |
mode_authoritative | bool | true only for full. Veto for --fail-under. |
package_version | str | The agent-guardian PyPI version that emitted this. |
probe_library_version | str | 2026.05 etc. — bumps when the corpus changes. |
scan_id | str | Generated id (e.g. cli-3a4c1d9c2840). |
scoring_valid | bool | false for stub LLM / empty corpus. |
signatures | object | HMAC + Ed25519 blocks. Stripped before recomputing the signing input. |
stopped_reason | str | completed / budget / early_stop / cancelled. |
sub_scores | {str: float} | The six PRD §6 sub-scores. |
target | object | {mode, ref, inferred_goal, profile_source}. |
tier | str | Detected or forced tier (T1–T4). |
tokens_total | int | Total input+output tokens across all roles. |
undertested | str[] | ASI categories the scan launched but exercised too thinly. |
audit envelope is added under contract-driven scans (contract
sha256, authorization ref, suppressed tool attempts, egress-refused
turns). See
reports/json_report.py:169.
Canonical form (the rules that make it deterministic)
Same inputs always produce byte-identical output. Three rules guarantee that:json.dumps(..., indent=2, sort_keys=True)— every object’s keys are sorted lexicographically before serialisation.signaturesis excluded from the signing input. The HMAC + Ed25519 blocks are computed over_strip_signatures(payload)(everything except thesignaturesfield) so signing an already-signed payload twice yields the same bytes.- PII redaction is on by default (
redact_pii=True). The sharedredact_findinghelper scrubs all five fields before serialisation — see Evidence timeline.
agent-guardian verify relies
on.
Signatures
Every JSON report carries two signature channels undersignatures:
- HMAC-SHA256 — uses
AGENT_GUARDIAN_SIGNING_SECRET(or the documented default for local-only smoke). The public default is never accepted on verify — without the real secret, the HMAC channel is integrity-only. - Ed25519 — uses a long-lived signer key under
~/.agentguardian/keys/. The public key is embedded so the report is self-verifying for integrity; trust requires anchoring (see below).
signatures key. Verifiers reconstruct the same bytes and recompute
both channels.
Verifying a JSON report
verify is fail-closed: a green result requires a pinned trust
anchor. Without one, integrity passes but the result is UNANCHORED
and the command exits non-zero.
| Outcome | What it means | Exit |
|---|---|---|
schema: OK + HMAC: OK + Ed25519: OK + trust anchor: PINNED | Bytes match + anchored to your pinned key. Quotable. | 0 |
schema: OK + integrity green + trust anchor: UNANCHORED | Bytes match but no anchor supplied. Don’t quote. | 1 |
Any channel FAIL or schema invalid | Tampered or wrong-anchor. | 1 |
EXIT_FAIL_UNDER (1) a failed
--fail-under gate uses — CI gates treat tamper and risk-floor
identically.
Read it in this order
When you first open ascan.json:
band— first glance. Human label.aivss— score behind the band. Trust only whenscoring_valid: trueANDmode_authoritative: true.evaluation_mode—real= a real LLM judged turns.stubforcesband: not_evaluatedand the number is meaningless.mode_authoritative—trueonly for--mode full.coverage_grade+undertested— categories launched but too thinly tested for “no findings” to be safety evidence.findings— sorted by severity then descending confidence.
Anti-patterns
Next step
SARIF export
The same findings as a SARIF 2.1.0 file for GitHub Code Scanning.
Markdown export
The same findings as a flat Markdown report for PR comments.
Report schema
Field-by-field schema reference.
Upload SARIF to GitHub
Walk-through for
github/codeql-action/upload-sarif@v3.