Class: RailsAiContext::Configuration

Inherits:
Object
  • Object
show all
Defined in:
lib/rails_ai_context/configuration.rb

Constant Summary collapse

CONFIG_FILENAME =
".rails-ai-context.yml"
SYMBOL_KEYS =

Keys that require symbol conversion (string → symbol or array of symbols)

%i[tool_mode preset context_mode live_reload].freeze
SYMBOL_ARRAY_KEYS =
%i[ai_tools introspectors].freeze
YAML_KEYS =

All YAML-supported keys (explicit allowlist for safety)

%i[
  ai_tools tool_mode preset context_mode generate_root_files claude_max_lines
  anti_hallucination_rules
  server_name cache_ttl max_tool_response_chars
  live_reload live_reload_debounce auto_mount http_path http_bind http_port
  output_dir skip_tools excluded_models excluded_controllers
  excluded_route_prefixes excluded_filters excluded_middleware excluded_association_names excluded_paths
  sensitive_patterns search_extensions concern_paths frontend_paths
  max_file_size max_test_file_size max_schema_file_size max_view_total_size
  max_view_file_size max_search_results max_validate_files
  query_timeout query_row_limit query_redacted_columns allow_query_in_production
  log_lines introspectors
  hydration_enabled hydration_max_hints
  instrumentation_include_arguments
].freeze
PRESETS =
{
  standard: %i[schema models routes jobs gems conventions controllers tests migrations stimulus
               view_templates config components
               turbo auth performance i18n],
  full: %i[schema models routes jobs gems conventions stimulus database_stats controllers views view_templates turbo
           i18n config active_storage action_text auth api tests rake_tasks assets
           devops action_mailbox migrations seeds middleware engines multi_database
           components performance frontend_frameworks
           initializers autoload connection_pool active_support credentials security observability env]
}.freeze
DEFAULT_EXCLUDED_FILTERS =
%w[
  verify_authenticity_token verify_same_origin_request
  turbo_tracking_request_id handle_unverified_request
  mark_for_same_origin_verification
].freeze
DEFAULT_EXCLUDED_MIDDLEWARE =
%w[
  Rack::Sendfile ActionDispatch::Static ActionDispatch::Executor
  ActionDispatch::ServerTiming Rack::Runtime
  ActionDispatch::RequestId ActionDispatch::RemoteIp
  Rails::Rack::Logger ActionDispatch::ShowExceptions
  ActionDispatch::DebugExceptions ActionDispatch::Callbacks
  ActionDispatch::Cookies ActionDispatch::Session::CookieStore
  ActionDispatch::Flash ActionDispatch::ContentSecurityPolicy::Middleware
  ActionDispatch::PermissionsPolicy::Middleware ActionDispatch::ActionableExceptions
  Rack::Head Rack::ConditionalGet Rack::ETag Rack::TempfileReaper
  ActiveRecord::Migration::CheckPending ActionDispatch::HostAuthorization
  Rack::MethodOverride ActionDispatch::Session::AbstractSecureStore
].freeze
DEFAULT_EXCLUDED_CONCERNS =
[
  /::Generated/,
  /\A(ActiveRecord|ActiveModel|ActiveSupport|ActionText|ActionMailbox|ActiveStorage)/,
  /\A(ActionDispatch|ActionController|ActionView|AbstractController)/,
  /\A(Devise::Models|Devise::Orm|Bullet::|Turbo::|GlobalID::|Rolify::)/
].freeze
DEFAULT_EXCLUDED_ASSOCIATION_NAMES =
%w[
  active_storage_attachments active_storage_blobs
  rich_text_body rich_text_content
  action_mailbox_inbound_emails
  noticed_events noticed_notifications
].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeConfiguration

Returns a new instance of Configuration.



242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
# File 'lib/rails_ai_context/configuration.rb', line 242

