rails-ai-context 5.36.8 → 5.36.9

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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +125 -0
  3. data/README.md +6 -0
  4. data/docs/CLI.md +1 -1
  5. data/docs/COMPATIBILITY.md +10 -0
  6. data/docs/GUIDE.md +1 -1
  7. data/docs/PROMPTS.md +3 -3
  8. data/docs/SETUP.md +191 -0
  9. data/docs/STANDALONE.md +1 -1
  10. data/docs/TROUBLESHOOTING.md +6 -2
  11. data/exe/rails-ai-context +53 -20
  12. data/lib/generators/rails_ai_context/install/install_generator.rb +8 -4
  13. data/lib/rails_ai_context/boot_manager.rb +7 -1
  14. data/lib/rails_ai_context/claude_code_settings.rb +1006 -0
  15. data/lib/rails_ai_context/cli/app_root.rb +126 -16
  16. data/lib/rails_ai_context/cli/entry_boot.rb +58 -6
  17. data/lib/rails_ai_context/configuration.rb +116 -34
  18. data/lib/rails_ai_context/doctor.rb +478 -23
  19. data/lib/rails_ai_context/gem_lock.rb +14 -7
  20. data/lib/rails_ai_context/initializer_settings.rb +4 -1
  21. data/lib/rails_ai_context/install/claude_plugin_removal.rb +107 -0
  22. data/lib/rails_ai_context/install/program.rb +133 -6
  23. data/lib/rails_ai_context/install/selection_record.rb +11 -5
  24. data/lib/rails_ai_context/introspectors/gemfile_gems.rb +2 -2
  25. data/lib/rails_ai_context/mcp_config_generator.rb +18 -6
  26. data/lib/rails_ai_context/redaction.rb +101 -14
  27. data/lib/rails_ai_context/resources.rb +15 -0
  28. data/lib/rails_ai_context/secret_columns.rb +1 -1
  29. data/lib/rails_ai_context/server.rb +6 -1
  30. data/lib/rails_ai_context/tools/safe_call.rb +5 -0
  31. data/lib/rails_ai_context/tools/search_docs.rb +2 -1
  32. data/lib/rails_ai_context/update_check.rb +17 -4
  33. data/lib/rails_ai_context/version.rb +1 -1
  34. data/lib/rails_ai_context.rb +26 -0
  35. metadata +3 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8cd401837a164e83cf1558e5ff9ed491e0409974c9ffae9d4b648e56b4e4fb68
4
- data.tar.gz: 1667e185eba134e006450acd3edf19ffe1e590b3a6033608db25ad60e529e87a
3
+ metadata.gz: e4f5530fd8b0a92932d1810f018d01de51af456064f92de2f9b95749360e43a5
4
+ data.tar.gz: dd8098d2f6d049088e92d857a407a69e84a19963379eaa698749bab6d5564539
5
5
  SHA512:
6
- metadata.gz: ef8df079d4306b933571f8a01f697a0ca8c6e96b663b71894e065760fc72eb5ffca09a0a07471722afb684e805258ad05c60676f28a7f68599f591e1f955ec67
7
- data.tar.gz: 7edafa2842e04597cbc61786c8ee67c7e8c74ab312ce9c75c6d0bc711bf0f496deff280e45984c5104e08b229ec7ba16b6d7dd822990f133d77e945b923ec174
6
+ metadata.gz: 5ac4f8fb6bdd15d56bf3db2aec1b5e53d3ca39f437d2acead40769014f3747546a931c2ad531250c614ff3f418eaae5d82bf84fe2790036e7931c50f515dd12b
7
+ data.tar.gz: 943060825f72f4e118bebc8160a209787582d8223050ca65cbdd6149bff4819fc12966962dc2ceb1f999689571db1121f908b68bb4ca27563094d7cf1874b6fd
data/CHANGELOG.md CHANGED
@@ -5,6 +5,131 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [5.36.9] - 2026-10-23
9
+
10
+ ### Security
11
+
12
+ - **`rails_read_logs` and `rails_query` hide a value under a plural secret name
13
+ or a list of codes** (#606). A secret word ending a name in its plural (`api_keys`,
14
+ `tokens`, `secrets`, `passwords`, `accessTokens`) named no secret, and
15
+ neither did `recovery_codes`, `backup_codes`, `recoveryCodes` or
16
+ `backupCodes`, so their values came back from a log line, inline or bound,
17
+ and `rails_query` returned such a column. A list or hash logged under a
18
+ secret name is now filtered whole, on one line or spread over lines, where
19
+ only its first element was, and so are a query parameter with a secret word
20
+ anywhere in its bracketed name (`user[password][new]=`) and every value of
21
+ `API_KEYS=a,b`. In a log line a count stays shown (`tokens_used`,
22
+ `token_count`, `prompt_tokens: 12`, `inputTokens: 12`), and so do `keys`,
23
+ `primary_keys` and `cache_keys`; `rails_query` still refuses a column whose
24
+ name holds `token` unless `query_allowed_columns` lists it.
25
+
26
+ ### Added
27
+
28
+ - **The repository is a Claude Code plugin marketplace.** `claude plugin install
29
+ rails-ai-context --marketplace crisnahine/rails-ai-context --scope project`
30
+ adds the MCP server and gives each session in a Rails app the six rules the
31
+ context files open with (unless the app's own files carry them or its config
32
+ turns them off), and writes no context files or MCP config. It runs the
33
+ installed rails-ai-context, for the `ruby` on `PATH`, Windows included.
34
+ Where it cannot serve (no gem for that Ruby, an older one, a Ruby too old,
35
+ several apps or none) its server still connects, with no tools, and tells
36
+ the session why, naming the Ruby and the folder it ran in, since Claude Code
37
+ skips a plugin server that failed to start in every new session for 15
38
+ minutes. Its command line names no versioned folder, so one
39
+ `allowedMcpServers` entry admits it across updates. See
40
+ [SETUP.md](docs/SETUP.md#as-a-plugin).
41
+ - **`doctor` knows the plugin.** It reads Claude Code's settings, install
42
+ registry, `/mcp` toggles and MCP policy per session folder, as Claude Code
43
+ does. Where the plugin serves the app it counts as Claude Code's MCP config;
44
+ where it does not run, `doctor` says why (not installed, a local marketplace
45
+ folder that is gone, turned off in `/mcp`, blocked by the MCP or marketplace
46
+ policy, naming each rule and the file that holds it, or a managed settings
47
+ file Claude Code cannot read) instead of sending you to `init`. A
48
+ `.mcp.json`, user scope or local scope server of the gem's, an HTTP one
49
+ included, that a session would start beside it is a warning naming the
50
+ commands that remove it, since Claude Code would list every tool twice. Where
51
+ Claude Code never ran, as on CI, what the plugin needs is a warning, so a
52
+ STRICT run stays green. Where an organization deploys `managed-mcp.json`,
53
+ which starts its own servers alone, `doctor` judges Claude Code by it; it
54
+ follows a `CLAUDE_CONFIG_DIR` set in the settings' `env` block, and warns
55
+ about one there or in the environment that is not an absolute path, which no
56
+ one can read from outside a session.
57
+
58
+ ### Changed
59
+
60
+ - **The install writes no Claude Code server where the app's committed settings
61
+ turn the plugin on.** `init`, the install generator and `context` leave
62
+ `.mcp.json` alone there and say why, so doctor's fix to remove an old entry
63
+ lasts; `init` in a folder holding one app does the same where that folder's
64
+ committed settings turn the plugin on, and writes the app's own `.mcp.json`
65
+ for sessions started in the app. Its summary marks the plugin off where it
66
+ does not start for you. Where only your own settings turn the plugin on,
67
+ Claude Code's next step says to turn the `.mcp.json` server off with `/mcp`.
68
+ - **The update notice in a plugin's server says to reconnect it.** It named
69
+ `init`, which would add a second server beside the plugin's.
70
+ - **`uninstall` names the Claude Code plugin** that runs the installed gem, and
71
+ the commands that turn it off for the app (one per folder whose local
72
+ settings its sessions read) and take it out, before it suggests removing the
73
+ gem.
74
+
75
+ ### Fixed
76
+
77
+ - **A YAML alias in `.rails-ai-context.yml` no longer stops the app's boot.**
78
+ The loader refused aliases and the error escaped the engine's initializer.
79
+ Aliases now apply, and YAML that will not load warns and keeps the defaults.
80
+ So does a value of the wrong shape, such as a nested list for `ai_tools`, a
81
+ list for `preset` or a mapping for a number, which raised past the
82
+ initializer too, in one short line however many aliases the file nests. A
83
+ number written as text reads as that number: `1e5` had read as 1, a
84
+ `query_timeout` of `010` as 8, and a quoted number failed the tools that
85
+ compare it.
86
+ - **`rails-ai-context init` and `context` read an odd config file as the
87
+ loader does** (#520). A file holding a list, not settings, and a `tool_mode`
88
+ that is not a name stopped both with a Ruby error. They now warn and keep the
89
+ default, as the loader does.
90
+ - **A number setting from a configure block is checked when it is set.** Text
91
+ such as an ENV lookup, a negative count or a list was stored as given for the
92
+ settings with no writer of their own, and a tool failed on it later. It now
93
+ reads as the number it is written as, and a wrong value raises ArgumentError
94
+ at boot, as `cache_ttl` already did; from the YAML file it warns and keeps
95
+ the default. `live_reload_debounce` likewise takes a finite number of
96
+ seconds, zero or more.
97
+ - **A query log tag in a statement's trailing comment is read as a tag.**
98
+ `rails_read_logs` read the comment as SQL, so where the statement named a
99
+ secret column, the first tag's value (`/*application='App'*/`) was
100
+ filtered. A tag is now filtered only when its key names a secret, in the
101
+ `key='value'` and `key:value` forms; MySQL's `/*!` and `/*+` stay SQL.
102
+ - **`live_reload: "false"` in `.rails-ai-context.yml` no longer turns live
103
+ reload on.** Any name was taken and meant auto. `true` and `false`, as
104
+ booleans or text, and `auto` now count; anything else warns and keeps auto
105
+ from the file, and raises ArgumentError from a configure block.
106
+ - **A Ruby file the app cannot read no longer stops the static tier.** Since
107
+ 5.36.8 the static tier reads the security settings an app's Ruby config
108
+ writes, and one file it could not open made every answer an error; no boot
109
+ loads that file either, so it now names no setting.
110
+ - **A `BUNDLE_GEMFILE` inherited from another project is named.** The app
111
+ booted against that bundle and failed with a bare LoadError; the warning
112
+ bundle exec already had now covers the variable on its own.
113
+ - **A running server survives `gem cleanup`.** The gem loads its files as it
114
+ needs them, so a tool call after its copy was removed raised a LoadError that
115
+ ended the server. A call that needs a file it has not loaded yet now answers
116
+ with an error that says to reconnect the server, or over HTTP to restart the
117
+ process serving it.
118
+ - **A boot failure names the Ruby the app pins** when another one runs and the
119
+ failure can come from that, a missing gem or a load error, as when a client
120
+ starts in a monorepo's root that pins its own.
121
+ - **No update notice where the app's lockfile names the version running.**
122
+ That lockfile decides the copy that serves the app, so `gem update` changed
123
+ nothing there.
124
+ - **A lockfile rewritten within the clock's resolution is read again.** The
125
+ app's bundle was cached by modification time alone, so a second write in the
126
+ same tick kept the first answer.
127
+ - **An app whose bundle has its own path runs its own copy.** Where `bundle
128
+ config set path`, a deployment bundle or `BUNDLE_PATH` put the gem under
129
+ the app, the installed copy served it and the app's boot loaded the
130
+ bundle's copy over it, two copies in one process, whichever version the
131
+ bundle locked. The bundle's path is now read as Bundler reads its settings.
132
+
8
133
  ## [5.36.8] - 2026-10-23
9
134
 
10
135
  ### Security
data/README.md CHANGED
@@ -81,6 +81,12 @@ gem install rails-ai-context
81
81
  rails-ai-context init # or: rails-ai-context init --tools claude --defaults
82
82
  ```
83
83
 
84
+ As a Claude Code plugin, which adds the MCP server and gives each session the six rules below, and writes no context files or MCP config. It runs the installed gem, so install that first, with `gem install rails-ai-context` (or `bundle add` alone, when the bundle installs where your `ruby` looks). Run it in the app's folder, and commit the `.claude/settings.json` it writes; the install generator and `init` then leave Claude Code's `.mcp.json` to the plugin ([details](docs/SETUP.md#as-a-plugin)):
85
+
86
+ ```bash
87
+ claude plugin install rails-ai-context --marketplace crisnahine/rails-ai-context --scope project
88
+ ```
89
+
84
90
  `--tools` takes `claude`, `cursor`, `copilot`, `opencode`, `codex` or `all`. Add `--cli` for context files only, or `--mcp-only` for the MCP config only. Re-running is safe: with `--defaults` it keeps your recorded tools and setup, keeps what you have and adds what is missing, and in a `CLAUDE.md` you wrote it only touches the block between its `<!-- BEGIN/END rails-ai-context -->` markers. Every step is in [What the install generator does](docs/GUIDE.md#what-the-install-generator-does).
85
91
 
86
92
  Needs Ruby 3.1+ and Rails 7.0+, on Linux, macOS or Windows. Optional: `brakeman` for `security_scan`, `listen` for `watch`, `ripgrep` for faster `search_code`.
data/docs/CLI.md CHANGED
@@ -320,7 +320,7 @@ rails-ai-context uninstall
320
320
  bundle exec rails-ai-context uninstall # in-Gemfile; then bundle remove rails-ai-context
321
321
  ```
322
322
 
323
- What you wrote stays: your lines around the markers in a shared `CLAUDE.md` or `AGENTS.md`, your rule files, other servers in an MCP config, and a pre-commit hook you changed by hand (named, not touched). Its own config files go even when you edited them: `.rails-ai-context.yml` and the initializer configure nothing once the gem is gone. An HTTP entry under the gem's name goes too, since only the gem's endpoint answers it. A `mount RailsAiContext::Engine` line in `config/routes.rb` is named with its line number for you to delete. In a folder of apps it uninstalls every app below and the folder's MCP configs. It needs no boot. An entry you added by hand to another client's own config from `mcp-entry` (Claude Desktop and the like) lives outside the app, so remove it there. Its last lines say how to remove the gem itself: `bundle remove rails-ai-context` when the Gemfile lists it, `gem uninstall rails-ai-context` once no other app uses the installed copy. Details in the [Guide](GUIDE.md#uninstalling).
323
+ What you wrote stays: your lines around the markers in a shared `CLAUDE.md` or `AGENTS.md`, your rule files, other servers in an MCP config, and a pre-commit hook you changed by hand (named, not touched). Its own config files go even when you edited them: `.rails-ai-context.yml` and the initializer configure nothing once the gem is gone. An HTTP entry under the gem's name goes too, since only the gem's endpoint answers it. A `mount RailsAiContext::Engine` line in `config/routes.rb` is named with its line number for you to delete. In a folder of apps it uninstalls every app below and the folder's MCP configs. It needs no boot. An entry you added by hand to another client's own config from `mcp-entry` (Claude Desktop and the like) lives outside the app, so remove it there. Where the Claude Code plugin runs the gem, it names the commands that turn the plugin off and take it out ([SETUP](SETUP.md#as-a-plugin)), since the plugin's server fails once the gem is gone. Its last lines say how to remove the gem itself: `bundle remove rails-ai-context` when the Gemfile lists it, `gem uninstall rails-ai-context` once no other app uses the installed copy. Details in the [Guide](GUIDE.md#uninstalling).
324
324
 
325
325
  ### `mcp-entry`
326
326
 
@@ -375,6 +375,16 @@ Proof sources:
375
375
  `--no-boot`, compared with v5.36.7 and every changed answer checked; the
376
376
  touched specs on Rails 7.0 (Ruby 3.1) and on prism 1.4; and the unit suite
377
377
  and the E2E harness on Linux, macOS and Windows.
378
+ In the v5.36.9 release QA: each fix's example failing on the code before
379
+ it; `doctor`'s plugin checks against what Claude Code 2.1.308 and 2.1.309
380
+ do with the same settings (marketplaces, enabled plugins, server command
381
+ and URL rules, managed files and `managed-mcp.json`), and the plugin's
382
+ launcher under Ruby 2.6 and 3.1; `rails_read_logs` and `rails_query` on
383
+ plural secret names and code lists, compared with v5.36.8 in a booted
384
+ SQLite app; the QA ladder on the SQLite labs in every tier, the E2E harness
385
+ and one large open-source app, booted; the unit suite on Ruby 3.4 and on
386
+ Rails 7.0 (Ruby 3.1); and the unit suite and the E2E harness on Linux,
387
+ macOS and Windows.
378
388
  2. Non-crash coverage for every built-in tool including `get_view` in
379
389
  `spec/e2e/in_gemfile_install_spec.rb`'s full-tool sweep; output correctness
380
390
  (ivar cross-check, render-form detection, partial interfaces) verified
data/docs/GUIDE.md CHANGED
@@ -159,7 +159,7 @@ rails-ai-context uninstall # standalone; then, once no app uses it
159
159
  - The lines the install added to `.gitignore`, with their comments.
160
160
  - The pre-commit hook, when it is the one the install wrote and covers only this app. A hook that covers other apps of the repository loses this one; a hook changed by hand is named and left for you.
161
161
 
162
- A `mount RailsAiContext::Engine` line in `config/routes.rb` is your code, so it is named with its line number, not edited. Run in a folder of apps, it does the same for every app below and for the folder's MCP configs. It needs no boot, so it works on an app that cannot start, and the binary of any install can run it: in an app whose bundle pins a version from before `uninstall` existed, `gem install rails-ai-context` and run `rails-ai-context uninstall`.
162
+ A `mount RailsAiContext::Engine` line in `config/routes.rb` is your code, so it is named with its line number, not edited. Run in a folder of apps, it does the same for every app below and for the folder's MCP configs. It needs no boot, so it works on an app that cannot start, and the binary of any install can run it: in an app whose bundle pins a version from before `uninstall` existed, `gem install rails-ai-context` and run `rails-ai-context uninstall`. Where the Claude Code plugin runs the gem, it first names the commands that turn the plugin off and take it out ([SETUP](SETUP.md#as-a-plugin)); a release from before the plugin names none, so turn it off yourself with `claude plugin disable rails-ai-context@rails-ai-context --scope local`.
163
163
 
164
164
  ---
165
165
 
data/docs/PROMPTS.md CHANGED
@@ -276,8 +276,8 @@ rails-ai-context isn't working right in this Rails app. Find out why and fix it.
276
276
  1. Check the version: `bundle exec rails-ai-context version` if the Gemfile lists rails-ai-context, else `rails-ai-context version`. If it is older than 5.35.0, upgrade first (`bundle update rails-ai-context --conservative`, or `gem install rails-ai-context -v '>= 5.35.0'`) and check the version again: older versions read `--defaults` in step 5 as every AI tool. If the Gemfile pins it below 5.35.0, change its rails-ai-context line to `gem "rails-ai-context", ">= 5.35.0", group: :development` and run the update again.
277
277
  2. Run doctor: `bundle exec rails ai:doctor` if the Gemfile lists the gem, else `rails-ai-context doctor`. Read every failing or warning check and do what each one says.
278
278
  3. If doctor itself cannot run because the app won't boot, run `bundle exec rails-ai-context tool onboard --no-boot` (or without bundle exec when standalone) to confirm the tools still answer from source, and tell me what stops the boot.
279
- 4. If my MCP tools are missing, open the MCP config file of the AI tool you are (Claude Code .mcp.json, Cursor .cursor/mcp.json, GitHub Copilot .vscode/mcp.json, OpenCode opencode.json, Codex CLI .codex/config.toml) and check it has a rails-ai-context entry. Run that entry's command and args by hand with `--help` added at the end, for example `bundle exec rails-ai-context serve --help`, and check it prints the serve usage.
280
- 5. Repair the install by running it again: `bundle exec rails generate rails_ai_context:install --defaults` if the Gemfile lists the gem, otherwise `rails-ai-context init --defaults`. On a re-run `--defaults` keeps the recorded AI tools and setup, keeps what exists and adds what is missing. For Codex CLI after a Ruby version change, it also refreshes the Ruby paths saved in .codex/config.toml.
279
+ 4. If my MCP tools are missing, open the MCP config file of the AI tool you are (Claude Code .mcp.json, Cursor .cursor/mcp.json, GitHub Copilot .vscode/mcp.json, OpenCode opencode.json, Codex CLI .codex/config.toml) and check it has a rails-ai-context entry. Run that entry's command and args by hand with `--help` added at the end, for example `bundle exec rails-ai-context serve --help`, and check it prints the serve usage. With the Claude Code plugin (rails-ai-context@rails-ai-context enabled in .claude/settings.json, .claude/settings.local.json or my user settings, or doctor names the plugin) there is no entry: where its server has no tools, its instructions in your context say why and what to run; where /mcp lists it as failed, ask me to start `claude --debug` and read that server's stderr. `ruby -S gem list rails-ai-context` run here shows the versions the `ruby` Claude Code starts has.
280
+ 5. If doctor named a missing or broken MCP config, missing context files, or Codex's saved Ruby paths, repair the install by running it again: `bundle exec rails generate rails_ai_context:install --defaults` if the Gemfile lists the gem, otherwise `rails-ai-context init --defaults`. On a re-run `--defaults` keeps the recorded AI tools and setup, keeps what exists and adds what is missing. For Codex CLI after a Ruby version change, it also refreshes the Ruby paths saved in .codex/config.toml.
281
281
  6. Tell me what was wrong, what you changed, and the "Next step" lines the install printed if I need to do one.
282
282
  ```
283
283
 
@@ -288,7 +288,7 @@ Removes everything the gem wrote and nothing you wrote: your part of a shared `C
288
288
  ```text
289
289
  Remove rails-ai-context from this Rails app completely. If the rails-ai-context entry in my MCP config runs `docker` (this app's Ruby lives in a container), run steps 1 and 3 inside that container, prefixed the way the entry's args are.
290
290
 
291
- 1. Run `bundle exec rails-ai-context uninstall` if the Gemfile lists rails-ai-context, else `rails-ai-context uninstall`. If the command is missing or unknown, run `gem install rails-ai-context -v '>= 5.35.0'` and then `rails-ai-context uninstall`.
291
+ 1. Run `bundle exec rails-ai-context uninstall` if the Gemfile lists rails-ai-context, else `rails-ai-context uninstall`. If the command is missing or unknown, run `gem install rails-ai-context -v '>= 5.35.0'` and then `rails-ai-context uninstall`. If its output names the Claude Code plugin, run the commands it names for it; if it does not, but rails-ai-context@rails-ai-context is enabled in .claude/settings.json, .claude/settings.local.json or my user settings, run `claude plugin disable rails-ai-context@rails-ai-context --scope local` here.
292
292
  2. If its output names a config/routes.rb line that mounts RailsAiContext::Engine, delete that line.
293
293
  3. If the Gemfile lists rails-ai-context, run `bundle remove rails-ai-context`.
294
294
  4. If .git/info/exclude lists rails-ai-context files (a private setup), delete those lines. If I added a rails-ai-context entry to another MCP client's own config (Claude Desktop, Windsurf, Zed and the like), remove that entry there too.
data/docs/SETUP.md CHANGED
@@ -91,6 +91,197 @@ This is what the generator writes for an in-Gemfile install. A standalone instal
91
91
 
92
92
  On Windows the command is `cmd` and `"/c"` goes ahead of the args (`["/c", "bundle", "exec", "rails-ai-context", "serve"]`): a gem's executables there are batch files, which a client that starts its server without a shell does not run. The generator writes that form on Windows, and `doctor` names an entry written for the other platform; see [GUIDE.md](GUIDE.md#mcp-server-setup) for teams on both.
93
93
 
94
+ ### As a plugin
95
+
96
+ The repository is also a Claude Code plugin marketplace. The plugin brings the
97
+ MCP server and, at the start of each session in a Rails app, the six rules the
98
+ context files open with. It writes no context files or MCP config, so it suits
99
+ a team that keeps its own `CLAUDE.md`; the install records it in
100
+ `.claude/settings.json`.
101
+
102
+ ```bash
103
+ gem install rails-ai-context # the plugin runs the installed gem
104
+ claude plugin install rails-ai-context --marketplace crisnahine/rails-ai-context --scope project
105
+ ```
106
+
107
+ In a session the second line is `/plugin install rails-ai-context --marketplace crisnahine/rails-ai-context`.
108
+ A Claude Code too old for `--marketplace` takes two steps:
109
+ `/plugin marketplace add crisnahine/rails-ai-context`, then
110
+ `/plugin install rails-ai-context@rails-ai-context`. Project scope records the
111
+ plugin in `.claude/settings.json` of the folder you run it in, so run it in the
112
+ app's folder; commit that file, and add the marketplace there too so a
113
+ teammate's Claude Code offers to install it:
114
+
115
+ ```json
116
+ {
117
+ "enabledPlugins": { "rails-ai-context@rails-ai-context": true },
118
+ "extraKnownMarketplaces": {
119
+ "rails-ai-context": { "source": { "source": "github", "repo": "crisnahine/rails-ai-context" } }
120
+ }
121
+ }
122
+ ```
123
+
124
+ A teammate who has the committed setting runs `claude plugin install
125
+ rails-ai-context --marketplace crisnahine/rails-ai-context --scope local`,
126
+ which leaves the committed file as it is.
127
+
128
+ - **Where it runs.** Claude Code reads `.claude/settings.json` only from the
129
+ folder a session starts in, so project scope reaches sessions started in the
130
+ app's folder. For sessions started in a folder inside the app, or in a
131
+ monorepo's app folder from the repository's root, enable it with `--scope
132
+ local` (the git repository's `settings.local.json`) or at user scope. The
133
+ server then reads the app Claude Code was started in, the app above that
134
+ folder, or the one app below it, as every command does. At user scope the
135
+ plugin starts in every project; outside a Rails app its server connects with
136
+ no tools and tells the session why. In a folder that holds several apps it
137
+ says to start Claude Code in one of them; for a session over all of them,
138
+ use the [workspace](CLI.md#init-standalone-only) entries `init` writes, and
139
+ turn the plugin off for that folder with `claude plugin disable
140
+ rails-ai-context@rails-ai-context --scope project` run there, or `--scope
141
+ local` where a `--scope local` install turns it on. On macOS and Linux a
142
+ local setting written at a git repository's root reaches every session in
143
+ that repository, the apps' too. On Windows, and where the repository's root
144
+ is your home folder or belongs to another user, a local setting reaches only
145
+ sessions started in the folder it was written in. Where `init` at a
146
+ repository's root wrote an app's own `.mcp.json`, which sessions started in
147
+ the app read, a `--scope local` install that reaches those sessions runs the
148
+ plugin beside it; `doctor` names the one to turn off.
149
+ - **The gem comes first.** The plugin needs rails-ai-context 5.35.1 or later,
150
+ installed for the `ruby` on Claude Code's `PATH` (Ruby 3.1 or later); `gem
151
+ update rails-ai-context` brings an older one up. A shim version manager
152
+ (rbenv, asdf, or mise with its shims on `PATH`) picks that Ruby by the folder
153
+ Claude Code starts in: that folder's `.ruby-version` or `.tool-versions`, or
154
+ the global one, so a session started above the app runs that folder's Ruby. A
155
+ shell-hook one (rvm, chruby, `mise activate`) leaves the Ruby of the shell
156
+ that started Claude Code, and a Claude Code started from the Dock or an IDE
157
+ may see the system Ruby instead. An app that also has the gem in its Gemfile
158
+ gets its bundled copy, as with any standalone install, a bundle kept under
159
+ its own path such as `vendor/bundle` too. A copy from git is the exception:
160
+ the installed copy serves and the app's boot loads the git copy over it, so
161
+ point the Gemfile at a release or a `path:` checkout. When the plugin cannot
162
+ serve, its server still connects, with no tools, and tells the session why,
163
+ naming the Ruby and the folder: no gem for that Ruby, an older one, a Ruby
164
+ too old, a bundle Claude Code inherited from `bundle exec` that lacks the
165
+ gem, several apps or none. The same line is the server's stderr, which
166
+ `claude --debug` shows. A start that fails after that, from the gem's own
167
+ error or an inherited bundle not installed for that Ruby (Bundler's trace,
168
+ [TROUBLESHOOTING.md](TROUBLESHOOTING.md#mcp-server-fails-to-start)), is
169
+ listed as failed in `/mcp`, and Claude Code then skips the server in new
170
+ sessions for about 15 minutes: reconnect it in `/mcp` once the cause is
171
+ fixed. A session gets no rules while the server has no tools for them to
172
+ name.
173
+ - **Install the gem, not its setup, for Claude Code.** Where the app's
174
+ `.claude/settings.json` turns the plugin on, the install generator and
175
+ `init` write no `.mcp.json` server and say why, and so does `init` in a
176
+ folder holding one app, where that folder's own `.claude/settings.json`
177
+ turns it on; it still writes the app's own `.mcp.json` for sessions started
178
+ in the app, which do not read that folder's settings, and says so. Where
179
+ only your own settings turn it on, they still write one for the team, and
180
+ their next step says to turn it off for yourself with `/mcp`.
181
+ - **The plugin or another server, not both.** Claude Code starts the plugin's
182
+ server and one from `.mcp.json` or `claude mcp add`, an HTTP entry under the
183
+ gem's name included, as two servers and lists every tool twice. `doctor`
184
+ reads Claude Code the way a session does, by the folder it started in: that
185
+ folder's settings and the local settings that reach it (its git
186
+ repository's, a linked worktree's being its repository's, as "Where it runs"
187
+ says), every `.mcp.json` from that folder up, the `/mcp` toggles and local
188
+ servers Claude Code keeps for the repository, the MCP policy in
189
+ `allowedMcpServers` and `deniedMcpServers` (by name, command or url), and a
190
+ deployed `managed-mcp.json`, whose servers are then the only ones Claude
191
+ Code starts, each still subject to `/mcp` and `deniedMcpServers`, and to
192
+ `allowedMcpServers` where its entry expands a `${VAR}`, and the marketplace
193
+ policy in `strictKnownMarketplaces` and `blockedMarketplaces`. It follows a
194
+ `CLAUDE_CONFIG_DIR` set in your settings' `env` block, as Claude Code does.
195
+ It does not see settings an organization delivers from the Claude console,
196
+ through MDM or the Windows registry, and it reads the managed settings files
197
+ as if all of them were in force; where policy comes that way, its MCP
198
+ verdicts can be wrong. It checks the shape of `enabledPlugins` only, while
199
+ Claude Code ignores a whole settings file that breaks its schema elsewhere
200
+ and says so when it starts: fix such a file first. It looks at the app, the
201
+ folder `doctor` runs in, the folders above the app that hold it alone, and
202
+ the folders Claude Code keeps projects for. The plugin counts where it is
203
+ enabled, installed for that project, not turned off in `/mcp` and not
204
+ blocked by policy; then Claude Code's MCP check passes without a
205
+ `.mcp.json`, and with no AI tools chosen it checks no other tool's config
206
+ unless that config is broken. Where the plugin runs only for sessions
207
+ started in another folder, `doctor` names that folder and what turns it on
208
+ for this one. Where Claude Code never ran, as on CI, what the plugin needs
209
+ is a warning, not a failure. Where it runs nowhere, `doctor` names why: not
210
+ installed (with the install that leaves a committed file alone), a local
211
+ marketplace folder that is gone, its server turned off in `/mcp`, the MCP or
212
+ marketplace policy, a managed settings file Claude Code cannot read, or a
213
+ `CLAUDE_CONFIG_DIR` that is empty or not an absolute path, set in the
214
+ environment or a settings `env` block (`doctor` names which), which leaves
215
+ each session reading its own folder's. A second server counts where such a
216
+ session would start it, and `doctor` names the command that removes it and
217
+ the folder to run it in: a `.mcp.json` entry comes out where the committed
218
+ settings turn the plugin on, and is turned off with `/mcp` where only your
219
+ own settings do.
220
+ - **The rules load once.** The hook skips them where Claude Code already loads
221
+ the generator's rules for that session: from the app's `CLAUDE.md` or
222
+ `.claude/rules/rails-mcp-tools.md`, or from its `AGENTS.md` where
223
+ `CLAUDE.md` imports it or no `CLAUDE.md` is on the way up from the folder
224
+ the session started in, or from a `CLAUDE.md`, `.claude/CLAUDE.md` or
225
+ `CLAUDE.local.md` on that way up that carries them, as an engine's above its
226
+ test/dummy app does (your own `~/.claude/CLAUDE.md` does not count). It
227
+ skips them too where `.rails-ai-context.yml` or a configure block in
228
+ `config/application.rb`, the environment's file or an initializer sets
229
+ `anti_hallucination_rules` to `false` or `nil`; a block's value wins over
230
+ the file's, as when the app boots. It reads that Ruby without running it, so
231
+ only a literal that ends its statement counts, and rule 3 leaves out the
232
+ `rails_get_config` sections `skip_tools` turns off, in the YAML or a literal
233
+ list, assigned or appended (`=`, `<<` chained or not, `+=`, `|=`, `push`,
234
+ `append`, `concat`); a symbol appended in place, a Set or a value built at
235
+ boot is not read, as the server skips none of those either. A session
236
+ started above the app gets the rules from the hook, and once a file in the
237
+ app is read, Claude Code also loads that app's `CLAUDE.md`, so such a
238
+ session can hold them twice. So can a session resumed after the app's
239
+ `CLAUDE.md` gained the rules (from `init`, `context` or a pull), until
240
+ `/clear` or a compaction.
241
+ - **Windows works the same.** The server starts `ruby` without a shell, so it
242
+ needs no `cmd /c`.
243
+ - **One allowlist entry lasts.** The server's command line names no plugin
244
+ folder, so no update changes it, and under an `allowedMcpServers` list this
245
+ entry admits it (`doctor` names it where it is missing). It admits any plugin
246
+ that ships the same line, too. Where the list admits other stdio servers by
247
+ `serverName`, adding this entry switches every stdio server to matching by
248
+ command, so each of them needs a `serverCommand` entry as well; `doctor`
249
+ says so. Naming no script also keeps rbenv from picking the Ruby by the
250
+ plugin's own folder.
251
+
252
+ ```json
253
+ {"serverCommand":["ruby","-e","load File.join(ENV.fetch('CLAUDE_PLUGIN_ROOT'), 'scripts', 'serve.rb')"]}
254
+ ```
255
+ - **Permission rules name the plugin's server.** Its tools are
256
+ `mcp__plugin_rails-ai-context_rails-ai-context__<tool>`, so a rule for the
257
+ `.mcp.json` server (`mcp__rails-ai-context`) does not cover them;
258
+ `mcp__plugin_rails-ai-context_rails-ai-context` allows them all.
259
+ - **A slow app's boot.** The plugin's server entry is the plugin's own, so set
260
+ `RAILS_AI_CONTEXT_BOOT_TIMEOUT` and `MCP_TIMEOUT` in Claude Code's settings
261
+ `env` (user, project or local) or in the shell that starts Claude Code; see
262
+ [TROUBLESHOOTING.md](TROUBLESHOOTING.md#answers-say-boot-did-not-finish-within-20s).
263
+ - **Updates follow this repository.** The plugin's version is the commit it was
264
+ installed from. Claude Code updates it only with auto-update on (under
265
+ `/plugin`, Marketplaces) or `claude plugin update
266
+ rails-ai-context@rails-ai-context`. The server is versioned by the gem: `gem
267
+ update rails-ai-context`, then reconnect the server in `/mcp` or start a new
268
+ session. Run `gem cleanup` only after that: a running server loads its files
269
+ as it needs them, so once its copy is gone, a call that needs a file it has
270
+ not loaded yet answers with a request to reconnect it.
271
+ - **Removing it** from one app is `claude plugin disable
272
+ rails-ai-context@rails-ai-context --scope local` run there, which wins over
273
+ your own and the committed settings for every session the local setting
274
+ reaches ("Where it runs"). Taking an install out is `claude plugin uninstall
275
+ rails-ai-context@rails-ai-context --scope <scope>`, with the scope it went in
276
+ at, run in the folder it was installed from: once for a user install, once
277
+ per project for a project or local one. A marketplace added from a local
278
+ folder or file runs the plugin with no install, so there only the disable
279
+ turns it off. The gem's `uninstall` leaves Claude Code's
280
+ settings alone and names those commands, one disable per repository whose
281
+ sessions run the plugin, before it suggests removing the gem, which the
282
+ plugin runs; where managed settings turn the plugin on, or a deployed
283
+ `managed-mcp.json` runs the gem, it says to ask whoever manages them.
284
+
94
285
  ### Split rules with `paths:` frontmatter
95
286
 
96
287
  Claude Code loads `.claude/rules/` files conditionally based on YAML frontmatter:
data/docs/STANDALONE.md CHANGED
@@ -60,7 +60,7 @@ rails-ai-context version # Show version
60
60
  1. **Loads only its boot shim** before the app - the binary requires the two files it needs to boot Rails, then `config/environment.rb`, and requires the gem itself only after the boot returns. Nothing it loads first is a gem an app pins: it reads the Gemfile and `config/boot.rb` with Ruby's own Ripper, not the prism gem, and loads json only once the app's bundle is set up
61
61
  2. **Restores `$LOAD_PATH`** entries that `Bundler.setup` strips (since the gem isn't in the Gemfile). The gem's own dependencies come off the load path for the duration of the boot, so every gem the app locks resolves to the app's pin, and go back behind it afterwards
62
62
  3. **YAML config** - uses `.rails-ai-context.yml` instead of a Ruby initializer
63
- 4. **Steps aside for the app's own copy** - in an app whose bundle carries its own rails-ai-context (another installed version, or a `path:` copy), a command that boots the app runs through that copy, as `bundle exec rails-ai-context` would, and says so on stderr. That is the copy the app's MCP configs start, and two copies in one process would each load half the gem. The bundle is the one `BUNDLE_GEMFILE` names when you set it (a dual boot's `Gemfile.next`), and a command typed in a subdirectory runs from the app root it found. `init` asks its questions itself and has that copy write only the context files; an MCP-only setup, chosen with `--mcp-only` or at the prompt, runs nothing of the app's. So does `--no-boot`: bundle exec would evaluate the app's Gemfile and start whatever copy the app names, which on a repo just cloned is code nobody has read. A bundle not installed yet (`bundle check` fails) is left alone too: its boot fails, and the static tier answers. A copy installed only under a vendored bundle path or from git is not seen from outside the bundle, so there the installed copy runs
63
+ 4. **Steps aside for the app's own copy** - in an app whose bundle carries its own rails-ai-context (another installed version, or a `path:` copy), a command that boots the app runs through that copy, as `bundle exec rails-ai-context` would, and says so on stderr. That is the copy the app's MCP configs start, and two copies in one process would each load half the gem. The bundle is the one `BUNDLE_GEMFILE` names when you set it (a dual boot's `Gemfile.next`), and a command typed in a subdirectory runs from the app root it found. `init` asks its questions itself and has that copy write only the context files; an MCP-only setup, chosen with `--mcp-only` or at the prompt, runs nothing of the app's. So does `--no-boot`: bundle exec would evaluate the app's Gemfile and start whatever copy the app names, which on a repo just cloned is code nobody has read. A bundle not installed yet (`bundle check` fails) is left alone too: its boot fails, and the static tier answers. A copy installed under the bundle's own path (`bundle config set path vendor/bundle`, or a deployment bundle) is handed the run as well. A copy from git is not seen from outside the bundle, so there the installed copy runs and the app's boot loads the bundle's copy over it: in such an app, start the server with `bundle exec rails-ai-context`.
64
64
 
65
65
  This means you get the same 35 tools, same MCP server, same context generation - without touching the project's Gemfile.
66
66
 
@@ -127,6 +127,8 @@ Codex reads `config.toml` as TOML, which is UTF-8, and loads nothing from a file
127
127
  - `can't find executable rails-ai-context for gem rails-ai-context`: the bundle's copy of the gem lists no executable, as a `path:` copy of 5.32.2 or earlier outside a git checkout does. Point the Gemfile at a git checkout or a release.
128
128
  - On Windows, a config that runs `bundle` or `rails-ai-context` itself rather than through `cmd /c`: those are batch files there, which Claude Code, Codex and the other clients that start a server without a shell do not run (`doctor` warns about it). Run the install again; on Windows it writes `cmd /c bundle exec rails-ai-context serve`.
129
129
  - On macOS or Linux, a config that runs `cmd /c ...`: it was written on Windows, and there is no `cmd` here (`doctor` fails it). Run the install again on this machine, and keep the MCP configs out of git if the team works on both.
130
+ - The Claude Code plugin's server connects with no tools: it tells the session why (no gem for its Ruby, an older one, a Ruby too old, several apps or none) and what to run; `claude --debug` shows the same line as its stderr.
131
+ - The Claude Code plugin's server is listed as failed in `/mcp`, and `claude --debug` shows a `Bundler::GemNotFound` trace in its stderr: Claude Code was started from `bundle exec`, or from a shell holding the `RUBYOPT` or `BUNDLER_SETUP` it sets, for a bundle not installed for the plugin's Ruby, which fails before the plugin runs. Start Claude Code outside `bundle exec`, or unset those two where a shell profile sets them. After a failed start Claude Code skips the server in new sessions for about 15 minutes, so reconnect it in `/mcp` once the cause is fixed.
130
132
 
131
133
  Check for Bundler/Ruby path issues:
132
134
 
@@ -148,8 +150,10 @@ command gives it 60. Start the service, or, for an app that is healthy but
148
150
  slow to boot, raise both limits in the server's MCP entry: the boot's with
149
151
  `RAILS_AI_CONTEXT_BOOT_TIMEOUT` (seconds) in its `env`, and the client's with
150
152
  its own setting (Claude Code reads `MCP_TIMEOUT`, in milliseconds). Raising
151
- only the boot's leaves a client that gives up first. `rails ai:serve` has no
152
- static tier, so it exits with the same message instead.
153
+ only the boot's leaves a client that gives up first. The Claude Code plugin's
154
+ entry is the plugin's own: set both in Claude Code's settings `env` (user,
155
+ project or local) or in the shell that starts Claude Code. `rails ai:serve`
156
+ has no static tier, so it exits with the same message instead.
153
157
 
154
158
  ### A server set up for a folder of apps fails to start
155
159