rails-ai-bridge 2.0.0 → 2.2.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 (161) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +33 -0
  3. data/CLAUDE.md +4 -4
  4. data/CONTRIBUTING.md +5 -3
  5. data/GEMINI.md +55 -0
  6. data/README.md +135 -22
  7. data/SECURITY.md +4 -1
  8. data/docs/BEST_PRACTICES.md +330 -0
  9. data/docs/GUIDE.md +63 -16
  10. data/docs/mcp-security.md +28 -0
  11. data/docs/review-workflow-report.md +72 -0
  12. data/docs/roadmap-context-assistants.md +4 -2
  13. data/docs/roadmaps.md +12 -2
  14. data/lib/generators/rails_ai_bridge/install/install_generator.rb +23 -2
  15. data/lib/rails_ai_bridge/assistant_formats_preference.rb +1 -1
  16. data/lib/rails_ai_bridge/config/introspection.rb +39 -0
  17. data/lib/rails_ai_bridge/config/mcp.rb +6 -0
  18. data/lib/rails_ai_bridge/configuration.rb +6 -2
  19. data/lib/rails_ai_bridge/doctor/check.rb +17 -0
  20. data/lib/rails_ai_bridge/doctor/checkers/base_checker.rb +55 -0
  21. data/lib/rails_ai_bridge/doctor/checkers/bridge_metadata_checker.rb +20 -0
  22. data/lib/rails_ai_bridge/doctor/checkers/context_files_checker.rb +21 -0
  23. data/lib/rails_ai_bridge/doctor/checkers/controllers_checker.rb +23 -0
  24. data/lib/rails_ai_bridge/doctor/checkers/gems_checker.rb +21 -0
  25. data/lib/rails_ai_bridge/doctor/checkers/i18n_checker.rb +23 -0
  26. data/lib/rails_ai_bridge/doctor/checkers/mcp_buildable_checker.rb +18 -0
  27. data/lib/rails_ai_bridge/doctor/checkers/migrations_checker.rb +23 -0
  28. data/lib/rails_ai_bridge/doctor/checkers/models_checker.rb +23 -0
  29. data/lib/rails_ai_bridge/doctor/checkers/ripgrep_checker.rb +20 -0
  30. data/lib/rails_ai_bridge/doctor/checkers/routes_checker.rb +21 -0
  31. data/lib/rails_ai_bridge/doctor/checkers/schema_checker.rb +21 -0
  32. data/lib/rails_ai_bridge/doctor/checkers/stimulus_mcp_tool_checker.rb +42 -0
  33. data/lib/rails_ai_bridge/doctor/checkers/tests_checker.rb +24 -0
  34. data/lib/rails_ai_bridge/doctor/checkers/view_mcp_tool_checker.rb +42 -0
  35. data/lib/rails_ai_bridge/doctor/checkers/views_checker.rb +23 -0
  36. data/lib/rails_ai_bridge/doctor.rb +24 -190
  37. data/lib/rails_ai_bridge/http_transport_app.rb +5 -0
  38. data/lib/rails_ai_bridge/introspector.rb +1 -0
  39. data/lib/rails_ai_bridge/introspectors/README.md +1 -0
  40. data/lib/rails_ai_bridge/introspectors/model_introspector.rb +76 -3
  41. data/lib/rails_ai_bridge/introspectors/non_ar_models_introspector.rb +210 -0
  42. data/lib/rails_ai_bridge/model_semantic_classifier.rb +165 -0
  43. data/lib/rails_ai_bridge/serializers/context_file_serializer.rb +3 -1
  44. data/lib/rails_ai_bridge/serializers/formatters/base.rb +3 -1
  45. data/lib/rails_ai_bridge/serializers/formatters/providers/base.rb +12 -0
  46. data/lib/rails_ai_bridge/serializers/formatters/providers/claude_footer_formatter.rb +16 -0
  47. data/lib/rails_ai_bridge/serializers/formatters/providers/claude_header_formatter.rb +24 -0
  48. data/lib/rails_ai_bridge/serializers/formatters/{codex_footer_formatter.rb → providers/codex_footer_formatter.rb} +2 -5
  49. data/lib/rails_ai_bridge/serializers/formatters/providers/codex_header_formatter.rb +23 -0
  50. data/lib/rails_ai_bridge/serializers/formatters/{copilot_footer_formatter.rb → providers/copilot_footer_formatter.rb} +2 -5
  51. data/lib/rails_ai_bridge/serializers/formatters/providers/copilot_header_formatter.rb +20 -0
  52. data/lib/rails_ai_bridge/serializers/formatters/{footer_formatter.rb → providers/footer_formatter.rb} +2 -5
  53. data/lib/rails_ai_bridge/serializers/formatters/providers/gemini_footer_formatter.rb +22 -0
  54. data/lib/rails_ai_bridge/serializers/formatters/providers/gemini_header_formatter.rb +28 -0
  55. data/lib/rails_ai_bridge/serializers/formatters/providers/header_formatter.rb +23 -0
  56. data/lib/rails_ai_bridge/serializers/formatters/providers/mcp_guide_formatter.rb +63 -0
  57. data/lib/rails_ai_bridge/serializers/formatters/{rules_footer_formatter.rb → providers/rules_footer_formatter.rb} +2 -5
  58. data/lib/rails_ai_bridge/serializers/formatters/{rules_header_formatter.rb → providers/rules_header_formatter.rb} +2 -6
  59. data/lib/rails_ai_bridge/serializers/formatters/{action_mailbox_formatter.rb → sections/action_mailbox_formatter.rb} +3 -1
  60. data/lib/rails_ai_bridge/serializers/formatters/{action_text_formatter.rb → sections/action_text_formatter.rb} +6 -4
  61. data/lib/rails_ai_bridge/serializers/formatters/sections/active_storage_formatter.rb +29 -0
  62. data/lib/rails_ai_bridge/serializers/formatters/sections/api_formatter.rb +33 -0
  63. data/lib/rails_ai_bridge/serializers/formatters/sections/app_overview_formatter.rb +28 -0
  64. data/lib/rails_ai_bridge/serializers/formatters/sections/assets_formatter.rb +30 -0
  65. data/lib/rails_ai_bridge/serializers/formatters/sections/auth_formatter.rb +29 -0
  66. data/lib/rails_ai_bridge/serializers/formatters/sections/base.rb +12 -0
  67. data/lib/rails_ai_bridge/serializers/formatters/sections/config_formatter.rb +43 -0
  68. data/lib/rails_ai_bridge/serializers/formatters/sections/controllers_formatter.rb +39 -0
  69. data/lib/rails_ai_bridge/serializers/formatters/sections/conventions_formatter.rb +89 -0
  70. data/lib/rails_ai_bridge/serializers/formatters/sections/devops_formatter.rb +37 -0
  71. data/lib/rails_ai_bridge/serializers/formatters/sections/engines_formatter.rb +24 -0
  72. data/lib/rails_ai_bridge/serializers/formatters/sections/gems_formatter.rb +31 -0
  73. data/lib/rails_ai_bridge/serializers/formatters/sections/i18n_formatter.rb +24 -0
  74. data/lib/rails_ai_bridge/serializers/formatters/sections/jobs_formatter.rb +29 -0
  75. data/lib/rails_ai_bridge/serializers/formatters/{middleware_formatter.rb → sections/middleware_formatter.rb} +3 -1
  76. data/lib/rails_ai_bridge/serializers/formatters/{migrations_formatter.rb → sections/migrations_formatter.rb} +3 -1
  77. data/lib/rails_ai_bridge/serializers/formatters/{models_formatter.rb → sections/models_formatter.rb} +3 -1
  78. data/lib/rails_ai_bridge/serializers/formatters/{multi_database_formatter.rb → sections/multi_database_formatter.rb} +3 -1
  79. data/lib/rails_ai_bridge/serializers/formatters/{rake_tasks_formatter.rb → sections/rake_tasks_formatter.rb} +3 -1
  80. data/lib/rails_ai_bridge/serializers/formatters/{routes_formatter.rb → sections/routes_formatter.rb} +3 -1
  81. data/lib/rails_ai_bridge/serializers/formatters/{schema_formatter.rb → sections/schema_formatter.rb} +3 -1
  82. data/lib/rails_ai_bridge/serializers/formatters/{section_formatter.rb → sections/section_formatter.rb} +5 -4
  83. data/lib/rails_ai_bridge/serializers/formatters/{seeds_formatter.rb → sections/seeds_formatter.rb} +3 -1
  84. data/lib/rails_ai_bridge/serializers/formatters/{tests_formatter.rb → sections/tests_formatter.rb} +3 -1
  85. data/lib/rails_ai_bridge/serializers/formatters/{turbo_formatter.rb → sections/turbo_formatter.rb} +3 -1
  86. data/lib/rails_ai_bridge/serializers/formatters/{views_formatter.rb → sections/views_formatter.rb} +3 -1
  87. data/lib/rails_ai_bridge/serializers/markdown_serializer.rb +29 -29
  88. data/lib/rails_ai_bridge/serializers/provider_document_header.rb +63 -0
  89. data/lib/rails_ai_bridge/serializers/providers/base.rb +16 -0
  90. data/lib/rails_ai_bridge/serializers/providers/base_provider_serializer.rb +235 -0
  91. data/lib/rails_ai_bridge/serializers/providers/claude_rules_serializer.rb +290 -127
  92. data/lib/rails_ai_bridge/serializers/providers/claude_serializer.rb +17 -204
  93. data/lib/rails_ai_bridge/serializers/providers/codex_serializer.rb +87 -106
  94. data/lib/rails_ai_bridge/serializers/providers/codex_support_serializer.rb +41 -39
  95. data/lib/rails_ai_bridge/serializers/providers/copilot_instructions_serializer.rb +133 -124
  96. data/lib/rails_ai_bridge/serializers/providers/copilot_serializer.rb +122 -139
  97. data/lib/rails_ai_bridge/serializers/providers/cursor_rules_serializer.rb +216 -213
  98. data/lib/rails_ai_bridge/serializers/providers/gemini_serializer.rb +30 -0
  99. data/lib/rails_ai_bridge/serializers/providers/mcp_tool_reference_formatter.rb +54 -0
  100. data/lib/rails_ai_bridge/serializers/providers/rules_orchestrator.rb +140 -0
  101. data/lib/rails_ai_bridge/serializers/providers/rules_serializer.rb +102 -125
  102. data/lib/rails_ai_bridge/serializers/providers/windsurf_rules_serializer.rb +71 -63
  103. data/lib/rails_ai_bridge/serializers/providers/windsurf_serializer.rb +99 -86
  104. data/lib/rails_ai_bridge/serializers/regeneration_footer.rb +50 -0
  105. data/lib/rails_ai_bridge/serializers/shared_assistant_guidance.rb +47 -0
  106. data/lib/rails_ai_bridge/tasks/rails_ai_bridge.rake +2 -1
  107. data/lib/rails_ai_bridge/tools/base_tool.rb +10 -3
  108. data/lib/rails_ai_bridge/tools/get_config.rb +32 -16
  109. data/lib/rails_ai_bridge/tools/get_controllers.rb +95 -49
  110. data/lib/rails_ai_bridge/tools/get_conventions.rb +74 -56
  111. data/lib/rails_ai_bridge/tools/get_gems.rb +38 -15
  112. data/lib/rails_ai_bridge/tools/get_model_details.rb +105 -12
  113. data/lib/rails_ai_bridge/tools/get_routes.rb +71 -38
  114. data/lib/rails_ai_bridge/tools/get_schema.rb +57 -14
  115. data/lib/rails_ai_bridge/tools/get_stimulus.rb +96 -65
  116. data/lib/rails_ai_bridge/tools/get_test_info.rb +33 -11
  117. data/lib/rails_ai_bridge/tools/get_view/base_formatter.rb +96 -0
  118. data/lib/rails_ai_bridge/tools/get_view/full_formatter.rb +33 -0
  119. data/lib/rails_ai_bridge/tools/get_view/specific_view_formatter.rb +28 -0
  120. data/lib/rails_ai_bridge/tools/get_view/standard_formatter.rb +41 -0
  121. data/lib/rails_ai_bridge/tools/get_view/summary_formatter.rb +33 -0
  122. data/lib/rails_ai_bridge/tools/get_view.rb +13 -167
  123. data/lib/rails_ai_bridge/tools/model_details/full_formatter.rb +10 -5
  124. data/lib/rails_ai_bridge/tools/model_details/non_ar_models_appendix.rb +53 -0
  125. data/lib/rails_ai_bridge/tools/model_details/single_model_formatter.rb +22 -2
  126. data/lib/rails_ai_bridge/tools/model_details/standard_formatter.rb +10 -5
  127. data/lib/rails_ai_bridge/tools/model_details/summary_formatter.rb +16 -6
  128. data/lib/rails_ai_bridge/tools/schema/full_formatter.rb +3 -1
  129. data/lib/rails_ai_bridge/tools/schema/standard_formatter.rb +3 -1
  130. data/lib/rails_ai_bridge/tools/schema/summary_formatter.rb +3 -1
  131. data/lib/rails_ai_bridge/tools/schema/table_formatter.rb +3 -1
  132. data/lib/rails_ai_bridge/tools/search_code/formatter.rb +32 -0
  133. data/lib/rails_ai_bridge/tools/search_code.rb +54 -13
  134. data/lib/rails_ai_bridge/version.rb +1 -1
  135. data/lib/rails_ai_bridge/watcher/bridge_regenerator.rb +31 -0
  136. data/lib/rails_ai_bridge/watcher/watch_directories.rb +27 -0
  137. data/lib/rails_ai_bridge/watcher.rb +18 -20
  138. data/tasks/prd-enhanced-context.md +223 -0
  139. data/tasks/prd-freshness-stamp.md +229 -0
  140. data/tasks/prd-incremental-ci.md +138 -0
  141. data/tasks/prd-overrides-ux.md +308 -0
  142. metadata +86 -39
  143. data/lib/rails_ai_bridge/serializers/formatters/active_storage_formatter.rb +0 -23
  144. data/lib/rails_ai_bridge/serializers/formatters/api_formatter.rb +0 -31
  145. data/lib/rails_ai_bridge/serializers/formatters/app_overview_formatter.rb +0 -22
  146. data/lib/rails_ai_bridge/serializers/formatters/assets_formatter.rb +0 -23
  147. data/lib/rails_ai_bridge/serializers/formatters/auth_formatter.rb +0 -34
  148. data/lib/rails_ai_bridge/serializers/formatters/claude_footer_formatter.rb +0 -31
  149. data/lib/rails_ai_bridge/serializers/formatters/claude_header_formatter.rb +0 -25
  150. data/lib/rails_ai_bridge/serializers/formatters/codex_header_formatter.rb +0 -23
  151. data/lib/rails_ai_bridge/serializers/formatters/config_formatter.rb +0 -23
  152. data/lib/rails_ai_bridge/serializers/formatters/controllers_formatter.rb +0 -48
  153. data/lib/rails_ai_bridge/serializers/formatters/conventions_formatter.rb +0 -24
  154. data/lib/rails_ai_bridge/serializers/formatters/copilot_header_formatter.rb +0 -22
  155. data/lib/rails_ai_bridge/serializers/formatters/devops_formatter.rb +0 -28
  156. data/lib/rails_ai_bridge/serializers/formatters/engines_formatter.rb +0 -27
  157. data/lib/rails_ai_bridge/serializers/formatters/gems_formatter.rb +0 -26
  158. data/lib/rails_ai_bridge/serializers/formatters/header_formatter.rb +0 -24
  159. data/lib/rails_ai_bridge/serializers/formatters/i18n_formatter.rb +0 -22
  160. data/lib/rails_ai_bridge/serializers/formatters/jobs_formatter.rb +0 -35
  161. data/lib/rails_ai_bridge/serializers/formatters/mcp_guide_formatter.rb +0 -59
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f8392971b0bc2f8bf98ebe626062b79e7ff271e8aa009ace229702948862eace
4
- data.tar.gz: d3e358ef11eef6c9050289d73ab69ec5ad09684d7d8e7d8b25b5da4350306c9e
3
+ metadata.gz: 89c1de6e57a12e9e993e3a6648f08829ebd7c59e975e70b33c1b8a73fd9e940d
4
+ data.tar.gz: 24b0733e1c31510a0c8876524cb670ec79ff6b53ed7fad477983ddbeff7d23a2
5
5
  SHA512:
6
- metadata.gz: d174446e69dddabd9f99457af197d607793f26b09ef346f2c27f124be15700fb1b7961e4ba76dd43959d32bfcfe108787c611505043ecf12e61ba7fd1735b7e9
7
- data.tar.gz: 6bb2d7c5290441e76359de520d3e7e737890d3d6456b6e269bfba579c79540a900cccdd872ec580dc5d392c09c6f053e2f0516842aa8e222f0d994111de2b5de
6
+ metadata.gz: 8a42be12f415b7957931b3c88cbd5a7ecf81af08357052b9d7d4c5d5ce20c40c0b93ab57a73c02c337e4fd22297780732b6d1dea073d47972df29d371b26456b
7
+ data.tar.gz: f6b2bc0cec702dc34388dd1606981d8d7169dafa5b35f3715e7dbfb8ac027d651e52d0e5504a7030af9cc92ce9f99d7ee4281e7fed54f6324149c10fc2c84c9d
data/CHANGELOG.md CHANGED
@@ -5,8 +5,41 @@ 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.2.0] - 2026-04-04
9
+
10
+ ### Added
11
+
12
+ - **`non_ar_models` introspector** — Lists Ruby classes under `app/models` that are not ActiveRecord models, tagged **`[POJO/Service]`** in MCP listings and `.claude/rules/rails-models.md`. Context key: `:non_ar_models` with `{ non_ar_models: [{ name, relative_path, tag }] }`. **Not** in `:standard` or `:full` presets (opt in via `config.introspectors << :non_ar_models`). Included in the `domain_metadata` disable category when enabled.
13
+ - **Model semantic classification** — Each ActiveRecord model in introspection output now includes `semantic_tier` (`core_entity`, `pure_join`, `rich_join`, `supporting`) and `semantic_tier_reason` for MCP transparency. Join tables used in `has_many :through` are detected; payload columns beyond FKs and metadata yield `rich_join`.
14
+ - **`config.core_models`** — List model class names to tag as `core_entity` for AI-focused context (initializer comment + `Config::Introspection`).
15
+ - **`RailsAiBridge::ModelSemanticClassifier`** — PORO that computes tiers from columns, `belongs_to` foreign keys, and through-association membership.
16
+ - **`.claude/rules/rails-context.md`** — Semantic layer summary (app metadata + models grouped by tier) for Claude Code, alongside existing split rules.
17
+
18
+ ### Changed
19
+
20
+ - **`rails-context.md` tier lists** — In compact `context_mode`, at most 20 model names per `semantic_tier` with an overflow line referencing `rails_get_model_details(detail:"summary")`; full mode lists all names per tier.
21
+ - **Claude rules `rails-models.md`** — Each model line includes `tier: …` when present.
22
+ - **`rails_get_model_details` formatters** — Summary, standard, full, and single-model views include semantic tier where applicable.
23
+ - **Combustion test setup** — `Combustion.path` is set to `spec/internal`, `Combustion::Database.setup` runs after boot so `:memory:` SQLite has schema before examples, and the internal `ExampleJob` no longer subclasses `ActiveJob::Base` (Active Job is not loaded in the minimal stack).
24
+
8
25
  ## [Unreleased]
