rails-ai-context 5.32.1 → 5.32.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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +74 -0
  3. data/CONTEXT.md +10 -8
  4. data/CONTRIBUTING.md +2 -2
  5. data/README.md +14 -11
  6. data/SECURITY.md +4 -4
  7. data/docs/ARCHITECTURE.md +11 -10
  8. data/docs/CLI.md +33 -7
  9. data/docs/COMPATIBILITY.md +48 -32
  10. data/docs/CONFIGURATION.md +10 -8
  11. data/docs/CUSTOM_TOOLS.md +8 -8
  12. data/docs/FAQ.md +6 -5
  13. data/docs/GUIDE.md +154 -80
  14. data/docs/INTROSPECTORS.md +24 -16
  15. data/docs/QUICKSTART.md +14 -3
  16. data/docs/RECIPES.md +50 -40
  17. data/docs/SECURITY.md +23 -13
  18. data/docs/SETUP.md +23 -26
  19. data/docs/STANDALONE.md +7 -3
  20. data/docs/TOOLS.md +79 -45
  21. data/docs/TROUBLESHOOTING.md +12 -11
  22. data/exe/rails-ai-context +8 -4
  23. data/lib/generators/rails_ai_context/install/install_generator.rb +1 -1
  24. data/lib/rails_ai_context/configuration.rb +2 -2
  25. data/lib/rails_ai_context/install/ai_tool.rb +11 -2
  26. data/lib/rails_ai_context/install/cleanup.rb +69 -23
  27. data/lib/rails_ai_context/install/program.rb +4 -1
  28. data/lib/rails_ai_context/install/selection_record.rb +20 -2
  29. data/lib/rails_ai_context/serializers/opencode_rules_serializer.rb +2 -2
  30. data/lib/rails_ai_context/server.rb +2 -2
  31. data/lib/rails_ai_context/tasks/rails_ai_context.rake +12 -4
  32. data/lib/rails_ai_context/test_helper.rb +2 -0
  33. data/lib/rails_ai_context/tools/base_tool.rb +3 -1
  34. data/lib/rails_ai_context/tools/dependency_graph.rb +2 -2
  35. data/lib/rails_ai_context/tools/get_concern.rb +1 -1
  36. data/lib/rails_ai_context/tools/get_env.rb +1 -1
  37. data/lib/rails_ai_context/tools/get_gems.rb +2 -2
  38. data/lib/rails_ai_context/tools/query.rb +107 -39
  39. data/lib/rails_ai_context/tools/search_code.rb +20 -16
  40. data/lib/rails_ai_context/version.rb +1 -1
  41. data/server.json +1 -1
  42. metadata +1 -1
data/docs/STANDALONE.md CHANGED
@@ -24,14 +24,18 @@ rails-ai-context init
24
24
  ```
25
25
 
26
26
  Interactive setup asks:
27
- 1. Which AI tools? (Claude, Cursor, Copilot, OpenCode, Codex, or all)
28
- 2. MCP or CLI mode?
27
+ 1. Which AI tools? (Claude, Cursor, Copilot, OpenCode, Codex, or all; an empty answer selects all five)
28
+ 2. What should it write? (MCP config + context files, context files only for CLI mode, or MCP config only)
29
+
30
+ On a re-run that drops a tool, it also asks whether to remove that tool's files. Unlike the install generator, `init` has no pre-commit hook prompt and no `--defaults` flag. The steps are listed in [What the install generator does](GUIDE.md#what-the-install-generator-does).
29
31
 
30
32
  Creates:
31
33
  - `.rails-ai-context.yml` - YAML configuration
32
34
  - MCP config files for selected AI tools
33
35
  - Context files for selected AI tools
34
36
 
37
+ It does not create `config/initializers/rails_ai_context.rb`.
38
+
35
39
  ## Usage
36
40
 
37
41
  ```bash
@@ -141,7 +145,7 @@ bundle remove rails-ai-context
141
145
  rails-ai-context init
