rails-ai-context 2.0.0 → 2.0.2

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: 34ef5e454a22f9719cf4439c70867a4e2f9dc900d34e1cca0f4ecd723e3a3308
4
- data.tar.gz: d7545c9afd73831f0f32e0808f82856e1cf48c3763308049f5ba54d453f3f452
3
+ metadata.gz: 28fe01be28232f19cf9fab8cb6b696630e21d663e47b426a206e771b0096bfcb
4
+ data.tar.gz: 488fdca01c018f6f9f468e7f03c78c2e6456e93dde0c7a89d17a5c554160b305
5
5
  SHA512:
6
- metadata.gz: f29724289bcf91b5aeb776cfac4eec673a8bb8b02016108bab7a52f9f6f52b4fe5f3045cee43053a4b6e660619800dc8ea6f0141ed5bdd812d00898d00f9d7ef
7
- data.tar.gz: 3178d4a6347de30aaf92e13b5db4d976fe6d2c0888de60b451bc187e9ae71518186c204c97f74e37d159431c2ea149d9fc19db00ab338bce44ffda6c33ef6da3
6
+ metadata.gz: bd0017a556c8a728b58ac5b18dc52682a825602e295be6a54f8bde15baf552d62247d57441af936d8762d00763aec076e46dc52d745274bf74362df5105bb0ec
7
+ data.tar.gz: e16d3d1306ad9d4aa617a72e0311cbf1ffb8f2f5e80074913e3c1be62ceca2f8325642e3cf1515c6c14a930349b2f5a78a98f913d7c53f011bf3e1b6d7450eaa
data/CHANGELOG.md CHANGED
@@ -5,6 +5,35 @@ 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.2] - 2026-03-25
9
+
10
+ ### Added
11
+
12
+ - **`match_type:"trace"` in search_code** — full method picture in one call: definition + source code + all callers grouped by type (Controller/Model/View/Job/Service/Test) + internal calls. The game changer for code navigation.
13
+ - **`match_type:"call"`** — find call sites only, excluding definitions.
14
+ - **Smart result limiting** — <10 shows all, 10-100 shows half, >100 caps at 100. Pagination via `offset:` param.
15
+ - **`exclude_tests:true`** — skip test/spec/features directories in search results.
16
+ - **`group_by_file:true`** — group search results by file with match counts.
17
+ - **Inline cross-references** — schema shows model name + association count per table, routes show controller filters inline, views use pipe-separated metadata.
18
+ - **Test template generation** — `get_test_info(detail:"standard")` includes a copy-paste test template matching the app's patterns (Minitest/RSpec, Devise sign_in, fixtures).
19
+ - **Interactive AI tool selection** — install generator and `rails ai:context` prompt users to select which AI tools they use (Claude, Cursor, Copilot, Windsurf, OpenCode). Selection saved to `config.ai_tools`.
20
+ - **Brakeman in validate** — `rails_validate(level:"rails")` now runs Brakeman security checks inline alongside syntax and semantic checks.
21
+
22
+ ### Fixed
23
+
24
+ - **Documentation audit** — fixed max_tool_response_chars reference (120K→200K), added missing search_code params to GUIDE, added config.ai_tools to config reference.
25
+
26
+ ## [2.0.1] - 2026-03-25
27
+
28
+ ### Fixed
29
+
30
+ - **MCP-first mandatory workflow in all serializers** — all 6 serializer outputs (Claude, Cursor, Copilot, Windsurf, OpenCode) now use "MANDATORY, Use Before Read" language with structured workflow, anti-patterns table, and "Do NOT Bypass" rules. AI agents are explicitly instructed to never read reference files directly.
31
+ - **27 type-safety bugs in serializers** — fixed `.keys` called on Array values (same pattern as #14) across `design_system_helper.rb`, `get_design_system.rb`, `markdown_serializer.rb`, and `stack_overview_helper.rb`.
32
+ - **Strong params JSONB check** — no longer skips the entire check when JSONB columns exist. Plain-word params allowed (could be JSON keys), `_id` params still validated.
33
+ - **Strong params test skip on Ruby < 3.3** — test now skips gracefully when Prism is unavailable, matching the tool's own degradation.
34
+ - **Issue #14** — `multi_db[:databases].keys` crash on Array fixed.
35
+ - **Search code NON_CODE_GLOBS** — excludes lock files, docs, CI configs, generated context from all searches.
36
+
8
37
  ## [2.0.0] - 2026-03-24
9
38
 
10
39
  ### Added
data/README.md CHANGED
@@ -111,7 +111,7 @@ The gem exposes **25 read-only tools** via MCP that AI clients call on-demand:
111
111
  | `rails_get_test_info` | Test framework, factory attributes/traits, fixtures, CI config, coverage |
112
112
  | `rails_get_gems` | Notable gems categorized by function with config location hints |
113
113
  | `rails_get_conventions` | Architecture patterns, frontend stack, directory structure |
114
- | `rails_search_code` | Ripgrep search with 2-line context default, `match_type:"definition"` for method defs only |
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
115
  | `rails_get_view` | View templates, partials with render locals, Stimulus references |
116
116
  | `rails_get_stimulus` | Stimulus controllers — targets, values, actions, outlets, lifecycle methods |
117
117
  | `rails_get_edit_context` | Surgical edit helper — returns code with class/method context and line numbers |
@@ -146,7 +146,7 @@ rails_get_routes(controller: "users") # → routes for one controller
146
146
  rails_get_model_details(model: "User") # → associations, validations, scopes
147
147
  ```
148
148
 
149
- A safety net (`max_tool_response_chars`, default 120K) truncates oversized responses with hints to use filters.
149
+ A safety net (`max_tool_response_chars`, default 200K) truncates oversized responses with hints to use filters.
150
150
 
151
151
  ---
152
152
 
@@ -351,6 +351,7 @@ end
351
351
  | **Extensibility** | | |
352
352
  | `custom_tools` | `[]` | Additional MCP tool classes to register alongside built-in tools |
353
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]` |
354
355
  </details>
355
356
 
356
357
  ---
data/docs/GUIDE.md CHANGED
@@ -561,31 +561,38 @@ Ripgrep-powered regex search across the codebase.
561
561
 
562
562
  | Param | Type | Description |
563
563
  |-------|------|-------------|
564
- | `pattern` | string | **Required.** Regex pattern to search for. |
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
- | `file_type` | string | Filter by file type (e.g. `rb`, `erb`, `js`). Alphanumeric only. |
567
- | `match_type` | string | Filter matches: `any` (default), `definition` (only `def` lines), `class` (only `class`/`module` lines). |
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). |
568
568
  | `exact_match` | boolean | Match whole words only (wraps pattern in `\b` boundaries). Default: false. |
