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.
Files changed (35) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +23 -0
  4. data/CHANGELOG.md +26 -0
  5. data/LICENSE +21 -0
  6. data/README.md +212 -0
  7. data/Rakefile +8 -0
  8. data/exe/rails-ai-context +67 -0
  9. data/lib/generators/rails_ai_context/install/install_generator.rb +85 -0
  10. data/lib/rails-ai-context.rb +5 -0
  11. data/lib/rails_ai_context/configuration.rb +52 -0
  12. data/lib/rails_ai_context/engine.rb +21 -0
  13. data/lib/rails_ai_context/introspector.rb +61 -0
  14. data/lib/rails_ai_context/introspectors/convention_detector.rb +125 -0
  15. data/lib/rails_ai_context/introspectors/gem_introspector.rb +128 -0
  16. data/lib/rails_ai_context/introspectors/job_introspector.rb +82 -0
  17. data/lib/rails_ai_context/introspectors/model_introspector.rb +163 -0
  18. data/lib/rails_ai_context/introspectors/route_introspector.rb +83 -0
  19. data/lib/rails_ai_context/introspectors/schema_introspector.rb +143 -0
  20. data/lib/rails_ai_context/serializers/context_file_serializer.rb +60 -0
  21. data/lib/rails_ai_context/serializers/json_serializer.rb +19 -0
  22. data/lib/rails_ai_context/serializers/markdown_serializer.rb +158 -0
  23. data/lib/rails_ai_context/server.rb +90 -0
  24. data/lib/rails_ai_context/tasks/rails_ai_context.rake +89 -0
  25. data/lib/rails_ai_context/tools/base_tool.rb +37 -0
  26. data/lib/rails_ai_context/tools/get_conventions.rb +87 -0
  27. data/lib/rails_ai_context/tools/get_gems.rb +49 -0
  28. data/lib/rails_ai_context/tools/get_model_details.rb +103 -0
  29. data/lib/rails_ai_context/tools/get_routes.rb +50 -0
  30. data/lib/rails_ai_context/tools/get_schema.rb +93 -0
  31. data/lib/rails_ai_context/tools/search_code.rb +111 -0
  32. data/lib/rails_ai_context/version.rb +5 -0
  33. data/lib/rails_ai_context.rb +74 -0
  34. data/rails-ai-context.gemspec +52 -0
  35. 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
@@ -0,0 +1,3 @@
1
+ --require spec_helper
2
+ --format documentation
3
+ --color
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
+ [![Gem Version](https://badge.fury.io/rb/rails-ai-context.svg)](https://rubygems.org/gems/rails-ai-context)
6
+ [![CI](https://github.com/crisnahine/rails-ai-context/actions/workflows/ci.yml/badge.svg)](https://github.com/crisnahine/rails-ai-context/actions)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](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,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
@@ -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,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Bundler auto-requires using the gem name (dashes).
4
+ # Forward to the real entry point (underscores).
5
+ require_relative "rails_ai_context"
@@ -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