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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +125 -0
- data/README.md +6 -0
- data/docs/CLI.md +1 -1
- data/docs/COMPATIBILITY.md +10 -0
- data/docs/GUIDE.md +1 -1
- data/docs/PROMPTS.md +3 -3
- data/docs/SETUP.md +191 -0
- data/docs/STANDALONE.md +1 -1
- data/docs/TROUBLESHOOTING.md +6 -2
- data/exe/rails-ai-context +53 -20
- data/lib/generators/rails_ai_context/install/install_generator.rb +8 -4
- data/lib/rails_ai_context/boot_manager.rb +7 -1
- data/lib/rails_ai_context/claude_code_settings.rb +1006 -0
- data/lib/rails_ai_context/cli/app_root.rb +126 -16
- data/lib/rails_ai_context/cli/entry_boot.rb +58 -6
- data/lib/rails_ai_context/configuration.rb +116 -34
- data/lib/rails_ai_context/doctor.rb +478 -23
- data/lib/rails_ai_context/gem_lock.rb +14 -7
- data/lib/rails_ai_context/initializer_settings.rb +4 -1
- data/lib/rails_ai_context/install/claude_plugin_removal.rb +107 -0
- data/lib/rails_ai_context/install/program.rb +133 -6
- data/lib/rails_ai_context/install/selection_record.rb +11 -5
- data/lib/rails_ai_context/introspectors/gemfile_gems.rb +2 -2
- data/lib/rails_ai_context/mcp_config_generator.rb +18 -6
- data/lib/rails_ai_context/redaction.rb +101 -14
- data/lib/rails_ai_context/resources.rb +15 -0
- data/lib/rails_ai_context/secret_columns.rb +1 -1
- data/lib/rails_ai_context/server.rb +6 -1
- data/lib/rails_ai_context/tools/safe_call.rb +5 -0
- data/lib/rails_ai_context/tools/search_docs.rb +2 -1
- data/lib/rails_ai_context/update_check.rb +17 -4
- data/lib/rails_ai_context/version.rb +1 -1
- data/lib/rails_ai_context.rb +26 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e4f5530fd8b0a92932d1810f018d01de51af456064f92de2f9b95749360e43a5
|
|
4
|
+
data.tar.gz: dd8098d2f6d049088e92d857a407a69e84a19963379eaa698749bab6d5564539
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
|
data/docs/COMPATIBILITY.md
CHANGED
|
@@ -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.
|
|
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
|
|
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
|
|
data/docs/TROUBLESHOOTING.md
CHANGED
|
@@ -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.
|
|
152
|
-
|
|
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
|
|