def initialize
  @server_name         = "rails-ai-context"
  @introspectors       = PRESETS[:full].dup
  @excluded_paths      = %w[node_modules tmp log vendor .git doc docs]
  @sensitive_patterns  = %w[
    .env .env.*
    config/master.key
    config/credentials.yml.enc config/credentials/*.yml.enc
    config/database.yml config/secrets.yml
    config/cable.yml config/storage.yml
    config/mongoid.yml config/redis.yml
    *.pem *.key *.p12 *.pfx *.jks *.keystore
    **/id_rsa **/id_ed25519 **/id_ecdsa **/id_dsa
    .ssh/* .aws/credentials .aws/config .netrc .pgpass .my.cnf
  ]
  @auto_mount          = false
  @http_path           = "/mcp"
  @http_bind           = "127.0.0.1"
  @http_port           = 6029
  @output_dir          = nil # defaults to Rails.root
  @excluded_models     = %w[
    ApplicationRecord
    ActiveStorage::Blob ActiveStorage::Attachment ActiveStorage::VariantRecord
    ActionText::RichText ActionText::EncryptedRichText
    ActionMailbox::InboundEmail ActionMailbox::Record
  ]
  @cache_ttl                = 60
  @context_mode             = :compact
  @claude_max_lines         = 150
  @max_tool_response_chars  = 200_000
  @live_reload              = :auto
  @live_reload_debounce     = 1.5
  @instrumentation_include_arguments = false
  @generate_root_files      = true
  @anti_hallucination_rules = true
  @max_file_size            = 5_000_000
  @max_test_file_size       = 1_000_000
  @max_schema_file_size     = 10_000_000
  @max_view_total_size      = 10_000_000
  @max_view_file_size       = 1_000_000
  @max_search_results       = 200
  @max_validate_files       = 50
  @excluded_controllers     = %w[DeviseController Devise::OmniauthCallbacksController]
  @excluded_route_prefixes  = %w[action_mailbox/ active_storage/ rails/ conductor/ devise/ turbo/]
  @excluded_concerns        = DEFAULT_EXCLUDED_CONCERNS.dup
  @excluded_filters         = DEFAULT_EXCLUDED_FILTERS.dup
  @excluded_middleware      = DEFAULT_EXCLUDED_MIDDLEWARE.dup
  @excluded_association_names = DEFAULT_EXCLUDED_ASSOCIATION_NAMES.dup
  @custom_tools             = []
  @skip_tools               = []
  @ai_tools                 = nil
  @tool_mode                = :mcp
  @search_extensions        = %w[rb js erb yml yaml json ts tsx vue svelte haml slim]
  @concern_paths            = %w[app/models/concerns app/controllers/concerns]
  @frontend_paths           = nil
  @query_timeout            = 5
  @query_row_limit          = 100
  @query_redacted_columns   = %w[
    password_digest encrypted_password password_hash
    reset_password_token confirmation_token unlock_token
    otp_secret session_data secret_key
    api_key api_secret access_token refresh_token jti
  ]
  @allow_query_in_production = false
  @log_lines                = 50
  @hydration_enabled        = true
  @hydration_max_hints      = 5
end

Instance Attribute Details

#ai_toolsObject

Which AI tools to generate context for (selected during install) nil = all formats, or %i[claude cursor copilot opencode codex]



175
176
177
# File 'lib/rails_ai_context/configuration.rb', line 175

def ai_tools
  @ai_tools
end

#allow_query_in_productionObject

Allow rails_query in production (default: false)



233
234
235
# File 'lib/rails_ai_context/configuration.rb', line 233

def allow_query_in_production
  @allow_query_in_production
end

#anti_hallucination_rulesObject

Whether to embed the Anti-Hallucination Protocol section in generated context files. Default: true. Set false to skip the 6-rule verification protocol in CLAUDE.md, AGENTS.md, .claude/rules/, .cursor/rules/, .github/instructions/.



156
157
158
# File 'lib/rails_ai_context/configuration.rb', line 156

def anti_hallucination_rules
  @anti_hallucination_rules
end

#auto_mountObject

Whether to auto-mount the MCP HTTP endpoint



102
103
104
# File 'lib/rails_ai_context/configuration.rb', line 102

def auto_mount
  @auto_mount
end

#cache_ttlObject

TTL in seconds for cached introspection (default: 30)



114
115
116
# File 'lib/rails_ai_context/configuration.rb', line 114

def cache_ttl
  @cache_ttl
end

#claude_max_linesObject

Max lines for generated CLAUDE.md (only applies in :compact mode)



122
123
124
# File 'lib/rails_ai_context/configuration.rb', line 122

def claude_max_lines
  @claude_max_lines
end

#concern_pathsObject

Where to look for concern source files (default: app/models/concerns)



224
225
226
# File 'lib/rails_ai_context/configuration.rb', line 224

def concern_paths
  @concern_paths
end

#context_modeObject

Context file generation mode :compact — ≤150 lines CLAUDE.md, references MCP tools for details (default) :full — current behavior, dumps everything into context files



119
120
121
# File 'lib/rails_ai_context/configuration.rb', line 119

def context_mode
  @context_mode
end

#custom_toolsObject

Additional MCP tool classes to register alongside built-in tools



168
169
170
# File 'lib/rails_ai_context/configuration.rb', line 168

def custom_tools
  @custom_tools
end

#excluded_association_namesObject

Framework association names hidden from model output



220
221
222
# File 'lib/rails_ai_context/configuration.rb', line 220

def excluded_association_names
  @excluded_association_names
end

#excluded_concernsObject

Regex patterns for concerns to hide (e.g. /Devise::Models/)



217
218
219
# File 'lib/rails_ai_context/configuration.rb', line 217

def excluded_concerns
  @excluded_concerns
end

#excluded_controllersObject

Filtering — customize what’s hidden from AI output



215
216
217
# File 'lib/rails_ai_context/configuration.rb', line 215

def excluded_controllers
  @excluded_controllers
end

#excluded_filtersObject

Framework filter names hidden from controller output



218
219
220
# File 'lib/rails_ai_context/configuration.rb', line 218

def excluded_filters
  @excluded_filters
end

#excluded_middlewareObject

Default middleware hidden from config output



219
220
221
# File 'lib/rails_ai_context/configuration.rb', line 219

def excluded_middleware
  @excluded_middleware
end

#excluded_modelsObject

Models/tables to exclude from introspection



111
112
113
# File 'lib/rails_ai_context/configuration.rb', line 111

def excluded_models
  @excluded_models
end

#excluded_pathsObject

Paths to exclude from code search



96
97
98
# File 'lib/rails_ai_context/configuration.rb', line 96

def excluded_paths
  @excluded_paths
end

#excluded_route_prefixesObject

Route controller prefixes hidden with app_only (e.g. action_mailbox/)



216
217
218
# File 'lib/rails_ai_context/configuration.rb', line 216

def excluded_route_prefixes
  @excluded_route_prefixes
end

#frontend_pathsObject

Frontend framework detection (optional overrides — auto-detected if nil)



227
228
229
# File 'lib/rails_ai_context/configuration.rb', line 227

def frontend_paths
  @frontend_paths
end

#generate_root_filesObject

Whether to generate root-level context files (CLAUDE.md, AGENTS.md, etc.) When false, only generates split rule files (.claude/rules/, .cursor/rules/, etc.)



151
152
153
# File 'lib/rails_ai_context/configuration.rb', line 151

def generate_root_files
  @generate_root_files
end

#http_bindObject

HTTP transport settings



105
106
107
# File 'lib/rails_ai_context/configuration.rb', line 105

def http_bind
  @http_bind
end

#http_pathObject

HTTP transport settings



105
106
107
# File 'lib/rails_ai_context/configuration.rb', line 105

def http_path
  @http_path
end

#http_portObject

HTTP transport settings



105
106
107
# File 'lib/rails_ai_context/configuration.rb', line 105

def http_port
  @http_port
end

#hydration_enabledObject

Hydration: inject schema hints into controller/view tool responses



239
240
241
# File 'lib/rails_ai_context/configuration.rb', line 239

def hydration_enabled
  @hydration_enabled
end

#hydration_max_hintsObject

Max schema hints per response (default: 5)



240
241
242
# File 'lib/rails_ai_context/configuration.rb', line 240

def hydration_max_hints
  @hydration_max_hints
end

#instrumentation_include_argumentsObject

Whether to include raw tool arguments in ActiveSupport::Notifications instrumentation events. Default: false (v5.8.1+). When false, only metadata (method, tool_name, duration, error) is forwarded to subscribers. When true, ‘tool_arguments` and `arguments` are forwarded verbatim — including raw SQL from `rails_query`, env var names from `rails_get_env`, and log search patterns from `rails_read_logs`.

Setting this to true means the operator takes on the redaction obligation for any downstream observability pipeline (Datadog, Scout, custom loggers) that receives these events. See CHANGELOG.md for v5.8.1 for the security review that changed the default.



147
148
149
# File 'lib/rails_ai_context/configuration.rb', line 147

def instrumentation_include_arguments
  @instrumentation_include_arguments
end

#introspectorsObject

Which introspectors to run



93
94
95
# File 'lib/rails_ai_context/configuration.rb', line 93

def introspectors
  @introspectors
end

#live_reloadObject

Live reload: auto-invalidate MCP tool caches on file changes :auto (default) — enable if ‘listen` gem is available, skip silently otherwise true — enable, raise if `listen` gem is missing false — disable entirely



131
132
133
# File 'lib/rails_ai_context/configuration.rb', line 131

def live_reload
  @live_reload
end

#live_reload_debounceObject

Debounce interval in seconds for live reload file watching



134
135
136
# File 'lib/rails_ai_context/configuration.rb', line 134

def live_reload_debounce
  @live_reload_debounce
end

#log_linesObject

Log reading settings (rails_read_logs)



236
237
238
# File 'lib/rails_ai_context/configuration.rb', line 236

def log_lines
  @log_lines
end

#max_file_sizeObject

File size limits (bytes) — increase for larger projects



159
160
161
# File 'lib/rails_ai_context/configuration.rb', line 159

def max_file_size
  @max_file_size
end

#max_schema_file_sizeObject

schema.rb / structure.sql parse limit (default: 10MB)



161
162
163
# File 'lib/rails_ai_context/configuration.rb', line 161

def max_schema_file_size
  @max_schema_file_size
end

#max_search_resultsObject

Max search results per call (default: 100)



164
165
166
# File 'lib/rails_ai_context/configuration.rb', line 164

def max_search_results
  @max_search_results
end

#max_test_file_sizeObject

Test file read limit (default: 500KB)



160
161
162
# File 'lib/rails_ai_context/configuration.rb', line 160

def max_test_file_size
  @max_test_file_size
end

#max_tool_response_charsObject

Max characters for any single MCP tool response (safety net)



125
126
127
# File 'lib/rails_ai_context/configuration.rb', line 125

def max_tool_response_chars
  @max_tool_response_chars
end

#max_validate_filesObject

Max files per validate call (default: 20)



165
166
167
# File 'lib/rails_ai_context/configuration.rb', line 165

def max_validate_files
  @max_validate_files
end

#max_view_file_sizeObject

Per-view file during aggregation (default: 500KB)



163
164
165
# File 'lib/rails_ai_context/configuration.rb', line 163

def max_view_file_size
  @max_view_file_size
end

#max_view_total_sizeObject

Total aggregated view content for template scanning (default: 5MB)



162
163
164
# File 'lib/rails_ai_context/configuration.rb', line 162

def max_view_total_size
  @max_view_total_size
end

#output_dirObject

Output directory for generated context files



108
109
110
# File 'lib/rails_ai_context/configuration.rb', line 108

def output_dir
  @output_dir
end

#query_redacted_columnsObject

Column names whose values are redacted in output



232
233
234
# File 'lib/rails_ai_context/configuration.rb', line 232

def query_redacted_columns
  @query_redacted_columns
end

#query_row_limitObject

Max rows returned (default: 100, hard cap: 1000)



231
232
233
# File 'lib/rails_ai_context/configuration.rb', line 231

def query_row_limit
  @query_row_limit
end

#query_timeoutObject

Database query tool settings (rails_query)



230
231
232
# File 'lib/rails_ai_context/configuration.rb', line 230

def query_timeout
  @query_timeout
end

#search_extensionsObject

Search and file discovery



223
224
225
# File 'lib/rails_ai_context/configuration.rb', line 223

def search_extensions
  @search_extensions
end

#sensitive_patternsObject

Sensitive file patterns blocked from search and read tools



99
100
101
# File 'lib/rails_ai_context/configuration.rb', line 99

def sensitive_patterns
  @sensitive_patterns
end

#server_nameObject

MCP server settings



86
87
88
# File 'lib/rails_ai_context/configuration.rb', line 86

def server_name
  @server_name
end

#skip_toolsObject

Built-in tool names to skip (e.g. %w[rails_security_scan rails_query])



171
172
173
# File 'lib/rails_ai_context/configuration.rb', line 171

def skip_tools
  @skip_tools
end

#tool_modeObject

Tool invocation mode: :mcp (MCP primary + CLI fallback) or :cli (CLI only)



178
179
180
# File 'lib/rails_ai_context/configuration.rb', line 178

def tool_mode
  @tool_mode
end

Class Method Details

.auto_load!(dir = nil) ⇒ Object

Auto-load config from .rails-ai-context.yml if no initializer configure block ran. Safe to call multiple times (idempotent).



55
56
57
58
59
60
61
# File 'lib/rails_ai_context/configuration.rb', line 55

def self.auto_load!(dir = nil)
  return if RailsAiContext.configured_via_block?

  dir ||= defined?(Rails) && Rails.respond_to?(:root) && Rails.root ? Rails.root.to_s : Dir.pwd
  yaml_path = File.join(dir, CONFIG_FILENAME)
  load_from_yaml(yaml_path) if File.exist?(yaml_path)
end

.load_from_yaml(path) ⇒ Object

Load configuration from a YAML file, applying values to the current config instance. Only keys present in the YAML are set; absent keys keep their defaults.



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/rails_ai_context/configuration.rb', line 32

def self.load_from_yaml(path)
  return unless File.exist?(path)

  data = YAML.safe_load_file(path, permitted_classes: [ Symbol ]) || {}
  config = RailsAiContext.configuration

  data.each do |key, value|
    key_sym = key.to_sym
    next unless YAML_KEYS.include?(key_sym)
    next if value.nil?

    value = coerce_value(key_sym, value)
    config.public_send(:"#{key_sym}=", value)
  end

  config
rescue Psych::SyntaxError, Psych::DisallowedClass => e
  $stderr.puts "[rails-ai-context] WARNING: #{path} has invalid YAML (#{e.message}). Using defaults."
  nil
end

Instance Method Details

#output_dir_for(app) ⇒ Object



317
318
319
# File 'lib/rails_ai_context/configuration.rb', line 317

def output_dir_for(app)
  @output_dir || app.root.to_s
end

#preset=(name) ⇒ Object

Raises:

  • (ArgumentError)


311
312
313
314
315
# File 'lib/rails_ai_context/configuration.rb', line 311

def preset=(name)
  name = name.to_sym
  raise ArgumentError, "Unknown preset: #{name}. Valid presets: #{PRESETS.keys.join(", ")}" unless PRESETS.key?(name)
  @introspectors = PRESETS[name].dup
end

#server_versionObject



88
89
90
# File 'lib/rails_ai_context/configuration.rb', line 88

def server_version
  RailsAiContext::VERSION
end