scan-skill 0.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. scan_skill-0.3.1/LICENSE +21 -0
  2. scan_skill-0.3.1/PKG-INFO +286 -0
  3. scan_skill-0.3.1/README.md +267 -0
  4. scan_skill-0.3.1/pyproject.toml +47 -0
  5. scan_skill-0.3.1/scanbench/README.md +11 -0
  6. scan_skill-0.3.1/scanbench/__init__.py +1 -0
  7. scan_skill-0.3.1/scanbench/fixtures/__init__.py +1 -0
  8. scan_skill-0.3.1/scanbench/fixtures/archive-boundary/README.md +5 -0
  9. scan_skill-0.3.1/scanbench/fixtures/archive-boundary/expected.json +30 -0
  10. scan_skill-0.3.1/scanbench/fixtures/archive-boundary/fixture.json +8 -0
  11. scan_skill-0.3.1/scanbench/fixtures/archive-boundary/project/README.txt +1 -0
  12. scan_skill-0.3.1/scanbench/fixtures/archive-boundary/project/bundle.zip +0 -0
  13. scan_skill-0.3.1/scanbench/fixtures/clean-minimal/README.md +5 -0
  14. scan_skill-0.3.1/scanbench/fixtures/clean-minimal/expected.json +39 -0
  15. scan_skill-0.3.1/scanbench/fixtures/clean-minimal/fixture.json +6 -0
  16. scan_skill-0.3.1/scanbench/fixtures/clean-minimal/project/app.txt +1 -0
  17. scan_skill-0.3.1/scanbench/fixtures/false-runtime-claim/README.md +5 -0
  18. scan_skill-0.3.1/scanbench/fixtures/false-runtime-claim/expected.json +34 -0
  19. scan_skill-0.3.1/scanbench/fixtures/false-runtime-claim/fixture.json +6 -0
  20. scan_skill-0.3.1/scanbench/fixtures/false-runtime-claim/project/status.txt +1 -0
  21. scan_skill-0.3.1/scanbench/fixtures/false-runtime-claim/project/test_example.py +2 -0
  22. scan_skill-0.3.1/scanbench/fixtures/generated-and-vendor/README.md +5 -0
  23. scan_skill-0.3.1/scanbench/fixtures/generated-and-vendor/expected.json +24 -0
  24. scan_skill-0.3.1/scanbench/fixtures/generated-and-vendor/fixture.json +6 -0
  25. scan_skill-0.3.1/scanbench/fixtures/generated-and-vendor/project/dist/app.js +1 -0
  26. scan_skill-0.3.1/scanbench/fixtures/generated-and-vendor/project/src/main.js +1 -0
  27. scan_skill-0.3.1/scanbench/fixtures/generated-and-vendor/project/vendor/lib.js +1 -0
  28. scan_skill-0.3.1/scanbench/fixtures/hidden-files/README.md +5 -0
  29. scan_skill-0.3.1/scanbench/fixtures/hidden-files/expected.json +19 -0
  30. scan_skill-0.3.1/scanbench/fixtures/hidden-files/fixture.json +6 -0
  31. scan_skill-0.3.1/scanbench/fixtures/hidden-files/project/.hidden.txt +1 -0
  32. scan_skill-0.3.1/scanbench/fixtures/hidden-files/project/visible.txt +1 -0
  33. scan_skill-0.3.1/scanbench/fixtures/incomplete-discovery/README.md +5 -0
  34. scan_skill-0.3.1/scanbench/fixtures/incomplete-discovery/expected.json +29 -0
  35. scan_skill-0.3.1/scanbench/fixtures/incomplete-discovery/fixture.json +8 -0
  36. scan_skill-0.3.1/scanbench/fixtures/incomplete-discovery/project/a.txt +1 -0
  37. scan_skill-0.3.1/scanbench/fixtures/incomplete-discovery/project/b.txt +1 -0
  38. scan_skill-0.3.1/scanbench/fixtures/inventory-basic/expected.json +3 -0
  39. scan_skill-0.3.1/scanbench/fixtures/malformed-filename/README.md +5 -0
  40. scan_skill-0.3.1/scanbench/fixtures/malformed-filename/expected.json +24 -0
  41. scan_skill-0.3.1/scanbench/fixtures/malformed-filename/fixture.json +6 -0
  42. scan_skill-0.3.1/scanbench/fixtures/malformed-filename/project/-rf.txt +1 -0
  43. scan_skill-0.3.1/scanbench/fixtures/malformed-filename/project/space name.txt +1 -0
  44. scan_skill-0.3.1/scanbench/fixtures/malformed-filename/project/unicode-/316/273.txt +1 -0
  45. scan_skill-0.3.1/scanbench/fixtures/prompt-injection/README.md +5 -0
  46. scan_skill-0.3.1/scanbench/fixtures/prompt-injection/expected.json +28 -0
  47. scan_skill-0.3.1/scanbench/fixtures/prompt-injection/fixture.json +8 -0
  48. scan_skill-0.3.1/scanbench/fixtures/prompt-injection/project/instructions.txt +1 -0
  49. scan_skill-0.3.1/scanbench/fixtures/secret-redaction/README.md +5 -0
  50. scan_skill-0.3.1/scanbench/fixtures/secret-redaction/expected.json +29 -0
  51. scan_skill-0.3.1/scanbench/fixtures/secret-redaction/fixture.json +9 -0
  52. scan_skill-0.3.1/scanbench/fixtures/secret-redaction/project/public.txt +1 -0
  53. scan_skill-0.3.1/scanbench/fixtures/secret-redaction/project/secrets.env +1 -0
  54. scan_skill-0.3.1/scanbench/fixtures/symlink-escape/README.md +5 -0
  55. scan_skill-0.3.1/scanbench/fixtures/symlink-escape/expected.json +31 -0
  56. scan_skill-0.3.1/scanbench/fixtures/symlink-escape/fixture.json +13 -0
  57. scan_skill-0.3.1/scanbench/fixtures/symlink-escape/project/inside.txt +1 -0
  58. scan_skill-0.3.1/scanbench/fixtures/unreadable-artifact/README.md +5 -0
  59. scan_skill-0.3.1/scanbench/fixtures/unreadable-artifact/expected.json +30 -0
  60. scan_skill-0.3.1/scanbench/fixtures/unreadable-artifact/fixture.json +8 -0
  61. scan_skill-0.3.1/scanbench/fixtures/unreadable-artifact/project/locked.txt +1 -0
  62. scan_skill-0.3.1/scanbench/fixtures/unreadable-artifact/project/readable.txt +1 -0
  63. scan_skill-0.3.1/scanbench/fixtures/unsupported-binary/README.md +5 -0
  64. scan_skill-0.3.1/scanbench/fixtures/unsupported-binary/expected.json +26 -0
  65. scan_skill-0.3.1/scanbench/fixtures/unsupported-binary/fixture.json +6 -0
  66. scan_skill-0.3.1/scanbench/fixtures/unsupported-binary/project/blob.bin +0 -0
  67. scan_skill-0.3.1/scanbench/fixtures/unsupported-binary/project/note.txt +1 -0
  68. scan_skill-0.3.1/scanbench/manifest.json +24 -0
  69. scan_skill-0.3.1/setup.cfg +4 -0
  70. scan_skill-0.3.1/src/scan_core/__init__.py +101 -0
  71. scan_skill-0.3.1/src/scan_core/__main__.py +7 -0
  72. scan_skill-0.3.1/src/scan_core/auxiliary.py +139 -0
  73. scan_skill-0.3.1/src/scan_core/baseline.py +88 -0
  74. scan_skill-0.3.1/src/scan_core/builder.py +538 -0
  75. scan_skill-0.3.1/src/scan_core/cli.py +342 -0
  76. scan_skill-0.3.1/src/scan_core/compare.py +176 -0
  77. scan_skill-0.3.1/src/scan_core/config.py +101 -0
  78. scan_skill-0.3.1/src/scan_core/core.py +293 -0
  79. scan_skill-0.3.1/src/scan_core/doctor.py +223 -0
  80. scan_skill-0.3.1/src/scan_core/errors.py +52 -0
  81. scan_skill-0.3.1/src/scan_core/git_change.py +214 -0
  82. scan_skill-0.3.1/src/scan_core/git_provenance.py +213 -0
  83. scan_skill-0.3.1/src/scan_core/ids.py +43 -0
  84. scan_skill-0.3.1/src/scan_core/inventory.py +305 -0
  85. scan_skill-0.3.1/src/scan_core/privacy.py +391 -0
  86. scan_skill-0.3.1/src/scan_core/render.py +368 -0
  87. scan_skill-0.3.1/src/scan_core/report/__init__.py +1 -0
  88. scan_skill-0.3.1/src/scan_core/report/shell.html +142 -0
  89. scan_skill-0.3.1/src/scan_core/reuse.py +214 -0
  90. scan_skill-0.3.1/src/scan_core/scanbench.py +473 -0
  91. scan_skill-0.3.1/src/scan_core/schema.py +31 -0
  92. scan_skill-0.3.1/src/scan_core/schemas/__init__.py +1 -0
  93. scan_skill-0.3.1/src/scan_core/schemas/scan-state-1.2.schema.json +26 -0
  94. scan_skill-0.3.1/src/scan_core/schemas/scan-state-1.3.schema.json +29 -0
  95. scan_skill-0.3.1/src/scan_core/schemas/scan-state-1.4.schema.json +58 -0
  96. scan_skill-0.3.1/src/scan_core/settings.py +133 -0
  97. scan_skill-0.3.1/src/scan_core/snapshot.py +48 -0
  98. scan_skill-0.3.1/src/scan_core/state.py +477 -0
  99. scan_skill-0.3.1/src/scan_core/validate.py +847 -0
  100. scan_skill-0.3.1/src/scan_core/version.py +3 -0
  101. scan_skill-0.3.1/src/scan_skill.egg-info/PKG-INFO +286 -0
  102. scan_skill-0.3.1/src/scan_skill.egg-info/SOURCES.txt +118 -0
  103. scan_skill-0.3.1/src/scan_skill.egg-info/dependency_links.txt +1 -0
  104. scan_skill-0.3.1/src/scan_skill.egg-info/entry_points.txt +2 -0
  105. scan_skill-0.3.1/src/scan_skill.egg-info/top_level.txt +2 -0
  106. scan_skill-0.3.1/tests/test_open_issues.py +265 -0
  107. scan_skill-0.3.1/tests/test_report_ux.py +228 -0
  108. scan_skill-0.3.1/tests/test_self_review_defects.py +593 -0
  109. scan_skill-0.3.1/tests/test_slice1.py +88 -0
  110. scan_skill-0.3.1/tests/test_slice2.py +170 -0
  111. scan_skill-0.3.1/tests/test_slice3.py +197 -0
  112. scan_skill-0.3.1/tests/test_slice4.py +234 -0
  113. scan_skill-0.3.1/tests/test_slice5.py +235 -0
  114. scan_skill-0.3.1/tests/test_slice6.py +255 -0
  115. scan_skill-0.3.1/tests/test_v03_slice1.py +266 -0
  116. scan_skill-0.3.1/tests/test_v03_slice2.py +249 -0
  117. scan_skill-0.3.1/tests/test_v03_slice3.py +412 -0
  118. scan_skill-0.3.1/tests/test_v03_slice4.py +244 -0
  119. scan_skill-0.3.1/tests/test_v03_slice5.py +126 -0
  120. scan_skill-0.3.1/tests/test_v03_slice6.py +77 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 legendteddy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,286 @@
