rails-ai-bridge 2.1.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -0
- data/CLAUDE.md +4 -4
- data/CONTRIBUTING.md +5 -3
- data/GEMINI.md +3 -3
- data/README.md +57 -23
- data/SECURITY.md +4 -1
- data/docs/BEST_PRACTICES.md +330 -0
- data/docs/GUIDE.md +63 -16
- data/docs/mcp-security.md +28 -0
- data/docs/review-workflow-report.md +72 -0
- data/lib/generators/rails_ai_bridge/install/install_generator.rb +21 -2
- data/lib/rails_ai_bridge/config/introspection.rb +39 -0
- data/lib/rails_ai_bridge/config/mcp.rb +6 -0
- data/lib/rails_ai_bridge/configuration.rb +6 -2
- data/lib/rails_ai_bridge/doctor/check.rb +17 -0
- data/lib/rails_ai_bridge/doctor/checkers/base_checker.rb +55 -0
- data/lib/rails_ai_bridge/doctor/checkers/bridge_metadata_checker.rb +20 -0
- data/lib/rails_ai_bridge/doctor/checkers/context_files_checker.rb +21 -0
- data/lib/rails_ai_bridge/doctor/checkers/controllers_checker.rb +23 -0
- data/lib/rails_ai_bridge/doctor/checkers/gems_checker.rb +21 -0
- data/lib/rails_ai_bridge/doctor/checkers/i18n_checker.rb +23 -0
- data/lib/rails_ai_bridge/doctor/checkers/mcp_buildable_checker.rb +18 -0
- data/lib/rails_ai_bridge/doctor/checkers/migrations_checker.rb +23 -0
- data/lib/rails_ai_bridge/doctor/checkers/models_checker.rb +23 -0
- data/lib/rails_ai_bridge/doctor/checkers/ripgrep_checker.rb +20 -0
- data/lib/rails_ai_bridge/doctor/checkers/routes_checker.rb +21 -0
- data/lib/rails_ai_bridge/doctor/checkers/schema_checker.rb +21 -0
- data/lib/rails_ai_bridge/doctor/checkers/stimulus_mcp_tool_checker.rb +42 -0
- data/lib/rails_ai_bridge/doctor/checkers/tests_checker.rb +24 -0
- data/lib/rails_ai_bridge/doctor/checkers/view_mcp_tool_checker.rb +42 -0
- data/lib/rails_ai_bridge/doctor/checkers/views_checker.rb +23 -0
- data/lib/rails_ai_bridge/doctor.rb +24 -190
- data/lib/rails_ai_bridge/http_transport_app.rb +5 -0
- data/lib/rails_ai_bridge/introspector.rb +1 -0
- data/lib/rails_ai_bridge/introspectors/README.md +1 -0
- data/lib/rails_ai_bridge/introspectors/model_introspector.rb +76 -3
- data/lib/rails_ai_bridge/introspectors/non_ar_models_introspector.rb +210 -0
- data/lib/rails_ai_bridge/model_semantic_classifier.rb +165 -0
- data/lib/rails_ai_bridge/serializers/formatters/base.rb +3 -1
- data/lib/rails_ai_bridge/serializers/formatters/providers/base.rb +12 -0
- data/lib/rails_ai_bridge/serializers/formatters/providers/claude_footer_formatter.rb +16 -0
- data/lib/rails_ai_bridge/serializers/formatters/providers/claude_header_formatter.rb +24 -0
- data/lib/rails_ai_bridge/serializers/formatters/{codex_footer_formatter.rb → providers/codex_footer_formatter.rb} +2 -5
- data/lib/rails_ai_bridge/serializers/formatters/providers/codex_header_formatter.rb +23 -0
- data/lib/rails_ai_bridge/serializers/formatters/{copilot_footer_formatter.rb → providers/copilot_footer_formatter.rb} +2 -5
- data/lib/rails_ai_bridge/serializers/formatters/providers/copilot_header_formatter.rb +20 -0
- data/lib/rails_ai_bridge/serializers/formatters/{footer_formatter.rb → providers/footer_formatter.rb} +2 -5
- data/lib/rails_ai_bridge/serializers/formatters/providers/gemini_footer_formatter.rb +22 -0
- data/lib/rails_ai_bridge/serializers/formatters/providers/gemini_header_formatter.rb +28 -0
- data/lib/rails_ai_bridge/serializers/formatters/providers/header_formatter.rb +23 -0
- data/lib/rails_ai_bridge/serializers/formatters/providers/mcp_guide_formatter.rb +63 -0
- data/lib/rails_ai_bridge/serializers/formatters/{rules_footer_formatter.rb → providers/rules_footer_formatter.rb} +2 -5
- data/lib/rails_ai_bridge/serializers/formatters/{rules_header_formatter.rb → providers/rules_header_formatter.rb} +2 -6
- data/lib/rails_ai_bridge/serializers/formatters/{action_mailbox_formatter.rb → sections/action_mailbox_formatter.rb} +3 -1
- data/lib/rails_ai_bridge/serializers/formatters/{action_text_formatter.rb → sections/action_text_formatter.rb} +6 -4
- data/lib/rails_ai_bridge/serializers/formatters/sections/active_storage_formatter.rb +29 -0
- data/lib/rails_ai_bridge/serializers/formatters/sections/api_formatter.rb +33 -0
- data/lib/rails_ai_bridge/serializers/formatters/sections/app_overview_formatter.rb +28 -0
- data/lib/rails_ai_bridge/serializers/formatters/sections/assets_formatter.rb +30 -0
- data/lib/rails_ai_bridge/serializers/formatters/sections/auth_formatter.rb +29 -0
- data/lib/rails_ai_bridge/serializers/formatters/sections/base.rb +12 -0
- data/lib/rails_ai_bridge/serializers/formatters/sections/config_formatter.rb +43 -0
- data/lib/rails_ai_bridge/serializers/formatters/sections/controllers_formatter.rb +39 -0
- data/lib/rails_ai_bridge/serializers/formatters/sections/conventions_formatter.rb +89 -0
- data/lib/rails_ai_bridge/serializers/formatters/sections/devops_formatter.rb +37 -0
- data/lib/rails_ai_bridge/serializers/formatters/sections/engines_formatter.rb +24 -0
- data/lib/rails_ai_bridge/serializers/formatters/sections/gems_formatter.rb +31 -0
- data/lib/rails_ai_bridge/serializers/formatters/sections/i18n_formatter.rb +24 -0
- data/lib/rails_ai_bridge/serializers/formatters/sections/jobs_formatter.rb +29 -0
- data/lib/rails_ai_bridge/serializers/formatters/{middleware_formatter.rb → sections/middleware_formatter.rb} +3 -1
- data/lib/rails_ai_bridge/serializers/formatters/{migrations_formatter.rb → sections/migrations_formatter.rb} +3 -1
- data/lib/rails_ai_bridge/serializers/formatters/{models_formatter.rb → sections/models_formatter.rb} +3 -1
- data/lib/rails_ai_bridge/serializers/formatters/{multi_database_formatter.rb → sections/multi_database_formatter.rb} +3 -1
- data/lib/rails_ai_bridge/serializers/formatters/{rake_tasks_formatter.rb → sections/rake_tasks_formatter.rb} +3 -1
- data/lib/rails_ai_bridge/serializers/formatters/{routes_formatter.rb → sections/routes_formatter.rb} +3 -1
- data/lib/rails_ai_bridge/serializers/formatters/{schema_formatter.rb → sections/schema_formatter.rb} +3 -1
- data/lib/rails_ai_bridge/serializers/formatters/{section_formatter.rb → sections/section_formatter.rb} +5 -4
- data/lib/rails_ai_bridge/serializers/formatters/{seeds_formatter.rb → sections/seeds_formatter.rb} +3 -1
- data/lib/rails_ai_bridge/serializers/formatters/{tests_formatter.rb → sections/tests_formatter.rb} +3 -1
- data/lib/rails_ai_bridge/serializers/formatters/{turbo_formatter.rb → sections/turbo_formatter.rb} +3 -1
- data/lib/rails_ai_bridge/serializers/formatters/{views_formatter.rb → sections/views_formatter.rb} +3 -1
- data/lib/rails_ai_bridge/serializers/markdown_serializer.rb +29 -29
- data/lib/rails_ai_bridge/serializers/provider_document_header.rb +63 -0
- data/lib/rails_ai_bridge/serializers/providers/base.rb +16 -0
- data/lib/rails_ai_bridge/serializers/providers/base_provider_serializer.rb +2 -18
- data/lib/rails_ai_bridge/serializers/providers/claude_rules_serializer.rb +160 -4
- data/lib/rails_ai_bridge/serializers/providers/claude_serializer.rb +2 -2
- data/lib/rails_ai_bridge/serializers/providers/codex_serializer.rb +2 -2
- data/lib/rails_ai_bridge/serializers/providers/copilot_serializer.rb +2 -2
- data/lib/rails_ai_bridge/serializers/providers/gemini_serializer.rb +2 -2
- data/lib/rails_ai_bridge/serializers/providers/mcp_tool_reference_formatter.rb +54 -0
- data/lib/rails_ai_bridge/serializers/providers/rules_orchestrator.rb +140 -0
- data/lib/rails_ai_bridge/serializers/providers/rules_serializer.rb +2 -2
- data/lib/rails_ai_bridge/serializers/regeneration_footer.rb +50 -0
- data/lib/rails_ai_bridge/serializers/shared_assistant_guidance.rb +47 -0
- data/lib/rails_ai_bridge/tools/base_tool.rb +10 -3
- data/lib/rails_ai_bridge/tools/get_config.rb +32 -16
- data/lib/rails_ai_bridge/tools/get_controllers.rb +95 -49
- data/lib/rails_ai_bridge/tools/get_conventions.rb +74 -56
- data/lib/rails_ai_bridge/tools/get_gems.rb +38 -15
- data/lib/rails_ai_bridge/tools/get_model_details.rb +105 -12
- data/lib/rails_ai_bridge/tools/get_routes.rb +71 -38
- data/lib/rails_ai_bridge/tools/get_schema.rb +57 -14
- data/lib/rails_ai_bridge/tools/get_stimulus.rb +96 -65
- data/lib/rails_ai_bridge/tools/get_test_info.rb +33 -11
- data/lib/rails_ai_bridge/tools/get_view/base_formatter.rb +96 -0
- data/lib/rails_ai_bridge/tools/get_view/full_formatter.rb +33 -0
- data/lib/rails_ai_bridge/tools/get_view/specific_view_formatter.rb +28 -0
- data/lib/rails_ai_bridge/tools/get_view/standard_formatter.rb +41 -0
- data/lib/rails_ai_bridge/tools/get_view/summary_formatter.rb +33 -0
- data/lib/rails_ai_bridge/tools/get_view.rb +13 -167
- data/lib/rails_ai_bridge/tools/model_details/full_formatter.rb +10 -5
- data/lib/rails_ai_bridge/tools/model_details/non_ar_models_appendix.rb +53 -0
- data/lib/rails_ai_bridge/tools/model_details/single_model_formatter.rb +22 -2
- data/lib/rails_ai_bridge/tools/model_details/standard_formatter.rb +10 -5
- data/lib/rails_ai_bridge/tools/model_details/summary_formatter.rb +16 -6
- data/lib/rails_ai_bridge/tools/schema/full_formatter.rb +3 -1
- data/lib/rails_ai_bridge/tools/schema/standard_formatter.rb +3 -1
- data/lib/rails_ai_bridge/tools/schema/summary_formatter.rb +3 -1
- data/lib/rails_ai_bridge/tools/schema/table_formatter.rb +3 -1
- data/lib/rails_ai_bridge/tools/search_code/formatter.rb +32 -0
- data/lib/rails_ai_bridge/tools/search_code.rb +54 -13
- data/lib/rails_ai_bridge/version.rb +1 -1
- data/lib/rails_ai_bridge/watcher/bridge_regenerator.rb +31 -0
- data/lib/rails_ai_bridge/watcher/watch_directories.rb +27 -0
- data/lib/rails_ai_bridge/watcher.rb +18 -20
- data/tasks/prd-enhanced-context.md +223 -0
- data/tasks/prd-freshness-stamp.md +229 -0
- data/tasks/prd-incremental-ci.md +138 -0
- data/tasks/prd-overrides-ux.md +308 -0
- metadata +83 -41
- data/lib/rails_ai_bridge/serializers/formatters/active_storage_formatter.rb +0 -23
- data/lib/rails_ai_bridge/serializers/formatters/api_formatter.rb +0 -31
- data/lib/rails_ai_bridge/serializers/formatters/app_overview_formatter.rb +0 -22
- data/lib/rails_ai_bridge/serializers/formatters/assets_formatter.rb +0 -23
- data/lib/rails_ai_bridge/serializers/formatters/auth_formatter.rb +0 -34
- data/lib/rails_ai_bridge/serializers/formatters/claude_footer_formatter.rb +0 -31
- data/lib/rails_ai_bridge/serializers/formatters/claude_header_formatter.rb +0 -25
- data/lib/rails_ai_bridge/serializers/formatters/codex_header_formatter.rb +0 -23
- data/lib/rails_ai_bridge/serializers/formatters/config_formatter.rb +0 -23
- data/lib/rails_ai_bridge/serializers/formatters/controllers_formatter.rb +0 -48
- data/lib/rails_ai_bridge/serializers/formatters/conventions_formatter.rb +0 -24
- data/lib/rails_ai_bridge/serializers/formatters/copilot_header_formatter.rb +0 -22
- data/lib/rails_ai_bridge/serializers/formatters/devops_formatter.rb +0 -28
- data/lib/rails_ai_bridge/serializers/formatters/engines_formatter.rb +0 -27
- data/lib/rails_ai_bridge/serializers/formatters/gemini_footer_formatter.rb +0 -33
- data/lib/rails_ai_bridge/serializers/formatters/gemini_header_formatter.rb +0 -29
- data/lib/rails_ai_bridge/serializers/formatters/gems_formatter.rb +0 -26
- data/lib/rails_ai_bridge/serializers/formatters/header_formatter.rb +0 -24
- data/lib/rails_ai_bridge/serializers/formatters/i18n_formatter.rb +0 -22
- data/lib/rails_ai_bridge/serializers/formatters/jobs_formatter.rb +0 -35
- 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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 89c1de6e57a12e9e993e3a6648f08829ebd7c59e975e70b33c1b8a73fd9e940d
|
|
4
|
+
data.tar.gz: 24b0733e1c31510a0c8876524cb670ec79ff6b53ed7fad477983ddbeff7d23a2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8a42be12f415b7957931b3c88cbd5a7ecf81af08357052b9d7d4c5d5ce20c40c0b93ab57a73c02c337e4fd22297780732b6d1dea073d47972df29d371b26456b
|
|
7
|
+
data.tar.gz: f6b2bc0cec702dc34388dd1606981d8d7169dafa5b35f3715e7dbfb8ac027d651e52d0e5504a7030af9cc92ce9f99d7ee4281e7fed54f6324149c10fc2c84c9d
|
data/CHANGELOG.md
CHANGED
|
@@ -5,8 +5,27 @@ 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
|
+
|
|
10
29
|
## [2.1.0] - 2026-04-02
|
|
11
30
|
|
|
12
31
|
### 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/` —
|
|
12
|
-
- `lib/rails_ai_bridge/tools/` —
|
|
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
|
|
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/ #
|
|
22
|
-
├── tools/ #
|
|
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` (
|
|
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
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/` —
|
|
12
|
-
- `lib/rails_ai_bridge/tools/` —
|
|
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, gemini)
|
|
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`) 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/`
|
data/README.md
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
[](https://rubygems.org/gems/rails-ai-bridge)
|
|
8
8
|
[](https://github.com/igmarin/rails-ai-bridge/actions)
|
|
9
9
|
[](LICENSE)
|
|
10
|
+

|
|
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
|
|
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.
|
|
35
36
|
2. **`rails ai:bridge`** writes bounded bridge files for Claude, Cursor, Copilot, Codex, Windsurf, Gemini, and JSON.
|
|
36
|
-
3. **`rails ai:serve`** exposes **
|
|
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 —
|
|
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
|
-
|
|
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 **
|
|
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
|
|
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
|
---
|
|
@@ -303,6 +313,8 @@ Codex support is centered on **`AGENTS.md`** at the repository root.
|
|
|
303
313
|
|
|
304
314
|
## Best Practices
|
|
305
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
|
+
|
|
306
318
|
After testing with Cursor, Windsurf, Copilot, Codex, and Claude Code in real projects, these patterns consistently produce the best results.
|
|
307
319
|
|
|
308
320
|
### Layer 1: Commit your static files
|
|
@@ -360,13 +372,13 @@ This keeps token usage low and answer quality high. Requesting full detail on ev
|
|
|
360
372
|
| Preset | Introspectors | Best for |
|
|
361
373
|
|--------|--------------|---------|
|
|
362
374
|
| `:standard` (default) | 9 core | Most apps — schema, models, routes, jobs, gems, conventions |
|
|
363
|
-
| `:full` |
|
|
375
|
+
| `:full` | 26 | Full-stack apps where frontend, auth, API, and DevOps context matter |
|
|
364
376
|
|
|
365
377
|
Add individual introspectors on top of a preset for targeted additions:
|
|
366
378
|
|
|
367
379
|
```ruby
|
|
368
380
|
config.preset = :standard
|
|
369
|
-
config.introspectors += %i[views auth api]
|
|
381
|
+
config.introspectors += %i[non_ar_models views auth api]
|
|
370
382
|
```
|
|
371
383
|
|
|
372
384
|
### Check your readiness score
|
|
@@ -384,11 +396,11 @@ Prints a 0–100 AI readiness score and flags anything missing: `.mcp.json`, gen
|
|
|
384
396
|
```ruby
|
|
385
397
|
# config/initializers/rails_ai_bridge.rb
|
|
386
398
|
RailsAiBridge.configure do |config|
|
|
387
|
-
# Presets: :standard (9 introspectors, default) or :full (
|
|
399
|
+
# Presets: :standard (9 introspectors, default) or :full (26). Add :non_ar_models etc. as needed.
|
|
388
400
|
config.preset = :standard
|
|
389
401
|
|
|
390
402
|
# Cherry-pick on top of a preset
|
|
391
|
-
# config.introspectors += %i[views turbo auth api]
|
|
403
|
+
# config.introspectors += %i[non_ar_models views turbo auth api]
|
|
392
404
|
|
|
393
405
|
# Context mode: :compact (≤150 lines, default) or :full (dump everything)
|
|
394
406
|
# config.context_mode = :compact
|
|
@@ -396,6 +408,9 @@ RailsAiBridge.configure do |config|
|
|
|
396
408
|
# Exclude models from introspection
|
|
397
409
|
config.excluded_models += %w[AdminUser InternalAuditLog]
|
|
398
410
|
|
|
411
|
+
# Tag primary domain models as core_entity (semantic context for AI + Claude rules)
|
|
412
|
+
# config.core_models += %w[User Order Project]
|
|
413
|
+
|
|
399
414
|
# Exclude paths from code search
|
|
400
415
|
config.excluded_paths += %w[vendor/bundle]
|
|
401
416
|
|
|
@@ -415,11 +430,18 @@ end
|
|
|
415
430
|
| `claude_max_lines` | `150` | Max lines for CLAUDE.md in compact mode |
|
|
416
431
|
| `max_tool_response_chars` | `120_000` | Safety cap for MCP tool responses |
|
|
417
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/` |
|
|
418
434
|
| `excluded_paths` | `node_modules tmp log vendor .git` | Paths excluded from code search |
|
|
419
435
|
| `auto_mount` | `false` | Auto-mount HTTP MCP endpoint |
|
|
420
436
|
| `allow_auto_mount_in_production` | `false` | Allow `auto_mount` in production (requires MCP token) |
|
|
421
437
|
| `http_mcp_token` | `nil` | Bearer token for HTTP MCP; `ENV["RAILS_AI_BRIDGE_MCP_TOKEN"]` overrides when set |
|
|
422
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 |
|
|
423
445
|
| `expose_credentials_key_names` | `false` | Include `credentials_keys` in config introspection / `rails://config` |
|
|
424
446
|
| `additional_introspectors` | `{}` | Optional custom introspector classes keyed by symbol |
|
|
425
447
|
| `additional_tools` | `[]` | Optional MCP tool classes appended to the built-in toolset |
|
|
@@ -427,6 +449,8 @@ end
|
|
|
427
449
|
| `http_path` | `"/mcp"` | HTTP endpoint path |
|
|
428
450
|
| `http_port` | `6029` | HTTP server port |
|
|
429
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).
|
|
430
454
|
</details>
|
|
431
455
|
|
|
432
456
|
### Extending the built-ins
|
|
@@ -521,23 +545,33 @@ The gem parses `db/schema.rb` as text when no database is connected. Works in CI
|
|
|
521
545
|
|
|
522
546
|
---
|
|
523
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
|
+
|
|
524
563
|
## Contributing
|
|
525
564
|
|
|
526
565
|
```bash
|
|
527
566
|
git clone https://github.com/igmarin/rails-ai-bridge.git
|
|
528
567
|
cd rails-ai-bridge && bundle install
|
|
529
|
-
bundle exec rspec # runs the full suite
|
|
530
|
-
bundle exec rubocop #
|
|
568
|
+
bundle exec rspec # runs the full suite (SimpleCov enforces ≥80% coverage)
|
|
569
|
+
bundle exec rubocop # lint
|
|
531
570
|
```
|
|
532
571
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
- 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)).
|
|
536
|
-
- After the run, open **`coverage/index.html`** in a browser for a per-file report (`coverage/` is gitignored).
|
|
537
|
-
- 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.
|
|
538
|
-
- 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.
|
|
539
573
|
|
|
540
|
-
Bug reports and pull requests
|
|
574
|
+
Bug reports and pull requests: [github.com/igmarin/rails-ai-bridge/issues](https://github.com/igmarin/rails-ai-bridge/issues)
|
|
541
575
|
|
|
542
576
|
## Acknowledgments & Origins
|
|
543
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
|
-
-
|
|
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
|
|