142
146
  ```
143
147
 
144
- The MCP config files are updated automatically. Both modes generate identical context files and provide the same 45 tools.
148
+ The MCP config files are updated automatically. Both modes generate the same set of context files and provide the same 45 tools. The commands named inside the files follow the install mode.
145
149
 
146
150
  Both also take `--mcp-only`, which writes the MCP config and no context files
147
151
  at all. See [CONFIGURATION.md](CONFIGURATION.md#mcp-only).
data/docs/TOOLS.md CHANGED
@@ -43,7 +43,7 @@ Tool name resolution is flexible - all of these work:
43
43
  | `get_schema` | `rails_get_schema` |
44
44
  | `rails_get_schema` | `rails_get_schema` |
45
45
 
46
- Individual lookup tools accept a **`detail`** parameter: `summary` (compact), `standard` (default), or `full` (everything). Start with summary, drill down as needed. Composite tools (`rails_get_context`, `rails_analyze_feature`) do not accept `detail`.
46
+ Most lookup tools accept a **`detail`** parameter: `summary` (compact), `standard` (default), or `full` (everything). Start with summary, drill down as needed. Composite tools (`rails_get_context`, `rails_analyze_feature`) do not accept `detail`.
47
47
 
48
48
  <p align="right"><a href="#table-of-contents">↑ back to top</a></p>
49
49
 
@@ -87,7 +87,7 @@ Search your codebase with regex, ripgrep acceleration, and sensitive file blocki
87
87
 
88
88
  The header counts matches, not emitted lines, so below the cap it does not move with `context_lines`. When the search hits `max_search_results` (a cap on emitted lines) the header says `first N lines scanned` and marks the count `N+`: it is then the matches among the lines that were scanned, a floor rather than the total, so it falls as `context_lines` grows. `offset` and `limit` count lines, so a search with context returns more lines than matches. A limit smaller than one match's context block would hold only context, so the page starts at the next match instead and says so.
89
89
 
90
- > **Trace mode** returns definition + source code + every caller grouped by type + tests - replaces 4-5 sequential file reads.
90
+ > **Trace mode** returns definition + source code + every caller grouped by file and labelled by type + tests - replaces 4-5 sequential file reads.
91
91
 
92
92
  Without ripgrep on the PATH, the Ruby fallback returns the rows ripgrep would, context lines and the line cap included, from the files ripgrep would search: no hidden files, no symlinks followed, no binary files (a NUL byte in the first 64 KiB), and ignore files read with ripgrep's precedence, where the file type decides before depth: any `.rgignore`, then any `.ignore`, then any `.gitignore`, then `.git/info/exclude`, then the global excludes file, the deepest file first within a type. `.ignore` and `.rgignore` apply everywhere, including the directories above the app; the git files apply only inside a repository and only as far up as the nearest `.git` (a file for a worktree or submodule), whose `info/exclude` is the only one read. Patterns match case-sensitively.
93
93
 
@@ -100,8 +100,8 @@ Method-aware code extraction with surrounding class context. Every line returned
100
100
  | Parameter | Type | Default | Description |
101
101
  |:----------|:-----|:--------|:------------|
102
102
  | `file` | string | *required* | File path relative to Rails root |
103
- | `method_name` | string | - | Extract a specific method |
104
- | `line` | integer | - | Center extraction around a line number |
103
+ | `near` | string | *required* | What to find in the file: a method name, keyword or string (e.g. `def index`, `validates`, `STATUSES`) |
104
+ | `context_lines` | integer | `5` | Lines of context above and below the match |
105
105
 
106
106
  <p align="right"><a href="#table-of-contents">↑ back to top</a></p>
107
107
 
@@ -116,7 +116,6 @@ Full-stack feature analysis: models + controllers + routes + services + admin re
116
116
  | Parameter | Type | Default | Description |
117
117
  |:----------|:-----|:--------|:------------|
118
118
  | `feature` | string | *required* | Feature name (e.g., `billing`, `auth`, `subscription`) |
119
- | `detail` | enum | `standard` | `summary`, `standard`, `full` |
120
119
 
121
120
  ### `rails_get_context`
122
121
 
@@ -124,9 +123,11 @@ Composite context: schema + model + controller + routes + views for a resource.
124
123
 
125
124
  | Parameter | Type | Default | Description |
126
125
  |:----------|:-----|:--------|:------------|
127
- | `resource` | string | *required* | Resource name (e.g., `users`, `Post`) |
128
- | `action` | string | - | Specific controller action |
129
- | `detail` | enum | `standard` | `summary`, `standard`, `full` |
126
+ | `controller` | string | - | Controller name (e.g., `PostsController`) |
127
+ | `action` | string | - | Specific controller action; requires `controller` |
128
+ | `model` | string | - | Model name (e.g., `Post`) |
129
+ | `feature` | string | - | Feature keyword (e.g., `post`) |
130
+ | `include` | array | - | Extra context to add: `stimulus`, `turbo`, `services`, `jobs`, `conventions`, `helpers`, `env`, `callbacks` |
130
131
 
131
132
  ### `rails_onboard`
132
133
 
@@ -164,15 +165,20 @@ composite unique index; `[in index after x]` marks a column that only trails
164
165
  |:----------|:-----|:--------|:------------|
165
166
  | `table` | string | - | Specific table (omit for overview) |
166
167
  | `detail` | enum | `standard` | `summary`, `standard`, `full` |
168
+ | `limit` | integer | auto | Max tables when listing: 50 for `summary`, 25 for `standard`, 10 for `full` |
169
+ | `offset` | integer | `0` | Skip this many tables |
170
+ | `format` | enum | `markdown` | `markdown`, `json` |
167
171
 
168
172
  ### `rails_get_model_details`
169
173
 
170
- AST-parsed model internals. Every result carries `[VERIFIED]` or `[INFERRED]` confidence tag. The method list says how many of the model's methods it is showing.
174
+ AST-parsed model internals. The model heading and each scope carry a confidence tag: `[VERIFIED]` or `[INFERRED]` on a booted app, `[STATIC]` without a boot. The method list says how many of the model's methods it is showing.
171
175
 
172
176
  | Parameter | Type | Default | Description |
173
177
  |:----------|:-----|:--------|:------------|
174
- | `model` | string | - | Model name (e.g., `User`, `Post`) |
178
+ | `model` | string | - | Model name (e.g., `User`, `Post`). Omit to list all models |
175
179
  | `detail` | enum | `standard` | `summary`, `standard`, `full` |
180
+ | `limit` | integer | `50` | Max models when listing |
181
+ | `offset` | integer | `0` | Skip this many models |
176
182
 
177
183
  Returns: associations, validations, scopes, enums, callbacks, macros, methods, concerns.
178
184
  What the included concerns declare is merged in, so the answer does not stop
@@ -181,7 +187,8 @@ Concerns as `[UNAVAILABLE]` rather than dropped.
181
187
 
182
188
  ### `rails_get_callbacks`
183
189
 
184
- Callbacks grouped by type, in Rails event order, with source code. The list
190
+ Callbacks grouped by type, in Rails event order, with source code at
191
+ `detail:"full"`. The list
185
192
  covers concern-declared callbacks too, with the body read from the concern
186
193
  file, and the "From Concerns" section says which concern declared each one.
187
194
  Within one type the order is the order Rails runs them: base classes first, a
@@ -198,12 +205,12 @@ not read, so the list can miss it or show the definition it replaces.
198
205
 
199
206
  | Parameter | Type | Default | Description |
200
207
  |:----------|:-----|:--------|:------------|
201
- | `model` | string | *required* | Model name |
208
+ | `model` | string | - | Model name. Omit to list every model with its callbacks |
202
209
  | `detail` | enum | `standard` | `summary`, `standard`, `full` |
203
210
 
204
211
  ### `rails_get_concern`
205
212
 
206
- Concern methods, source code, and which models include it. A class under
213
+ Concern methods, their source code at `detail:"full"`, and which models include it. A class under
207
214
  `app/models/concerns` that subclasses `ActiveModel::Validator` is listed as a
208
215
  validator rather than a concern, and its users are the models that name it in
209
216
  `validates_with`. The rule reads the class the file is named for, so a concern
@@ -230,8 +237,10 @@ Controller actions with inherited filters, render map, strong params. Includes s
230
237
  | Parameter | Type | Default | Description |
231
238
  |:----------|:-----|:--------|:------------|
232
239
  | `controller` | string | - | Controller name (e.g., `UsersController`) |
233
- | `action` | string | - | Specific action |
240
+ | `action` | string | - | Specific action; requires `controller` |
234
241
  | `detail` | enum | `standard` | `summary`, `standard`, `full` |
242
+ | `limit` | integer | `50` | Max controllers when listing |
243
+ | `offset` | integer | `0` | Skip this many controllers |
235
244
 
236
245
  ### `rails_get_routes`
237
246
 
@@ -248,6 +257,9 @@ the summary counts them.
248
257
  |:----------|:-----|:--------|:------------|
249
258
  | `controller` | string | - | Filter by controller |
250
259
  | `detail` | enum | `standard` | `summary`, `standard`, `full` |
260
+ | `limit` | integer | auto | Max routes to return; the default depends on `detail` |
261
+ | `offset` | integer | `0` | Skip this many routes |
262
+ | `app_only` | boolean | `true` | Leave out internal Rails routes (Active Storage, Action Mailbox, Conductor) |
251
263
 
252
264
  <p align="right"><a href="#table-of-contents">↑ back to top</a></p>
253
265
 
@@ -262,7 +274,7 @@ View templates with instance variables, Turbo frames, Stimulus controllers, part
262
274
  | Parameter | Type | Default | Description |
263
275
  |:----------|:-----|:--------|:------------|
264
276
  | `controller` | string | - | Controller name |
265
- | `action` | string | - | Specific action view |
277
+ | `path` | string | - | Specific view path relative to `app/views` (e.g., `posts/index.html.erb`); returns its content |
266
278
  | `detail` | enum | `standard` | `summary`, `standard`, `full` |
267
279
 
268
280
  ### `rails_get_stimulus`
@@ -287,6 +299,8 @@ two or more confirmed neighbours that all drop the directory's segment.
287
299
  |:----------|:-----|:--------|:------------|
288
300
  | `controller` | string | - | Stimulus controller name |
289
301
  | `detail` | enum | `standard` | `summary`, `standard`, `full` |
302
+ | `limit` | integer | `50` | Max controllers when listing |
303
+ | `offset` | integer | `0` | Skip this many controllers |
290
304
 
291
305
  ### `rails_get_partial_interface`
292
306
 
@@ -304,6 +318,8 @@ Turbo Stream broadcast-to-subscription wiring with mismatch warnings.
304
318
  | Parameter | Type | Default | Description |
305
319
  |:----------|:-----|:--------|:------------|
306
320
  | `detail` | enum | `standard` | `summary`, `standard`, `full` |
321
+ | `stream` | string | - | Filter by stream or channel name (e.g., `notifications`) |
322
+ | `controller` | string | - | Filter by controller name (e.g., `messages`) |
307
323
 
308
324
  ### `rails_get_frontend_stack`
309
325
 
@@ -335,8 +351,10 @@ Test scaffolding that matches your project's patterns (fixtures vs factories, RS
335
351
 
336
352
  | Parameter | Type | Default | Description |
337
353
  |:----------|:-----|:--------|:------------|
338
- | `file` | string | *required* | File to generate tests for |
339
- | `detail` | enum | `standard` | `summary`, `standard`, `full` |
354
+ | `model` | string | - | Model to generate a model test for (e.g., `User`) |
355
+ | `controller` | string | - | Controller to generate a request test for (e.g., `PostsController`) |
356
+ | `file` | string | - | File to generate tests for, relative to Rails root; the type is detected |
357
+ | `type` | enum | `unit` | `unit`, `request`, `system` |
340
358
 
341
359
  ### `rails_validate`
342
360
 
@@ -353,11 +371,15 @@ Brakeman static analysis: SQL injection, XSS, mass assignment, command injection
353
371
 
354
372
  | Parameter | Type | Default | Description |
355
373
  |:----------|:-----|:--------|:------------|
374
+ | `files` | array | - | File paths to filter results to (omit to scan the whole app) |
375
+ | `confidence` | enum | `weak` | Minimum confidence: `high`, `medium`, `weak` (`weak` shows every warning) |
376
+ | `checks` | array | - | Run only these Brakeman checks, by class name (e.g., `CheckSQL`) |
356
377
  | `detail` | enum | `standard` | `summary`, `standard`, `full` |
357
378
 
358
- > Requires the `brakeman` gem. When it cannot be loaded, the answer says which
359
- > case it is: brakeman is nowhere on the machine, or it is installed and the
360
- > app's bundle does not carry it, which `--no-boot` scans around.
379
+ > Requires the `brakeman` gem. When the app's bundle does not carry it but the
380
+ > machine has it, the scan runs brakeman as its own process from outside the
381
+ > bundle and says so. When no scan can run, the answer says which case it is:
382
+ > brakeman is nowhere on the machine, or it is installed and produced no report.
361
383
 
362
384
  ### `rails_performance_check`
363
385
 
@@ -365,6 +387,8 @@ N+1 query risks, missing indexes, missing counter_cache, eager load candidates.
365
387
 
366
388
  | Parameter | Type | Default | Description |
367
389
  |:----------|:-----|:--------|:------------|
390
+ | `model` | string | - | Filter results to one model |
391
+ | `category` | enum | `all` | `n_plus_one`, `counter_cache`, `indexes`, `model_all`, `eager_load`, `all` |
368
392
  | `detail` | enum | `standard` | `summary`, `standard`, `full` |
369
393
 
370
394
  <p align="right"><a href="#table-of-contents">↑ back to top</a></p>
@@ -385,17 +409,13 @@ API layer: api_only mode, serialization strategy (Jbuilder, serializers), GraphQ
385
409
 
386
410
  Auth checks, flash messages, create action template, test patterns, and the admin resources ActiveAdmin, Administrate, Avo, Madmin and Trestle register (with ActiveAdmin's permitted params).
387
411
 
388
- | Parameter | Type | Default | Description |
389
- |:----------|:-----|:--------|:------------|
390
- | `detail` | enum | `standard` | `summary`, `standard`, `full` |
412
+ *No parameters.*
391
413
 
392
414
  ### `rails_get_config`
393
415
 
394
416
  Database config, auth framework, assets, cache, queue, Action Cable. The `use` and `map` calls in `config.ru` are listed apart from the stack, since they run before Rails.
395
417
 
396
- | Parameter | Type | Default | Description |
397
- |:----------|:-----|:--------|:------------|
398
- | `detail` | enum | `standard` | `summary`, `standard`, `full` |
418
+ *No parameters.*
399
419
 
400
420
  ### `rails_get_gems`
401
421
 
@@ -405,11 +425,13 @@ found under a load-order prefix too (`config/initializers/3_omniauth.rb`).
405
425
 
406
426
  | Parameter | Type | Default | Description |
407
427
  |:----------|:-----|:--------|:------------|
408
- | `detail` | enum | `standard` | `summary`, `standard`, `full` |
428
+ | `category` | enum | `all` | `auth`, `jobs`, `frontend`, `api`, `database`, `files`, `testing`, `deploy`, `monitoring`, `admin`, `pagination`, `search`, `forms`, `server`, `notifications`, `validation`, `utilities`, `services`, `payments`, `all` |
429
+ | `offset` | integer | `0` | Skip this many gems |
430
+ | `limit` | integer | `50` | Max gems to return |
409
431
 
410
432
  ### `rails_get_env`
411
433
 
412
- Environment variables + credentials keys (values are never exposed). Scans `.rb`, `.rake`, ERB views and config YAML under `app`, `config` and `lib`, plus `config.ru`, `db/seeds.rb`, `db/seeds/` and the Ruby scripts in `bin/`; files matching `sensitive_patterns` (`config/database.yml`, credentials, keys) are never read, and the answer says so. The env Kamal's `config/deploy.yml` gives the app container is listed too: secret names only, and clear values, except one holding a URL or a key-like token, or under a secret-named variable, which shows as hidden, and one an ERB tag sets, which says so. So are the setting keys in the config gem's `config/settings.yml` and `config/settings/<env>.yml` when the bundle has the config gem, and the attributes of each `Anyway::Config` class in `config/configs` or `app/configs` with the env name it reads (`PAYMENT_API_KEY`), never their values. A variable whose call sites pass different defaults is labelled as such rather than with one site's default; `detail:"full"` names each site's. A default is redacted by the rule a source literal gets: a credential format under any name, a URL's password, and under a secret-named variable a value that is not clearly something else, so an address, URL or hostname default prints as written.
434
+ Environment variables + credentials keys (values are never exposed). Scans `.rb`, `.rake`, ERB views and config YAML under `app`, `config` and `lib`, plus `config.ru`, `db/seeds.rb`, `db/seeds/` and the Ruby scripts in `bin/`; config YAML matching `sensitive_patterns` (`config/database.yml`) is read only for the ENV names in its ERB tags, credentials and keys are never read, and the answer says so. The env Kamal's `config/deploy.yml` gives the app container is listed too: secret names only, and clear values, except one holding a URL or a key-like token, or under a secret-named variable, which shows as hidden, and one an ERB tag sets, which says so. So are the setting keys in the config gem's `config/settings.yml` and `config/settings/<env>.yml` when the bundle has the config gem, and the attributes of each `Anyway::Config` class in `config/configs` or `app/configs` with the env name it reads (`PAYMENT_API_KEY`), never their values. A variable whose call sites pass different defaults is labelled as such rather than with one site's default; `detail:"full"` names each site's. A default is redacted by the rule a source literal gets: a credential format under any name, a URL's password, and under a secret-named variable a value that is not clearly something else, so an address, URL or hostname default prints as written.
413
435
 
414
436
  | Parameter | Type | Default | Description |
415
437
  |:----------|:-----|:--------|:------------|
@@ -417,11 +439,14 @@ Environment variables + credentials keys (values are never exposed). Scans `.rb`
417
439
 
418
440
  ### `rails_get_helper_methods`
419
441
 
420
- Application and framework helpers with view cross-references.
442
+ Application and framework helpers, with view cross-references at `detail:"full"`.
421
443
 
422
444
  | Parameter | Type | Default | Description |
423
445
  |:----------|:-----|:--------|:------------|
446
+ | `helper` | string | - | Helper module name (e.g., `ApplicationHelper`). Omit to list all helpers |
424
447
  | `detail` | enum | `standard` | `summary`, `standard`, `full` |
448
+ | `offset` | integer | `0` | Skip this many helpers |
449
+ | `limit` | integer | `50` | Max helpers to return |
425
450
 
426
451
  ### `rails_get_service_pattern`
427
452
 
@@ -438,7 +463,7 @@ own file ceiling left the list partial. A module under
438
463
 
439
464
  | Parameter | Type | Default | Description |
440
465
  |:----------|:-----|:--------|:------------|
441
- | `service` | string | *required* | Service class name |
466
+ | `service` | string | - | Service class name or filename. Omit to list all services |
442
467
  | `detail` | enum | `standard` | `summary`, `standard`, `full` |
443
468
 
444
469
  ### `rails_get_job_pattern`
@@ -481,6 +506,8 @@ ViewComponent/Phlex components: props, slots, previews, sidecar assets, usage ex
481
506
  |:----------|:-----|:--------|:------------|
482
507
  | `component` | string | - | Specific component name |
483
508
  | `detail` | enum | `standard` | `summary`, `standard`, `full` |
509
+ | `offset` | integer | `0` | Skip this many components |
510
+ | `limit` | integer | `50` | Max components to return |
484
511
 
485
512
  ### `rails_get_i18n`
486
513
 
@@ -555,7 +582,7 @@ only.
555
582
 
556
583
  ### `rails_dependency_graph`
557
584
 
558
- Model/service dependency graph in Mermaid or text format.
585
+ Model association graph in Mermaid or text format.
559
586
 
560
587
  | Parameter | Type | Default | Description |
561
588
  |:----------|:-----|:--------|:------------|
@@ -565,7 +592,7 @@ Model/service dependency graph in Mermaid or text format.
565
592
  | `show_cycles` | boolean | `false` | Detect and list circular dependencies |
566
593
  | `show_sti` | boolean | `false` | Show Single Table Inheritance hierarchies |
567
594
 
568
- Without `model` the graph is capped at 50 nodes, and says so when it cuts.
595
+ The graph is capped at 50 nodes, with or without `model`, and says so when it cuts.
569
596
 
570
597
  ### `rails_migration_advisor`
571
598
 
@@ -573,10 +600,12 @@ Migration code generation with duplicate/nonexistent column warnings, reversibil
573
600
 
574
601
  | Parameter | Type | Default | Description |
575
602
  |:----------|:-----|:--------|:------------|
576
- | `action` | string | *required* | Migration action (e.g., `add_column`, `create_table`) |
603
+ | `action` | enum | *required* | `add_column`, `remove_column`, `rename_column`, `add_index`, `add_association`, `change_type`, `create_table` |
577
604
  | `table` | string | *required* | Table name |
578
- | `columns` | string | - | Column definitions |
579
- | `detail` | enum | `standard` | `summary`, `standard`, `full` |
605
+ | `column` | string | - | Column name |
606
+ | `type` | string | - | Column type (e.g., `string`, `integer`, `references`) |
607
+ | `new_name` | string | - | New column name, for `rename_column` only |
608
+ | `options` | string | - | Extra options (e.g., `null: false, default: 0`) |
580
609
 
581
610
  ### `rails_search_docs`
582
611
 
@@ -585,7 +614,9 @@ Bundled topic index with weighted keyword search. Optional on-demand GitHub fetc
585
614
  | Parameter | Type | Default | Description |
586
615
  |:----------|:-----|:--------|:------------|
587
616
  | `query` | string | *required* | Search query |
588
- | `fetch` | boolean | `false` | Fetch from GitHub if not found locally |
617
+ | `source` | enum | `all` | `all`, `guides`, `stimulus`, `turbo`, `hotwire` |
618
+ | `limit` | integer | `5` | Max results to return (1-20) |
619
+ | `fetch` | boolean | `false` | Fetch the full content from GitHub (cached 24h in `tmp/`) |
589
620
 
590
621
  ### `rails_query`
591
622
 
@@ -593,7 +624,7 @@ Safe read-only SQL with 4-layer security: regex validation, `SET TRANSACTION REA
593
624
 
