rails-ai-context 0.1.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 +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +23 -0
- data/CHANGELOG.md +26 -0
- data/LICENSE +21 -0
- data/README.md +212 -0
- data/Rakefile +8 -0
- data/exe/rails-ai-context +67 -0
- data/lib/generators/rails_ai_context/install/install_generator.rb +85 -0
- data/lib/rails-ai-context.rb +5 -0
- data/lib/rails_ai_context/configuration.rb +52 -0
- data/lib/rails_ai_context/engine.rb +21 -0
- data/lib/rails_ai_context/introspector.rb +61 -0
- data/lib/rails_ai_context/introspectors/convention_detector.rb +125 -0
- data/lib/rails_ai_context/introspectors/gem_introspector.rb +128 -0
- data/lib/rails_ai_context/introspectors/job_introspector.rb +82 -0
- data/lib/rails_ai_context/introspectors/model_introspector.rb +163 -0
- data/lib/rails_ai_context/introspectors/route_introspector.rb +83 -0
- data/lib/rails_ai_context/introspectors/schema_introspector.rb +143 -0
- data/lib/rails_ai_context/serializers/context_file_serializer.rb +60 -0
- data/lib/rails_ai_context/serializers/json_serializer.rb +19 -0
- data/lib/rails_ai_context/serializers/markdown_serializer.rb +158 -0
- data/lib/rails_ai_context/server.rb +90 -0
- data/lib/rails_ai_context/tasks/rails_ai_context.rake +89 -0
- data/lib/rails_ai_context/tools/base_tool.rb +37 -0
- data/lib/rails_ai_context/tools/get_conventions.rb +87 -0
- data/lib/rails_ai_context/tools/get_gems.rb +49 -0
- data/lib/rails_ai_context/tools/get_model_details.rb +103 -0
- data/lib/rails_ai_context/tools/get_routes.rb +50 -0
- data/lib/rails_ai_context/tools/get_schema.rb +93 -0
- data/lib/rails_ai_context/tools/search_code.rb +111 -0
- data/lib/rails_ai_context/version.rb +5 -0
- data/lib/rails_ai_context.rb +74 -0
- data/rails-ai-context.gemspec +52 -0
- metadata +223 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 994a7f4531e3c387086796826815f5b4489107ec50b47d8bd86e46fa208d59ee
|
|
4
|
+
data.tar.gz: 11dd7dae7425c70d1bff80a43a183b66b4a0863fffa72d2d227093f5d1928b30
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 733527414a221eb42d66510eeeeead2d46ec69482998bd79c2b913c87cf34b37ec23160b0a44b22a07689aae7ae1f3bef37094e836c2a2a18b992d7d3620f294
|
|
7
|
+
data.tar.gz: 1c4dfeb48b4a521631ae339de511dfe62ce2119c19fc8b50bfcee6fa3e8112632652f053e6040b4aa46bbf7ef47db352a90e41ff8dcc882631cb308c1638fa34
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require:
|
|
2
|
+
- rubocop-rails-omakase
|
|
3
|
+
|
|
4
|
+
AllCops:
|
|
5
|
+
TargetRubyVersion: 3.2
|
|
6
|
+
NewCops: enable
|
|
7
|
+
Exclude:
|
|
8
|
+
- "spec/fixtures/**/*"
|
|
9
|
+
- "vendor/**/*"
|
|
10
|
+
|
|
11
|
+
Style/Documentation:
|
|
12
|
+
Enabled: false
|
|
13
|
+
|
|
14
|
+
Metrics/MethodLength:
|
|
15
|
+
Max: 25
|
|
16
|
+
|
|
17
|
+
Metrics/ClassLength:
|
|
18
|
+
Max: 200
|
|
19
|
+
|
|
20
|
+
Metrics/BlockLength:
|
|
21
|
+
Exclude:
|
|
22
|
+
- "spec/**/*"
|
|
23
|
+
- "*.gemspec"
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - Unreleased
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Initial release
|
|
13
|
+
- Schema introspection (live DB + static schema.rb fallback)
|
|
14
|
+
- Model introspection (associations, validations, scopes, enums, callbacks, concerns)
|
|
15
|
+
- Route introspection (HTTP verbs, paths, controller actions, API namespaces)
|
|
16
|
+
- Job introspection (ActiveJob, mailers, Action Cable channels)
|
|
17
|
+
- Gem analysis (40+ notable gems mapped to categories with explanations)
|
|
18
|
+
- Convention detection (architecture style, design patterns, directory structure)
|
|
19
|
+
- 6 MCP tools: `rails_get_schema`, `rails_get_routes`, `rails_get_model_details`, `rails_get_gems`, `rails_search_code`, `rails_get_conventions`
|
|
20
|
+
- Context file generation: CLAUDE.md, .cursorrules, .windsurfrules, .github/copilot-instructions.md, JSON
|
|
21
|
+
- Rails Engine with Railtie auto-setup
|
|
22
|
+
- Install generator (`rails generate rails_ai_context:install`)
|
|
23
|
+
- Rake tasks: `ai:context`, `ai:serve`, `ai:serve_http`, `ai:inspect`
|
|
24
|
+
- CLI executable: `rails-ai-context serve|context|inspect`
|
|
25
|
+
- Stdio + Streamable HTTP transport support via official mcp SDK
|
|
26
|
+
- CI matrix: Ruby 3.2/3.3/3.4 × Rails 7.1/7.2/8.0
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Cris
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# rails-ai-context
|
|
2
|
+
|
|
3
|
+
**Turn any Rails app into an AI-ready codebase — one gem install.**
|
|
4
|
+
|
|
5
|
+
[](https://rubygems.org/gems/rails-ai-context)
|
|
6
|
+
[](https://github.com/crisnahine/rails-ai-context/actions)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
|
|
9
|
+
`rails-ai-context` automatically introspects your Rails application and exposes your models, routes, schema, jobs, gems, and conventions to AI assistants through the [Model Context Protocol (MCP)](https://modelcontextprotocol.io).
|
|
10
|
+
|
|
11
|
+
**Your AI assistant instantly understands your entire Rails app. No configuration. No manual tool definitions. Just `bundle add` and go.**
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## The Problem
|
|
16
|
+
|
|
17
|
+
You open Claude Code, Cursor, or Copilot in your Rails project and ask: *"Add a draft status to posts with a scheduled publish date."*
|
|
18
|
+
|
|
19
|
+
The AI doesn't know your schema. It doesn't know you use Devise for auth, Sidekiq for jobs, or that Post already has an `enum :status`. It generates generic code that doesn't match your app's patterns.
|
|
20
|
+
|
|
21
|
+
## The Solution
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
bundle add rails-ai-context
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
That's it. Now your AI assistant knows:
|
|
28
|
+
|
|
29
|
+
- 📦 **Every table, column, index, and foreign key** in your database
|
|
30
|
+
- 🏗️ **Every model** with its associations, validations, scopes, enums, and callbacks
|
|
31
|
+
- 🛤️ **Every route** with HTTP verbs, paths, and controller actions
|
|
32
|
+
- ⚡ **Every background job**, mailer, and Action Cable channel
|
|
33
|
+
- 💎 **Every notable gem** and what it means (Devise → auth, Sidekiq → jobs, Turbo → Hotwire)
|
|
34
|
+
- 🏛️ **Your architecture patterns**: service objects, STI, polymorphism, state machines, multi-tenancy
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
### 1. Install
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
bundle add rails-ai-context
|
|
44
|
+
rails generate rails_ai_context:install
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 2. Generate Context Files
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
rails ai:context
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
This creates:
|
|
54
|
+
- `CLAUDE.md` — for Claude Code
|
|
55
|
+
- `.cursorrules` — for Cursor
|
|
56
|
+
- `.windsurfrules` — for Windsurf
|
|
57
|
+
- `.github/copilot-instructions.md` — for GitHub Copilot
|
|
58
|
+
|
|
59
|
+
**Commit these files.** Your entire team gets smarter AI assistance.
|
|
60
|
+
|
|
61
|
+
### 3. Start the MCP Server
|
|
62
|
+
|
|
63
|
+
For Claude Code / Cursor / any MCP client:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
rails ai:serve
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Or add to your Claude Code config (`~/.claude/claude_desktop_config.json`):
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"mcpServers": {
|
|
74
|
+
"my-rails-app": {
|
|
75
|
+
"command": "bundle",
|
|
76
|
+
"args": ["exec", "rails", "ai:serve"],
|
|
77
|
+
"cwd": "/path/to/your/rails/app"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## MCP Tools
|
|
86
|
+
|
|
87
|
+
The gem exposes 6 tools via MCP that AI clients can call:
|
|
88
|
+
|
|
89
|
+
| Tool | Description | Annotations |
|
|
90
|
+
|------|-------------|-------------|
|
|
91
|
+
| `rails_get_schema` | Database schema: tables, columns, indexes, FKs | read-only, idempotent |
|
|
92
|
+
| `rails_get_routes` | All routes with HTTP verbs and controller actions | read-only, idempotent |
|
|
93
|
+
| `rails_get_model_details` | Model associations, validations, scopes, enums, callbacks | read-only, idempotent |
|
|
94
|
+
| `rails_get_gems` | Notable gems categorized by function with explanations | read-only, idempotent |
|
|
95
|
+
| `rails_search_code` | Ripgrep-powered code search across the codebase | read-only, idempotent |
|
|
96
|
+
| `rails_get_conventions` | Architecture patterns, directory structure, config files | read-only, idempotent |
|
|
97
|
+
|
|
98
|
+
All tools are **read-only** — they never modify your application or database.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## How It Works
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
┌─────────────────────────────────────────┐
|
|
106
|
+
│ Your Rails App │
|
|
107
|
+
│ │
|
|
108
|
+
│ models/ routes schema jobs gems │
|
|
109
|
+
│ │ │ │ │ │ │
|
|
110
|
+
│ └────────┴───────┴──────┴─────┘ │
|
|
111
|
+
│ │ │
|
|
112
|
+
│ ┌───────┴────────┐ │
|
|
113
|
+
│ │ Introspector │ │
|
|
114
|
+
│ └───────┬────────┘ │
|
|
115
|
+
│ │ │
|
|
116
|
+
│ ┌────────────┼────────────┐ │
|
|
117
|
+
│ ▼ ▼ ▼ │
|
|
118
|
+
│ CLAUDE.md MCP Server .cursorrules │
|
|
119
|
+
│ (static) (live tools) (static) │
|
|
120
|
+
└─────────────────────────────────────────┘
|
|
121
|
+
│ │
|
|
122
|
+
▼ ▼
|
|
123
|
+
Claude Code Cursor / Windsurf /
|
|
124
|
+
(reads file) any MCP client
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Two modes:**
|
|
128
|
+
1. **Static files** (`rails ai:context`) — generates markdown files that AI tools read as project context. Zero runtime cost. Works everywhere.
|
|
129
|
+
2. **MCP server** (`rails ai:serve`) — live introspection tools that AI clients call on-demand. Richer, always up-to-date.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Configuration
|
|
134
|
+
|
|
135
|
+
```ruby
|
|
136
|
+
# config/initializers/rails_ai_context.rb
|
|
137
|
+
RailsAiContext.configure do |config|
|
|
138
|
+
# Exclude internal models from introspection
|
|
139
|
+
config.excluded_models += %w[AdminUser InternalAuditLog]
|
|
140
|
+
|
|
141
|
+
# Exclude paths from code search
|
|
142
|
+
config.excluded_paths += %w[vendor/bundle]
|
|
143
|
+
|
|
144
|
+
# Auto-mount HTTP MCP endpoint (for remote AI clients)
|
|
145
|
+
config.auto_mount = true
|
|
146
|
+
config.http_path = "/mcp"
|
|
147
|
+
config.http_port = 6029
|
|
148
|
+
end
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Rake Tasks
|
|
154
|
+
|
|
155
|
+
| Command | Description |
|
|
156
|
+
|---------|-------------|
|
|
157
|
+
| `rails ai:context` | Generate all context files (CLAUDE.md, .cursorrules, etc.) |
|
|
158
|
+
| `rails ai:context_for[claude]` | Generate for a specific format |
|
|
159
|
+
| `rails ai:serve` | Start MCP server (stdio, for Claude Code) |
|
|
160
|
+
| `rails ai:serve_http` | Start MCP server (HTTP, for remote clients) |
|
|
161
|
+
| `rails ai:inspect` | Print introspection summary to stdout |
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Works Without a Database
|
|
166
|
+
|
|
167
|
+
The gem gracefully degrades when no database is connected — it parses `db/schema.rb` as text. This means it works in:
|
|
168
|
+
|
|
169
|
+
- CI environments
|
|
170
|
+
- Claude Code sessions (no DB running)
|
|
171
|
+
- Docker build stages
|
|
172
|
+
- Any environment where you have the source code but not a running database
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Requirements
|
|
177
|
+
|
|
178
|
+
- Ruby >= 3.2
|
|
179
|
+
- Rails >= 7.1
|
|
180
|
+
- [mcp](https://github.com/modelcontextprotocol/ruby-sdk) (official MCP SDK, installed automatically)
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## vs. Other Ruby MCP Projects
|
|
185
|
+
|
|
186
|
+
| Project | What it does | How rails-ai-context differs |
|
|
187
|
+
|---------|-------------|------------------------------|
|
|
188
|
+
| [Official Ruby SDK](https://github.com/modelcontextprotocol/ruby-sdk) | Low-level MCP protocol library | We **use** this as our foundation |
|
|
189
|
+
| [fast-mcp](https://github.com/yjacquin/fast-mcp) | Generic Ruby MCP framework | We're a **product**, not a framework — zero-config Rails introspection |
|
|
190
|
+
| [rails-mcp-server](https://github.com/maquina-app/rails-mcp-server) | Rails MCP server with manual config | We auto-discover everything, no `projects.yml` needed |
|
|
191
|
+
| [mcp_on_ruby](https://github.com/rubyonai/mcp_on_ruby) | MCP server with manual tool definitions | We auto-generate tools from your app's structure |
|
|
192
|
+
|
|
193
|
+
**rails-ai-context is not another MCP SDK.** It's a product that gives your Rails app AI superpowers with one `bundle add`.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Development
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
git clone https://github.com/crisnahine/rails-ai-context.git
|
|
201
|
+
cd rails-ai-context
|
|
202
|
+
bundle install
|
|
203
|
+
bundle exec rspec
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Contributing
|
|
207
|
+
|
|
208
|
+
Bug reports and pull requests welcome at https://github.com/crisnahine/rails-ai-context.
|
|
209
|
+
|
|
210
|
+
## License
|
|
211
|
+
|
|
212
|
+
[MIT License](LICENSE)
|
data/Rakefile
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "thor"
|
|
5
|
+
|
|
6
|
+
module RailsAiContext
|
|
7
|
+
class CLI < Thor
|
|
8
|
+
desc "serve", "Start MCP server (stdio transport)"
|
|
9
|
+
option :transport, type: :string, default: "stdio", desc: "Transport: stdio or http"
|
|
10
|
+
option :port, type: :numeric, default: 6029, desc: "HTTP port (only for http transport)"
|
|
11
|
+
def serve
|
|
12
|
+
boot_rails!
|
|
13
|
+
require "rails_ai_context"
|
|
14
|
+
|
|
15
|
+
transport = options[:transport].to_sym
|
|
16
|
+
if transport == :http
|
|
17
|
+
RailsAiContext.configuration.http_port = options[:port]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
RailsAiContext.start_mcp_server(transport: transport)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
desc "context", "Generate AI context files"
|
|
24
|
+
option :format, type: :string, default: "all", desc: "Format: claude, cursor, windsurf, copilot, json, all"
|
|
25
|
+
def context
|
|
26
|
+
boot_rails!
|
|
27
|
+
require "rails_ai_context"
|
|
28
|
+
|
|
29
|
+
format = options[:format].to_sym
|
|
30
|
+
$stderr.puts "Introspecting Rails app..."
|
|
31
|
+
files = RailsAiContext.generate_context(format: format)
|
|
32
|
+
files.each { |f| $stderr.puts " Written: #{f}" }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
desc "inspect", "Print introspection summary"
|
|
36
|
+
def inspect_app
|
|
37
|
+
boot_rails!
|
|
38
|
+
require "rails_ai_context"
|
|
39
|
+
require "json"
|
|
40
|
+
|
|
41
|
+
context = RailsAiContext.introspect
|
|
42
|
+
puts JSON.pretty_generate(context)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
desc "version", "Print version"
|
|
46
|
+
def version
|
|
47
|
+
require_relative "../rails_ai_context/version"
|
|
48
|
+
puts "rails-ai-context v#{RailsAiContext::VERSION}"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def boot_rails!
|
|
54
|
+
# Try to find and boot the Rails app
|
|
55
|
+
config_path = File.join(Dir.pwd, "config", "environment.rb")
|
|
56
|
+
if File.exist?(config_path)
|
|
57
|
+
require config_path
|
|
58
|
+
else
|
|
59
|
+
$stderr.puts "Error: No Rails app found in #{Dir.pwd}"
|
|
60
|
+
$stderr.puts "Run this command from your Rails app root directory."
|
|
61
|
+
exit 1
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
RailsAiContext::CLI.start(ARGV)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsAiContext
|
|
4
|
+
module Generators
|
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
|
6
|
+
source_root File.expand_path("templates", __dir__)
|
|
7
|
+
|
|
8
|
+
desc "Install rails-ai-context: creates initializer and generates initial context files."
|
|
9
|
+
|
|
10
|
+
def create_initializer
|
|
11
|
+
create_file "config/initializers/rails_ai_context.rb", <<~RUBY
|
|
12
|
+
# frozen_string_literal: true
|
|
13
|
+
|
|
14
|
+
RailsAiContext.configure do |config|
|
|
15
|
+
# MCP server name (shown to AI clients)
|
|
16
|
+
# config.server_name = "rails-ai-context"
|
|
17
|
+
|
|
18
|
+
# Auto-mount HTTP MCP endpoint at /mcp
|
|
19
|
+
# Set to true if you want remote MCP clients to connect
|
|
20
|
+
# config.auto_mount = false
|
|
21
|
+
# config.http_path = "/mcp"
|
|
22
|
+
# config.http_port = 6029
|
|
23
|
+
|
|
24
|
+
# Models to exclude from introspection
|
|
25
|
+
# config.excluded_models += %w[AdminUser InternalThing]
|
|
26
|
+
|
|
27
|
+
# Paths to exclude from code search
|
|
28
|
+
# config.excluded_paths += %w[vendor/bundle]
|
|
29
|
+
end
|
|
30
|
+
RUBY
|
|
31
|
+
|
|
32
|
+
say "Created config/initializers/rails_ai_context.rb", :green
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def add_to_gitignore
|
|
36
|
+
gitignore = Rails.root.join(".gitignore")
|
|
37
|
+
return unless File.exist?(gitignore)
|
|
38
|
+
|
|
39
|
+
content = File.read(gitignore)
|
|
40
|
+
append = []
|
|
41
|
+
append << ".ai-context.json" unless content.include?(".ai-context.json")
|
|
42
|
+
|
|
43
|
+
if append.any?
|
|
44
|
+
File.open(gitignore, "a") do |f|
|
|
45
|
+
f.puts ""
|
|
46
|
+
f.puts "# rails-ai-context (JSON cache — markdown files should be committed)"
|
|
47
|
+
append.each { |line| f.puts line }
|
|
48
|
+
end
|
|
49
|
+
say "Updated .gitignore", :green
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def generate_context_files
|
|
54
|
+
say ""
|
|
55
|
+
say "Generating AI context files...", :yellow
|
|
56
|
+
|
|
57
|
+
if Rails.application
|
|
58
|
+
require "rails_ai_context"
|
|
59
|
+
context = RailsAiContext.introspect
|
|
60
|
+
files = RailsAiContext.generate_context(format: :all)
|
|
61
|
+
files.each { |f| say " Created #{f}", :green }
|
|
62
|
+
else
|
|
63
|
+
say " Skipped (Rails app not fully loaded). Run `rails ai:context` after install.", :yellow
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def show_instructions
|
|
68
|
+
say ""
|
|
69
|
+
say "=" * 50, :cyan
|
|
70
|
+
say " rails-ai-context installed!", :cyan
|
|
71
|
+
say "=" * 50, :cyan
|
|
72
|
+
say ""
|
|
73
|
+
say "Quick start:", :yellow
|
|
74
|
+
say " rails ai:context # Regenerate context files"
|
|
75
|
+
say " rails ai:serve # Start MCP server (stdio)"
|
|
76
|
+
say " rails ai:inspect # Print introspection summary"
|
|
77
|
+
say ""
|
|
78
|
+
say "For Claude Code, add to your claude_desktop_config.json:", :yellow
|
|
79
|
+
say ' { "mcpServers": { "rails": { "command": "rails", "args": ["ai:serve"], "cwd": "/path/to/your/app" } } }'
|
|
80
|
+
say ""
|
|
81
|
+
say "Commit CLAUDE.md and .cursorrules so your team benefits!", :green
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsAiContext
|
|
4
|
+
class Configuration
|
|
5
|
+
# MCP server settings
|
|
6
|
+
attr_accessor :server_name, :server_version
|
|
7
|
+
|
|
8
|
+
# Which introspectors to run (all by default)
|
|
9
|
+
attr_accessor :introspectors
|
|
10
|
+
|
|
11
|
+
# Paths to exclude from code search
|
|
12
|
+
attr_accessor :excluded_paths
|
|
13
|
+
|
|
14
|
+
# Whether to auto-mount the MCP HTTP endpoint
|
|
15
|
+
attr_accessor :auto_mount
|
|
16
|
+
|
|
17
|
+
# HTTP transport settings
|
|
18
|
+
attr_accessor :http_path, :http_bind, :http_port
|
|
19
|
+
|
|
20
|
+
# Output directory for generated context files
|
|
21
|
+
attr_accessor :output_dir
|
|
22
|
+
|
|
23
|
+
# Models/tables to exclude from introspection
|
|
24
|
+
attr_accessor :excluded_models
|
|
25
|
+
|
|
26
|
+
# Maximum depth for association traversal
|
|
27
|
+
attr_accessor :max_association_depth
|
|
28
|
+
|
|
29
|
+
def initialize
|
|
30
|
+
@server_name = "rails-ai-context"
|
|
31
|
+
@server_version = RailsAiContext::VERSION
|
|
32
|
+
@introspectors = %i[schema models routes jobs gems conventions]
|
|
33
|
+
@excluded_paths = %w[node_modules tmp log vendor .git]
|
|
34
|
+
@auto_mount = false
|
|
35
|
+
@http_path = "/mcp"
|
|
36
|
+
@http_bind = "127.0.0.1"
|
|
37
|
+
@http_port = 6029
|
|
38
|
+
@output_dir = nil # defaults to Rails.root
|
|
39
|
+
@excluded_models = %w[
|
|
40
|
+
ApplicationRecord
|
|
41
|
+
ActiveStorage::Blob ActiveStorage::Attachment ActiveStorage::VariantRecord
|
|
42
|
+
ActionText::RichText ActionText::EncryptedRichText
|
|
43
|
+
ActionMailbox::InboundEmail ActionMailbox::Record
|
|
44
|
+
]
|
|
45
|
+
@max_association_depth = 2
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def output_dir_for(app)
|
|
49
|
+
@output_dir || app.root.to_s
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsAiContext
|
|
4
|
+
class Engine < ::Rails::Engine
|
|
5
|
+
# Register the MCP server after Rails finishes loading
|
|
6
|
+
initializer "rails_ai_context.setup", after: :load_config_initializers do |_app|
|
|
7
|
+
# Make introspection available via Rails console
|
|
8
|
+
Rails.application.config.rails_ai_context = RailsAiContext.configuration
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Register Rake tasks
|
|
12
|
+
rake_tasks do
|
|
13
|
+
load File.expand_path("tasks/rails_ai_context.rake", __dir__)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Register generators
|
|
17
|
+
generators do
|
|
18
|
+
require_relative "../generators/rails_ai_context/install/install_generator"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsAiContext
|
|
4
|
+
# Orchestrates all sub-introspectors to build a complete
|
|
5
|
+
# picture of the Rails application for AI consumption.
|
|
6
|
+
class Introspector
|
|
7
|
+
attr_reader :app, :config
|
|
8
|
+
|
|
9
|
+
def initialize(app)
|
|
10
|
+
@app = app
|
|
11
|
+
@config = RailsAiContext.configuration
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Run all configured introspectors and return unified context hash
|
|
15
|
+
#
|
|
16
|
+
# @return [Hash] complete application context
|
|
17
|
+
def call
|
|
18
|
+
context = {
|
|
19
|
+
app_name: app_name,
|
|
20
|
+
ruby_version: RUBY_VERSION,
|
|
21
|
+
rails_version: Rails.version,
|
|
22
|
+
environment: Rails.env,
|
|
23
|
+
generated_at: Time.current.iso8601,
|
|
24
|
+
generator: "rails-ai-context v#{RailsAiContext::VERSION}"
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
config.introspectors.each do |name|
|
|
28
|
+
introspector = resolve_introspector(name)
|
|
29
|
+
context[name] = introspector.call
|
|
30
|
+
rescue => e
|
|
31
|
+
context[name] = { error: e.message }
|
|
32
|
+
Rails.logger.warn "[rails-ai-context] #{name} introspection failed: #{e.message}"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
context
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def app_name
|
|
41
|
+
if app.class.respond_to?(:module_parent_name)
|
|
42
|
+
app.class.module_parent_name
|
|
43
|
+
else
|
|
44
|
+
app.class.name.deconstantize
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def resolve_introspector(name)
|
|
49
|
+
case name
|
|
50
|
+
when :schema then Introspectors::SchemaIntrospector.new(app)
|
|
51
|
+
when :models then Introspectors::ModelIntrospector.new(app)
|
|
52
|
+
when :routes then Introspectors::RouteIntrospector.new(app)
|
|
53
|
+
when :jobs then Introspectors::JobIntrospector.new(app)
|
|
54
|
+
when :gems then Introspectors::GemIntrospector.new(app)
|
|
55
|
+
when :conventions then Introspectors::ConventionDetector.new(app)
|
|
56
|
+
else
|
|
57
|
+
raise ConfigurationError, "Unknown introspector: #{name}"
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|