rails-ai-context 5.6.0 → 5.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b89e4a41169c9ddd8a649833f96c6792b6c75ec24101ac220d9c3f431c6126e2
4
- data.tar.gz: b2e4c8d0fa16d62b8fd2b67e0dddcd6f9754eb085a1b0cbae59d7b6e0d6898d0
3
+ metadata.gz: 313744756e1399207abeb841866440c3de88da5863f92163fd7d344b60c479c5
4
+ data.tar.gz: 4de97686b1d62c8444a76ed78fc709aade9e0e004adae1a7a655c7d0eae8ce23
5
5
  SHA512:
6
- metadata.gz: 670a61dd4524c7cae544b3277947191fe4e8ab6f0de54eca4e14eb27c8255e1b1b36c6ad10c99e76e9eac46bc4954676fae9f4680d7108dbc3134422ab9e5d13
7
- data.tar.gz: f6ca688b6ae4e2c1c41cde1fdba672596cc25815f72d32cd85f039e64596c8c61f30cd24ff2d0996cd7acacb8217abace18eee32ae5ea1d0569d2376d217fad8
6
+ metadata.gz: 0df4cd4cd7c0e99f8c1e662baae65a960819ed8bea551e8bb536bf06cf2b1ba6c42fee462668e990c2bf48572d5b65b66b6f38c730f643c2cd6e19b751ab7a9c
7
+ data.tar.gz: 88df4ee906be73bb71212bf47acc88e09efe0ac82a87abef786a3f9a829c5aed57bdb63d19c58d6f5a4361d8ebf5955b3ce29a09235a84aa01e9c204e7ee9471
data/CHANGELOG.md CHANGED
@@ -5,6 +5,33 @@ 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.7.0] — 2026-04-09
9
+
10
+ ### Quickstart — Two commands. Problem gone.
11
+
12
+ ```bash
13
+ gem "rails-ai-context", group: :development
14
+ rails generate rails_ai_context:install
15
+ ```
16
+
17
+ ### Fixed — Bug Fixes from Codebase Audit
18
+
19
+ 6 bug fixes discovered via automated codebase audit (bug-finder, code-reviewer, doc-consistency-checker agents).
20
+
21
+ - **AnalyzeFeature service/mailer method extraction** (HIGH) — `\A` (start-of-string) anchor in `scan` regex replaced with `^` (start-of-line). Services and mailers now correctly list all methods instead of always returning empty arrays.
22
+
23
+ - **SearchCode exact_match + definition double-escaping** (HIGH) — Word boundaries (`\b`) were applied before `Regexp.escape`, producing unmatchable regex when combining `exact_match: true` with `match_type: "definition"` or `"class"`. Boundaries now applied per-match_type after escaping.
24
+
25
+ - **MigrationAdvisor empty string column bypass** (MEDIUM) — Empty string `""` column names bypassed the "column required" validation (Ruby truthiness). Now normalized via `.presence` so empty strings become `nil` and are caught.
26
+
27
+ - **GetConcern class method block tracking** — Regex no longer matches `def self.method` as a `class_methods do` block entry, preventing instance methods after `def self.` from being incorrectly skipped.
28
+
29
+ - **AstCache eviction comment accuracy** — Comment corrected from "evicts oldest entries" to "arbitrary selection" since `Concurrent::Map` has no ordering guarantee.
30
+
31
+ - **SECURITY.md supported versions** — Added missing 5.6.x row to supported versions table.
32
+
33
+ - **CONFIGURATION.md preset count** — Fixed stale `:standard` preset count from 13 to 17.
34
+
8
35
  ## [5.6.0] — 2026-04-09
9
36
 
10
37
  ### Added — Auto-Registration, TestHelper & Bug Fixes
data/README.md CHANGED
@@ -10,7 +10,7 @@
10
10
  <a href="https://github.com/features/copilot"><img src="https://img.shields.io/badge/GitHub_Copilot-000000?style=for-the-badge&logo=githubcopilot&logoColor=white" alt="GitHub Copilot"></a>
11
11
  <a href="https://opencode.ai"><img src="https://img.shields.io/badge/OpenCode-4285F4?style=for-the-badge&logoColor=white" alt="OpenCode"></a>
12
12
  <a href="https://codex.openai.com"><img src="https://img.shields.io/badge/Codex_CLI-412991?style=for-the-badge&logo=openai&logoColor=white" alt="Codex CLI"></a>
