rails-ai-context 2.0.2 → 2.0.3

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: 28fe01be28232f19cf9fab8cb6b696630e21d663e47b426a206e771b0096bfcb
4
- data.tar.gz: 488fdca01c018f6f9f468e7f03c78c2e6456e93dde0c7a89d17a5c554160b305
3
+ metadata.gz: 582aebf4849cdb8617b33dff88f3822009b8960e1334bbd1aa2eb6a3f6a03350
4
+ data.tar.gz: 03c8eedbf4989f07a75f878fe86380b809dd4ae1e2afd0020836a848da99b5c3
5
5
  SHA512:
6
- metadata.gz: bd0017a556c8a728b58ac5b18dc52682a825602e295be6a54f8bde15baf552d62247d57441af936d8762d00763aec076e46dc52d745274bf74362df5105bb0ec
7
- data.tar.gz: e16d3d1306ad9d4aa617a72e0311cbf1ffb8f2f5e80074913e3c1be62ceca2f8325642e3cf1515c6c14a930349b2f5a78a98f913d7c53f011bf3e1b6d7450eaa
6
+ metadata.gz: 5a2abfe4dc7c9c123dacd427354789810197c478fab741ac88e9aa0d8c95fcccc5cac2b5005f01615cf678f7229362d3e4ea5838d7c76d2210b28a8531edd9da
7
+ data.tar.gz: 3f04bb928f49325badb6a956a54c1adb9dec73ac2f73b9d7f81831f5da5931ac0ef1f4494a5c71780cdabcfa159c38ff11a4bd6f7fbcbb7ac79272aaf5de4e3b
data/CHANGELOG.md CHANGED
@@ -5,6 +5,13 @@ 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
+ ## [2.0.3] - 2026-03-25
9
+
10
+ ### Added
11
+
12
+ - **Trace mode 100%** — `match_type:"trace"` now shows 7 sections: definition with class/module context, source code, internal calls, sibling methods (same file), app callers with route chain hints, and test coverage (separated from app code). Zero follow-up calls needed.
13
+ - **README rewrite** — neuro marketing techniques: loss aversion hook, measured token savings table, trace output inline, architecture diagram. 456→261 lines.
14
+
8
15
  ## [2.0.2] - 2026-03-25
9
16
 
10
17
  ### Added
data/README.md CHANGED
@@ -1,273 +1,182 @@
1
1
  # rails-ai-context
2
2
 
3
- **Give AI agents a complete mental model of your Rails app — not just files, but how everything connects.**
3
+ ### Your AI is guessing. This gem makes it know.
4
4
 
