rails-ai-context 5.18.0 → 5.19.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +67 -0
  3. data/CONTEXT.md +17 -0
  4. data/CONTRIBUTING.md +2 -2
  5. data/README.md +19 -13
  6. data/SECURITY.md +1 -1
  7. data/app/controllers/rails_ai_context/mcp_controller.rb +52 -10
  8. data/docs/ARCHITECTURE.md +8 -8
  9. data/docs/CLI.md +2 -2
  10. data/docs/COMPATIBILITY.md +3 -2
  11. data/docs/CONFIGURATION.md +3 -3
  12. data/docs/CUSTOM_TOOLS.md +2 -2
  13. data/docs/FAQ.md +4 -4
  14. data/docs/GUIDE.md +19 -16
  15. data/docs/INTROSPECTORS.md +8 -7
  16. data/docs/SECURITY.md +2 -2
  17. data/docs/SETUP.md +2 -2
  18. data/docs/STANDALONE.md +2 -2
  19. data/docs/TOOLS.md +50 -2
  20. data/docs/TROUBLESHOOTING.md +1 -1
  21. data/docs/_config.yml +1 -1
  22. data/docs/index.md +3 -3
  23. data/exe/rails-ai-context +1 -1
  24. data/lib/rails_ai_context/configuration.rb +1 -1
  25. data/lib/rails_ai_context/introspector.rb +1 -0
  26. data/lib/rails_ai_context/introspectors/env_config_introspector.rb +127 -0
  27. data/lib/rails_ai_context/json_budget.rb +301 -0
  28. data/lib/rails_ai_context/resources.rb +2 -2
  29. data/lib/rails_ai_context/serializers/tool_guide_helper.rb +7 -1
  30. data/lib/rails_ai_context/server.rb +13 -0
  31. data/lib/rails_ai_context/tools/base_tool.rb +1 -1
  32. data/lib/rails_ai_context/tools/get_active_support.rb +107 -0
  33. data/lib/rails_ai_context/tools/get_autoload.rb +71 -0
  34. data/lib/rails_ai_context/tools/get_engines.rb +56 -0
  35. data/lib/rails_ai_context/tools/get_env_config.rb +91 -0
  36. data/lib/rails_ai_context/tools/get_i18n.rb +135 -0
  37. data/lib/rails_ai_context/tools/get_mailers.rb +65 -0
  38. data/lib/rails_ai_context/version.rb +1 -1
  39. data/lib/rails_ai_context/vfs.rb +4 -4
  40. data/server.json +4 -4
  41. metadata +12 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d4a8615479dc45f376da0873dbd18511feda7dafddad0e4c4c14039d26f8a4bf
4
- data.tar.gz: 9fa06c53d871f05d30c284964777ebd15b26d44e87284e9232591e288ab47d29
3
+ metadata.gz: 46645f9291dee2458c1a03529fcf888bfd4d11be1d742310f224ae439baed82f
4
+ data.tar.gz: 6c1a79f00117f9617970e5c0f1380337fdc17578fe350515d1a8d301a0fef3fd
5
5
  SHA512:
6
- metadata.gz: 38cc97cb5ec47c4ecd680ebb588169372d4d5a41c53dd0c59fde9260dc2bffad4f9830ffea5bc84cbef0079b167d522bccf77903104e5f6e5a03bd93aa85445d
7
- data.tar.gz: 9987140ad897944e8def9318c6eedad861228f345465937062dba5e6ea36a2c47246d5c0697acce041afe7966b866d40bd289e67eeb1d582a6b220cc5c6dc147
6
+ metadata.gz: 6ffd81a61373550ad0df085b3c01dc647de386bd79773b148711d8f040969f8a7f71fffb4e059539deef7285fc1fa21480761bd9f04cbaabd7aaaebab0e84e9d
7
+ data.tar.gz: c83fe3ae8dfa8bb663bba3b09dd6cd8b3b29939e2ae7ce6cf379cb9df0f739a2b21e86976a6741bee103240324f6e6118ba1fdf85b70d36927a702521e48a159
data/CHANGELOG.md CHANGED
@@ -5,6 +5,73 @@ 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.19.0] - 2026-08-09
9
+
10
+ ### Added - 6 new tools surfacing previously unserved introspection (45 tools total)
11
+
12
+ An audit found five introspectors whose data never reached the tool
13
+ surface (three only served context files; `:autoload` and
14
+ `:active_support` were unreachable entirely), plus one nervous-system
15
+ gap nothing introspected. All six are now first-class tools, registered
16
+ automatically in both MCP and CLI:
17
+
18
+ - **`rails_get_i18n`** - default/available locales, backend, locale files with
19
+ key counts, per-locale coverage vs the default locale, and fallbacks
20
+ (data: `:i18n` introspector, previously serializer-only).
21
+ - **`rails_get_mailers`** - every ActionMailer class with its delivery actions
22
+ and delivery method (data: `:jobs` introspector's mailer extraction,
23
+ previously serializer-only). Filter with `mailer:"UserMailer"`.
24
+ - **`rails_get_engines`** - engines mounted in `config/routes.rb` with
25
+ known-engine descriptions, plus loaded engine classes with route/model
26
+ counts (data: `:engines` introspector, previously resource-only).
27
+ - **`rails_get_autoload`** - Zeitwerk vs Classic mode, autoloaders with
28
+ collapsed/ignored dirs, autoload/eager-load paths, and custom inflections
29
+ (data: `:autoload` introspector, previously unreachable).
30
+ - **`rails_get_active_support`** - concerns registry, deprecators,
31
+ MessageVerifier/MessageEncryptor usage, tagged logging, subscribed
32
+ `on_load` hooks, and cache store (data: `:active_support` introspector,
33
+ previously unreachable).
34
+ - **`rails_get_env_config`** - per-environment configuration from
35
+ `config/environments/*.rb`: notable toggles (`force_ssl`, `eager_load`,
36
+ caching, log level, queue adapter, mailer delivery) and every config key
37
+ each environment sets. Backed by the new **EnvConfigIntrospector**
38
+ (40 introspectors total, wired into `PRESETS[:full]`; file-based, so it
39
+ also works in the static tier). Config keys and values are read with
40
+ `ConfigAssignmentListener`, so a multi-line value, an assignment nested in
41
+ a conditional, and the `Rails.application.config.x = y` form all read
42
+ correctly. The key list pages with `offset`/`limit`.
43
+
44
+ ### Fixed
45
+
46
+ - **Engine-mounted MCP returns JSON-RPC errors instead of Rails 500s.**
47
+ `McpController#handle` had no rescue around `handle_request` - a
48
+ transport-level exception escaped into a generic Rails HTML 500, breaking
49
+ the client's JSON-RPC loop. It now answers 500 with a JSON-RPC `-32603`
50
+ body, mirroring `RailsAiContext::Middleware`.
51
+ - **Standalone HTTP transport survives transport exceptions.** The Rack
52
+ lambda behind `rails-ai-context serve --transport http` let a
53
+ `handle_request` exception propagate to rackup (dropped connection). It
54
+ now returns the same JSON-RPC `-32603` body.
55
+ - **MCP resources honor `max_tool_response_chars` without breaking the JSON
56
+ contract.** Static resource, model, and VFS routes payloads were emitted
57
+ unbounded (a huge schema or routes table rode a single JSON-RPC frame).
58
+ They now fit the cap by dropping whole elements from the data rather than
59
+ slicing the serialized string, so a capped payload still parses as the
60
+ `application/json` it is labeled. What was dropped is reported under a
61
+ `_truncated` key, which also counts any over-long string value that had to
62
+ be cut. New `RailsAiContext::JsonBudget` owns the reduction.
63
+ - **A committed SSE stream is no longer overwritten by the error handler.**
64
+ `McpController#handle`'s rescue set a status, headers, and a JSON body on
65
+ responses that were already on the wire - closing a stream commits it, so
66
+ every streaming failure reached the rescue committed. Assigning a body
67
+ there swapped the stream out from under the thread draining it, turning a
68
+ truncated SSE response into a garbled one. Committed failures now re-raise
69
+ to `ActionController::Live`, which logs them with a backtrace and closes
70
+ the connection; uncommitted failures still get the JSON-RPC `-32603` body.
71
+ - **`server.json` tool count** said 38 while the gem served 39; now tracks
72
+ the real count (45). Broken `RAILS_NERVOUS_SYSTEM.md` link in
73
+ `docs/INTROSPECTORS.md` replaced with a plain reference.
74
+
8
75
  ## [5.18.0] - 2026-08-09
9
76
 
10
77
  ### Added