13
- <a href="#-cli--works-everywhere"><img src="https://img.shields.io/badge/Any_Terminal-4EAA25?style=for-the-badge&logo=gnubash&logoColor=white" alt="Any Terminal"></a>
13
+ <a href="docs/CLI.md"><img src="https://img.shields.io/badge/Any_Terminal-4EAA25?style=for-the-badge&logo=gnubash&logoColor=white" alt="Any Terminal"></a>
14
14
 
15
15
 
16
16
 
@@ -187,20 +187,18 @@ rails 'ai:tool[analyze_feature]' feature=billing
187
187
  <br>
188
188
 
189
189
  ```bash
190
- # Step 1: Check what exists
191
190
  rails 'ai:tool[schema]' table=users
192
- # → 20 columns, types, indexes, encrypted hints, defaults
193
-
194
- # Step 2: Understand the model
195
- rails 'ai:tool[model_details]' model=User
196
- # → associations, validations, scopes, enums, callbacks, Devise modules
197
-
198
- # Step 3: See the full feature
199
- rails 'ai:tool[analyze_feature]' feature=subscription
200
- # → models + controllers + routes + services + jobs + views + tests in one shot
191
+ ```
192
+ ```
193
+ ## Table: users
194
+ | Column | Type | Null | Default |
195
+ |---------------------|---------|------|---------|
196
+ | email | string | NO | [unique] |
197
+ | subscription_status | string | yes | "free" |
198
+ | created_at | datetime| NO | |
201
199
  ```
202
200
 
203
- AI writes a correct migration, model change, and controller update on the **first attempt**.
201
+ AI sees `subscription_status` already exists. Checks the model, then generates a correct migration **first attempt**.
204
202
 
205
203
  </details>
206
204
 
@@ -210,19 +208,18 @@ AI writes a correct migration, model change, and controller update on the **firs
210
208
  <br>
211
209
 
212
210
  ```bash
213
- # Trace what happens
214
211
  rails 'ai:tool[controllers]' controller=CooksController action=create
215
- # → source code + inherited filters + strong params + render map + side effects
216
-
217
- # Check the routes
218
- rails 'ai:tool[routes]' controller=cooks
219
- # → code-ready helpers (cook_path(@record)) + required params
212
+ ```
213
+ ```
214
+ # CooksController#create
220
215
 
221
- # Validate after fixing
222
- rails 'ai:tool[validate]' files=app/controllers/cooks_controller.rb level=rails
223
- # syntax + semantics + Brakeman security scan
216
+ Filters: before_action :authenticate_user!, before_action :set_cook (only: show, edit)
217
+ Strong params: cook_params → name, specialty, bio
218
+ Renders: redirect_to @cook | render :new
224
219
  ```
225
220
 
221
+ AI sees the inherited `authenticate_user!` filter, the actual strong params, and the render paths. No guessing.
222
+
226
223
  </details>
227
224
 
228
225
  <details>
@@ -252,7 +249,7 @@ rails 'ai:tool[stimulus]' controller=chart
252
249
 
253
250
  Every tool is **read-only** and returns data verified against your actual app — not guesses, not training data.
254
251
 
255
- <details>
252
+ <details open>
256
253
  <summary><strong>Search & Trace</strong></summary>
257
254
 
258
255
  | Tool | What it does |
@@ -262,7 +259,7 @@ Every tool is **read-only** and returns data verified against your actual app
262
259
 
263
260
  </details>
264
261
 
265
- <details>
262
+ <details open>
266
263
  <summary><strong>Understand</strong></summary>
267
264
 
268
265
  | Tool | What it does |
@@ -273,7 +270,7 @@ Every tool is **read-only** and returns data verified against your actual app
273
270
 
274
271
  </details>
275
272
 
276
- <details>
273
+ <details open>
277
274
  <summary><strong>Schema & Models</strong></summary>
278
275
 
279
276
  | Tool | What it does |
@@ -285,7 +282,7 @@ Every tool is **read-only** and returns data verified against your actual app
285
282
 
286
283
  </details>
287
284
 
288
- <details>
285
+ <details open>
289
286
  <summary><strong>Controllers & Routes</strong></summary>
290
287
 
291
288
  | Tool | What it does |
@@ -295,7 +292,7 @@ Every tool is **read-only** and returns data verified against your actual app
295
292
 
296
293
  </details>
297
294
 
298
- <details>
295
+ <details open>
299
296
  <summary><strong>Views & Frontend</strong></summary>
