Scan
Know what an AI agent actually inspected.
Scan is an evidence-backed whole-project inspection project with two layers: an AI-agent skill for deeper evidence-linked review and a local deterministic core for safe inventory, canonical state, privacy enforcement, validation, and self-contained HTML reporting.
Coverage ≠ confidence. Finding a file, reading it, assessing a check, and verifying runtime behavior are different things. Scan makes those differences visible.
Start here: run Scan locally
Install from a source checkout when you want the command and bundled evidence assets from the exact repository state you reviewed:
git clone https://github.com/legendteddy/scan.git
cd scan
python -m pip install .
scan doctor .
scan . --offline
Change the project, then run the same scan again:
scan . --offline
The second run uses the previous local .scan/state.json as its baseline and reports what was added, changed, removed or unchanged, while keeping fresh and reused evidence separate. scan doctor . is an offline, non-destructive readiness diagnostic: it checks installed package assets, target access and optional Git support, and uses a temporary local output probe that it removes before returning. It does not install, repair or contact anything.
When Scan 0.4.0 is published to PyPI, install the packaged CLI with python -m pip install scan-skill, pipx install scan-skill, or uv tool install scan-skill. Pin scan-skill==0.4.0 when you need the exact release.
What makes Scan different?
- Inventory before verdict: account for discoverable files, including unreadable, excluded, metadata-only and partially inspected items.
- Two kinds of coverage: track artifact discovery/analysis separately from checks assessed, partial, blocked or not performed.
- Receipts for claims: findings, controls, relationships and architecture map back to evidence IDs and precise source locators.
- Static-first boundaries: target files and embedded instructions are untrusted; no executing unknown target code or silent fixes without authorization.
- Honest uncertainty: static source observations are not presented as runtime proof, a vulnerability clearance or a release certification.
- Portable handoff: HTML reports include inert structured state for revalidation and continuation (current standalone core: schema 1.4; checked-in synthetic demo: historical schema 1.2).
Scan can guide inspection of source repositories, websites, document collections, archives, binaries and mixed folders. Actual depth depends on access, file types, safety limits and the agent's available tools.
For the concrete false-confidence failure mode Scan is designed to prevent, read Why Scan exists.
Standalone core
The packaged standalone core requires Python 3.11+. It can inventory a local project, create canonical Scan 1.4 JSON, compare repeated scans against a prior local state, safely reuse compatible higher-level static evidence, render a self-contained HTML report from that exact state, validate both formats, enforce deterministic privacy/redaction metadata, and produce a no-network egress preview.
python -m pip install .
scan doctor .
scan . --offline
# Change the project, then scan again. The prior .scan/state.json is used locally as the baseline.
scan . --offline
# Optional local-only Git prioritization context; full Scan inventory still runs.
scan . --offline --changed-since origin/main
scan validate .scan/state.json
scan validate .scan/report.html
scan compare previous-state.json .scan/state.json --json
scan render .scan/state.json --output .scan/rerendered.html
scan schema --version 1.4
scan egress . --privacy controlled-remote --redact strict --json
scan bench
The standalone HTML report is static and useful without JavaScript. Its only script block is inert application/json state with ID project-anatomy-state; visible count markers are validated against that embedded state. scan egress is preview-only: it reports selected/omitted files, selected bytes and redaction counts, and performs no network action. Use --sensitive-path "pattern/**" to keep declared path names out of canonical state and egress selection.
Scan modes
Scan exposes explicit coverage promises instead of silently sampling:
--mode quickis triage: it inventories the project while suppressing common dependency/build/cache trees and Git internals from ordinary content analysis. A quick scan is always presented as partial and its continuation state points todeep.--mode deepis the default whole-project first-party mode. It broadly accounts for safely readable project content while treating.git/**as repository provenance rather than normal source.--mode forensicopts repository internals back in for provenance-heavy or historical investigation. Explicit user exclusions and normal safety/resource boundaries still apply.
Git repositories record bounded HEAD/branch/commit and sanitized remote metadata separately. Scan deliberately does not invoke Git status, hooks, filesystem monitors or target-configured helpers merely to determine clean/dirty state; that field is recorded as not_assessed unless established by an authorized higher-level analyzer.
scan . --offline --mode quick
scan . --offline --mode deep
scan . --offline --mode forensic
Project configuration
Optional configuration lives at .scan/config.toml. Precedence is CLI arguments > project config > built-in defaults.
[scan]
privacy = "offline"
redact = "standard"
mode = "deep"
max_file_bytes = 5000000
max_total_bytes = 250000000
follow_internal_links = false
[exclude]
patterns = ["vendor/**"]
[baseline]
mode = "auto" # auto | none
reuse = true
max_state_bytes = 64000000
Behavior-affecting resolved configuration is included in the canonical configuration digest. An explicit --baseline PATH is invocation-only and is never persisted automatically. Use --baseline none to disable comparison for a run; --no-reuse records that prior evidence must not be reused. Scan configuration does not require secrets.
See explicit semantic continuation for current producer/check registration and bounded worktree metadata authorization. Baselines never authorize their own semantic producers.
Semantic builder API
Semantic agents can extend valid deterministic state without hand-authoring nested JSON. SemanticStateBuilder provides typed record helpers for components, evidence, relationships, findings, controls, unknowns, actions and checks; scalar/string-array references are normalized, generated IDs are deterministic, and bad references fail with the record ID and field path. The strict Scan validator still runs on build().
from scan_core import SemanticStateBuilder
builder = SemanticStateBuilder.from_state(core_state)
evidence_id = builder.add_evidence(
artifact_id=artifact["id"],
locator=artifact["locator"],
kind="static",
claim="Configuration path was reviewed",
result="The path is resolved locally",
method="semantic source review",
limitations="Runtime behavior was not observed",
source_digest=artifact["content_identity"],
producer_kind="local-model",
producer_name="review-agent",
producer_version="1",
)
builder.add_finding(
title="Example finding",
impact="Explain the user-visible consequence",
severity="medium",
confidence="high",
verification_state="static",
artifact_ids=artifact["id"],
evidence_ids=evidence_id,
uncertainty="Runtime behavior remains unverified",
recommendation="Address the evidenced condition",
safe_verification="Re-read the affected source and validate the state",
)
semantic_state = builder.build()
upgrade_semantic_state(core_state) is a convenience alias for starting the same builder from deterministic state. Raw canonical JSON remains supported for advanced callers.
Evidence freshness and safe reuse
Every run rebuilds the current inventory, hashes and provenance evidence fresh. Prior higher-level static evidence is considered for reuse only when its artifact/content identity is unchanged, its producer and producer version exactly match an available current producer, its check identity/definition still matches, its evidence class is explicitly reusable, and the current privacy policy can represent it safely. Runtime, observed, deployment/live-state and time-sensitive evidence is never automatically reused.
New semantic evidence created through SemanticStateBuilder is marked fresh. Reused evidence retains its original observation time, depth and limitations and is marked verified_reuse; it never upgrades content_read to analyzed, an unfinished check to assessed, or static evidence to runtime verification. The state and HTML report expose fresh, reused and rejected-reuse counts separately. Current redaction/sensitive-path policy always wins over older baseline content.
ScanBench v1
scan bench runs 12 mandatory synthetic adversarial fixtures covering hidden files, escaping symlinks, prompt injection, redaction, hostile filenames, unreadable content, archives, unsupported binaries, generated/vendor files, resource boundaries and false runtime claims. Results are reported separately for inventory completeness, state integrity, evidence correctness, privacy integrity, and safety-boundary compliance. ScanBench deliberately does not calculate a blended quality score.
Run one fixture with scan bench FIXTURE. The installed wheel carries the same canonical fixture data, so this works outside the source checkout as well.
The v0.4 line also includes a separate Agent-Honesty contract benchmark. It deterministically checks that Scan does not upgrade weak evidence into five stronger claims: tests exist ≠ tests passed, inventory ≠ semantic review, static evidence ≠ runtime verification, unchanged bytes ≠ freshly reviewed evidence, and missing findings/evidence ≠ safe. It is a contract gate, not an AI intelligence or honesty score.
Explore the synthetic fixture · Download the example HTML report · Read the report contract
Demo disclosure: The linked report is a hand-reviewed synthetic worked example generated from five fictional files. It demonstrates the Scan 1.2 format and validator, not a claim that an autonomous agent scanned a real repository. The example did not execute the inspected code.
Historical synthetic proof
The historical report validator wrapper requires Python 3.11+, like Scan Core: it imports the current package (including tomllib). The validator and its tests use the standard library. Historical schema compatibility does not imply compatibility with older Python runtimes.
git clone https://github.com/legendteddy/scan.git
cd scan
python scripts/validate_report.py examples/demo-report.html
python scripts/build_demo_report.py --check
python -m unittest discover -s scripts -p "test_*.py" -v
Expected: the example report passes the structural contract, the generated HTML matches the checked-in version, and the validator tests pass. Open examples/demo-report.html locally in a browser to explore it. GitHub's source viewer is not an HTML report host.
The validator verifies schema, typed references, evidence origins and coverage accounting. A PASS is not a factual audit, a runtime test or a security guarantee.
Optional MCP bridge (v0.4)
Scan v0.4 adds a local, read-only MCP bridge so compatible AI hosts can use Scan Core without manually translating the CLI/state contract. The base package remains dependency-free; MCP is an optional extra.
After v0.4.0 is published to PyPI:
python -m pip install "scan-skill[mcp]==0.4.0"
scan-mcp doctor /path/to/project
scan-mcp /path/to/project
From an exact source checkout:
python -m pip install -e ".[mcp]"
scan-mcp doctor /path/to/project
scan-mcp /path/to/project
scan-mcp config can generate host-ready launch configuration using the absolute Python interpreter and project path, which avoids relying on shell activation or a full host PATH. The generator supports the documented Codex, Claude Desktop, Claude Code, Cursor and VS Code host shapes and does not modify host configuration automatically.
The MCP server uses local stdio by default and exposes a snapshot summary, explicit refresh, paginated inventory, canonical Scan state, bounded redacted artifact reads, a trust-boundary resource and an evidence-discipline review prompt. Each coverage mode keeps one in-memory server snapshot so inventory pages and reads stay consistent; scan_refresh rebuilds it when current bytes are needed. The project root is fixed at server startup; tool calls cannot broaden it. Artifact text reads reject traversal and unsafe link/reparse paths, verify bytes against the cached snapshot digest, enforce byte ceilings, block configured sensitive paths and apply Scan redaction before returning text. A changed file returns stale until the snapshot is refreshed.
The MCP application also exposes bounded semantic continuation tied to that snapshot. An agent can add evidence-linked semantic records in a separate in-memory workspace, validate canonical Scan 1.4 state, and render a self-contained report without modifying the inspected project. Evidence is bound to current artifact bytes, invalid mutations roll back, stale snapshots block further semantic writes, and static semantic work cannot be upgraded into observed/runtime claims without separate runtime evidence.
The Scan MCP process performs no network egress and does not execute target code or write .scan output into the target. The connected MCP host/model is a separate trust boundary and may transmit tool results according to its own architecture and policy. A deep MCP-backed review is still semantic work performed by the agent; the deterministic Core does not turn unassessed checks into passes.
See the v0.4 MCP foundation contract for the exact scope and non-goals.
Install as an agent skill
Scan also remains an instruction-based agent skill. Copy or clone this repository into the skill directory used by your compatible agent, then ask the agent to inspect a target.
For environments that discover user skills in ~/.agents/skills/:
mkdir -p ~/.agents/skills
git clone https://github.com/legendteddy/scan.git ~/.agents/skills/scan
On Windows PowerShell:
New-Item -ItemType Directory -Force "$HOME\.agents\skills" | Out-Null
git clone https://github.com/legendteddy/scan.git "$HOME\.agents\skills\scan"
Skill locations, invocation and tool access vary by agent. Consult your host's skill documentation; copying a folder alone does not guarantee the host will load it.
Example requests to a compatible agent:
Scan this entire repository and show what you could not verify.
Inspect this project and produce an evidence-backed HTML report.
Use $scan to map this package's architecture, risks and unknowns.
The governing instructions are in SKILL.md. Scan asks for explicit authorization before running untrusted target code or modifying the inspected target.
What the example shows
The fictional Pocket Ledger CSV totaler has five source files. Its worked report includes a source-linked concern about floating-point amounts, a missing malformed-input test gap, 14 accounted-for check categories, and explicit unanswered questions.
The report's static analysis of the five fixture files is complete within that narrow scope, but its broader checks are not complete. That distinction is the point of the demonstration.
To regenerate the sample after editing the fixture, update the snapshot time and evidence anchors in scripts/build_demo_report.py, then run:
python scripts/build_demo_report.py
python scripts/validate_report.py examples/demo-report.html
Optional visual QA and screenshot refresh: python scripts/capture_preview.py (requires Playwright and Chromium; not needed for Scan or CI).
Repository map
SKILL.md Agent instructions and safety boundaries
pyproject.toml Scan Core package metadata and `scan` / `scan-mcp` entry points
src/scan_core/ Deterministic Scan Core package
src/scan_core/baseline.py Local-only bounded baseline resolver
src/scan_core/compare.py Pure deterministic 1.3/1.4 state comparison
src/scan_core/git_change.py Local-only advisory Git changed-scope integration
src/scan_core/reuse.py Strict evidence freshness/reuse decision engine
src/scan_core/render.py Validated canonical-state HTML renderer
src/scan_core/scanbench.py ScanBench v1 deterministic harness
src/scan_core/mcp_server.py Optional read-only local MCP bridge
src/scan_core/settings.py `.scan/config.toml` loader and precedence defaults
src/scan_core/schemas/ Bundled structural schemas 1.2, 1.3 and 1.4
src/scan_core/report/shell.html Packaged self-contained report shell
scanbench/fixtures/ 12 mandatory adversarial/ground-truth v1 fixtures
tests/ Packaged core/contract regression tests
agents/openai.yaml Skill metadata
assets/report-shell.html Self-contained HTML dashboard template
assets/report-components.html Report component patterns
assets/demo-preview.png Screenshot of the synthetic worked report
assets/social-preview.png Upload-ready GitHub social image (1280 × 640)
references/ Inspection lenses, coverage and schema contracts
scripts/validate_report.py Backward-compatible Scan 1.2 validator wrapper
scripts/test_validate_report.py Frozen 1.2 validator regression tests
scripts/build_demo_report.py Reproducible synthetic example generator
examples/demo-project/ Fictional five-file project
examples/demo-report.html Validated, self-contained Scan 1.2 example
launch/launch-kit.md Draft launch copy and approval checklist
docs/v0.2-technical-spec.md Approved standalone Scan Core + CLI contract
docs/v0.2-compatibility.md Python/schema/config/ScanBench compatibility boundary
docs/v0.3-technical-spec.md Approved repeat-scan baseline/diff contract
docs/v0.4-mcp-foundation.md Read-only MCP bridge contract
Contribute and report security issues
Contributions that strengthen evidence discipline, safety, inspection depth, portability, accessibility or validator correctness are welcome. Read CONTRIBUTING.md and SECURITY.md.
MIT licensed — see LICENSE.
Metadata
Release files for scan-skill 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| scan_skill-0.4.0.tar.gz | 154.8 kB | With provenance | Details for scan_skill-0.4.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| scan_skill-0.4.0-py3-none-any.whl | Python 3 | none | any | Details for scan_skill-0.4.0-py3-none-any.whl |
Total release size: 292.1 kB
Release files / scan_skill-0.4.0.tar.gz
| Download URL | scan_skill-0.4.0.tar.gz |
|---|---|
| Size | 154.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
67cb7c34e4bafce400e770076fe238d0daeacd9ddbc27661646b845896b845bf
|
|
BLAKE2b-256 checksum How to use checksums |
9d83229b8a2b84a979e57a76b4101346af55aaa5f19209e78f2d774d01d48ee8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.
Transparency logRelease files / scan_skill-0.4.0-py3-none-any.whl
| Download URL | scan_skill-0.4.0-py3-none-any.whl |
|---|---|
| Size | 137.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2bd32da331dd392214cb63bcb67c019c0fd9dea8bc9ca8063dbe8cabd1a02ac6
|
|
BLAKE2b-256 checksum How to use checksums |
2e8c1ee61a4123b5cae2a50779a5db3e71efd04a9e288441a679062d50795d44
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.
Transparency logSecurity for scan-skill 0.4.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for scan_skill-0.4.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.