569
- | `max_results` | integer | Max results to return. Default: 30, max: 100. |
569
+ | `exclude_tests` | boolean | Exclude test/spec/features directories. Default: false. |
570
+ | `group_by_file` | boolean | Group results by file with match counts. Default: false. |
571
+ | `offset` | integer | Skip this many results for pagination. Default: 0. |
570
572
  | `context_lines` | integer | Lines of context before and after each match (like grep -C). Default: 2, max: 5. |
571
573
 
574
+ Smart result limiting: <10 results shows all, 10-100 shows half, >100 caps at 100. Use `offset` for pagination.
575
+
572
576
  **Examples:**
573
577
 
574
578
  ```
575
- rails_search_code(pattern: "has_secure_password")
576
- All files containing has_secure_password
579
+ rails_search_code(pattern: "can_cook?", match_type: "trace")
580
+ FULL PICTURE: definition + source code + all callers grouped by type + internal calls
581
+
582
+ rails_search_code(pattern: "create", match_type: "definition")
583
+ → Only `def create` / `def self.create` lines
577
584
 
578
- rails_search_code(pattern: "class.*Controller", file_type: "rb")
579
- All Ruby files with controller class definitions
585
+ rails_search_code(pattern: "can_cook", match_type: "call")
586
+ Only call sites (excludes the definition)
580
587
 
581
- rails_search_code(pattern: "def create", file_type: "rb", max_results: 50)
582
- First 50 create methods across the codebase
588
+ rails_search_code(pattern: "Controller", match_type: "class")
589
+ All class/module definitions matching *Controller
583
590
 
584
- rails_search_code(pattern: "current_user", path: "app/controllers")
585
- Search only in app/controllers/
591
+ rails_search_code(pattern: "has_many", group_by_file: true)
592
+ Results grouped by file with match counts
586
593
 
587
- rails_search_code(pattern: "validates", context_lines: 3)
588
- Matches with 3 lines of context before and after (default is 2)
594
+ rails_search_code(pattern: "cook", exclude_tests: true)
595
+ Skip test/spec directories
589
596
 
590
597
  rails_search_code(pattern: "activate", match_type: "definition")
591
598
  → Only `def activate` / `def self.activate` lines (skips method calls)
@@ -1175,6 +1182,7 @@ end
1175
1182
  | `cache_ttl` | Integer | `60` | Cache TTL in seconds for introspection results |
1176
1183
  | `custom_tools` | Array | `[]` | Additional MCP tool classes to register alongside built-in tools |
1177
1184
  | `skip_tools` | Array | `[]` | Built-in tool names to exclude (e.g. `%w[rails_security_scan]`) |
1185
+ | `ai_tools` | Array | `nil` (all) | AI tools to generate context for: `%i[claude cursor copilot windsurf opencode]`. Selected during install. |
1178
1186
  | `excluded_models` | Array | internal Rails models | Models to skip |
1179
1187
  | `excluded_paths` | Array | `node_modules tmp log vendor .git` | Paths excluded from code search |
1180
1188
  | `sensitive_patterns` | Array | `.env`, `.key`, `.pem`, credentials | File patterns blocked from search and read tools |
@@ -9,6 +9,43 @@ module RailsAiContext
9
9
 
10
10
  desc "Install rails-ai-context: creates initializer, MCP config, and generates initial context files."
11
11
 
12
+ AI_TOOLS = {
13
+ "1" => { key: :claude, name: "Claude Code", files: "CLAUDE.md + .claude/rules/", format: :claude },
14
+ "2" => { key: :cursor, name: "Cursor", files: ".cursor/rules/", format: :cursor },
15
+ "3" => { key: :copilot, name: "GitHub Copilot", files: ".github/copilot-instructions.md + .github/instructions/", format: :copilot },
16
+ "4" => { key: :windsurf, name: "Windsurf", files: ".windsurfrules + .windsurf/rules/", format: :windsurf },
17
+ "5" => { key: :opencode, name: "OpenCode", files: "AGENTS.md", format: :opencode }
18
+ }.freeze
19
+
20
+ def select_ai_tools
21
+ say ""
22
+ say "Which AI tools do you use? (select all that apply)", :yellow
23
+ say ""
24
+ AI_TOOLS.each do |num, info|
25
+ say " #{num}. #{info[:name].ljust(16)} → #{info[:files]}"
26
+ end
27
+ say " a. All of the above"
28
+ say ""
29
+
30
+ input = ask("Enter numbers separated by commas (e.g. 1,2) or 'a' for all:").strip.downcase
31
+
32
+ @selected_formats = if input == "a" || input == "all"
33
+ AI_TOOLS.values.map { |t| t[:format] }
34
+ else
35
+ nums = input.split(/[\s,]+/)
36
+ nums.filter_map { |n| AI_TOOLS[n]&.dig(:format) }
37
+ end
38
+
39
+ if @selected_formats.empty?
40
+ say "No tools selected — defaulting to all.", :yellow
41
+ @selected_formats = AI_TOOLS.values.map { |t| t[:format] }
42
+ end
43
+
44
+ selected_names = AI_TOOLS.values.select { |t| @selected_formats.include?(t[:format]) }.map { |t| t[:name] }
45
+ say ""
46
+ say "Selected: #{selected_names.join(', ')}", :green
47
+ end
48
+
12
49
  def create_mcp_config
13
50
  mcp_path = Rails.root.join(".mcp.json")
14
51
  server_entry = {
@@ -36,46 +73,33 @@ module RailsAiContext
36
73
  end
37
74
 
38
75
  def create_initializer
76
+ tools_line = if @selected_formats.size == AI_TOOLS.size
77
+ " # config.ai_tools = %i[claude cursor copilot windsurf opencode] # default: all"
78
+ else
79
+ " config.ai_tools = %i[#{@selected_formats.join(' ')}]"
80
+ end
81
+
39
82
  create_file "config/initializers/rails_ai_context.rb", <<~RUBY
40
83
  # frozen_string_literal: true
41
84
 
42
85
  RailsAiContext.configure do |config|
86
+ # AI tools to generate context files for (selected during install)
87
+ # Run `rails generate rails_ai_context:install` to change selection
88
+ #{tools_line}
89
+
43
90
  # Introspector preset:
44
- # :full — all 28 introspectors (default — schema, models, routes, views, turbo, auth, API, assets, devops, etc.)
45
- # :standard — 13 core introspectors (schema, models, routes, jobs, gems, conventions, controllers, tests, migrations, stimulus, view_templates, design_tokens, config)
91
+ # :full — all 28 introspectors (default)
92
+ # :standard — 13 core introspectors
46
93
  # config.preset = :full
47
94
 
48
- # Or cherry-pick individual introspectors:
49
- # config.introspectors += %i[views turbo auth api]
50
-
51
95
  # Models to exclude from introspection
52
96
  # config.excluded_models += %w[AdminUser InternalThing]
53
97
 
54
- # Paths to exclude from code search
55
- # config.excluded_paths += %w[vendor/bundle]
56
-
57
- # Context mode for generated files (CLAUDE.md, .cursor/rules/, etc.)
58
- # :compact — smart, ≤150 lines, references MCP tools for details (default)
59
- # :full — dumps everything into context files (good for small apps <30 models)
98
+ # Context mode: :compact (default, ≤150 lines) or :full (dumps everything)
60
99
  # config.context_mode = :compact
61
100
 
62
- # Max lines for CLAUDE.md in compact mode
63
- # config.claude_max_lines = 150
64
-
65
- # Max response size for MCP tool results (chars). Safety net for large apps.
66
- # config.max_tool_response_chars = 120_000
67
-
68
101
  # Live reload: auto-invalidate MCP tool caches on file changes
69
- # :auto (default) — enable if `listen` gem is available
70
- # true — enable, raise if `listen` is missing
71
- # false — disable entirely
72
102
  # config.live_reload = :auto
73
- # config.live_reload_debounce = 1.5 # seconds
74
-
75
- # Auto-mount HTTP MCP endpoint at /mcp
76
- # config.auto_mount = false
77
- # config.http_path = "/mcp"
78
- # config.http_port = 6029
79
103
  end
80
104
  RUBY
81
105
 
@@ -104,13 +128,21 @@ module RailsAiContext
104
128
  say ""
105
129
  say "Generating AI context files...", :yellow
106
130
 
107
- if Rails.application
108
- require "rails_ai_context"
109
- context = RailsAiContext.introspect
110
- files = RailsAiContext.generate_context(format: :all)
111
- files.each { |f| say " Created #{f}", :green }
112
- else
131
+ unless Rails.application
113
132
  say " Skipped (Rails app not fully loaded). Run `rails ai:context` after install.", :yellow
133
+ return
134
+ end
135
+
136
+ require "rails_ai_context"
137
+
138
+ @selected_formats.each do |fmt|
139
+ begin
140
+ result = RailsAiContext.generate_context(format: fmt)
141
+ (result[:written] || []).each { |f| say " ✅ #{f}", :green }
142
+ (result[:skipped] || []).each { |f| say " ⏭️ #{f} (unchanged)", :yellow }
143
+ rescue => e
144
+ say " ❌ #{fmt}: #{e.message}", :red
145
+ end
114
146
  end
115
147
  end
116
148
 
@@ -120,27 +152,26 @@ module RailsAiContext
120
152
  say " rails-ai-context installed!", :cyan
121
153
  say "=" * 50, :cyan
122
154
  say ""
123
- say "Quick start:", :yellow
124
- say " rails ai:context # Generate all context files"
125
- say " rails ai:context:claude # Generate CLAUDE.md only"
126
- say " rails ai:context:cursor # Generate .cursor/rules/ only"
127
- say " rails ai:serve # Start MCP server (stdio)"
128
- say " rails ai:inspect # Print introspection summary"
155
+ say "Your setup:", :yellow
156
+ AI_TOOLS.each_value do |info|
157
+ next unless @selected_formats.include?(info[:format])
158
+ say " #{info[:name].ljust(16)} #{info[:files]}"
159
+ end
129
160
  say ""
130
- say "Generated files per AI tool:", :yellow
131
- say " Claude Code → CLAUDE.md + .claude/rules/*.md"
132
- say " OpenCode → AGENTS.md"
133
- say " Cursor → .cursor/rules/*.mdc"
134
- say " Windsurf → .windsurfrules + .windsurf/rules/*.md"
135
- say " GitHub Copilot → .github/copilot-instructions.md + .github/instructions/*.instructions.md"
161
+ say "Commands:", :yellow
162
+ say " rails ai:context # Regenerate context files"
163
+ say " rails ai:serve # Start MCP server (25 live tools)"
164
+ say " rails ai:doctor # Check AI readiness"
165
+ say " rails ai:inspect # Print introspection summary"
136
166
  say ""
137
167
  say "MCP auto-discovery:", :yellow
138
168
  say " .mcp.json is auto-detected by Claude Code and Cursor."
139
- say " No manual MCP config needed — just open your project."
169
+ say " No manual config needed — just open your project."
140
170
  say ""
141
- say "Context modes:", :yellow
142
- say " rails ai:context # compact mode (default, smart for any app size)"
143
- say " rails ai:context:full # full dump (good for small apps)"
171
+ say "To add more AI tools later:", :yellow
172
+ say " rails ai:context:cursor # Generate for Cursor"
173
+ say " rails ai:context:copilot # Generate for Copilot"
174
+ say " rails generate rails_ai_context:install # Re-run to pick tools"
144
175
  say ""
145
176
  say "Commit context files and .mcp.json so your team benefits!", :green
146
177
  end
@@ -75,6 +75,10 @@ module RailsAiContext
75
75
  # Built-in tool names to skip (e.g. %w[rails_security_scan rails_get_design_system])
76
76
  attr_accessor :skip_tools
77
77
 
78
+ # Which AI tools to generate context for (selected during install)
79
+ # nil = all formats, or %i[claude cursor copilot windsurf opencode]
80
+ attr_accessor :ai_tools
81
+
78
82
  # Filtering — customize what's hidden from AI output
79
83
  attr_accessor :excluded_controllers # Controller classes hidden from listings (e.g. DeviseController)
80
84
  attr_accessor :excluded_route_prefixes # Route controller prefixes hidden with app_only (e.g. action_mailbox/)
@@ -148,6 +152,7 @@ module RailsAiContext
148
152
  ]
149
153
  @custom_tools = []
150
154
  @skip_tools = []
155
+ @ai_tools = nil
151
156
  @search_extensions = %w[rb js erb yml yaml json ts tsx vue svelte haml slim]
152
157
  @concern_paths = %w[app/models/concerns app/controllers/concerns]
153
158
  end
@@ -96,7 +96,8 @@ module RailsAiContext
96
96
  rescue; end
97
97
 
98
98
  lines << ""
99
- lines << "Use MCP tools for detailed data. Start with `detail:\"summary\"`."
99
+ lines << "ALWAYS use MCP tools for context do NOT read reference files directly."
100
+ lines << "Start with `detail:\"summary\"`. Read files ONLY when you will Edit them."
100
101
 
