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



227
228
229
230
231
232
233
234
235
236
237
238
239
240
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
# File 'lib/rails_ai_context/configuration.rb', line 227

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 *.pem *.key
  ]
  @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
  @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]



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

def ai_tools
  @ai_tools
end

#allow_query_in_productionObject

Allow rails_query in production (default: false)



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

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



141
142
143
# File 'lib/rails_ai_context/configuration.rb', line 141

def anti_hallucination_rules
  @anti_hallucination_rules
end

#auto_mountObject

Whether to auto-mount the MCP HTTP endpoint



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

def auto_mount
  @auto_mount
end

#cache_ttlObject

TTL in seconds for cached introspection (default: 30)



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

def cache_ttl
  @cache_ttl
end

#claude_max_linesObject

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



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

def claude_max_lines
  @claude_max_lines
end

#concern_pathsObject

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



209
210
211
# File 'lib/rails_ai_context/configuration.rb', line 209

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



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

def context_mode
  @context_mode
end

#custom_toolsObject

Additional MCP tool classes to register alongside built-in tools



153
154
155
# File 'lib/rails_ai_context/configuration.rb', line 153

def custom_tools
  @custom_tools
end

#excluded_association_namesObject

Framework association names hidden from model output



205
206
207
# File 'lib/rails_ai_context/configuration.rb', line 205

def excluded_association_names
  @excluded_association_names
end

#excluded_concernsObject

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



202
203
204
# File 'lib/rails_ai_context/configuration.rb', line 202

def excluded_concerns
  @excluded_concerns
end

#excluded_controllersObject

Filtering — customize what’s hidden from AI output



200
201
202
# File 'lib/rails_ai_context/configuration.rb', line 200

def excluded_controllers
  @excluded_controllers
end

#excluded_filtersObject

Framework filter names hidden from controller output



203
204
205
# File 'lib/rails_ai_context/configuration.rb', line 203

def excluded_filters
  @excluded_filters
end

#excluded_middlewareObject

Default middleware hidden from config output



204
205
206
# File 'lib/rails_ai_context/configuration.rb', line 204

def excluded_middleware
  @excluded_middleware
end

#excluded_modelsObject

Models/tables to exclude from introspection



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

def excluded_models
  @excluded_models
end

#excluded_pathsObject

Paths to exclude from code search



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

def excluded_paths
  @excluded_paths
end

#excluded_route_prefixesObject

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



201
202
203
# File 'lib/rails_ai_context/configuration.rb', line 201

def excluded_route_prefixes
  @excluded_route_prefixes
end

#frontend_pathsObject

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



212
213
214
# File 'lib/rails_ai_context/configuration.rb', line 212

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



136
137
138
# File 'lib/rails_ai_context/configuration.rb', line 136

def generate_root_files
  @generate_root_files
end

#http_bindObject

HTTP transport settings



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

def http_bind
  @http_bind
end

#http_pathObject

HTTP transport settings



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

def http_path
  @http_path
end

#http_portObject

HTTP transport settings



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

def http_port
  @http_port
end

#hydration_enabledObject

Hydration: inject schema hints into controller/view tool responses



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

def hydration_enabled
  @hydration_enabled
end

#hydration_max_hintsObject

Max schema hints per response (default: 5)



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

def hydration_max_hints
  @hydration_max_hints
end

#introspectorsObject

Which introspectors to run



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

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



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

def live_reload
  @live_reload
end

#live_reload_debounceObject

Debounce interval in seconds for live reload file watching



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

def live_reload_debounce
  @live_reload_debounce
end

#log_linesObject

Log reading settings (rails_read_logs)



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

def log_lines
  @log_lines
end

#max_file_sizeObject

File size limits (bytes) — increase for larger projects



144
145
146
# File 'lib/rails_ai_context/configuration.rb', line 144

def max_file_size
  @max_file_size
end

#max_schema_file_sizeObject

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



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

def max_schema_file_size
  @max_schema_file_size
end

#max_search_resultsObject

Max search results per call (default: 100)



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

def max_search_results
  @max_search_results
end

#max_test_file_sizeObject

Test file read limit (default: 500KB)



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

def max_test_file_size
  @max_test_file_size
end

#max_tool_response_charsObject

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



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

def max_tool_response_chars
  @max_tool_response_chars
end

#max_validate_filesObject

Max files per validate call (default: 20)



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

def max_validate_files
  @max_validate_files
end

#max_view_file_sizeObject

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



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

def max_view_file_size
  @max_view_file_size
end

#max_view_total_sizeObject

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



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

def max_view_total_size
  @max_view_total_size
end

#output_dirObject

Output directory for generated context files



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

def output_dir
  @output_dir
end

#query_redacted_columnsObject

Column names whose values are redacted in output



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

def query_redacted_columns
  @query_redacted_columns
end

#query_row_limitObject

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



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

def query_row_limit
  @query_row_limit
end

#query_timeoutObject

Database query tool settings (rails_query)



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

def query_timeout
  @query_timeout
end

#search_extensionsObject

Search and file discovery



208
209
210
# File 'lib/rails_ai_context/configuration.rb', line 208

def search_extensions
  @search_extensions
end

#sensitive_patternsObject

Sensitive file patterns blocked from search and read tools



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

def sensitive_patterns
  @sensitive_patterns
end

#server_nameObject

MCP server settings



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

def server_name
  @server_name
end

#skip_toolsObject

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



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

def skip_tools
  @skip_tools
end

#tool_modeObject

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



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

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



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

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.



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

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



294
295
296
# File 'lib/rails_ai_context/configuration.rb', line 294

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

#preset=(name) ⇒ Object

Raises:

  • (ArgumentError)


288
289
290
291
292
# File 'lib/rails_ai_context/configuration.rb', line 288

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



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

def server_version
  RailsAiContext::VERSION
end