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]
}.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.



241
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
# File 'lib/rails_ai_context/configuration.rb', line 241

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]



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

def ai_tools
  @ai_tools
end

#allow_query_in_productionObject

Allow rails_query in production (default: false)



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

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/.



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

def anti_hallucination_rules
  @anti_hallucination_rules
end

#auto_mountObject

Whether to auto-mount the MCP HTTP endpoint



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

def auto_mount
  @auto_mount
end

#cache_ttlObject

TTL in seconds for cached introspection (default: 30)



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

def cache_ttl
  @cache_ttl
end

#claude_max_linesObject

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



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

def claude_max_lines
  @claude_max_lines
end

#concern_pathsObject

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



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

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



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

def context_mode
  @context_mode
end

#custom_toolsObject

Additional MCP tool classes to register alongside built-in tools



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

def custom_tools
  @custom_tools
end

#excluded_association_namesObject

Framework association names hidden from model output



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

def excluded_association_names
  @excluded_association_names
end

#excluded_concernsObject

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



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

def excluded_concerns
  @excluded_concerns
end

#excluded_controllersObject

Filtering — customize what’s hidden from AI output



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

def excluded_controllers
  @excluded_controllers
end

#excluded_filtersObject

Framework filter names hidden from controller output



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

def excluded_filters
  @excluded_filters
end

#excluded_middlewareObject

Default middleware hidden from config output



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

def excluded_middleware
  @excluded_middleware
end

#excluded_modelsObject

Models/tables to exclude from introspection



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

def excluded_models
  @excluded_models
end

#excluded_pathsObject

Paths to exclude from code search



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

def excluded_paths
  @excluded_paths
end

#excluded_route_prefixesObject

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



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

def excluded_route_prefixes
  @excluded_route_prefixes
end

#frontend_pathsObject

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



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

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.)



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

def generate_root_files
  @generate_root_files
end

#http_bindObject

HTTP transport settings



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

def http_bind
  @http_bind
end

#http_pathObject

HTTP transport settings



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

def http_path
  @http_path
end

#http_portObject

HTTP transport settings



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

def http_port
  @http_port
end

#hydration_enabledObject

Hydration: inject schema hints into controller/view tool responses



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

def hydration_enabled
  @hydration_enabled
end

#hydration_max_hintsObject

Max schema hints per response (default: 5)



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

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.



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

def instrumentation_include_arguments
  @instrumentation_include_arguments
end

#introspectorsObject

Which introspectors to run



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

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



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

def live_reload
  @live_reload
end

#live_reload_debounceObject

Debounce interval in seconds for live reload file watching



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

def live_reload_debounce
  @live_reload_debounce
end

#log_linesObject

Log reading settings (rails_read_logs)



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

def log_lines
  @log_lines
end

#max_file_sizeObject

File size limits (bytes) — increase for larger projects



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

def max_file_size
  @max_file_size
end

#max_schema_file_sizeObject

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



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

def max_schema_file_size
  @max_schema_file_size
end

#max_search_resultsObject

Max search results per call (default: 100)



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

def max_search_results
  @max_search_results
end

#max_test_file_sizeObject

Test file read limit (default: 500KB)



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

def max_test_file_size
  @max_test_file_size
end

#max_tool_response_charsObject

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



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

def max_tool_response_chars
  @max_tool_response_chars
end

#max_validate_filesObject

Max files per validate call (default: 20)



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

def max_validate_files
  @max_validate_files
end

#max_view_file_sizeObject

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



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

def max_view_file_size
  @max_view_file_size
end

#max_view_total_sizeObject

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



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

def max_view_total_size
  @max_view_total_size
end

#output_dirObject

Output directory for generated context files



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

def output_dir
  @output_dir
end

#query_redacted_columnsObject

Column names whose values are redacted in output



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

def query_redacted_columns
  @query_redacted_columns
end

#query_row_limitObject

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



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

def query_row_limit
  @query_row_limit
end

#query_timeoutObject

Database query tool settings (rails_query)



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

def query_timeout
  @query_timeout
end

#search_extensionsObject

Search and file discovery



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

def search_extensions
  @search_extensions
end

#sensitive_patternsObject

Sensitive file patterns blocked from search and read tools



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

def sensitive_patterns
  @sensitive_patterns
end

#server_nameObject

MCP server settings



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

def server_name
  @server_name
end

#skip_toolsObject

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



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

def skip_tools
  @skip_tools
end

#tool_modeObject

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



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

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



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

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

#preset=(name) ⇒ Object

Raises:

  • (ArgumentError)


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

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



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

def server_version
  RailsAiContext::VERSION
end