594
625
  | Parameter | Type | Default | Description |
595
626
  |:----------|:-----|:--------|:------------|
596
- | `sql` | string | *required* | SQL query (SELECT only) |
627
+ | `sql` | string | *required* | SQL query. Only `SELECT`, `WITH`, `SHOW`, `EXPLAIN`, `DESCRIBE` are allowed |
597
628
  | `limit` | integer | `100` | Maximum rows to return (hard cap: 1000) |
598
629
  | `format` | enum | `table` | `table`, `csv` |
599
630
  | `explain` | boolean | `false` | Show query plan instead of results |
@@ -606,20 +637,21 @@ Reverse file tail with level filtering and sensitive data redaction.
606
637
 
607
638
  | Parameter | Type | Default | Description |
608
639
  |:----------|:-----|:--------|:------------|
609
- | `file` | string | `development.log` | Log file name |
610
- | `lines` | integer | `50` | Number of lines |
611
- | `level` | enum | - | Filter: `debug`, `info`, `warn`, `error`, `fatal` |
640
+ | `file` | string | current environment's log | Log file name in `log/` (e.g., `production`, `sidekiq`); the `.log` suffix is optional |
641
+ | `lines` | integer | `50` | Number of lines, max 500 |
642
+ | `level` | enum | `all` | Minimum level: `DEBUG`, `INFO`, `WARN`, `ERROR`, `FATAL`, `all` |
612
643
  | `search` | string | - | Keep lines matching this term. The match runs on the redacted line, so a redacted value cannot be searched for |
