rails-ai-context 5.26.0 → 5.27.0
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 +140 -0
- data/README.md +3 -1
- data/docs/COMPATIBILITY.md +4 -1
- data/docs/CONFIGURATION.md +27 -0
- data/docs/FAQ.md +13 -0
- data/docs/INTROSPECTORS.md +1 -1
- data/docs/QUICKSTART.md +5 -1
- data/docs/SETUP.md +4 -0
- data/docs/STANDALONE.md +3 -0
- data/docs/TOOLS.md +12 -6
- data/exe/rails-ai-context +46 -16
- data/lib/generators/rails_ai_context/install/install_generator.rb +54 -11
- data/lib/rails_ai_context/action_filters.rb +42 -5
- data/lib/rails_ai_context/configuration.rb +8 -1
- data/lib/rails_ai_context/doctor.rb +4 -0
- data/lib/rails_ai_context/erb_source.rb +45 -0
- data/lib/rails_ai_context/gem_lock.rb +18 -2
- data/lib/rails_ai_context/hydrators/controller_hydrator.rb +1 -2
- data/lib/rails_ai_context/hydrators/model_hints.rb +5 -2
- data/lib/rails_ai_context/install/program.rb +33 -9
- data/lib/rails_ai_context/install/selection_record.rb +72 -0
- data/lib/rails_ai_context/introspectors/active_support_introspector.rb +9 -0
- data/lib/rails_ai_context/introspectors/api_introspector.rb +87 -8
- data/lib/rails_ai_context/introspectors/convention_introspector.rb +17 -1
- data/lib/rails_ai_context/introspectors/env_config_introspector.rb +47 -7
- data/lib/rails_ai_context/introspectors/gem_introspector.rb +58 -4
- data/lib/rails_ai_context/introspectors/job_introspector.rb +36 -4
- data/lib/rails_ai_context/introspectors/listeners/config_assignment_listener.rb +36 -0
- data/lib/rails_ai_context/introspectors/listeners/routes_dsl_listener.rb +22 -4
- data/lib/rails_ai_context/introspectors/model_introspector.rb +56 -15
- data/lib/rails_ai_context/introspectors/performance_introspector.rb +70 -2
- data/lib/rails_ai_context/introspectors/route_introspector.rb +30 -13
- data/lib/rails_ai_context/introspectors/view_introspector.rb +1 -0
- data/lib/rails_ai_context/introspectors/view_template_introspector.rb +16 -7
- data/lib/rails_ai_context/output_guard.rb +43 -3
- data/lib/rails_ai_context/tasks/rails_ai_context.rake +34 -8
- data/lib/rails_ai_context/tools/analyze_feature.rb +7 -1
- data/lib/rails_ai_context/tools/base_tool.rb +9 -0
- data/lib/rails_ai_context/tools/dependency_graph.rb +96 -15
- data/lib/rails_ai_context/tools/generate_test.rb +110 -14
- data/lib/rails_ai_context/tools/get_active_support.rb +5 -1
- data/lib/rails_ai_context/tools/get_api.rb +24 -0
- data/lib/rails_ai_context/tools/get_callbacks.rb +6 -6
- data/lib/rails_ai_context/tools/get_controllers.rb +33 -3
- data/lib/rails_ai_context/tools/get_env.rb +68 -31
- data/lib/rails_ai_context/tools/get_gems.rb +9 -2
- data/lib/rails_ai_context/tools/get_job_pattern.rb +25 -3
- data/lib/rails_ai_context/tools/get_model_details.rb +2 -1
- data/lib/rails_ai_context/tools/get_partial_interface.rb +12 -20
- data/lib/rails_ai_context/tools/get_routes.rb +6 -2
- data/lib/rails_ai_context/tools/get_service_pattern.rb +81 -20
- data/lib/rails_ai_context/tools/get_view.rb +9 -1
- data/lib/rails_ai_context/tools/onboard.rb +5 -0
- data/lib/rails_ai_context/tools/query.rb +6 -1
- data/lib/rails_ai_context/tools/search_code.rb +38 -7
- data/lib/rails_ai_context/tools/validate_semantics.rb +32 -1
- data/lib/rails_ai_context/version.rb +1 -1
- data/lib/rails_ai_context/vfs.rb +22 -2
- data/lib/rails_ai_context/view_file.rb +38 -0
- data/lib/rails_ai_context/watcher.rb +4 -1
- data/lib/rails_ai_context.rb +7 -1
- data/server.json +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 44038590682c51bc7722a4a5b587ee31b5b78f3842575b6386390a584038b81e
|
|
4
|
+
data.tar.gz: 4c7de07da1f44144291ba86e9bfc34ab3a3da893c0a159b8cfe99de284d3d3be
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b581d96cb4ff655823a103c21527a53ddb71c3cb36d644a59485a796693001e247f6480b381d1f54ea8ec0995e175aa0389109fe1155bfbeea2dfeefd5566d9c
|
|
7
|
+
data.tar.gz: 61c4aa682dd49afaf780652300f41de2216a0bfbe0b6ed7e6ec188237c63eade5036fe2051ba6771f89e96803a0971811230e532a7c623d7a25d0bfb1f069df8
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,146 @@ 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.27.0] - 2026-09-22
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **MCP-only install (`--mcp-only`, `config.context_files`).** Some apps keep
|
|
13
|
+
their own `CLAUDE.md`, `AGENTS.md`, rules files and Copilot instructions and
|
|
14
|
+
want the server and nothing else. There was no supported way to ask for it:
|
|
15
|
+
every install entry point ended by generating context files. The install
|
|
16
|
+
menu now has a third answer, `rails generate rails_ai_context:install
|
|
17
|
+
--mcp-only` and `rails-ai-context init --mcp-only` take it non-interactively,
|
|
18
|
+
and the choice is recorded in the initializer and the YAML like the tool
|
|
19
|
+
mode. With it off, `ai:context` writes nothing and exits 0, `ai:watch` writes
|
|
20
|
+
nothing, `ai:doctor` raises no context-file warning, and the `.ai-context.json`
|
|
21
|
+
line is left out of `.gitignore` because nothing writes that file. A command
|
|
22
|
+
that names a file still writes it: `ai:context:claude` and
|
|
23
|
+
`context --format claude` both work.
|
|
24
|
+
- **Sidekiq workers in `job_pattern`.** A class that includes `Sidekiq::Job` is
|
|
25
|
+
not an ActiveJob descendant and does not live in `app/jobs`, so both job
|
|
26
|
+
passes missed it and no tool in either tier could describe the biggest code
|
|
27
|
+
area of an app that runs its background work that way. Workers are read from
|
|
28
|
+
`app/workers` in both tiers, with each one's `sidekiq_options` and `perform`
|
|
29
|
+
signature. The conventions directory structure counts every directory the app
|
|
30
|
+
keeps under `app/` rather than a fixed list.
|
|
31
|
+
- **ActiveInteraction services.** `service_pattern` lists a service's declared
|
|
32
|
+
filters with their types and defaults, names `ActiveInteraction::Base` as the
|
|
33
|
+
dominant pattern when it is, and `generate_test` writes `.run` with those
|
|
34
|
+
filters rather than a `.call` the base class does not define.
|
|
35
|
+
- **Notable gems that shape an app.** `active_interaction`, `paper_trail`,
|
|
36
|
+
`rack-cors`, `figaro`, `webauthn`, `stripe`, `plaid`, `braintree`,
|
|
37
|
+
`lockbox`, `blind_index`, `neighbor`, `pgvector`, `interactor`,
|
|
38
|
+
`trailblazer-operation` and the Sidekiq add-ons (`sidekiq-pro`,
|
|
39
|
+
`sidekiq-scheduler`, `sidekiq-cron`, `sidekiq-unique-jobs`,
|
|
40
|
+
`sidekiq-throttled`).
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
|
|
44
|
+
- **`config.ai_tools = []` writes no context files.** It used to write every
|
|
45
|
+
tool's files, which is the opposite of what the value says and of what
|
|
46
|
+
`ContextFileSerializer` has always done with `format: []`. Only an unset
|
|
47
|
+
selection means "all". The install flow never produced an empty list, so this
|
|
48
|
+
reaches hand-edited configs only.
|
|
49
|
+
- **The inherited filter list is emitted root first.** Rails runs the root's
|
|
50
|
+
callbacks first, and the static tier printed the nearest parent's first, so a
|
|
51
|
+
chain read as authentication running before the current user is loaded.
|
|
52
|
+
- **A filter no ancestor's body declares names no class.** `sentry_around_action`
|
|
53
|
+
and `set_paper_trail_whodunnit` arrive through a gem's
|
|
54
|
+
`on_load :action_controller` block; crediting them to the nearest app
|
|
55
|
+
controller sent an agent to a file that never mentions them. They now carry
|
|
56
|
+
`provenance` instead of `from`.
|
|
57
|
+
- **Model callbacks print the macro Rails has.** `after_commit_on_create` is a
|
|
58
|
+
key this gem synthesizes to order the events of one `after_commit on: [...]`;
|
|
59
|
+
copying it got a `NoMethodError`. Every renderer prints
|
|
60
|
+
`after_commit (on: :create)`.
|
|
61
|
+
- **`sanitize_options` keeps Array, numeric, boolean, nil and Symbol option
|
|
62
|
+
values.** They were stringified, so `in: %w[draft sent]` reached
|
|
63
|
+
`generate_test` as one String and `in_array` got a quoted list. A consumer
|
|
64
|
+
reading `validations[].options`, `.ai-context.json` included, sees the
|
|
65
|
+
change: `dependent: :destroy` is the Symbol `:destroy` rather than
|
|
66
|
+
`"destroy"`, and `allow_nil: false` is `false` rather than the truthy String
|
|
67
|
+
`"false"`.
|
|
68
|
+
- **Only a handler extension counts as a template.** A JPEG or a seed file under
|
|
69
|
+
`app/views` was counted as a template and had ivar names read out of its
|
|
70
|
+
bytes.
|
|
71
|
+
|
|
72
|
+
### Fixed
|
|
73
|
+
|
|
74
|
+
Defects found by a tenth QA round of v5.26.0 against a private Rails 8.0.5.1
|
|
75
|
+
API-only app (issues #184 to #222), each rebuilt on a minimal fixture before
|
|
76
|
+
filing.
|
|
77
|
+
|
|
78
|
+
- **One dangling reflection cost the whole model.** A `has_many :through` naming
|
|
79
|
+
an association the model does not declare loads fine and only raises when
|
|
80
|
+
something touches it, so `class_name` ended in `nil.klass` and the per-model
|
|
81
|
+
rescue replaced the model - its callbacks, its table heading, its graph node -
|
|
82
|
+
with a single error line. The rescue is per association now, and the
|
|
83
|
+
reflection is marked `[UNAVAILABLE: through :x is not an association]`.
|
|
84
|
+
- **The MCP transport lost its stdout across a Bundler re-exec.** `exec` closed
|
|
85
|
+
the saved descriptor, so the new image saved fd 1, by then pointing at stderr,
|
|
86
|
+
and wrote every JSON-RPC response there. A client launched from outside the
|
|
87
|
+
app got no answer to `initialize`.
|
|
88
|
+
- **`dependency_graph` drew nodes no app defines.** A `through` hop was the
|
|
89
|
+
association name camelized (`PrimaryBuyer`, `InvoicePdfAttachment`), the
|
|
90
|
+
static target ignored `source:`, and a derived name knew none of the app's
|
|
91
|
+
acronyms. It also cut the graph at 50 models without saying so.
|
|
92
|
+
- **`service_pattern` named a service after a word in a comment.** The regex ran
|
|
93
|
+
over raw source, never matched `module`, and its basename fallback dropped
|
|
94
|
+
every namespace. The lookup matched by basename before exact path, so only
|
|
95
|
+
the alphabetically first `create.rb` could be looked up, and "Called By" was a
|
|
96
|
+
substring search that listed a non-caller and dropped the real one.
|
|
97
|
+
- **Static route helper names did not exist.** Hyphens were kept
|
|
98
|
+
(`api_v1_gift-cards_redeem_path` is a subtraction in Ruby), a dotted path was
|
|
99
|
+
used in the name where Rails uses none, and a name that cannot be one was
|
|
100
|
+
kept anyway. A booted redirect route appeared in no row and no count.
|
|
101
|
+
- **`get_context` for one action listed every strong-params method in the
|
|
102
|
+
controller**, so `create_params`' permit list read as the fields `deactivate`
|
|
103
|
+
accepts.
|
|
104
|
+
- **Controller Schema Hints reported services, serializers and plain constants
|
|
105
|
+
as missing models.** Only names that resolve to a model are kept now, and the
|
|
106
|
+
rest are dropped without a line.
|
|
107
|
+
- **`env` read only `.rb` files**, so ENV names in `config/*.yml`, ERB views and
|
|
108
|
+
rake tasks were missing with nothing saying a file type was skipped. Category
|
|
109
|
+
matching was unanchored (`PORT` inside `PORTAL`), and a `nil` default printed
|
|
110
|
+
as `[FILTERED]`.
|
|
111
|
+
- **`env_config` reported the first assignment in a file**, so it printed the
|
|
112
|
+
branch that is not running and disagreed with `config` on the same app.
|
|
113
|
+
- **`gems` reported a Minitest suite in a `test/` directory that is not there**,
|
|
114
|
+
from a lockfile entry every Rails app resolves through activesupport, and
|
|
115
|
+
pointed at a `config/sidekiq.yml` without checking that it exists.
|
|
116
|
+
- **`generate_test` wrote specs that cannot run.** Shoulda matchers were emitted
|
|
117
|
+
into apps that do not bundle the gem, a namespaced controller produced
|
|
118
|
+
`create(:api/v1/admin/order)`, the example sent GET whatever the route's verb,
|
|
119
|
+
and a controller with no file was answered with "no routes found".
|
|
120
|
+
- **`performance_check` suggested indexes and counters the app cannot use.**
|
|
121
|
+
Every unindexed `*_id` column was a missing foreign key index whatever its
|
|
122
|
+
type, and a counter the app maintains itself was offered a `counter_cache`
|
|
123
|
+
that double-counts every create.
|
|
124
|
+
- **`query` answered an unknown column with "Database not found" and exit 0.**
|
|
125
|
+
Postgres words a missing column, table and database the same way.
|
|
126
|
+
- **`view` counted images and text files as templates**, read ivars out of
|
|
127
|
+
binary data, and read the CSS rule `@page` as an ivar.
|
|
128
|
+
- **`partial_interface` could not resolve a `.text.erb` partial** by the Rails
|
|
129
|
+
name its own "Available" list had just printed, and cut a local's method calls
|
|
130
|
+
at ten with no marker.
|
|
131
|
+
- **`api` merged every CORS allow block and environment branch into one origin
|
|
132
|
+
list**, so the line read as the API allowing `*` on every resource.
|
|
133
|
+
- **`active_support` listed validator classes as "plain module" concerns.**
|
|
134
|
+
- **`validate` flagged an `acceptance:` virtual attribute as a missing column**
|
|
135
|
+
and suggested a migration for a column nobody needs.
|
|
136
|
+
- **`search_code --match-type trace` reported no internal calls** for a body
|
|
137
|
+
whose calls take no parentheses, counted a comment mentioning the method as a
|
|
138
|
+
call site, and tagged `app/services/models/...` as a Model.
|
|
139
|
+
- **Static answers missed an app's inflections.** A route group found no
|
|
140
|
+
controller for `api/v1/ai_matches`, and a service file with no `class` line
|
|
141
|
+
was named by its camelized basename.
|
|
142
|
+
- **The `controllers/{name}` resource refused a short name** the `routes/{name}`
|
|
143
|
+
resource accepts, and the controller answer pointed at a model that does not
|
|
144
|
+
exist.
|
|
145
|
+
- **`ai:watch` rewrote every tool's files** whatever the configuration asked
|
|
146
|
+
for.
|
|
147
|
+
|
|
8
148
|
## [5.26.0] - 2026-09-11
|
|
9
149
|
|
|
10
150
|
### Added
|
data/README.md
CHANGED
|
@@ -87,7 +87,9 @@ bundle add rails-ai-context --group development
|
|
|
87
87
|
rails generate rails_ai_context:install
|
|
88
88
|
```
|
|
89
89
|
|
|
90
|
-
The generator asks which AI tools you use and
|
|
90
|
+
The generator asks which AI tools you use and what to write, then creates the context files, the MCP config for each tool, and `config/initializers/rails_ai_context.rb`. Re-running it is safe; it keeps what you have and adds what is missing.
|
|
91
|
+
|
|
92
|
+
Keeping your own `CLAUDE.md` and `AGENTS.md`? `rails generate rails_ai_context:install --mcp-only` writes the MCP config and leaves every context file alone.
|
|
91
93
|
|
|
92
94
|
### Install standalone
|
|
93
95
|
|
data/docs/COMPATIBILITY.md
CHANGED
|
@@ -200,7 +200,10 @@ Proof sources:
|
|
|
200
200
|
(Rails 8.1, Ruby 3.4) in the v5.25.0 release QA, booted and static tiers,
|
|
201
201
|
standalone and in-Gemfile installs; Mastodon again in the v5.26.0 release QA,
|
|
202
202
|
with packs, in-repo engines, Postgres and concurrent tool calls covered by
|
|
203
|
-
hand where no lab shape plants them.
|
|
203
|
+
hand where no lab shape plants them; a private Rails 8.0.5.1 API-only app
|
|
204
|
+
(Ruby 3.4.10, 133 models, 102 controllers, 1630 ActiveInteraction services,
|
|
205
|
+
516 Sidekiq workers) in the v5.27.0 QA round, booted and static tiers, with
|
|
206
|
+
every report rebuilt on a minimal Rails 8.0.5.1 fixture before it was filed.
|
|
204
207
|
2. Non-crash coverage for every built-in tool including `get_view` in
|
|
205
208
|
`spec/e2e/in_gemfile_install_spec.rb`'s full-tool sweep; output correctness
|
|
206
209
|
(ivar cross-check, render-form detection, partial interfaces) verified
|
data/docs/CONFIGURATION.md
CHANGED
|
@@ -51,6 +51,33 @@ preset: full
|
|
|
51
51
|
|:-------|:-----|:--------|:------------|
|
|
52
52
|
| `ai_tools` | Array of symbols | `[:claude]` | Which AI tools to generate context for. Options: `:claude`, `:cursor`, `:copilot`, `:opencode`, `:codex` |
|
|
53
53
|
| `tool_mode` | Symbol | `:mcp` | `:mcp` (MCP server primary, CLI fallback) or `:cli` (CLI only, no MCP server) |
|
|
54
|
+
| `context_files` | Boolean | `true` | Set `false` for MCP-only: the server and the CLI still answer, and no context file is written or touched |
|
|
55
|
+
|
|
56
|
+
#### MCP only
|
|
57
|
+
|
|
58
|
+
Some apps keep their own `CLAUDE.md`, `AGENTS.md` and rules files and want the
|
|
59
|
+
server and nothing else:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
rails generate rails_ai_context:install --mcp-only # or: rails-ai-context init --mcp-only
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
That writes the MCP config for the tools you pick and records:
|
|
66
|
+
|
|
67
|
+
```ruby
|
|
68
|
+
RailsAiContext.configure do |config|
|
|
69
|
+
config.tool_mode = :mcp
|
|
70
|
+
config.context_files = false
|
|
71
|
+
end
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`rails ai:context` then writes nothing and exits 0, `rails ai:watch` writes
|
|
75
|
+
nothing, and `rails ai:doctor` raises no context-file warning. A command that
|
|
76
|
+
names a file still writes it: `rails ai:context:claude` and
|
|
77
|
+
`rails-ai-context context --format claude`.
|
|
78
|
+
|
|
79
|
+
`config.ai_tools = []` means no context files too, and still picks which MCP
|
|
80
|
+
config file is written. Before v5.27.0 an empty list wrote every tool's files.
|
|
54
81
|
|
|
55
82
|
### Introspection
|
|
56
83
|
|
data/docs/FAQ.md
CHANGED
|
@@ -59,6 +59,19 @@ Yes, freely. Both generate identical context files and provide the same 45 tools
|
|
|
59
59
|
**Don't commit:**
|
|
60
60
|
- `.ai-context.json` - auto-added to .gitignore by the install generator
|
|
61
61
|
|
|
62
|
+
### Can I use only the MCP server?
|
|
63
|
+
|
|
64
|
+
Yes:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
rails generate rails_ai_context:install --mcp-only # or: rails-ai-context init --mcp-only
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The MCP config is written, `config.context_files = false` is recorded, and no
|
|
71
|
+
`CLAUDE.md`, `AGENTS.md`, rules file or `.ai-context.json` is written or
|
|
72
|
+
touched. Every tool still answers over MCP and over the CLI. See
|
|
73
|
+
[CONFIGURATION.md](CONFIGURATION.md#mcp-only).
|
|
74
|
+
|
|
62
75
|
---
|
|
63
76
|
|
|
64
77
|
## MCP & Tools
|
data/docs/INTROSPECTORS.md
CHANGED
|
@@ -126,7 +126,7 @@ end
|
|
|
126
126
|
|
|
127
127
|
| Introspector | Key | What it extracts |
|
|
128
128
|
|:-------------|:----|:-----------------|
|
|
129
|
-
| JobIntrospector | `:jobs` | Background jobs and mailers: queue, retries, schedules, and the `file:` each one is defined in |
|
|
129
|
+
| JobIntrospector | `:jobs` | Background jobs, Sidekiq workers under `app/workers`, and mailers: queue, retries, `sidekiq_options`, schedules, and the `file:` each one is defined in |
|
|
130
130
|
| RakeTaskIntrospector | `:rake_tasks` | Custom rake tasks |
|
|
131
131
|
|
|
132
132
|
### Security & Auth
|
data/docs/QUICKSTART.md
CHANGED
|
@@ -23,7 +23,11 @@ rails generate rails_ai_context:install
|
|
|
23
23
|
The generator asks two questions:
|
|
24
24
|
|
|
25
25
|
1. **Which AI tools do you use?** - Claude Code, Cursor, GitHub Copilot, OpenCode, Codex CLI, or all
|
|
26
|
-
2. **
|
|
26
|
+
2. **What should rails-ai-context write?** - MCP config + context files (default), context files only (CLI mode), or MCP config only
|
|
27
|
+
|
|
28
|
+
The third answer is MCP-only: the server and the CLI answer in full, and your
|
|
29
|
+
own `CLAUDE.md`, `AGENTS.md` and rules files are left alone. Non-interactively
|
|
30
|
+
that is `--mcp-only`.
|
|
27
31
|
|
|
28
32
|
That's it. Your AI tool now has live access to your schema, models, routes, controllers, views, and conventions.
|
|
29
33
|
|
data/docs/SETUP.md
CHANGED
|
@@ -66,6 +66,10 @@ This creates:
|
|
|
66
66
|
- `.claude/rules/rails-context.md` - General context rules (always loaded)
|
|
67
67
|
- `.claude/rules/rails-mcp-tools.md` - Tool reference (always loaded)
|
|
68
68
|
|
|
69
|
+
Keeping your own `CLAUDE.md`? Add `--mcp-only` and only `.mcp.json` is
|
|
70
|
+
written; every context file is left alone. See
|
|
71
|
+
[CONFIGURATION.md](CONFIGURATION.md#mcp-only).
|
|
72
|
+
|
|
69
73
|
### Manual MCP config
|
|
70
74
|
|
|
71
75
|
If you need to configure manually, create `.mcp.json`:
|
data/docs/STANDALONE.md
CHANGED
|
@@ -143,6 +143,9 @@ rails-ai-context init
|
|
|
143
143
|
|
|
144
144
|
The MCP config files are updated automatically. Both modes generate identical context files and provide the same 45 tools.
|
|
145
145
|
|
|
146
|
+
Both also take `--mcp-only`, which writes the MCP config and no context files
|
|
147
|
+
at all. See [CONFIGURATION.md](CONFIGURATION.md#mcp-only).
|
|
148
|
+
|
|
146
149
|
## Troubleshooting
|
|
147
150
|
|
|
148
151
|
### "Bundler::GemNotFound" on `rails-ai-context serve`
|
data/docs/TOOLS.md
CHANGED
|
@@ -349,7 +349,7 @@ Notable gems with versions, categories, and config file locations.
|
|
|
349
349
|
|
|
350
350
|
### `rails_get_env`
|
|
351
351
|
|
|
352
|
-
Environment variables + credentials keys (values are never exposed).
|
|
352
|
+
Environment variables + credentials keys (values are never exposed). Scans `.rb`, `.rake`, ERB views and config YAML under `app`, `config` and `lib`; files matching `sensitive_patterns` (`config/database.yml`, credentials, keys) are never read, and the answer says so.
|
|
353
353
|
|
|
354
354
|
| Parameter | Type | Default | Description |
|
|
355
355
|
|:----------|:-----|:--------|:------------|
|
|
@@ -374,7 +374,9 @@ Service object interface, dependencies, side effects, callers.
|
|
|
374
374
|
|
|
375
375
|
### `rails_get_job_pattern`
|
|
376
376
|
|
|
377
|
-
Background job queue, retries, guard clauses, broadcasts, schedules.
|
|
377
|
+
Background job queue, retries, guard clauses, broadcasts, schedules. Sidekiq
|
|
378
|
+
workers under `app/workers` are listed alongside the ActiveJob jobs, with
|
|
379
|
+
their `sidekiq_options` and `perform` signature.
|
|
378
380
|
|
|
379
381
|
| Parameter | Type | Default | Description |
|
|
380
382
|
|:----------|:-----|:--------|:------------|
|
|
@@ -430,7 +432,7 @@ ActiveSupport surface: concerns registry, deprecators, MessageVerifier/MessageEn
|
|
|
430
432
|
|
|
431
433
|
### `rails_get_env_config`
|
|
432
434
|
|
|
433
|
-
Per-environment configuration from `config/environments/*.rb`: notable toggles (`force_ssl`, `eager_load`, caching, log level, queue adapter, mailer delivery) and every config key each environment sets.
|
|
435
|
+
Per-environment configuration from `config/environments/*.rb`: notable toggles (`force_ssl`, `eager_load`, caching, log level, queue adapter, mailer delivery) and every config key each environment sets. A key assigned in more than one branch reports every value with its condition; booted, the running environment reports the value the app resolved.
|
|
434
436
|
|
|
435
437
|
| Parameter | Type | Default | Description |
|
|
436
438
|
|:----------|:-----|:--------|:------------|
|
|
@@ -450,9 +452,13 @@ Model/service dependency graph in Mermaid or text format.
|
|
|
450
452
|
|
|
451
453
|
| Parameter | Type | Default | Description |
|
|
452
454
|
|:----------|:-----|:--------|:------------|
|
|
453
|
-
| `
|
|
454
|
-
| `
|
|
455
|
-
| `
|
|
455
|
+
| `model` | string | - | Center the graph on this model |
|
|
456
|
+
| `depth` | integer | `2` | Hops from the centre model (1-3) |
|
|
457
|
+
| `format` | enum | `mermaid` | `mermaid`, `text` |
|
|
458
|
+
| `show_cycles` | boolean | `false` | Detect and list circular dependencies |
|
|
459
|
+
| `show_sti` | boolean | `false` | Show Single Table Inheritance hierarchies |
|
|
460
|
+
|
|
461
|
+
Without `model` the graph is capped at 50 nodes, and says so when it cuts.
|
|
456
462
|
|
|
457
463
|
### `rails_migration_advisor`
|
|
458
464
|
|
data/exe/rails-ai-context
CHANGED
|
@@ -191,6 +191,16 @@ class RailsAiContextCLI < Thor
|
|
|
191
191
|
end
|
|
192
192
|
::RailsAiContext::LegacyCleanup.prompt_legacy_files(cleanup_tools, root: Dir.pwd)
|
|
193
193
|
|
|
194
|
+
# An explicit --format names a file, so it is written either way. With
|
|
195
|
+
# no format and an MCP-only install there is nothing to write, and the
|
|
196
|
+
# rake surface says the same thing in the same words.
|
|
197
|
+
if options[:format].nil? && !::RailsAiContext.configuration.context_files
|
|
198
|
+
$stderr.puts "MCP-only install (config.context_files = false): no context files written."
|
|
199
|
+
$stderr.puts "Run `rails-ai-context context --format claude` to write one anyway, " \
|
|
200
|
+
"or set config.context_files = true."
|
|
201
|
+
return
|
|
202
|
+
end
|
|
203
|
+
|
|
194
204
|
$stderr.puts "Introspecting Rails app..."
|
|
195
205
|
|
|
196
206
|
# An explicit --format overrides the recorded selection.
|
|
@@ -264,6 +274,8 @@ class RailsAiContextCLI < Thor
|
|
|
264
274
|
|
|
265
275
|
desc "init", "Set up rails-ai-context for standalone use (creates .rails-ai-context.yml and .mcp.json)"
|
|
266
276
|
option :no_boot, type: :boolean, default: false, desc: "Skip booting the app; serve static analysis only"
|
|
277
|
+
option :mcp_only, type: :boolean, default: false,
|
|
278
|
+
desc: "Write the MCP config and nothing else: no CLAUDE.md, AGENTS.md, rules files or .ai-context.json"
|
|
267
279
|
def init
|
|
268
280
|
unless entry_boot.app_present?(Dir.pwd, allow_source_only: true)
|
|
269
281
|
$stderr.puts "Error: No Rails app found in #{Dir.pwd}"
|
|
@@ -278,7 +290,9 @@ class RailsAiContextCLI < Thor
|
|
|
278
290
|
|
|
279
291
|
# --- Prompts (no Rails needed) ---
|
|
280
292
|
ai_tools = prompt_ai_tools
|
|
281
|
-
|
|
293
|
+
setup = prompt_setup
|
|
294
|
+
tool_mode = setup.tool_mode
|
|
295
|
+
context_files = setup.context_files
|
|
282
296
|
|
|
283
297
|
# --- Cleanup removed tools ---
|
|
284
298
|
cleanup_removed_tools(previous_tools, ai_tools) if previous_tools&.any?
|
|
@@ -287,13 +301,13 @@ class RailsAiContextCLI < Thor
|
|
|
287
301
|
::RailsAiContext::LegacyCleanup.prompt_legacy_files(ai_tools, root: Dir.pwd)
|
|
288
302
|
|
|
289
303
|
# --- Record the selection (YAML, plus the initializer line) ---
|
|
290
|
-
record_selection(ai_tools, tool_mode)
|
|
304
|
+
record_selection(ai_tools, tool_mode, context_files)
|
|
291
305
|
|
|
292
306
|
# --- Write per-tool MCP config files (MCP mode only) ---
|
|
293
307
|
write_mcp_configs(ai_tools, tool_mode)
|
|
294
308
|
|
|
295
309
|
# --- Add .ai-context.json to .gitignore ---
|
|
296
|
-
add_to_gitignore
|
|
310
|
+
add_to_gitignore(context_files)
|
|
297
311
|
|
|
298
312
|
# --- Boot Rails, load config, generate context ---
|
|
299
313
|
# The config files are already on disk by now, so failing here leaves the
|
|
@@ -301,12 +315,17 @@ class RailsAiContextCLI < Thor
|
|
|
301
315
|
# what you run on a repo you have just cloned.
|
|
302
316
|
boot_rails!(command: "init", allow_static: true)
|
|
303
317
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
318
|
+
if context_files
|
|
319
|
+
$stderr.puts ""
|
|
320
|
+
$stderr.puts "Generating AI context files..."
|
|
321
|
+
print_context_result(::RailsAiContext.generate_context(format: ai_tools))
|
|
322
|
+
else
|
|
323
|
+
$stderr.puts ""
|
|
324
|
+
$stderr.puts "MCP-only setup: no context files written."
|
|
325
|
+
end
|
|
307
326
|
|
|
308
327
|
# --- Instructions ---
|
|
309
|
-
show_standalone_instructions(ai_tools, tool_mode)
|
|
328
|
+
show_standalone_instructions(ai_tools, tool_mode, context_files)
|
|
310
329
|
end
|
|
311
330
|
|
|
312
331
|
desc "preset NAME", "Run a multi-tool preset (architecture, debugging, migration)"
|
|
@@ -367,8 +386,12 @@ class RailsAiContextCLI < Thor
|
|
|
367
386
|
::RailsAiContext::Install::Program.select_ai_tools(program_surface)
|
|
368
387
|
end
|
|
369
388
|
|
|
370
|
-
def
|
|
371
|
-
|
|
389
|
+
def prompt_setup
|
|
390
|
+
if options[:mcp_only]
|
|
391
|
+
return ::RailsAiContext::Install::Program::Setup.new(:mcp, false)
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
::RailsAiContext::Install::Program.select_setup(program_surface)
|
|
372
395
|
end
|
|
373
396
|
|
|
374
397
|
def read_previous_ai_tools
|
|
@@ -381,14 +404,17 @@ class RailsAiContextCLI < Thor
|
|
|
381
404
|
)
|
|
382
405
|
end
|
|
383
406
|
|
|
384
|
-
def add_to_gitignore
|
|
385
|
-
::RailsAiContext::Install::Program.mark_gitignore(program_surface, root: Dir.pwd
|
|
407
|
+
def add_to_gitignore(context_files = true)
|
|
408
|
+
::RailsAiContext::Install::Program.mark_gitignore(program_surface, root: Dir.pwd,
|
|
409
|
+
context_files: context_files)
|
|
386
410
|
end
|
|
387
411
|
|
|
388
|
-
def record_selection(ai_tools, tool_mode)
|
|
412
|
+
def record_selection(ai_tools, tool_mode, context_files = true)
|
|
389
413
|
result = ::RailsAiContext::Install::SelectionRecord.write(
|
|
390
|
-
ai_tools, root: Dir.pwd,
|
|
414
|
+
ai_tools, root: Dir.pwd,
|
|
415
|
+
extra_yaml: { "tool_mode" => tool_mode.to_s, "context_files" => context_files }
|
|
391
416
|
)
|
|
417
|
+
::RailsAiContext::Install::SelectionRecord.write_context_files(context_files, root: Dir.pwd)
|
|
392
418
|
|
|
393
419
|
::RailsAiContext::Install::SelectionRecord.messages(result).each do |level, text|
|
|
394
420
|
$stderr.puts(level == :warn ? "Warning: #{text}" : text)
|
|
@@ -402,7 +428,7 @@ class RailsAiContextCLI < Thor
|
|
|
402
428
|
)
|
|
403
429
|
end
|
|
404
430
|
|
|
405
|
-
def show_standalone_instructions(ai_tools, tool_mode)
|
|
431
|
+
def show_standalone_instructions(ai_tools, tool_mode, context_files = true)
|
|
406
432
|
$stderr.puts ""
|
|
407
433
|
$stderr.puts "=" * 50
|
|
408
434
|
$stderr.puts " rails-ai-context initialized!"
|
|
@@ -411,11 +437,15 @@ class RailsAiContextCLI < Thor
|
|
|
411
437
|
$stderr.puts "Your setup:"
|
|
412
438
|
::RailsAiContext::Install::AiTool.all.each do |tool|
|
|
413
439
|
next unless ai_tools.include?(tool.key)
|
|
414
|
-
$stderr.puts " #{tool.name.ljust(16)} -> #{tool.files}"
|
|
440
|
+
$stderr.puts " #{tool.name.ljust(16)} -> #{context_files ? tool.files : 'MCP config only'}"
|
|
441
|
+
end
|
|
442
|
+
unless context_files
|
|
443
|
+
$stderr.puts ""
|
|
444
|
+
$stderr.puts " Left alone on purpose: CLAUDE.md, AGENTS.md, the rules directories and .ai-context.json."
|
|
415
445
|
end
|
|
416
446
|
$stderr.puts ""
|
|
417
447
|
$stderr.puts "Commands:"
|
|
418
|
-
$stderr.puts " rails-ai-context context # Regenerate context files"
|
|
448
|
+
$stderr.puts " rails-ai-context context # Regenerate context files" if context_files
|
|
419
449
|
$stderr.puts " rails-ai-context tool NAME # Run any of the #{RailsAiContext::CountPhrase.call(builtin_tool_count, "tool")}"
|
|
420
450
|
if tool_mode == :mcp
|
|
421
451
|
$stderr.puts " rails-ai-context serve # Start MCP server"
|
|
@@ -38,6 +38,9 @@ module RailsAiContext
|
|
|
38
38
|
class_option :defaults, type: :boolean, default: false,
|
|
39
39
|
desc: "Skip all interactive prompts and use each prompt's documented default (for CI/non-interactive use)"
|
|
40
40
|
|
|
41
|
+
class_option :mcp_only, type: :boolean, default: false,
|
|
42
|
+
desc: "Write the MCP config and nothing else: no CLAUDE.md, AGENTS.md, rules files or .ai-context.json"
|
|
43
|
+
|
|
41
44
|
BARE_GUARD_PATTERN = RailsAiContext::Install::InitializerFile::BARE_GUARD
|
|
42
45
|
|
|
43
46
|
def select_ai_tools
|
|
@@ -54,8 +57,16 @@ module RailsAiContext
|
|
|
54
57
|
)
|
|
55
58
|
end
|
|
56
59
|
|
|
57
|
-
def
|
|
58
|
-
|
|
60
|
+
def select_setup
|
|
61
|
+
if options[:mcp_only]
|
|
62
|
+
@tool_mode = :mcp
|
|
63
|
+
@context_files = false
|
|
64
|
+
return
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
setup = RailsAiContext::Install::Program.select_setup(program_surface)
|
|
68
|
+
@tool_mode = setup.tool_mode
|
|
69
|
+
@context_files = setup.context_files
|
|
59
70
|
end
|
|
60
71
|
|
|
61
72
|
def create_mcp_config
|
|
@@ -79,6 +90,11 @@ module RailsAiContext
|
|
|
79
90
|
# :mcp - MCP primary + CLI fallback (default, requires `rails ai:serve`)
|
|
80
91
|
# :cli - CLI only (no MCP server needed, uses `rails 'ai:tool[NAME]'`)
|
|
81
92
|
# config.tool_mode = :mcp
|
|
93
|
+
|
|
94
|
+
# Whether this gem writes context files at all. false is MCP-only:
|
|
95
|
+
# the server and the CLI still answer, and CLAUDE.md, AGENTS.md,
|
|
96
|
+
# the rules directories and .ai-context.json are left alone.
|
|
97
|
+
# config.context_files = true
|
|
82
98
|
SECTION
|
|
83
99
|
"Introspection" => <<~SECTION,
|
|
84
100
|
# ── Introspection ─────────────────────────────────────────────────
|
|
@@ -261,11 +277,7 @@ module RailsAiContext
|
|
|
261
277
|
# Always write uncommented so re-install can detect previous selection
|
|
262
278
|
tools_line = RailsAiContext::Install::SelectionRecord.initializer_line(@selected_formats)
|
|
263
279
|
|
|
264
|
-
tool_mode_line =
|
|
265
|
-
" config.tool_mode = :cli # CLI only (no MCP server needed)"
|
|
266
|
-
else
|
|
267
|
-
" config.tool_mode = :mcp # MCP primary + CLI fallback"
|
|
268
|
-
end
|
|
280
|
+
tool_mode_line = build_tool_mode_line
|
|
269
281
|
|
|
270
282
|
content = "# frozen_string_literal: true\n\nRailsAiContext.configure do |config|\n"
|
|
271
283
|
|
|
@@ -280,6 +292,7 @@ module RailsAiContext
|
|
|
280
292
|
# :mcp - MCP primary + CLI fallback (default, requires `rails ai:serve`)
|
|
281
293
|
# :cli - CLI only (no MCP server needed, uses `rails 'ai:tool[NAME]'`)
|
|
282
294
|
#{tool_mode_line}
|
|
295
|
+
#{build_context_files_line}
|
|
283
296
|
|
|
284
297
|
SECTION
|
|
285
298
|
|
|
@@ -312,7 +325,11 @@ module RailsAiContext
|
|
|
312
325
|
existing, changed = update_config_line(existing, "config.tool_mode", build_tool_mode_line)
|
|
313
326
|
changes << "tool_mode" if changed
|
|
314
327
|
|
|
315
|
-
# 3.
|
|
328
|
+
# 3. Record whether this install writes context files at all
|
|
329
|
+
existing, changed = update_config_line(existing, "config.context_files", build_context_files_line)
|
|
330
|
+
changes << "context_files" if changed
|
|
331
|
+
|
|
332
|
+
# 4. Add any missing config sections
|
|
316
333
|
CONFIG_SECTIONS.each do |name, section_content|
|
|
317
334
|
marker = "── #{name}"
|
|
318
335
|
next if existing.include?(marker)
|
|
@@ -423,6 +440,20 @@ module RailsAiContext
|
|
|
423
440
|
end
|
|
424
441
|
end
|
|
425
442
|
|
|
443
|
+
# Written uncommented either way, so a re-run reads the same answer the
|
|
444
|
+
# last one recorded.
|
|
445
|
+
def build_context_files_line
|
|
446
|
+
if context_files?
|
|
447
|
+
" config.context_files = true # write CLAUDE.md, AGENTS.md and rules files"
|
|
448
|
+
else
|
|
449
|
+
" config.context_files = false # MCP only: no context files are written"
|
|
450
|
+
end
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
def context_files?
|
|
454
|
+
@context_files.nil? ? true : @context_files
|
|
455
|
+
end
|
|
456
|
+
|
|
426
457
|
def read_previous_ai_tools
|
|
427
458
|
RailsAiContext::Install::SelectionRecord.read(root: Rails.root)
|
|
428
459
|
end
|
|
@@ -435,7 +466,7 @@ module RailsAiContext
|
|
|
435
466
|
# comment behind. One writer per file, and it is not this call.
|
|
436
467
|
result = RailsAiContext::Install::SelectionRecord.write(
|
|
437
468
|
@selected_formats, root: Rails.root,
|
|
438
|
-
extra_yaml: { "tool_mode" => @tool_mode.to_s },
|
|
469
|
+
extra_yaml: { "tool_mode" => @tool_mode.to_s, "context_files" => context_files? },
|
|
439
470
|
initializer: false
|
|
440
471
|
)
|
|
441
472
|
|
|
@@ -445,7 +476,8 @@ module RailsAiContext
|
|
|
445
476
|
end
|
|
446
477
|
|
|
447
478
|
def add_to_gitignore
|
|
448
|
-
RailsAiContext::Install::Program.mark_gitignore(program_surface, root: Rails.root
|
|
479
|
+
RailsAiContext::Install::Program.mark_gitignore(program_surface, root: Rails.root,
|
|
480
|
+
context_files: context_files?)
|
|
449
481
|
end
|
|
450
482
|
|
|
451
483
|
def install_validation_hook
|
|
@@ -505,6 +537,12 @@ module RailsAiContext
|
|
|
505
537
|
end
|
|
506
538
|
|
|
507
539
|
def generate_context_files
|
|
540
|
+
unless context_files?
|
|
541
|
+
say ""
|
|
542
|
+
say "MCP-only install: no context files written.", :yellow
|
|
543
|
+
return
|
|
544
|
+
end
|
|
545
|
+
|
|
508
546
|
say ""
|
|
509
547
|
say "Generating AI context files...", :yellow
|
|
510
548
|
|
|
@@ -540,7 +578,12 @@ module RailsAiContext
|
|
|
540
578
|
say "Your setup:", :yellow
|
|
541
579
|
RailsAiContext::Install::AiTool.all.each do |tool|
|
|
542
580
|
next unless @selected_formats.include?(tool.key)
|
|
543
|
-
|
|
581
|
+
files = context_files? ? tool.files : "MCP config only"
|
|
582
|
+
say " ✅ #{tool.name.ljust(16)} -> #{files}"
|
|
583
|
+
end
|
|
584
|
+
unless context_files?
|
|
585
|
+
say ""
|
|
586
|
+
say " Left alone on purpose: CLAUDE.md, AGENTS.md, the rules directories and .ai-context.json.", :yellow
|
|
544
587
|
end
|
|
545
588
|
say ""
|
|
546
589
|
say "Commands:", :yellow
|