CLI reference¶
whatifd --help
Commands¶
Command |
Purpose |
|---|---|
|
Fork production traces, replay with a proposed change, score the diff, emit a verdict. |
|
Compare two |
|
Validate that an |
|
Migrate a report to the current schema (v0.1 → v0.2). Human-readable indented JSON by default ( |
|
Wipe |
|
Remove |
|
Verify cache-entry structural integrity. |
Check the installed version via python -c "import whatifd; print(whatifd.__version__)". __version__ reads from importlib.metadata so it always matches the distribution metadata.
whatifd fork¶
The main verb. Ingests traces, replays, scores, emits report. Config-file driven — there are no --source, --target, --change CLI flags; everything comes from the YAML.
whatifd fork --config whatifd.config.yaml
whatifd fork -c whatifd.config.yaml --profile review # override reporting profile
Flags¶
Flag |
Default |
Description |
|---|---|---|
|
|
Path to the whatifd config file ( |
|
(config value) |
Reporting profile override; must match the config’s |
|
(dated default) |
Write the |
|
(dated default) |
Write the Markdown report to this exact path instead of |
|
off |
After writing, emit only a JSON object |
Config schema lives at config reference.
The runner reference (target.runner: python:<module>:<attr>) resolves from your project root — run whatifd fork from your project directory and your own runner module imports, no install or PYTHONPATH needed. (v0.3)
Output¶
By default whatifd fork writes two files to ./reports/:
whatifd-fork-<YYYY-MM-DD>.json— the fullReportV01JSON; consumers validate against the v0.1 schema.whatifd-fork-<YYYY-MM-DD>.md— the rendered Markdown report.
Use --output-json / --output-md to control the destinations, or --print-paths to have the CLI report exactly where it wrote (and the verdict) for a CI step to consume:
whatifd fork --config whatifd.config.yaml --print-paths
# {"report_json": "reports/whatifd-fork-2026-06-04.json", "report_md": "...", "verdict": "ship"}
Exit codes¶
Code |
Verdict |
Meaning |
|---|---|---|
|
Ship |
Floor passed, no |
|
Don’t Ship |
Floor passed, at least one |
|
Inconclusive or setup failure |
Floor failed, a |
whatifd enforces your declared policy. Exit code 0 is not a safety certification; it means the run satisfied the policy you declared.
whatifd diff¶
Compare two reports. Descriptive, not a verdict — exits 0 on any successful render, 2 on file-level errors (missing file, parse failure, non-mapping JSON).
whatifd diff reports/2026-05-03-v3.json reports/2026-05-04-v4.json
Output is Markdown to stdout. Surfaces verdict transitions, cohort row deltas, decision-findings added/removed, and failure-count delta. The diff intentionally reads raw JSON dicts (not ReportV01) so cross-version diffs during schema migration don’t fail spuriously.
whatifd exec-check¶
Validate that an exec: runner speaks the whatifd-exec/1 protocol before wiring it into a full run.
whatifd exec-check "exec:node ./replay-agent.js"
Spawns the child and drives it through hello → a probe replay_request (answering any tool_lookup from a synthetic cache) → clean shutdown, printing pass/fail per behavior. Checks protocol conformance (framing, handshake, a valid ReplayOutput, teardown), not agent answer quality. Exits 0 if the runner conforms, 2 otherwise.
whatifd report-migrate¶
whatifd report-migrate path/to/old-report.json # writes old-report.v0.2.json
whatifd report-migrate path/to/old-report.json --in-place
whatifd report-migrate path/to/old-report.json --no-indent # compact canonical form
Migrates a report to the current schema (v0.1 → v0.2, injecting the required experiment_shape field). The artifact is human-readable indented JSON by default (its audience is an operator diffing v0.1 vs v0.2); pass --no-indent for the compact canonical form. Already-current reports are reported as no-ops with exit 0; malformed input exits 2 with a structured message.
whatifd cache¶
Cache management subcommands. The cache stores scorer results keyed by (judge_provider, judge_model_id, rubric_id, rubric_text_hash, scoring_params) so identical scoring inputs across runs are reused (cardinal #10 reproducibility, NOT validity).
whatifd cache rebuild¶
whatifd cache rebuild --force [--cache-root .whatifd/cache]
Wipes <cache-root>/entries/. Preserves meta.json and the lock file so the storage-layer schema-version contract stays intact; only cached values are removed.
Flag |
Required |
Description |
|---|---|---|
|
yes (for delete) |
Safety belt: without |
|
no |
Override the default |
Exit codes:
0— clean rebuild OR no-op when<cache-root>/entries/is already absent.2—--forcewas omitted while entries exist (typo-protection refuse).
whatifd cache unlock¶
whatifd cache unlock [--allow-alive] [--cache-root .whatifd/cache]
Removes <cache-root>/.lock after a PID-alive safety check. Refuses to unlock if the recorded PID is still running. Use after a previous run was hard-killed.
Flag |
Required |
Description |
|---|---|---|
|
no |
Override the live-PID safety check. Use only when you’re sure the recorded process is gone (e.g., the PID was inherited by an unrelated process the OS just recycled to). |
|
no |
Override the default |
whatifd cache verify¶
whatifd cache verify [--cache-root .whatifd/cache]
Verifies cache-entry structural integrity — checks every entry parses, the digest matches its filename, and the schema version is recognized. Prints a counts summary.
Two-affirmation for forensic mode¶
The forensic reporting profile (which controls Sensitive[T] redaction depth — see report anatomy) requires both the config’s reporting.profile: forensic AND --profile forensic on the CLI. Either alone fails per cardinal #7. This is intentional: forensic mode reveals more user content in the artifact, and a single misconfigured field shouldn’t be enough to flip the bit.