5
5
  [![Gem Version](https://img.shields.io/gem/v/rails-ai-context?color=brightgreen)](https://rubygems.org/gems/rails-ai-context)
6
6
  [![MCP Registry](https://img.shields.io/badge/MCP_Registry-listed-green)](https://registry.modelcontextprotocol.io)
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
- > Built by a Rails developer with 10 years of production experience. Yes, AI helped write this gem — the same way AI helps me ship features at work. I designed the architecture, made every decision, reviewed every line, and wrote 520 tests. The gem exists because I understand Rails deeply enough to know what AI agents get wrong and what context they need to get it right.
10
+ **Works with:** Claude Code • Cursor • GitHub Copilot • Windsurf • OpenCode
11
11
 
12
- ---
13
-
14
- ## The Problem
15
-
16
- AI agents working on Rails apps operate blind. They read files one at a time but never see the full picture — how your schema connects to your models, which callbacks fire on save, what filters apply to a controller action, which Stimulus controllers exist, or what your UI conventions are.
17
-
18
- The result: **guess-and-check coding.** The agent writes code, it breaks, it reads more files, fixes it, breaks again. Each iteration wastes tokens and erodes trust.
19
-
20
- ## The Solution
21
-
22
- **rails-ai-context** gives your AI agent what a senior Rails developer has naturally: a structured mental model of the entire application.
12
+ > Built by a Rails developer with 10 years of production experience. Yes, AI helped write this gem — the same way AI helps me ship features at work. I designed the architecture, made every decision, reviewed every line, and wrote 575 tests. The gem exists because I understand Rails deeply enough to know what AI agents get wrong and what context they need to get it right.
23
13
 
24
14
  ```bash
25
- bundle add rails-ai-context
15
+ gem "rails-ai-context", group: :development
26
16
  rails generate rails_ai_context:install
27
- rails ai:context
28
17
  ```
29
18
 
30
- Three commands. Your AI now understands your schema, models, routes, controllers, views, jobs, gems, auth, Stimulus controllers, design patterns, and conventions — through the [Model Context Protocol (MCP)](https://modelcontextprotocol.io).
19
+ That's it. Your AI now has 25 live MCP tools that understand your entire Rails app. Zero config.
31
20
 
32
- The install generator creates `.mcp.json` for auto-discovery — Claude Code and Cursor detect it automatically.
21
+ ---
33
22
 
34
- > **[Full Guide](docs/GUIDE.md)** complete documentation with every command, parameter, and configuration option.
23
+ ## What AI gets wrong without this
35
24
 
36
- ---
25
+ Right now, your AI agent:
37
26
 
38
- ## What Changes
27
+ - **Reads all 2,000 lines of schema.rb** to find one column type
28
+ - **Misses encrypted columns** — doesn't know `gemini_api_key` is encrypted
29
+ - **Shows 25 Devise methods** as if they're your code
30
+ - **Doesn't see inherited filters** — misses `authenticate_user!` from ApplicationController
31
+ - **Uses underscores in Stimulus HTML** — `data-cook_status` instead of `data-cook-status`
32
+ - **Breaks Turbo Stream wiring** — broadcasts to channels nobody subscribes to
33
+ - **Permits wrong params** — doesn't cross-check against your schema
34
+ - **Guesses your UI patterns** — invents new button styles instead of matching yours
39
35
 
40
- ### Without rails-ai-context
36
+ **Every wrong guess = a wasted iteration.** You fix it, re-run, it breaks something else.
41
37
 
42
- The agent asks itself: *What columns does `users` have?* It reads all 2,000 lines of `schema.rb`. *What associations does `Cook` have?* It reads the model file but misses the concern that adds 12 methods. *What filters apply to `CooksController#create`?* It reads the controller but doesn't see the inherited `authenticate_user!` from the parent class. It writes code that references a nonexistent partial, permits a wrong param, and renders a Stimulus controller that doesn't exist.
38
+ ---
43
39
 
44
- **Every mistake is a wasted iteration.**
40
+ ## What AI knows with this
45
41
 
46
- ### With rails-ai-context
42
+ One call. Full picture.
47
43
 
48
44
  ```
49
- Agent: rails_get_schema(table:"users") → 25 lines: columns, types, NOT NULL, defaults, indexes, FKs
50
- Agent: rails_get_model_details(model:"Cook") → associations, validations, scopes, callbacks, concern methods
51
- Agent: rails_get_controllers(controller:"cooks", action:"create") → source code + applicable filters + strong params body
52
- Agent: rails_validate(files:["app/models/cook.rb"], level:"rails") → catches column/route/partial errors before execution
45
+ rails_search_code(pattern: "can_cook?", match_type: "trace")
53
46
  ```
54
47
 
55
- **Orient → drill down → act → verify.** The first attempt is correct.
56
-
57
- ---
58
-
59
- ## Three Layers of Context
60
-
61
- | Layer | What it provides | When it loads | Token cost |
62
- |-------|-----------------|---------------|------------|
63
- | **Static files** (CLAUDE.md, .cursorrules, etc.) | App overview: stack, models, gems, architecture, UI patterns, MCP tool reference | Automatically at session start | ~150 lines, zero tool calls |
64
- | **Split rules** (.claude/rules/, .cursor/rules/) | Deep reference: full schema with column types, all model associations/scopes, controller listings | Conditionally — only when editing relevant files | Zero when not needed |
65
- | **Live MCP tools** (25 tools) | Real-time queries: drill into any table, model, controller action, or view on demand. Semantic validation. Design system. Security scanning. | On-demand via agent tool calls | ~25-100 lines per call |
48
+ ```
49
+ # Trace: can_cook?
50
+
51
+ ## Definition
52
+ app/models/concerns/plan_limitable.rb:8
53
+ def can_cook?
54
+ p = effective_plan
55
+ return true if p.unlimited_cooks?
56
+ (cooks_this_month || 0) < p.cooks_per_month
57
+ end
58
+
59
+ ## Calls internally
60
+ - unlimited_cooks?
61
+
62
+ ## Called from (8 sites)
63
+ ### app/controllers/cooks_controller.rb (Controller)
64
+ 24: unless current_user.can_cook?
65
+ ### app/views/cooks/new.html.erb (View)
66
+ 7: <% unless current_user.can_cook? %>
67
+ ### test/models/concerns/plan_limitable_test.rb (Test)
68
+ 24: assert @user.can_cook?
69
+ 29: assert_not @user.can_cook?
70
+ ```
66
71
 
67
- **Progressive disclosure:** the agent gets the map for free, reference guides when relevant, and live GPS when building.
72
+ Definition + source code + every caller grouped by type + what it calls internally. **One tool call replaces 6 file reads.**
68
73
 
69
74
  ---
70
75
 
71
- ## Real Impact: 37% Fewer Tokens, 95% Fewer Errors
76
+ ## Measured token savings
72
77
 
73
- | Setup | Tokens | What it knows |
74
- |-------|--------|---------------|
75
- | **rails-ai-context (full)** | **28,834** | 25 MCP tools + generated docs + split rules |
76
- | rails-ai-context CLAUDE.md only | 33,106 | Generated docs + rules, no MCP tools |
77
- | Normal Claude `/init` | 40,700 | Generic CLAUDE.md only |
78
- | No rails-ai-context | 45,477 | Nothing — discovers everything from scratch |
78
+ Tested on a real Rails 8 app (5 models, 19 controllers, 95 routes):
79
79
 
80
- ```
81
- No rails-ai-context 45,477 tk █████████████████████████████████████████████
82
- Normal Claude /init 40,700 tk █████████████████████████████████████████ -11%
83
- rails-ai-context CLAUDE.md 33,106 tk █████████████████████████████████ -27%
84
- rails-ai-context (full) 28,834 tk █████████████████████████████ -37%
85
- ```
80
+ | Task | Without gem | With gem | Saved |
81
+ |------|-------------|----------|-------|
82
+ | Trace a method across the codebase | ~9,080 tokens (read 5 files) | ~198 tokens (1 MCP call) | **98%** |
83
+ | Understand a feature (schema + model + controller) | ~5,200 tokens (read 3 files) | ~1,500 tokens (2 MCP calls) | **71%** |
84
+ | Check all table columns | ~2,573 tokens (read schema.rb) | ~908 tokens (1 MCP call) | **65%** |
86
85
 
87
- https://github.com/user-attachments/assets/14476243-1210-4e62-9dc5-9d4aa9caef7e
86
+ "Without" = AI reads files it would realistically need. "With" = MCP tools return only what's relevant.
88
87
 
89
- > **Token savings scale with app size.** A 5-model app saves 37%. A 50-model app with auth + payments + mailers saves 60-80% because MCP tools return only what's needed instead of reading entire files.
88
+ > Savings scale with app size. A 50-model app reads more files per task — MCP calls stay the same size.
90
89
 
91
- But token savings is the side effect. The real value:
90
+ But tokens are the side effect. The real value:
92
91
 
93
- - **Fewer iterations** — the agent understands associations, callbacks, and constraints before writing code
94
- - **Cross-file accuracy** — semantic validation catches nonexistent partials, wrong column references, and missing routes in one call
95
- - **Convention awareness** — the agent matches your UI patterns, test framework, and architecture style
96
- - **No stale context** — live reload invalidates caches when files change mid-session
92
+ - **First attempt is correct** — AI understands associations, callbacks, and constraints before writing code
93
+ - **Cross-file validation** — catches wrong columns, missing partials, broken routes in one call
94
+ - **Matches your patterns** — your button classes, your test style, your flash messages
97
95
 
98
96
  ---
99
97
 
100
98
  ## 25 Live MCP Tools
101
99
 
102
- The gem exposes **25 read-only tools** via MCP that AI clients call on-demand:
103
-
104
- | Tool | What it returns |
105
- |------|----------------|
106
- | `rails_get_schema` | Tables, columns with `[indexed]`/`[unique]` hints, indexes, foreign keys |
107
- | `rails_get_model_details` | Associations with `dependent:`, validations, scopes, enums with backing type, callbacks |
108
- | `rails_get_routes` | HTTP verbs, paths with `[params]`, controller actions |
109
- | `rails_get_controllers` | Actions, filters, strong params, respond_to formats |
110
- | `rails_get_config` | Database adapter, auth framework, assets stack, cache, session, timezone, middleware |
111
- | `rails_get_test_info` | Test framework, factory attributes/traits, fixtures, CI config, coverage |
112
- | `rails_get_gems` | Notable gems categorized by function with config location hints |
113
- | `rails_get_conventions` | Architecture patterns, frontend stack, directory structure |
114
- | `rails_search_code` | Ripgrep search with `match_type:"trace"` (definition + callers + internal calls in one shot), `"definition"`, `"call"`, `"class"` filters, smart result limiting, pagination |
115
- | `rails_get_view` | View templates, partials with render locals, Stimulus references |
116
- | `rails_get_stimulus` | Stimulus controllers targets, values, actions, outlets, lifecycle methods |
117
- | `rails_get_edit_context` | Surgical edit helper returns code with class/method context and line numbers |
118
- | `rails_validate` | Syntax + semantic validation with fix suggestions (migrations, dependent options, index commands) |
119
- | `rails_analyze_feature` | Full-stack feature analysis models, controllers, routes, services, jobs, views, Stimulus, tests, test coverage gaps |
120
- | `rails_get_design_system` | App design systemcolor palette, component patterns with real HTML examples, typography, layout, responsive breakpoints |
121
- | `rails_security_scan` | Brakeman static security analysis — SQL injection, XSS, mass assignment. Filter by file, confidence level, specific checks |
122
- | `rails_get_concern` | Concern public methods, signatures, which models/controllers include it |
123
- | `rails_get_callbacks` | Model callbacks in Rails execution order with source code |
124
- | `rails_get_helper_methods` | Application + framework helper methods with view usage cross-references |
125
- | `rails_get_service_pattern` | Service objects — interface, dependencies, side effects, error handling, calling convention |
126
- | `rails_get_job_pattern` | Background jobs — queue, retries, guard clauses, service calls, Turbo broadcasts, schedules |
100
+ Every tool is **read-only** and returns structured, token-efficient data. Start with `detail:"summary"`, drill into specifics.
101
+
102
+ | Tool | One-liner |
103
+ |------|-----------|
104
+ | `rails_search_code` | **Trace mode**: definition + class context + source + internal calls + sibling methods + callers with route chain + test coverage. Also: `"definition"`, `"call"`, `"class"` filters, smart pagination |
105
+ | `rails_get_context` | **Composite**: schema + model + controller + routes + views in one call |
106
+ | `rails_analyze_feature` | **Full-stack**: everything about a feature — models, controllers, routes, services, jobs, views, Stimulus, tests |
107
+ | `rails_validate` | **Syntax + semantic + security** in one call. Catches wrong columns, missing partials, broken routes, Brakeman vulnerabilities |
108
+ | `rails_get_controllers` | Action source code + inherited filters + render map + side effects + private methods inline |
109
+ | `rails_get_schema` | Columns with `[indexed]`, `[unique]`, `[encrypted]`, `[default: value]` hints + model name inline |
110
+ | `rails_get_model_details` | Associations, validations, scopes with lambda body, enum backing types, macros, delegations, constants |
111
+ | `rails_get_routes` | Code-ready helpers (`cook_path(@record)`), controller filters inline, required params |
112
+ | `rails_get_view` | Templates with ivars, Turbo wiring, Stimulus refs, partial locals pipe-separated, scannable |
113
+ | `rails_get_stimulus` | Copy-paste HTML data-attributes (dashes, not underscores) + reverse view lookup |
114
+ | `rails_get_design_system` | Canonical HTML/ERB copy-paste patterns for buttons, inputs, cards, modals |
115
+ | `rails_get_test_info` | Fixture contents with relationships + test template matching your app's patterns |
116
+ | `rails_get_conventions` | Your app's actual patterns auth checks, flash messages, create action template, test patterns |
117
+ | `rails_get_turbo_map` | Broadcast subscription wiring with mismatch warnings |
118
+ | `rails_get_partial_interface` | Partial locals contractwhat to pass, what methods are called on each local |
119
+ | `rails_get_concern` | Public methods, signatures, which models include it |
120
+ | `rails_get_callbacks` | Callbacks in Rails execution order with source code |
121
+ | `rails_get_service_pattern` | Interface, dependencies, side effects, error handling, who calls it |
122
+ | `rails_get_job_pattern` | Queue, retries, guard clauses, Turbo broadcasts, schedules |
127
123
  | `rails_get_env` | Environment variables, credentials keys (not values), external service dependencies |
128
- | `rails_get_partial_interface` | Partial locals contract required variables, method calls on each, usage examples |
129
- | `rails_get_turbo_map` | Turbo Streams/Frames wiring — broadcasts, subscriptions, channel matching, mismatch warnings |
130
- | `rails_get_context` | Composite tool assembles schema + model + controller + routes + views in one call |
124
+ | `rails_get_helper_methods` | App + framework helpers with view usage cross-references |
125
+ | `rails_get_config` | Database adapter, auth framework, assets stack, Action Cable, middleware |
126
+ | `rails_get_gems` | Notable gems with versions, categories, and config file locations |
127
+ | `rails_get_edit_context` | Method-aware code extraction with class/method context header |
128
+ | `rails_security_scan` | Brakeman static analysis — SQL injection, XSS, mass assignment |
131
129
 
132
- ### Smart Detail Levels
133
-
134
- Schema, routes, models, and controllers tools support a `detail` parameter — critical for large apps:
135
-
136
- | Level | Returns | Default limit |
137
- |-------|---------|---------------|
138
- | `summary` | Names + counts | 50 |
139
- | `standard` | Names + key details *(default)* | 25 |
140
- | `full` | Everything (indexes, FKs, constraints) | 10 |
141
-
142
- ```ruby
143
- rails_get_schema(detail: "summary") # → all tables with column counts
144
- rails_get_schema(table: "users") # → full detail for one table
145
- rails_get_routes(controller: "users") # → routes for one controller
146
- rails_get_model_details(model: "User") # → associations, validations, scopes
147
- ```
148
-
149
- A safety net (`max_tool_response_chars`, default 200K) truncates oversized responses with hints to use filters.
130
+ > **[Full parameter documentation →](docs/GUIDE.md)**
150
131
 
151
132
  ---
152
133
 
153
- ## What Gets Generated
154
-
155
- `rails ai:context` generates context files tailored to each AI assistant:
134
+ ## How It Works
156
135
 
157
136
  ```
158
- your-rails-app/
159
-
160
- ├── 🟣 Claude Code
161
- │ ├── CLAUDE.md ≤150 lines (compact)
162
- └── .claude/rules/
163
- │ ├── rails-context.md app overview
164
- │ ├── rails-schema.md table listing + column types
165
- ├── rails-models.md model listing
166
- ├── rails-ui-patterns.md CSS/Tailwind component patterns
167
- │ └── rails-mcp-tools.md full tool reference
168
-
169
- ├── 🟢 Cursor
170
- │ └── .cursor/rules/
171
- ├── rails-project.mdc alwaysApply: true
172
- ├── rails-models.mdc globs: app/models/**
173
- ├── rails-controllers.mdc globs: app/controllers/**
174
- ├── rails-ui-patterns.mdc globs: app/views/**
175
- └── rails-mcp-tools.mdc alwaysApply: true
176
-
177
- ├── ⚡ OpenCode
178
- │ ├── AGENTS.md native OpenCode context
179
- │ ├── app/models/AGENTS.md auto-loaded when editing models
180
- │ └── app/controllers/AGENTS.md auto-loaded when editing controllers
181
-
182
- ├── 🔵 Windsurf
183
- │ ├── .windsurfrules ≤5,800 chars (6K limit)
184
- │ └── .windsurf/rules/
185
- │ ├── rails-context.md project overview
186
- │ ├── rails-ui-patterns.md CSS component patterns
187
- │ └── rails-mcp-tools.md tool reference
188
-
189
- ├── 🟠 GitHub Copilot
190
- │ ├── .github/copilot-instructions.md ≤500 lines (compact)
191
- │ └── .github/instructions/
192
- │ ├── rails-context.instructions.md applyTo: **/*
193
- │ ├── rails-models.instructions.md applyTo: app/models/**
194
- │ ├── rails-controllers.instructions.md applyTo: app/controllers/**
195
- │ ├── rails-ui-patterns.instructions.md applyTo: app/views/**
196
- │ └── rails-mcp-tools.instructions.md applyTo: **/*
197
-
198
- ├── 📋 .ai-context.json full JSON (programmatic)
199
- └── .mcp.json MCP auto-discovery
137
+ ┌─────────────────────────────────────────────────────────┐
138
+ Your Rails App │
139
+ │ models + schema + routes + controllers + views + jobs │
140
+ └────────────────────────┬────────────────────────────────┘
141
+ introspects
142
+
143
+ ┌─────────────────────────────────────────────────────────┐
144
+ rails-ai-context (29 introspectors) │
145
+ Parses everything. Caches results. Zero config. │
146
+ └────────┬─────────────────────────────┬──────────────────┘
147
+
148
+ ▼ ▼
149
+ ┌────────────────────┐ ┌───────────────────────────────┐
150
+ Static Files │ │ Live MCP Server (25 tools) │
151
+ CLAUDE.md │ │ Real-time queries on demand │
152
+ .cursor/rules/ │ │ Schema, models, routes, etc.
153
+ .github/instr... │ │ Trace, validate, analyze │
154
+ .windsurfrules │ │ Auto-discovered via .mcp.json
155
+ └────────────────────┘ └───────────────────────────────┘
200
156
  ```
201
157
 
202
- 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.
203
-
204
- ---
205
-
206
- ## What Your AI Learns
207
-
208
- | Category | What's introspected |
209
- |----------|-------------------|
210
- | **Database** | Every table, column, index, foreign key, and migration |
211
- | **Models** | Associations, validations, scopes, enums, callbacks, concerns, macros |
212
- | **Routing** | Every route with HTTP verbs, paths, controller actions, API namespaces |
213
- | **Controllers** | Actions, filters, strong params, concerns, API controllers |
214
- | **Views** | Layouts, templates, partials, helpers, template engines, view components |
215
- | **Frontend** | Stimulus controllers (targets, values, actions, outlets), Turbo Frames/Streams |
216
- | **Background** | ActiveJob classes, mailers, Action Cable channels |
217
- | **Gems** | 70+ notable gems categorized (Devise = auth, Sidekiq = jobs, Pundit = authorization) |
218
- | **Auth** | Devise modules, Pundit policies, CanCanCan, has_secure_password, CORS, CSP |
219
- | **API** | Serializers, GraphQL, versioning, rate limiting, API-only mode |
220
- | **Testing** | Framework, factories/fixtures, CI config, coverage, system tests |
221
- | **Config** | Cache store, session store, middleware, initializers, timezone |
222
- | **DevOps** | Puma, Procfile, Docker, deployment tools, asset pipeline |
223
- | **Architecture** | Service objects, STI, polymorphism, state machines, multi-tenancy, engines |
224
-
225
- 29 introspectors total. The `:full` preset runs 28 by default; use `:standard` for 13 core only (`database_stats` is opt-in, PostgreSQL only).
158
+ The install generator asks which AI tools you use and only generates files for those.
226
159
 
227
160
  ---
228
161
 
229
- ## MCP Server Setup
230
-
231
- The install generator creates `.mcp.json` — **Claude Code and Cursor auto-detect it**. No manual config needed.
162
+ ## Install
232
163
 
233
- This server is also listed on the [official MCP Registry](https://registry.modelcontextprotocol.io) as `io.github.crisnahine/rails-ai-context`.
164
+ ```bash
165
+ # Add to Gemfile
166
+ gem "rails-ai-context", group: :development
234
167
 
235
- To start manually: `rails ai:serve`
168
+ # Install (picks your AI tools, generates context)
169
+ rails generate rails_ai_context:install
236
170
 
237
- <details>
238
- <summary><strong>Claude Desktop setup</strong></summary>
239
-
240
- Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS):
241
-
242
- ```json
243
- {
244
- "mcpServers": {
245
- "rails-ai-context": {
246
- "command": "bundle",
247
- "args": ["exec", "rails", "ai:serve"],
248
- "cwd": "/path/to/your/rails/app"
249
- }
250
- }
251
- }
171
+ # Or generate context directly
172
+ rails ai:context
252
173
  ```
253
- </details>
254
-
255
- <details>
256
- <summary><strong>HTTP transport (for remote clients)</strong></summary>
257
174
 
258
- ```bash
259
- rails ai:serve_http # Starts at http://127.0.0.1:6029/mcp
260
- ```
175
+ Both commands ask which AI tools you use (Claude, Cursor, Copilot, Windsurf, OpenCode) and only generate what you need.
261
176
 
262
- Or auto-mount inside your Rails app:
177
+ MCP auto-discovery: `.mcp.json` is detected automatically by Claude Code and Cursor. No manual config.
263
178
 
264
- ```ruby
265
- RailsAiContext.configure do |config|
266
- config.auto_mount = true
267
- config.http_path = "/mcp"
268
- end
269
- ```
270
- </details>
179
+ > **[Full Guide →](docs/GUIDE.md)** — every command, parameter, and configuration option.
271
180
 
272
181
  ---
273
182
 
@@ -276,31 +185,17 @@ end
276
185
  ```ruby
277
186
  # config/initializers/rails_ai_context.rb
278
187
  RailsAiContext.configure do |config|
279
- # Presets: :full (28 introspectors, default) or :standard (13 core)
280
- config.preset = :full
281
-
282
- # Cherry-pick on top of a preset
283
- # config.introspectors += %i[views turbo auth api]
188
+ # Which AI tools to generate context for (selected during install)
189
+ # config.ai_tools = %i[claude cursor]
284
190
 
285
- # Context mode: :compact (≤150 lines, default) or :full (dump everything)
286
- # config.context_mode = :compact
191
+ # Presets: :full (28 introspectors, default) or :standard (13 core)
192
+ # config.preset = :full
287
193
 
288
194
  # Exclude models from introspection
289
- config.excluded_models += %w[AdminUser InternalAuditLog]
290
-
291
- # Exclude paths from code search
292
- config.excluded_paths += %w[vendor/bundle]
293
-
294
- # Cache TTL for MCP tool responses (seconds)
295
- config.cache_ttl = 60
195
+ # config.excluded_models += %w[AdminUser]
296
196
 
297
- # Live reload: auto-invalidate MCP caches on file changes
298
- # :auto (default), true, or false
299
- # config.live_reload = :auto
300
-
301
- # Skip root files (CLAUDE.md, .windsurfrules, etc.) — only generate split rules
302
- # Lets you manage root files yourself while still getting .claude/rules/, .cursor/rules/, etc.
303
- # config.generate_root_files = false
197
+ # Skip specific MCP tools
198
+ # config.skip_tools = %w[rails_security_scan]
304
199
  end
305
200
  ```
306
201
 
@@ -316,122 +211,39 @@ end
316
211
  | `context_mode` | `:compact` | `:compact` (≤150 lines) or `:full` (dump everything) |
317
212
  | `claude_max_lines` | `150` | Max lines for CLAUDE.md in compact mode |
318
213
  | `generate_root_files` | `true` | Generate root files (CLAUDE.md, etc.) — set `false` for split rules only |
319
- | `output_dir` | `Rails.root` | Output directory for generated context files |
214
+ | `ai_tools` | `nil` (all) | AI tools to generate context for: `%i[claude cursor copilot windsurf opencode]` |
320
215
  | **MCP Server** | | |
321
- | `server_name` | `"rails-ai-context"` | MCP server name |
322
- | `server_version` | gem version | MCP server version |
323
- | `auto_mount` | `false` | Auto-mount HTTP MCP endpoint |
324
- | `http_path` | `"/mcp"` | HTTP endpoint path |
325
- | `http_port` | `6029` | HTTP server port |
326
- | `http_bind` | `"127.0.0.1"` | HTTP server bind address |
327
216
  | `cache_ttl` | `60` | Cache TTL in seconds |
328
217
  | `max_tool_response_chars` | `200_000` | Safety cap for MCP tool responses |
329
218
  | `live_reload` | `:auto` | `:auto`, `true`, or `false` — MCP live reload |
330
- | `live_reload_debounce` | `1.5` | Debounce interval in seconds |
331
- | **Filtering & Exclusions** | | |
332
- | `excluded_models` | internal Rails models | Models to skip during introspection |
333
- | `excluded_paths` | `node_modules tmp log vendor .git` | Paths excluded from code search |
334
- | `sensitive_patterns` | `.env .env.* config/master.key config/credentials.yml.enc config/credentials/*.yml.enc *.pem *.key` | File patterns blocked from search and read tools |
335
- | `excluded_controllers` | `DeviseController` etc. | Controller classes hidden from listings |
336
- | `excluded_route_prefixes` | `action_mailbox/ active_storage/ rails/` etc. | Route controller prefixes hidden with app_only |
337
- | `excluded_concerns` | Rails/Devise/framework patterns | Regex patterns for concerns to hide |
338
- | `excluded_filters` | `verify_authenticity_token` etc. | Framework filter names hidden from controller output |
339
- | `excluded_middleware` | standard Rack/Rails middleware | Default middleware hidden from config output |
219
+ | `auto_mount` | `false` | Auto-mount HTTP MCP endpoint |
340
220
  | **File Size Limits** | | |
341
- | `max_file_size` | `5_000_000` | Per-file read limit for tools (bytes) |
342
- | `max_test_file_size` | `1_000_000` | Test file read limit (bytes) |
343
- | `max_schema_file_size` | `10_000_000` | schema.rb / structure.sql parse limit (bytes) |
344
- | `max_view_total_size` | `10_000_000` | Total aggregated view content for UI patterns (bytes) |
345
- | `max_view_file_size` | `1_000_000` | Per-view file during aggregation (bytes) |
221
+ | `max_file_size` | `5_000_000` | Per-file read limit (bytes) |
346
222
  | `max_search_results` | `200` | Max search results per call |
347
223
  | `max_validate_files` | `50` | Max files per validate call |
348
- | **Search & Discovery** | | |
349
- | `search_extensions` | `rb js erb yml yaml json ts tsx vue svelte haml slim` | File extensions for Ruby fallback search |
350
- | `concern_paths` | `app/models/concerns app/controllers/concerns` | Where to look for concern source files |
351
224
  | **Extensibility** | | |
352
- | `custom_tools` | `[]` | Additional MCP tool classes to register alongside built-in tools |
353
- | `skip_tools` | `[]` | Built-in tool names to exclude (e.g. `%w[rails_security_scan]`) |
354
- | `ai_tools` | `nil` (all) | AI tools to generate context for: `%i[claude cursor copilot windsurf opencode]` |
225
+ | `custom_tools` | `[]` | Additional MCP tool classes |
226
+ | `skip_tools` | `[]` | Built-in tool names to exclude |
355
227
  </details>
356
228
 
357
229
  ---
358
230
 
359
231
  ## Commands
360
232
 
361
- ### Rake tasks (recommended)
362
-
363
- | Command | Description |
233
+ | Command | What it does |
364
234
  |---------|-------------|
365
- | `rails ai:context` | Generate all context files (skips unchanged) |
366
- | `rails ai:context:full` | Generate all files in full mode (dumps everything) |
367
- | `rails ai:context:claude` | Generate Claude Code files only |
368
- | `rails ai:context:opencode` | Generate OpenCode files only |
369
- | `rails ai:context:cursor` | Generate Cursor files only |
370
- | `rails ai:context:windsurf` | Generate Windsurf files only |
371
- | `rails ai:context:copilot` | Generate Copilot files only |
372
- | `rails ai:context:json` | Generate JSON context file only |
235
+ | `rails ai:context` | Generate context files for your AI tools |
373
236
  | `rails ai:serve` | Start MCP server (stdio) |
374
- | `rails ai:serve_http` | Start MCP server (HTTP) |
375
- | `rails ai:doctor` | Run diagnostics and AI readiness score (0-100) |
376
- | `rails ai:watch` | Auto-regenerate context files on code changes |
377
- | `rails ai:inspect` | Print introspection summary to stdout |
378
-
379
- ### Standalone CLI
380
-
381
- The gem also ships a `rails-ai-context` executable — an alternative to rake tasks.
382
-
383
- | Command | Equivalent rake task |
384
- |---------|---------------------|
385
- | `rails-ai-context serve` | `rails ai:serve` |
386
- | `rails-ai-context serve --transport http` | `rails ai:serve_http` |
387
- | `rails-ai-context context` | `rails ai:context` |
388
- | `rails-ai-context context --format claude` | `rails ai:context:claude` |
389
- | `rails-ai-context doctor` | `rails ai:doctor` |
390
- | `rails-ai-context watch` | `rails ai:watch` |
391
- | `rails-ai-context inspect` | `rails ai:inspect` |
392
- | `rails-ai-context version` | — |
393
-
394
- Run from your Rails app root. Use `rails-ai-context help` for all options.
395
-
396
- ---
397
-
398
- ## Stack Compatibility
399
-
400
- Works with every Rails architecture — auto-detects what's relevant:
401
-
402
- | Setup | Coverage | Notes |
403
- |-------|----------|-------|
404
- | Rails full-stack (ERB + Hotwire) | 29/29 | All introspectors relevant |
405
- | Rails + Inertia.js (React/Vue) | ~22/29 | Views/Turbo partially useful, backend fully covered |
406
- | Rails API + React/Next.js SPA | ~20/29 | Schema, models, routes, API, auth, jobs — all covered |
407
- | Rails API + mobile app | ~20/29 | Same as SPA — backend introspection is identical |
408
- | Rails engine (mountable gem) | ~15/29 | Core introspectors (schema, models, routes, gems) work |
409
-
410
- Frontend introspectors (views, Turbo, Stimulus, assets) degrade gracefully — they report nothing when those features aren't present.
411
-
412
- ---
413
-
414
- ## Works Without a Database
415
-
416
- 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.
237
+ | `rails ai:doctor` | Diagnostics + AI readiness score |
238
+ | `rails ai:watch` | Auto-regenerate on file changes |
239
+ | `rails ai:inspect` | Print introspection summary |
417
240
 
418
241
  ---
419
242
 
420
243
  ## Requirements
421
244
 
422
245
  - Ruby >= 3.2, Rails >= 7.1
423
- - [mcp](https://github.com/modelcontextprotocol/ruby-sdk) gem (installed automatically)
424
- - Optional: `listen` gem for watch mode, `ripgrep` for fast code search
425
-
426
- ---
427
-
428
- ## vs. Other Ruby MCP Projects
429
-
430
- | Project | Approach | rails-ai-context |
431
- |---------|----------|-----------------|
432
- | [Official Ruby SDK](https://github.com/modelcontextprotocol/ruby-sdk) | Low-level protocol library | We **use** this as our foundation |
433
- | [fast-mcp](https://github.com/yjacquin/fast-mcp) | Generic MCP framework | We're a **product** — zero-config Rails introspection |
434
- | [rails-mcp-server](https://github.com/maquina-app/rails-mcp-server) | Manual config (`projects.yml`) | We auto-discover everything |
246
+ - Optional: `brakeman` for security scanning, `listen` for watch mode, `ripgrep` for fast search
435
247
 
436
248
  ---
437
249
 
@@ -440,7 +252,7 @@ The gem parses `db/schema.rb` as text when no database is connected. Works in CI
440
252
  ```bash
441
253
  git clone https://github.com/crisnahine/rails-ai-context.git
442
254
  cd rails-ai-context && bundle install
443
- bundle exec rspec # 520 examples
255
+ bundle exec rspec # 575 examples
444
256
  bundle exec rubocop # Lint
445
257
  ```
446
258
 
@@ -448,7 +260,7 @@ Bug reports and pull requests welcome at [github.com/crisnahine/rails-ai-context
448
260
 
449
261
  ## Sponsorship
450
262
 
451
- If rails-ai-context helps your workflow, consider [becoming a sponsor](https://github.com/sponsors/crisnahine).
263
+ If rails-ai-context saves you time, consider [becoming a sponsor](https://github.com/sponsors/crisnahine).
452
264
 
453
265
  ## License
454
266
 
data/docs/GUIDE.md CHANGED
@@ -564,7 +564,7 @@ Ripgrep-powered regex search across the codebase.
564
564
  | `pattern` | string | **Required.** Regex pattern or method name to search for. |
565
565
  | `path` | string | Subdirectory to search in (e.g. `app/models`, `config`). Default: entire app. |
566
566
  | `file_type` | string | Filter by file extension (e.g. `rb`, `erb`, `js`). Alphanumeric only. |
567
- | `match_type` | string | `any` (default), `definition` (def lines), `class` (class/module lines), `call` (call sites only), `trace` (**full picture** — definition + source + callers + internal calls). |
567
+ | `match_type` | string | `any` (default), `definition` (def lines), `class` (class/module lines), `call` (call sites only), `trace` (**full picture** — definition with class context + source code + internal calls + sibling methods + callers with route chain + test coverage separated). |
568
568
  | `exact_match` | boolean | Match whole words only (wraps pattern in `\b` boundaries). Default: false. |
569
569
  | `exclude_tests` | boolean | Exclude test/spec/features directories. Default: false. |
570
570
  | `group_by_file` | boolean | Group results by file with match counts. Default: false. |
@@ -577,7 +577,8 @@ Smart result limiting: <10 results shows all, 10-100 shows half, >100 caps at 10
577
577
 
578
578
  ```
579
579
  rails_search_code(pattern: "can_cook?", match_type: "trace")
580
- → FULL PICTURE: definition + source code + all callers grouped by type + internal calls
580
+ → FULL PICTURE: definition with class context + source code + internal calls
581
+ + sibling methods + app callers with route chain + test coverage (separated)
581
582
 
582
583
  rails_search_code(pattern: "create", match_type: "definition")
583
584
  → Only `def create` / `def self.create` lines
@@ -306,15 +306,18 @@ module RailsAiContext
306
306
  if def_results.any?
307
307
  lines << "## Definition"
308
308
  def_results.each do |r|
309
- lines << "**#{r[:file]}:#{r[:line_number]}**"
310
- # Extract the full method body
309
+ # Class/module context
310
+ class_context = extract_class_context(File.join(root, r[:file]), r[:line_number])
311
+ lines << "**#{r[:file]}:#{r[:line_number]}**#{class_context ? " in `#{class_context}`" : ""}"
312
+
313
+ # Full method body
311
314
  body = extract_method_body(File.join(root, r[:file]), r[:line_number])
312
315
  if body
313
316
  lines << "```ruby"
314
317
  lines << body
315
318
  lines << "```"
316
319
 
317
- # 3. What does this method call? (extract method-like calls from body)
320
+ # What does this method call?
318
321
  internal_calls = body.scan(/\b([a-z_]\w*[!?]?)(?:\s*[\(])/).flatten.uniq
319
322
  internal_calls += body.scan(/\b([A-Z]\w+(?:::\w+)*)\.(new|call|perform_later|perform_async|find|where|create)/).map { |c| "#{c[0]}.#{c[1]}" }
320
323
  internal_calls.reject! { |c| %w[if else elsif unless return end def class module do begin rescue ensure raise puts print].include?(c) }
@@ -325,6 +328,14 @@ module RailsAiContext
325
328
  internal_calls.first(15).each { |c| lines << "- `#{c}`" }
326
329
  end
327
330
  end
331
+
332
+ # Sibling methods in the same file
333
+ siblings = extract_sibling_methods(File.join(root, r[:file]), r[:line_number], cleaned)
334
+ if siblings.any?
335
+ lines << "" << "## Sibling methods (same file)"
336
+ siblings.first(10).each { |s| lines << "- `#{s}`" }
337
+ end
338
+
328
339
  lines << ""
329
340
  end
330
341
  else
@@ -346,28 +357,46 @@ module RailsAiContext
346
357
  callers.reject! { |r| def_locations.include?("#{r[:file]}:#{r[:line_number]}") }
347
358
 
348
359
  if callers.any?
349
- lines << "## Called from (#{callers.size} sites)"
350
-
351
- # Group by file for readability
352
- grouped = callers.group_by { |r| r[:file] }
353
- grouped.each do |file, matches|
354
- # Categorize the file
355
- category = case file
356
- when /controller/i then "Controller"
357
- when /model/i then "Model"
358
- when /view|\.erb/i then "View"
359
- when /job/i then "Job"
360
- when /service/i then "Service"
361
- when /test|spec/i then "Test"
362
- when /\.js$|\.ts$/i then "JavaScript"
363
- else "Other"
360
+ # Separate app code from tests
361
+ app_callers = callers.reject { |r| r[:file].match?(/\A(test|spec)\//) }
362
+ test_callers = callers.select { |r| r[:file].match?(/\A(test|spec)\//) }
363
+
364
+ if app_callers.any?
365
+ lines << "## Called from (#{app_callers.size} sites)"
366
+ grouped = app_callers.group_by { |r| r[:file] }
367
+ grouped.each do |file, matches|
368
+ category = case file
369
+ when /controller/i then "Controller"
370
+ when /model/i then "Model"
371
+ when /view|\.erb/i then "View"
372
+ when /job/i then "Job"
373
+ when /service/i then "Service"
374
+ when /\.js$|\.ts$/i then "JavaScript"
375
+ else "Other"
376
+ end
377
+
378
+ # Route chain for controller callers
379
+ route_hint = ""
380
+ if category == "Controller" && file.match?(/app\/controllers\/(.+)_controller\.rb/)
381
+ ctrl_path = $1
382
+ route_actions = extract_controller_actions_from_matches(matches)
383
+ routes = find_routes_for_controller(ctrl_path, route_actions, root)
384
+ route_hint = " → #{routes}" if routes
385
+ end
386
+
387
+ lines << "### #{file} (#{category})#{route_hint}"
388
+ matches.first(5).each do |r|
389
+ lines << " #{r[:line_number]}: #{r[:content].strip}"
390
+ end
391
+ lines << " _(#{matches.size - 5} more)_" if matches.size > 5
364
392
  end
393
+ end
365
394
 
366
- lines << "### #{file} (#{category})"
367
- matches.first(5).each do |r|
368
- lines << " #{r[:line_number]}: #{r[:content].strip}"
395
+ if test_callers.any?
396
+ lines << "" << "## Tested by (#{test_callers.size} references)"
397
+ test_callers.group_by { |r| r[:file] }.each do |file, matches|
398
+ lines << "- `#{file}` (#{matches.size} references)"
369
399
  end
370
- lines << " _(#{matches.size - 5} more)_" if matches.size > 5
371
400
  end
372
401
  else
373
402
  lines << "## Called from"
@@ -388,6 +417,64 @@ module RailsAiContext
388
417
  end
389
418
  end
390
419
 
420
+ # Extract class/module context for a line
421
+ private_class_method def self.extract_class_context(file_path, line_num)
422
+ return nil unless File.exist?(file_path)
423
+ lines = File.readlines(file_path)
424
+ # Walk backwards from the method to find the enclosing class/module
425
+ (line_num - 2).downto(0) do |i|
426
+ if lines[i]&.match?(/\A\s*(class|module)\s+(\S+)/)
427
+ return lines[i].strip.sub(/\s*<.*/, "")
428
+ end
429
+ end
430
+ nil
431
+ rescue
432
+ nil
433
+ end
434
+
435
+ # Extract sibling methods in the same file (other public methods)
436
+ private_class_method def self.extract_sibling_methods(file_path, def_line, exclude_method)
437
+ return [] unless File.exist?(file_path)
438
+ return [] if File.size(file_path) > RailsAiContext.configuration.max_file_size
439
+ source = File.read(file_path, encoding: "UTF-8", invalid: :replace, undef: :replace)
440
+ methods = []
441
+ in_private = false
442
+ source.each_line do |line|
443
+ in_private = true if line.match?(/\A\s*private\s*$/)
444
+ next if in_private
445
+ if (m = line.match(/\A\s*def\s+((?:self\.)?\w+[?!]?)/))
446
+ name = m[1]
447
+ methods << name unless name == exclude_method || name.start_with?("initialize")
448
+ end
449
+ end
450
+ methods
451
+ rescue
452
+ []
453
+ end
454
+
455
+ # Extract which action a controller caller is in
456
+ private_class_method def self.extract_controller_actions_from_matches(matches)
457
+ actions = []
458
+ matches.each do |m|
459
+ # Look for the method name from indentation context
460
+ actions << $1 if m[:content].match?(/\b(create|index|show|new|edit|update|destroy|[a-z_]+)\b/)
461
+ end
462
+ actions.uniq.first(3)
463
+ end
464
+
465
+ # Find routes for a controller
466
+ private_class_method def self.find_routes_for_controller(ctrl_path, _actions, _root)
467
+ routes = cached_context[:routes]
468
+ return nil unless routes
469
+ by_controller = routes[:by_controller] || {}
470
+ ctrl_routes = by_controller[ctrl_path]
471
+ return nil unless ctrl_routes&.any?
472
+ # Show the first 2 routes as hints
473
+ ctrl_routes.first(2).map { |r| "`#{r[:verb]} #{r[:path]}`" }.join(", ")
474
+ rescue
475
+ nil
476
+ end
477
+
391
478
  # Extract a method body from a file given the def line number
392
479
  private_class_method def self.extract_method_body(file_path, def_line)
393
480
  return nil unless File.exist?(file_path)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsAiContext
4
- VERSION = "2.0.2"
4
+ VERSION = "2.0.3"
5
5
  end
data/server.json CHANGED
@@ -7,11 +7,11 @@
7
7
  "url": "https://github.com/crisnahine/rails-ai-context",
8
8
  "source": "github"
9
9
  },
10
- "version": "2.0.2",
10
+ "version": "2.0.3",
11
11
  "packages": [
12
12
  {
13
13
  "registryType": "mcpb",
14
- "identifier": "https://github.com/crisnahine/rails-ai-context/releases/download/v2.0.2/rails-ai-context-mcp.mcpb",
14
+ "identifier": "https://github.com/crisnahine/rails-ai-context/releases/download/v2.0.3/rails-ai-context-mcp.mcpb",
15
15
  "fileSha256": "dd711a0ad6c4de943ae4da94eaf59a6dc9494b9d57f726e24649ed4e2f156990",
16
16
  "transport": {
17
17
  "type": "stdio"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-ai-context
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - crisnahine