rigortype 0.2.1 → 0.2.2

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 (105) 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 +557 -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 +532 -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.rb +25 -3
  89. data/lib/rigor/inference/method_dispatcher/constant_folding.rb +124 -32
  90. data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +37 -6
  91. data/lib/rigor/inference/scope_indexer.rb +87 -89
  92. data/lib/rigor/plugin/isolation.rb +5 -5
  93. data/lib/rigor/plugin/loader.rb +4 -2
  94. data/lib/rigor/version.rb +1 -1
  95. data/skills/rigor-ask/SKILL.md +172 -0
  96. data/skills/rigor-doctor/SKILL.md +87 -0
  97. data/skills/rigor-editor-setup/SKILL.md +114 -0
  98. data/skills/rigor-mcp-setup/SKILL.md +117 -0
  99. data/skills/rigor-monkeypatch-resolve/SKILL.md +79 -0
  100. data/skills/rigor-next-steps/SKILL.md +113 -0
  101. data/skills/rigor-plugin-tune/SKILL.md +79 -0
  102. data/skills/rigor-protection-uplift/SKILL.md +133 -0
  103. data/skills/rigor-rbs-setup/SKILL.md +128 -0
  104. data/skills/rigor-upgrade/SKILL.md +79 -0
  105. metadata +90 -1