9
26
 
27
+ _Targeting **v2.3.0** when Phase 2–3 and final review are done; gem version remains **2.2.0** until that release tag._
28
+
29
+ ## [2.1.0] - 2026-04-02
30
+
31
+ ### Added
32
+
33
+ - **Gemini Support:** Added support for Google's Gemini AI assistant via `GEMINI.md`.
34
+ - **New Rake Task:** Added `rails ai:bridge:gemini` to generate Gemini-specific context.
35
+ - **Context Harmonization:** Refactored all provider serializers (Claude, Gemini, Codex, Copilot, Cursor, Windsurf) to use a shared `BaseProviderSerializer`.
36
+ - **Enhanced AI Guidance:** All context files now feature directive headers, complexity-sorted model lists, and explicit behavioral rules to improve AI code generation.
37
+ - **Improved Metadata:** Context files now include descriptions for key config files and standard maintenance commands (e.g., `rubocop`).
38
+
39
+ ### Changed
40
+
41
+ - **Internal Refactor:** Extracted common rendering logic into `RailsAiBridge::Serializers::Providers::BaseProviderSerializer` to ensure consistency and maintainability across all AI assistants.
42
+
10
43
  ## [2.0.0] - 2026-03-31
11
44
 
12
45
  ### Added
data/CLAUDE.md CHANGED
@@ -8,8 +8,8 @@ structure to AI assistants via the Model Context Protocol (MCP).
8
8
  - `lib/rails_ai_bridge.rb` — Main entry point, public API (Zeitwerk autoloaded)