data/CONTEXT.md ADDED
@@ -0,0 +1,17 @@
1
+ # Context
2
+
3
+ Terms this project uses in a narrower sense than everyday English. One entry per term that has caused a naming collision or an ambiguous read.
4
+
5
+ ## Environment
6
+
7
+ Overloaded. Always qualify it; never use "environment" bare in a tool name, an introspector name, or a config key.
8
+
9
+ **Process environment** - the environment variables a running app sees, plus the places they are declared (`ENV[]` call sites, `.env.example`, Dockerfile, credentials keys). Served by `rails_get_env`, read by `EnvIntrospector`.
10
+
11
+ **Environment config** - what `config/environments/*.rb` declares per environment: the assigned `config.*` keys and the values of the notable toggles. Served by `rails_get_env_config`, read by `EnvConfigIntrospector`.
12
+
13
+ **Environment** (unqualified, as data) - a single named Rails environment: development, production, staging. This is the only sense in which the bare word is allowed, and only as a value, never as a name. The `:environments` payload key means "the list of these", which is why it kept its name when the introspector was renamed.
14
+
15
+ ## Static tier
16
+
17
+ The mode where the app did not boot, or `--no-boot` was passed. An introspector answers in this tier only if it defines `static_call`. Two shapes count as defining it: reading a different source (parsing `db/schema.rb` instead of querying the connection), and reading the same source a booted app would (a file-based introspector, where `static_call` is the same work under another name).
data/CONTRIBUTING.md CHANGED
@@ -19,8 +19,8 @@ The test suite uses [Combustion](https://github.com/pat/combustion) to boot a mi
19
19
  ```
20
20
  lib/rails_ai_context/
21
21
  ├── cli/ # CLI tool runner (tool_runner.rb) - executes MCP tools from rake/Thor
22
- ├── introspectors/ # 39 introspectors (schema, models, routes, etc.)
23
- ├── tools/ # 39 MCP tools with detail levels and pagination
22
+ ├── introspectors/ # 40 introspectors (schema, models, routes, etc.)
23
+ ├── tools/ # 45 MCP tools with detail levels and pagination
24
24
  ├── serializers/ # Per-assistant formatters + shared ToolGuideHelper
25
25
  ├── server.rb # MCP server setup (stdio + HTTP)
26
26
  ├── live_reload.rb # MCP live reload (file watcher + cache invalidation)
data/README.md CHANGED
@@ -68,7 +68,7 @@ rails-ai-context serve # start MCP server
68
68
 
69
69
  </div>
70
70
 
71
- Now your AI doesn't guess - it **asks your app directly.** 39 tools and 5 resource templates that query your schema, models, routes, controllers, views, and conventions on demand. Model introspection uses Prism AST parsing - every result carries a `[VERIFIED]` or `[INFERRED]` confidence tag so AI knows what's ground truth and what needs runtime checking.
71
+ Now your AI doesn't guess - it **asks your app directly.** 45 tools and 5 resource templates that query your schema, models, routes, controllers, views, and conventions on demand. Model introspection uses Prism AST parsing - every result carries a `[VERIFIED]` or `[INFERRED]` confidence tag so AI knows what's ground truth and what needs runtime checking.
72
72
 
73
73
  <br>
74
74
 
@@ -163,7 +163,7 @@ Native Rails controller transport. No separate process needed.
163
163
 
164
164
  ### CLI
165
165
 
166
- Same 39 tools, no server needed. Works in any terminal, any AI tool.
166
+ Same 45 tools, no server needed. Works in any terminal, any AI tool.
167
167
 
168
168
  ```bash
169
169
  rails 'ai:tool[search_code]' pattern="publishable?" match_type=trace
@@ -245,7 +245,7 @@ rails 'ai:tool[stimulus]' controller=chart
245
245
 
246
246
  <br>
247
247
 
248
- ## 39 Tools
248
+ ## 45 Tools
249
249
 
250
250
  Every tool is **read-only** and returns data verified against your actual app - not guesses, not training data.
251
251
 
@@ -331,6 +331,12 @@ Every tool is **read-only** and returns data verified against your actual app -
331
331
  | `get_service_pattern` | Interface, dependencies, side effects, callers |
332
332
  | `get_job_pattern` | Queue, retries, guard clauses, broadcasts, schedules |
333
333
  | `get_component_catalog` | ViewComponent/Phlex: props, slots, previews, sidecar assets |
334
+ | `get_i18n` | Locales, translation files with key counts, per-locale coverage, fallbacks |
335
+ | `get_mailers` | Mailer classes with delivery actions and delivery method |
336
+ | `get_engines` | Mounted engines (with known-engine descriptions) + loaded engine classes |
337
+ | `get_autoload` | Zeitwerk mode, autoload/eager-load paths, collapsed dirs, custom inflections |
338
+ | `get_active_support` | Concerns registry, deprecators, MessageVerifier usage, on_load hooks, cache store |
339
+ | `get_env_config` | Per-environment config: notable toggles + every config key each env sets |
334
340
 
335
341
  </details>
336
342
 
@@ -351,7 +357,7 @@ Every tool is **read-only** and returns data verified against your actual app -
351
357
 
352
358
  </details>
353
359
 
354
- > **[All 39 tools with parameters →](docs/TOOLS.md)** &nbsp;|&nbsp; **[Real-world recipes →](docs/RECIPES.md)**
360
+ > **[All 45 tools with parameters →](docs/TOOLS.md)** &nbsp;|&nbsp; **[Real-world recipes →](docs/RECIPES.md)**
355
361
 
356
362
  <br>
357
363
 
@@ -397,12 +403,12 @@ Enabled by default. Disable with `config.anti_hallucination_rules = false` if yo
397
403
 
398
404
  ```mermaid
399
405
  graph TD
400
- A["Your Rails App\nmodels + schema + routes + controllers + views + jobs"] -->|"39 introspectors"| B
406
+ A["Your Rails App\nmodels + schema + routes + controllers + views + jobs"] -->|"40 introspectors"| B
401
407
 
402
408
  B["rails-ai-context\nPrism AST parsing · Cached · Confidence-tagged\nVFS: rails-ai-context:// URIs introspected fresh"]
403
409
 
404
- B --> C["MCP Server\nstdio / HTTP\n39 tools · 5 templates"]
405
- B --> D["CLI Tools\nRake / Thor\nSame 39 tools"]
410
+ B --> C["MCP Server\nstdio / HTTP\n45 tools · 5 templates"]
411
+ B --> D["CLI Tools\nRake / Thor\nSame 45 tools"]
406
412
  B --> E["Static Files\nCLAUDE.md · .cursor/rules/ · .cursorrules\n.github/instructions/"]
407
413
 
408
414
  style A fill:#4a9eff,stroke:#2d7ad4,color:#fff
@@ -440,7 +446,7 @@ Both paths ask which AI tools you use (Claude Code, Cursor, GitHub Copilot, Open
440
446
  | In-Gemfile | Standalone | What it does |
441
447
  |:-----------|:-----------|:------------|
442
448
  | `rails ai:context` | `rails-ai-context context` | Generate context files |
443
- | `rails 'ai:tool[NAME]'` | `rails-ai-context tool NAME` | Run any of the 39 tools |
449
+ | `rails 'ai:tool[NAME]'` | `rails-ai-context tool NAME` | Run any of the 45 tools |
444
450
  | `rails ai:tool` | `rails-ai-context tool --list` | List all available tools |
445
451
  | `rails ai:serve` | `rails-ai-context serve` | Start MCP server (stdio) |
446
452
  | `rails ai:doctor` | `rails-ai-context doctor` | Diagnostics + AI readiness score |
@@ -491,13 +497,13 @@ empty listings.
491
497
  | | |
492
498
  |:------|:------------|
493
499
  | **[Quickstart](docs/QUICKSTART.md)** | 5-minute getting started |
494
- | **[Tools Reference](docs/TOOLS.md)** | All 39 tools with every parameter |
500
+ | **[Tools Reference](docs/TOOLS.md)** | All 45 tools with every parameter |
495
501
  | **[Recipes](docs/RECIPES.md)** | Real-world workflows and examples |
496
502
  | **[Custom Tools](docs/CUSTOM_TOOLS.md)** | Build and test your own MCP tools |
497
503
  | **[Configuration](docs/CONFIGURATION.md)** | 40+ config options with defaults |
498
504
  | **[AI Tool Setup](docs/SETUP.md)** | Claude, Cursor, Copilot, OpenCode, Codex |
499
505
  | **[Architecture](docs/ARCHITECTURE.md)** | System design and internals |
500
- | **[Introspectors](docs/INTROSPECTORS.md)** | All 39 introspectors and AST engine |
506
+ | **[Introspectors](docs/INTROSPECTORS.md)** | All 40 introspectors and AST engine |
501
507
  | **[Security](docs/SECURITY.md)** | 4-layer SQL safety and file blocking |
502
508
  | **[CLI Reference](docs/CLI.md)** | Commands and argument syntax |
503
509
  | **[Standalone](docs/STANDALONE.md)** | Use without Gemfile entry |
@@ -509,7 +515,7 @@ empty listings.
509
515
 
510
516
  ## Build your own tools
511
517
 
512
- Register custom MCP tools alongside the 39 built-in ones:
518
+ Register custom MCP tools alongside the 45 built-in ones:
513
519
 
514
520
  ```ruby
515
521
  # app/mcp_tools/rails_get_business_metrics.rb
@@ -547,7 +553,7 @@ if defined?(RailsAiContext)
547
553
  RailsAiContext.configure do |config|
548
554
  config.ai_tools = %i[claude cursor] # Which AI tools to generate for
549
555
  config.tool_mode = :mcp # :mcp (default) or :cli
550
- config.preset = :full # :full (39 introspectors) or :standard (17)
556
+ config.preset = :full # :full (40 introspectors) or :standard (17)
551
557
  end
552
558
  end
553
559
  ```
@@ -583,7 +589,7 @@ end
583
589
  ## About
584
590
 
585
591
  Built by a Rails developer with 10+ years of production experience.<br>
586
- 2154 tests + 100-example e2e harness. 39 tools. 5 resource templates. 39 introspectors. Standalone or in-Gemfile.<br>
592
+ 2727 tests + 158-example e2e harness. 45 tools. 5 resource templates. 40 introspectors. Standalone or in-Gemfile.<br>
587
593
  MIT licensed. [Contributions welcome.](CONTRIBUTING.md)
588
594
 
589
595
  <br>
data/SECURITY.md CHANGED
@@ -39,7 +39,7 @@ If you discover a security vulnerability in rails-ai-context, please report it r
39
39
 
40
40
  ## Security Design
41
41
 
42
- - All 38 MCP tools are **read-only** and never modify your application or database.
42
+ - All 45 MCP tools are **read-only** and never modify your application or database.
43
43
  - **Sensitive file blocking** - configurable `sensitive_patterns` blocks access to `.env`, `*.key`, `*.pem`, `credentials.yml.enc` across all search and read tools. Patterns are checked in `rails_search_code`, `rails_get_edit_context`, and all new tools.
44
44
  - **Path traversal protection** - all file-reading tools validate paths with `File.realpath()` against `Rails.root` to prevent directory escape.
45
45
  - **Command injection prevention** - code search uses `Open3.capture2` with array arguments (never shell strings). The `--` flag separator prevents pattern injection.
@@ -29,15 +29,7 @@ module RailsAiContext
29
29
  def handle
30
30
  status_code, rack_headers, body = self.class.mcp_transport.handle_request(request)
31
31
  self.status = status_code
32
- rack_headers.each do |k, v|
33
- # mcp >= 1.0 returns Rack 3-style lowercase header keys. Rails 7.0's
34
- # response header hash is case-sensitive (Rack 2), so a lowercase
35
- # "content-type" never registers and Rails falls back to text/html on
36
- # an otherwise valid JSON body. Write it with the canonical case.
37
- key = k.casecmp("content-type").zero? ? "Content-Type" : k
38
- response.headers[key] = v
39
- end
40
-
32
+ apply_transport_headers(rack_headers)
41
33
  if body.respond_to?(:each)
42
34
  # Plain enumerable body (initialize, errors, JSON mode): join to a
43
35
  # string so Content-Length/ETag semantics stay conventional.
@@ -75,16 +67,66 @@ module RailsAiContext
75
67
  else
76
68
  self.response_body = body
77
69
  end
70
+ rescue => e
71
+ # Once the response is committed the status and headers are already on
72
+ # the wire, so a JSON-RPC frame written here cannot reach the client.
73
+ # Worse, assigning a body swaps the stream out from under the thread
74
+ # still draining the old one, turning a truncated SSE stream into a
75
+ # garbled one. The streaming branch's ensure always closes the stream,
76
+ # and closing commits, so every streaming failure lands here committed.
77
+ # Hand those to Live, which logs them with a backtrace and tears the
78
+ # connection down.
79
+ raise if response.committed?
80
+
81
+ # Mirror Middleware#json_rpc_error_response: a transport failure must
82
+ # still answer in JSON-RPC shape. Without this the exception escapes
83
+ # into a generic Rails 500 (HTML), breaking the client's JSON-RPC loop.
84
+ RailsAiContext.log_warn "[rails-ai-context] MCP request failed: #{e.class}: #{e.message}"
85
+ self.status = 500
86
+ response.headers["Content-Type"] = "application/json"
87
+ self.response_body = {
88
+ jsonrpc: "2.0",
89
+ error: { code: -32603, message: "Internal error: #{e.message}" },
90
+ id: nil
91
+ }.to_json
78
92
  end
79
93
 
80
94
  private
81
95
 
96
+ # Rack 3 transports name their headers in lowercase, and the MCP SDK
97
+ # switched to that in 1.0. Rails 7.0 keeps response headers in a
98
+ # case-sensitive Hash, so a lowercase "content-type" is invisible to the
99
+ # canonical lookup Rails makes when it commits, and it labels the response
100
+ # with its own text/html default - a correct JSON-RPC body under a type no
101
+ # client will parse. Rails 7.1 moved to case-insensitive Rack::Headers and
102
+ # does not have the problem. Only the type needs the canonical spelling,
103
+ # because Rails is the only reader that looks a header up by name; the
104
+ # value is passed through so nothing gains a charset it did not have.
105
+ def apply_transport_headers(rack_headers)
106
+ rack_headers.each do |name, value|
107
+ key = name.to_s.casecmp?("content-type") ? "Content-Type" : name
108
+ response.headers[key] = value
109
+ end
110
+ end
111
+
82
112
  def wait_for_stream_close
83
- sleep 0.5 until response.stream.closed?
113
+ sleep 0.5 until stream_finished?
84
114
  rescue IOError
85
115
  nil
86
116
  end
87
117
 
118
+ # A client hangup aborts the buffer instead of closing it, so `closed?`
119
+ # alone leaves this thread parked until the transport's next keepalive
120
+ # write notices the hangup - up to the keepalive interval per dropped
121
+ # client. Live's buffer reports the hangup through `connected?`; the plain
122
+ # buffer used off the streaming path does not define it, so ask first.
123
+ def stream_finished?
124
+ stream = response.stream
125
+ return true if stream.closed?
126
+
127
+ stream.respond_to?(:connected?) && !stream.connected?
128
+ end
129
+
88
130
  class << self
89
131
  # Class-level memoization - transport persists across requests.
90
132
  # Thread-safe: MCP::Server and transport are stateless for reads.
data/docs/ARCHITECTURE.md CHANGED
@@ -18,19 +18,19 @@ graph TD
18
18
  A["models + schema + routes + controllers + views + jobs + config"]
19
19
  end
20
20
 
21
- A -->|"39 introspectors"| gem
21
+ A -->|"40 introspectors"| gem
22
22
 
23
23
  subgraph gem["rails-ai-context"]
24
24
  direction TB
25
25
 
26
26
  subgraph engine["Introspection Engine"]
27
27
  direction LR
28
- I["Introspectors\n39 modules\nPresets\nCached"]
28
+ I["Introspectors\n40 modules\nPresets\nCached"]
29
29
  AST["AST Engine\nPrism\n24 listeners\nConfidence tags"]
30
30
  H["Hydration Layer\nSchema hints\ninjected into\ntool responses"]
31
31
  end
32
32
 
33
- engine --> R["Tool Registry\n39 tools auto-discovered via inherited\n+ custom_tools - skip_tools = active tools"]
33
+ engine --> R["Tool Registry\n45 tools auto-discovered via inherited\n+ custom_tools - skip_tools = active tools"]
34
34
  end
35
35
 
36
36
  R --> MCP
@@ -40,7 +40,7 @@ graph TD
40
40
  subgraph outputs["Output"]
41
41
  direction LR
42
42
  MCP["MCP Server\nstdio / HTTP\nResources\nVFS URIs"]
43
- CLI["CLI Runner\nRake / Thor\nSame 39 tools\nNo server needed"]
43
+ CLI["CLI Runner\nRake / Thor\nSame 45 tools\nNo server needed"]
44
44
  S["Serializers\n14 modules\nStatic files\nPer-AI-tool"]
45
45
  end
46
46
 
@@ -73,7 +73,7 @@ sequenceDiagram
73
73
  alt cache hit (TTL + fingerprint valid)
74
74
  Cache-->>TR: cached context
75
75
  else cache miss
76
- Cache->>App: introspect (39 modules)
76
+ Cache->>App: introspect (40 modules)
77
77
  App-->>Cache: structured data
78
78
  Cache-->>TR: fresh context
79
79
  end
@@ -101,7 +101,7 @@ flowchart LR
101
101
 
102
102
  ### Introspectors (`lib/rails_ai_context/introspectors/`)
103
103
 
104
- 39 modules that extract structured data from your Rails app. Each introspector:
104
+ 40 modules that extract structured data from your Rails app. Each introspector:
105
105
 
106
106
  - Returns a Hash (never raises - wraps errors in `{ error: msg }`)
107
107
  - Is registered in `INTROSPECTOR_MAP` with a symbol key
@@ -192,7 +192,7 @@ Thor-based CLI that works standalone (no Gemfile entry):
192
192
 
193
193
  - `ToolRunner` - Parses CLI args, resolves tool names, executes tools, formats output
194
194
  - Supports `--json` mode for machine-readable output
195
- - Same 39 tools available as MCP and CLI
195
+ - Same 45 tools available as MCP and CLI
196
196
 
197
197
  ### Caching
198
198
 
@@ -215,7 +215,7 @@ SHA256-based change detection:
215
215
  ## Key design decisions
216
216
 
217
217
  1. **Official MCP SDK** - Not a custom protocol. Uses `mcp` gem's `MCP::Tool`, `MCP::Server`, transports.
218
- 2. **Read-only tools** - All 39 tools annotated as non-destructive. Defense-in-depth for query tool.
218
+ 2. **Read-only tools** - All 45 tools annotated as non-destructive. Defense-in-depth for query tool.
219
219
  3. **Graceful degradation** - Works without database (parses schema.rb as text), without Brakeman, without ripgrep, without listen gem.
220
220
  4. **Zeitwerk autoloading** - Files loaded on-demand. No `require_relative` in the gem.
221
221
  5. **Diff-aware generation** - Context file regeneration skips unchanged files using fingerprinting.
data/docs/CLI.md CHANGED
@@ -17,7 +17,7 @@
17
17
  | In-Gemfile (Rake) | `rails ai:` | `rails 'ai:tool[schema]' table=users` |
18
18
  | Standalone (Thor) | `rails-ai-context` | `rails-ai-context tool schema --table users` |
19
19
 
20
- Both provide the same 39 tools and functionality.
20
+ Both provide the same 45 tools and functionality.
21
21
 
22
22
  ---
23
23
 
@@ -40,7 +40,7 @@ rails-ai-context serve --transport http --port 6029 # HTTP transport
40
40
 
41
41
  ### `tool`
42
42
 
43
- Run any of the 39 MCP tools from the terminal.
43
+ Run any of the 45 MCP tools from the terminal.
44
44
 
45
45
  ```bash
46
46
  # Rake syntax
@@ -80,6 +80,7 @@ that define a `static_call` path can answer without a booted app:
80
80
  | `routes` | `config/routes.rb` parsed with a dedicated Prism listener |
81
81
  | `models` | `app/models/**/*.rb` (plus packs/engines/extra paths) parsed, not constantized |
82
82
  | `controllers` | `app/controllers/**/*.rb` (plus packs/engines/extra paths) parsed, not constantized |
83
+ | `env_config` | `config/environments/*.rb` read from disk - file-based, so the static tier serves the same data as a booted app |
83
84
 
84
85
  The other 34 introspectors (views, jobs, gems, turbo, i18n, active_storage,
85
86
  auth, api, and the rest) have no static path and report `{ unavailable: reason
@@ -167,11 +168,11 @@ Proof sources:
167
168
  prints to stdout, writes via the `STDOUT` constant, hangs past the
168
169
  timeout) plus `spec/e2e/static_tier_spec.rb` ("broken-boot app over the
169
170
  CLI", "broken-boot app over MCP stdio", "syntax error in one model file").
170
- 8. No introspector outside the five in the operating-tiers table defines
171
+ 8. No introspector outside the six in the operating-tiers table defines
171
172
  `static_call` (`lib/rails_ai_context/introspectors/view_introspector.rb`
172
173
  has none); `Introspector#run_introspector` reports `{ unavailable: reason
173
174
  }` for every such section regardless of shape.
174
- 9. `spec/e2e/empty_app_spec.rb` - all 39 built-in tools swept against an app
175
+ 9. `spec/e2e/empty_app_spec.rb` - all 45 built-in tools swept against an app
175
176
  with no scaffold, no models, no controllers beyond
176
177
  `ApplicationController`, no routes beyond root.
177
178
  10. `spec/e2e/massive_app_spec.rb` - `schema`, `model_details`, and `routes`
@@ -56,7 +56,7 @@ preset: full
56
56
 
57
57
  | Option | Type | Default | Description |
58
58
  |:-------|:-----|:--------|:------------|
59
- | `preset` | Symbol | `:full` | `:full` (39 introspectors) or `:standard` (17 introspectors) |
59
+ | `preset` | Symbol | `:full` | `:full` (40 introspectors) or `:standard` (17 introspectors) |
60
60
  | `context_mode` | Symbol | `:compact` | `:compact` (context files capped at ~150 lines) or `:full` (no line cap) |
61
61
  | `introspectors` | Array of symbols | (from preset) | Override the introspector list directly |
62
62
  | `generate_root_files` | Boolean | `true` | Set `false` to generate split rules only, no root CLAUDE.md/AGENTS.md |
@@ -69,7 +69,7 @@ preset: full
69
69
  |:-------|:-----|:--------|:-----------|:------------|
70
70
  | `server_name` | String | `"rails-ai-context"` | - | MCP server name |
71
71
  | `cache_ttl` | Integer | `60` | Must be positive | Cache time-to-live in seconds |
72
- | `max_tool_response_chars` | Integer | `200_000` | Must be positive | Safety cap for tool response length |
72
+ | `max_tool_response_chars` | Integer | `200_000` | Must be positive | Safety cap for tool responses and MCP resource payloads. An over-cap resource keeps its JSON shape: whole elements are dropped and reported under a `_truncated` key |
73
73
  | `live_reload` | Symbol/Boolean | `:auto` | - | `:auto` (uses `listen` gem if available), `true`, or `false` |
74
74
  | `live_reload_debounce` | Float | `1.5` | - | Seconds to wait before processing file changes |
75
75
  | `auto_mount` | Boolean | `false` | - | Auto-mount Rack middleware for HTTP transport |
@@ -166,7 +166,7 @@ preset: full
166
166
 
167
167
  ## Presets
168
168
 
169
- ### `:full` (default) - 39 introspectors
169
+ ### `:full` (default) - 40 introspectors
170
170
 
171
171
  All available introspectors. Maximum context.
172
172
 
data/docs/CUSTOM_TOOLS.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Custom Tools
4
4
 
5
- **Build your own MCP tools that run alongside the 39 built-in ones.**
5
+ **Build your own MCP tools that run alongside the 45 built-in ones.**
6
6
 
7
7
  [Tools Reference](TOOLS.md) · [Configuration](CONFIGURATION.md) · [Architecture](ARCHITECTURE.md) · [FAQ](FAQ.md)
8
8
 
@@ -11,7 +11,7 @@
11
11
  ---
12
12
 
13
13
  > [!NOTE]
14
- > Custom tools have full access to your Rails environment - ActiveRecord, services, mailers, everything. They appear alongside the 39 built-in tools in both MCP and CLI.
14
+ > Custom tools have full access to your Rails environment - ActiveRecord, services, mailers, everything. They appear alongside the 45 built-in tools in both MCP and CLI.
15
15
 
16
16
  ## Creating a custom tool
17
17
 
data/docs/FAQ.md CHANGED
@@ -25,7 +25,7 @@ Claude Code, Cursor, GitHub Copilot, OpenCode, and Codex CLI. Each gets tailored
25
25
  No. The gem works three ways:
26
26
  1. **MCP server** - AI calls tools via the protocol (best experience)
27
27
  2. **Static files** - Generated context files (CLAUDE.md, .cursor/rules/, etc.)
28
- 3. **CLI** - Same 39 tools from the terminal, no server needed
28
+ 3. **CLI** - Same 45 tools from the terminal, no server needed
29
29
 
30
30
  ### Is this safe for production?
31
31
 
@@ -47,7 +47,7 @@ Yes. The gem gracefully degrades - it parses `db/schema.rb` as text when no data
47
47
 
48
48
  ### Can I switch between Gemfile and standalone?
49
49
 
50
- Yes, freely. Both generate identical context files and provide the same 39 tools. Just re-run the install/init to update MCP config files.
50
+ Yes, freely. Both generate identical context files and provide the same 45 tools. Just re-run the install/init to update MCP config files.
51
51
 
52
52
  ### Do I need to commit the generated files?
53
53
 
@@ -69,7 +69,7 @@ Start with `rails_onboard` for an app overview, `rails_analyze_feature` for feat
69
69
 
70
70
  ### Can I add my own tools?
71
71
 
72
- Yes. See [Custom Tools](CUSTOM_TOOLS.md). Create an `MCP::Tool` subclass, register it via `config.custom_tools`, and it appears alongside the 39 built-in tools.
72
+ Yes. See [Custom Tools](CUSTOM_TOOLS.md). Create an `MCP::Tool` subclass, register it via `config.custom_tools`, and it appears alongside the 45 built-in tools.
73
73
 
74
74
  ### Can I remove built-in tools?
75
75
 
@@ -99,7 +99,7 @@ PostgreSQL, MySQL, and SQLite. Each gets database-specific safety mechanisms (re
99
99
 
100
100
  ### What's the difference between `:full` and `:standard` preset?
101
101
 
102
- - **`:full`** (default) - 39 introspectors. Full context for every aspect of your app.
102
+ - **`:full`** (default) - 40 introspectors. Full context for every aspect of your app.
103
103
  - **`:standard`** - 17 introspectors. Faster, covers the essentials (schema, models, routes, controllers, tests, etc.).
104
104
 
105
105
  ### What's `:compact` vs `:full` context mode?
data/docs/GUIDE.md CHANGED
@@ -18,13 +18,13 @@
18
18
  | Guide | Description |
19
19
  |:------|:------------|
20
20
  | [Quickstart](QUICKSTART.md) | Get running in 5 minutes |
21
- | [Tools Reference](TOOLS.md) | All 39 MCP tools with parameters |
21
+ | [Tools Reference](TOOLS.md) | All 45 MCP tools with parameters |
22
22
  | [Recipes](RECIPES.md) | Real-world workflows and examples |
23
23
  | [Custom Tools](CUSTOM_TOOLS.md) | Build your own MCP tools |
24
24
  | [Configuration](CONFIGURATION.md) | Every config option |
25
25
  | [AI Tool Setup](SETUP.md) | Per-editor setup |
26
26
  | [Architecture](ARCHITECTURE.md) | System design and internals |
27
- | [Introspectors](INTROSPECTORS.md) | All 39 introspectors |
27
+ | [Introspectors](INTROSPECTORS.md) | All 40 introspectors |
28
28
  | [Security](SECURITY.md) | Security model and SQL safety |
29
29
  | [CLI Reference](CLI.md) | All commands and argument syntax |
30
30
  | [Standalone Mode](STANDALONE.md) | Use without Gemfile |
@@ -40,7 +40,7 @@
40
40
  - [Generated Files](#generated-files)
41
41
  - [All Commands](#all-commands)
42
42
  - [CLI Tools](#cli-tools)
43
- - [MCP Tools - Full Reference](#mcp-tools--full-reference)
43
+ - [MCP Tools - Common Reference](#mcp-tools--common-reference)
44
44
  - [MCP Resources](#mcp-resources)
45
45
  - [MCP Server Setup](#mcp-server-setup)
46
46
  - [Configuration - All Options](#configuration--all-options)
@@ -283,7 +283,7 @@ rails ai:context:claude # Use this instead (no quoting needed)
283
283
 
284
284
  ## CLI Tools
285
285
 
286
- All 39 MCP tools can be run directly from the terminal - no MCP server or AI client needed.
286
+ All 45 MCP tools can be run directly from the terminal - no MCP server or AI client needed.
287
287
 
288
288
  ### Rake
289
289
 
@@ -347,9 +347,11 @@ The `tool_mode` is selected during `rails generate rails_ai_context:install`.
347
347
 
348
348
  ---
349
349
 
350
- ## MCP Tools - Full Reference
350
+ ## MCP Tools - Common Reference
351
351
 
352
- All 39 tools are **read-only** and **idempotent** - they never modify your application or database.
352
+ The 24 tools below are the ones worth reading about before you start. [Tools Reference](TOOLS.md) carries all 45 with their parameters.
353
+
354
+ Every tool is **read-only** and **idempotent** - they never modify your application or database.
353
355
 
354
356
  ### rails_get_schema
355
357
 
@@ -1169,7 +1171,7 @@ if defined?(RailsAiContext)
1169
1171
  end
1170
1172
  ```
