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
@@ -183,8 +183,10 @@ module Rigor
183
183
  Plugin.registered_for(newly_registered.first)
184
184
  else
185
185
  raise LoadError.new(
186
- "plugin gem #{entry[:gem].inspect} registered multiple plugins " \
187
- "(#{newly_registered.sort.inspect}); disambiguate with an explicit `id:` field",
186
+ "plugin gem #{entry[:gem].inspect} bundles #{newly_registered.size} plugins " \
187
+ "(#{newly_registered.sort.inspect}) and cannot be activated as a single `plugins:` entry — " \
188
+ "it is a convenience meta-gem. List the individual plugin gems you want in `plugins:` " \
189
+ "(e.g. `rigor-#{newly_registered.min}`), or select one with an explicit `id:` field.",
188
190
  plugin_ref: entry[:gem]
189
191
  )
190
192
  end
@@ -87,12 +87,27 @@ module Rigor
87
87
  GENUINE_BUG_MAX_COUNT = 5 # rule total ≤ N → "likely genuine bug"
88
88
  private_constant :SYSTEMIC_THRESHOLD, :MONKEY_PATCH_MIN_FILES, :GENUINE_BUG_MAX_COUNT
89
89
 
90
+ # WD6 (ADR-23): H5 (systemic cluster) and H6 (genuine bugs) are
91
+ # the only count-based, severity-agnostic recognisers, so they
92
+ # alone risk reading plugin recognition trace (`:info`
93
+ # `*.model-call` / `*.helper`, …) as a "systemic cluster" or a
94
+ # "genuine bug" — frightening working code. They are guarded
95
+ # against `:info` unless `include_info` restores the pre-v0.2.3
96
+ # behaviour. Every other recogniser keys on an error/warning rule
97
+ # (H1/H2/H2K/H4/H7) or intentionally reads an info notice
98
+ # (H3 — the `gem-without-rbs` `rbs.coverage.missing-gem`), so the
99
+ # full pool is correct for them.
100
+ INFO_GUARDED = %i[h5_systemic_cluster h6_genuine_bugs].freeze
101
+ private_constant :INFO_GUARDED
102
+
90
103
  # @param diagnostics [Array<Analysis::Diagnostic>]
104
+ # @param include_info [Boolean] let H5/H6 see `:info` diagnostics
91
105
  # @return [Array<Hint>]
92
- def recognise(diagnostics)
106
+ def recognise(diagnostics, include_info: false)
93
107
  claimed = {}.compare_by_identity
94
108
  recognisers.filter_map do |recogniser|
95
109
  pool = diagnostics.reject { |d| claimed[d] }
110
+ pool = pool.reject { |d| d.severity == :info } if INFO_GUARDED.include?(recogniser) && !include_info
96
111
  hint, matched = send(recogniser, pool)
97
112
  next unless hint
98
113
 
data/lib/rigor/triage.rb CHANGED
@@ -26,21 +26,40 @@ module Rigor
26
26
  # receiver); `files` is the distinct-file count (a systemic vs.
27
27
  # localised signal); `rules` is the per-rule breakdown.
28
28
  Selector = Data.define(:receiver, :method_name, :count, :files, :rules)
29
- Report = Data.define(:summary, :distribution, :selectors, :hotspots, :hints)
29
+ Report = Data.define(:summary, :distribution, :selectors, :hotspots, :hints, :include_info)
30
30
 
31
31
  module_function
32
32
 
33
+ # WD6 (ADR-23): the volume views — distribution / selectors /
34
+ # hotspots — route only the *actionable* diagnostics (error +
35
+ # warning) by default. Plugin-emitted `:info` diagnostics are
36
+ # overwhelmingly recognition trace (`plugin.activerecord.model-call`,
37
+ # `plugin.rails-routes.helper`, …) — positive "Rigor resolved this
38
+ # call" records, not problems — and on a real Rails app they swamp
39
+ # the genuine error/warning signal (the field trip: 257 of 267
40
+ # diagnostics were such trace) and invert the hotspot ranking
41
+ # towards the files with the *most working* code. The summary still
42
+ # reports the full info count, and `include_info: true` (the
43
+ # `--include-info` flag) restores the pre-v0.2.3 behaviour. Hints
44
+ # always see the full stream so the `gem-without-rbs` notice (an
45
+ # info-severity `rbs.coverage.missing-gem`) survives; the
46
+ # count-based H5/H6 recognisers guard against info themselves so
47
+ # recognition trace never reads as a bug.
48
+ #
33
49
  # @param diagnostics [Array<Analysis::Diagnostic>]