613
644
 
614
645
  ### `rails_diagnose`
615
646
 
616
- One-call error diagnosis with classification, context, git blame, and log correlation. It does not call a method undefined when the model's method list could be missing one - a concern's, a parent's, or anything past the payload's own cap.
647
+ One-call error diagnosis with classification, context, recent git changes, and log correlation. It does not call a method undefined when the model's method list could be missing one - a concern's, a parent's, or anything past the payload's own cap.
617
648
 
618
649
  | Parameter | Type | Default | Description |
619
650
  |:----------|:-----|:--------|:------------|
620
651
  | `error` | string | *required* | Error message or class |
621
652
  | `file` | string | - | File where error occurred |
622
653
  | `line` | integer | - | Line number |
654
+ | `action` | string | - | `controller#action` (e.g., `posts#create`); adds that action's context |
623
655
 
624
656
  ### `rails_review_changes`
625
657
 
@@ -627,8 +659,8 @@ PR/commit review with per-file context and warnings.
627
659
 
628
660
  | Parameter | Type | Default | Description |
629
661
  |:----------|:-----|:--------|:------------|
630
- | `ref` | string | `HEAD` | Git ref to review |
631
- | `detail` | enum | `standard` | `summary`, `standard`, `full` |
662
+ | `ref` | string | `HEAD` | Git ref to diff against. `HEAD` reviews uncommitted changes |
663
+ | `files` | array | - | Review only these changed files (omit for all) |
632
664
 