300
297
 
301
298
  | Tool | What it does |
@@ -308,7 +305,7 @@ Every tool is **read-only** and returns data verified against your actual app
308
305
 
309
306
  </details>
310
307
 
311
- <details>
308
+ <details open>
312
309
  <summary><strong>Testing & Quality</strong></summary>
313
310
 
314
311
  | Tool | What it does |
@@ -321,7 +318,7 @@ Every tool is **read-only** and returns data verified against your actual app
321
318
 
322
319
  </details>
323
320
 
324
- <details>
321
+ <details open>
325
322
  <summary><strong>App Config & Services</strong></summary>
326
323
 
327
324
  | Tool | What it does |
@@ -337,7 +334,7 @@ Every tool is **read-only** and returns data verified against your actual app
337
334
 
338
335
  </details>
339
336
 
340
- <details>
337
+ <details open>
341
338
  <summary><strong>Data & Debugging</strong></summary>
342
339
 
343
340
  | Tool | What it does |
@@ -354,7 +351,7 @@ Every tool is **read-only** and returns data verified against your actual app
354
351
 
355
352
  </details>
356
353
 
357
- > **[Full parameter docs →](docs/GUIDE.md)**
354
+ > **[All 38 tools with parameters →](docs/TOOLS.md)** &nbsp;|&nbsp; **[Real-world recipes →](docs/RECIPES.md)**
358
355
 
359
356
  <br>
360
357
 
@@ -398,26 +395,21 @@ Enabled by default. Disable with `config.anti_hallucination_rules = false` if yo
398
395
 
399
396
  ## How it works
400
397
 
401
- ```
402
- ┌─────────────────────────────────────────────────────────┐
403
- Your Rails App
404
- │ models + schema + routes + controllers + views + jobs │
405
- └────────────────────────┬────────────────────────────────┘
406
- │ introspects (31 introspectors)
407
-
408
- ┌─────────────────────────────────────────────────────────┐
409
- │ rails-ai-context │
410
- │ Prism AST parsing. Cached. Confidence-tagged results. │
411
- │ VFS: rails-ai-context:// URIs introspected fresh. │
412
- └────────┬──────────────────┬──────────────┬──────────────┘
413
- │ │ │
414
- ▼ ▼ ▼
415
- ┌──────────────────┐ ┌────────────┐ ┌────────────────────┐
416
- │ Static Files │ │ MCP Server │ │ CLI Tools │
417
- │ CLAUDE.md │ │ 38 tools │ │ Same 38 tools │
418
- │ .cursor/rules/ │ │ 5 templates│ │ No server needed │
419
- │ .github/instr... │ │ stdio/HTTP │ │ rails 'ai:tool[X]' │
420
- └──────────────────┘ └────────────┘ └────────────────────┘
398
+ ```mermaid
399
+ graph TD
400
+ A["Your Rails App\nmodels + schema + routes + controllers + views + jobs"] -->|"31 introspectors"| B
401
+
402
+ B["rails-ai-context\nPrism AST parsing · Cached · Confidence-tagged\nVFS: rails-ai-context:// URIs introspected fresh"]
403
+
404
+ B --> C["MCP Server\nstdio / HTTP\n38 tools · 5 templates"]
405
+ B --> D["CLI Tools\nRake / Thor\nSame 38 tools"]
406
+ B --> E["Static Files\nCLAUDE.md · .cursor/rules/\n.github/instructions/"]
407
+
408
+ style A fill:#4a9eff,stroke:#2d7ad4,color:#fff
409
+ style B fill:#2d2d2d,stroke:#555,color:#fff
410
+ style C fill:#0984e3,stroke:#0770c2,color:#fff
411
+ style D fill:#00cec9,stroke:#00b5b0,color:#fff
412
+ style E fill:#a29bfe,stroke:#8c83f0,color:#fff
421
413
  ```
422
414
 
423
415
  <br>
@@ -456,6 +448,58 @@ Both paths ask which AI tools you use (Claude Code, Cursor, GitHub Copilot, Open
456
448
 
457
449
  <br>
458
450
 
451
+ ## Documentation
452
+
453
+ | | |
454
+ |:------|:------------|
455
+ | **[Quickstart](docs/QUICKSTART.md)** | 5-minute getting started |
456
+ | **[Tools Reference](docs/TOOLS.md)** | All 38 tools with every parameter |
457
+ | **[Recipes](docs/RECIPES.md)** | Real-world workflows and examples |
458
+ | **[Custom Tools](docs/CUSTOM_TOOLS.md)** | Build and test your own MCP tools |
459
+ | **[Configuration](docs/CONFIGURATION.md)** | 40+ config options with defaults |
460
+ | **[AI Tool Setup](docs/SETUP.md)** | Claude, Cursor, Copilot, OpenCode, Codex |
461
+ | **[Architecture](docs/ARCHITECTURE.md)** | System design and internals |
462
+ | **[Introspectors](docs/INTROSPECTORS.md)** | All 31 introspectors and AST engine |
463
+ | **[Security](docs/SECURITY.md)** | 4-layer SQL safety and file blocking |
464
+ | **[CLI Reference](docs/CLI.md)** | Commands and argument syntax |
465
+ | **[Standalone](docs/STANDALONE.md)** | Use without Gemfile entry |
466
+ | **[Troubleshooting](docs/TROUBLESHOOTING.md)** | Common issues and fixes |
467
+ | **[FAQ](docs/FAQ.md)** | Frequently asked questions |
468
+
469
+ <br>
470
+
471
+ ## Build your own tools
472
+
473
+ Register custom MCP tools alongside the 38 built-in ones:
474
+
475
+ ```ruby
476
+ # app/mcp_tools/rails_get_business_metrics.rb
477
+ class RailsGetBusinessMetrics < MCP::Tool
478
+ tool_name "rails_get_business_metrics"
479
+ description "Key business metrics for this app"
480
+
481
+ def call(period: "week")
482
+ MCP::Tool::Response.new([{ type: "text", text: "Users this #{period}: #{User.recent.count}" }])
483
+ end
484
+ end
485
+
486
+ # config/initializers/rails_ai_context.rb
487
+ config.custom_tools = [RailsGetBusinessMetrics]
488
+ ```
489
+
490
+ Test with the built-in `TestHelper` (works with RSpec and Minitest):
491
+
492
+ ```ruby
493
+ include RailsAiContext::TestHelper
494
+
495
+ response = execute_tool("business_metrics", period: "month")
496
+ assert_tool_response_includes(response, "Users")
497
+ ```
498
+
499
+ > **[Custom Tools Guide →](docs/CUSTOM_TOOLS.md)**
500
+
501
+ <br>
502
+
459
503
  ## Configuration
460
504
 
461
505
  ```ruby
