---
name: rigor-project-init
description: >-
  Onboard a project to Rigor from scratch by detecting the stack, selecting plugins and an adoption mode,
  and writing the initial config and baseline or strict gate. Use for first-time Rigor setup; not for an
  existing baseline or plugin authoring.
license: MPL-2.0
metadata:
  version: 0.1.0
  homepage: https://github.com/rigortype/rigor
---

# Rigor Project Init

End-to-end onboarding for a project that has never run Rigor. The
output is a committed `.rigor.dist.yml`, an explicit adoption mode,
and — if the project chooses it — a `.rigor-baseline.yml` snapshot.

This skill is for **users adopting Rigor on their own project**. It
uses the published `rigor` executable, installed standalone — Rigor
is a tool, not a library, so it does **not** go in the project's
`Gemfile`. For the install channels (`mise` recommended) see the
manual's Installing Rigor chapter — `rigor docs manual/01-installation`
once any `rigor` is on `PATH`, or (pre-install)
<https://github.com/rigortype/rigor/blob/master/docs/manual/01-installation.md>. This skill
references only public CLI flags and config keys — the same surface
`rigor --help` documents.

## First: load the version-current copy

This skill's step detail lives in its `references/` files, and its exact
commands, flags, and config keys drift between Rigor releases — so follow
the copy that ships with the **installed** Rigor rather than any vendored
or frozen copy of this file. Get the complete current procedure (body + all
references, inline) in one call:

```sh
rigor skill --full rigor-project-init
```

If you already loaded this skill *via* `rigor skill` you have the current
copy — just proceed. If `rigor` is not on `PATH`, this task needs it: run
**`rigor-next-steps`** to install Rigor first, then come back.

## Phase 0 — When to use this skill

Trigger when the user says "set up Rigor here", "configure rigor for
this app", "add type checking", or runs `rigor check` in a project
that has no `.rigor.yml` / `.rigor.dist.yml`.

Do NOT trigger for:

- **An existing baseline the user wants to shrink** — that is the
  `rigor-baseline-reduce` skill.
- **Writing a Rigor plugin** for the project's own DSL /
  metaprogramming — that is the `rigor-plugin-author` skill. (This
  skill *points at* plugin authoring as an escalation in Phase 8;
  it does not do it.)
- **Tweaking an already-configured project** — ordinary edits to an
  existing `.rigor.yml`; no onboarding pipeline needed.

## Note — plugin installation

All `rigor-*` plugins ship **bundled inside the `rigortype` gem**.
No separate installation is needed. Listing a plugin under
`plugins:` in `.rigor.dist.yml` is sufficient to activate it.
The project's `Gemfile` is untouched by this workflow.
See [`references/02-configure.md`](references/02-configure.md)
§ "No separate installation needed" for detail.

## The central decision — adoption mode

A mature Ruby codebase routinely reports hundreds to thousands of
diagnostics the first time `rigor check` runs. Most are not fresh
bugs: some are real-but-empirically-safe (`T | nil` that production
always initialises), some are project style, a minority are genuine
latent bugs. Forcing every site to zero before adoption blocks
adoption entirely.

So **before writing any config, present the user with two modes**
and let them choose. The mode drives the severity profile, whether a
baseline is generated, and how Phase 8 frames the leftover
diagnostics.

| | **Acknowledge mode** (baseline adoption) | **Strict mode** (no compromise) |
| --- | --- | --- |
| Goal | Adopt Rigor now; make sure *ordinary coding does not increase* the diagnostic count. | Drive the project to zero outstanding diagnostics and keep it there. |
| Today's diagnostics | Snapshotted into `.rigor-baseline.yml`; suppressed as long as the count does not grow. | All surfaced; every one is fixed or consciously suppressed. |
| Hard-to-fix diagnostics | Left in the baseline. The project **trusts its test / spec suite** to cover runtime correctness for those sites — the static `T | nil` reading is worst-case-sound, the suite proves the worst case is not hit. | Fixed, or annotated `# rigor:disable <rule>` with an author-intent reason at the specific line. No blanket suppression. |
| `severity_profile` | `lenient` (or `balanced` for a small project). | `strict`. |
| Best for | **Every project by default** — mature or brand-new, large or small. | Users fluent in both type theory and RBS who opt in and will resolve Rigor's inference gaps themselves. |
| New diagnostics later | Surface immediately — anything beyond the baseline envelope is a regression. | Surface immediately — there is no envelope; every diagnostic is live. |

