rails-ai-context 4.5.2 → 4.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +41 -1
  3. data/CLAUDE.md +3 -3
  4. data/README.md +51 -24
  5. data/SECURITY.md +3 -0
  6. data/docs/GUIDE.md +7 -0
  7. data/exe/rails-ai-context +5 -1
  8. data/lib/generators/rails_ai_context/install/install_generator.rb +5 -1
  9. data/lib/rails_ai_context/configuration.rb +44 -30
  10. data/lib/rails_ai_context/introspector.rb +1 -1
  11. data/lib/rails_ai_context/introspectors/{convention_detector.rb → convention_introspector.rb} +1 -1
  12. data/lib/rails_ai_context/serializers/claude_rules_serializer.rb +13 -40
  13. data/lib/rails_ai_context/serializers/claude_serializer.rb +11 -191
  14. data/lib/rails_ai_context/serializers/compact_serializer_helper.rb +141 -0
  15. data/lib/rails_ai_context/serializers/copilot_instructions_serializer.rb +17 -75
  16. data/lib/rails_ai_context/serializers/copilot_serializer.rb +3 -3
  17. data/lib/rails_ai_context/serializers/cursor_rules_serializer.rb +19 -79
  18. data/lib/rails_ai_context/serializers/markdown_serializer.rb +14 -6
  19. data/lib/rails_ai_context/serializers/opencode_rules_serializer.rb +18 -60
  20. data/lib/rails_ai_context/serializers/opencode_serializer.rb +5 -141
  21. data/lib/rails_ai_context/serializers/stack_overview_helper.rb +121 -0
  22. data/lib/rails_ai_context/serializers/tool_guide_helper.rb +85 -100
  23. data/lib/rails_ai_context/tools/base_tool.rb +49 -24
  24. data/lib/rails_ai_context/tools/dependency_graph.rb +1 -2
  25. data/lib/rails_ai_context/tools/generate_test.rb +1 -2
  26. data/lib/rails_ai_context/tools/get_callbacks.rb +3 -35
  27. data/lib/rails_ai_context/tools/get_concern.rb +4 -31
  28. data/lib/rails_ai_context/tools/get_context.rb +1 -3
  29. data/lib/rails_ai_context/tools/get_model_details.rb +1 -2
  30. data/lib/rails_ai_context/tools/get_view.rb +2 -2
  31. data/lib/rails_ai_context/version.rb +1 -1
  32. data/lib/rails_ai_context.rb +0 -1
  33. data/server.json +3 -3
  34. metadata +11 -25
  35. data/lib/rails_ai_context/markdown_escape.rb +0 -15
  36. data/lib/rails_ai_context/serializers/rules_serializer.rb +0 -155
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d53c26bdd73eac84be7e9a49ea08c2a50dd0230f969cb29ae240cf2d08b9e4c3
4
- data.tar.gz: a65a518fab277ff246401cffb32701fb36048f65034b068e20f4b3fe76ddc4eb
3
+ metadata.gz: c780366dc085c17be730aded4bbe8548b0e5e71c5c810caed96104a9379363fa
4
+ data.tar.gz: f5c46207b643df1a7dc1c5563c1d9e932f772ce5e27eb1839d9f14ddde116bd0
5
5
  SHA512:
6
- metadata.gz: 0504e0e68f018d325189ccdfd153b7097d1204c906241a9a0dfea41586272b0c2ae296f81704c4e6c4ac9bb414aaab83c5de35e226b7aabff52b984d1bec451e
7
- data.tar.gz: f2c8a762bd3520edd09e719337043be0a9b7158d0099076118226012cea980ca1877c48459d78810c8e9a1c9d91bf526aad4a2c334521e19c5ac7b715bc44b1e
6
+ metadata.gz: 934c4d703203801494a8addde164c71e56119e5701dd454574b0362d2a6d68523b6f0830654ff81eaa1d36fac7eca457374960e4e9fe54731f32431fe23ea8a4
7
+ data.tar.gz: ca2bf9e27db44fb35b8d9bd984748b7fce1108a013ef7ea6ec5a01757c48187b6ce6985c529ee8bf4df7cc9abd59085da8c356b3c73052e5196b07cc9a9a3790
data/CHANGELOG.md CHANGED
@@ -5,6 +5,30 @@ 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
+ ## [4.7.0] — 2026-04-05
9
+
10
+ ### Added
11
+ - **Anti-Hallucination Protocol** — 6-rule verification section embedded in every generated context file (CLAUDE.md, AGENTS.md, .claude/rules/, .cursor/rules/, .github/instructions/, copilot-instructions.md). Targets specific AI failure modes: statistical priors overriding observed facts, pattern completion beating verification, inheritance blindness, empty-output-as-permission, stale-context-lies. Rules force AI to verify column/association/route/method/gem names before writing, mark assumptions with `[ASSUMPTION]` prefix, check inheritance chains, and re-query after writes. Enabled by default via new `config.anti_hallucination_rules` option (boolean, default: `true`). Set `false` to skip.
12
+
13
+ ### Changed
14
+ - **Repositioning: ground truth, not token savings** — the gem's mission is now explicit about what it actually does: stop AI from guessing your Rails app. Token savings are a side-effect, not the product. Updated README headline, "What stops being wrong" section (replaces "Measured token savings"), gemspec summary/description, server.json MCP registry description, docs/GUIDE.md intro, and the tools guide embedded in every generated CLAUDE.md/AGENTS.md/.cursor/rules. The core pitch: AI queries your running app for real schema, real associations, real filters — and writes correct code on the first try instead of iterating through corrections.
15
+
16
+ ## [4.6.0] — 2026-04-04
17
+
18
+ ### Added
19
+ - **Integration test suite** — 3 purpose-built Rails 8 apps exercising every gem feature end-to-end:
20
+ - `full_app` — comprehensive app (38 gems, 14 models, 15 controllers, 26 views, 5 jobs, 3 mailers, multi-database, ViewComponent, Stimulus, STI, polymorphic, AASM, PaperTrail, FriendlyId, encrypted attributes, CurrentAttributes, Flipper feature flags, Sentry monitoring, Pundit auth, Ransack search, Dry-rb, acts_as_tenant, Docker, Kamal, GitHub Actions CI, RSpec + FactoryBot)
21
+ - `api_app` — API-only app (Products/Orders/OrderItems, namespaced API v1 routes, CLI tool_mode)
22
+ - `minimal_app` — bare minimum app (single model, graceful degradation testing)
23
+ - **Master test runner** (`test_apps/run_all_tests.sh`) — validates Doctor, context generation, all 33 introspectors, all 39 MCP tools, Rake tasks, MCP server startup, and app-specific pattern detection across all 3 apps (222 tests)
24
+ - All 3 test apps achieve **100/100 AI Readiness Score**
25
+
26
+ ### Fixed
27
+ - **Standalone CLI `full_gem_path` crash** — `Gem.loaded_specs.delete_if { |_, spec| !spec.default_gem? }` in the exe file cleared gem specs needed by MCP SDK at runtime (`json-schema` gem's `full_gem_path` returned nil). Added `!ENV["BUNDLE_BIN_PATH"]` guard so cleanup only runs in true standalone mode, not under `bundle exec`. This bug affected ALL `rails-ai-context tool` commands in standalone mode.
28
+
29
+ ### Changed
30
+ - Test count: 1621 RSpec examples + 222 integration tests across 3 apps
31
+
8
32
  ## [4.5.2] — 2026-04-04
9
33
 
10
34
  ### Added
@@ -30,8 +54,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
30
54
  - **CLI error messages** — Clean error messages for all CLI error paths
31
55
  - **Rake/init parity** — `rake ai:context` and `init` command now match generator output
32
56
 
57
+ ### Refactored
58
+ - **SLOP audit: ~640 lines removed** — comprehensive audit eliminating superfluous abstractions, dead code, and duplicated patterns
59
+ - **CompactSerializerHelper** — extracted shared logic from ClaudeSerializer and OpencodeSerializer, eliminating ~75% duplication
60
+ - **StackOverviewHelper consolidation** — moved `project_root`, `detect_service_files`, `detect_job_files`, `detect_before_actions`, `scope_names`, `notable_gems_list`, `arch_labels_hash`, `pattern_labels_hash`, `write_rule_files` into shared module, replacing 30+ duplicate copies across 6 serializers
61
+ - **Atomic file writes** — `write_rule_files` uses temp file + rename for crash-safe context file generation
62
+ - **ConventionDetector → ConventionIntrospector** — renamed for naming consistency with all 33 other introspectors
63
+ - **MarkdownEscape inlined** — single-use module inlined into MarkdownSerializer as private method
64
+ - **RulesSerializer deleted** — dead code never called by ContextFileSerializer
65
+ - **BaseTool cleanup** — removed dead `auto_compress`, `app_size`, `session_queried?` methods
66
+ - **IntrospectionError deleted** — exception class never raised anywhere
67
+ - **mobile_paths config removed** — config option never read by any introspector, tool, or serializer
68
+ - **server_version** — changed from attr_accessor to method delegating to `VERSION` constant
69
+ - **Configuration constants** — extracted `DEFAULT_EXCLUDED_FILTERS`, `DEFAULT_EXCLUDED_MIDDLEWARE`, `DEFAULT_EXCLUDED_CONCERNS` as frozen constants
70
+ - **Detail spec consolidation** — merged 5 detail spec files into their base spec counterparts
71
+ - **Orphaned spec cleanup** — removed `gem_introspector_spec.rb` duplicate (canonical spec already exists under introspectors/)
72
+
33
73
  ### Changed
34
- - Test count: 1658 examples (76 new tests for Phase 2 features)
74
+ - Test count: 1621 examples (consolidated from 1658 no coverage lost, only duplicate/orphaned specs removed)
35
75
 
36
76
  ## [4.4.0] — 2026-04-03
37
77
 
data/CLAUDE.md CHANGED
@@ -11,12 +11,11 @@ structure to AI assistants via the Model Context Protocol (MCP).
11
11
  - `lib/rails_ai_context/introspectors/` — 33 introspectors (schema, models, routes, jobs, gems, conventions, stimulus, database_stats, controllers, views, view_templates, design_tokens, turbo, i18n, config, active_storage, action_text, auth, api, tests, rake_tasks, assets, devops, action_mailbox, migrations, seeds, middleware, engines, multi_database, components, accessibility, performance, frontend_frameworks)
12
12
  - `lib/rails_ai_context/tools/` — 39 MCP tools using the official mcp SDK
13
13
  - `lib/rails_ai_context/cli/` — CLI tool runner (`tool_runner.rb`) — executes MCP tools from rake/Thor
14
- - `lib/rails_ai_context/serializers/` — Output formatters (claude, claude_rules, opencode, opencode_rules, cursor_rules, copilot, copilot_instructions, rules, markdown, JSON, context_file_serializer, test_command_detection, tool_guide_helper, design_system_helper, stack_overview_helper)
14
+ - `lib/rails_ai_context/serializers/` — Output formatters (claude, claude_rules, opencode, opencode_rules, cursor_rules, copilot, copilot_instructions, markdown, JSON, context_file_serializer, compact_serializer_helper, test_command_detection, tool_guide_helper, design_system_helper, stack_overview_helper)
15
15
  - `lib/rails_ai_context/resources.rb` — MCP resources (static data AI clients read directly)
16
16
  - `lib/rails_ai_context/server.rb` — MCP server configuration (stdio + HTTP transports)
17
17
  - `lib/rails_ai_context/middleware.rb` — Rack middleware for auto-mounting MCP HTTP endpoint
18
18
  - `lib/rails_ai_context/safe_file.rb` — Safe file reading with size limits and error handling
19
- - `lib/rails_ai_context/markdown_escape.rb` — Escapes markdown special characters in dynamic content
20
19
  - `lib/rails_ai_context/fingerprinter.rb` — SHA256 file fingerprinting for cache invalidation
21
20
  - `lib/rails_ai_context/doctor.rb` — Diagnostic checks and AI readiness scoring
22
21
  - `lib/rails_ai_context/live_reload.rb` — MCP live reload: watches files, invalidates caches, notifies AI clients
@@ -64,11 +63,12 @@ structure to AI assistants via the Model Context Protocol (MCP).
64
63
  35. **YAML config** — `.rails-ai-context.yml` as alternative to initializer. Supports all config options except `custom_tools` (Ruby classes) and `excluded_concerns` (regex). Precedence: initializer > YAML > defaults.
65
64
  36. **Config auto-loading** — `Configuration.auto_load!` checks `configured_via_block?` flag. If initializer ran, YAML is skipped. Corrupted YAML degrades gracefully with a warning.
66
65
  37. **Three install paths** — In-Gemfile (`rails generate rails_ai_context:install`), Standalone (`rails-ai-context init`), Zero config (just run `rails-ai-context serve` with defaults). Users can switch between paths freely; `.mcp.json` command is updated on re-init/re-install.
66
+ 38. **Anti-Hallucination Protocol** — 6-rule verification section embedded in every generated context file (CLAUDE.md, AGENTS.md, .claude/rules/, .cursor/rules/, .github/instructions/). Targets AI failure modes: statistical priors overriding facts, pattern completion beating verification, stale context. Toggleable via `config.anti_hallucination_rules` (default: true). Rendered by `tools_anti_hallucination_section` in `tool_guide_helper.rb`, placed between intro and detail_guidance in both full and compact render methods.
67
67
 
68
68
  ## Testing
69
69
 
70
70
  ```bash
71
- bundle exec rspec # Run specs (1658 examples)
71
+ bundle exec rspec # Run specs (1627 examples)
72
72
  bundle exec rubocop # Lint
73
73
  ```
74
74
 
data/README.md CHANGED
@@ -19,7 +19,7 @@
19
19
  [![MCP Registry](https://img.shields.io/badge/MCP_Registry-listed-green)](https://registry.modelcontextprotocol.io)
20
20
  [![Ruby](https://img.shields.io/badge/Ruby-3.2%20%7C%203.3%20%7C%203.4-CC342D)](https://github.com/crisnahine/rails-ai-context)
21
21
  [![Rails](https://img.shields.io/badge/Rails-7.1%20%7C%207.2%20%7C%208.0-CC0000)](https://github.com/crisnahine/rails-ai-context)
22
- [![Tests](https://img.shields.io/badge/Tests-1529%20passing-brightgreen)](https://github.com/crisnahine/rails-ai-context/actions)
22
+ [![Tests](https://img.shields.io/badge/Tests-1621%20passing-brightgreen)](https://github.com/crisnahine/rails-ai-context/actions)
23
23
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
24
24
 
25
25
  </div>
@@ -35,12 +35,12 @@ You've seen it. Your AI:
35
35
  - **Uses the wrong association name** — `user.posts` when it's `user.articles`
36
36
  - **Generates tests that don't match your patterns** — factories when you use fixtures, or the reverse
37
37
  - **Adds a gem you already have** — or calls an API from one you don't
38
- - **Reads 2,000 lines of schema.rb** to answer a question about one table
39
38
  - **Misses `before_action` filters from parent controllers** — then wonders why auth fails
39
+ - **Invents a method** that isn't in your codebase — then you spend 10 minutes finding out
40
40
 
41
41
  You catch it. You fix it. You re-prompt. It breaks something else.
42
42
 
43
- **That loop is the actual cost of AI coding — not the tokens, the corrections.**
43
+ **The real cost of AI coding isn't the tokens it's the correction loop.** Every guess is a round-trip: you catch it, you fix it, you re-prompt, and something adjacent breaks. This gem kills the guessing at its source.
44
44
 
45
45
  <br>
46
46
 
@@ -82,37 +82,41 @@ One call returns: definition + source code + every caller grouped by type + test
82
82
 
83
83
  <br>
84
84
 
85
- ## Measured token savings
85
+ ## What stops being wrong
86
86
 
87
- Real numbers from a production Rails app:
87
+ Real scenarios where AI goes sideways — and what it does instead with ground truth:
88
88
 
89
- | Task | Without | With | Saved |
90
- |:-----|--------:|-----:|------:|
91
- | Get one table's columns | 1,492 tokens | 335 tokens | **77%** |
92
- | Trace a method across codebase | 10,556 tokens | 256 tokens | **97%** |
93
- | Understand a model | 1,754 tokens | 588 tokens | **66%** |
94
- | Map Stimulus controllers | 9,886 tokens | 620 tokens | **94%** |
95
- | Routes for one controller | 373 tokens | 121 tokens | **68%** |
89
+ | You ask AI to... | Without — AI guesses | With AI verifies first |
90
+ |:-----|:-----|:-----|
91
+ | Add a `subscription_tier` column to users | Writes the migration, duplicates an existing column | Reads live schema, spots `subscription_status` already exists, asks before migrating |
92
+ | Call `user.posts` in a controller | Uses the guess; runtime `NoMethodError` | Resolves the actual association (`user.articles`) from the model |
93
+ | Write tests for a new model | Scaffolds with FactoryBot | Detects your fixture-based suite and matches it |
94
+ | Fix a failing create action | Misses inherited `before_action :authenticate_user!` | Returns parent-controller filters inline with the action source |
95
+ | Build a dashboard page | Invents Tailwind classes from memory | Returns your actual button/card/alert patterns, copy-paste ready |
96
+ | Trace where `can_cook?` is used | Reads 6 files sequentially, still misses callers | Single call: definition + source + every caller + tests |
96
97
 
97
98
  <details>
98
- <summary><strong>How to reproduce these numbers yourself</strong></summary>
99
+ <summary><strong>Verify it on your own app</strong></summary>
99
100
 
100
101
  <br>
101
102
 
103
+ Run these before and after installing to see what changes in *your* codebase:
104
+
102
105
  ```bash
103
- # Schema: full file vs one table
104
- wc -c db/schema.rb
105
- rails 'ai:tool[schema]' table=users | wc -c
106
+ # Schema: does AI know what columns exist?
107
+ rails 'ai:tool[schema]' table=users
106
108
 
107
- # Trace: all files AI reads vs one call
108
- rails 'ai:tool[search_code]' pattern=your_method match_type=trace | wc -c
109
+ # Trace: find every caller of a method across the codebase
110
+ rails 'ai:tool[search_code]' pattern=your_method match_type=trace
111
+
112
+ # Model: associations, scopes, callbacks, concerns — all resolved
113
+ rails 'ai:tool[model_details]' model=User
109
114
 
110
- # Model: raw file + schema vs structured output
111
- wc -c app/models/user.rb db/schema.rb
112
- rails 'ai:tool[model_details]' model=User | wc -c
115
+ # Controllers: action source + inherited filters + strong params in one shot
116
+ rails 'ai:tool[controllers]' controller=UsersController action=create
113
117
  ```
114
118
 
115
- Divide bytes by 4 for rough token count. Bigger apps save more tool output stays focused while raw files grow.
119
+ Compare what AI outputs with and without these tools wired in. The difference is measured in *corrections avoided*, not bytes saved.
116
120
 
117
121
  </details>
118
122
 
@@ -230,7 +234,7 @@ rails 'ai:tool[stimulus]' controller=chart
230
234
 
231
235
  ## 39 Tools
232
236
 
233
- Every tool is **read-only** and returns structured, token-efficient context.
237
+ Every tool is **read-only** and returns data verified against your actual app — not guesses, not training data.
234
238
 
235
239
  <details>
236
240
  <summary><strong>Search & Trace</strong></summary>
@@ -339,6 +343,28 @@ Every tool is **read-only** and returns structured, token-efficient context.
339
343
 
340
344
  <br>
341
345
 
346
+ ## Anti-Hallucination Protocol
347
+
348
+ Every generated context file ships with **6 rules that force AI verification** before writing code. The protocol targets the exact cognitive failures that produce confident-wrong code: statistical priors overriding observed facts, pattern completion beating verification, stale context lies.
349
+
350
+ <details>
351
+ <summary><strong>The 6 rules (shown to AI in every CLAUDE.md / .cursor/rules / .github/instructions)</strong></summary>
352
+
353
+ <br>
354
+
355
+ 1. **Verify before you write.** Never reference a column, association, route, helper, method, class, partial, or gem not verified in THIS project via a tool call in THIS turn. Never invent names that "sound right."
356
+ 2. **Mark every assumption.** If proceeding without verification, prefix with `[ASSUMPTION]`. Silent assumptions forbidden. "I'd need to check X first" is a preferred answer.
357
+ 3. **Training data describes average Rails. This app isn't average.** When something feels "obviously" standard Rails, query anyway. Check `rails_get_conventions` + `rails_get_gems` BEFORE scaffolding.
358
+ 4. **Check the inheritance chain before every edit.** Inherited `before_action` filters, concerns, includes, STI parents. Inheritance is never flat.
359
+ 5. **Empty tool output is information, not permission.** "0 callers found" signals investigation, not license to proceed on guesses.
360
+ 6. **Stale context lies. Re-query after writes.** Earlier tool output may be wrong after edits.
361
+
362
+ Enabled by default. Disable with `config.anti_hallucination_rules = false` if you prefer your own rules.
363
+
364
+ </details>
365
+
366
+ <br>
367
+
342
368
  ## How it works
343
369
 
344
370
  ```
@@ -419,6 +445,7 @@ end
419
445
  | `preset` | `:full` | `:full` (33 introspectors) or `:standard` (19) |
420
446
  | `context_mode` | `:compact` | `:compact` (150 lines) or `:full` |
421
447
  | `generate_root_files` | `true` | Set `false` for split rules only |
448
+ | `anti_hallucination_rules` | `true` | Embed 6-rule verification protocol in generated context files |
422
449
  | `cache_ttl` | `60` | Cache TTL in seconds |
423
450
  | `max_tool_response_chars` | `200_000` | Safety cap for tool responses |
424
451
  | `live_reload` | `:auto` | `:auto`, `true`, or `false` |
@@ -444,7 +471,7 @@ end
444
471
  ## About
445
472
 
446
473
  Built by a Rails developer with 10+ years of production experience.<br>
447
- 1529 tests. 39 tools. 33 introspectors. Standalone or in-Gemfile.<br>
474
+ 1621 tests. 39 tools. 33 introspectors. Standalone or in-Gemfile.<br>
448
475
  MIT licensed. [Contributions welcome.](CONTRIBUTING.md)
449
476
 
450
477
  <br>
data/SECURITY.md CHANGED
@@ -4,6 +4,9 @@
4
4
 
5
5
  | Version | Supported |
6
6
  |---------|--------------------|
7
+ | 4.6.x | :white_check_mark: |
8
+ | 4.5.x | :white_check_mark: |
9
+ | 4.4.x | :white_check_mark: |
7
10
  | 4.3.x | :white_check_mark: |
8
11
  | 4.2.x | :white_check_mark: (4.2.1 includes security hardening) |
9
12
  | 4.1.x | :white_check_mark: |
data/docs/GUIDE.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  > Full documentation for [rails-ai-context](https://github.com/crisnahine/rails-ai-context).
4
4
  > For a quick overview, see the [README](../README.md).
5
+ >
6
+ > **Why this gem exists:** AI coding assistants guess your Rails app. They invent columns,
7
+ > use wrong association names, miss inherited filters, and scaffold tests that don't match
8
+ > your patterns. This gem turns your running app into the source of truth — so agents query
9
+ > real schema, real associations, and real conventions on demand, and write correct code
10
+ > on the first try.
5
11
 
6
12
  ---
7
13
 
@@ -1290,6 +1296,7 @@ end
1290
1296
  | `server_name` | String | `"rails-ai-context"` | MCP server name |
1291
1297
  | `server_version` | String | gem version | MCP server version |
1292
1298
  | `generate_root_files` | Boolean | `true` | Generate root files (CLAUDE.md, etc.) — set `false` for split rules only |
1299
+ | `anti_hallucination_rules` | Boolean | `true` | Embed 6-rule Anti-Hallucination Protocol in generated context files — set `false` to skip |
1293
1300
  | `max_file_size` | Integer | `5_000_000` | Per-file read limit for tools (5MB) |
1294
1301
  | `max_test_file_size` | Integer | `1_000_000` | Test file read limit (1MB) |
1295
1302
  | `max_schema_file_size` | Integer | `10_000_000` | schema.rb / structure.sql parse limit (10MB) |
data/exe/rails-ai-context CHANGED
@@ -6,7 +6,11 @@
6
6
  # may need different versions of those deps (e.g., bigdecimal 4.1.0 activated here
7
7
  # but Gemfile.lock wants 4.0.1). Clear non-default gem activations so Bundler can
8
8
  # resolve cleanly. The $LOAD_PATH entries remain (Bundler.setup replaces them anyway).
9
- if defined?(Gem) && Gem.respond_to?(:loaded_specs)
9
+ #
10
+ # Skip this when running under `bundle exec` — Bundler has already resolved gems
11
+ # correctly, and clearing specs breaks gems that look up their own path at runtime
12
+ # (e.g., MCP SDK reads Gem.loaded_specs["json-schema"].full_gem_path).
13
+ if defined?(Gem) && Gem.respond_to?(:loaded_specs) && !ENV["BUNDLE_BIN_PATH"]
10
14
  Gem.loaded_specs.delete_if { |_, spec| !spec.default_gem? }
11
15
  end
12
16
 
@@ -187,6 +187,11 @@ module RailsAiContext
187
187
  # Whether to generate root files (CLAUDE.md, AGENTS.md, etc.)
188
188
  # Set false to only generate split rules (.claude/rules/, .cursor/rules/, etc.)
189
189
  # config.generate_root_files = true
190
+
191
+ # Anti-Hallucination Protocol: 6-rule verification section embedded in every
192
+ # generated context file. Forces AI to verify facts before writing code.
193
+ # Default: true. Set false to skip the protocol entirely.
194
+ # config.anti_hallucination_rules = true
190
195
  SECTION
191
196
  "Models & Filtering" => <<~SECTION,
192
197
  # ── Models & Filtering ────────────────────────────────────────────
@@ -257,7 +262,6 @@ module RailsAiContext
257
262
  # ── Frontend Framework Detection ─────────────────────────────────
258
263
  # Auto-detected from package.json, config/vite.json, etc. Override only if needed.
259
264
  # config.frontend_paths = ["app/frontend", "../web-client"]
260
- # config.mobile_paths = ["../mobile-app"]
261
265
  SECTION
262
266
  }.freeze
263
267
 
@@ -13,11 +13,12 @@ module RailsAiContext
13
13
  # All YAML-supported keys (explicit allowlist for safety)
14
14
  YAML_KEYS = %i[
15
15
  ai_tools tool_mode preset context_mode generate_root_files claude_max_lines
16
- server_name server_version cache_ttl max_tool_response_chars
16
+ anti_hallucination_rules
17
+ server_name cache_ttl max_tool_response_chars
17
18
  live_reload live_reload_debounce auto_mount http_path http_bind http_port
18
19
  output_dir skip_tools excluded_models excluded_controllers
19
20
  excluded_route_prefixes excluded_filters excluded_middleware excluded_paths
20
- sensitive_patterns search_extensions concern_paths frontend_paths mobile_paths
21
+ sensitive_patterns search_extensions concern_paths frontend_paths
21
22
  max_file_size max_test_file_size max_schema_file_size max_view_total_size
22
23
  max_view_file_size max_search_results max_validate_files
23
24
  query_timeout query_row_limit query_redacted_columns allow_query_in_production
@@ -79,7 +80,11 @@ module RailsAiContext
79
80
  }.freeze
80
81
 
81
82
  # MCP server settings
82
- attr_accessor :server_name, :server_version
83
+ attr_accessor :server_name
84
+
85
+ def server_version
86
+ RailsAiContext::VERSION
87
+ end
83
88
 
84
89
  # Which introspectors to run
85
90
  attr_accessor :introspectors
@@ -129,6 +134,11 @@ module RailsAiContext
129
134
  # When false, only generates split rule files (.claude/rules/, .cursor/rules/, etc.)
130
135
  attr_accessor :generate_root_files
131
136
 
137
+ # Whether to embed the Anti-Hallucination Protocol section in generated context files.
138
+ # Default: true. Set false to skip the 6-rule verification protocol in CLAUDE.md,
139
+ # AGENTS.md, .claude/rules/, .cursor/rules/, .github/instructions/.
140
+ attr_accessor :anti_hallucination_rules
141
+
132
142
  # File size limits (bytes) — increase for larger projects
133
143
  attr_accessor :max_file_size # Per-file read limit for tools (default: 2MB)
134
144
  attr_accessor :max_test_file_size # Test file read limit (default: 500KB)
@@ -151,6 +161,33 @@ module RailsAiContext
151
161
  # Tool invocation mode: :mcp (MCP primary + CLI fallback) or :cli (CLI only)
152
162
  attr_accessor :tool_mode
153
163
 
164
+ DEFAULT_EXCLUDED_FILTERS = %w[
165
+ verify_authenticity_token verify_same_origin_request
166
+ turbo_tracking_request_id handle_unverified_request
167
+ mark_for_same_origin_verification
168
+ ].freeze
169
+
170
+ DEFAULT_EXCLUDED_MIDDLEWARE = %w[
171
+ Rack::Sendfile ActionDispatch::Static ActionDispatch::Executor
172
+ ActionDispatch::ServerTiming Rack::Runtime
173
+ ActionDispatch::RequestId ActionDispatch::RemoteIp
174
+ Rails::Rack::Logger ActionDispatch::ShowExceptions
175
+ ActionDispatch::DebugExceptions ActionDispatch::Callbacks
176
+ ActionDispatch::Cookies ActionDispatch::Session::CookieStore
177
+ ActionDispatch::Flash ActionDispatch::ContentSecurityPolicy::Middleware
178
+ ActionDispatch::PermissionsPolicy::Middleware ActionDispatch::ActionableExceptions
179
+ Rack::Head Rack::ConditionalGet Rack::ETag Rack::TempfileReaper
180
+ ActiveRecord::Migration::CheckPending ActionDispatch::HostAuthorization
181
+ Rack::MethodOverride ActionDispatch::Session::AbstractSecureStore
182
+ ].freeze
183
+
184
+ DEFAULT_EXCLUDED_CONCERNS = [
185
+ /::Generated/,
186
+ /\A(ActiveRecord|ActiveModel|ActiveSupport|ActionText|ActionMailbox|ActiveStorage)/,
187
+ /\A(ActionDispatch|ActionController|ActionView|AbstractController)/,
188
+ /\A(Devise::Models|Devise::Orm|Bullet::|Turbo::|GlobalID::|Rolify::)/
189
+ ].freeze
190
+
154
191
  # Filtering — customize what's hidden from AI output
155
192
  attr_accessor :excluded_controllers # Controller classes hidden from listings (e.g. DeviseController)
156
193
  attr_accessor :excluded_route_prefixes # Route controller prefixes hidden with app_only (e.g. action_mailbox/)
@@ -164,7 +201,6 @@ module RailsAiContext
164
201
 
165
202
  # Frontend framework detection (optional overrides — auto-detected if nil)
166
203
  attr_accessor :frontend_paths # User-declared frontend dirs (e.g. ["app/frontend", "../web-client"])
167
- attr_accessor :mobile_paths # User-declared mobile dirs (e.g. ["../mobile-app"])
168
204
 
169
205
  # Database query tool settings (rails_query)
170
206
  attr_accessor :query_timeout # Statement timeout in seconds (default: 5)
@@ -177,7 +213,6 @@ module RailsAiContext
177
213
 
178
214
  def initialize
179
215
  @server_name = "rails-ai-context"
180
- @server_version = RailsAiContext::VERSION
181
216
  @introspectors = PRESETS[:full].dup
182
217
  @excluded_paths = %w[node_modules tmp log vendor .git doc docs]
183
218
  @sensitive_patterns = %w[
@@ -202,6 +237,7 @@ module RailsAiContext
202
237
  @live_reload = :auto
203
238
  @live_reload_debounce = 1.5
204
239
  @generate_root_files = true
240
+ @anti_hallucination_rules = true
205
241
  @max_file_size = 5_000_000
206
242
  @max_test_file_size = 1_000_000
207
243
  @max_schema_file_size = 10_000_000
@@ -211,30 +247,9 @@ module RailsAiContext
211
247
  @max_validate_files = 50
212
248
  @excluded_controllers = %w[DeviseController Devise::OmniauthCallbacksController]
213
249
  @excluded_route_prefixes = %w[action_mailbox/ active_storage/ rails/ conductor/ devise/ turbo/]
214
- @excluded_concerns = [
215
- /::Generated/,
216
- /\A(ActiveRecord|ActiveModel|ActiveSupport|ActionText|ActionMailbox|ActiveStorage)/,
217
- /\A(ActionDispatch|ActionController|ActionView|AbstractController)/,
218
- /\A(Devise::Models|Devise::Orm|Bullet::|Turbo::|GlobalID::|Rolify::)/
219
- ]
220
- @excluded_filters = %w[
221
- verify_authenticity_token verify_same_origin_request
222
- turbo_tracking_request_id handle_unverified_request
223
- mark_for_same_origin_verification
224
- ]
225
- @excluded_middleware = %w[
226
- Rack::Sendfile ActionDispatch::Static ActionDispatch::Executor
227
- ActionDispatch::ServerTiming Rack::Runtime
228
- ActionDispatch::RequestId ActionDispatch::RemoteIp
229
- Rails::Rack::Logger ActionDispatch::ShowExceptions
230
- ActionDispatch::DebugExceptions ActionDispatch::Callbacks
231
- ActionDispatch::Cookies ActionDispatch::Session::CookieStore
232
- ActionDispatch::Flash ActionDispatch::ContentSecurityPolicy::Middleware
233
- ActionDispatch::PermissionsPolicy::Middleware ActionDispatch::ActionableExceptions
234
- Rack::Head Rack::ConditionalGet Rack::ETag Rack::TempfileReaper
235
- ActiveRecord::Migration::CheckPending ActionDispatch::HostAuthorization
236
- Rack::MethodOverride ActionDispatch::Session::AbstractSecureStore
237
- ]
250
+ @excluded_concerns = DEFAULT_EXCLUDED_CONCERNS.dup
251
+ @excluded_filters = DEFAULT_EXCLUDED_FILTERS.dup
252
+ @excluded_middleware = DEFAULT_EXCLUDED_MIDDLEWARE.dup
238
253
  @custom_tools = []
239
254
  @skip_tools = []
240
255
  @ai_tools = nil
@@ -242,7 +257,6 @@ module RailsAiContext
242
257
  @search_extensions = %w[rb js erb yml yaml json ts tsx vue svelte haml slim]
243
258
  @concern_paths = %w[app/models/concerns app/controllers/concerns]
244
259
  @frontend_paths = nil
245
- @mobile_paths = nil
246
260
  @query_timeout = 5
247
261
  @query_row_limit = 100
248
262
  @query_redacted_columns = %w[
@@ -63,7 +63,7 @@ module RailsAiContext
63
63
  when :routes then Introspectors::RouteIntrospector.new(app)
64
64
  when :jobs then Introspectors::JobIntrospector.new(app)
65
65
  when :gems then Introspectors::GemIntrospector.new(app)
66
- when :conventions then Introspectors::ConventionDetector.new(app)
66
+ when :conventions then Introspectors::ConventionIntrospector.new(app)
67
67
  when :stimulus then Introspectors::StimulusIntrospector.new(app)
68
68
  when :database_stats then Introspectors::DatabaseStatsIntrospector.new(app)
69
69
  when :controllers then Introspectors::ControllerIntrospector.new(app)
@@ -4,7 +4,7 @@ module RailsAiContext
4
4
  module Introspectors
5
5
  # Detects high-level Rails conventions and patterns in use,
6
6
  # giving AI assistants critical context about the app's architecture.
7
- class ConventionDetector
7
+ class ConventionIntrospector
8
8
  attr_reader :app
9
9
 
10
10
  def initialize(app)
@@ -19,34 +19,18 @@ module RailsAiContext
19
19
  # @return [Hash] { written: [paths], skipped: [paths] }
20
20
  def call(output_dir)
21
21
  rules_dir = File.join(output_dir, ".claude", "rules")
22
- FileUtils.mkdir_p(rules_dir)
23
-
24
- written = []
25
- skipped = []
26
22
 
27
23
  files = {
28
- "rails-context.md" => render_context_overview,
29
- "rails-schema.md" => render_schema_reference,
30
- "rails-models.md" => render_models_reference,
31
- "rails-ui-patterns.md" => render_ui_patterns_reference,
32
- "rails-mcp-tools.md" => render_mcp_tools_reference,
33
- "rails-components.md" => render_components_reference,
34
- "rails-accessibility.md" => render_accessibility_reference
24
+ File.join(rules_dir, "rails-context.md") => render_context_overview,
25
+ File.join(rules_dir, "rails-schema.md") => render_schema_reference,
26
+ File.join(rules_dir, "rails-models.md") => render_models_reference,
27
+ File.join(rules_dir, "rails-ui-patterns.md") => render_ui_patterns_reference,
28
+ File.join(rules_dir, "rails-mcp-tools.md") => render_mcp_tools_reference,
29
+ File.join(rules_dir, "rails-components.md") => render_components_reference,
30
+ File.join(rules_dir, "rails-accessibility.md") => render_accessibility_reference
35
31
  }
36
32
 
37
- files.each do |filename, content|
38
- next unless content
39
-
40
- filepath = File.join(rules_dir, filename)
41
- if File.exist?(filepath) && File.read(filepath) == content
42
- skipped << filepath
43
- else
44
- File.write(filepath, content)
45
- written << filepath
46
- end
47
- end
48
-
49
- { written: written, skipped: skipped }
33
+ write_rule_files(files)
50
34
  end
51
35
 
52
36
  private
@@ -74,17 +58,8 @@ module RailsAiContext
74
58
  lines.concat(full_preset_stack_lines)
75
59
 
76
60
  # ApplicationController before_actions — apply to all controllers
77
- begin
78
- root = defined?(Rails) ? Rails.root.to_s : Dir.pwd
79
- app_ctrl_file = File.join(root, "app", "controllers", "application_controller.rb")
80
- if File.exist?(app_ctrl_file)
81
- source = File.read(app_ctrl_file)
82
- before_actions = source.scan(/before_action\s+:([\w!?]+)/).flatten
83
- if before_actions.any?
84
- lines << "" << "**Global before_actions:** #{before_actions.join(', ')}"
85
- end
86
- end
87
- rescue => e; $stderr.puts "[rails-ai-context] Serializer section skipped: #{e.message}"; end
61
+ before_actions = detect_before_actions
62
+ lines << "" << "**Global before_actions:** #{before_actions.join(', ')}" if before_actions.any?
88
63
 
89
64
  lines << ""
90
65
  lines << "ALWAYS use MCP tools for context — do NOT read reference files directly."
@@ -206,7 +181,7 @@ module RailsAiContext
206
181
 
207
182
  # Include scopes so agents know available query methods
208
183
  scopes = data[:scopes] || []
209
- scope_names = scopes.map { |s| s.is_a?(Hash) ? s[:name] : s }
184
+ scope_names = scope_names(scopes)
210
185
  lines << " scopes: #{scope_names.join(', ')}" if scopes.any?
211
186
 
212
187
  # Instance methods — filter Devise/framework internals that add noise
@@ -248,8 +223,7 @@ module RailsAiContext
248
223
 
249
224
  # Shared partials — so agents reuse them instead of recreating
250
225
  begin
251
- root = defined?(Rails) ? Rails.root.to_s : Dir.pwd
252
- shared_dir = File.join(root, "app", "views", "shared")
226
+ shared_dir = File.join(project_root, "app", "views", "shared")
253
227
  if Dir.exist?(shared_dir)
254
228
  partials = Dir.glob(File.join(shared_dir, "_*.html.erb"))
255
229
  .map { |f| File.basename(f) }
@@ -263,8 +237,7 @@ module RailsAiContext
263
237
 
264
238
  # Helpers — so agents use existing helpers instead of creating new ones
265
239
  begin
266
- root = defined?(Rails) ? Rails.root.to_s : Dir.pwd
267
- helper_file = File.join(root, "app", "helpers", "application_helper.rb")
240
+ helper_file = File.join(project_root, "app", "helpers", "application_helper.rb")
268
241
  if File.exist?(helper_file)
269
242
  helper_methods = File.read(helper_file).scan(/def\s+(\w+)/).flatten
270
243
  if helper_methods.any?