633
665
  ### `rails_runtime_info`
634
666
 
@@ -637,14 +669,16 @@ Live database pool stats, table sizes, pending migrations, cache stats, queue de
637
669
  | Parameter | Type | Default | Description |
638
670
  |:----------|:-----|:--------|:------------|
639
671
  | `detail` | enum | `standard` | `summary`, `standard`, `full` |
672
+ | `section` | enum | - | One section only: `database`, `cache`, `jobs`, `connections` |
640
673
 
641
674
  ### `rails_session_context`
642
675
 
643
- Session-aware context tracking across tool calls within a conversation.
676
+ Session-aware context tracking across tool calls within a conversation. Pass `action` or `mark`; a call with neither is an error.
644
677
 
645
678
  | Parameter | Type | Default | Description |
646
679
  |:----------|:-----|:--------|:------------|
647
- | `detail` | enum | `standard` | `summary`, `standard`, `full` |
680
+ | `action` | enum | - | `status` (queried tools with timestamps), `summary` (short recap), `reset` (clear the session) |
681
+ | `mark` | string | - | Record a tool and its params as already queried (e.g., `get_schema:users`) |
648
682
 
649
683
  <p align="right"><a href="#table-of-contents">↑ back to top</a></p>
650
684
 
@@ -40,14 +40,14 @@ The gem is likely in a `:development` group but you're running in another enviro
40
40
 