9
9
  - `lib/rails_ai_bridge/configuration.rb` — User-facing config with presets (:standard, :full)
10
10
  - `lib/rails_ai_bridge/introspector.rb` — Orchestrates sub-introspectors
11
- - `lib/rails_ai_bridge/introspectors/` — 27 introspectors (schema, models, routes, jobs, gems, conventions, stimulus, database_stats, controllers, views, turbo, i18n, config, active_storage, action_text, auth, api, tests, rake_tasks, assets, devops, action_mailbox, migrations, seeds, middleware, engines, multi_database)
12
- - `lib/rails_ai_bridge/tools/` — 9 MCP tools using the official mcp SDK
11
+ - `lib/rails_ai_bridge/introspectors/` — Built-in introspector classes; `:standard` preset runs **9**, `:full` runs **26** (see `Configuration::PRESETS`). Registry: `Introspector::BUILTIN_INTROSPECTORS` (includes opt-in symbols such as `database_stats`, `non_ar_models` not listed in those presets).
12
+ - `lib/rails_ai_bridge/tools/` — 11 built-in MCP tools using the official mcp SDK (hosts can add more via `additional_tools`)
13
13
  - `lib/rails_ai_bridge/serializers/` — Output formatters (claude, claude_rules, cursor_rules, windsurf, windsurf_rules, copilot, copilot_instructions, rules, markdown, JSON)
14
14
  - `lib/rails_ai_bridge/resources.rb` — MCP resources (static data AI clients read directly)
15
15
  - `lib/rails_ai_bridge/server.rb` — MCP server configuration (stdio + HTTP transports)
@@ -30,7 +30,7 @@ structure to AI assistants via the Model Context Protocol (MCP).
30
30
  6. **Diff-aware** — context regeneration skips unchanged files
31
31
  7. **Per-assistant serializers** — each AI tool gets tailored output format
32
32
  8. **Zeitwerk autoloading** — files loaded on-demand, not all upfront
33
- 9. **Introspector presets** — `:standard` (9 core) default, `:full` (26) for power users
33
+ 9. **Introspector presets** — `:standard` (9 core) default, `:full` (26 introspectors; optional extras such as `database_stats`, `non_ar_models`) for power users
34
34
  10. **MCP auto-discovery** — `.mcp.json` generated by install generator
35
35
  11. **Compact by default** — context files ≤150 lines, MCP tools use `detail` parameter (summary/standard/full)
36
36
  12. **Per-tool split rules** — `.claude/rules/`, `.cursor/rules/`, `.windsurf/rules/`, `.github/instructions/`
@@ -38,7 +38,7 @@ structure to AI assistants via the Model Context Protocol (MCP).
38
38
  ## Testing
39
39
 
40
40
  ```bash
41
- bundle exec rspec # Run specs (364 examples)
41
+ bundle exec rspec # Run specs
42
42
  bundle exec rubocop # Lint
43
43
  ```
44
44
 