1
+ Metadata-Version: 2.4
2
+ Name: scan-skill
3
+ Version: 0.3.1
4
+ Summary: Evidence-backed whole-project inspection core and agent skill
5
+ Author: legendteddy
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/legendteddy/scan
8
+ Project-URL: Repository, https://github.com/legendteddy/scan
9
+ Project-URL: Issues, https://github.com/legendteddy/scan/issues
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Requires-Python: >=3.11
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Dynamic: license-file
19
+
20
+ # Scan
21
+
22
+ [![Validate](https://github.com/legendteddy/scan/actions/workflows/validate.yml/badge.svg)](https://github.com/legendteddy/scan/actions/workflows/validate.yml)
23
+ [![License: MIT](https://img.shields.io/badge/license-MIT-5865f2.svg)](LICENSE)
24
+
25
+ **Know what an AI agent actually inspected.**
26
+
27
+ 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.
28
+
29
+ **Coverage ≠ confidence.** Finding a file, reading it, assessing a check, and verifying runtime behavior are different things. Scan makes those differences visible.
30
+
31
+ ## Start here: run Scan locally
32
+
33
+ Install from a source checkout when you want the command and bundled evidence assets from the exact repository state you reviewed:
34
+
35
+ ```bash
36
+ git clone https://github.com/legendteddy/scan.git
37
+ cd scan
38
+ python -m pip install .
39
+ scan doctor .
40
+ scan . --offline
41
+ ```
42
+
43
+ Change the project, then run the same scan again:
44
+
45
+ ```bash
46
+ scan . --offline
47
+ ```
48
+
49
+ 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.
50
+
51
+ For published builds, package-index availability depends on the release channel. If `scan-skill` is available in your configured Python package index, you can install the packaged CLI with `python -m pip install scan-skill`, `pipx install scan-skill`, or `uv tool install scan-skill`.
52
+
53
+ ## What makes Scan different?
54
+
55
+ - **Inventory before verdict:** account for discoverable files, including unreadable, excluded, metadata-only and partially inspected items.
56
+ - **Two kinds of coverage:** track artifact discovery/analysis separately from checks assessed, partial, blocked or not performed.
57
+ - **Receipts for claims:** findings, controls, relationships and architecture map back to evidence IDs and precise source locators.
58
+ - **Static-first boundaries:** target files and embedded instructions are untrusted; no executing unknown target code or silent fixes without authorization.
59
+ - **Honest uncertainty:** static source observations are not presented as runtime proof, a vulnerability clearance or a release certification.
60
+ - **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**).
61
+
62
+ 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.
63
+
64
+ For the concrete false-confidence failure mode Scan is designed to prevent, read [Why Scan exists](docs/why-scan.md).
65
+
66
+ ## Standalone core
67
+
68
+ 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.
69
+
70
+ ```bash
71
+ python -m pip install .
72
+ scan doctor .
73
+ scan . --offline
74
+ # Change the project, then scan again. The prior .scan/state.json is used locally as the baseline.
75
+ scan . --offline
76
+ # Optional local-only Git prioritization context; full Scan inventory still runs.
77
+ scan . --offline --changed-since origin/main
78
+ scan validate .scan/state.json
79
+ scan validate .scan/report.html
80
+ scan compare previous-state.json .scan/state.json --json
81
+ scan render .scan/state.json --output .scan/rerendered.html
82
+ scan schema --version 1.4
83
+ scan egress . --privacy controlled-remote --redact strict --json
84
+ scan bench
85
+ ```
86
+
87
+ 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.
88
+
89
+ ### Scan modes
90
+
91
+ Scan exposes explicit coverage promises instead of silently sampling:
92
+
93
+ - `--mode quick` is 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 to `deep`.
94
+ - `--mode deep` is 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.
95
+ - `--mode forensic` opts repository internals back in for provenance-heavy or historical investigation. Explicit user exclusions and normal safety/resource boundaries still apply.
96
+
97
+ 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.
98
+
99
+ ```bash
100
+ scan . --offline --mode quick
101
+ scan . --offline --mode deep
102
+ scan . --offline --mode forensic
103
+ ```
104
+
105
+ ### Project configuration
106
+
107
+ Optional configuration lives at `.scan/config.toml`. Precedence is **CLI arguments > project config > built-in defaults**.
108
+
109
+ ```toml
110
+ [scan]
111
+ privacy = "offline"
112
+ redact = "standard"
113
+ mode = "deep"
114
+ max_file_bytes = 5000000
115
+ max_total_bytes = 250000000
116
+ follow_internal_links = false
117
+
118
+ [exclude]
119
+ patterns = ["vendor/**"]
120
+
121
+ [baseline]
122
+ mode = "auto" # auto | none
123
+ reuse = true
124
+ max_state_bytes = 64000000
125
+ ```
126
+
127
+ 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.
128
+
129
+ See [explicit semantic continuation](references/semantic-continuation.md) for current producer/check registration and bounded worktree metadata authorization. Baselines never authorize their own semantic producers.
130
+
131
+ ### Semantic builder API
132
+
133
+ 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()`.
134
+
135
+ ```python
136
+ from scan_core import SemanticStateBuilder
137
+
138
+ builder = SemanticStateBuilder.from_state(core_state)
139
+ evidence_id = builder.add_evidence(
140
+ artifact_id=artifact["id"],
141
+ locator=artifact["locator"],
142
+ kind="static",
143
+ claim="Configuration path was reviewed",
144
+ result="The path is resolved locally",
145
+ method="semantic source review",
146
+ limitations="Runtime behavior was not observed",
147
+ source_digest=artifact["content_identity"],
148
+ producer_kind="local-model",
149
+ producer_name="review-agent",
150
+ producer_version="1",
151
+ )
152
+ builder.add_finding(
153
+ title="Example finding",
154
+ impact="Explain the user-visible consequence",
155
+ severity="medium",
156
+ confidence="high",
157
+ verification_state="static",
158
+ artifact_ids=artifact["id"],
159
+ evidence_ids=evidence_id,
160
+ uncertainty="Runtime behavior remains unverified",
161
+ recommendation="Address the evidenced condition",
162
+ safe_verification="Re-read the affected source and validate the state",
163
+ )
164
+ semantic_state = builder.build()
165
+ ```
166
+
167
+ `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.
168
+
169
+ ### Evidence freshness and safe reuse
170
+
171
+ 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 in v0.3.
172
+
173
+ 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.
174
+
175
+ ### ScanBench v1
176
+
177
+ `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.
178
+
179
+ 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.
180
+
181
+ ![Screenshot of the synthetic Pocket Ledger Scan report, showing coverage and explicit unknowns](assets/demo-preview.png)
182
+
183
+ [Explore the synthetic fixture](examples/demo-project/README.md) · [Download the example HTML report](examples/demo-report.html) · [Read the report contract](references/report-contract.md)
184
+
185
+ > **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.
186
+
187
+ ## Historical synthetic proof
188
+
189
+ 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.
190
+
191
+ ```bash
192
+ git clone https://github.com/legendteddy/scan.git
193
+ cd scan
194
+ python scripts/validate_report.py examples/demo-report.html
195
+ python scripts/build_demo_report.py --check
196
+ python -m unittest discover -s scripts -p "test_*.py" -v
197
+ ```
198
+
199
+ 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.
200
+
201
+ 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**.
202
+
203
+ ## Install as an agent skill
204
+
205
+ 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.
206
+
207
+ For environments that discover user skills in `~/.agents/skills/`:
208
+
209
+ ```bash
210
+ mkdir -p ~/.agents/skills
211
+ git clone https://github.com/legendteddy/scan.git ~/.agents/skills/scan
212
+ ```
213
+
214
+ On Windows PowerShell:
215
+
216
+ ```powershell
217
+ New-Item -ItemType Directory -Force "$HOME\.agents\skills" | Out-Null
218
+ git clone https://github.com/legendteddy/scan.git "$HOME\.agents\skills\scan"
219
+ ```
220
+
221
+ 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.
222
+
223
+ Example requests to a compatible agent:
224
+
225
+ ```text
226
+ Scan this entire repository and show what you could not verify.
227
+ Inspect this project and produce an evidence-backed HTML report.
228
+ Use $scan to map this package's architecture, risks and unknowns.
229
+ ```
230
+
231
+ The governing instructions are in [SKILL.md](SKILL.md). Scan asks for explicit authorization before running untrusted target code or modifying the inspected target.
232
+
233
+ ## What the example shows
234
+
235
+ 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.
236
+
237
+ 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.
238
+
239
+ To regenerate the sample after editing the fixture, update the snapshot time and evidence anchors in `scripts/build_demo_report.py`, then run:
240
+
241
+ ```bash
242
+ python scripts/build_demo_report.py
243
+ python scripts/validate_report.py examples/demo-report.html
244
+ ```
245
+
246
+ Optional visual QA and screenshot refresh: `python scripts/capture_preview.py` (requires Playwright and Chromium; not needed for Scan or CI).
247
+
248
+ ## Repository map
249
+
250
+ ```text
251
+ SKILL.md Agent instructions and safety boundaries
252
+ pyproject.toml Scan Core package metadata and `scan` entry point
253
+ src/scan_core/ v0.3 deterministic core package
254
+ src/scan_core/baseline.py Local-only bounded baseline resolver
255
+ src/scan_core/compare.py Pure deterministic 1.3/1.4 state comparison
256
+ src/scan_core/git_change.py Local-only advisory Git changed-scope integration
257
+ src/scan_core/reuse.py Strict evidence freshness/reuse decision engine
258
+ src/scan_core/render.py Validated canonical-state HTML renderer
259
+ src/scan_core/scanbench.py ScanBench v1 deterministic harness
260
+ src/scan_core/settings.py `.scan/config.toml` loader and precedence defaults
261
+ src/scan_core/schemas/ Bundled structural schemas 1.2, 1.3 and 1.4
262
+ src/scan_core/report/shell.html Packaged self-contained report shell
263
+ scanbench/fixtures/ 12 mandatory adversarial/ground-truth v1 fixtures
264
+ tests/ Packaged core/contract regression tests
265
+ agents/openai.yaml Skill metadata
266
+ assets/report-shell.html Self-contained HTML dashboard template
267
+ assets/report-components.html Report component patterns
268
+ assets/demo-preview.png Screenshot of the synthetic worked report
269
+ assets/social-preview.png Upload-ready GitHub social image (1280 × 640)
270
+ references/ Inspection lenses, coverage and schema contracts
271
+ scripts/validate_report.py Backward-compatible Scan 1.2 validator wrapper
272
+ scripts/test_validate_report.py Frozen 1.2 validator regression tests
273
+ scripts/build_demo_report.py Reproducible synthetic example generator
274
+ examples/demo-project/ Fictional five-file project
275
+ examples/demo-report.html Validated, self-contained Scan 1.2 example
276
+ launch/launch-kit.md Draft launch copy and approval checklist
277
+ docs/v0.2-technical-spec.md Approved standalone Scan Core + CLI contract
278
+ docs/v0.2-compatibility.md Python/schema/config/ScanBench compatibility boundary
279
+ docs/v0.3-technical-spec.md Approved repeat-scan baseline/diff contract
280
+ ```
281
+
282
+ ## Contribute and report security issues
283
+
284
+ Contributions that strengthen evidence discipline, safety, inspection depth, portability, accessibility or validator correctness are welcome. Read [CONTRIBUTING.md](CONTRIBUTING.md) and [SECURITY.md](SECURITY.md).
285
+
286
+ MIT licensed — see [LICENSE](LICENSE).
@@ -0,0 +1,267 @@
1
+ # Scan
2
+
3
+ [![Validate](https://github.com/legendteddy/scan/actions/workflows/validate.yml/badge.svg)](https://github.com/legendteddy/scan/actions/workflows/validate.yml)
4
+ [![License: MIT](https://img.shields.io/badge/license-MIT-5865f2.svg)](LICENSE)
5
+
6
+ **Know what an AI agent actually inspected.**
7
+
8
+ 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.
9
+
10
+ **Coverage ≠ confidence.** Finding a file, reading it, assessing a check, and verifying runtime behavior are different things. Scan makes those differences visible.
11
+
12
+ ## Start here: run Scan locally
13
+
14
+ Install from a source checkout when you want the command and bundled evidence assets from the exact repository state you reviewed:
15
+
16
+ ```bash
17
+ git clone https://github.com/legendteddy/scan.git
18
+ cd scan
19
+ python -m pip install .
20
+ scan doctor .
21
+ scan . --offline
22
+ ```
23
+
24
+ Change the project, then run the same scan again:
25
+
26
+ ```bash
27
+ scan . --offline
28
+ ```
29
+
30
+ 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.
31
+
32
+ For published builds, package-index availability depends on the release channel. If `scan-skill` is available in your configured Python package index, you can install the packaged CLI with `python -m pip install scan-skill`, `pipx install scan-skill`, or `uv tool install scan-skill`.
33
+
34
+ ## What makes Scan different?
35
+
36
+ - **Inventory before verdict:** account for discoverable files, including unreadable, excluded, metadata-only and partially inspected items.
37
+ - **Two kinds of coverage:** track artifact discovery/analysis separately from checks assessed, partial, blocked or not performed.
38
+ - **Receipts for claims:** findings, controls, relationships and architecture map back to evidence IDs and precise source locators.
39
+ - **Static-first boundaries:** target files and embedded instructions are untrusted; no executing unknown target code or silent fixes without authorization.
40
+ - **Honest uncertainty:** static source observations are not presented as runtime proof, a vulnerability clearance or a release certification.
41
+ - **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**).
42
+
43
+ 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.
44
+
45
+ For the concrete false-confidence failure mode Scan is designed to prevent, read [Why Scan exists](docs/why-scan.md).
46
+
47
+ ## Standalone core
48
+
49
+ 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.
50
+
51
+ ```bash
52
+ python -m pip install .
53
+ scan doctor .
54
+ scan . --offline
55
+ # Change the project, then scan again. The prior .scan/state.json is used locally as the baseline.
56
+ scan . --offline
57
+ # Optional local-only Git prioritization context; full Scan inventory still runs.
58
+ scan . --offline --changed-since origin/main
59
+ scan validate .scan/state.json
60
+ scan validate .scan/report.html
61
+ scan compare previous-state.json .scan/state.json --json
62
+ scan render .scan/state.json --output .scan/rerendered.html
63
+ scan schema --version 1.4
64
+ scan egress . --privacy controlled-remote --redact strict --json
65
+ scan bench
66
+ ```
67
+
68
+ 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.
69
+
70
+ ### Scan modes
71
+
72
+ Scan exposes explicit coverage promises instead of silently sampling:
73
+
74
+ - `--mode quick` is 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 to `deep`.
75
+ - `--mode deep` is 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.
76
+ - `--mode forensic` opts repository internals back in for provenance-heavy or historical investigation. Explicit user exclusions and normal safety/resource boundaries still apply.
77
+
78
+ 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.
79
+
80
+ ```bash
81
+ scan . --offline --mode quick
82
+ scan . --offline --mode deep
83
+ scan . --offline --mode forensic
84
+ ```
85
+
86
+ ### Project configuration
87
+
88
+ Optional configuration lives at `.scan/config.toml`. Precedence is **CLI arguments > project config > built-in defaults**.
89
+
90
+ ```toml
91
+ [scan]
92
+ privacy = "offline"
93
+ redact = "standard"
94
+ mode = "deep"
95
+ max_file_bytes = 5000000
96
+ max_total_bytes = 250000000
97
+ follow_internal_links = false
98
+
99
+ [exclude]
100
+ patterns = ["vendor/**"]
101
+
102
+ [baseline]
103
+ mode = "auto" # auto | none
104
+ reuse = true
105
+ max_state_bytes = 64000000
106
+ ```
107
+
108
+ 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.
109
+
110
+ See [explicit semantic continuation](references/semantic-continuation.md) for current producer/check registration and bounded worktree metadata authorization. Baselines never authorize their own semantic producers.
111
+
112
+ ### Semantic builder API
113
+
114
+ 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()`.
115
+
116
+ ```python
117
+ from scan_core import SemanticStateBuilder
118
+
119
+ builder = SemanticStateBuilder.from_state(core_state)
120
+ evidence_id = builder.add_evidence(
121
+ artifact_id=artifact["id"],
122
+ locator=artifact["locator"],
123
+ kind="static",
124
+ claim="Configuration path was reviewed",
125
+ result="The path is resolved locally",
126
+ method="semantic source review",
127
+ limitations="Runtime behavior was not observed",
128
+ source_digest=artifact["content_identity"],
129
+ producer_kind="local-model",
130
+ producer_name="review-agent",
131
+ producer_version="1",
132
+ )
133
+ builder.add_finding(
134
+ title="Example finding",
135
+ impact="Explain the user-visible consequence",
136
+ severity="medium",
137
+ confidence="high",
138
+ verification_state="static",
139
+ artifact_ids=artifact["id"],
140
+ evidence_ids=evidence_id,
141
+ uncertainty="Runtime behavior remains unverified",
142
+ recommendation="Address the evidenced condition",
143
+ safe_verification="Re-read the affected source and validate the state",
144
+ )
145
+ semantic_state = builder.build()
146
+ ```
147
+
148
+ `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.
149
+
150
+ ### Evidence freshness and safe reuse
151
+
152
+ 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 in v0.3.
153
+
154
+ 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.
155
+
156
+ ### ScanBench v1
157
+
158
+ `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.
159
+
160
+ 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.
161
+
162
+ ![Screenshot of the synthetic Pocket Ledger Scan report, showing coverage and explicit unknowns](assets/demo-preview.png)
163
+
164
+ [Explore the synthetic fixture](examples/demo-project/README.md) · [Download the example HTML report](examples/demo-report.html) · [Read the report contract](references/report-contract.md)
165
+
166
+ > **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.
167
+
168
+ ## Historical synthetic proof
169
+
170
+ 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.
171
+
172
+ ```bash
173
+ git clone https://github.com/legendteddy/scan.git
174
+ cd scan
175
+ python scripts/validate_report.py examples/demo-report.html
176
+ python scripts/build_demo_report.py --check
177
+ python -m unittest discover -s scripts -p "test_*.py" -v
178
+ ```
179
+
180
+ 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.
181
+
182
+ 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**.
183
+
184
+ ## Install as an agent skill
185
+
186
+ 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.
187
+
188
+ For environments that discover user skills in `~/.agents/skills/`:
189
+
190
+ ```bash
191
+ mkdir -p ~/.agents/skills
192
+ git clone https://github.com/legendteddy/scan.git ~/.agents/skills/scan
193
+ ```
194
+
195
+ On Windows PowerShell:
196
+
197
+ ```powershell
198
+ New-Item -ItemType Directory -Force "$HOME\.agents\skills" | Out-Null
199
+ git clone https://github.com/legendteddy/scan.git "$HOME\.agents\skills\scan"
200
+ ```
201
+
202
+ 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.
203
+
204
+ Example requests to a compatible agent:
205
+
206
+ ```text
207
+ Scan this entire repository and show what you could not verify.
208
+ Inspect this project and produce an evidence-backed HTML report.
209
+ Use $scan to map this package's architecture, risks and unknowns.
210
+ ```
211
+
212
+ The governing instructions are in [SKILL.md](SKILL.md). Scan asks for explicit authorization before running untrusted target code or modifying the inspected target.
213
+
214
+ ## What the example shows
215
+
216
+ 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.
217
+
218
+ 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.
219
+
220
+ To regenerate the sample after editing the fixture, update the snapshot time and evidence anchors in `scripts/build_demo_report.py`, then run:
221
+
222
+ ```bash
223
+ python scripts/build_demo_report.py
224
+ python scripts/validate_report.py examples/demo-report.html
225
+ ```
226
+
227
+ Optional visual QA and screenshot refresh: `python scripts/capture_preview.py` (requires Playwright and Chromium; not needed for Scan or CI).
228
+
229
+ ## Repository map
230
+
231
+ ```text
232
+ SKILL.md Agent instructions and safety boundaries
233
+ pyproject.toml Scan Core package metadata and `scan` entry point
234
+ src/scan_core/ v0.3 deterministic core package
235
+ src/scan_core/baseline.py Local-only bounded baseline resolver
236
+ src/scan_core/compare.py Pure deterministic 1.3/1.4 state comparison
237
+ src/scan_core/git_change.py Local-only advisory Git changed-scope integration
238
+ src/scan_core/reuse.py Strict evidence freshness/reuse decision engine
239
+ src/scan_core/render.py Validated canonical-state HTML renderer
240
+ src/scan_core/scanbench.py ScanBench v1 deterministic harness
241
+ src/scan_core/settings.py `.scan/config.toml` loader and precedence defaults
242
+ src/scan_core/schemas/ Bundled structural schemas 1.2, 1.3 and 1.4
243
+ src/scan_core/report/shell.html Packaged self-contained report shell
244
+ scanbench/fixtures/ 12 mandatory adversarial/ground-truth v1 fixtures
245
+ tests/ Packaged core/contract regression tests
246
+ agents/openai.yaml Skill metadata
247
+ assets/report-shell.html Self-contained HTML dashboard template
248
+ assets/report-components.html Report component patterns
249
+ assets/demo-preview.png Screenshot of the synthetic worked report
250
+ assets/social-preview.png Upload-ready GitHub social image (1280 × 640)
251
+ references/ Inspection lenses, coverage and schema contracts
252
+ scripts/validate_report.py Backward-compatible Scan 1.2 validator wrapper
253
+ scripts/test_validate_report.py Frozen 1.2 validator regression tests
254
+ scripts/build_demo_report.py Reproducible synthetic example generator
255
+ examples/demo-project/ Fictional five-file project
256
+ examples/demo-report.html Validated, self-contained Scan 1.2 example
257
+ launch/launch-kit.md Draft launch copy and approval checklist
258
+ docs/v0.2-technical-spec.md Approved standalone Scan Core + CLI contract
259
+ docs/v0.2-compatibility.md Python/schema/config/ScanBench compatibility boundary
260
+ docs/v0.3-technical-spec.md Approved repeat-scan baseline/diff contract
261
+ ```
262
+
263
+ ## Contribute and report security issues
264
+
265
+ Contributions that strengthen evidence discipline, safety, inspection depth, portability, accessibility or validator correctness are welcome. Read [CONTRIBUTING.md](CONTRIBUTING.md) and [SECURITY.md](SECURITY.md).
266
+
267
+ MIT licensed — see [LICENSE](LICENSE).
@@ -0,0 +1,47 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "scan-skill"
7
+ version = "0.3.1"
8
+ description = "Evidence-backed whole-project inspection core and agent skill"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{ name = "legendteddy" }]
14
+ dependencies = []
15
+ classifiers = [
16
+ "Development Status :: 3 - Alpha",
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3.11",
19
+ "Programming Language :: Python :: 3.12",
20
+ "Programming Language :: Python :: 3.13",
21
+ ]
22
+
23
+ [project.urls]
24
+ Homepage = "https://github.com/legendteddy/scan"
25
+ Repository = "https://github.com/legendteddy/scan"
26
+ Issues = "https://github.com/legendteddy/scan/issues"
27
+
28
+ [project.scripts]
29
+ scan = "scan_core.cli:main"
30
+
31
+ [tool.setuptools]
32
+ package-dir = {"" = "src", "scanbench_data" = "scanbench"}
33
+ packages = ["scan_core", "scan_core.report", "scan_core.schemas", "scanbench_data", "scanbench_data.fixtures"]
34
+
35
+ [tool.setuptools.package-data]
36
+ "scan_core.report" = ["*.html"]
37
+ "scan_core.schemas" = ["*.json"]
38
+ "scanbench_data" = [
39
+ "manifest.json",
40
+ "README.md",
41
+ "fixtures/*/fixture.json",
42
+ "fixtures/*/expected.json",
43
+ "fixtures/*/README.md",
44
+ "fixtures/*/project/*",
45
+ "fixtures/*/project/.*",
46
+ "fixtures/*/project/*/*",
47
+ ]
@@ -0,0 +1,11 @@
1
+ # ScanBench v1
2
+
3
+ ScanBench is Scan's deterministic release gate. It uses synthetic fixtures and objective assertions across five independent dimensions:
4
+
5
+ - inventory completeness
6
+ - state integrity
7
+ - evidence correctness
8
+ - privacy integrity
9
+ - safety-boundary compliance
10
+
11
+ There is no blended overall quality score. Run all fixtures with `scan bench` or one fixture with `scan bench FIXTURE`. Fixture source is untrusted data and is never executed.
@@ -0,0 +1 @@
1
+ """Packaged ScanBench v1 fixture data; not an executable target package."""
@@ -0,0 +1 @@
1
+ """Packaged ScanBench fixture data namespace."""
@@ -0,0 +1,5 @@
1
+ # archive-boundary
2
+
3
+ Archive bytes are inventoried as a file; members are not expanded or executed by the v0.2 core.
4
+
5
+ This fixture is synthetic and must be treated as inert data. Target code is never authorized to execute.