Both modes give the same core guarantee: **a change that introduces
a new diagnostic is caught.** They differ only in what happens to the
diagnostics that exist *today*. Acknowledge mode parenthesises them
behind a baseline and leans on the test suite; strict mode refuses to
parenthesise anything.

**Recommend acknowledge mode for every project, including new and
small ones.** Rigor's inference still has gaps, so even a fresh
project meets diagnostics on correct code. Under strict mode each one
needs a `sig/` fix, an RBS workaround, or a reasoned
`# rigor:disable` — work that takes type theory and RBS. Without that
knowledge, users rewrite correct code for the tool or scatter
suppressions. Acknowledge mode keeps the same regression guard with an
exit: a new diagnostic still fails the check, and once it is confirmed
as an inference gap, the baseline can absorb it (report the false
positive upstream). `rigor baseline regenerate` rewrites the baseline
from every live diagnostic, so run it only when a whole-project
`rigor check` (no path arguments) shows nothing but confirmed false
positives; otherwise it silences a real
bug alongside them.

Present strict mode as an opt-in for users who know type theory and
RBS, want the zero-diagnostic gate, and accept resolving inference
gaps themselves — never as the recommendation, and never because the
project is new, small, or a library. If the user picks it, tell them
how to move to acknowledge mode later: optionally relax
`severity_profile`, re-run triage, then run Phase 7 (generate a
baseline and wire `baseline:`). The profile change comes first because
it changes which rules fire.

For a large first run (more than ~100 errors), acknowledge mode also
suggests `severity_profile: lenient`; see Phase 4.

Note the ordering: the error count that feeds the `severity_profile`
choice in Phase 4 is only *measured* in
Phase 6's triage run. Any profile written in Phase 4 is therefore
**provisional** — Phase 6 revisits it against the measured count (see
[`references/02-configure.md`](references/02-configure.md)
§ "Severity profile").

## Non-interactive / agent-driven runs

This skill has several ask-the-user points (the mode choice, the RBS
collection install, the final gitignore-and-commit confirmation). A
*delegation* is the user asking, before the run, for the onboarding to
proceed without these questions ("set it up, don't ask me"). An
ordinary request to set Rigor up is not one: ask as usual. Under a
delegation those points resolve without blocking:

- The **mode** the user pre-declared is settled; record it and skip the
  Phase 2 presentation. If the delegation names no mode, choose
  acknowledge mode and say so in the report — never strict.
- Low-risk, reversible, in-repo confirmations (`rbs collection
  install`, the `.gitignore` addition) are covered by the delegation —
  act, and note each self-answer in your report.
- **Never commit or push under a general delegation.** Run the Final
  step's file inventory as a *report* (what was created, what to
  commit) instead of a question, and leave the commits to the user.

## Phase outline

| Phase | What | Reference |
| --- | --- | --- |
| 1 | Detect the project shape (Gemfile / Gemfile.lock walk). | [`references/01-detect.md`](references/01-detect.md) |
| 2 | Present the two adoption modes; record the user's choice. | (this file — § "The central decision") |
| 3 | Select the plugin set matching the detected stack. | [`references/01-detect.md`](references/01-detect.md) |
| 4 | Write `.rigor.dist.yml` — severity profile follows the mode. Verify activation with `rigor plugins`. | [`references/02-configure.md`](references/02-configure.md) |
| 5 | Generate initial RBS sigs; uplift attr_reader precision with `--params=observed`. | [`references/04-sig-uplift.md`](references/04-sig-uplift.md) |
| 6 | Run `rigor triage --format json` to diagnose the diagnostic stream. | [`references/03-baseline-and-bugs.md`](references/03-baseline-and-bugs.md) |
| 6a | **Pre-baseline cleanup** — apply quick fixes that triage diagnosed (`pre_eval:` for monkey-patch hints, `rbs collection install` if still needed). Re-run triage; repeat until the count is stable. | [`references/03-baseline-and-bugs.md`](references/03-baseline-and-bugs.md) § "Phase 6a" |
| 7 | Acknowledge mode only — generate the baseline and wire `baseline:`. | [`references/03-baseline-and-bugs.md`](references/03-baseline-and-bugs.md) |
| 8 | Surface likely real bugs; distinguish sig quality FPs from real bugs; offer escalation paths. | [`references/03-baseline-and-bugs.md`](references/03-baseline-and-bugs.md) |
| 8a | Install the agent type-contract into `AGENTS.md` / `CLAUDE.md`, so an AI contributor sources types from Rigor instead of guessing them. | [`references/06-agent-contract.md`](references/06-agent-contract.md) |
| 9 | Confirm the generated files with the user — what each is, and whether to commit it. | (this file — § "Final step") |