1171
1173
 
1172
- Both transports are **read-only** - they expose the same 39 tools and never modify your app.
1174
+ Both transports are **read-only** - they expose the same 45 tools and never modify your app.
1173
1175
 
1174
1176
  ### Controller Transport (Alternative)
1175
1177
 
@@ -1192,7 +1194,7 @@ if defined?(RailsAiContext)
1192
1194
  RailsAiContext.configure do |config|
1193
1195
  # --- Introspectors ---
1194
1196
 
1195
- # Presets: :full (39 introspectors, default) or :standard (17)
1197
+ # Presets: :full (40 introspectors, default) or :standard (17)
1196
1198
  config.preset = :full
1197
1199
 
1198
1200
  # Cherry-pick on top of a preset
@@ -1311,10 +1313,10 @@ end
1311
1313
  | Option | Type | Default | Description |
1312
1314
  |--------|------|---------|-------------|
1313
1315
  | `preset` | Symbol | `:full` | Introspector preset (`:full` or `:standard`) |
1314
- | `introspectors` | Array | 39 (full preset) | Which introspectors to run |
1316
+ | `introspectors` | Array | 40 (full preset) | Which introspectors to run |
1315
1317
  | `context_mode` | Symbol | `:compact` | `:compact` or `:full` |
1316
1318
  | `claude_max_lines` | Integer | `150` | Max lines for CLAUDE.md in compact mode |