34
50
  # @param top [Integer] hotspot-file cap
35
51
  # @param hints [Boolean] run the heuristic catalogue
52
+ # @param include_info [Boolean] route info into the volume views
36
53
  # @return [Report]
37
- def analyze(diagnostics, top: 10, hints: true)
54
+ def analyze(diagnostics, top: 10, hints: true, include_info: false)
55
+ routed = include_info ? diagnostics : diagnostics.reject { |d| d.severity == :info }
38
56
  Report.new(
39
57
  summary: build_summary(diagnostics),
40
- distribution: build_distribution(diagnostics),
41
- selectors: build_selectors(diagnostics),
42
- hotspots: build_hotspots(diagnostics, top),
43
- hints: hints ? Catalogue.recognise(diagnostics) : []
58
+ distribution: build_distribution(routed),
59
+ selectors: build_selectors(routed),
60
+ hotspots: build_hotspots(routed, top),
61
+ hints: hints ? Catalogue.recognise(diagnostics, include_info: include_info) : [],
62
+ include_info: include_info
44
63
  )
45
64
  end
46
65
 
@@ -150,7 +169,11 @@ module Rigor
150
169
  "hotspots" => report.hotspots.map do |h|
151
170
  { "file" => h.file, "count" => h.count, "by_rule" => h.by_rule }
152
171
  end,
153
- "hints" => report.hints.map(&:to_h)
172
+ "hints" => report.hints.map(&:to_h),
173
+ # WD6: false means distribution / selectors / hotspots above
174
+ # exclude `:info` (their counts will not sum to summary.total);
175
+ # the summary's `info` field still reports the full count.
176
+ "include_info" => report.include_info
154
177
  }
155
178
  end
156
179
  end
data/lib/rigor/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rigor
4
- VERSION = "0.2.1"
4
+ VERSION = "0.2.3"
5
5
  end