Load each reference when you reach its phase. Phases run in order;
the only branch is Phase 7 (acknowledge mode runs it, strict mode
skips it). Phase 5 is also optional if the project already has a
committed `sig/` directory.

## Reading order — modules

| Module | Read | Covers |
| --- | --- | --- |
| 1 | [`references/01-detect.md`](references/01-detect.md) | **Phases 1 + 3.** Gemfile / Gemfile.lock walk → framework family. The plugin-recommendation table (Rails / dry-rb / Sinatra / RSpec / plain Ruby). RBS-collection presence check. |
| 2 | [`references/02-configure.md`](references/02-configure.md) | **Phase 4.** Severity-profile choice tied to the mode. The `.rigor.dist.yml` template and every key it uses. The `.rigor.dist.yml` vs `.rigor.yml` convention. |
| 3 | [`references/04-sig-uplift.md`](references/04-sig-uplift.md) | **Phase 5.** `rigor sig-gen --write` baseline. `rigor sig-gen --params=observed --write` attr_reader precision uplift. Handling residual `untyped` methods. Committing `sig/`. |
| 4 | [`references/03-baseline-and-bugs.md`](references/03-baseline-and-bugs.md) | **Phases 6–8.** `rigor triage` as the diagnosis layer. Phase 6a pre-baseline cleanup loop (`pre_eval:` for monkey-patch hints, `rbs collection install`). `rigor baseline generate` + wiring `baseline:`. Surfacing likely real bugs; sig quality FP recognition (Struct `call.wrong-arity`, `-> bot` return-type-mismatch, regex-capture `$1` FPs). The two escalation paths — write a project plugin, or open a Rigor issue. |
| 5 | [`references/06-agent-contract.md`](references/06-agent-contract.md) | **Phase 8a.** The one paragraph the project's `AGENTS.md` / `CLAUDE.md` keeps so every agent session sources types from Rigor rather than guessing them. Where to append it, when to create the file, and what never to overwrite. |
| — (optional) | [`references/05-jit-performance.md`](references/05-jit-performance.md) | **Operational, not a phase.** Run speed via a Ruby JIT: Rigor auto-enables YJIT for long runs (~5 s break-even), how to detect JIT support in your install, the override env vars, and why YJIT beats ZJIT for Rigor on Ruby 4.0. Read only when a large project's `rigor check` wall time matters. |

## Escalation paths (Phase 8 preview)

Some diagnostic clusters are neither a quick fix nor honest baseline
material. Two of them have a dedicated answer this skill hands off to:

- **Application-specific metaprogramming** — a project DSL,
  `define_method` factory, `method_missing` accessor, or `class_eval`
  heredoc generator that Rigor cannot follow produces a cluster of
  `call.undefined-method` (or `unresolved-toplevel`). **First decide
  whether `pre_eval:` can fix it** — it resolves only methods written
  as *literal* `def` / `def self.` in a project file. When the methods
  are **generated dynamically** (computed `define_method` names,
  `method_missing`, a `class_eval <<~RUBY … def #{name} … RUBY`
  template), `pre_eval:` walks the file and finds no literal method to
  register, so the cluster *survives*. That residue is the signal that
  the durable fix is a **project-private Rigor plugin** which teaches
  Rigor the DSL's shape. **This is the recommended next step**, and
  Rigor does **not** ship per-application plugins for it — a Redmine
  app's `Setting.define_setting` accessors, an in-house
  `acts_as_*`, etc. are the *project's* plugin to own (ADR-16 §
  Audience: application-specific homegrown DSLs are out of scope for
  the bundled substrate). Surface it and offer to launch the
  **`rigor-plugin-author`** skill (see § "Next step" below).
- **An external gem Rigor does not understand** — a dependency ships
  no RBS and Rigor has no built-in coverage for it. Try
  `rbs collection install` first; if that gem genuinely needs Rigor
  support, **open an issue on the Rigor project** asking for it:
  <https://github.com/rigortype/rigor/issues>.