@@ -0,0 +1,557 @@
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
+ The **`selectors`** section is the by-(class, method) axis: it
236
+ aggregates the structured `receiver_type` / `method_name` fields the
237
+ diagnostics carry into `{receiver, method, count, files, rules}`
238
+ rows, so you can ask "which method concentrates the diagnostics?"
239
+ without parsing message text. Under `--format json` the full list is
240
+ emitted, keyed on a normalised receiver class (literals fold to their
241
+ class), ready for a `jq` query:
242
+
243
+ ```sh
244
+ # methods with diagnostics spread across ≥ 3 files (systemic clusters)
245
+ rigor triage --format json | jq '.selectors[] | select(.files >= 3)'
246
+ # everything Rigor flagged on String receivers, by method
247
+ rigor triage --format json | jq '[.selectors[] | select(.receiver == "String")]'
248
+ ```
249
+
250
+ The same `receiver_type` / `method_name` fields ride on each
251
+ diagnostic of `rigor check --format json`, for per-site (rather than
252
+ aggregated) grouping.
253
+
254
+ ## `rigor coverage`
255
+
256
+ > For the value proposition and a workflow guide to the
257
+ > `--protection` tiers, see
258
+ > [Type-protection coverage](15-type-protection-coverage.md). This
259
+ > section is the flag reference.
260
+
261
+ Report type-precision coverage — the ratio of call sites that
262
+ resolve to a precise type versus those that fall back to
263
+ `Dynamic`. A quality gate for "how much is Rigor actually
264
+ inferring".
265
+
266
+ ```sh
267
+ rigor coverage [paths]
268
+ ```
269
+
270
+ `--format=text|json` selects the output format and
271
+ `--config=PATH` overrides config discovery. `--threshold=RATIO`
272
+ exits `1` when the precision ratio falls below `RATIO`
273
+ (`0.0`–`1.0`), making it a CI gate.
274
+
275
+ `--protection` switches to **type-protection coverage**: it
276
+ reports "if I introduce a bug, would Rigor catch it" rather than
277
+ "how precise are my types". Each dispatch site (a call with an
278
+ explicit receiver) is *protected* when the receiver types to a
279
+ concrete class (a site where Rigor's call rules can catch a
280
+ wrong method or argument) and *unprotected* when the receiver is
281
+ `Dynamic`. The report leads with the protected ratio, then a
282
+ ranked "add a type here" list (the methods most often called on
283
+ an untyped receiver), then the least-protected files;
284
+ `--threshold` and `--format=json` work the same. It is a sound
285
+ upper bound on real protection — a concrete receiver is necessary
286
+ but not sufficient for a diagnostic to fire.
287
+
288
+ Adding `--mutation` (with `--protection`) switches to the
289
+ **effectiveness** tier: it measures whether Rigor *does* catch a
290
+ bug, rather than whether it *could*. It introduces
291
+ type-visible breakages at each dispatch site — dropping a
292
+ call-argument to `nil`, swapping its type, renaming a call to a
293
+ missing method — re-analyses the mutated source against a clean
294
+ baseline, and reports the kill rate (caught breakages). It
295
+ defaults to the git-changed `.rb` files (whole-project is
296
+ minutes; pass explicit paths to widen), and leads with the
297
+ effectiveness ratio, then the breakages Rigor missed ("add a type
298
+ here"), then the least-effective files. `--threshold` gates on
299
+ the effectiveness ratio and `--format=json` carries `mode`,
300
+ `killed`, `survived`, `effectiveness_ratio`, per-file rows, and
301
+ `add_a_type_here`. It is the truth tier behind the static
302
+ `--protection` proxy, at the cost of many analyses — an opt-in CI
303
+ deep-dive, not an interactive check.
304
+
305
+ ```sh
306
+ rigor coverage --protection --mutation [paths]
307
+ ```
308
+
309
+ Adding `--with-tests` (with `--protection --mutation`) turns
310
+ that into the **fused static∪dynamic** view: for each breakage
311
+ the type checker does *not* catch, it runs your test suite to see
312
+ whether a **test** catches it. Each site is then classified
313
+ `type-protected` (the type checker caught it), `test-protected`
314
+ (a test caught what the type checker missed), or `unprotected`
315
+ (neither — the actionable "add a type **or** a test here" list),
316
+ and the report names the cheaper missing axis. A type-killed
317
+ mutant never reaches the suite (a gradual short-circuit), so the
318
+ cost is proportional to the protection hole. `--format=json`
319
+ carries `mode` (`protection-fused`), `type_killed`,
320
+ `test_killed`, `unprotected`, `protected_ratio`, per-file rows,
321
+ and `add_protection_here`; `--threshold` gates on the fused
322
+ ratio.
323
+
324
+ `--test-command=CMD` is the runner hook (default
325
+ `bundle exec rake`). The suite must pass on clean code first, or
326
+ the run aborts — point it at a plain pass/fail runner (a coverage
327
+ floor that exits non-zero on a passing suite trips this). It runs
328
+ with Bundler's environment stripped, so a `bundle exec` command
329
+ resolves your project's bundle even when Rigor itself was
330
+ launched under its own, with no env wrapper needed. The command
331
+ runs **without a shell** (it is split into an argv and executed
332
+ directly), so shell constructs are not interpreted — including an
333
+ inline `BUNDLE_GEMFILE=… ` prefix. For a non-default Gemfile, set
334
+ it with `bundle config set --local gemfile PATH` (it persists in
335
+ `.bundle/config`) or wrap the command in `bash -c '…'`.
336
+
337
+ `--include-dynamic` extends the overlay to `Dynamic`-receiver
338
+ (untyped) sites, where a test is the only possible protection —
339
+ completing the map to *every* dispatch site rather than only the
340
+ ones Rigor can type-check. Every such site is a type-survivor, so
341
+ it runs the suite far more; it is an explicit opt-in.
342
+
343
+ `--limit=N` (with `--seed=N`, default `1`) caps the measurement
344
+ to a deterministic sample of `N` mutations per file, bounding the
345
+ cost on large files. Per-file ratios then become estimates, noted
346
+ on stderr so `--format=json` stdout stays clean.
347
+
348
+ ```sh
349
+ rigor coverage --protection --mutation --with-tests \
350
+ --test-command "bundle exec rspec" --include-dynamic [paths]
351
+ ```
352
+
353
+ ## `rigor mcp`
354
+
355
+ Run the Rigor MCP (Model Context Protocol) server over stdio,
356
+ so AI coding assistants can call Rigor tools directly. See
357
+ [MCP server](10-mcp-server.md).
358
+
359
+ ```sh
360
+ rigor mcp [--transport=stdio] [--config=PATH]
361
+ ```
362
+
363
+ `stdio` is the only transport. The server is a pure-Ruby
364
+ JSON-RPC 2.0 implementation exposing seven read-only tools:
365
+ `rigor_check`, `rigor_type_of`, `rigor_triage`,
366
+ `rigor_annotate`, `rigor_sig_gen`, `rigor_explain`,
367
+ `rigor_coverage`.
368
+
369
+ ## `rigor lsp` vs `rigor mcp`
370
+
371
+ `lsp` speaks the Language Server Protocol to editors; `mcp`
372
+ speaks the Model Context Protocol to AI assistants. Both run
373
+ over stdio and wrap the same analysis engine.
374
+
375
+ ## `rigor plugins`
376
+
377
+ Report the activation status of every plugin configured in
378
+ `.rigor.yml` — loaded, load-error (with reason), and each
379
+ plugin's declared extension surfaces. See [Plugins](07-plugins.md).
380
+
381
+ ```sh
382
+ rigor plugins [--format=text|json] [--strict] [--capabilities] [--config=PATH]
383
+ ```
384
+
385
+ Without `--strict` the command always exits `0`; with
386
+ `--strict` it exits `1` when any plugin failed to load (a CI
387
+ gate).
388
+
389
+ `--capabilities` switches to the **extension-protocol
390
+ catalogue** ([ADR-37](../adr/37-plugin-interface-segregation.md)):
391
+ a focused, machine-readable map of what each loaded plugin
392
+ contributes — the AST node types its `node_rule`s match, the
393
+ receiver classes its `dynamic_return`s gate on, the methods its
394
+ `type_specifier`s narrow, and the facts it `produces` /
395
+ `consumes`. Combine with `--format=json` for tooling (an AI
396
+ agent can enumerate every plugin's behaviour without reading a
397
+ line of plugin source). The same narrow surfaces also appear in
398
+ the default full report. Not to be confused with the singular
399
+ `rigor plugin`.
400
+
401
+ ## `rigor plugin`
402
+
403
+ Browse the on-disk source of the plugins bundled in the
404
+ toolchain, so you can read a real, working plugin as a worked
405
+ example when authoring your own.
406
+
407
+ ```sh
408
+ rigor plugin <list|path|print|root> [name]
409
+ ```
410
+
411
+ | Subcommand | Purpose |
412
+ | --- | --- |
413
+ | `list` | Table of every bundled plugin and example, name + absolute directory path (default when no subcommand given). |
414
+ | `path <name>` | One-line absolute path to the plugin's directory. |
415
+ | `print <name>` | A header (dir / lib / sig / README paths) followed by the plugin's main source body inlined. |
416
+ | `root` | The `rigortype` gem root and its key subdirectories. |
417
+
418
+ Paths resolve at runtime from the gem location (a documented
419
+ caveat for container / cross-filesystem setups).
420
+
421
+ ## `rigor playground`
422
+
423
+ Start the browser playground (a CodeMirror editor with
424
+ real-time diagnostics). Requires the separate `rigor-playground`
425
+ gem; if it is not installed the command prints an install hint
426
+ and exits `64`.
427
+
428
+ ```sh
429
+ rigor playground
430
+ ```
431
+
432
+ ## `rigor skill`
433
+
434
+ List or print the bundled Agent Skills shipped inside the
435
+ `rigortype` gem, so an AI coding agent installed alongside
436
+ Rigor can discover and follow them without a project-side
437
+ source checkout. See [Skills](08-skills.md).
438
+
439
+ The positional slot is a skill *name*; alternative outputs are flags,
440
+ so a skill can never be shadowed by a verb.
441
+
442
+ ```sh
443
+ rigor skill [<name>] [--path <name>] [--list] [--describe]
444
+ ```
445
+
446
+ | Form | Purpose |
447
+ | --- | --- |
448
+ | (none) / `--list` | Table of every bundled skill (name + absolute path). |
449
+ | `<name>` | Print the `SKILL.md` body to stdout, with a header pointing at the skill's `references/` directory. |
450
+ | `--path <name>` | Print the single-line absolute `SKILL.md` path, suitable as input to a file-reading tool. |
451
+ | `--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. |
452
+
453
+ The verb spellings `rigor skill list` / `print <name>` / `path <name>`
454
+ are **deprecated** (a one-line stderr notice; removed in v0.3.0) — use
455
+ the forms above. `describe` / `--describe` stay first-class.
456
+
457
+ ## `rigor describe`
458
+
459
+ Top-level alias for [`rigor skill describe`](#rigor-skill) — the
460
+ onboarding entry point that recommends the next skill for this project.
461
+ A bare `rigor describe` is the intuitive guess most users reach for
462
+ first, so it is surfaced as its own command ([ADR-73](../adr/73-skill-driven-user-experience.md)
463
+ § WD2).
464
+
465
+ ```sh
466
+ rigor describe
467
+ ```
468
+
469
+ It reports a presence-only project-state probe (does a `.rigor.yml`,
470
+ `.rigor-baseline.yml`, `sig/` directory, or CI integration exist?) and a
471
+ recommended next skill. It is read-only and side-effect-free — it never
472
+ runs `rigor check`. Identical output to `rigor skill describe`.
473
+
474
+ ## `rigor docs`
475
+
476
+ Print the documentation bundled inside the `rigortype` gem
477
+ **offline**, so once Rigor is installed an AI coding agent (or you) can
478
+ read the drive-Rigor guidance the SKILL-driven UX routes to without the
479
+ network ([ADR-74](../adr/74-offline-doc-access-and-llms-txt.md)). It is
480
+ the doc twin of [`rigor skill`](#rigor-skill): the gem ships
481
+ `docs/install.md`, `docs/llms.txt`, and the full user-facing
482
+ [manual](README.md) and [handbook](../handbook/README.md); the
483
+ contributor-facing ADR / spec / notes corpus stays web-only on the site.
484
+
485
+ The positional slot is a doc *name*; alternative outputs are flags.
486
+
487
+ ```sh
488
+ rigor docs [<name>] [--path <name>] [--list [<category>]]
489
+ ```
490
+
491
+ | Form | Purpose |
492
+ | --- | --- |
493
+ | (none) | Print the bundled `llms.txt` offline doc index — the map of what `rigor docs <name>` can serve. |
494
+ | `<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`. |
495
+ | `--path <name>` | Print the single-line absolute path of a doc, suitable as input to a file-reading tool. |
496
+ | `--list [<category>]` | Table of every bundled doc (name + absolute path); pass `manual` or `handbook` to filter. |
497
+
498
+ The verb spellings `rigor docs list` / `path <name>` are **deprecated**
499
+ (a one-line stderr notice; removed in v0.3.0) — use `--list` / `--path`.
500
+
501
+ The canonical web copy of the index is
502
+ <https://rigor.typedduck.fail/llms.txt>; `rigor docs` serves the same
503
+ pages from the installed gem with no HTTP request.
504
+
505
+ ## `rigor show-bleedingedge`
506
+
507
+ Print the **bleeding-edge overlay** — the Rigor-maintained set of
508
+ the next major's queued diagnostic disciplines ([ADR-50](../adr/50-release-engineering-and-stability-strategy.md)
509
+ § WD2) — and report which of them the project's
510
+ [`bleeding_edge:`](03-configuration.md) configuration adopts. Read-only:
511
+ it loads `.rigor.yml` to resolve the active selection but runs no
512
+ analysis.
513
+
514
+ ```sh
515
+ rigor show-bleedingedge [--config PATH] [--format text|json]
516
+ ```
517
+
518
+ | Flag | Purpose |
519
+ | --- | --- |
520
+ | `--config PATH` | Use this `.rigor.yml` instead of auto-discovery. |
521
+ | `--format text\|json` | Output format. Default `text`. |
522
+
523
+ The overlay is **empty in this release** — the mechanism is wired and
524
+ ready, but no discipline has been queued for a major yet, so the command
525
+ currently reports an empty set. When a feature is queued it appears here
526
+ with its stable id, the severity it would impose, and whether your config
527
+ adopts it. See [`docs/compatibility.md`](../compatibility.md) for how
528
+ bleeding-edge fits the stability model.
529
+
530
+ ## Environment variables
531
+
532
+ Most behaviour is driven by flags and `.rigor.yml`; a few
533
+ operational knobs read the environment instead.
534
+
535
+ | Variable | Effect |
536
+ | --- | --- |
537
+ | `NO_COLOR` | Disable coloured output (honoured by `rigor annotate`; `--no-color` does the same). |
538
+ | `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). |
539
+ | `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). |
540
+ | `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. |
541
+ | `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`. |
542
+
543
+ Three further variables (`RIGOR_BUDGET_TRACE`,
544
+ `RIGOR_HEAP_PROFILE`, `RIGOR_HEAP_TRACE`) enable developer-facing
545
+ diagnostics about Rigor's own inference cutoffs and memory — see
546
+ [Troubleshooting § Advanced diagnostics](13-troubleshooting.md#advanced-diagnostics).
547
+
548
+ ## Exit codes
549
+
550
+ | Code | Meaning |
551
+ | --- | --- |
552
+ | `0` | Success — no error-severity diagnostics. |
553
+ | `1` | Diagnostics found, or a per-command failure (parse error, missing file, new diagnostics on `diff`). |
554
+ | `64` | Usage error — unknown command, bad flag, malformed argument. |
555
+
556
+ `rigor triage` is the exception: it is advisory and always
557
+ exits `0`.