rails-ai-context 0.9.0 → 0.10.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: 661adfd69ce52e181149673477e63271b1bb0d0e866f19b734e44054ba01e230
4
- data.tar.gz: b9468609fa7b9579b49b3cc2fefff3a30c4ac3fdbaeac31643cf0a211f4e4a77
3
+ metadata.gz: 9c9dabd282aadc577e5a66416e23e27c72dc728328490e4ce1af213358c215f1
4
+ data.tar.gz: 291cfd489f7b0b639655e3d0cdb473b0859b68bfdc2ed7ca1199826ac234af0a
5
5
  SHA512:
6
- metadata.gz: e3f09200ea197372810ce5526a9db0baa9f5c1f74072126c92b6a0318eaedb11bc0e2cb6b671d9b4de0813dd04e6cd86a97e9643f2952606fa2e8ae60ec9893b
7
- data.tar.gz: 5fda7235d72d4ccca1b918b93ee6a57f02add14a911d7178a7120db195ab7e6d4e1846d234db88beb36d842ae838bf7394f4bf89361d5dd389e26824140aee1d
6
+ metadata.gz: 95fd8e8c760b88e74d321102d9a55fda265c8cc7fb1d7de1b15ac8a7bc09666d08ada3540c194a7e9c1f2b134c6913feee1583c788113ec6d368485a41259cbf
7
+ data.tar.gz: d6a09886b74f4ece17e4529cff42fe99cdd1c68c2a6e04413d979754d362f461cdd074c40fea576c98b4187c83306787eeb88f25ea4952ffa99d1dee9bec3a80
data/CHANGELOG.md CHANGED
@@ -5,6 +5,17 @@ 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
+ ## [0.10.0] - 2026-03-19
9
+
10
+ ### Added
11
+
12
+ - **`rails_get_view` MCP tool** — get view template contents, partials, Stimulus references. Filter by controller or specific path. Supports summary/standard/full detail levels. Eliminates reading 490+ lines of view files per task. ([#7](https://github.com/crisnahine/rails-ai-context/issues/7))
13
+ - **`rails_get_stimulus` MCP tool** — get Stimulus controller details (targets, values, actions, outlets, classes). Filter by controller name. Wraps existing StimulusIntrospector. ([#8](https://github.com/crisnahine/rails-ai-context/issues/8))
14
+ - **`rails_get_controllers` `action` parameter** — returns actual action source code + applicable filters instead of the entire controller file. Saves ~1,400 tokens per call. ([#9](https://github.com/crisnahine/rails-ai-context/issues/9))
15
+ - **`rails_get_test_info` enhanced** — now supports `detail` levels (summary/standard/full), `model` and `controller` params to find existing tests, fixture/factory names, test helper setup. ([#10](https://github.com/crisnahine/rails-ai-context/issues/10))
16
+ - **ViewTemplateIntrospector** — new introspector that reads view file contents and extracts partial references and Stimulus data attributes.
17
+ - **Stimulus in standard preset** — `:stimulus` introspector now included in the `:standard` preset (was `:full` only).
18
+
8
19
  ## [0.9.0] - 2026-03-19
9
20
 
10
21
  ### Added
data/CLAUDE.md CHANGED
@@ -8,8 +8,8 @@ structure to AI assistants via the Model Context Protocol (MCP).
8
8
  - `lib/rails_ai_context.rb` — Main entry point, public API (Zeitwerk autoloaded)
9
9
  - `lib/rails_ai_context/configuration.rb` — User-facing config with presets (:standard, :full)
10
10
  - `lib/rails_ai_context/introspector.rb` — Orchestrates sub-introspectors
11
- - `lib/rails_ai_context/introspectors/` — 27 introspectors (schema, models, routes, jobs, gems, conventions, stimulus, database_stats, controllers, views, turbo, i18n, config, active_storage, action_text, auth, api, tests, rake_tasks, assets, devops, action_mailbox, migrations, seeds, middleware, engines, multi_database)
12
- - `lib/rails_ai_context/tools/` — 9 MCP tools using the official mcp SDK
11
+ - `lib/rails_ai_context/introspectors/` — 28 introspectors (schema, models, routes, jobs, gems, conventions, stimulus, database_stats, controllers, views, view_templates, turbo, i18n, config, active_storage, action_text, auth, api, tests, rake_tasks, assets, devops, action_mailbox, migrations, seeds, middleware, engines, multi_database)
12
+ - `lib/rails_ai_context/tools/` — 11 MCP tools using the official mcp SDK
13
13
  - `lib/rails_ai_context/serializers/` — Output formatters (claude, claude_rules, opencode, cursor_rules, windsurf, windsurf_rules, copilot, copilot_instructions, rules, markdown, JSON)
14
14
  - `lib/rails_ai_context/resources.rb` — MCP resources (static data AI clients read directly)
15
15
  - `lib/rails_ai_context/server.rb` — MCP server configuration (stdio + HTTP transports)
@@ -32,7 +32,7 @@ structure to AI assistants via the Model Context Protocol (MCP).
32
32
  6. **Diff-aware** — context regeneration skips unchanged files
33
33
  7. **Per-assistant serializers** — each AI tool gets tailored output format
34
34
  8. **Zeitwerk autoloading** — files loaded on-demand, not all upfront
35
- 9. **Introspector presets** — `:standard` (9 core) default, `:full` (26) for power users
35
+ 9. **Introspector presets** — `:standard` (10 core) default, `:full` (28) for power users
36
36
  10. **MCP auto-discovery** — `.mcp.json` generated by install generator
37
37
  11. **Compact by default** — context files ≤150 lines, MCP tools use `detail` parameter (summary/standard/full)
38
38
  12. **Per-tool split rules** — `.claude/rules/`, `.cursor/rules/`, `.windsurf/rules/`, `.github/instructions/`
@@ -42,7 +42,7 @@ structure to AI assistants via the Model Context Protocol (MCP).
42
42
  ## Testing
43
43
 
44
44
  ```bash
45
- bundle exec rspec # Run specs (408 examples)
45
+ bundle exec rspec # Run specs (412 examples)
46
46
  bundle exec rubocop # Lint
47
47
  ```
48
48
 
data/CONTRIBUTING.md CHANGED
@@ -18,8 +18,8 @@ The test suite uses [Combustion](https://github.com/pat/combustion) to boot a mi
18
18
 
19
19
  ```
20
20
  lib/rails_ai_context/
21
- ├── introspectors/ # 27 introspectors (schema, models, routes, etc.)
22
- ├── tools/ # 9 MCP tools with detail levels and pagination
21
+ ├── introspectors/ # 28 introspectors (schema, models, routes, etc.)
22
+ ├── tools/ # 11 MCP tools with detail levels and pagination
23
23
  ├── serializers/ # Per-assistant formatters (claude, opencode, cursor, windsurf, copilot, JSON)
24
24
  ├── server.rb # MCP server setup (stdio + HTTP)
25
25
  ├── live_reload.rb # MCP live reload (file watcher + cache invalidation)
data/README.md CHANGED
@@ -7,15 +7,11 @@
7
7
  [![CI](https://github.com/crisnahine/rails-ai-context/actions/workflows/ci.yml/badge.svg)](https://github.com/crisnahine/rails-ai-context/actions)
8
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
9
9
 
10
- ![Token Comparison](https://raw.githubusercontent.com/crisnahine/rails-ai-context/main/docs/token-comparison.jpeg)
11
-
12
10
  *Built by a Rails dev who got tired of burning tokens explaining his app to AI assistants every single session.*
13
11
 
14
- ![Demo](https://raw.githubusercontent.com/crisnahine/rails-ai-context/main/demo.gif)
15
-
16
12
  ---
17
13
 
18
- ## Why?
14
+ ## The Problem
19
15
 
20
16
  You open Claude Code, Cursor, or Copilot and ask: *"Add a draft status to posts with a scheduled publish date."*
21
17
 
@@ -23,9 +19,24 @@ The AI doesn't know your schema, your Devise setup, your Sidekiq jobs, or that `
23
19
 
24
20
  **rails-ai-context fixes this.** It auto-introspects your entire Rails app and feeds everything to your AI assistant — schema, models, routes, controllers, jobs, gems, auth, API, tests, config, and conventions — through the [Model Context Protocol (MCP)](https://modelcontextprotocol.io).
25
21
 
26
- **No configuration. No manual tool definitions. Just `bundle add` and go.**
22
+ ---
27
23
 
28
- > **[Full Guide](docs/GUIDE.md)** complete documentation with every command, parameter, and configuration option.
24
+ ## Proof: 35% Token Savings (Real Benchmark)
25
+
26
+ We ran the same feature task — *"Add status and date range filters to the Cooks index page"* — across 4 scenarios in parallel on a real Rails app:
27
+
28
+ | Scenario | MCP Tools | CLAUDE.md | Tokens Used | Savings |
29
+ |----------|-----------|-----------|-------------|---------|
30
+ | **MCP + CLAUDE.md** | Yes | Yes | **25,884** | **35% saved** |
31
+ | MCP only | Yes | No | 27,822 | 31% saved |
32
+ | CLAUDE.md only | No | Yes | 32,699 | 19% saved |
33
+ | Zero (nothing) | No | No | 40,129 | baseline |
34
+
35
+ All 4 produced the same working feature. The only difference was how many tokens were burned getting there.
36
+
37
+ https://github.com/user-attachments/assets/171f52ae-bd30-43f6-a44f-bcfdda7fc139
38
+
39
+ MCP tools give the AI structured, filtered access to your codebase instead of reading entire files. On this small 5-model app, that saved 35%. **On larger projects, the savings compound significantly.**
29
40
 
30
41
  ---
31
42
 
@@ -41,11 +52,64 @@ That's it. Three commands. Your AI assistant now understands your entire Rails a
41
52
 
42
53
  The install generator creates `.mcp.json` for auto-discovery — Claude Code and Cursor detect it automatically. No manual MCP config needed.
43
54
 
55
+ > **[Full Guide](docs/GUIDE.md)** — complete documentation with every command, parameter, and configuration option.
56
+
57
+ ---
58
+
59
+ ## How It Saves Tokens
60
+
61
+ ![Token Comparison](https://raw.githubusercontent.com/crisnahine/rails-ai-context/main/docs/token-comparison.jpeg)
62
+
63
+ - Compact context files load ≤150 lines instead of thousands
64
+ - MCP tools return `detail:"summary"` first (~55 tokens for schema overview), then drill into specifics
65
+ - Specific lookups (`table:`, `model:`, `controller:`) return only what's needed
66
+ - Pagination prevents dumping hundreds of tables/routes at once
67
+ - Split rule files only activate in relevant directories
68
+
69
+ ---
70
+
71
+ ## 11 Live MCP Tools
72
+
73
+ The gem exposes **11 read-only tools** via MCP that AI clients call on-demand:
74
+
75
+ | Tool | What it returns |
76
+ |------|----------------|
77
+ | `rails_get_schema` | Tables, columns, indexes, foreign keys |
78
+ | `rails_get_model_details` | Associations, validations, scopes, enums, callbacks |
79
+ | `rails_get_routes` | HTTP verbs, paths, controller actions |
80
+ | `rails_get_controllers` | Actions, filters, strong params, concerns |
81
+ | `rails_get_config` | Cache, session, timezone, middleware, initializers |
82
+ | `rails_get_test_info` | Test framework, factories, CI config, coverage |
83
+ | `rails_get_gems` | Notable gems categorized by function |
84
+ | `rails_get_conventions` | Architecture patterns, directory structure |
85
+ | `rails_search_code` | Ripgrep-powered regex search across the codebase |
86
+ | `rails_get_view` | View templates, partials, Stimulus references |
87
+ | `rails_get_stimulus` | Stimulus controllers — targets, values, actions, outlets |
88
+
89
+ ### Smart Detail Levels
90
+
91
+ Schema, routes, models, and controllers tools support a `detail` parameter — critical for large apps:
92
+
93
+ | Level | Returns | Default limit |
94
+ |-------|---------|---------------|
95
+ | `summary` | Names + counts | 50 |
96
+ | `standard` | Names + key details *(default)* | 15 |
97
+ | `full` | Everything (indexes, FKs, constraints) | 5 |
98
+
99
+ ```ruby
100
+ rails_get_schema(detail: "summary") # → all tables with column counts
101
+ rails_get_schema(table: "users") # → full detail for one table
102
+ rails_get_routes(controller: "users") # → routes for one controller
103
+ rails_get_model_details(model: "User") # → associations, validations, scopes
104
+ ```
105
+
106
+ A safety net (`max_tool_response_chars`, default 120K) truncates oversized responses with hints to use filters.
107
+
44
108
  ---
45
109
 
46
110
  ## What Gets Generated
47
111
 
48
- `rails ai:context` generates **20 files** tailored to each AI assistant:
112
+ `rails ai:context` generates context files tailored to each AI assistant:
49
113
 
50
114
  ```
51
115
  your-rails-app/
@@ -53,9 +117,9 @@ your-rails-app/
53
117
  ├── 🟣 Claude Code
54
118
  │ ├── CLAUDE.md ≤150 lines (compact)
55
119
  │ └── .claude/rules/
120
+ │ ├── rails-context.md app overview
56
121
  │ ├── rails-schema.md table listing
57
122
  │ ├── rails-models.md model listing
58
- │ ├── rails-context.md app overview
59
123
  │ └── rails-mcp-tools.md full tool reference
60
124
 
61
125
  ├── 🟢 Cursor
@@ -87,9 +151,7 @@ your-rails-app/
87
151
  └── .mcp.json MCP auto-discovery
88
152
  ```
89
153
 
90
- Each file respects the AI tool's format and size limits. **Commit these files** your entire team gets smarter AI assistance.
91
-
92
- > Use `rails ai:context:full` to dump everything into the files (good for small apps <30 models).
154
+ Root files (CLAUDE.md, AGENTS.md, etc.) use **section markers** your custom content outside the markers is preserved on re-generation. Set `config.generate_root_files = false` to only generate split rules.
93
155
 
94
156
  ---
95
157
 
@@ -98,13 +160,13 @@ Each file respects the AI tool's format and size limits. **Commit these files**
98
160
  | Category | What's introspected |
99
161
  |----------|-------------------|
100
162
  | **Database** | Every table, column, index, foreign key, and migration |
101
- | **Models** | Associations, validations, scopes, enums, callbacks, concerns, macros (`has_secure_password`, `encrypts`, `normalizes`, etc.) |
163
+ | **Models** | Associations, validations, scopes, enums, callbacks, concerns, macros |
102
164
  | **Routing** | Every route with HTTP verbs, paths, controller actions, API namespaces |
103
165
  | **Controllers** | Actions, filters, strong params, concerns, API controllers |
104
166
  | **Views** | Layouts, templates, partials, helpers, template engines, view components |
105
- | **Frontend** | Stimulus controllers (targets, values, actions, outlets), Turbo Frames/Streams, model broadcasts |
167
+ | **Frontend** | Stimulus controllers (targets, values, actions, outlets), Turbo Frames/Streams |
106
168
  | **Background** | ActiveJob classes, mailers, Action Cable channels |
107
- | **Gems** | 70+ notable gems categorized (Devise = auth, Sidekiq = jobs, Pundit = authorization, etc.) |
169
+ | **Gems** | 70+ notable gems categorized (Devise = auth, Sidekiq = jobs, Pundit = authorization) |
108
170
  | **Auth** | Devise modules, Pundit policies, CanCanCan, has_secure_password, CORS, CSP |
109
171
  | **API** | Serializers, GraphQL, versioning, rate limiting, API-only mode |
110
172
  | **Testing** | Framework, factories/fixtures, CI config, coverage, system tests |
@@ -112,76 +174,7 @@ Each file respects the AI tool's format and size limits. **Commit these files**
112
174
  | **DevOps** | Puma, Procfile, Docker, deployment tools, asset pipeline |
113
175
  | **Architecture** | Service objects, STI, polymorphism, state machines, multi-tenancy, engines |
114
176
 
115
- 27 introspectors total. The `:standard` preset runs 9 core ones by default; use `:full` for all 27.
116
-
117
- ---
118
-
119
- ## MCP Tools
120
-
121
- The gem exposes **9 live tools** via MCP that AI clients call on-demand:
122
-
123
- | Tool | What it returns |
124
- |------|----------------|
125
- | `rails_get_schema` | Tables, columns, indexes, foreign keys |
126
- | `rails_get_model_details` | Associations, validations, scopes, enums, callbacks |
127
- | `rails_get_routes` | HTTP verbs, paths, controller actions |
128
- | `rails_get_controllers` | Actions, filters, strong params, concerns |
129
- | `rails_get_config` | Cache, session, timezone, middleware, initializers |
130
- | `rails_get_test_info` | Test framework, factories, CI config, coverage |
131
- | `rails_get_gems` | Notable gems categorized by function |
132
- | `rails_get_conventions` | Architecture patterns, directory structure |
133
- | `rails_search_code` | Ripgrep-powered regex search across the codebase |
134
-
135
- All tools are **read-only** — they never modify your application or database.
136
-
137
- ### Smart Detail Levels
138
-
139
- Schema, routes, models, and controllers tools support a `detail` parameter — critical for large apps:
140
-
141
- | Level | Returns | Default limit |
142
- |-------|---------|---------------|
143
- | `summary` | Names + counts | 50 |
144
- | `standard` | Names + key details *(default)* | 15 |
145
- | `full` | Everything (indexes, FKs, constraints) | 5 |
146
-
147
- ```ruby
148
- # Start broad
149
- rails_get_schema(detail: "summary") # → all tables with column counts
150
-
151
- # Drill into specifics
152
- rails_get_schema(table: "users") # → full detail for one table
153
-
154
- # Paginate large schemas
155
- rails_get_schema(detail: "summary", limit: 20, offset: 40)
156
-
157
- # Filter routes by controller
158
- rails_get_routes(controller: "users")
159
-
160
- # Get one model's full details
161
- rails_get_model_details(model: "User")
162
- ```
163
-
164
- A safety net (`max_tool_response_chars`, default 120K) truncates oversized responses with hints to use filters.
165
-
166
- ### Token Savings
167
-
168
- The summary-first approach dramatically reduces AI token consumption — especially for large apps:
169
-
170
- | Metric | Without gem | Full dump (v0.6) | Smart mode (v0.7+) |
171
- |--------|-------------|------------------|---------------------|
172
- | Context file | 0 tokens | ~15,000 tokens | ~1,500 tokens |
173
- | Schema lookup | manual copy-paste | ~45,000 tokens (all tables) | ~800 tokens (summary) |
174
- | Drill into 1 table | manual copy-paste | included above | ~400 tokens |
175
- | **2-call workflow** | **error-prone** | **~60,000 tokens** | **~2,700 tokens** |
176
-
177
- That's **~95% fewer tokens** for the same understanding. The AI gets a compact overview first, then only loads what it actually needs — you pay for precision, not bulk.
178
-
179
- **How it saves:**
180
- - Compact context files load ≤150 lines instead of thousands
181
- - `detail:"summary"` gives the AI the full landscape in ~800 tokens
182
- - Specific lookups (`table:`, `model:`, `controller:`) return only what's needed
183
- - Pagination prevents dumping hundreds of tables/routes at once
184
- - Split rule files only activate in relevant directories (e.g., model rules load only when editing `app/models/`)
177
+ 28 introspectors total. The `:standard` preset runs 10 core ones by default; use `:full` for 27 (`database_stats` is opt-in, PostgreSQL only).
185
178
 
186
179
  ---
187
180
 
@@ -235,7 +228,7 @@ end
235
228
  ```ruby
236
229
  # config/initializers/rails_ai_context.rb
237
230
  RailsAiContext.configure do |config|
238
- # Presets: :standard (9 introspectors, default) or :full (all 27)
231
+ # Presets: :standard (10 introspectors, default) or :full (all 28)
239
232
  config.preset = :standard
240
233
 
241
234
  # Cherry-pick on top of a preset
@@ -269,7 +262,7 @@ end
269
262
  | Option | Default | Description |
270
263
  |--------|---------|-------------|
271
264
  | `preset` | `:standard` | Introspector preset (`:standard` or `:full`) |
272
- | `introspectors` | 9 core | Array of introspector symbols |
265
+ | `introspectors` | 10 core | Array of introspector symbols |
273
266
  | `context_mode` | `:compact` | `:compact` (≤150 lines) or `:full` (dump everything) |
274
267
  | `claude_max_lines` | `150` | Max lines for CLAUDE.md in compact mode |
275
268
  | `max_tool_response_chars` | `120_000` | Safety cap for MCP tool responses |
@@ -286,29 +279,13 @@ end
286
279
 
287
280
  ---
288
281
 
289
- ## Stack Compatibility
290
-
291
- Works with every Rails architecture — auto-detects what's relevant:
292
-
293
- | Setup | Coverage | Notes |
294
- |-------|----------|-------|
295
- | Rails full-stack (ERB + Hotwire) | 27/27 | All introspectors relevant |
296
- | Rails + Inertia.js (React/Vue) | ~22/27 | Views/Turbo partially useful, backend fully covered |
297
- | Rails API + React/Next.js SPA | ~20/27 | Schema, models, routes, API, auth, jobs — all covered |
298
- | Rails API + mobile app | ~20/27 | Same as SPA — backend introspection is identical |
299
- | Rails engine (mountable gem) | ~15/27 | Core introspectors (schema, models, routes, gems) work |
300
-
301
- Frontend introspectors (views, Turbo, Stimulus, assets) degrade gracefully — they report nothing when those features aren't present.
302
-
303
- ---
304
-
305
282
  ## Commands
306
283
 
307
284
  ### Rake tasks (recommended)
308
285
 
309
286
  | Command | Description |
310
287
  |---------|-------------|
311
- | `rails ai:context` | Generate all 20 context files (skips unchanged) |
288
+ | `rails ai:context` | Generate all context files (skips unchanged) |
312
289
  | `rails ai:context:full` | Generate all files in full mode (dumps everything) |
313
290
  | `rails ai:context:claude` | Generate Claude Code files only |
314
291
  | `rails ai:context:opencode` | Generate OpenCode files only |
@@ -321,17 +298,9 @@ Frontend introspectors (views, Turbo, Stimulus, assets) degrade gracefully — t
321
298
  | `rails ai:watch` | Auto-regenerate context files on code changes |
322
299
  | `rails ai:inspect` | Print introspection summary to stdout |
323
300
 
324
- > **Context modes:**
325
- > ```bash
326
- > rails ai:context # compact (default) — all formats
327
- > rails ai:context:full # full dump — all formats
328
- > CONTEXT_MODE=full rails ai:context:claude # full dump — Claude only
329
- > CONTEXT_MODE=full rails ai:context:cursor # full dump — Cursor only
330
- > ```
331
-
332
301
  ### Standalone CLI
333
302
 
334
- The gem also ships a `rails-ai-context` executable — an alternative to rake tasks. Useful for `.mcp.json` configs or when you prefer a shorter command.
303
+ The gem also ships a `rails-ai-context` executable — an alternative to rake tasks.
335
304
 
336
305
  | Command | Equivalent rake task |
337
306
  |---------|---------------------|
@@ -348,6 +317,22 @@ Run from your Rails app root. Use `rails-ai-context help` for all options.
348
317
 
349
318
  ---
350
319
 
320
+ ## Stack Compatibility
321
+
322
+ Works with every Rails architecture — auto-detects what's relevant:
323
+
324
+ | Setup | Coverage | Notes |
325
+ |-------|----------|-------|
326
+ | Rails full-stack (ERB + Hotwire) | 28/28 | All introspectors relevant |
327
+ | Rails + Inertia.js (React/Vue) | ~22/27 | Views/Turbo partially useful, backend fully covered |
328
+ | Rails API + React/Next.js SPA | ~20/27 | Schema, models, routes, API, auth, jobs — all covered |
329
+ | Rails API + mobile app | ~20/27 | Same as SPA — backend introspection is identical |
330
+ | Rails engine (mountable gem) | ~15/27 | Core introspectors (schema, models, routes, gems) work |
331
+
332
+ Frontend introspectors (views, Turbo, Stimulus, assets) degrade gracefully — they report nothing when those features aren't present.
333
+
334
+ ---
335
+
351
336
  ## Works Without a Database
352
337
 
353
338
  The gem parses `db/schema.rb` as text when no database is connected. Works in CI, Docker build stages, and Claude Code sessions without a running DB.
@@ -377,7 +362,7 @@ The gem parses `db/schema.rb` as text when no database is connected. Works in CI
377
362
  ```bash
378
363
  git clone https://github.com/crisnahine/rails-ai-context.git
379
364
  cd rails-ai-context && bundle install
380
- bundle exec rspec # 408 examples
365
+ bundle exec rspec # 412 examples
381
366
  bundle exec rubocop # Lint
382
367
  ```
383
368
 
data/demo_script.sh CHANGED
@@ -8,7 +8,7 @@ echo 'Fetching gem metadata from https://rubygems.org...'
8
8
  sleep 0.3
9
9
  echo 'Resolving dependencies...'
10
10
  sleep 0.3
11
- echo 'Installing rails-ai-context 0.9.0'
11
+ echo 'Installing rails-ai-context 0.10.0'
12
12
  echo ''
13
13
  sleep 1
14
14
 
data/docs/GUIDE.md CHANGED
@@ -246,7 +246,7 @@ rails ai:context:claude # Use this instead (no quoting needed)
246
246
 
247
247
  ## MCP Tools — Full Reference
248
248
 
249
- All 9 tools are **read-only** and **idempotent** — they never modify your application or database.
249
+ All 11 tools are **read-only** and **idempotent** — they never modify your application or database.
250
250
 
251
251
  ### rails_get_schema
252
252
 
@@ -568,7 +568,7 @@ RailsAiContext.configure do |config|
568
568
  end
569
569
  ```
570
570
 
571
- Both transports are **read-only** — they expose the same 9 tools and never modify your app.
571
+ Both transports are **read-only** — they expose the same 11 tools and never modify your app.
572
572
 
573
573
  ---
574
574
 
@@ -579,7 +579,7 @@ Both transports are **read-only** — they expose the same 9 tools and never mod
579
579
  RailsAiContext.configure do |config|
580
580
  # --- Introspectors ---
581
581
 
582
- # Presets: :standard (9 core, default) or :full (all 27)
582
+ # Presets: :standard (10 core, default) or :full (all 28)
583
583
  config.preset = :standard
584
584
 
585
585
  # Cherry-pick on top of a preset
@@ -636,7 +636,7 @@ end
636
636
  | Option | Type | Default | Description |
637
637
  |--------|------|---------|-------------|
638
638
  | `preset` | Symbol | `:standard` | Introspector preset (`:standard` or `:full`) |
639
- | `introspectors` | Array | 9 core symbols | Which introspectors to run |
639
+ | `introspectors` | Array | 10 core symbols | Which introspectors to run |
640
640
  | `context_mode` | Symbol | `:compact` | `:compact` or `:full` |
641
641
  | `claude_max_lines` | Integer | `150` | Max lines for CLAUDE.md in compact mode |
642
642
  | `max_tool_response_chars` | Integer | `120_000` | Safety cap for MCP tool responses |
@@ -689,7 +689,7 @@ These run by default. Fast and cover core Rails structure.
689
689
  | `tests` | Test framework (rspec/minitest), factories/fixtures with locations and counts, system tests, CI config files, coverage tool, test helpers, VCR cassettes. |
690
690
  | `migrations` | Total count, schema version, pending migrations, recent migration history with detected actions (create_table, add_column, etc.), migration statistics. |
691
691
 
692
- ### Full preset (27 introspectors)
692
+ ### Full preset (28 introspectors)
693
693
 
694
694
  Includes all standard introspectors plus:
695
695
 
@@ -812,7 +812,7 @@ OpenCode uses **per-directory lazy-loading**: when the agent reads a file, it wa
812
812
 
813
813
  | Setup | Coverage | Notes |
814
814
  |-------|----------|-------|
815
- | Rails full-stack (ERB + Hotwire) | 27/27 | All introspectors relevant |
815
+ | Rails full-stack (ERB + Hotwire) | 28/28 | All introspectors relevant |
816
816
  | Rails + Inertia.js (React/Vue) | ~22/27 | Views/Turbo partially useful, backend fully covered |
817
817
  | Rails API + React/Next.js SPA | ~20/27 | Schema, models, routes, API, auth, jobs — all covered |
818
818
  | Rails API + mobile app | ~20/27 | Same as SPA — backend introspection is identical |
Binary file
@@ -3,8 +3,8 @@
3
3
  module RailsAiContext
4
4
  class Configuration
5
5
  PRESETS = {
6
- standard: %i[schema models routes jobs gems conventions controllers tests migrations],
7
- full: %i[schema models routes jobs gems conventions stimulus controllers views turbo
6
+ standard: %i[schema models routes jobs gems conventions controllers tests migrations stimulus],
7
+ full: %i[schema models routes jobs gems conventions stimulus controllers views view_templates turbo
8
8
  i18n config active_storage action_text auth api tests rake_tasks assets
9
9
  devops action_mailbox migrations seeds middleware engines multi_database]
10
10
  }.freeze
@@ -57,6 +57,7 @@ module RailsAiContext
57
57
  when :database_stats then Introspectors::DatabaseStatsIntrospector.new(app)
58
58
  when :controllers then Introspectors::ControllerIntrospector.new(app)
59
59
  when :views then Introspectors::ViewIntrospector.new(app)
60
+ when :view_templates then Introspectors::ViewTemplateIntrospector.new(app)
60
61
  when :turbo then Introspectors::TurboIntrospector.new(app)
61
62
  when :i18n then Introspectors::I18nIntrospector.new(app)
62
63
  when :config then Introspectors::ConfigIntrospector.new(app)
@@ -15,9 +15,13 @@ module RailsAiContext
15
15
  {
16
16
  framework: detect_framework,
17
17
  factories: detect_factories,
18
+ factory_names: detect_factory_names,
18
19
  fixtures: detect_fixtures,
20
+ fixture_names: detect_fixture_names,
19
21
  system_tests: detect_system_tests,
20
22
  test_helpers: detect_test_helpers,
23
+ test_helper_setup: detect_test_helper_setup,
24
+ test_files: detect_test_files,
21
25
  vcr_cassettes: detect_vcr,
22
26
  ci_config: detect_ci,
23
27
  coverage: detect_coverage
@@ -97,6 +101,71 @@ module RailsAiContext
97
101
  end.flatten.sort
98
102
  end
99
103
 
104
+ def detect_factory_names
105
+ %w[spec/factories test/factories].each do |dir_rel|
106
+ dir = File.join(root, dir_rel)
107
+ next unless Dir.exist?(dir)
108
+
109
+ names = {}
110
+ Dir.glob(File.join(dir, "**/*.rb")).each do |path|
111
+ file = path.sub("#{root}/", "")
112
+ factories = File.read(path).scan(/factory\s+:(\w+)/).flatten
113
+ names[file] = factories if factories.any?
114
+ rescue
115
+ next
116
+ end
117
+ return names if names.any?
118
+ end
119
+ nil
120
+ end
121
+
122
+ def detect_fixture_names
123
+ %w[spec/fixtures test/fixtures].each do |dir_rel|
124
+ dir = File.join(root, dir_rel)
125
+ next unless Dir.exist?(dir)
126
+
127
+ names = {}
128
+ Dir.glob(File.join(dir, "**/*.yml")).each do |path|
129
+ file = File.basename(path, ".yml")
130
+ content = File.read(path) rescue next
131
+ # Top-level YAML keys are fixture names
132
+ keys = content.scan(/^(\w+):/).flatten
133
+ names[file] = keys if keys.any?
134
+ end
135
+ return names if names.any?
136
+ end
137
+ nil
138
+ end
139
+
140
+ def detect_test_helper_setup
141
+ helpers = %w[
142
+ spec/rails_helper.rb spec/spec_helper.rb
143
+ test/test_helper.rb
144
+ ]
145
+
146
+ setup = []
147
+ helpers.each do |rel|
148
+ path = File.join(root, rel)
149
+ next unless File.exist?(path)
150
+ content = File.read(path) rescue next
151
+ content.scan(/(?:config\.)?include\s+([\w:]+)/).each { |m| setup << m[0] }
152
+ end
153
+ setup.uniq
154
+ end
155
+
156
+ def detect_test_files
157
+ categories = {}
158
+ %w[models controllers requests system services integration features].each do |cat|
159
+ %w[spec test].each do |base|
160
+ dir = File.join(root, base, cat)
161
+ next unless Dir.exist?(dir)
162
+ count = Dir.glob(File.join(dir, "**/*.rb")).size
163
+ categories[cat] = { location: "#{base}/#{cat}", count: count } if count > 0
164
+ end
165
+ end
166
+ categories
167
+ end
168
+
100
169
  def detect_vcr
101
170
  dirs = [
102
171
  File.join(root, "spec/cassettes"),
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsAiContext
4
+ module Introspectors
5
+ # Reads actual view template contents and extracts metadata:
6
+ # partial references, Stimulus controller usage, line counts.
7
+ # Separate from ViewIntrospector which focuses on structural discovery.
8
+ class ViewTemplateIntrospector
9
+ attr_reader :app
10
+
11
+ def initialize(app)
12
+ @app = app
13
+ end
14
+
15
+ def call
16
+ views_dir = File.join(app.root.to_s, "app", "views")
17
+ return { templates: {}, partials: {} } unless Dir.exist?(views_dir)
18
+
19
+ {
20
+ templates: scan_templates(views_dir),
21
+ partials: scan_partials(views_dir)
22
+ }
23
+ rescue => e
24
+ { error: e.message }
25
+ end
26
+
27
+ private
28
+
29
+ def scan_templates(views_dir)
30
+ templates = {}
31
+ Dir.glob(File.join(views_dir, "**", "*")).each do |path|
32
+ next if File.directory?(path)
33
+ next if File.basename(path).start_with?("_") # skip partials
34
+ next if path.include?("/layouts/")
35
+
36
+ relative = path.sub("#{views_dir}/", "")
37
+ content = File.read(path) rescue next
38
+ templates[relative] = {
39
+ lines: content.lines.count,
40
+ partials: extract_partial_refs(content),
41
+ stimulus: extract_stimulus_refs(content)
42
+ }
43
+ end
44
+ templates
45
+ end
46
+
47
+ def scan_partials(views_dir)
48
+ partials = {}
49
+ Dir.glob(File.join(views_dir, "**", "_*")).each do |path|
50
+ next if File.directory?(path)
51
+ relative = path.sub("#{views_dir}/", "")
52
+ lines = File.read(path).lines.count rescue 0
53
+ partials[relative] = { lines: lines }
54
+ end
55
+ partials
56
+ end
57
+
58
+ def extract_partial_refs(content)
59
+ refs = []
60
+ # render "partial_name" or render partial: "name"
61
+ content.scan(/render\s+(?:partial:\s*)?["']([^"']+)["']/).each { |m| refs << m[0] }
62
+ # render @collection
63
+ content.scan(/render\s+@(\w+)/).each { |m| refs << m[0] }
64
+ refs.uniq
65
+ end
66
+
67
+ def extract_stimulus_refs(content)
68
+ refs = []
69
+ # data-controller="name" or data-controller="name1 name2"
70
+ content.scan(/data-controller=["']([^"']+)["']/).each do |m|
71
+ m[0].split.each { |c| refs << c }
72
+ end
73
+ # data: { controller: "name" }
74
+ content.scan(/controller:\s*["']([^"']+)["']/).each do |m|
75
+ m[0].split.each { |c| refs << c }
76
+ end
77
+ refs.uniq
78
+ end
79
+ end
80
+ end
81
+ end