Neither is a Phase 8 obligation — they are options to *offer* the
user when the triage report points at one of these causes. The
project-DSL handoff is detailed in
[`references/03-baseline-and-bugs.md`](references/03-baseline-and-bugs.md)
§ "Escalation path A".

## Next step — hand off to plugin authoring when a project DSL remains

Onboarding's job ends at a committed config + (acknowledge mode) a
baseline. But if Phase 6a/8 found a **dynamically-generated project
DSL** that `pre_eval:` could not resolve (a `define_method` factory,
`method_missing`, or a `class_eval` heredoc generator), the onboarding
is not *complete* until the user knows the durable fix — a
**project-owned Rigor plugin**, which Rigor does not bundle per app.

Before the final file-confirmation step, when such a cluster exists:
name it and its generator, say plainly that the fix is a project plugin
(not a baseline entry), and **offer to launch the `rigor-plugin-author`
skill** — on the user's confirmation, invoke it (Skill tool). The full
detection-and-handoff recipe is
[`references/03-baseline-and-bugs.md`](references/03-baseline-and-bugs.md)
§ "Escalation path A". The offer is not automatic — the user may
baseline the cluster now and author the plugin later — but never leave
a generated-DSL cluster in the baseline without naming its real fix.

## Final step — confirm the generated files with the user

Onboarding scatters new files across the project root. Before
finishing, present the user with a short message that names **each
file the workflow produced**, says what it is, and recommends
whether to commit it — so the team shares one consistent setup
rather than each developer reinventing it. Do not silently leave the
files for the user to discover.

Run `git status --short` first; only describe files that actually
exist (e.g. `sig/` exists only if Phase 5 ran; `.rigor-baseline.yml`
only in acknowledge mode). For each, give the commit recommendation:

| File | What it is | Commit? |
| --- | --- | --- |
| `.rigor.dist.yml` | The shared project config (Phase 4) — `target_ruby`, `paths:`, `test_paths:`, `plugins:`, `severity_profile:`, and the `baseline:` pointer. The single source of truth every contributor's `rigor check` reads. | **Yes** — it is the shared config; sharing it is the whole point. |
| `.rigor-baseline.yml` | Acknowledge mode only (Phase 7) — the snapshot of today's known diagnostics. Doubles as a record of project state; without it each developer's baseline diverges and the regression guard means different things per machine. | **Yes** — commit it; it documents project state and pins the regression envelope. |
| `sig/` | RBS skeletons from `rigor sig-gen` (Phase 5), if that phase ran. A first-class project artefact — it sharpens inference for everyone. | **Yes** — commit it (see [`references/04-sig-uplift.md`](references/04-sig-uplift.md) § "Commit the sig/ directory"). |
| `.rigor/` (contains `cache/`) | The per-file analysis cache `rigor check` writes to speed up re-runs. Regenerable and machine-local. | **No** — add `.rigor/` to `.gitignore`. |
| `.rigor.yml` | Optional per-developer local override (not written by this skill). Takes precedence over `.rigor.dist.yml`; used to opt out locally (e.g. run without the baseline). | **No** — gitignore it if a developer creates one. |
| `rbs_collection.lock.yaml` | Not a Rigor artefact — but if Phase 1 ran `rbs collection install`, the install may have regenerated this pre-existing project file (e.g. the stdlib gem list for the resolved Ruby). | **Yes**, but flag it separately: it is a change to an existing project file, not part of the Rigor file set. |
| `AGENTS.md` / `CLAUDE.md` | The agent type-contract section added in Phase 8a — "a type you did not obtain from Rigor is a guess". Created only if neither file existed; otherwise this is an appended section in a pre-existing file. | **Yes** — commit it; the point is that every contributor's agent reads the same rule. Flag an appended section separately, as with `rbs_collection.lock.yaml`. |

Recommend the two concrete actions and **ask before doing them**
(both touch the user's repo): (1) add `.rigor/` — and `.rigor.yml`
if present — to `.gitignore`; (2) commit `.rigor.dist.yml`,
`.rigor-baseline.yml`, `sig/`, and the Phase 8a `AGENTS.md` /
`CLAUDE.md` section as the shared Rigor setup. Per the git-safety
default, do not commit on the user's behalf until they confirm.