101
102
  lines.join("\n")
102
103
  end
@@ -294,31 +295,52 @@ module RailsAiContext
294
295
 
295
296
  def render_mcp_tools_reference # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
296
297
  lines = [
297
- "# Rails MCP Tools — ALWAYS Use These First",
298
- "",
299
- "IMPORTANT: This project has live MCP tools that return parsed, up-to-date data.",
300
- "Use these tools for reference-only files (schema, routes, tests). For files you will edit, Read them directly.",
301
- "The tools return structured, token-efficient summaries with line numbers.",
302
- "",
303
- "## When to use MCP tools vs Read",
304
- "- Use MCP for files you WON'T edit (schema, routes, understanding context)",
305
- "- For files you WILL edit, just Read them directly — you need Read before Edit anyway",
306
- "- Use MCP for orientation (summary calls) on large codebases",
307
- "- Skip MCP when CLAUDE.md + rules already have the info you need",
308
- "- Do NOT call rails_get_model_details if CLAUDE.md already shows the model's associations and column types",
309
- "- Do NOT call rails_get_stimulus just to check if Stimulus exists — CLAUDE.md confirms it",
310
- "",
311
- "## After editingALWAYS use rails_validate (not Bash)",
312
- "- `rails_validate(files:[\"app/models/cook.rb\", \"app/controllers/cooks_controller.rb\", \"app/views/cooks/index.html.erb\"])` — one call checks all",
298
+ "# Rails MCP Tools — MANDATORY, Use Before Read/Grep",
299
+ "",
300
+ "CRITICAL: This project has live MCP tools. You MUST use them for gathering context.",
301
+ "MCP tools return parsed, up-to-date, token-efficient data with line numbers.",
302
+ "Read files ONLY when you are about to Edit them. Never read reference files directly.",
303
+ "",
304
+ "## Mandatory Workflow Follow This Order",
305
+ "",
306
+ "### 1. Gathering context (BEFORE writing any code)",
307
+ "- Exploring a feature area → `rails_analyze_feature(feature:\"...\")` NOT Explore agents, NOT Grep",
308
+ "- Understanding a model `rails_get_model_details(model:\"...\")` NOT reading the model file",
309
+ "- Checking database columns `rails_get_schema(table:\"...\")` NOT reading db/schema.rb",
310
+ "- Checking routes `rails_get_routes(controller:\"...\")` NOT reading config/routes.rb",
311
+ "- Understanding a controller → `rails_get_controllers(controller:\"...\", action:\"...\")` — NOT reading the file",
312
+ "- Finding code patterns → `rails_search_code(pattern:\"...\")` NOT using Grep tool",
313
+ "- UI patterns `rails_get_design_system`NOT reading view files for patterns",
314
+ "- Full cross-layer context → `rails_get_context(model:\"...\")` — replaces multiple Read calls",
315
+ "",
316
+ "### 2. Reading files (ONLY files you will edit)",
317
+ "- Read a file ONLY when you are about to Edit it (Read is required before Edit)",
318
+ "- For everything else — schema, routes, models, tests, patterns — use MCP tools above",
319
+ "",
320
+ "### 3. After editing (EVERY time, no exceptions)",
321
+ "- `rails_validate(files:[\"path/to/file.rb\", \"path/to/view.erb\"])` — one call checks all",
313
322
  "- Do NOT run `ruby -c`, `erb` checks, or `node -c` separately — use rails_validate instead",
314
323
  "- Do NOT re-read files to verify edits. Trust your Edit and validate syntax only.",
315
324
  "",
316
- "## Reference-only filescheck rules first, then MCP or Read if needed",
317
- "- db/schema.rb column names and types are in rails-schema.md rules. Read only if you need constraints/defaults.",
318
- "- config/routes.rb — use `rails_get_routes` for reference. Read directly if you'll add routes.",
319
- "- Model files — scopes, constants, enums are in rails-models.md rules. Read for business logic/methods.",
320
- "- app/javascript/controllers/index.js Stimulus auto-registers controllers. No need to read.",
321
- "- Test files use `rails_get_test_info(detail:\"full\")` for patterns.",
325
+ "## Do NOT Bypass Anti-Patterns",
326
+ "| Instead of... | Use this MCP tool |",
327
+ "|---------------|-------------------|",
328
+ "| Reading db/schema.rb | `rails_get_schema(table:\"name\")` |",
329
+ "| Reading config/routes.rb for reference | `rails_get_routes(controller:\"name\")` |",
330
+ "| Reading model files for associations | `rails_get_model_details(model:\"Name\")` |",
331
+ "| Grep/Explore agent for code search | `rails_search_code(pattern:\"regex\")` |",
332
+ "| Reading test files for patterns | `rails_get_test_info(model:\"Name\")` |",
333
+ "| Reading controller files for context | `rails_get_controllers(controller:\"Name\")` |",
334
+ "| Reading JS files for Stimulus API | `rails_get_stimulus(controller:\"name\")` |",
335
+ "| Multiple reads to understand a feature | `rails_analyze_feature(feature:\"keyword\")` |",
336
+ "| ruby -c / erb / node -c after edits | `rails_validate(files:[...])` |",
337
+ "",
338
+ "## Reference-only files — NEVER read these, use MCP",
339
+ "- db/schema.rb → `rails_get_schema` (column types in rails-schema.md rules for quick checks)",
340
+ "- config/routes.rb → `rails_get_routes` (Read ONLY when adding routes)",
341
+ "- Model files → `rails_get_model_details` (Read ONLY when editing business logic)",
342
+ "- app/javascript/controllers/index.js → Stimulus auto-registers. Never read this.",
343
+ "- Test files → `rails_get_test_info`",
322
344
  "",
323
345
  "## Tools (25)",
324
346
  "",
@@ -200,30 +200,38 @@ module RailsAiContext
200
200
  [
201
201
  "## MCP Tools (25) — ALWAYS Use These First",
202
202
  "",
203
- "Use MCP for reference files (schema, routes, tests). Read directly if you'll edit.",
204
- "MCP tools return line numbers. Start with `detail:\"summary\"`.",
203
+ "This project has live MCP tools. You MUST use them instead of reading reference files.",
204
+ "Start with `detail:\"summary\"`, then drill into specifics.",
205
205
  "",
206
- "- `rails_get_schema(detail:\"summary\")` → `rails_get_schema(table:\"name\")`",
207
- "- `rails_get_model_details(detail:\"summary\")` `rails_get_model_details(model:\"Name\")`",
208
- "- `rails_get_routes(detail:\"summary\")` `rails_get_routes(controller:\"name\")`",
209
- "- `rails_get_controllers(controller:\"Name\", action:\"index\")` — one action's source code",
210
- "- `rails_get_view(controller:\"cooks\")` — view list; `(path:\"cooks/index.html.erb\")` content",
211
- "- `rails_get_stimulus(detail:\"summary\")` `(controller:\"name\")` — targets, actions, values",
212
- "- `rails_get_test_info(detail:\"full\")` — fixtures, factories, helpers; `(model:\"Cook\")` tests",
213
- "- `rails_analyze_feature(feature:\"auth\")` — schema + models + controllers + routes for a feature",
214
- "- `rails_get_design_system` — color palette, component patterns, canonical page examples",
215
- "- `rails_get_config` | `rails_get_gems` | `rails_get_conventions` | `rails_search_code`",
216
- "- `rails_validate(files:[\"path/to/file.rb\"])` — validate Ruby, ERB, JS syntax in one call",
217
- "- `rails_security_scan` Brakeman security analysis",
218
- "- `rails_get_concern(name:\"Searchable\")` concern methods and includers",
219
- "- `rails_get_callbacks(model:\"User\")` model callbacks in execution order",
220
- "- `rails_get_helper_methods` app + framework helpers",
221
- "- `rails_get_service_pattern` service object patterns and interfaces",
222
- "- `rails_get_job_pattern` background job patterns and schedules",
223
- "- `rails_get_env` environment variables and credentials keys",
224
- "- `rails_get_partial_interface(path:\"shared/_form\")` partial locals contract",
225
- "- `rails_get_turbo_map` Turbo Streams/Frames wiring",
226
- "- `rails_get_context(model:\"User\")` composite cross-layer context",
206
+ "### Mandatory Workflow",
207
+ "1. **Before exploring a feature**: `rails_analyze_feature(feature:\"...\")` NOT Explore agents or Grep",
208
+ "2. **Before writing migrations**: `rails_get_schema(table:\"...\")` NOT reading db/schema.rb",
209
+ "3. **Before modifying a model**: `rails_get_model_details(model:\"...\")` — NOT reading the model file",
210
+ "4. **Before adding routes**: `rails_get_routes(controller:\"...\")` — Read routes.rb only when you will edit it",
211
+ "5. **Before creating views**: `rails_get_design_system` — match existing patterns",
212
+ "6. **After editing ANY file**: `rails_validate(files:[...])` — no exceptions, no ruby -c / erb / node -c",
213
+ "",
214
+ "### Quick Reference",
215
+ "| Need | Use this MCP tool | Do NOT use |",
216
+ "|------|-------------------|------------|",
217
+ "| Column types | `rails_get_schema(table:\"x\")` | Read db/schema.rb |",
218
+ "| Model associations | `rails_get_model_details(model:\"X\")` | Read app/models/x.rb |",
219
+ "| Route paths | `rails_get_routes(controller:\"x\")` | Read config/routes.rb |",
220
+ "| Feature overview | `rails_analyze_feature(feature:\"x\")` | Explore agent / Grep |",
221
+ "| Find code | `rails_search_code(pattern:\"x\")` | Grep tool |",
222
+ "| Validate edits | `rails_validate(files:[...])` | ruby -c / erb / node |",
223
+ "| Controller logic | `rails_get_controllers(controller:\"X\", action:\"y\")` | Read controller file |",
224
+ "| UI patterns | `rails_get_design_system` | Read view files |",
225
+ "| Stimulus API | `rails_get_stimulus(controller:\"x\")` | Read JS files |",
226
+ "| Test patterns | `rails_get_test_info(model:\"X\")` | Read test files |",
227
+ "| Full context | `rails_get_context(model:\"X\")` | Multiple Read calls |",
228
+ "",
229
+ "### More Tools",
230
+ "- `rails_get_view(controller:\"x\")` | `rails_get_concern(name:\"X\")` | `rails_get_callbacks(model:\"X\")`",
231
+ "- `rails_get_helper_methods` | `rails_get_service_pattern` | `rails_get_job_pattern`",
232
+ "- `rails_get_env` | `rails_get_partial_interface(path:\"shared/_form\")` | `rails_get_turbo_map`",
233
+ "- `rails_get_config` | `rails_get_gems` | `rails_get_conventions` | `rails_security_scan`",
234
+ "- `rails_get_edit_context(file:\"path\", near:\"keyword\")` — surgical edit helper with line numbers",
227
235
  ""
228
236
  ]
229
237
  end
@@ -256,12 +264,20 @@ module RailsAiContext
256
264
  [
257
265
  "## Rules",
258
266
  "- Follow existing patterns and conventions",
259
- "- Use the MCP tools to check schema before writing migrations",
260
267
  "- Match existing code style",
261
268
  "- Run tests after changes",
262
269
  "- After editing, ALWAYS use `rails_validate(files:[...])` — do NOT use separate ruby -c / erb / node -c calls",
263
270
  "- Do NOT re-read files to verify edits — trust your Edit, validate syntax only",
264
271
  "- Stimulus controllers auto-register — no manual import in controllers/index.js needed",
272
+ "",
273
+ "## MCP-First Rule — Do NOT Bypass",
274
+ "- Do NOT read db/schema.rb — use `rails_get_schema`",
275
+ "- Do NOT read config/routes.rb for reference — use `rails_get_routes`",
276
+ "- Do NOT read model files for associations/scopes — use `rails_get_model_details`",
277
+ "- Do NOT use Grep to search code — use `rails_search_code`",
278
+ "- Do NOT launch Explore agents for context — use `rails_analyze_feature`",
279
+ "- Do NOT read test files for patterns — use `rails_get_test_info`",
280
+ "- Read files ONLY when you are about to Edit them",
265
281
  ""
266
282
  ]
267
283
  end
@@ -219,36 +219,38 @@ module RailsAiContext
219
219
  "applyTo: \"**/*\"",
220
220
  "---",
221
221
  "",
222
- "# Rails MCP Tools (25) — Use These First",
222
+ "# Rails MCP Tools (25) — MANDATORY, Use Before Read",
223
223
  "",
224
- "Use MCP for reference files (schema, routes, tests). Read directly if you'll edit.",
225
- "MCP tools return line numbers for surgical edits.",
226
- "**Start with `detail:\"summary\"`, then drill into specifics.**",
224
+ "CRITICAL: This project has live MCP tools. You MUST use them for gathering context.",
225
+ "Read files ONLY when you are about to edit them. Never read reference files directly.",
226
+ "Start with `detail:\"summary\"`, then drill into specifics.",
227
227
  "",
228
- "- `rails_get_schema(detail:\"summary\")` → `rails_get_schema(table:\"name\")`",
229
- "- `rails_get_model_details(detail:\"summary\")``rails_get_model_details(model:\"Name\")`",
230
- "- `rails_get_routes(detail:\"summary\")``rails_get_routes(controller:\"name\")`",
231
- "- `rails_get_controllers(controller:\"Name\", action:\"index\")` one action's source code",
232
- "- `rails_get_view(controller:\"cooks\")` — view list; `(path:\"cooks/index.html.erb\")` — content",
233
- "- `rails_get_stimulus(detail:\"summary\")` → `(controller:\"name\")` — targets, actions, values",
234
- "- `rails_get_test_info(detail:\"full\")` — fixtures, factories, helpers; `(model:\"Cook\")` — existing tests",
235
- "- `rails_analyze_feature(feature:\"auth\")` — schema + models + controllers + routes for a feature",
236
- "- `rails_get_design_system` — color palette, components, canonical page examples",
237
- "- `rails_get_config` | `rails_get_gems` | `rails_get_conventions` | `rails_search_code`",
238
- "- `rails_get_edit_context(file:\"path\", near:\"keyword\")` — surgical edit context with line numbers",
239
- "- `rails_validate(files:[\"path\"])` — validate Ruby, ERB, JS syntax in one call",
240
- "- `rails_security_scan` — Brakeman security analysis",
241
- "- `rails_get_concern(name:\"Searchable\")` — concern methods and includers",
242
- "- `rails_get_callbacks(model:\"User\")` — model callbacks in execution order",
243
- "- `rails_get_helper_methods` — app + framework helpers",
244
- "- `rails_get_service_pattern` — service object patterns and interfaces",
245
- "- `rails_get_job_pattern` — background job patterns and schedules",
246
- "- `rails_get_env` — environment variables and credentials keys",
247
- "- `rails_get_partial_interface(path:\"shared/_form\")` — partial locals contract",
248
- "- `rails_get_turbo_map` — Turbo Streams/Frames wiring",
249
- "- `rails_get_context(model:\"User\")` — composite cross-layer context",
228
+ "## Mandatory Workflow",
229
+ "1. Gathering context use MCP tools (NOT file reads, NOT grep)",
230
+ "2. Reading files ONLY files you will edit",
231
+ "3. After editing → `rails_validate(files:[...])` every time, no exceptions",
250
232
  "",
251
- "After editing: use rails_validate to check syntax. Do NOT re-read files to verify."
233
+ "## Do NOT Bypass",
234
+ "| Instead of... | Use this MCP tool |",
235
+ "|---------------|-------------------|",
236
+ "| Reading db/schema.rb | `rails_get_schema(table:\"name\")` |",
237
+ "| Reading config/routes.rb | `rails_get_routes(controller:\"name\")` |",
238
+ "| Reading model files for context | `rails_get_model_details(model:\"Name\")` |",
239
+ "| Grep for code patterns | `rails_search_code(pattern:\"regex\")` |",
240
+ "| Reading test files | `rails_get_test_info(model:\"Name\")` |",
241
+ "| Reading controller for context | `rails_get_controllers(controller:\"Name\", action:\"x\")` |",
242
+ "| Reading JS for Stimulus API | `rails_get_stimulus(controller:\"name\")` |",
243
+ "| Multiple reads for a feature | `rails_analyze_feature(feature:\"keyword\")` |",
244
+ "| ruby -c / erb / node -c | `rails_validate(files:[...])` |",
245
+ "",
246
+ "## All 25 Tools",
247
+ "- `rails_get_schema` | `rails_get_model_details` | `rails_get_routes` | `rails_get_controllers`",
248
+ "- `rails_get_view` | `rails_get_stimulus` | `rails_get_test_info` | `rails_analyze_feature`",
249
+ "- `rails_get_design_system` | `rails_get_edit_context` | `rails_validate` | `rails_search_code`",
250
+ "- `rails_get_config` | `rails_get_gems` | `rails_get_conventions` | `rails_security_scan`",
251
+ "- `rails_get_concern` | `rails_get_callbacks` | `rails_get_helper_methods` | `rails_get_service_pattern`",
252
+ "- `rails_get_job_pattern` | `rails_get_env` | `rails_get_partial_interface` | `rails_get_turbo_map`",
253
+ "- `rails_get_context(model:\"X\")` — composite cross-layer context in one call"
252
254
  ]
253
255
 
254
256
  lines.join("\n")