data/CONTRIBUTING.md CHANGED
@@ -18,8 +18,8 @@ The test suite uses [Combustion](https://github.com/pat/combustion) to boot a mi
18
18
 
19
19
  ```
20
20
  lib/rails_ai_bridge/
21
- ├── introspectors/ # 27 introspectors (schema, models, routes, etc.)
22
- ├── tools/ # 9 MCP tools with detail levels and pagination
21
+ ├── introspectors/ # Built-in introspectors (schema, models, non_ar_models, routes, )
22
+ ├── tools/ # 11 built-in MCP tools (detail levels, pagination, extensible)
23
23
  ├── serializers/ # Per-assistant formatters (claude, cursor, windsurf, copilot, JSON)
24
24
  ├── server.rb # MCP server setup (stdio + HTTP)
25
25
  ├── engine.rb # Rails Engine for auto-integration
@@ -30,7 +30,7 @@ lib/rails_ai_bridge/
30
30
 
31
31
  1. Create `lib/rails_ai_bridge/introspectors/your_introspector.rb` (auto-loaded by Zeitwerk)
32
32
  2. Implement `#initialize(app)` and `#call` → returns a Hash (never raises)
33
- 3. Register it in `lib/rails_ai_bridge/introspector.rb` (the `INTROSPECTOR_MAP`)
33
+ 3. Register it in `lib/rails_ai_bridge/introspector.rb` (`BUILTIN_INTROSPECTORS`)
34
34
  4. Add the key to the appropriate preset(s) in `Configuration::PRESETS` (`:standard` for core, `:full` for all)
35
35
  5. Write specs in `spec/lib/rails_ai_bridge/your_introspector_spec.rb`
36
36
 
@@ -45,6 +45,8 @@ lib/rails_ai_bridge/
45
45
  ## Code Style
46
46
 
47
47
  - Follow `rubocop-rails-omakase` style (run `bundle exec rubocop`)
48
+ - Optional complexity check: `bundle exec skunk lib/rails_ai_bridge/…` (gem in `:development`/`:test`) — keep new or refactored files lean (project goal: Skunk score around **≤ 25** where practical).
49
+
48
50
  - Ruby 3.2+ features welcome (pattern matching, etc.)
49
51
  - Every introspector must return a Hash and never raise — wrap errors in `{ error: msg }`
50
52
  - MCP tools return `MCP::Tool::Response` objects
data/GEMINI.md ADDED
@@ -0,0 +1,55 @@
1
+ # GEMINI.md — rails-ai-bridge development guide
2
+
3
+ This is a Ruby gem that auto-introspects Rails applications and exposes their
4
+ structure to AI assistants via the Model Context Protocol (MCP).
5
+
6
+ ## Architecture
7
+
8
+ - `lib/rails_ai_bridge.rb` — Main entry point, public API (Zeitwerk autoloaded)
9
+ - `lib/rails_ai_bridge/configuration.rb` — User-facing config with presets (:standard, :full)
10
+ - `lib/rails_ai_bridge/introspector.rb` — Orchestrates sub-introspectors
11
+ - `lib/rails_ai_bridge/introspectors/` — Built-in introspector classes; `:standard` preset runs **9**, `:full` runs **26** (see `Configuration::PRESETS`). Registry: `Introspector::BUILTIN_INTROSPECTORS` (includes opt-in symbols such as `database_stats`, `non_ar_models` not listed in those presets).
12
+ - `lib/rails_ai_bridge/tools/` — 11 built-in MCP tools using the official mcp SDK (hosts can add more via `additional_tools`)
13
+ - `lib/rails_ai_bridge/serializers/` — Output formatters (claude, claude_rules, cursor_rules, windsurf, windsurf_rules, copilot, copilot_instructions, rules, markdown, JSON, gemini)
14
+ - `lib/rails_ai_bridge/resources.rb` — MCP resources (static data AI clients read directly)
15
+ - `lib/rails_ai_bridge/server.rb` — MCP server configuration (stdio + HTTP transports)
16
+ - `lib/rails_ai_bridge/middleware.rb` — Rack middleware for auto-mounting MCP HTTP endpoint
17
+ - `lib/rails_ai_bridge/fingerprinter.rb` — SHA256 file fingerprinting for cache invalidation
18
+ - `lib/rails_ai_bridge/doctor.rb` — Diagnostic checks and AI readiness scoring
19
+ - `lib/rails_ai_bridge/watcher.rb` — File watcher for auto-regenerating context files
20
+ - `lib/rails_ai_bridge/engine.rb` — Rails Engine for auto-integration
21
+ - `lib/generators/rails_ai_bridge/install/` — Install generator (creates .mcp.json, initializer, context files)
22
+
23
+ ## Key Design Decisions
24
+
25
+ 1. **Built on official mcp SDK** — not a custom protocol implementation
26
+ 2. **Zero-config** — Railtie auto-registers at boot, introspects without setup
27
+ 3. **Graceful degradation** — works without DB by parsing schema.rb as text
28
+ 4. **Read-only tools only** — all MCP tools are annotated as non-destructive
29
+ 5. **Dual output** — static files (GEMINI.md) + live MCP server (stdio/HTTP)
30
+ 6. **Diff-aware** — context regeneration skips unchanged files
31
+ 7. **Per-assistant serializers** — each AI tool gets tailored output format
32
+ 8. **Zeitwerk autoloading** — files loaded on-demand, not all upfront
33
+ 9. **Introspector presets** — `:standard` (9 core) default, `:full` (26 introspectors; optional extras such as `database_stats`) for power users
34
+ 10. **MCP auto-discovery** — `.mcp.json` generated by install generator
35
+ 11. **Compact by default** — context files ≤150 lines, MCP tools use `detail` parameter (summary/standard/full)
36
+ 12. **Per-tool split rules** — `.claude/rules/`, `.cursor/rules/`, `.windsurf/rules/`, `.github/instructions/`
37
+
38
+ ## Testing
39
+
40
+ ```bash
41
+ bundle exec rspec # Run specs (364 examples)
42
+ bundle exec rubocop # Lint
43
+ ```
44
+
45
+ Uses combustion gem for testing Rails engine behavior in isolation.
46
+
47
+ ## Conventions
48
+
49
+ - Ruby 3.2+ features OK (pattern matching, etc.)
50
+ - Follow rubocop-rails-omakase style
51
+ - Every introspector returns a Hash, never raises (wraps errors in `{ error: msg }`)
52
+ - MCP tools return `MCP::Tool::Response` objects per SDK convention
53
+ - All tools prefixed with `rails_` per MCP naming best practices
54
+ - `generate_context` returns `{ written: [], skipped: [] }` hash
55
+ - Zeitwerk autoloads all files — no `require_relative` needed for new classes
data/README.md CHANGED
@@ -7,6 +7,7 @@
7
7
  [![Gem Version](https://badge.fury.io/rb/rails-ai-bridge.svg)](https://rubygems.org/gems/rails-ai-bridge)
8
8
  [![CI](https://github.com/igmarin/rails-ai-bridge/actions/workflows/ci.yml/badge.svg)](https://github.com/igmarin/rails-ai-bridge/actions)
9
9
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
10
+ ![CodeRabbit Pull Request Reviews](https://img.shields.io/coderabbit/prs/github/igmarin/rails-ai-bridge?utm_source=oss&utm_medium=github&utm_campaign=igmarin%2Frails-ai-bridge&labelColor=171717&color=FF570A&link=https%3A%2F%2Fcoderabbit.ai&label=CodeRabbit+Reviews)
10
11
 
11
12
  ---
12
13
 
@@ -31,9 +32,9 @@ flowchart LR
31
32
  app --> intro --> mcp --> clients
32
33
  ```
33
34
 
34
- 1. **Up to 27 introspectors** scan schema, models, routes, controllers, jobs, gems, conventions, and more (preset `:standard` runs 9 core ones by default; `:full` runs all).
35
- 2. **`rails ai:bridge`** writes bounded bridge files for Claude, Cursor, Copilot, Codex, Windsurf, and JSON.
36
- 3. **`rails ai:serve`** exposes **9 MCP tools** so assistants pull detail on demand (`detail: "summary"` first, then drill down).
35
+ 1. **Up to 26 introspectors** in the `:full` preset scan schema, models, routes, controllers, jobs, gems, conventions, and more (`:standard` runs 9 core ones by default). Opt-in extras (e.g. `non_ar_models`, `database_stats`) are not in those presets.
36
+ 2. **`rails ai:bridge`** writes bounded bridge files for Claude, Cursor, Copilot, Codex, Windsurf, Gemini, and JSON.
37
+ 3. **`rails ai:serve`** exposes **11 built-in MCP tools** (plus any `additional_tools`) so assistants pull detail on demand (`detail: "summary"` first, then drill down).
37
38
 
38
39
  ### Folder guides
39
40
 
@@ -94,7 +95,7 @@ The install generator creates **`.mcp.json`** (MCP auto-discovery) and generates
94
95
  | Zero config | Yes — Railtie + install generator | No — per-project `projects.yml` | No |
95
96
  | Token optimization | Yes — compact files + `detail:"summary"` workflow | Varies | No |
96
97
  | Codex-oriented repo files | Yes — `AGENTS.md`, `.codex/README.md` | No | DIY |
97
- | Live MCP tools | Yes — 9 read-only `rails_*` tools | Yes | No |
98
+ | Live MCP tools | Yes — 11 read-only `rails_*` tools (extensible) | Yes | No |
98
99
  | Auto-introspection | Yes — up to **27** domains (`:full`) | No — server points at projects you configure | DIY |
99
100
 
100
101
  *Comparison reflects typical documented setups; verify against each project before treating any row as absolute.*
@@ -111,8 +112,9 @@ your-rails-app/
111
112
  ├── 🟣 Claude Code
112
113
  │ ├── CLAUDE.md ≤150 lines (compact)
113
114
  │ └── .claude/rules/
115
+ │ ├── rails-context.md semantic layer (compact: capped per tier + MCP hint)
114
116
  │ ├── rails-schema.md table listing
115
- │ ├── rails-models.md model listing
117
+ │ ├── rails-models.md model listing (includes semantic tier)
116
118
  │ └── rails-mcp-tools.md full tool reference
117
119
 
118
120
  ├── 🟡 OpenAI Codex
@@ -142,6 +144,9 @@ your-rails-app/
142
144
  │ ├── rails-controllers.instructions.md applyTo: app/controllers/**
143
145
  │ └── rails-mcp-tools.instructions.md applyTo: **/*
144
146
 
147
+ ├── 🔴 Gemini
148
+ │ └── GEMINI.md directive briefing + MCP guide
149
+
145
150
  ├── 📋 .ai-context.json full JSON (programmatic)
146
151
  └── .mcp.json MCP auto-discovery
147
152
  ```
@@ -157,7 +162,8 @@ Each file respects the AI tool's format and size limits. **Commit these files**
157
162
  | Category | What's introspected |
158
163
  |----------|-------------------|
159
164
  | **Database** | Every table, column, index, foreign key, and migration |
160
- | **Models** | Associations, validations, scopes, enums, callbacks, concerns, macros (`has_secure_password`, `encrypts`, `normalizes`, etc.) |
165
+ | **Models** | Associations, validations, scopes, enums, callbacks, concerns, macros (`has_secure_password`, `encrypts`, `normalizes`, etc.), **semantic tier** (`core_entity`, `pure_join`, `rich_join`, `supporting`) |
166
+ | **Non-AR Models** | Ruby classes under `app/models` that aren't ActiveRecord, tagged as `[POJO/Service]` (opt-in via `:non_ar_models` introspector) |
161
167
  | **Routing** | Every route with HTTP verbs, paths, controller actions, API namespaces |
162
168
  | **Controllers** | Actions, filters, strong params, concerns, API controllers |
163
169
  | **Views** | Layouts, templates, partials, helpers, template engines, view components |
@@ -171,25 +177,27 @@ Each file respects the AI tool's format and size limits. **Commit these files**
171
177
  | **DevOps** | Puma, Procfile, Docker, deployment tools, asset pipeline |
172
178
  | **Architecture** | Service objects, STI, polymorphism, state machines, multi-tenancy, engines |
173
179
 
174
- 27 introspectors total. The `:standard` preset runs 9 core ones by default; use `:full` for all 27.
180
+ The `:full` preset runs 26 introspectors. The `:standard` preset runs 9 core ones by default. Add symbols such as `:non_ar_models` or `:database_stats` to `config.introspectors` when you need them.
175
181
 
176
182
  ---
177
183
 
178
184
  ## MCP Tools
179
185
 
180
- The gem exposes **9 live tools** via MCP that AI clients call on-demand:
186
+ The gem exposes **11 built-in tools** via MCP that AI clients call on-demand (hosts can append more via `config.additional_tools`):
181
187
 
182
188
  | Tool | What it returns |
183
189
  |------|----------------|
184
190
  | `rails_get_schema` | Tables, columns, indexes, foreign keys |
185
- | `rails_get_model_details` | Associations, validations, scopes, enums, callbacks |
191
+ | `rails_get_model_details` | Associations, validations, scopes, enums, callbacks, semantic tier, non-AR models (when enabled) |
186
192
  | `rails_get_routes` | HTTP verbs, paths, controller actions |
187
193
  | `rails_get_controllers` | Actions, filters, strong params, concerns |
188
194
  | `rails_get_config` | Cache, session, timezone, middleware, initializers |
189
195
  | `rails_get_test_info` | Test framework, factories, CI config, coverage |
190
196
  | `rails_get_gems` | Notable gems categorized by function |
191
197
  | `rails_get_conventions` | Architecture patterns, directory structure |
192
- | `rails_search_code` | Ripgrep-powered regex search across the codebase |
198
+ | `rails_search_code` | Ripgrep (or Ruby) search under `Rails.root` with allowlisted extensions, pattern size cap, and optional wall-clock timeout |
199
+ | `rails_get_view` | View layouts, templates, partials; optional per-file detail under `app/views` |
200
+ | `rails_get_stimulus` | Stimulus controllers: targets, values, actions, outlets (requires `:stimulus` introspector) |
193
201
 
194
202
  All tools are **read-only** — they never modify your application or database.
195
203
 
@@ -280,12 +288,14 @@ RailsAiBridge.configure do |config|
280
288
  # Production only: explicit opt-in + token required (see SECURITY.md)
281
289
  # config.allow_auto_mount_in_production = true
282
290
  config.http_path = "/mcp"
291
+ # Optional: reject HTTP requests when no Bearer/JWT/static auth is configured (safer beyond localhost)
292
+ # config.mcp.require_http_auth = true
283
293
  end
284
294
  ```
285
295
 
286
296
  Clients must send `Authorization: Bearer <token>` when a token is configured.
287
297
 
288
- Security note: keep the HTTP transport bound to `127.0.0.1` unless you add your own network and authentication controls. The tools are read-only, but they can still expose sensitive application structure. In **production**, `rails ai:serve_http` and `auto_mount` require a configured MCP token; `auto_mount` also requires `allow_auto_mount_in_production = true`.
298
+ Security note: keep the HTTP transport bound to `127.0.0.1` unless you add your own network and authentication controls. The tools are read-only, but they can still expose sensitive application structure. In **production**, `rails ai:serve_http` and `auto_mount` require a configured MCP token; `auto_mount` also requires `allow_auto_mount_in_production = true`. For operational hardening (tokens, proxies, `require_http_auth`, stdio threat model), see **[docs/mcp-security.md](docs/mcp-security.md)** and **[SECURITY.md](SECURITY.md)**.
289
299
  </details>
290
300
 
291
301
  ---
@@ -301,16 +311,96 @@ Codex support is centered on **`AGENTS.md`** at the repository root.
301
311
 
302
312
  ---
303
313
 
314
+ ## Best Practices
315
+
316
+ > See **[docs/BEST_PRACTICES.md](docs/BEST_PRACTICES.md)** for the full guide — including a client compatibility matrix, token optimization patterns, staleness management, and per-assistant workflow tips.
317
+
318
+ After testing with Cursor, Windsurf, Copilot, Codex, and Claude Code in real projects, these patterns consistently produce the best results.
319
+
320
+ ### Layer 1: Commit your static files
321
+
322
+ The generated files (`.cursorrules`, `.cursor/rules/`, `AGENTS.md`, `.windsurfrules`, `CLAUDE.md`, `.github/copilot-instructions.md`) are loaded **passively** by AI tools on every session start — giving the assistant immediate project grounding before it reads a single line of your code.
323
+
324
+ **Always commit these files.** The whole team benefits, not just the developer who ran `rails ai:bridge`.
325
+
326
+ ### Layer 2: Run the MCP server
327
+
328
+ Static files cover overview. The MCP server covers depth. When an assistant needs full schema details, specific model associations, or a filtered route listing, the `rails_*` tools fetch live data on demand — without inflating your initial context window.
329
+
330
+ The combination is additive:
331
+
332
+ | Setup | What you get |
333
+ |-------|-------------|
334
+ | Static files only | Passive overview: project structure always loaded |
335
+ | MCP server only | On-demand depth: accurate live data, no passive grounding |
336
+ | **Both (recommended)** | **Passive overview + on-demand depth = best coverage** |
337
+
338
+ This is the pattern that consistently outperforms either layer alone. The files reduce orientation overhead; the server handles the details when the assistant actually needs them.
339
+
340
+ ### Keep files fresh — regenerate after every significant change
341
+
342
+ Static files are snapshots. An assistant working from a schema that is 20 commits out of date will still make assumptions based on the old structure. After any significant change — a new model, a migration, a refactor, a feature merged — run:
343
+
344
+ ```bash
345
+ rails ai:bridge
346
+ ```
347
+
348
+ **Rule of thumb:** treat `rails ai:bridge` the same way you treat `bundle install` after a `Gemfile` change — a routine step, not a one-time setup. Commit the regenerated files alongside the code change so the whole team stays in sync.
349
+
350
+ #### Auto-regeneration during active development
351
+
352
+ ```bash
353
+ rails ai:watch
354
+ ```
355
+
356
+ Watches for file changes and regenerates relevant context files automatically. Useful when you are actively adding models, routes, or controllers and want the assistant to track along in the same session.
357
+
358
+ ### Use `detail: "summary"` first with the MCP server
359
+
360
+ When the MCP server is running, start broad and drill down:
361
+
362
+ ```
363
+ 1. rails_get_schema(detail: "summary") → all tables, no noise
364
+ 2. rails_get_schema(table: "orders") → full detail for one table
365
+ 3. rails_get_model_details(model: "Order") → associations, validations, scopes
366
+ ```
367
+
368
+ This keeps token usage low and answer quality high. Requesting full detail on every table at once is rarely necessary and wastes context on data the assistant does not need yet.
369
+
370
+ ### Pick the right preset for your app
371
+
372
+ | Preset | Introspectors | Best for |
373
+ |--------|--------------|---------|
374
+ | `:standard` (default) | 9 core | Most apps — schema, models, routes, jobs, gems, conventions |
375
+ | `:full` | 26 | Full-stack apps where frontend, auth, API, and DevOps context matter |
376
+
377
+ Add individual introspectors on top of a preset for targeted additions:
378
+
379
+ ```ruby
380
+ config.preset = :standard
381
+ config.introspectors += %i[non_ar_models views auth api]
382
+ ```
383
+
384
+ ### Check your readiness score
385
+
386
+ ```bash
387
+ rails ai:doctor
388
+ ```
389
+
390
+ Prints a 0–100 AI readiness score and flags anything missing: `.mcp.json`, generated context files, MCP token in production, and more. Run it after initial setup and after major configuration changes.
391
+
392
+ ---
393
+
304
394
  ## Configuration
305
395
 
306
396
  ```ruby
307
397
  # config/initializers/rails_ai_bridge.rb
308
398
  RailsAiBridge.configure do |config|
309
- # Presets: :standard (9 introspectors, default) or :full (all 27)
399
+ # Presets: :standard (9 introspectors, default) or :full (26). Add :non_ar_models etc. as needed.
310
400
  config.preset = :standard
311
401
 
312
402
  # Cherry-pick on top of a preset
313
- # config.introspectors += %i[views turbo auth api]
403
+ # config.introspectors += %i[non_ar_models views turbo auth api]
314
404
 
315
405
  # Context mode: :compact (≤150 lines, default) or :full (dump everything)
316
406
  # config.context_mode = :compact
@@ -318,6 +408,9 @@ RailsAiBridge.configure do |config|
318
408
  # Exclude models from introspection
319
409
  config.excluded_models += %w[AdminUser InternalAuditLog]
320
410
 
411
+ # Tag primary domain models as core_entity (semantic context for AI + Claude rules)
412
+ # config.core_models += %w[User Order Project]
413
+
321
414
  # Exclude paths from code search
322
415
  config.excluded_paths += %w[vendor/bundle]
323
416
 
@@ -337,11 +430,18 @@ end
337
430
  | `claude_max_lines` | `150` | Max lines for CLAUDE.md in compact mode |
338
431
  | `max_tool_response_chars` | `120_000` | Safety cap for MCP tool responses |
339
432
  | `excluded_models` | internal Rails models | Models to skip during introspection |
433
+ | `core_models` | `[]` | Model names tagged as `core_entity` in introspection and `.claude/rules/` |
340
434
  | `excluded_paths` | `node_modules tmp log vendor .git` | Paths excluded from code search |
341
435
  | `auto_mount` | `false` | Auto-mount HTTP MCP endpoint |
342
436
  | `allow_auto_mount_in_production` | `false` | Allow `auto_mount` in production (requires MCP token) |
343
437
  | `http_mcp_token` | `nil` | Bearer token for HTTP MCP; `ENV["RAILS_AI_BRIDGE_MCP_TOKEN"]` overrides when set |
344
438
  | `search_code_allowed_file_types` | `[]` | Extra extensions allowed for `rails_search_code` `file_type` |
439
+ | `search_code_pattern_max_bytes` | `2048` | Maximum `pattern` size (bytes) for `rails_search_code` |
440
+ | `search_code_timeout_seconds` | `5.0` | Wall-clock limit per search (`0` disables); mitigates runaway regex / CPU |
441
+ | `require_http_auth` | `false` | When `true`, HTTP MCP returns `401` if no Bearer/JWT/static auth is configured |
442
+ | `rate_limit_max_requests` | `nil` (profile default) | Per-IP sliding window ceiling (`0` disables); not shared across workers |
443
+ | `rate_limit_window_seconds` | `60` | Sliding window length for HTTP rate limiting |
444
+ | `http_log_json` | `false` | One JSON log line per HTTP MCP response when enabled |
345
445
  | `expose_credentials_key_names` | `false` | Include `credentials_keys` in config introspection / `rails://config` |
346
446
  | `additional_introspectors` | `{}` | Optional custom introspector classes keyed by symbol |
347
447
  | `additional_tools` | `[]` | Optional MCP tool classes appended to the built-in toolset |
@@ -349,6 +449,8 @@ end
349
449
  | `http_path` | `"/mcp"` | HTTP endpoint path |
350
450
  | `http_port` | `6029` | HTTP server port |
351
451
  | `cache_ttl` | `30` | Cache TTL in seconds |
452
+
453
+ Other HTTP MCP knobs live only on the nested object, for example `RailsAiBridge.configuration.mcp.authorize`, `mcp.mode`, `mcp.security_profile`, and `mcp.require_auth_in_production` — see [docs/GUIDE.md](docs/GUIDE.md) and [docs/mcp-security.md](docs/mcp-security.md).
352
454
  </details>
353
455
 
354
456
  ### Extending the built-ins
@@ -402,6 +504,7 @@ Frontend introspectors (views, Turbo, Stimulus, assets) degrade gracefully — t
402
504
  | `rails ai:bridge:cursor` | Generate Cursor files only |
403
505
  | `rails ai:bridge:windsurf` | Generate Windsurf files only |
404
506
  | `rails ai:bridge:copilot` | Generate Copilot files only |
507
+ | `rails ai:bridge:gemini` | Generate Gemini files only |
405
508
  | `rails ai:serve` | Start MCP server (stdio) |
406
509
  | `rails ai:serve_http` | Start MCP server (HTTP) |
407
510
  | `rails ai:doctor` | Run diagnostics and AI readiness score (0-100) |
@@ -442,23 +545,33 @@ The gem parses `db/schema.rb` as text when no database is connected. Works in CI
442
545
 
443
546
  ---
444
547
 
548
+ ## Documentation
549
+
550
+ | Document | Description |
551
+ |----------|-------------|
552
+ | [docs/GUIDE.md](docs/GUIDE.md) | Full reference — every command, option, MCP parameter, and AI assistant setup |
553
+ | [docs/BEST_PRACTICES.md](docs/BEST_PRACTICES.md) | Client compatibility matrix, token optimization, staleness management, per-assistant tips |
554
+ | [docs/mcp-security.md](docs/mcp-security.md) | MCP HTTP hardening — tokens, `require_http_auth`, rate limits, proxies, stdio model |
555
+ | [UPGRADING.md](UPGRADING.md) | Migration guide when upgrading between major versions |
556
+ | [CHANGELOG.md](CHANGELOG.md) | Full version history and release notes |
557
+ | [CONTRIBUTING.md](CONTRIBUTING.md) | Dev setup, adding introspectors/tools, PR process, and release checklist |
558
+ | [SECURITY.md](SECURITY.md) | Security policy, vulnerability reporting, design notes, and HTTP MCP authentication |
559
+ | [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) | Community standards |
560
+
561
+ ---
562
+
445
563
  ## Contributing
446
564
 
447
565
  ```bash
448
566
  git clone https://github.com/igmarin/rails-ai-bridge.git
449
567
  cd rails-ai-bridge && bundle install
450
- bundle exec rspec # runs the full suite; SimpleCov runs locally by default
451
- bundle exec rubocop # Lint
568
+ bundle exec rspec # runs the full suite (SimpleCov enforces ≥80% coverage)
569
+ bundle exec rubocop # lint
452
570
  ```
453
571
 
454
- ### Test coverage (SimpleCov)
455
-
456
- - Running `bundle exec rspec` locally enables **SimpleCov** and enforces **at least 80% line coverage** across `lib/**/*.rb` (see [`spec/simplecov_helper.rb`](spec/simplecov_helper.rb)).
457
- - After the run, open **`coverage/index.html`** in a browser for a per-file report (`coverage/` is gitignored).
458
- - CI runs coverage enforcement on **one matrix job** (Ruby **3.3** + Rails **8.0**) with `COVERAGE=true` and uploads the HTML report as a workflow artifact for inspection on PRs.
459
- - For a **prioritized backlog of files below 80%** (refreshed after substantive test work), see [`docs/COVERAGE.md`](docs/COVERAGE.md).
572
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for the full guide: adding introspectors, adding MCP tools, code style rules, PR process, and the maintainer release checklist.
460
573
 
461
- Bug reports and pull requests for this fork are handled at [github.com/igmarin/rails-ai-bridge](https://github.com/igmarin/rails-ai-bridge).
574
+ Bug reports and pull requests: [github.com/igmarin/rails-ai-bridge/issues](https://github.com/igmarin/rails-ai-bridge/issues)
462
575
 
463
576
  ## Acknowledgments & Origins
464
577
 
data/SECURITY.md CHANGED
@@ -27,17 +27,20 @@ This fork is maintained by **Ismael Marin**. If you discover a security vulnerab
27
27
  - Code search (`rails_search_code`) uses `Open3.capture2` with array arguments to prevent shell injection.
28
28
  - File paths are validated against path traversal attacks, and invalid regex input now returns a controlled tool response in the Ruby fallback path.
29
29
  - Search is limited to an **allowlisted set of file extensions** by default; arbitrary extensions (e.g. `key`, `pem`, `env`) are rejected. See `config.search_code_allowed_file_types` to extend the list.
30
+ - `rails_search_code` caps **pattern length** (`config.search_code_pattern_max_bytes`, default 2048) and applies an optional **wall-clock timeout** per invocation (`config.search_code_timeout_seconds`, default 5; `0` disables).
30
31
  - Credential **values** are never exposed. Top-level **key names** from encrypted credentials are omitted from introspection and the `rails://config` resource by default; set `config.expose_credentials_key_names = true` only if you accept that metadata exposure.
31
32
  - The gem does not make any outbound network requests.
32
33
  - The main risk is **information exposure**, not mutation: schema names, routes, controller structure, and code excerpts may still be sensitive in some environments.
33
34
 
34
35
  ## HTTP MCP authentication
35
36
 
37
+ For day-to-day hardening (tokens, `require_http_auth`, proxies, stdio threat model), see **[docs/mcp-security.md](docs/mcp-security.md)**.
38
+
36
39
  - **Shared secret:** set `config.http_mcp_token` and/or `ENV["RAILS_AI_BRIDGE_MCP_TOKEN"]` (**ENV overrides** the config value when set). Clients send `Authorization: Bearer <token>`.
37
40
  - **Custom resolver / JWT:** configure `config.mcp_token_resolver` or `config.mcp_jwt_decoder` (see [docs/GUIDE.md](docs/GUIDE.md)); clients still use a Bearer header; the gem does not ship a JWT library — you verify and decode inside your lambda.
38
41
  - **Rack env context:** after a successful auth, `env["rails_ai_bridge.mcp.context"]` may contain **PII or claims** (e.g. JWT payload). Do not dump full Rack `env` to logs or APM; treat this key like session-derived data.
39
42
  - When **no** auth mechanism is configured, HTTP MCP is **unauthenticated** (backward compatible for local use); configure one of the above before exposing the port beyond localhost.
40
- - **Misconfiguration guard:** setting `:bearer_token` strategy without a `token_resolver` and without a static token causes **boot failure** (`ConfigurationError`) so the endpoint cannot start in an accidentally open state.
43
+ - **`require_http_auth`:** set `config.require_http_auth = true` (or `config.mcp.require_http_auth = true`) so HTTP MCP returns **401** when no auth strategy is configured useful when the bind address is not strictly localhost.
41
44
  - **Rate limiting:** optional `config.mcp.rate_limit_max_requests` is an **in-memory, per-process** sliding window keyed by client IP (`request.ip`). It is **not** shared across Puma workers or hosts. Treat this as a light guard — use a reverse proxy, WAF, or `rack-attack` for strict distributed quotas.
42
45
  - **MCP HTTP JSON logs:** when `config.mcp.http_log_json` is enabled, log lines include `client_ip` and path; treat log sinks like any operational data store (retention, access control).
43
46