1317
- | `max_tool_response_chars` | Integer | `200_000` | Safety cap for MCP tool responses |
1319
+ | `max_tool_response_chars` | Integer | `200_000` | Safety cap for MCP tool responses and resource payloads |
1318
1320
  | `cache_ttl` | Integer | `60` | Cache TTL in seconds for introspection results |
1319
1321
  | `custom_tools` | Array | `[]` | Additional MCP tool classes to register alongside built-in tools |
1320
1322
  | `skip_tools` | Array | `[]` | Built-in tool names to exclude (e.g. `%w[rails_security_scan]`) |
@@ -1398,7 +1400,7 @@ Core Rails structure only. Use `config.preset = :standard` for a lighter footpri
1398
1400
  | `performance` | N+1 query risks, missing counter_cache, missing FK indexes, Model.all anti-patterns, eager load candidates. |
1399
1401
  | `i18n` | Default locale, available locales, locale files with key counts, backend class, parse errors. |
1400
1402
 
1401
- ### Full preset (39 introspectors) - default
1403
+ ### Full preset (40 introspectors) - default
1402
1404
 
1403
1405
  Includes all standard introspectors plus:
1404
1406
 
@@ -1415,6 +1417,7 @@ Includes all standard introspectors plus:
1415
1417
  | `seeds` | db/seeds.rb analysis (Faker usage, environment conditionals), seed files in db/seeds/, models seeded. |