41
41
  ```ruby
42
42
  # config/initializers/rails_ai_context.rb
43
- if defined?(RailsAiContext)
43
+ if defined?(RailsAiContext) && RailsAiContext.respond_to?(:configure)
44
44
  RailsAiContext.configure do |config|
45
45
  # ...
46
46
  end
47
47
  end
48
48
  ```
49
49
 
50
- The `if defined?` guard prevents crashes when the gem isn't loaded.
50
+ The guard prevents crashes when the gem isn't loaded. `rails ai:doctor` warns about a guard that checks `defined?(RailsAiContext)` alone, since the constant can exist where `configure` does not.
51
51
 
52
52
  ### "Permission denied" during install
53
53
 
@@ -172,7 +172,7 @@ config.generate_root_files = false
172
172
 
173
173
  ## Query tool issues
174
174
 
175
- ### "Query tool disabled in production"
175
+ ### "rails_query is disabled in production"
176
176
 
177
177
  By design. Override if needed:
178
178
 
@@ -180,20 +180,21 @@ By design. Override if needed:
180
180
  config.allow_query_in_production = true
181
181
  ```
182
182
 
183
- ### "Query blocked: potentially unsafe SQL"
183
+ ### "Blocked: contains INSERT" and other "Blocked:" messages
184
184
 
185
- The 4-layer SQL validator blocks write operations and injection patterns. Ensure you're only running SELECT queries.
185
+ The 4-layer SQL validator blocks write operations and injection patterns, and the message names what it hit. Ensure you're only running SELECT queries.
186
186
 
187
187
  Common false positives:
188
- - Hash characters in strings → write the hash outside a comment position
188
+ - A blocked keyword inside a string (`WHERE note = 'please insert coin'`) → the validator matches words, not SQL structure, so the query is refused
189
+ - Hash characters → a `#` starts a comment on MySQL only, and never inside a quoted string
189
190
  - JSONB operators (`#>>`) → preserved correctly since v5.6.0
