seal verify
seal verify reads seal.json, hashes every recorded bundle and every directory or regular file matched by discovery, and reports whether the project is Verified, Drift, Warning, or Blocked.
It is read‑only: it never prompts, never writes to seal.json, and never makes network calls. Run it as often as you like.
Synopsis
Section titled “Synopsis”seal verify [--json | --quiet] [--verbose]| Flag | Effect |
|---|---|
--json |
Emit a machine‑readable JSON object to stdout. Suppresses the human summary on stderr. |
--quiet |
No output to either stream. Exit code is the only signal. |
-v, --verbose |
In human mode only: expand each Mismatch into per‑file modified / added / missing lines. |
--json and --quiet are mutually exclusive. Combining them is a usage error (exit 2).
Behaviour
Section titled “Behaviour”- Locate
seal.jsonin the current working directory. Not found → exit2withseal: verify: seal.json not found in current directory; run 'seal init' first. - Decode and validate
seal.json. Invalid → exit2with the specific validation failure (e.g., unknown field, malformed hash, mismatchedcontentHash, uncovered bundle key, nested bundle keys, or overlapping discovery patterns). - Build the verification set: every entry in
bundlesplus every directory or regular file matched bydiscoveryexpansion. Unsupported discovery matches, such as symlinks, are kept so they can reportMismatch. - For each set member, hash the on‑disk sealed root and classify it as
Verified,Unverified,Removed, orMismatch. See verification outcomes for details. - Apply
policyto derive the overall outcome. - Render output according to the flags.
- Exit
0forVerified/Drift/Warning,1forBlocked.
Output
Section titled “Output”Human mode (default, on stderr)
Section titled “Human mode (default, on stderr)”A short summary lists:
- Counts:
<n> verified, <m> unverified, <p> removed, <q> mismatch. - Per‑bundle status lines for non‑verified entries.
- For Mismatch, with
--verbose: per‑file lists ofmodified,added,missing. - A trailing line stating the outcome and policy:
Result: Blocked (block mode).
The current human renderer is plain text. Treat it as terminal output for people, not as a stable machine interface.
JSON mode (--json, on stdout)
Section titled “JSON mode (--json, on stdout)”{ "status": "Blocked", "verified": ["./.claude/skills/code-review"], "unverified": ["./.claude/skills/new-thing"], "removed": ["./.claude/skills/deleted"], "mismatch": ["./.claude/skills/deploy-guard"]}Guarantees:
statusis exactly one of"Verified","Drift","Warning","Blocked".- The four arrays (
verified,unverified,removed,mismatch) are always present, even when empty. - Each array is sorted lexicographically by UTF‑8 bytes (NFC).
- Implementations MAY include additional diagnostic metadata, but MUST preserve the four required arrays and the
statusfield exactly.
If the CLI exits 2 (fatal error), it does not emit JSON to stdout. Diagnostic text always goes to stderr.
Quiet mode (--quiet)
Section titled “Quiet mode (--quiet)”No output to either stream. The exit code is the entire signal, useful for the simplest possible CI gate.
Exit codes
Section titled “Exit codes”| Code | Outcome | Meaning |
|---|---|---|
0 |
Verified, Drift, or Warning |
Project may load bundles. |
1 |
Blocked |
Unverified or mismatched bundles found under policy: "block". |
2 |
(fatal) | seal.json missing or invalid, system error, or --json + --quiet combined. |
See the complete exit codes table.
What gets verified
Section titled “What gets verified”The verification set is exactly:
- Every entry in
bundles. - Every directory or regular file matched by
discoverypattern expansion.
The CLI does not scan the project tree for bundles outside of discovery. If you want a bundle to be checked, either pin it explicitly with seal pin <path> or add a discovery pattern that produces its bundle key.
Targeted seal pin <path> adds exact discovery coverage for that named key when needed. Exact coverage keeps the lockfile valid, but it does not detect new sibling files. For sibling insertion detection, use a broader pattern such as docs/*.md or pin the containing directory as one recursive sealed root.
This is deterministic across implementations: seal verify in CI on Linux behaves identically to seal verify on a developer’s macOS laptop, because both rely strictly on the written lockfile.
Examples
Section titled “Examples”Default (human output to stderr):
$ seal verify1 verified, 1 unverified, 0 removed, 1 mismatch Mismatch ./.claude/skills/deploy-guard Unverified ./.claude/skills/new-thingResult: Blocked (block mode)$ echo $?1CI gate (silent, exit code only):
$ seal verify --quiet ; echo $?1Machine‑readable JSON for downstream tooling:
$ seal verify --json{ "status": "Blocked", "verified": ["./.claude/skills/code-review"], "unverified": ["./.claude/skills/new-thing"], "removed": [], "mismatch": ["./.claude/skills/deploy-guard"]}Verbose mode with per‑file diffs:
$ seal verify --verbose0 verified, 0 unverified, 0 removed, 1 mismatch Mismatch ./.claude/skills/deploy-guard modified: SKILL.md added: scripts/new-tool.sh missing: scripts/old-tool.shResult: Blocked (block mode)Common scenarios
Section titled “Common scenarios”| You see | What it means | What to do |
|---|---|---|
Result: Verified |
All clean. | Nothing. |
Result: Drift |
Lockfile lists bundles not on disk. | If intentional, seal pin --prune to drop them. Otherwise restore from version control. |
Result: Warning |
Unverified/mismatched under policy: "warn". Loads still allowed. |
Review the listed bundles; consider switching to policy: "block" once stable. |
Result: Blocked |
Unverified/mismatched under policy: "block". Loads forbidden. |
Run seal pin <path> after reviewing the actual file changes (git diff). |
The discipline Seal asks of you is to look at the diff before re‑pinning. That is the entire point.