1416
1418
  | `middleware` | Custom Rack middleware in app/middleware/ with detected patterns (auth, rate limiting, tenant isolation, logging). Full middleware stack. |
1417
1419
  | `engines` | Mounted Rails engines from routes.rb with paths and descriptions for 23+ known engines (Sidekiq::Web, Flipper::UI, PgHero, ActiveAdmin, etc.). |
1420
+ | `env_config` | Per-environment config files (`config/environments/*.rb`): notable toggles (`force_ssl`, `eager_load`, caching, log level, queue adapter, mailer delivery) with URI credentials redacted, assigned config keys. |
1418
1421
  | `multi_database` | Multiple databases, replicas, sharding config, model-specific `connects_to` declarations. database.yml parsing fallback. |
1419
1422
  | `frontend_frameworks` | Frontend JS framework detection (React/Vue/Svelte/Angular), mounting strategy (Inertia/react-rails), TypeScript config, state management, package manager. |
1420
1423
  | `database_stats` | PostgreSQL approximate row counts via `pg_stat_user_tables`. Gracefully skips on non-PostgreSQL adapters. |
@@ -1534,11 +1537,11 @@ OpenCode uses **per-directory lazy-loading**: when the agent reads a file, it wa
1534
1537
 
1535
1538
  | Setup | Coverage | Notes |
