Skip to content
my-saas scan · 2 of 5 layers running
00:00:03.412
Illustration · planned interface This screen is a mockup of a graphical interface that does not exist yet. The shipped product is a command-line tool: one static binary that runs locally, with no account and no server. The project, the file counts and the log below are a worked example, not a real scan.
Scan in progress

Reading C:\dev\my-saas

Reading files. Not executing them, not installing anything, not calling anything. The scan is root-scoped and symlink-safe: a link pointing outside the project root is skipped and reported.

Files walked12,481
Elapsed3.4s / 60s budget
Read budget512 MiB total

The five detection layers

Each layer corresponds to one of the five places an obligation hides. A layer that finds nothing says so explicitly — "clean" and "not looked at" must never look the same.

01 Code licence Manifests, lockfiles, vendored LICENSE / COPYING / NOTICE, SPDX headers in source done · 47
02 Model weights Magic-byte detection, GGUF metadata, config.json, model-card frontmatter done · 3
03 Platform ToS Third-party CLI orchestration detected from source AST and config files running…
04 Brand assets Name, logo and icon files reserved outside the grant — forces a rebrand obligation queued
05 Territories Territorial clauses evaluated against your declared jurisdictions queued

Scan log

deterministic order · no map iteration
3.402SCANwalk complete · 12,481 files · 2 skipped
3.404WARNSkipped symlink 'docs/link' → '/etc/passwd' (outside project root).
3.405WARNcannot parse pnpm-lock.yaml: unsupported lockfile — falling back to package.json ranges (E-PARSE-001).
3.410L147 dependencies resolved
3.412L1licence trap: firecrawl · AGPL-3.0-only
3.418L23 weight files by magic bytes
3.421L2weights licence from model-card frontmatter: CC-BY-NC-4.0
3.424L2no licence statement for models/embed.bin
3.426L3scanning for upstream CLI orchestration…
——awaiting layer 3

What the scanner will not do

enforced by test
✓Never executes project code — no os/exec outside the CLI layer
✓Never runs a package manager — lockfiles only, nothing installed
✓Never reads a .env — its existence is recorded, its contents are not
✓Never follows a symlink out of the project root
✓Never makes an outbound call in --offline — asserted, not promised
✓Never writes to the scanned tree — read-only, always
✓Never parses a billion-laughs YAML or a deep-nesting bomb — refused, not crashed
Seven invariants, each with a named test in internal/guard_invariants_test.go and the security suite.
A degraded scan is still a scan. If a file is too large, unparseable or unreadable, Clearance records the gap and keeps going — then reports it. It never silently drops a dependency, and it never rounds a gap up to "clean".

Budgets and limits

Every limit has a defined behaviour, because "it just hung" is not an error state anyone can act on.

LimitValueOn breachCodeExit
Files walked200,000Truncate, report the ratioE-SCAN-0030
Single file size8 MiBSkip parsing, record the fileE-SCAN-0060
Directory depth24Stop descending, report the nodeE-SCAN-0080
AST size2 MiBFall back to string signalsE-SCAN-0140
JSON nesting depth64Refuse to parse — treat as hostileE-PARSE-0060
Total scan time60sFatal — no verdict producedE-SCAN-0192
Ignore breadth> 50% of treeWarn — an ignore may be hiding a dependencyE-SCAN-0200

Only the timeout is fatal. Everything else degrades and says so — a partial answer with a stated gap is more useful than no answer, as long as the gap is visible.