@@ -469,31 +513,13 @@ if defined?(RailsAiContext)
469
513
  end
470
514
  ```
471
515
 
472
- <details>
473
- <summary><strong>All configuration options</strong></summary>
474
-
475
- <br>
476
-
477
- | Option | Default | Description |
478
- |:-------|:--------|:------------|
479
- | `preset` | `:full` | `:full` (31 introspectors) or `:standard` (17) |
480
- | `context_mode` | `:compact` | `:compact` (150 lines) or `:full` |
481
- | `generate_root_files` | `true` | Set `false` for split rules only |
482
- | `anti_hallucination_rules` | `true` | Embed 6-rule verification protocol in generated context files |
483
- | `cache_ttl` | `60` | Cache TTL in seconds |
484
- | `max_tool_response_chars` | `200_000` | Safety cap for tool responses |
485
- | `live_reload` | `:auto` | `:auto`, `true`, or `false` |
486
- | `custom_tools` | `[]` | Additional MCP tool classes |
487
- | `skip_tools` | `[]` | Built-in tools to exclude |
488
- | `excluded_models` | `[]` | Models to skip during introspection |
489
-
490
- </details>
516
+ > **[All 40+ configuration options →](docs/CONFIGURATION.md)**
491
517
 
492
518
  <br>
493
519
 
494
520
  ## Observability
495
521
 
496
- Every MCP tool call and resource read fires an `ActiveSupport::Notifications` event. Subscribe with standard Rails patterns:
522
+ Every MCP tool call fires an `ActiveSupport::Notifications` event:
497
523
 
498
524
  ```ruby
499
525
  ActiveSupport::Notifications.subscribe("rails_ai_context.tools.call") do |event|
@@ -501,8 +527,6 @@ ActiveSupport::Notifications.subscribe("rails_ai_context.tools.call") do |event|
501
527
  end