@@ -0,0 +1,172 @@
1
+ ---
2
+ name: rigor-ask
3
+ description: |
4
+ Rigor is a niche, fast-moving Ruby type checker; its rules, flags, and type behaviour are version-specific, so what you "remember" about it is likely wrong or stale — do NOT answer from memory or guess. For ANY question about Rigor, use this skill and investigate procedurally: run `rigor docs` (handbook + manual, bundled OFFLINE and version-matched), `rigor explain` for a diagnostic id, and for the user's own code `rigor check` / `annotate` / `type-of`, then answer only from what you read. Covers: why a line is flagged or if it's a false positive; the type model (narrowing, refinements, `Dynamic`, RBS); config keys, flags, baselines; comparisons to Sorbet, Steep, mypy, PHPStan; whether it handles Rails, RSpec, or a gem; writing an RBS signature; "what is Rigor / why use it / is it right for us?". Trigger on any Rigor mention seeking understanding — even casual, comparative, or grumbling. Skip only when Rigor isn't mentioned, or it's purely "set it up / fix / reduce it for me" (→ rigor-next-steps).
5
+ license: MPL-2.0
6
+ metadata:
7
+ version: 0.2.0
8
+ homepage: https://github.com/rigortype/rigor
9
+ ---
10
+
11
+ # Ask Rigor anything
12
+
13
+ Someone has a question about Rigor. It might be about a diagnostic, the
14
+ type model, a flag, how Rigor stacks up against another type checker,
15
+ whether Rigor can handle their framework, how to type a method — or just
16
+ "what is this, and should I use it?" Whatever it is, **answer from the
17
+ source, not from memory.**
18
+
19
+ Two things make that easy, and you have both offline:
20
+
21
+ - **Rigor's own docs ship inside the gem.** `rigor docs` serves the full
22
+ handbook and manual, always matching the user's installed version, no
23
+ network. This is the authoritative copy: a rule's exact firing
24
+ condition, a flag's spelling, a config default — all drift release to
25
+ release, and `rigor docs` is the copy that shipped with *this* install,
26
+ so an answer drawn from it cannot disagree with the binary they run.
27
+ - **Rigor can read the user's actual code.** When the question is about
28
+ *their* program — "why is this flagged?", "what type does Rigor see
29
+ here?", "how well-typed is my project?" — `rigor check` / `annotate` /
30
+ `type-of` / `triage` / `coverage` answer from what Rigor inferred. A
31
+ concrete inferred type beats any abstract explanation.
32
+
33
+ This is the user's shortcut: they only ever need to remember two skills —
34
+ **`rigor-next-steps`** ("what should we do next?") and **`rigor-ask`**
35
+ ("answer this about Rigor"). They ask in plain language; *you* turn it
36
+ into the right lookup or analysis so they never have to remember the
37
+ command.
38
+
39
+ ## The toolbox
40
+
41
+ Everything here is read-only and needs no network.
42
+
43
+ ### Reading the docs
44
+
45
+ | Command | Use |
46
+ | --- | --- |
47
+ | `rigor docs` | The offline doc index (`llms.txt`) — the map. Start here when you don't know which page. |
48
+ | `rigor docs --list [manual\|handbook]` | List every bundled page with its path (optionally one category). |
49
+ | `rigor docs <name>` | Print a page. `<name>` is a category-qualified path (`handbook/03-narrowing`), a prefixed basename (`03-narrowing`), or a unique short name (`narrowing`). Pages that exist in **both** trees (e.g. `plugins`) must be qualified — `manual/07-plugins` vs `handbook/09-plugins`. |
50
+ | `rigor explain <rule>` | The catalogue entry for a diagnostic id (`rigor explain call.undefined-method`) — what it means, why it fires, how to address it. |
51
+
52
+ ### Grounding the answer in the user's code
53
+
54
+ | Command | Use |
55
+ | --- | --- |
56
+ | `rigor check <path>` | Run the analysis. Scope it to a file or directory for a quick answer — don't analyse the whole project just to settle one question. `--format json` exposes structured fields (`receiver_type`, `method_name`, `evidence_tier`, …). |
57
+ | `rigor annotate <file>` | Reprint the file with the inferred type of each line in the margin — *what Rigor actually sees*. |
58
+ | `rigor type-of <file>:<line>:<col>` | The inferred type at one position. |
59
+ | `rigor triage` | Cluster the project's diagnostics by rule / receiver / method — for "what's the shape of my errors?". |
60
+ | `rigor coverage [--protection]` | Type / type-protection coverage — for "how well-typed is this?" and "where are the holes?". |
61
+ | `rigor plugins` | Which plugins are installed and enabled *here* — the honest answer to "does Rigor support <gem/framework>?". |
62
+ | `rigor sig-gen <path>` | Generate RBS for code — for "how do I type this?". Offer it and show the result; this project prefers sig-gen over hand-written RBS. |
63
+
64
+ ## Where the answer lives
65
+
66
+ Classify the question, then go to the page(s) — and, for anything about
67
+ *their* code, the command(s) — that own it. When unsure where a page is,
68
+ `rigor docs` (the index) or `rigor docs --list handbook` routes you.
69
+
70
+ | The question is about… | Go to |
71
+ | --- | --- |
72
+ | **A specific diagnostic** — "why is this flagged?", "what does this error mean?", "is this a false positive?" | `rigor explain <rule>`, then `rigor docs diagnostics`. If it's *their* code, also `rigor annotate <file>` / `rigor type-of` to see the inferred types the rule fired on. |
73
+ | **The type model / a concept** — narrowing, refinements, tuple & hash shapes, `Dynamic`, RBS interop, lightweight HKT | The handbook: `rigor docs --list handbook`, then the chapter — `handbook/03-narrowing`, `04-tuples-and-shapes`, `07-rbs-and-extended`, `12-lightweight-hkt`, … |
74
+ | **Operating Rigor** — a config key, CLI flag, baseline, plugins, CI, caching | The manual: `rigor docs configuration`, `cli-reference`, `baseline`, `manual/07-plugins`, `ci`, `caching`, `troubleshooting`. |
75
+ | **How Rigor compares to another tool** — Sorbet, Steep, RBS, TypeScript, mypy, PHPStan, TypeProf, Go, Rust, Java/C# | The chapter/appendix written for exactly that: `handbook/10-sorbet`, `appendix-steep`, `appendix-typescript`, `appendix-mypy`, `appendix-phpstan`, `appendix-typeprof`, `appendix-rust`, `appendix-go`, `appendix-java-csharp` (`rigor docs --list handbook` shows them all). |
76
+ | **Whether Rigor can do X** — generics, Rails, RSpec, a specific gem, concurrency | The handbook for the language feature; for framework/gem support, **`rigor plugins`** (what's actually available in *this* install) plus the per-plugin page `rigor docs rigor-<gem>` (e.g. `rigor docs rigor-sidekiq`) and the catalogue `rigor docs --list manual`. |
77
+ | **Writing a type / RBS** — "how do I type this?", an annotation, a signature | Handbook `07-rbs-and-extended` + `11-sig-gen`; manual `rbs-extended-annotations`. Then offer `rigor sig-gen <path>` to generate it (preferred over hand-RBS) and show the output. |
78
+ | **What Rigor is / why use it / is it right for me** | Handbook `01-getting-started` for the pitch, `handbook/02-everyday-types` for a quick mental model of the type zoo. Ground "is it right for *my* project" in a scoped `rigor check` / `rigor coverage` so they see Rigor on their real code. |
79
+
80
+ ## Answer from the page, name the page
81
+
82
+ Quote or paraphrase the relevant passage and **say which page you drew
83
+ from** (e.g. "per `rigor docs handbook/03-narrowing` …"), so the user can
84
+ re-read it with the same command. Prefer the doc's own wording over a
85
+ remembered approximation. When you ran a command against their code, show
86
+ the relevant line of output — a concrete inferred type is more convincing
87
+ than prose, and it proves the answer rather than asserting it.
88
+
89
+ ## When the question is really "do X for me"
90
+
91
+ Some questions are a task in disguise: *"how do I get Rigor into CI?"*,
92
+ *"how do I shrink this baseline?"*, *"how do I set Rigor up here?"* The
93
+ useful reply is **short**: orient the user — what the thing is, the one
94
+ decision that actually matters, the rough shape of it — then **hand the
95
+ doing to the skill built for it.** Resist pasting the full procedure
96
+ inline (the entire CI workflow YAML, the whole baseline-reduction loop):
97
+ that skill owns the steps, keeps them correct, and updates as the tool
98
+ moves, so duplicating them here only bloats the answer and drifts out of
99
+ date. The line is *explaining* the thing (yours) versus *wiring it in*
100
+ (the setup skill's).
101
+
102
+ A good hand-off is two or three sentences of orientation plus the pointer:
103
+
104
+ - setup / "what next?" → **`rigor-next-steps`** (it probes the project and routes)
105
+ - CI → **`rigor-ci-setup`** · editor → **`rigor-editor-setup`** · MCP agent → **`rigor-mcp-setup`**
106
+ - baseline reduction → **`rigor-baseline-reduce`** · coverage holes → **`rigor-protection-uplift`**
107
+ - a missing gem/DSL → **`rigor-plugin-author`** · monkey-patch clusters → **`rigor-monkeypatch-resolve`**
108
+
109
+ When in doubt, give less and point — it respects the user's "two skills
110
+ to remember" promise and keeps each answer to the part only `rigor-ask`
111
+ can give.
112
+
113
+ ## If the docs don't cover it
114
+
115
+ The bundled set is the **drive-Rigor** corpus (manual + handbook). The
116
+ normative **type specification**, the internal spec, and the ADRs are
117
+ contributor-facing and stay web-only — they are *not* in `rigor docs`; if
118
+ a question genuinely needs them, say so and point at
119
+ <https://rigor.typedduck.fail/llms.txt> rather than guessing.
120
+
121
+ But before you defer, remember Rigor installs from RubyGems **with its
122
+ full source** — the per-plugin pages under the gem's `docs/manual/plugins/`,
123
+ the analyzer and plugin code under `lib/`. For a detail no doc page spells
124
+ out (a plugin's exact rule, a default baked into the code), reading the
125
+ bundled file directly is a perfectly good way to ground the answer, and
126
+ beats a guess. The rule that never bends: **never invent a flag, rule id,
127
+ config key, behaviour, or command output** — read the page, read the
128
+ source, or run the command, and quote only output you actually saw. A
129
+ confident wrong answer about a type checker is worse than "let me check."
130
+
131
+ ## Examples
132
+
133
+ **A diagnostic on their code** — *"Why is Rigor flagging `s.lenght`?"*
134
+
135
+ ```sh
136
+ rigor explain call.undefined-method # what the rule means and why it fires
137
+ rigor annotate demo.rb # the inferred type of `s` on that line
138
+ ```
139
+
140
+ Answer from both: Rigor inferred a concrete `String` receiver for `s`,
141
+ and `String` has no `lenght` (a typo for `length`) — grounded in what
142
+ `annotate` showed, not in a guess.
143
+
144
+ **A comparison** — *"How is Rigor different from Sorbet?"*
145
+
146
+ ```sh
147
+ rigor docs handbook/10-sorbet # the chapter written for this
148
+ ```
149
+
150
+ Answer from the chapter's framing (RBS-superset, gradual `Dynamic`,
151
+ inference-first) rather than a remembered summary, and name it so they
152
+ can read on.
153
+
154
+ **A capability** — *"Does Rigor understand our Sidekiq workers?"*
155
+
156
+ ```sh
157
+ rigor plugins # is rigor-sidekiq enabled in THIS project?
158
+ rigor docs rigor-sidekiq # the per-plugin page: what it teaches Rigor
159
+ ```
160
+
161
+ Answer from what's actually installed, plus — if useful — a scoped
162
+ `rigor check app/workers` so they see Rigor on their real workers.
163
+
164
+ **Authoring** — *"How do I type this method?"*
165
+
166
+ ```sh
167
+ rigor sig-gen path/to/file.rb # generate the RBS, show it
168
+ rigor docs handbook/07-rbs-and-extended
169
+ ```
170
+
171
+ Generate it, show the signature, and explain it from the handbook —
172
+ preferring sig-gen's output over hand-written RBS.
@@ -0,0 +1,87 @@
1
+ ---
2
+ name: rigor-doctor
3
+ description: |
4
+ Validate that a project's Rigor setup is actually healthy — config parses with no silently-inert values, every configured plugin loads, the baseline is not stale, and the bundled paths resolve — by running Rigor's existing validators and interpreting them. Triggers: "is my Rigor setup correct?", "check my rigor config", "rigor diagnostics look wrong / suspicious", "validate rigor setup", "why is rigor reporting nothing / everything?". NOT for first-time setup (use rigor-project-init) or for working real diagnostics down (use rigor-baseline-reduce).
5
+ license: MPL-2.0
6
+ metadata:
7
+ version: 0.1.0
8
+ homepage: https://github.com/rigortype/rigor
9
+ ---
10
+
11
+ # Rigor Doctor
12
+
13
+ `rigor skill describe` reports what *exists* (presence checks). This skill
14
+ goes a level deeper: it *runs* Rigor's validators to confirm the setup is
15
+ actually working — the difference between "a `.rigor.yml` is present" and
16
+ "it parses, loads its plugins, and analyses the right files." Use it when
17
+ the diagnostics look wrong (suspiciously zero, or suspiciously many) or
18
+ after editing the config.
19
+
20
+ It needs **no special command** — it orchestrates checks Rigor already
21
+ ships and interprets the results.
22
+
23
+ ## Checks
24
+
25
+ ### 1. Config resolves with nothing silently inert
26
+
27
+ ```sh
28
+ rigor check --format json # read the `config_warnings` array
29
+ ```
30
+
31
+ `rigor check` audits the config and emits `config_warnings` for the typo
32
+ class whose only symptom is a confusing downstream error: a
33
+ `signature_paths:` that is missing / not a directory / holds no `.rbs`
34
+ (which would turn every covered call into a false `call.undefined-method`
35
+ at `evidence_tier: high`), a `libraries:` name RBS does not recognise, a
36
+ `disable:` / `severity_overrides:` id naming no real rule, or a missing
37
+ `bundler` / `rbs_collection` path. **Each warning here is a real
38
+ misconfiguration — fix it.** None appearing is the healthy state.
39
+
40
+ ### 2. Every configured plugin loads
41
+
42
+ ```sh
43
+ rigor plugins --strict
44
+ ```
45
+
46
+ Reports the activation status of each plugin in `plugins:`; `--strict`
47
+ exits non-zero on any failure. A failure is usually a misspelled id or a
48
+ plugin whose `signature_paths:` did not resolve. Fix it, or the plugin's
49
+ type knowledge is silently absent.
50
+
51
+ ### 3. The baseline is not stale (if one exists)
52
+
53
+ ```sh
54
+ rigor baseline drift
55
+ ```
56
+
57
+ Shows whether the live diagnostics have drifted from `.rigor-baseline.yml`
58
+ — entries the baseline ignores that no longer occur (safe to prune) and
59
+ new diagnostics outside the envelope. A large drift means the baseline
60
+ needs regenerating (often after an upgrade — see `rigor-upgrade`).
61
+
62
+ ### 4. The analysis is actually seeing your code
63
+
64
+ ```sh
65
+ rigor check --format json # check the "Ruby source files" count
66
+ ```
67
+
68
+ If the file count is `0` or far below your project size, `paths:` /
69
+ `exclude:` are mis-scoped, or the command is running from the wrong
70
+ directory. The analysis is only as good as the files it reads.
71
+
72
+ ## Interpreting the result
73
+
74
+ - **All clean** → the setup is healthy; any diagnostics are about the
75
+ code, not the configuration. Move on to `rigor-baseline-reduce` or
76
+ `rigor-protection-uplift`.
77
+ - **A `config_warning` or a plugin failure** → that is the real problem;
78
+ fixing it usually resolves a whole cluster of confusing downstream
79
+ diagnostics at once.
80
+
81
+ For deeper symptoms (hover shows `untyped` everywhere, completion empty,
82
+ LSP silent) see the manual's troubleshooting:
83
+ <https://github.com/rigortype/rigor/blob/master/docs/manual/13-troubleshooting.md>
84
+
85
+ ## Next step
86
+
87
+ Re-run `rigor skill describe` for the recommended next move.
@@ -0,0 +1,114 @@
1
+ ---
2
+ name: rigor-editor-setup
3
+ description: |
4
+ Wire Rigor's bundled language server (`rigor lsp`) into the developer's editor for live diagnostics, hover-to-type, outline, and type-aware completion. The per-editor config snippets live in the manual; this skill identifies the editor, applies the right one, and verifies the server attaches. Triggers: "set up Rigor in my editor", "rigor LSP / language server", "live Rigor diagnostics in VS Code / Neovim / Helix / Emacs", "hover types in my editor". NOT for CI integration (use rigor-ci-setup) or first-time project setup (use rigor-project-init).
5
+ license: MPL-2.0
6
+ metadata:
7
+ version: 0.1.0
8
+ homepage: https://github.com/rigortype/rigor
9
+ ---
10
+
11
+ # Rigor Editor Setup
12
+
13
+ `rigor lsp` is the in-process Language Server bundled with the
14
+ `rigortype` gem. It speaks LSP over stdio and turns Rigor's analyzer
15
+ into a live editor experience: diagnostics as you type, hover-to-type,
16
+ an outline view, and type-aware completion. This skill wires it into the
17
+ developer's editor.
18
+
19
+ The authoritative, per-editor configuration lives in the manual. With
20
+ Rigor installed, read it **offline** with no network round-trip:
21
+
22
+ ```sh
23
+ rigor docs editor-integration
24
+ ```
25
+
26
+ (Web fallback, only before Rigor is installed:
27
+ **[Rigor LSP — Editor Integration](https://github.com/rigortype/rigor/blob/master/docs/manual/09-editor-integration.md)**.)
28
+ This skill is the *workflow* around it (identify the editor → apply the
29
+ manual's snippet → verify), so it does not duplicate (and cannot
30
+ stale-out) the config details.
31
+
32
+ ## When to use
33
+
34
+ - A developer wants Rigor feedback live in their editor, not just from
35
+ `rigor check` on the command line.
36
+ - A project commits a shared editor config (e.g. `.vscode/`) and you want
37
+ to add Rigor's LSP to it so the whole team gets it.
38
+
39
+ ## When NOT to use
40
+
41
+ - Wiring Rigor into CI — that is `rigor-ci-setup`.
42
+ - The project has no Rigor config yet — run `rigor-project-init` first
43
+ (the LSP uses the same `.rigor.yml` discovery as `rigor check`).
44
+
45
+ ## The one stable fact
46
+
47
+ Every editor snippet simply launches **`rigor lsp`** (stdio) and needs
48
+ **`rigor` on the editor's `PATH`** — the same executable `rigor check`
49
+ uses. For GUI editors that do not inherit your shell, the `mise` shim
50
+ path is the most reliable channel (see `rigor docs install`, or
51
+ [Installing Rigor](https://github.com/rigortype/rigor/blob/master/docs/install.md)
52
+ on the web). Do **not** add `rigortype` to the project's `Gemfile` — it
53
+ is a tool, not a library.
54
+
55
+ ## Procedure
56
+
57
+ ### Phase 1 — confirm the analyzer works from the CLI first
58
+
59
+ ```sh
60
+ rigor check <a-file-or-dir>
61
+ ```
62
+
63
+ The LSP shares `rigor check`'s config discovery and analysis. If `check`
64
+ works from the project root, the LSP will too; if it fails, fix that
65
+ first — the editor would only surface the same failure.
66
+
67
+ ### Phase 2 — identify the editor
68
+
69
+ Ask the developer which editor they use, or detect it (a committed
70
+ `.vscode/`, a Neovim `init.lua`, `~/.config/helix/`, an Emacs config).
71
+ The manual chapter covers:
72
+
73
+ - **Neovim** (nvim-lspconfig)
74
+ - **VS Code** (generic LSP-client wrapper / minimal extension)
75
+ - **Helix** (`languages.toml`)
76
+ - **Emacs** (Eglot and lsp-mode)
77
+
78
+ ### Phase 3 — apply the matching config
79
+
80
+ Open the manual's **Editor wiring** section and apply the snippet for
81
+ the developer's editor verbatim:
82
+
83
+ ```sh
84
+ rigor docs editor-integration
85
+ ```
86
+
87
+ (or, pre-install, the web copy:
88
+ <https://github.com/rigortype/rigor/blob/master/docs/manual/09-editor-integration.md>)
89
+
90
+ All snippets invoke `rigor lsp` directly. (Only if the project still
91
+ uses a legacy bundler-local install do you swap in
92
+ `bundle exec rigor lsp` — the manual notes this per editor.)
93
+
94
+ If the project commits a shared editor config (e.g. `.vscode/`), add the
95
+ Rigor LSP wiring there and commit it, so every contributor gets the same
96
+ setup rather than configuring it individually.
97
+
98
+ ### Phase 4 — verify
99
+
100
+ Open a Ruby file inside a Rigor-configured project and confirm:
101
+
102
+ - diagnostics appear (on save / as you type), and
103
+ - hover over a method or local shows its inferred type.
104
+
105
+ If the server starts but nothing appears, work the manual's
106
+ **Troubleshooting** section (most often: `rigor` not on the editor's
107
+ PATH, or no `.rigor.yml` at the project root). Capture the LSP log with
108
+ `rigor lsp --log=/tmp/rigor-lsp.log` when filing an issue.
109
+
110
+ ## Next step
111
+
112
+ Re-run `rigor skill describe` for the next move — with live feedback in
113
+ the editor, raising protection (`rigor-protection-uplift`) or reducing a
114
+ baseline (`rigor-baseline-reduce`) is a tighter loop.
@@ -0,0 +1,117 @@
1
+ ---
2
+ name: rigor-mcp-setup
3
+ description: |
4
+ Wire Rigor's bundled MCP server (`rigor mcp`) into an AI coding agent (Claude Code, Claude Desktop, Cursor, Cline) so the agent can call Rigor's read-only analysis tools — rigor_check, rigor_type_of, rigor_triage, rigor_coverage, and more — during a session. The per-client config lives in the manual; this skill identifies the client, applies the right one, and verifies the handshake. Triggers: "set up rigor mcp", "give my AI agent Rigor tools", "wire Rigor into Claude Code / Cursor / Cline", "rigor MCP server". NOT for editor LSP integration (use rigor-editor-setup) or CI (use rigor-ci-setup).
5
+ license: MPL-2.0
6
+ metadata:
7
+ version: 0.1.0
8
+ homepage: https://github.com/rigortype/rigor
9
+ ---
10
+
11
+ # Rigor MCP Setup
12
+
13
+ `rigor mcp` is the Model Context Protocol server bundled with the
14
+ `rigortype` gem. It exposes Rigor's analysis as JSON-RPC tool calls over
15
+ stdio, so an AI coding agent can call Rigor directly during a session —
16
+ check types before a refactor, look up the type at a cursor, or triage a
17
+ project's diagnostics as review context. All tools are **read-only**
18
+ (write-side commands like `rigor init` / `sig-gen --write` are
19
+ deliberately excluded — modifying files stays the developer's call).
20
+
21
+ The authoritative, per-client configuration lives in the manual. With
22
+ Rigor installed, read it **offline** with no network round-trip:
23
+
24
+ ```sh
25
+ rigor docs mcp-server
26
+ ```
27
+
28
+ (Web fallback, only before Rigor is installed:
29
+ **[Rigor MCP Server — AI Agent Integration](https://github.com/rigortype/rigor/blob/master/docs/manual/10-mcp-server.md)**.)
30
+ This skill is the *workflow* around it (identify the client → apply the
31
+ manual's snippet → verify the handshake), so it does not duplicate (and
32
+ cannot stale-out) the config details.
33
+
34
+ ## When to use
35
+
36
+ - A developer wants their AI agent to call Rigor's tools mid-session.
37
+ - A project commits a shared MCP config (`.mcp.json`, `.cursor/mcp.json`)
38
+ and you want to add Rigor to it for the whole team.
39
+
40
+ ## When NOT to use
41
+
42
+ - Editor (human) integration — that is `rigor-editor-setup` (`rigor lsp`).
43
+ - The project has no Rigor config yet — run `rigor-project-init` first
44
+ (the MCP tools use the same `.rigor.yml` discovery as `rigor check`).
45
+
46
+ ## The tools you are wiring in
47
+
48
+ `rigor_check`, `rigor_type_of`, `rigor_triage`, `rigor_annotate`,
49
+ `rigor_sig_gen`, `rigor_explain`, `rigor_coverage` — each the JSON form
50
+ of the matching `rigor` CLI command. See the manual's **Tool reference**
51
+ for inputs and outputs.
52
+
53
+ ## The one stable fact
54
+
55
+ Every client config simply launches **`rigor mcp`** (stdio) and needs
56
+ **`rigor` on the agent's `PATH`** — the same executable `rigor check`
57
+ uses. For agents that do not inherit your shell, the `mise` shim path is
58
+ the most reliable channel (see `rigor docs install`, or
59
+ [Installing Rigor](https://github.com/rigortype/rigor/blob/master/docs/install.md)
60
+ on the web). Do **not** add `rigortype` to the project's `Gemfile` — it
61
+ is a tool, not a library.
62
+
63
+ ## Procedure
64
+
65
+ ### Phase 1 — confirm the analyzer works from the CLI first
66
+
67
+ ```sh
68
+ rigor check <a-file-or-dir>
69
+ ```
70
+
71
+ The MCP tools share `rigor check`'s config discovery. If `check` works
72
+ from the project root, the tools will too.
73
+
74
+ ### Phase 2 — identify the client and apply the config
75
+
76
+ Ask the developer which agent they use, or detect a committed config
77
+ (`.mcp.json`, `.cursor/mcp.json`, `.claude/settings.json`). Apply the
78
+ matching snippet from the manual's **Client wiring** section verbatim —
79
+ it covers Claude Desktop, Claude Code CLI, Cursor, Cline, and a generic
80
+ stdio client:
81
+
82
+ ```sh
83
+ rigor docs mcp-server
84
+ ```
85
+
86
+ (or, pre-install, the web copy:
87
+ <https://github.com/rigortype/rigor/blob/master/docs/manual/10-mcp-server.md>)
88
+
89
+ Each snippet is the same shape — `{"command": "rigor", "args": ["mcp"]}`.
90
+ If the project commits a shared MCP config, add the Rigor entry there and
91
+ commit it so every contributor gets it.
92
+
93
+ **Working-directory gotcha (from the manual's Troubleshooting):** the
94
+ server discovers config from the directory it is launched in. If the
95
+ client starts `rigor mcp` from `$HOME` or a temp dir, no `.rigor.yml` is
96
+ found and tools return an empty set. Pin it with
97
+ `"args": ["mcp", "--config=/abs/path/.rigor.yml"]`, or pass absolute
98
+ `paths` in the tool call.
99
+
100
+ ### Phase 3 — verify the handshake
101
+
102
+ Confirm `rigor mcp` answers the MCP `initialize` request:
103
+
104
+ ```sh
105
+ echo '{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"0"}}}' | rigor mcp
106
+ ```
107
+
108
+ A JSON `result` with `serverInfo.name: "rigor"` means it works; nothing
109
+ or a shell error means `rigor` is not on the PATH the client uses. Then
110
+ restart the client and confirm the `rigor_*` tools appear in its tool
111
+ palette.
112
+
113
+ ## Next step
114
+
115
+ Re-run `rigor skill describe` for the next move — with the agent able to
116
+ call Rigor's tools, raising protection (`rigor-protection-uplift`) or
117
+ reducing a baseline (`rigor-baseline-reduce`) is a tighter loop.