CLI
Commands, options, scenario naming, timeouts, and exit codes.
Commands
| Command | Purpose |
|---|---|
granttrace init | Explicitly create private ignored local state |
granttrace doctor | Diagnose local and optional live prerequisites safely |
granttrace doctor --repair | Remove only a lock that is proven stale and safe |
granttrace record NAME -- COMMAND | Auto-initialize, record one scenario, and review its diff |
granttrace scenario list | List local scenario recordings |
granttrace scenario remove NAME | Remove one local recording |
granttrace check | Compare all recordings with the accepted contract |
granttrace check --accept | Atomically accept the reviewed contract |
granttrace frontier list | List complete nondominated permission assignments |
granttrace frontier select NUMBER | Explicitly choose one listed assignment |
granttrace keep add/remove/list | Manage reasoned, unproven access |
granttrace prove NAME -- COMMAND | Prove one accepted scenario live |
granttrace analyze OBSERVATIONS | Inspect one lower-level NDJSON file |
Run granttrace <command> --help for its complete usage.
record
granttrace record [--no-review] <name> [--timeout 15m] -- <command> [args...]The scenario name is 1–64 lowercase letters, numbers, hyphens, or underscores.
It cannot begin or end with a hyphen or underscore.
The legacy --scenario <name> spelling remains compatible.
Durations accept ms, s, or m; the effective minimum is one second.
Recording defaults to 15 minutes and allows at most 60 minutes.
The child command is passed as an argument array with shell: false. Its output
streams to the terminal and is not retained. On first use, recording creates
private .granttrace/ state and adds it to .gitignore before launching the
child. Unsafe, symlinked, or stale existing state still blocks execution
instead of being silently repaired.
For the standard Node.js path, GrantTrace injects a preload that observes
supported GitHub REST requests through global fetch, including requests from
standard Octokit clients. Automatic capture observes only the exact
https://api.github.com origin and ignores off-origin responses even when they
include a permission-like header. Custom fetch implementations, transports,
unusual runtimes, and subprocesses that discard the injected Node options need
the explicit fallback.
After a successful recording, record calculates and prints the aggregate
contract diff. If the diff is safe and stdin and stdout are interactive TTYs,
it asks for explicit acceptance with a default of no. In noninteractive
environments it never prompts or accepts; a semantic change exits 6.
--no-review saves the recording without calculating the aggregate diff. It
exists for multi-scenario automation, where each intermediate aggregate is
intentionally incomplete. Use it only when a later granttrace check is
guaranteed.
check
granttrace check [--accept] [--format <text|json|markdown>]
[--github-step-summary]
[--observations <path>] [--lock <path>]Without --accept, the command never changes the contract. The path flags are
advanced overrides for inspecting a different observation directory or
contract file.
--format text is the default and preserves the human-readable terminal
report. --format json emits a versioned JSON object, and --format markdown
emits a PR-ready Markdown report. Structured reports are written to stdout for
every completed check, including nonzero review and evidence outcomes. The
process exit code remains authoritative and has the same meaning in every
format.
The JSON object has schemaVersion: 1, a stable status, exitCode, an
enumerated reason or null, aggregate summary counts, observed permissions,
manual keeps without their free-form reasons, the mandatory baseline, a
categorized changes object, safe findings, and migration identifiers. Arrays
use the deterministic contract and diff ordering. JSON and Markdown deliberately
omit scenario names, repository and resource identities, raw URLs, commands,
credentials, manual reasons, paths, and raw error messages.
Permission identifiers are required machine-readable contract data and are not
redacted, including syntactically valid user-supplied manual-keep keys. Use real
GitHub permission names and never encode an identity, tenant, repository, path,
or secret in a permission name.
Only templates recognized by the pinned catalog are included; any other route
template is represented as null in JSON and an em dash in Markdown.
--github-step-summary explicitly opts in to appending the same safe Markdown
report to the file named by GITHUB_STEP_SUMMARY. It works only when
GITHUB_ACTIONS=true and that runner-provided value is an absolute path to an
existing, bounded regular file with no symlink or hard-link ambiguity. The path
may live on GitHub's separate /github/file_commands container mount and is
not required to be under RUNNER_TEMP. GrantTrace does not create, truncate,
or follow links for this file. Terminal output still uses the selected
--format; the summary is an additional destination. A missing or unsafe
summary target is an analysis failure and exits 5 without following or
modifying that target.
Contract acceptance, frontier selection, and manual-keep mutation are refused
when CI is enabled or GITHUB_ACTIONS=true, before acquiring the mutation
lock or writing. Review and update contracts from a trusted local checkout.
Removing a recording is only a local change. The next check presents the
scenario, route, attribution, and permission contraction for review. Removing
the final recording can therefore produce a deterministic zero-scenario v3
contract after check --accept; validated manual keeps remain until explicitly
removed.
An accepted nondefault frontier selection is preserved when it is still a
complete member of the recomputed frontier. If evidence makes it invalid, the
deterministic default is proposed through the usual exit-6 review. Only an
explicit interactive confirmation or check --accept persists that proposal.
frontier
granttrace frontier list
granttrace frontier select <number>list is read-only and marks the current selection. select accepts only a
numbered complete assignment already stored in permissionFrontier; partial
assignments and arbitrary permission text are not accepted. It changes
selectedPermissions atomically without changing the evidence or frontier.
Review and commit the resulting granttrace.lock.json diff. A selection that
would duplicate a manual keep is blocked rather than removing the keep.
Selection is blocked until any v1/v2 contract migration is accepted as v3,
and it is refused in CI. list remains available because it does not mutate.
keep
granttrace keep add <permission>:<read|write> --reason <text>
granttrace keep remove <permission>
granttrace keep listManual-keep reasons are validated review text and are omitted from structured check output. Permission keys are emitted, so use real GitHub permission names and never put identities or secrets in the key.
prove
granttrace prove <name> [--timeout 15m] -- <command> [args...]The scenario must exist in an accepted schema-v3 contract. See
live proof. Proof requires initialized safe local state and
complete live setup. It defaults to 15 minutes and allows at most 30 minutes;
durations accept ms, s, or m with an effective one-second minimum.
doctor
FAIL blocks local execution. WARN means an attempted optional live setup is
incomplete or unsafe but does not block offline record/check work. INFO means
optional live proof is not configured. Stale sessions are a FAIL: inspect the
artifact and any possible mutation residue before removing it and retrying.
doctor --repair is intentionally narrow. It removes an owned, private
operation lock only when its recorded process no longer exists. It can also
remove an otherwise empty lock after it has remained unchanged for at least one
hour, covering a crash between directory creation and owner-record creation.
Live processes, unverifiable process states, malformed owner records, young
empty locks, symlinks, unsafe modes, and unexpected files are never removed.
Exit codes
| Exit | Meaning |
|---|---|
0 | Success |
2 | Invalid command usage |
3 | No supported operation was observed |
4 | Child test failed, timed out, or could not start |
5 | Invalid or unsafe artifact, configuration failure, or analysis failure |
6 | Contract review or schema migration required |
7 | Unknown, unsupported, malformed, or contradictory evidence |
8 | Live proof, negative-control, or cleanup failure |
130 | Child interrupted by a terminal signal |
The default CLI output is stable plain text without ANSI color. JSON and Markdown check output are also deterministic and contain no ANSI styling.