1536
1539
  |-------|----------|-------|
1537
- | Rails full-stack (ERB + Hotwire) | 39/39 | All introspectors relevant |
1538
- | Rails + Inertia.js (React/Vue) | ~33/39 | Views/Turbo partially useful, backend fully covered |
1539
- | Rails API + React/Next.js SPA | ~31/39 | Schema, models, routes, API, auth, jobs - all covered |
1540
- | Rails API + mobile app | ~31/39 | Same as SPA - backend introspection is identical |
1541
- | Rails engine (mountable gem) | ~26/39 | Core introspectors (schema, models, routes, gems) work |
1540
+ | Rails full-stack (ERB + Hotwire) | 40/40 | All introspectors relevant |
1541
+ | Rails + Inertia.js (React/Vue) | ~34/40 | Views/Turbo partially useful, backend fully covered |
1542
+ | Rails API + React/Next.js SPA | ~32/40 | Schema, models, routes, API, auth, jobs - all covered |
1543
+ | Rails API + mobile app | ~32/40 | Same as SPA - backend introspection is identical |
1544
+ | Rails engine (mountable gem) | ~27/40 | Core introspectors (schema, models, routes, gems) work |
1542
1545
 
1543
1546
  Frontend introspectors (views, Turbo, Stimulus, assets) degrade gracefully - they report nothing when those features aren't present.
1544
1547