rigortype 0.2.1 → 0.2.3

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 (109) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +41 -14
  3. data/docs/handbook/01-getting-started.md +311 -0
  4. data/docs/handbook/02-everyday-types.md +337 -0
  5. data/docs/handbook/03-narrowing.md +359 -0
  6. data/docs/handbook/04-tuples-and-shapes.md +321 -0
  7. data/docs/handbook/05-methods-and-blocks.md +339 -0
  8. data/docs/handbook/06-classes.md +305 -0
  9. data/docs/handbook/07-rbs-and-extended.md +427 -0
  10. data/docs/handbook/08-understanding-errors.md +373 -0
  11. data/docs/handbook/09-plugins.md +241 -0
  12. data/docs/handbook/10-sorbet.md +347 -0
  13. data/docs/handbook/11-sig-gen.md +312 -0
  14. data/docs/handbook/12-lightweight-hkt.md +333 -0
  15. data/docs/handbook/README.md +275 -0
  16. data/docs/handbook/appendix-elixir.md +370 -0
  17. data/docs/handbook/appendix-go.md +399 -0
  18. data/docs/handbook/appendix-java-csharp.md +470 -0
  19. data/docs/handbook/appendix-liskov.md +580 -0
  20. data/docs/handbook/appendix-mypy.md +370 -0
  21. data/docs/handbook/appendix-phpstan.md +338 -0
  22. data/docs/handbook/appendix-protocols-and-structural-typing.md +292 -0
  23. data/docs/handbook/appendix-rust.md +446 -0
  24. data/docs/handbook/appendix-steep.md +336 -0
  25. data/docs/handbook/appendix-type-theory.md +1662 -0
  26. data/docs/handbook/appendix-typeprof.md +416 -0
  27. data/docs/handbook/appendix-typescript.md +332 -0
  28. data/docs/install.md +189 -0
  29. data/docs/llms.txt +72 -0
  30. data/docs/manual/01-installation.md +342 -0
  31. data/docs/manual/02-cli-reference.md +569 -0
  32. data/docs/manual/03-configuration.md +152 -0
  33. data/docs/manual/04-diagnostics.md +206 -0
  34. data/docs/manual/05-inspecting-types.md +109 -0
  35. data/docs/manual/06-baseline.md +104 -0
  36. data/docs/manual/07-plugins.md +92 -0
  37. data/docs/manual/08-skills.md +143 -0
  38. data/docs/manual/09-editor-integration.md +245 -0
  39. data/docs/manual/10-mcp-server.md +539 -0
  40. data/docs/manual/11-ci.md +274 -0
  41. data/docs/manual/12-caching.md +116 -0
  42. data/docs/manual/13-troubleshooting.md +120 -0
  43. data/docs/manual/14-rails-quickstart.md +332 -0
  44. data/docs/manual/15-type-protection-coverage.md +204 -0
  45. data/docs/manual/16-rbs-extended-annotations.md +190 -0
  46. data/docs/manual/17-driving-improvement.md +160 -0
  47. data/docs/manual/README.md +87 -0
  48. data/docs/manual/ci-templates/README.md +58 -0
  49. data/docs/manual/plugins/README.md +86 -0
  50. data/docs/manual/plugins/rigor-actioncable.md +78 -0
  51. data/docs/manual/plugins/rigor-actionmailer.md +74 -0
  52. data/docs/manual/plugins/rigor-actionpack.md +80 -0
  53. data/docs/manual/plugins/rigor-activejob.md +58 -0
  54. data/docs/manual/plugins/rigor-activerecord.md +102 -0
  55. data/docs/manual/plugins/rigor-activestorage.md +74 -0
  56. data/docs/manual/plugins/rigor-activesupport-core-ext.md +86 -0
  57. data/docs/manual/plugins/rigor-devise.md +70 -0
  58. data/docs/manual/plugins/rigor-dry-schema.md +56 -0
  59. data/docs/manual/plugins/rigor-dry-struct.md +60 -0
  60. data/docs/manual/plugins/rigor-dry-types.md +59 -0
  61. data/docs/manual/plugins/rigor-dry-validation.md +62 -0
  62. data/docs/manual/plugins/rigor-factorybot.md +76 -0
  63. data/docs/manual/plugins/rigor-graphql.md +89 -0
  64. data/docs/manual/plugins/rigor-hanami.md +83 -0
  65. data/docs/manual/plugins/rigor-mangrove.md +73 -0
  66. data/docs/manual/plugins/rigor-minitest.md +86 -0
  67. data/docs/manual/plugins/rigor-pundit.md +72 -0
  68. data/docs/manual/plugins/rigor-rails-i18n.md +92 -0
  69. data/docs/manual/plugins/rigor-rails-routes.md +94 -0
  70. data/docs/manual/plugins/rigor-rails.md +44 -0
  71. data/docs/manual/plugins/rigor-rbs-inline.md +83 -0
  72. data/docs/manual/plugins/rigor-rspec-rails.md +72 -0
  73. data/docs/manual/plugins/rigor-rspec.md +86 -0
  74. data/docs/manual/plugins/rigor-shoulda-matchers.md +78 -0
  75. data/docs/manual/plugins/rigor-sidekiq.md +78 -0
  76. data/docs/manual/plugins/rigor-sinatra.md +61 -0
  77. data/docs/manual/plugins/rigor-sorbet.md +63 -0
  78. data/docs/manual/plugins/rigor-statesman.md +75 -0
  79. data/docs/manual/plugins/rigor-typescript-utility-types.md +71 -0
  80. data/exe/rigor +1 -1
  81. data/lib/rigor/analysis/incremental_session.rb +4 -2
  82. data/lib/rigor/analysis/run_stats.rb +13 -1
  83. data/lib/rigor/analysis/runner.rb +54 -12
  84. data/lib/rigor/cli/check_command.rb +1 -1
  85. data/lib/rigor/cli/docs_command.rb +248 -0
  86. data/lib/rigor/cli/skill_command.rb +103 -41
  87. data/lib/rigor/cli/skill_describe.rb +346 -0
  88. data/lib/rigor/cli/triage_command.rb +8 -2
  89. data/lib/rigor/cli/triage_renderer.rb +4 -0
  90. data/lib/rigor/cli.rb +25 -3
  91. data/lib/rigor/inference/method_dispatcher/constant_folding.rb +124 -32
  92. data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +37 -6
  93. data/lib/rigor/inference/scope_indexer.rb +87 -89
  94. data/lib/rigor/plugin/isolation.rb +5 -5
  95. data/lib/rigor/plugin/loader.rb +4 -2
  96. data/lib/rigor/triage/catalogue.rb +16 -1
  97. data/lib/rigor/triage.rb +30 -7
  98. data/lib/rigor/version.rb +1 -1
  99. data/skills/rigor-ask/SKILL.md +172 -0
  100. data/skills/rigor-doctor/SKILL.md +87 -0
  101. data/skills/rigor-editor-setup/SKILL.md +114 -0
  102. data/skills/rigor-mcp-setup/SKILL.md +117 -0
  103. data/skills/rigor-monkeypatch-resolve/SKILL.md +79 -0
  104. data/skills/rigor-next-steps/SKILL.md +113 -0
  105. data/skills/rigor-plugin-tune/SKILL.md +79 -0
  106. data/skills/rigor-protection-uplift/SKILL.md +133 -0
  107. data/skills/rigor-rbs-setup/SKILL.md +128 -0
  108. data/skills/rigor-upgrade/SKILL.md +79 -0
  109. metadata +90 -1