502
528
  ```
503
529
 
504
- Events: `rails_ai_context.tools.call`, `rails_ai_context.resources.read`, and more. All 38 tools declare `output_schema` in the MCP protocol, so clients know the response format before calling.
505
-
506
530
  <br>
507
531
 
508
532
  ## Requirements
data/SECURITY.md CHANGED
@@ -4,6 +4,8 @@
4
4
 
5
5
  | Version | Supported |
6
6
  |---------|--------------------|
7
+ | 5.7.x | :white_check_mark: |
8
+ | 5.6.x | :white_check_mark: |
7
9
  | 5.5.x | :white_check_mark: |
8
10
  | 5.4.x | :white_check_mark: |
9
11
  | 5.3.x | :white_check_mark: |
@@ -0,0 +1,244 @@
1
+ <div align="center" markdown="1">
2
+
3
+ # Architecture
4
+
5
+ **How rails-ai-context is built, and why.**
6
+
7
+ [Tools Reference](TOOLS.md) · [Introspectors](INTROSPECTORS.md) · [Security](SECURITY.md) · [Custom Tools](CUSTOM_TOOLS.md)
8
+
9
+ </div>
10
+
11
+ ---
12
+
13
+ ## System overview
14
+
15
+ ```mermaid
16
+ graph TD
17
+ subgraph app["Your Rails App"]
18
+ A["models + schema + routes + controllers + views + jobs + config"]
19
+ end
20
+
21
+ A -->|"31 introspectors"| gem
22
+
23
+ subgraph gem["rails-ai-context"]
24
+ direction TB
25
+
26
+ subgraph engine["Introspection Engine"]
27
+ direction LR
28
+ I["Introspectors\n31 modules\nPresets\nCached"]
29
+ AST["AST Engine\nPrism\n7 listeners\nConfidence tags"]
30
+ H["Hydration Layer\nSchema hints\ninjected into\ntool responses"]
31
+ end
32
+
33
+ engine --> R["Tool Registry\n38 tools auto-discovered via inherited\n+ custom_tools - skip_tools = active tools"]
34
+ end
35
+
36
+ R --> MCP
37
+ R --> CLI
38
+ R --> S
39
+
40
+ subgraph outputs["Output"]
41
+ direction LR
42
+ MCP["MCP Server\nstdio / HTTP\nResources\nVFS URIs"]
43
+ CLI["CLI Runner\nRake / Thor\nSame 38 tools\nNo server needed"]
44
+ S["Serializers\n14 modules\nStatic files\nPer-AI-tool"]
45
+ end
46
+
47
+ style app fill:#4a9eff,stroke:#2d7ad4,color:#fff
48
+ style gem fill:#2d2d2d,stroke:#555,color:#fff
49
+ style engine fill:#3a3a3a,stroke:#666,color:#fff
50
+ style outputs fill:#1a1a1a,stroke:#444,color:#fff
51
+ style I fill:#6c5ce7,stroke:#5a4bd1,color:#fff
52
+ style AST fill:#e17055,stroke:#c0392b,color:#fff
53
+ style H fill:#00b894,stroke:#00a381,color:#fff
54
+ style R fill:#fdcb6e,stroke:#f0b429,color:#333
55
+ style MCP fill:#0984e3,stroke:#0770c2,color:#fff
56
+ style CLI fill:#00cec9,stroke:#00b5b0,color:#fff
57
+ style S fill:#a29bfe,stroke:#8c83f0,color:#fff
58
+ ```
59
+
60
+ ### Data flow
61
+
62
+ ```mermaid
63
+ sequenceDiagram
64
+ participant AI as AI Assistant
65
+ participant MCP as MCP Server
66
+ participant TR as Tool Registry
67
+ participant Cache as Cache Layer
68
+ participant App as Rails App
69
+
70
+ AI->>MCP: rails_get_schema(table: "users")
71
+ MCP->>TR: resolve tool + execute
72
+ TR->>Cache: check introspection cache
73
+ alt cache hit (TTL + fingerprint valid)
74
+ Cache-->>TR: cached context
75
+ else cache miss
76
+ Cache->>App: introspect (31 modules)
77
+ App-->>Cache: structured data
78
+ Cache-->>TR: fresh context
79
+ end
80
+ TR-->>MCP: MCP::Tool::Response
81
+ MCP-->>AI: schema with columns, indexes, hints
82
+ ```
83
+
84
+ ### Request lifecycle
85
+
86
+ ```mermaid
87
+ flowchart LR
88
+ A[Tool Call] --> B{Registered?}
89
+ B -->|Yes| C{Cache Valid?}
90
+ B -->|No| E[ToolNotFoundError]
91
+ C -->|Hit| D[Return Cached]
92
+ C -->|Miss| F[Introspect]
93
+ F --> G[Cache Result]
94
+ G --> D
95
+ D --> H[Hydrate\nSchema Hints]
96
+ H --> I[Truncate\nmax_chars]
97
+ I --> J[MCP::Tool::Response]
98
+ ```
99
+
100
+ ## Core modules
101
+
102
+ ### Introspectors (`lib/rails_ai_context/introspectors/`)
103
+
104
+ 31 modules that extract structured data from your Rails app. Each introspector:
105
+
106
+ - Returns a Hash (never raises — wraps errors in `{ error: msg }`)
107
+ - Is registered in `INTROSPECTOR_MAP` with a symbol key
108
+ - Belongs to one or both presets (`:standard`, `:full`)
109
+ - Results are cached with TTL + fingerprint invalidation
110
+
111
+ The `Introspector` orchestrator runs configured introspectors and merges results.
112
+
113
+ ### AST Engine
114
+
115
+ **Prism AST parsing** replaced all regex-based Ruby source parsing in v5.2.0.
116
+
117
+ - **AstCache** — Thread-safe parse cache (`Concurrent::Map`), keyed by path + SHA256 + mtime
118
+ - **SourceIntrospector** — Single-pass Prism Dispatcher walks the AST once, feeds events to all 7 listeners simultaneously
119
+ - **7 Listeners** — Associations, Validations, Scopes, Enums, Callbacks, Macros, Methods
120
+ - **Confidence** — Every result carries `[VERIFIED]` (static literals) or `[INFERRED]` (dynamic expressions)
121
+
122
+ ### Tool Registry (`lib/rails_ai_context/tools/base_tool.rb`)
123
+
124
+ Auto-registration via Ruby's `inherited` hook:
125
+
126
+ 1. `BaseTool.inherited(subclass)` fires when any file in `tools/` defines a subclass
127
+ 2. Subclass is appended to `@descendants` (protected by `@registry_mutex`)
128
+ 3. `BaseTool.registered_tools` eager-loads all tool files and returns non-abstract classes
129
+ 4. `BaseTool` itself is marked `abstract!` — excluded from the registry
130
+
131
+ **Deadlock-free design**: `eager_load!` collects constants to load inside the mutex, loads them outside (because `const_get` triggers Zeitwerk autoloading which calls `inherited` which needs the mutex), then sets the flag inside the mutex.
132
+
133
+ ### MCP Server (`lib/rails_ai_context/server.rb`)
134
+
135
+ Built on the official `mcp` Ruby SDK:
136
+
137
+ - **Transports**: stdio (default) or HTTP (Streamable HTTP via `MCP::Server::Transports::StreamableHTTPTransport`)
138
+ - **Tools**: all active tools (builtin + custom − skip_tools)
139
+ - **Resources**: 9 static resources + 5 dynamic VFS resource templates
140
+ - **Instrumentation**: bridges to `ActiveSupport::Notifications`
141
+ - **Live Reload**: watches files, invalidates caches, notifies clients
142
+
143
+ ### VFS (`lib/rails_ai_context/vfs.rb`)
144
+
145
+ Virtual File System for `rails-ai-context://` URIs:
146
+
147
+ ```
148
+ rails-ai-context://models/Post → model details + schema
149
+ rails-ai-context://controllers/Posts → actions, filters, params
150
+ rails-ai-context://controllers/Posts/index → action source
151
+ rails-ai-context://views/posts/show.html.erb → template content
152
+ rails-ai-context://routes/posts → filtered routes
153
+ ```
154
+
155
+ Every resolve call introspects fresh — zero stale data.
156
+
157
+ ### Hydration Layer (`lib/rails_ai_context/hydrators/`)
158
+
159
+ Cross-tool semantic hydration (v5.3.0):
160
+
161
+ - **ControllerHydrator** — Parses controller source via Prism AST to detect model references, injects schema hints
162
+ - **ViewHydrator** — Maps `@post` → `Post` by convention, injects schema hints
163
+ - **SchemaHintBuilder** — Resolves model names to `SchemaHint` value objects from cached context
164
+ - **HydrationFormatter** — Renders hints as compact Markdown sections
165
+
166
+ Result: controller and view tools automatically include relevant schema information without extra tool calls.
167
+
168
+ ### Serializers (`lib/rails_ai_context/serializers/`)
169
+
170
+ 14 modules that format introspection output for different AI tools:
171
+
172
+ | Serializer | Output |
173
+ |:-----------|:-------|
174
+ | `ClaudeSerializer` | `CLAUDE.md` |
175
+ | `ClaudeRulesSerializer` | `.claude/rules/*.md` |
176
+ | `CursorRulesSerializer` | `.cursor/rules/*.mdc` |
177
+ | `CopilotSerializer` | `.github/copilot-instructions.md` |
178
+ | `CopilotInstructionsSerializer` | `.github/instructions/*.instructions.md` |
179
+ | `OpencodeSerializer` | `AGENTS.md` (root) |
180
+ | `OpencodeRulesSerializer` | `app/*/AGENTS.md` |
181
+ | `JsonSerializer` | `.ai-context.json` |
182
+ | `MarkdownSerializer` | Base formatting |
183
+ | `ContextFileSerializer` | Atomic file writes with section markers |
184
+ | `CompactSerializerHelper` | Compact mode (≤150 lines) |
185
+ | `StackOverviewHelper` | Stack overview sections |
186
+ | `ToolGuideHelper` | MCP/CLI tool reference sections |
187
+ | `TestCommandDetection` | Test framework detection |
188
+
189
+ ### CLI (`exe/rails-ai-context`, `lib/rails_ai_context/cli/`)
190
+
191
+ Thor-based CLI that works standalone (no Gemfile entry):
192
+
193
+ - `ToolRunner` — Parses CLI args, resolves tool names, executes tools, formats output
194
+ - Supports `--json` mode for machine-readable output
195
+ - Same 38 tools available as MCP and CLI
196
+
197
+ ### Caching
198
+
199
+ Three cache layers:
200
+
201
+ 1. **Introspection cache** (`BaseTool.SHARED_CACHE`) — Mutex-protected, TTL + fingerprint invalidation
202
+ 2. **AST cache** (`AstCache`) — `Concurrent::Map`, SHA256 fingerprint per file
203
+ 3. **Session cache** (`BaseTool.SESSION_CONTEXT`) — Mutex-protected call history, resets on server restart
204
+
205
+ `LiveReload` watches files and calls `reset_all_caches!` when changes are detected.
206
+
207
+ ### Fingerprinter (`lib/rails_ai_context/fingerprinter.rb`)
208
+
209
+ SHA256-based change detection:
210
+
211
+ - Watches: `app/`, `config/`, `db/`, `lib/tasks/`, Gemfile.lock
212
+ - Computes a composite fingerprint from all watched files
213
+ - Used by introspection cache and live reload to detect actual changes
214
+
215
+ ## Key design decisions
216
+
217
+ 1. **Official MCP SDK** — Not a custom protocol. Uses `mcp` gem's `MCP::Tool`, `MCP::Server`, transports.
218
+ 2. **Read-only tools** — All 38 tools annotated as non-destructive. Defense-in-depth for query tool.
219
+ 3. **Graceful degradation** — Works without database (parses schema.rb as text), without Brakeman, without ripgrep, without listen gem.
220
+ 4. **Zeitwerk autoloading** — Files loaded on-demand. No `require_relative` in the gem.
221
+ 5. **Diff-aware generation** — Context file regeneration skips unchanged files using fingerprinting.
222
+ 6. **Section markers** — Root file content wrapped in `<!-- BEGIN/END rails-ai-context -->` to preserve user-added content.
223
+
224
+ ## Dependencies
225
+
226
+ | Gem | Purpose | Required? |
227
+ |:----|:--------|:----------|
228
+ | `mcp` | MCP SDK — server, tools, transports | Yes |
229
+ | `prism` | AST parsing (stdlib in Ruby 3.3+) | Yes |
230
+ | `concurrent-ruby` | Thread-safe caches | Yes |
231
+ | `zeitwerk` | Autoloading | Yes |
232
+ | `thor` | CLI framework | Yes |
233
+ | `brakeman` | Security scanning | Optional |
234
+ | `listen` | File watching for live reload | Optional |
235
+
236
+ ---
237
+
238
+ <div align="center" markdown="1">
239
+
240
+ **[← AI Tool Setup](SETUP.md)** · **[Introspectors →](INTROSPECTORS.md)**
241
+
242
+ [Back to Home](index.md)
243
+
244
+ </div>