190
191
 
191
192
  ### "Column values show [FILTERED]"
192
193
 
193
- Columns matching sensitive patterns are redacted. Configure:
194
+ Columns whose names look sensitive are redacted, and a query that names one is rejected with "Blocked: query references sensitive column". Shortening `config.query_redacted_columns` does not lift either, because a built-in list applies as well. Exempt a column of your own by name:
194
195
 
195
196
  ```ruby
196
- config.query_redacted_columns = %w[password_digest encrypted_password]
197
+ config.query_allowed_columns = %w[secret]
197
198
  ```
198
199
 
199
200
  ---
@@ -203,11 +204,11 @@ config.query_redacted_columns = %w[password_digest encrypted_password]
203
204
  ### "Search returns no results"
204
205
 
205
206
  1. Check the case: the search is case-sensitive on both backends, as ripgrep is by default
206
- 2. Check excluded paths: `config.excluded_paths` excludes `node_modules`, `tmp`, `log`, `doc` and `docs` directories at any depth
207
+ 2. Check excluded paths: `config.excluded_paths` excludes `node_modules`, `tmp`, `log`, `vendor`, `.git`, `doc` and `docs` directories at any depth
207
208
  3. Check `config.search_extensions`: when set, it narrows the Ruby fallback to those extensions
208
209
  4. Check sensitive patterns: some files are blocked by design
209
210
 
210
- ### "ripgrep not found" warning
211
+ ### "ripgrep not installed" warning
211
212
 
212
213
  Install ripgrep for faster search:
213
214
 
@@ -245,7 +246,7 @@ The file is read from the app root, once, at boot, and an initializer does not r
245
246
 
246
247
  ## Security scan issues
247
248
 
248
- ### "Brakeman not installed"
249
+ ### "Brakeman is not installed"
249
250
 
250
251
  The `rails_security_scan` tool requires Brakeman:
251
252
 
data/exe/rails-ai-context CHANGED
@@ -269,7 +269,7 @@ class RailsAiContextCLI < Thor
269
269
  end
270
270
  end
271
271
 
272
- desc "init", "Set up rails-ai-context for standalone use (creates .rails-ai-context.yml and .mcp.json)"
272
+ desc "init", "Set up rails-ai-context for standalone use (creates .rails-ai-context.yml, each AI tool's MCP config and its context files)"
273
273
  option :no_boot, type: :boolean, default: false, desc: "Skip booting the app; serve static analysis only"
274
274
  option :mcp_only, type: :boolean, default: false,
275
275
  desc: "Write the MCP config and nothing else: no CLAUDE.md, AGENTS.md, rules files or .ai-context.json"
@@ -295,7 +295,7 @@ class RailsAiContextCLI < Thor
295
295
  cleanup_removed_tools(previous_tools, ai_tools) if previous_tools&.any?
296
296
 
297
297
  # --- One-time v5.0.0 legacy UI-pattern files cleanup prompt ---
298
- ::RailsAiContext::LegacyCleanup.prompt_legacy_files(ai_tools, root: Dir.pwd)
298
+ ::RailsAiContext::LegacyCleanup.prompt_legacy_files(ai_tools, root: Dir.pwd) if context_files
299
299
 
300
300
  # --- Record the selection (YAML, plus the initializer line) ---
301
301
  record_selection(ai_tools, tool_mode, context_files)
@@ -397,9 +397,13 @@ class RailsAiContextCLI < Thor
397
397
  ai_tools, root: Dir.pwd,
398
398
  extra_yaml: { "tool_mode" => tool_mode.to_s, "context_files" => context_files }
399
399
  )