@@ -0,0 +1,569 @@
1
+ # CLI command reference
2
+
3
+ Every Rigor command is a subcommand of the single `rigor`
4
+ executable:
5
+
6
+ ```sh
7
+ rigor <command> [options] [arguments]
8
+ ```
9
+
10
+ `rigor help` prints the command list; `rigor version` prints
11
+ the installed version. An unknown command, or a malformed
12
+ option, exits `64` — the conventional "usage error" code.
13
+
14
+ Every command that loads your project configuration also
15
+ accepts `--config=PATH` to point at a specific config file
16
+ instead of auto-discovery (it is called out below only where it
17
+ has an additional effect).
18
+
19
+ ## `rigor check`
20
+
21
+ Analyse Ruby source for type errors and report diagnostics.
22
+ This is the command you run day to day and in CI.
23
+
24
+ ```sh
25
+ rigor check [paths...]
26
+ ```
27
+
28
+ `paths` are files or directories; when omitted, Rigor checks
29
+ the `paths:` list from the configuration file.
30
+
31
+ | Option | Effect |
32
+ | --- | --- |
33
+ | `--config=PATH` | Use a specific config file instead of auto-discovery. |
34
+ | `--format=FORMAT` | Output format. Default `text`. Also `json` (structured stream), plus the CI-native renderings `sarif`, `github`, `gitlab`, `checkstyle`, `junit`, and `teamcity` — see [Running Rigor in CI](11-ci.md). |
35
+ | `--no-ci-detect` | Disable CI auto-detection — by default `text` output also emits the running CI's native annotations / hint (`RIGOR_CI_DETECT=0` does the same). See [Running Rigor in CI § auto-detection](11-ci.md). |
36
+ | `--explain` | Surface fail-soft fallback events as `info` diagnostics. |
37
+ | `--no-cache` | Skip the persistent cache for this run. |
38
+ | `--incremental` | Re-analyse only the files changed since the last run plus the files that depend on them, serving the rest from a cross-process disk snapshot (ADR-46). Diagnostics are identical to a full run; a config / gem / version change (or a file added or removed) transparently forces a full re-analysis. See [Caching](12-caching.md). |
39
+ | `--verify-incremental` | Acceptance gate: run the incremental analyzer against a full `--no-cache` run and assert the diagnostics are byte-identical, then exit (0 on match, 1 with the differing diagnostics on mismatch). Used in CI to guarantee `--incremental` never serves a stale result. |
40
+ | `--clear-cache` | Delete the cache directory before running. |
41
+ | `--cache-stats` | Print the on-disk cache inventory when finished. |
42
+ | `--[no-]stats` | Print a run summary (files, classes, memory, wall time) to stderr. Default on. |
43
+ | `--coverage` | Add a type-precision coverage block to the output (`coverage` object under `--format json`; a one-line summary in text mode). Off by default — it is a second precision pass over the analyzed files, the same scan [`rigor coverage`](#rigor-coverage) runs, so it is opt-in. |
44
+ | `--workers=N` | Dispatch analysis across `N` parallel worker processes (fork-based pool today; ADR-15). Default `0` (sequential). |
45
+ | `--baseline=PATH` | Load a baseline file, overriding config. |
46
+ | `--no-baseline` | Ignore any configured baseline. |
47
+ | `--baseline-strict` | Fail the run on any baseline drift — a CI gate. |
48
+ | `--treat-all-as-inline-rbs` | Force-load `rigor-rbs-inline` with `require_magic_comment: false`, so every analysed file is treated as inline-RBS without the `# rbs_inline: enabled` comment (ADR-32). |
49
+ | `--bleeding-edge[=ids]` | Adopt the bleeding-edge overlay for this run, overriding the configured [`bleeding_edge:`](03-configuration.md) selection (ADR-50 § WD2). Bare adopts every queued feature; `--bleeding-edge=a,b` adopts only the named feature ids. The overlay is empty in this release, so this is currently a no-op. Inspect it with [`rigor show-bleedingedge`](#rigor-show-bleedingedge). |
50
+ | `--no-bleeding-edge` | Ignore any configured `bleeding_edge:` selection for this run (adopt none). |
51
+ | `--tmp-file=PATH --instead-of=PATH` | Editor mode: analyse `PATH` using the buffer in `--tmp-file`. Both required together. |
52
+
53
+ Exit `0` when no error-severity diagnostics remain, `1` when
54
+ any are reported, `64` on a usage error.
55
+
56
+ ## `rigor init`
57
+
58
+ Write a starter configuration file.
59
+
60
+ ```sh
61
+ rigor init [--path=PATH] [--force]
62
+ ```
63
+
64
+ Writes `.rigor.dist.yml` by default. `--path` chooses a
65
+ different target; `--force` overwrites an existing file.
66
+ Exit `1` if the file exists and `--force` was not given.
67
+
68
+ ## `rigor annotate`
69
+
70
+ Reprint a file with every line tagged by the type of the
71
+ expression it evaluates to, as a trailing `#=>` comment. See
72
+ [Inspecting inferred types](05-inspecting-types.md).
73
+
74
+ ```sh
75
+ rigor annotate [--[no-]color] [--[no-]bat] [--format=text|json] [--config=PATH] FILE
76
+ ```
77
+
78
+ `FILE` is required. Colour is auto-detected for a tty and
79
+ honours `NO_COLOR`; `--color` / `--no-color` override. When
80
+ colour is on and [`bat`](https://github.com/sharkdp/bat) is on
81
+ `PATH`, highlighting goes through bat (`--no-bat` opts out;
82
+ `--bat` warns if bat is missing and falls back to the built-in
83
+ colorizer). `--format=json` emits a `{ line => type }` map
84
+ instead of the annotated source. Exit `1` on a parse error or a
85
+ missing file.
86
+
87
+ ## `rigor type-of`
88
+
89
+ Print the inferred type at one source position.
90
+
91
+ ```sh
92
+ rigor type-of FILE:LINE:COL
93
+ rigor type-of FILE LINE COL
94
+ ```
95
+
96
+ Accepts the position as a single `file:line:col` triple or as
97
+ three arguments. `--format=json` emits a machine-readable
98
+ form; `--trace` records fail-soft fallbacks. The editor-mode
99
+ `--tmp-file` / `--instead-of` pair is accepted as on `check`.
100
+
101
+ ## `rigor trace`
102
+
103
+ Replay HOW the engine typed a file, step by step, as a
104
+ terminal animation. It is a teaching probe over the same
105
+ inference `rigor check` runs.
106
+
107
+ ```sh
108
+ rigor trace [--delay=SECONDS] [--line=N] [--verbose] [--format=json] FILE
109
+ ```
110
+
111
+ Each frame highlights the source range being evaluated next to
112
+ the scope's locals and describes one inference moment: a local
113
+ binding entering the scope (`bind`), branch types merging
114
+ (`union`), or a method call resolving — or fail-softening to
115
+ `Dynamic[top]` (`dispatch`). On a tty the replay steps on a key
116
+ press (`q` quits); `--delay` autoplays. `--verbose` adds every
117
+ expression enter/result frame, `--line=N` keeps only events on
118
+ one line, and `--format=json` dumps the raw event stream for
119
+ tooling or course material. See
120
+ [Inspecting inferred types](05-inspecting-types.md).
121
+
122
+ ## `rigor type-scan`
123
+
124
+ Report `type_of` inference coverage across paths — a
125
+ diagnostic-of-the-diagnoser, useful when investigating why a
126
+ class infers poorly.
127
+
128
+ ```sh
129
+ rigor type-scan PATH...
130
+ ```
131
+
132
+ `--limit=N` caps the printed examples (default 10),
133
+ `--show-recognized` includes fully-covered classes,
134
+ `--threshold=RATIO` makes the command exit non-zero when the
135
+ unrecognized-node ratio exceeds `RATIO`, and `--format=text|json`
136
+ selects the output format.
137
+
138
+ ## `rigor explain`
139
+
140
+ Print the catalogue entry for a diagnostic rule, or list every
141
+ rule when called with no argument.
142
+
143
+ ```sh
144
+ rigor explain [rule]
145
+ ```
146
+
147
+ `rule` is a rule ID (`call.undefined-method`), a legacy alias,
148
+ or a family wildcard (`call`, `flow`, `def`, `assert`, `dump`).
149
+ `--format=json` is available. Exit `64` for an unknown rule.
150
+
151
+ ## `rigor diff`
152
+
153
+ Compare the current diagnostics against a saved baseline JSON
154
+ and report only what is new.
155
+
156
+ ```sh
157
+ rigor diff <baseline.json> [paths...]
158
+ ```
159
+
160
+ `--current=PATH` compares against a saved diagnostics JSON
161
+ instead of running a fresh check. Exit `1` when new
162
+ diagnostics appear.
163
+
164
+ ## `rigor sig-gen`
165
+
166
+ Emit RBS signatures inferred from your Ruby source. See
167
+ [handbook chapter 11](../handbook/11-sig-gen.md) for the
168
+ classification model and the `--params` policy.
169
+
170
+ ```sh
171
+ rigor sig-gen [paths]
172
+ ```
173
+
174
+ | Option | Effect |
175
+ | --- | --- |
176
+ | `--print` | Write RBS to stdout. Default. |
177
+ | `--diff` | Write a unified diff against existing RBS. |
178
+ | `--write` | Write RBS to `sig/<path>.rbs` files. |
179
+ | `--overwrite` | Allow tighter-return updates to replace user-authored RBS. |
180
+ | `--include-private` | Emit private and protected methods too. |
181
+ | `--params=untyped\|observed\|observed-strict` | Parameter-typing policy. Default `untyped`. |
182
+ | `--observe=PATH` | Scan `PATH` for call-site observations. Repeatable. |
183
+ | `--new-files` / `--new-methods` / `--tighter-returns` | Emit only that classification. |
184
+ | `--format=text\|json` | Output format. |
185
+
186
+ ## `rigor lsp`
187
+
188
+ Run the Language Server over stdio. See
189
+ [Editor integration](09-editor-integration.md).
190
+
191
+ ```sh
192
+ rigor lsp [--transport=stdio] [--log=PATH] [--config=PATH]
193
+ ```
194
+
195
+ `stdio` is the only transport in v1. `--log=PATH` is accepted
196
+ but not yet wired in this release — it is reserved for routing
197
+ the server's wire log to a file; until then logging stays on
198
+ stderr.
199
+
200
+ ## `rigor baseline`
201
+
202
+ Manage diagnostic baselines. See [Baselines](06-baseline.md)
203
+ for the file format and workflow.
204
+
205
+ ```sh
206
+ rigor baseline <generate|regenerate|dump|drift|prune> [options]
207
+ ```
208
+
209
+ | Subcommand | Purpose |
210
+ | --- | --- |
211
+ | `generate` | Write a fresh baseline from the current diagnostics. Refuses to overwrite without `--force`. |
212
+ | `regenerate` | Rewrite the baseline unconditionally — use after a quality pass. |
213
+ | `dump` | Print the baseline contents, filterable by `--rule` and `--file`. |
214
+ | `drift` | Audit how each bucket has drifted; filter with `--only=within\|over\|cleared\|reducible`. |
215
+ | `prune` | Drop buckets that no longer match any diagnostic. `--dry-run` previews. |
216
+
217
+ `generate` and `regenerate` accept `--output=PATH` and
218
+ `--match-mode=rule|message`; `dump`, `drift`, and `prune` accept
219
+ `--baseline=PATH` to read a non-default baseline file.
220
+
221
+ ## `rigor triage`
222
+
223
+ Summarise a diagnostic stream — rule distribution, **class/method
224
+ selectors**, per-file hotspots, and heuristic "why" hints — instead
225
+ of dumping the raw list. See [Baselines](06-baseline.md).
226
+
227
+ ```sh
228
+ rigor triage [paths]
229
+ ```
230
+
231
+ `--top=N` sets the hotspot count (default 10); `--hints-only`,
232
+ `--selectors-only`, and `--no-hints` select which sections print.
233
+ `triage` is advisory and always exits `0` — it never gates a build.
234
+
235
+ By default the distribution, selectors, and hotspots sections count
236
+ only the **actionable** diagnostics (`error` + `warning`). `info`
237
+ diagnostics are excluded from these volume views — on a Rails project
238
+ they are dominated by plugin *recognition trace* (`Account.find
239
+ resolves to Account`, `users_path → GET /users`), positive "Rigor
240
+ resolved this" records that would otherwise bury the genuine signal
241
+ and skew the hotspot ranking toward the files with the most *working*
242
+ code. The summary line still reports the full `info` count, and
243
+ heuristic hints still see every diagnostic (so the `gem-without-rbs`
244
+ notice survives). Pass `--include-info` to route `info` into the
245
+ volume views as well.
246
+
247
+ The **`selectors`** section is the by-(class, method) axis: it
248
+ aggregates the structured `receiver_type` / `method_name` fields the
249
+ diagnostics carry into `{receiver, method, count, files, rules}`
250
+ rows, so you can ask "which method concentrates the diagnostics?"
251
+ without parsing message text. Under `--format json` the full list is
252
+ emitted, keyed on a normalised receiver class (literals fold to their
253
+ class), ready for a `jq` query:
254
+
255
+ ```sh
256
+ # methods with diagnostics spread across ≥ 3 files (systemic clusters)
257
+ rigor triage --format json | jq '.selectors[] | select(.files >= 3)'
258
+ # everything Rigor flagged on String receivers, by method
259
+ rigor triage --format json | jq '[.selectors[] | select(.receiver == "String")]'
260
+ ```
261
+
262
+ The same `receiver_type` / `method_name` fields ride on each
263
+ diagnostic of `rigor check --format json`, for per-site (rather than
264
+ aggregated) grouping.
265
+
266
+ ## `rigor coverage`
267
+
268
+ > For the value proposition and a workflow guide to the
269
+ > `--protection` tiers, see
270
+ > [Type-protection coverage](15-type-protection-coverage.md). This
271
+ > section is the flag reference.
272
+
273
+ Report type-precision coverage — the ratio of call sites that
274
+ resolve to a precise type versus those that fall back to
275
+ `Dynamic`. A quality gate for "how much is Rigor actually
276
+ inferring".
277
+
278
+ ```sh
279
+ rigor coverage [paths]
280
+ ```
281
+
282
+ `--format=text|json` selects the output format and
283
+ `--config=PATH` overrides config discovery. `--threshold=RATIO`
284
+ exits `1` when the precision ratio falls below `RATIO`
285
+ (`0.0`–`1.0`), making it a CI gate.
286
+
287
+ `--protection` switches to **type-protection coverage**: it
288
+ reports "if I introduce a bug, would Rigor catch it" rather than
289
+ "how precise are my types". Each dispatch site (a call with an
290
+ explicit receiver) is *protected* when the receiver types to a
291
+ concrete class (a site where Rigor's call rules can catch a
292
+ wrong method or argument) and *unprotected* when the receiver is
293
+ `Dynamic`. The report leads with the protected ratio, then a
294
+ ranked "add a type here" list (the methods most often called on
295
+ an untyped receiver), then the least-protected files;
296
+ `--threshold` and `--format=json` work the same. It is a sound
297
+ upper bound on real protection — a concrete receiver is necessary
298
+ but not sufficient for a diagnostic to fire.
299
+
300
+ Adding `--mutation` (with `--protection`) switches to the
301
+ **effectiveness** tier: it measures whether Rigor *does* catch a
302
+ bug, rather than whether it *could*. It introduces
303
+ type-visible breakages at each dispatch site — dropping a
304
+ call-argument to `nil`, swapping its type, renaming a call to a
305
+ missing method — re-analyses the mutated source against a clean
306
+ baseline, and reports the kill rate (caught breakages). It
307
+ defaults to the git-changed `.rb` files (whole-project is
308
+ minutes; pass explicit paths to widen), and leads with the
309
+ effectiveness ratio, then the breakages Rigor missed ("add a type
310
+ here"), then the least-effective files. `--threshold` gates on
311
+ the effectiveness ratio and `--format=json` carries `mode`,
312
+ `killed`, `survived`, `effectiveness_ratio`, per-file rows, and
313
+ `add_a_type_here`. It is the truth tier behind the static
314
+ `--protection` proxy, at the cost of many analyses — an opt-in CI
315
+ deep-dive, not an interactive check.
316
+
317
+ ```sh
318
+ rigor coverage --protection --mutation [paths]
319
+ ```
320
+
321
+ Adding `--with-tests` (with `--protection --mutation`) turns
322
+ that into the **fused static∪dynamic** view: for each breakage
323
+ the type checker does *not* catch, it runs your test suite to see
324
+ whether a **test** catches it. Each site is then classified
325
+ `type-protected` (the type checker caught it), `test-protected`
326
+ (a test caught what the type checker missed), or `unprotected`
327
+ (neither — the actionable "add a type **or** a test here" list),
328
+ and the report names the cheaper missing axis. A type-killed
329
+ mutant never reaches the suite (a gradual short-circuit), so the
330
+ cost is proportional to the protection hole. `--format=json`
331
+ carries `mode` (`protection-fused`), `type_killed`,
332
+ `test_killed`, `unprotected`, `protected_ratio`, per-file rows,
333
+ and `add_protection_here`; `--threshold` gates on the fused
334
+ ratio.
335
+
336
+ `--test-command=CMD` is the runner hook (default
337
+ `bundle exec rake`). The suite must pass on clean code first, or
338
+ the run aborts — point it at a plain pass/fail runner (a coverage
339
+ floor that exits non-zero on a passing suite trips this). It runs
340
+ with Bundler's environment stripped, so a `bundle exec` command
341
+ resolves your project's bundle even when Rigor itself was
342
+ launched under its own, with no env wrapper needed. The command
343
+ runs **without a shell** (it is split into an argv and executed
344
+ directly), so shell constructs are not interpreted — including an
345
+ inline `BUNDLE_GEMFILE=… ` prefix. For a non-default Gemfile, set
346
+ it with `bundle config set --local gemfile PATH` (it persists in
347
+ `.bundle/config`) or wrap the command in `bash -c '…'`.
348
+
349
+ `--include-dynamic` extends the overlay to `Dynamic`-receiver
350
+ (untyped) sites, where a test is the only possible protection —
351
+ completing the map to *every* dispatch site rather than only the
352
+ ones Rigor can type-check. Every such site is a type-survivor, so
353
+ it runs the suite far more; it is an explicit opt-in.
354
+
355
+ `--limit=N` (with `--seed=N`, default `1`) caps the measurement
356
+ to a deterministic sample of `N` mutations per file, bounding the
357
+ cost on large files. Per-file ratios then become estimates, noted
358
+ on stderr so `--format=json` stdout stays clean.
359
+
360
+ ```sh
361
+ rigor coverage --protection --mutation --with-tests \
362
+ --test-command "bundle exec rspec" --include-dynamic [paths]
363
+ ```
364
+
365
+ ## `rigor mcp`
366
+
367
+ Run the Rigor MCP (Model Context Protocol) server over stdio,
368
+ so AI coding assistants can call Rigor tools directly. See
369
+ [MCP server](10-mcp-server.md).
370
+
371
+ ```sh
372
+ rigor mcp [--transport=stdio] [--config=PATH]
373
+ ```
374
+
375
+ `stdio` is the only transport. The server is a pure-Ruby
376
+ JSON-RPC 2.0 implementation exposing seven read-only tools:
377
+ `rigor_check`, `rigor_type_of`, `rigor_triage`,
378
+ `rigor_annotate`, `rigor_sig_gen`, `rigor_explain`,
379
+ `rigor_coverage`.
380
+
381
+ ## `rigor lsp` vs `rigor mcp`
382
+
383
+ `lsp` speaks the Language Server Protocol to editors; `mcp`
384
+ speaks the Model Context Protocol to AI assistants. Both run
385
+ over stdio and wrap the same analysis engine.
386
+
387
+ ## `rigor plugins`
388
+
389
+ Report the activation status of every plugin configured in
390
+ `.rigor.yml` — loaded, load-error (with reason), and each
391
+ plugin's declared extension surfaces. See [Plugins](07-plugins.md).
392
+
393
+ ```sh
394
+ rigor plugins [--format=text|json] [--strict] [--capabilities] [--config=PATH]
395
+ ```
396
+
397
+ Without `--strict` the command always exits `0`; with
398
+ `--strict` it exits `1` when any plugin failed to load (a CI
399
+ gate).
400
+
401
+ `--capabilities` switches to the **extension-protocol
402
+ catalogue** ([ADR-37](../adr/37-plugin-interface-segregation.md)):
403
+ a focused, machine-readable map of what each loaded plugin
404
+ contributes — the AST node types its `node_rule`s match, the
405
+ receiver classes its `dynamic_return`s gate on, the methods its
406
+ `type_specifier`s narrow, and the facts it `produces` /
407
+ `consumes`. Combine with `--format=json` for tooling (an AI
408
+ agent can enumerate every plugin's behaviour without reading a
409
+ line of plugin source). The same narrow surfaces also appear in
410
+ the default full report. Not to be confused with the singular
411
+ `rigor plugin`.
412
+
413
+ ## `rigor plugin`
414
+
415
+ Browse the on-disk source of the plugins bundled in the
416
+ toolchain, so you can read a real, working plugin as a worked
417
+ example when authoring your own.
418
+
419
+ ```sh
420
+ rigor plugin <list|path|print|root> [name]
421
+ ```
422
+
423
+ | Subcommand | Purpose |
424
+ | --- | --- |
425
+ | `list` | Table of every bundled plugin and example, name + absolute directory path (default when no subcommand given). |
426
+ | `path <name>` | One-line absolute path to the plugin's directory. |
427
+ | `print <name>` | A header (dir / lib / sig / README paths) followed by the plugin's main source body inlined. |
428
+ | `root` | The `rigortype` gem root and its key subdirectories. |
429
+
430
+ Paths resolve at runtime from the gem location (a documented
431
+ caveat for container / cross-filesystem setups).
432
+
433
+ ## `rigor playground`
434
+
435
+ Start the browser playground (a CodeMirror editor with
436
+ real-time diagnostics). Requires the separate `rigor-playground`
437
+ gem; if it is not installed the command prints an install hint
438
+ and exits `64`.
439
+
440
+ ```sh
441
+ rigor playground
442
+ ```
443
+
444
+ ## `rigor skill`
445
+
446
+ List or print the bundled Agent Skills shipped inside the
447
+ `rigortype` gem, so an AI coding agent installed alongside
448
+ Rigor can discover and follow them without a project-side
449
+ source checkout. See [Skills](08-skills.md).
450
+
451
+ The positional slot is a skill *name*; alternative outputs are flags,
452
+ so a skill can never be shadowed by a verb.
453
+
454
+ ```sh
455
+ rigor skill [<name>] [--path <name>] [--list] [--describe]
456
+ ```
457
+
458
+ | Form | Purpose |
459
+ | --- | --- |
460
+ | (none) / `--list` | Table of every bundled skill (name + absolute path). |
461
+ | `<name>` | Print the `SKILL.md` body to stdout, with a header pointing at the skill's `references/` directory. |
462
+ | `--path <name>` | Print the single-line absolute `SKILL.md` path, suitable as input to a file-reading tool. |
463
+ | `--describe` | Probe the project's state (config / baseline / `sig/` / CI — presence only, never runs `rigor check`) and recommend the next skill to run. Also spelled `describe`; surfaced top-level as [`rigor describe`](#rigor-describe) below. |
464
+
465
+ The verb spellings `rigor skill list` / `print <name>` / `path <name>`
466
+ are **deprecated** (a one-line stderr notice; removed in v0.3.0) — use
467
+ the forms above. `describe` / `--describe` stay first-class.
468
+
469
+ ## `rigor describe`
470
+
471
+ Top-level alias for [`rigor skill describe`](#rigor-skill) — the
472
+ onboarding entry point that recommends the next skill for this project.
473
+ A bare `rigor describe` is the intuitive guess most users reach for
474
+ first, so it is surfaced as its own command ([ADR-73](../adr/73-skill-driven-user-experience.md)
475
+ § WD2).
476
+
477
+ ```sh
478
+ rigor describe
479
+ ```
480
+
481
+ It reports a presence-only project-state probe (does a `.rigor.yml`,
482
+ `.rigor-baseline.yml`, `sig/` directory, or CI integration exist?) and a
483
+ recommended next skill. It is read-only and side-effect-free — it never
484
+ runs `rigor check`. Identical output to `rigor skill describe`.
485
+
486
+ ## `rigor docs`
487
+
488
+ Print the documentation bundled inside the `rigortype` gem
489
+ **offline**, so once Rigor is installed an AI coding agent (or you) can
490
+ read the drive-Rigor guidance the SKILL-driven UX routes to without the
491
+ network ([ADR-74](../adr/74-offline-doc-access-and-llms-txt.md)). It is
492
+ the doc twin of [`rigor skill`](#rigor-skill): the gem ships
493
+ `docs/install.md`, `docs/llms.txt`, and the full user-facing
494
+ [manual](README.md) and [handbook](../handbook/README.md); the
495
+ contributor-facing ADR / spec / notes corpus stays web-only on the site.
496
+
497
+ The positional slot is a doc *name*; alternative outputs are flags.
498
+
499
+ ```sh
500
+ rigor docs [<name>] [--path <name>] [--list [<category>]]
501
+ ```
502
+
503
+ | Form | Purpose |
504
+ | --- | --- |
505
+ | (none) | Print the bundled `llms.txt` offline doc index — the map of what `rigor docs <name>` can serve. |
506
+ | `<name>` | Print a doc page to stdout, prefixed with a provenance comment. Accepts a category-qualified path (`handbook/03-narrowing`), the chapter's prefixed name (`02-cli-reference`), its short name (`cli-reference`, when unique), or `install`. |
507
+ | `--path <name>` | Print the single-line absolute path of a doc, suitable as input to a file-reading tool. |
508
+ | `--list [<category>]` | Table of every bundled doc (name + absolute path); pass `manual` or `handbook` to filter. |
509
+
510
+ The verb spellings `rigor docs list` / `path <name>` are **deprecated**
511
+ (a one-line stderr notice; removed in v0.3.0) — use `--list` / `--path`.
512
+
513
+ The canonical web copy of the index is
514
+ <https://rigor.typedduck.fail/llms.txt>; `rigor docs` serves the same
515
+ pages from the installed gem with no HTTP request.
516
+
517
+ ## `rigor show-bleedingedge`
518
+
519
+ Print the **bleeding-edge overlay** — the Rigor-maintained set of
520
+ the next major's queued diagnostic disciplines ([ADR-50](../adr/50-release-engineering-and-stability-strategy.md)
521
+ § WD2) — and report which of them the project's
522
+ [`bleeding_edge:`](03-configuration.md) configuration adopts. Read-only:
523
+ it loads `.rigor.yml` to resolve the active selection but runs no
524
+ analysis.
525
+
526
+ ```sh
527
+ rigor show-bleedingedge [--config PATH] [--format text|json]
528
+ ```
529
+
530
+ | Flag | Purpose |
531
+ | --- | --- |
532
+ | `--config PATH` | Use this `.rigor.yml` instead of auto-discovery. |
533
+ | `--format text\|json` | Output format. Default `text`. |
534
+
535
+ The overlay is **empty in this release** — the mechanism is wired and
536
+ ready, but no discipline has been queued for a major yet, so the command
537
+ currently reports an empty set. When a feature is queued it appears here
538
+ with its stable id, the severity it would impose, and whether your config
539
+ adopts it. See [`docs/compatibility.md`](../compatibility.md) for how
540
+ bleeding-edge fits the stability model.
541
+
542
+ ## Environment variables
543
+
544
+ Most behaviour is driven by flags and `.rigor.yml`; a few
545
+ operational knobs read the environment instead.
546
+
547
+ | Variable | Effect |
548
+ | --- | --- |
549
+ | `NO_COLOR` | Disable coloured output (honoured by `rigor annotate`; `--no-color` does the same). |
550
+ | `RIGOR_CI_DETECT=0` | Turn off CI auto-detection — the same as `--no-ci-detect`. See [Running Rigor in CI § auto-detection](11-ci.md). |
551
+ | `RIGOR_RACTOR_WORKERS=N` | Worker count for parallel analysis. Sits between the CLI flag and the config key in precedence: `--workers=N` > `RIGOR_RACTOR_WORKERS` > `parallel.workers:` > `0` (sequential). |
552
+ | `RIGOR_POOL_BACKEND=ractor` | Opt back into the (off-by-default) Ractor worker pool instead of the active fork-based pool ([ADR-15](../adr/15-ractor-concurrency.md)). Only relevant with a non-zero worker count; the fork pool is the supported backend. |
553
+ | `RIGOR_PLUGIN_ISOLATION=none\|process\|ruby_box` | How a plugin's direct calls into its target library are isolated. Default `process`. See [Using plugins § Isolation strategy](07-plugins.md). `RIGOR_BOX` is a legacy alias for `ruby_box`. |
554
+
555
+ Three further variables (`RIGOR_BUDGET_TRACE`,
556
+ `RIGOR_HEAP_PROFILE`, `RIGOR_HEAP_TRACE`) enable developer-facing
557
+ diagnostics about Rigor's own inference cutoffs and memory — see
558
+ [Troubleshooting § Advanced diagnostics](13-troubleshooting.md#advanced-diagnostics).
559
+
560
+ ## Exit codes
561
+
562
+ | Code | Meaning |
563
+ | --- | --- |
564
+ | `0` | Success — no error-severity diagnostics. |
565
+ | `1` | Diagnostics found, or a per-command failure (parse error, missing file, new diagnostics on `diff`). |
566
+ | `64` | Usage error — unknown command, bad flag, malformed argument. |
567
+
568
+ `rigor triage` is the exception: it is advisory and always
569
+ exits `0`.