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 +4 -4
- data/CHANGELOG.md +27 -0
- data/README.md +96 -72
- data/SECURITY.md +2 -0
- data/docs/ARCHITECTURE.md +244 -0
- data/docs/CLI.md +234 -0
- data/docs/CONFIGURATION.md +235 -0
- data/docs/CUSTOM_TOOLS.md +214 -0
- data/docs/FAQ.md +240 -0
- data/docs/GUIDE.md +30 -8
- data/docs/INTROSPECTORS.md +211 -0
- data/docs/QUICKSTART.md +118 -0
- data/docs/RECIPES.md +390 -0
- data/docs/SECURITY.md +238 -0
- data/docs/SETUP.md +359 -0
- data/docs/STANDALONE.md +169 -0
- data/docs/TOOLS.md +495 -0
- data/docs/TROUBLESHOOTING.md +285 -0
- data/docs/_config.yml +15 -0
- data/docs/_includes/head-custom.html +16 -0
- data/docs/index.md +54 -0
- data/docs/social-preview.html +164 -0
- data/lib/rails_ai_context/ast_cache.rb +2 -2
- data/lib/rails_ai_context/tools/analyze_feature.rb +2 -2
- data/lib/rails_ai_context/tools/get_concern.rb +1 -1
- data/lib/rails_ai_context/tools/migration_advisor.rb +1 -1
- data/lib/rails_ai_context/tools/search_code.rb +7 -8
- data/lib/rails_ai_context/version.rb +1 -1
- data/server.json +3 -3
- metadata +18 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 313744756e1399207abeb841866440c3de88da5863f92163fd7d344b60c479c5
|
|
4
|
+
data.tar.gz: 4de97686b1d62c8444a76ed78fc709aade9e0e004adae1a7a655c7d0eae8ce23
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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="
|
|
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
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
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
|
|
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
|
-
|
|
216
|
-
|
|
217
|
-
#
|
|
218
|
-
rails 'ai:tool[routes]' controller=cooks
|
|
219
|
-
# → code-ready helpers (cook_path(@record)) + required params
|
|
212
|
+
```
|
|
213
|
+
```
|
|
214
|
+
# CooksController#create
|
|
220
215
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
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
|
-
> **[
|
|
354
|
+
> **[All 38 tools with parameters →](docs/TOOLS.md)** | **[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
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
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
|
-
|
|
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
|
|
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
|
@@ -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>
|