400
- ::RailsAiContext::Install::SelectionRecord.write_context_files(context_files, root: Dir.pwd)
400
+ record = ::RailsAiContext::Install::SelectionRecord
401
+ conflicts = [
402
+ record.conflict_message(:context_files, record.write_context_files(context_files, root: Dir.pwd)),
403
+ record.conflict_message(:tool_mode, record.write_tool_mode(tool_mode, root: Dir.pwd))
404
+ ].compact
401
405
 
402
- ::RailsAiContext::Install::SelectionRecord.messages(result).each do |level, text|
406
+ (record.messages(result) + conflicts).each do |level, text|
403
407
  $stderr.puts(level == :warn ? "Warning: #{text}" : text)
404
408
  end
405
409
  end
@@ -550,7 +550,7 @@ module RailsAiContext
550
550
 
551
551
  # One-time v5.0.0 legacy UI-pattern files cleanup prompt
552
552
  RailsAiContext::LegacyCleanup.prompt_legacy_files(
553
- @selected_formats, root: Rails.root
553
+ @selected_formats, root: Rails.root, warn_only: options[:defaults]
554
554
  )
555
555
 
556
556
  begin
@@ -235,7 +235,7 @@ module RailsAiContext
235
235
  attr_accessor :max_tool_response_chars
236
236
 
237
237
  # Live reload: auto-invalidate MCP tool caches on file changes
238
- # :auto (default) - enable if `listen` gem is available, skip silently otherwise
238
+ # :auto (default) - enable if `listen` gem is available, say so on stderr otherwise
239
239
  # true - enable, raise if `listen` gem is missing
240
240
  # false - disable entirely
241
241
  attr_accessor :live_reload
@@ -372,7 +372,7 @@ module RailsAiContext
372
372
  # Database query tool settings (rails_query)
373
373
  attr_accessor :query_timeout # Statement timeout in seconds (default: 5)
374
374
  attr_accessor :query_row_limit # Max rows returned (default: 100, hard cap: 1000)
375
- attr_accessor :query_redacted_columns # Column names whose values are redacted in output
375
+ attr_accessor :query_redacted_columns # Column names a query may not reference, redacted in output
376
376
  attr_accessor :query_allowed_columns # Column names to exempt from the built-in sensitive list
377
377
  attr_accessor :allow_query_in_production # Allow rails_query in production (default: false)
378
378
 
@@ -13,8 +13,11 @@ module RailsAiContext
13
13
  #
14
14
  # context_paths lists the root file first, then the split-rule targets. The writers,
15
15
  # doctor and cleanup all read this table, so a moved path changes every surface at once.
16
- AiTool = Struct.new(:number, :key, :name, :files, :context_paths, :rules_dir, :mcp_config, :legacy_paths,
17
- :owned_dir, keyword_init: true)
16
+ #
17
+ # rule_files names what the gem writes inside rules_dir. The directory is shared with
18
+ # rules the user writes by hand, so cleanup removes these names and nothing else.
19
+ AiTool = Struct.new(:number, :key, :name, :files, :context_paths, :rules_dir, :rule_files, :mcp_config,
20
+ :legacy_paths, :owned_dir, keyword_init: true)
18
21
 
19
22
  class AiTool
20
23
  ALL = [
@@ -23,6 +26,7 @@ module RailsAiContext
23
26
  files: "CLAUDE.md + .claude/rules/",
24
27
  context_paths: %w[CLAUDE.md .claude/rules],
25
28
  rules_dir: ".claude/rules",
29
+ rule_files: %w[rails-context.md rails-schema.md rails-models.md rails-mcp-tools.md rails-components.md],
26
30
  mcp_config: { path: ".mcp.json", root_key: "mcpServers", format: :mcp_json },
27
31
  legacy_paths: [ ".claude/rules/rails-ui-patterns.md", ".claude/rules/rails-accessibility.md" ],
28
32
  owned_dir: ".claude"
@@ -32,6 +36,7 @@ module RailsAiContext
32
36
  files: ".cursor/rules/ + .cursorrules (legacy fallback)",
33
37
  context_paths: %w[.cursor/rules .cursorrules],
34
38
  rules_dir: ".cursor/rules",
39
+ rule_files: %w[rails-project.mdc rails-models.mdc rails-controllers.mdc rails-mcp-tools.mdc],
35
40
  mcp_config: { path: ".cursor/mcp.json", root_key: "mcpServers", format: :mcp_json },
36
41
  legacy_paths: [ ".cursor/rules/rails-ui-patterns.mdc" ],
37
42
  owned_dir: ".cursor"
@@ -41,6 +46,10 @@ module RailsAiContext
41
46
  files: ".github/copilot-instructions.md + .github/instructions/",
42
47
  context_paths: %w[.github/copilot-instructions.md .github/instructions],
43
48
  rules_dir: ".github/instructions",
49
+ rule_files: %w[
50
+ rails-context.instructions.md rails-models.instructions.md
51
+ rails-controllers.instructions.md rails-mcp-tools.instructions.md
52
+ ],
44
53
  mcp_config: { path: ".vscode/mcp.json", root_key: "servers", format: :vscode_json },
45
54
  legacy_paths: [ ".github/instructions/rails-ui-patterns.instructions.md" ]
46
55
  ),