rails-ai-context 0.15.4 → 0.15.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: df16cb513ad22c8fca7405fed9a9b111e7018184e1bd16cd08230dace76a9612
4
- data.tar.gz: c4846d86197db0fe697b21cd23ead829a4433abfe444b0a14695433a5ab3d0f0
3
+ metadata.gz: 0eb46f9da0fc24418021dbb2ca4a6850017ab555ac0bbe98b589777ef30593a2
4
+ data.tar.gz: 5b77c8e0b1c7832c17ea84fffdc96524060fc594e4691f11a84b5e010158f925
5
5
  SHA512:
6
- metadata.gz: dd8e4f99421b6efbc1b589734c03dbf3f167ec6a2779957a357f2924a9ac3bccd3d40c5c8aca442d92e9392cfed40d517b20455f7e9a9dd2f792c543c3c13928
7
- data.tar.gz: f970c8cf22b53531143352ea4a8a90d615dbe7530a2a70eabd04dd7fd9e532119a803260681dbb431278ad6bfdc7103e82b487840514afd0c49b4c792e3ce8df
6
+ metadata.gz: 13a6f6e8e274cf47210b6cb94f160ba00e4cebe3349eb6c1e2612b4ec53561ab87d99690c9949c4eae389427bf7e80850b1c5a930283792bfa3294010303ec04
7
+ data.tar.gz: 5ae9e78447e0ec33496b608729be0088bf57f180a37f27690f7eaa0b6ca0a3c1a6637887a747d3de67bec808636a139be88e2b9ba72e71db0e07faa156541182
data/CHANGELOG.md CHANGED
@@ -5,6 +5,35 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.15.6] - 2026-03-22
9
+
10
+ ### Added
11
+
12
+ - **7 new configurable options** — `excluded_controllers`, `excluded_route_prefixes`, `excluded_concerns`, `excluded_filters`, `excluded_middleware`, `search_extensions`, `concern_paths` for stack-specific customization.
13
+ - **Configurable file size limits** — `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` all exposed via `Configuration`.
14
+ - **Class methods in model detail** — `rails_get_model_details` now shows class methods section.
15
+ - **Custom validate methods** — `validate :method_name` calls extracted from source and shown in model detail.
16
+
17
+ ### Fixed
18
+
19
+ - **Schema defaults always visible** — Null and Default columns always shown (NOT NULL marked bold). Previous token-saving logic accidentally hid critical migration data.
20
+ - **Optional associations** — `belongs_to` with `optional: true` now shows `[optional]` flag.
21
+ - **Concern methods inline** — shows public methods from concern source files (e.g. `PlanLimitable — can_cook?, increment_cook_count!`).
22
+ - **MCP tool error messages** — all tools now show available values on error/not-found for AI self-correction.
23
+
24
+ ## [0.15.5] - 2026-03-22
25
+
26
+ ### Fixed
27
+
28
+ - **ERB validation** — now catches missing `<% end %>` by compiling ERB to Ruby then syntax-checking the result (was only checking ERB tag syntax).
29
+ - **Controller namespace format** — accepts both `Bonus::CrisesController` and `bonus/crises` (cross-tool consistency).
30
+ - **Layouts discoverable** — `controller:"layouts"` now works in view tool.
31
+ - **Validate error detail** — Ruby shows up to 5 error lines, JS shows 3 (was truncated to 1).
32
+ - **Invalid/empty regex** — early validation with clear error messages instead of silent fail.
33
+ - **Route count accuracy** — shows filtered count when `app_only:true`, not unfiltered total.
34
+ - **Namespace test lookup** — supports `bonus/crises` format and flat test directories.
35
+ - **Empty inputs** — `near:""` in edit_context and `pattern:""` in search return helpful errors.
36
+
8
37
  ## [0.15.4] - 2026-03-22
9
38
 
10
39
  ### Fixed
data/README.md CHANGED
@@ -295,22 +295,45 @@ end
295
295
 
296
296
  | Option | Default | Description |
297
297
  |--------|---------|-------------|
298
+ | **Presets & Introspectors** | | |
298
299
  | `preset` | `:standard` | Introspector preset (`:standard` or `:full`) |
299
300
  | `introspectors` | 13 core | Array of introspector symbols |
301
+ | **Context Generation** | | |
300
302
  | `context_mode` | `:compact` | `:compact` (≤150 lines) or `:full` (dump everything) |
301
303
  | `claude_max_lines` | `150` | Max lines for CLAUDE.md in compact mode |
302
- | `max_tool_response_chars` | `120_000` | Safety cap for MCP tool responses |
303
- | `excluded_models` | internal Rails models | Models to skip during introspection |
304
- | `excluded_paths` | `node_modules tmp log vendor .git` | Paths excluded from code search |
305
- | `sensitive_patterns` | `.env .env.* *.key *.pem config/master.key config/credentials.yml.enc` | File patterns blocked from search and read tools |
304
+ | `generate_root_files` | `true` | Generate root files (CLAUDE.md, etc.) — set `false` for split rules only |
305
+ | `output_dir` | `Rails.root` | Output directory for generated context files |
306
+ | **MCP Server** | | |
307
+ | `server_name` | `"rails-ai-context"` | MCP server name |
308
+ | `server_version` | gem version | MCP server version |
306
309
  | `auto_mount` | `false` | Auto-mount HTTP MCP endpoint |
307
310
  | `http_path` | `"/mcp"` | HTTP endpoint path |
308
311
  | `http_port` | `6029` | HTTP server port |
309
312
  | `http_bind` | `"127.0.0.1"` | HTTP server bind address |
310
313
  | `cache_ttl` | `30` | Cache TTL in seconds |
314
+ | `max_tool_response_chars` | `120_000` | Safety cap for MCP tool responses |
311
315
  | `live_reload` | `:auto` | `:auto`, `true`, or `false` — MCP live reload |
312
316
  | `live_reload_debounce` | `1.5` | Debounce interval in seconds |
313
- | `generate_root_files` | `true` | Generate root files (CLAUDE.md, etc.) — set `false` for split rules only |
317
+ | **Filtering & Exclusions** | | |
318
+ | `excluded_models` | internal Rails models | Models to skip during introspection |
319
+ | `excluded_paths` | `node_modules tmp log vendor .git` | Paths excluded from code search |
320
+ | `sensitive_patterns` | `.env .env.* config/master.key config/credentials.yml.enc config/credentials/*.yml.enc *.pem *.key` | File patterns blocked from search and read tools |
321
+ | `excluded_controllers` | `DeviseController` etc. | Controller classes hidden from listings |
322
+ | `excluded_route_prefixes` | `action_mailbox/ active_storage/ rails/` etc. | Route controller prefixes hidden with app_only |
323
+ | `excluded_concerns` | Rails/Devise/framework patterns | Regex patterns for concerns to hide |
324
+ | `excluded_filters` | `verify_authenticity_token` etc. | Framework filter names hidden from controller output |
325
+ | `excluded_middleware` | standard Rack/Rails middleware | Default middleware hidden from config output |
326
+ | **File Size Limits** | | |
327
+ | `max_file_size` | `2_000_000` | Per-file read limit for tools (bytes) |
328
+ | `max_test_file_size` | `500_000` | Test file read limit (bytes) |
329
+ | `max_schema_file_size` | `10_000_000` | schema.rb / structure.sql parse limit (bytes) |
330
+ | `max_view_total_size` | `5_000_000` | Total aggregated view content for UI patterns (bytes) |
331
+ | `max_view_file_size` | `500_000` | Per-view file during aggregation (bytes) |
332
+ | `max_search_results` | `100` | Max search results per call |
333
+ | `max_validate_files` | `20` | Max files per validate call |
334
+ | **Search & Discovery** | | |
335
+ | `search_extensions` | `rb js erb yml yaml json ts tsx vue svelte haml slim` | File extensions for Ruby fallback search |
336
+ | `concern_paths` | `app/models/concerns app/controllers/concerns` | Where to look for concern source files |
314
337
  </details>
315
338
 
316
339
  ---
data/SECURITY.md CHANGED
@@ -5,7 +5,7 @@
5
5
  | Version | Supported |
6
6
  |---------|--------------------|
7
7
  | 0.15.x | :white_check_mark: |
8
- | < 0.14 | :x: |
8
+ | < 0.15 | :x: |
9
9
 
10
10
  ## Reporting a Vulnerability
11
11
 
data/docs/GUIDE.md CHANGED
@@ -146,22 +146,23 @@ end
146
146
  | `app/models/AGENTS.md` | Model reference | Auto-loaded by OpenCode when reading files in `app/models/`. |
147
147
  | `app/controllers/AGENTS.md` | Controller reference | Auto-loaded by OpenCode when reading files in `app/controllers/`. |
148
148
 
149
- ### Cursor (6 files)
149
+ ### Cursor (5 files)
150
150
 
151
151
  | File | Purpose | Notes |
152
152
  |------|---------|-------|
153
153
  | `.cursor/rules/rails-project.mdc` | Project overview | `alwaysApply: true` — loaded in every conversation. |
154
154
  | `.cursor/rules/rails-models.mdc` | Model reference | `globs: app/models/**/*.rb` — auto-attaches when editing models. |
155
155
  | `.cursor/rules/rails-controllers.mdc` | Controller reference | `globs: app/controllers/**/*.rb` — auto-attaches when editing controllers. |
156
- | `.cursor/rules/rails-ui-patterns.mdc` | UI patterns and design tokens | `alwaysApply: true` — loaded in every conversation. |
156
+ | `.cursor/rules/rails-ui-patterns.mdc` | UI patterns and design tokens | `globs: app/views/**/*.erb` — loaded when editing views. |
157
157
  | `.cursor/rules/rails-mcp-tools.mdc` | MCP tool reference | `alwaysApply: true` — always available. |
158
158
 
159
- ### Windsurf (3 files)
159
+ ### Windsurf (4 files)
160
160
 
161
161
  | File | Purpose | Notes |
162
162
  |------|---------|-------|
163
163
  | `.windsurfrules` | Main context file | Hard-capped at 5,800 chars (Windsurf's 6K limit). Truncated silently if exceeded. |
164
164
  | `.windsurf/rules/rails-context.md` | Project overview | New Windsurf rules format. |
165
+ | `.windsurf/rules/rails-ui-patterns.md` | UI patterns and design tokens | Loaded when editing views. |
165
166
  | `.windsurf/rules/rails-mcp-tools.md` | MCP tool reference | Compact — respects 6K per-file limit. |
166
167
 
167
168
  ### GitHub Copilot (6 files)
@@ -172,7 +173,7 @@ end
172
173
  | `.github/instructions/rails-models.instructions.md` | Model context | `applyTo: app/models/**/*.rb` — loaded when editing models. |
173
174
  | `.github/instructions/rails-controllers.instructions.md` | Controller context | `applyTo: app/controllers/**/*.rb` — loaded when editing controllers. |
174
175
  | `.github/instructions/rails-context.instructions.md` | Project context and conventions | `applyTo: **/*` — loaded everywhere. |
175
- | `.github/instructions/rails-ui-patterns.instructions.md` | UI patterns and design tokens | `applyTo: **/*` — loaded everywhere. |
176
+ | `.github/instructions/rails-ui-patterns.instructions.md` | UI patterns and design tokens | `applyTo: app/views/**/*.erb` — loaded when editing views. |
176
177
  | `.github/instructions/rails-mcp-tools.instructions.md` | MCP tool reference | `applyTo: **/*` — loaded everywhere. |
177
178
 
178
179
  ### Generic (1 file)
@@ -296,6 +297,8 @@ Returns model details: associations, validations, scopes, enums, callbacks, conc
296
297
  |-------|------|-------------|
297
298
  | `model` | string | Model class name (e.g. `User`). Case-insensitive. Omit for listing. |
298
299
  | `detail` | string | `summary` / `standard` (default) / `full`. Ignored when model is specified. |
300
+ | `limit` | integer | Max models to return when listing. Default: 50. |
301
+ | `offset` | integer | Skip models for pagination. Default: 0. |
299
302
 
300
303
  **Examples:**
301
304
 
@@ -328,6 +331,7 @@ Returns all routes: HTTP verbs, paths, controller actions, route names.
328
331
  | `detail` | string | `summary` / `standard` (default) / `full` |
329
332
  | `limit` | integer | Max routes to return. Default: 100 (standard), 200 (full). |
330
333
  | `offset` | integer | Skip routes for pagination. Default: 0. |
334
+ | `app_only` | boolean | Filter out internal Rails routes (Active Storage, Action Mailbox, Conductor, etc.). Default: true. |
331
335
 
332
336
  **Examples:**
333
337
 
@@ -359,8 +363,11 @@ Returns controller details: actions, filters, strong params, concerns.
359
363
 
360
364
  | Param | Type | Description |
361
365
  |-------|------|-------------|
362
- | `controller` | string | Specific controller name (e.g. `UsersController`). Case-insensitive. |
366
+ | `controller` | string | Specific controller name (e.g. `UsersController`, `cooks`, `bonus/crises`). Case-insensitive, flexible format. |
367
+ | `action` | string | Specific action (e.g. `index`). Requires controller. Returns source code with applicable filters. |
363
368
  | `detail` | string | `summary` / `standard` (default) / `full`. Ignored when controller is specified. |
369
+ | `limit` | integer | Max controllers to return when listing. Default: 50. |
370
+ | `offset` | integer | Skip this many controllers for pagination. Default: 0. |
364
371
 
365
372
  **Examples:**
366
373
 
@@ -382,7 +389,7 @@ rails_get_controllers(detail: "full")
382
389
 
383
390
  Returns application configuration. No parameters.
384
391
 
385
- **Returns:** cache store, session store, timezone, middleware stack, initializers, credentials keys, current attributes.
392
+ **Returns:** cache store, session store, timezone, queue adapter, mailer settings, custom middleware (framework defaults are filtered out), notable initializers, CurrentAttributes classes.
386
393
 
387
394
  ```
388
395
  rails_get_config()
@@ -391,20 +398,35 @@ rails_get_config()
391
398
 
392
399
  ### rails_get_test_info
393
400
 
394
- Returns test infrastructure details. No parameters.
401
+ Returns test infrastructure details. Optionally filter by model or controller to find existing tests.
395
402
 
396
- **Returns:** test framework (rspec/minitest), factories/fixtures with locations and counts, system tests, CI config, coverage tool, test helpers.
403
+ **Parameters:**
404
+
405
+ | Param | Type | Description |
406
+ |-------|------|-------------|
407
+ | `model` | string | Show tests for a specific model (e.g. `User`). |
408
+ | `controller` | string | Show tests for a specific controller (e.g. `Cooks`). |
409
+ | `detail` | string | `summary` / `standard` (default) / `full`. |
397
410
 
398
411
  ```
399
412
  rails_get_test_info()
400
- → Framework: rspec, Factories: spec/factories (12 files), CI: .github/workflows/ci.yml, ...
413
+ → Framework: rspec, Factories: spec/factories (12 files), CI: .github/workflows/ci.yml
414
+
415
+ rails_get_test_info(model: "User")
416
+ → Shows spec/models/user_spec.rb test names (summary/standard) or full source (full)
401
417
  ```
402
418
 
403
419
  ### rails_get_gems
404
420
 
405
- Returns notable gems categorized by function. No parameters.
421
+ Returns notable gems categorized by function.
406
422
 
407
- **Returns:** 70+ recognized gems grouped by category (auth, background_jobs, admin, monitoring, search, pagination, etc.) with versions and descriptions.
423
+ **Parameters:**
424
+
425
+ | Param | Type | Description |
426
+ |-------|------|-------------|
427
+ | `category` | string | Filter by category: `auth`, `jobs`, `frontend`, `api`, `database`, `files`, `testing`, `deploy`, `all` (default). |
428
+
429
+ **Returns:** Notable gems grouped by category with descriptions.
408
430
 
409
431
  ```
410
432
  rails_get_gems()
@@ -422,6 +444,108 @@ rails_get_conventions()
422
444
  → Architecture: [MVC, Service objects, Concerns], Patterns: [STI, Polymorphism], ...
423
445
  ```
424
446
 
447
+ ### rails_get_stimulus
448
+
449
+ Returns Stimulus controller details: targets, values, actions, outlets, classes.
450
+
451
+ **Parameters:**
452
+
453
+ | Param | Type | Description |
454
+ |-------|------|-------------|
455
+ | `controller` | string | Specific Stimulus controller name (e.g. `hello`, `filter-form`). Case-insensitive. |
456
+ | `detail` | string | `summary` / `standard` (default) / `full` |
457
+ | `limit` | integer | Max controllers to return when listing. Default: 50. |
458
+ | `offset` | integer | Skip controllers for pagination. Default: 0. |
459
+
460
+ **Examples:**
461
+
462
+ ```
463
+ rails_get_stimulus()
464
+ → Standard: controller names with targets and actions
465
+
466
+ rails_get_stimulus(detail: "summary")
467
+ → Names with target/action counts
468
+
469
+ rails_get_stimulus(controller: "filter-form")
470
+ → Full detail: targets, actions, values, outlets, classes, file path
471
+
472
+ rails_get_stimulus(detail: "full")
473
+ → All controllers with all details
474
+ ```
475
+
476
+ ### rails_get_view
477
+
478
+ Returns view template contents, partials, and Stimulus controller references.
479
+
480
+ **Parameters:**
481
+
482
+ | Param | Type | Description |
483
+ |-------|------|-------------|
484
+ | `controller` | string | Filter views by controller name (e.g. `cooks`, `brand_profiles`). Use `layouts` for layout files. |
485
+ | `path` | string | Specific view path relative to `app/views` (e.g. `cooks/index.html.erb`). Returns full content. |
486
+ | `detail` | string | `summary` / `standard` (default) / `full` |
487
+
488
+ **Examples:**
489
+
490
+ ```
491
+ rails_get_view()
492
+ → Standard: all view files with partial/stimulus refs
493
+
494
+ rails_get_view(controller: "cooks")
495
+ → All templates and partials for CooksController
496
+
497
+ rails_get_view(path: "cooks/index.html.erb")
498
+ → Full template content
499
+
500
+ rails_get_view(controller: "layouts")
501
+ → Layout files
502
+
503
+ rails_get_view(controller: "cooks", detail: "full")
504
+ → Full template content for all cooks views
505
+ ```
506
+
507
+ ### rails_get_edit_context
508
+
509
+ Returns just enough context to make a surgical Edit to a file. Returns the target area with line numbers and surrounding code.
510
+
511
+ **Parameters:**
512
+
513
+ | Param | Type | Description |
514
+ |-------|------|-------------|
515
+ | `file` | string | **Required.** File path relative to Rails root (e.g. `app/models/cook.rb`). |
516
+ | `near` | string | **Required.** What to find — a method name, keyword, or string to locate (e.g. `scope`, `def index`). |
517
+ | `context_lines` | integer | Lines of context above and below the match. Default: 5. |
518
+
519
+ **Examples:**
520
+
521
+ ```
522
+ rails_get_edit_context(file: "app/models/cook.rb", near: "scope")
523
+ → Code around the first scope with line numbers, expanded to full method
524
+
525
+ rails_get_edit_context(file: "app/controllers/cooks_controller.rb", near: "def index")
526
+ → The index action source with surrounding context
527
+ ```
528
+
529
+ ### rails_validate
530
+
531
+ Validates syntax of multiple files at once (Ruby, ERB, JavaScript).
532
+
533
+ **Parameters:**
534
+
535
+ | Param | Type | Description |
536
+ |-------|------|-------------|
537
+ | `files` | array | **Required.** File paths relative to Rails root (e.g. `["app/models/cook.rb", "app/views/cooks/index.html.erb"]`). |
538
+
539
+ **Examples:**
540
+
541
+ ```
542
+ rails_validate(files: ["app/models/cook.rb"])
543
+ → ✓ app/models/cook.rb — syntax OK
544
+
545
+ rails_validate(files: ["app/models/cook.rb", "app/controllers/cooks_controller.rb", "app/views/cooks/index.html.erb"])
546
+ → Checks all three files, reports pass/fail for each
547
+ ```
548
+
425
549
  ### rails_search_code
426
550
 
427
551
  Ripgrep-powered regex search across the codebase.
@@ -431,8 +555,10 @@ Ripgrep-powered regex search across the codebase.
431
555
  | Param | Type | Description |
432
556
  |-------|------|-------------|
433
557
  | `pattern` | string | **Required.** Regex pattern to search for. |
558
+ | `path` | string | Subdirectory to search in (e.g. `app/models`, `config`). Default: entire app. |
434
559
  | `file_type` | string | Filter by file type (e.g. `rb`, `erb`, `js`). Alphanumeric only. |
435
- | `max_results` | integer | Max results to return. Default: 20, max: 100. |
560
+ | `max_results` | integer | Max results to return. Default: 30, max: 100. |
561
+ | `context_lines` | integer | Lines of context before and after each match (like grep -C). Default: 0, max: 5. |
436
562
 
437
563
  **Examples:**
438
564
 
@@ -445,18 +571,28 @@ rails_search_code(pattern: "class.*Controller", file_type: "rb")
445
571
 
446
572
  rails_search_code(pattern: "def create", file_type: "rb", max_results: 50)
447
573
  → First 50 create methods across the codebase
574
+
575
+ rails_search_code(pattern: "current_user", path: "app/controllers")
576
+ → Search only in app/controllers/
577
+
578
+ rails_search_code(pattern: "validates", context_lines: 2)
579
+ → Matches with 2 lines of context before and after
448
580
  ```
449
581
 
450
- **Security:** Uses `Open3.capture2` with array arguments (no shell injection). Validates file_type. Blocks path traversal. Respects `excluded_paths` config.
582
+ **Security:** Uses `Open3.capture2` with array arguments (no shell injection). Validates file_type. Blocks path traversal. Respects `excluded_paths` and `sensitive_patterns` config.
451
583
 
452
584
  ### Detail Level Summary
453
585
 
454
- | Level | What it returns | Default limit | Best for |
455
- |-------|----------------|---------------|----------|
586
+ All tools that support `detail` use these three levels. Default limits vary by tool — schema defaults shown below:
587
+
588
+ | Level | What it returns | Schema default limit | Best for |
589
+ |-------|----------------|---------------------|----------|
456
590
  | `summary` | Names + counts | 50 | Getting the landscape, understanding what exists |
457
591
  | `standard` | Names + key details | 15 | Working context, column types, action names |
458
592
  | `full` | Everything | 5 | Deep inspection, indexes, FKs, constraints |
459
593
 
594
+ Other tools default to higher limits (e.g. models/controllers/stimulus: 50 for all levels, routes: 100/200).
595
+
460
596
  ### Recommended Workflow
461
597
 
462
598
  1. **Start with `detail:"summary"`** to see what exists
@@ -617,6 +753,49 @@ RailsAiContext.configure do |config|
617
753
  # Paths to exclude from code search
618
754
  config.excluded_paths += %w[vendor/bundle]
619
755
 
756
+ # Sensitive file patterns blocked from search and read tools
757
+ # config.sensitive_patterns += %w[config/my_secret.yml]
758
+
759
+ # Controllers hidden from listings (e.g. Devise internals)
760
+ # config.excluded_controllers += %w[MyInternalController]
761
+
762
+ # Route prefixes hidden with app_only (e.g. admin frameworks)
763
+ # config.excluded_route_prefixes += %w[admin/]
764
+
765
+ # Regex patterns for concerns to hide from model output
766
+ # config.excluded_concerns += [/MyInternal::/]
767
+
768
+ # Framework filter names hidden from controller output
769
+ # config.excluded_filters += %w[my_internal_filter]
770
+
771
+ # Default middleware hidden from config output
772
+ # config.excluded_middleware += %w[MyMiddleware]
773
+
774
+ # --- File size limits ---
775
+
776
+ # Per-file read limit for tools (default: 2MB)
777
+ # config.max_file_size = 2_000_000
778
+
779
+ # Test file read limit (default: 500KB)
780
+ # config.max_test_file_size = 500_000
781
+
782
+ # schema.rb / structure.sql parse limit (default: 10MB)
783
+ # config.max_schema_file_size = 10_000_000
784
+
785
+ # Max search results per call (default: 100)
786
+ # config.max_search_results = 100
787
+
788
+ # Max files per validate call (default: 20)
789
+ # config.max_validate_files = 20
790
+
791
+ # --- Search and file discovery ---
792
+
793
+ # File extensions for Ruby fallback search
794
+ # config.search_extensions = %w[rb js erb yml yaml json ts tsx vue svelte haml slim]
795
+
796
+ # Where to look for concern source files
797
+ # config.concern_paths = %w[app/models/concerns app/controllers/concerns]
798
+
620
799
  # --- Live reload ---
621
800
 
622
801
  # Auto-invalidate MCP tool caches on file changes
@@ -648,6 +827,7 @@ end
648
827
  | `cache_ttl` | Integer | `30` | Cache TTL in seconds for introspection results |
649
828
  | `excluded_models` | Array | internal Rails models | Models to skip |
650
829
  | `excluded_paths` | Array | `node_modules tmp log vendor .git` | Paths excluded from code search |
830
+ | `sensitive_patterns` | Array | `.env`, `.key`, `.pem`, credentials | File patterns blocked from search and read tools |
651
831
  | `output_dir` | String | `nil` (Rails.root) | Where to write context files |
652
832
  | `auto_mount` | Boolean | `false` | Auto-mount HTTP MCP endpoint |
653
833
  | `http_path` | String | `"/mcp"` | HTTP endpoint path |
@@ -656,7 +836,22 @@ end
656
836
  | `live_reload` | Symbol/Boolean | `:auto` | `:auto`, `true`, or `false` — enable MCP live reload |
657
837
  | `live_reload_debounce` | Float | `1.5` | Debounce interval in seconds for live reload |
658
838
  | `server_name` | String | `"rails-ai-context"` | MCP server name |
839
+ | `server_version` | String | gem version | MCP server version |
659
840
  | `generate_root_files` | Boolean | `true` | Generate root files (CLAUDE.md, .windsurfrules, etc.) — set `false` for split rules only |
841
+ | `max_file_size` | Integer | `2_000_000` | Per-file read limit for tools (2MB) |
842
+ | `max_test_file_size` | Integer | `500_000` | Test file read limit (500KB) |
843
+ | `max_schema_file_size` | Integer | `10_000_000` | schema.rb / structure.sql parse limit (10MB) |
844
+ | `max_view_total_size` | Integer | `5_000_000` | Total aggregated view content for UI patterns (5MB) |
845
+ | `max_view_file_size` | Integer | `500_000` | Per-view file during aggregation (500KB) |
846
+ | `max_search_results` | Integer | `100` | Max search results per call |
847
+ | `max_validate_files` | Integer | `20` | Max files per validate call |
848
+ | `excluded_controllers` | Array | `DeviseController`, etc. | Controller classes hidden from listings |
849
+ | `excluded_route_prefixes` | Array | `action_mailbox/`, `active_storage/`, etc. | Route controller prefixes hidden with `app_only` |
850
+ | `excluded_concerns` | Array | framework regex patterns | Regex patterns for concerns to hide from model output |
851
+ | `excluded_filters` | Array | `verify_authenticity_token`, etc. | Framework filter names hidden from controller output |
852
+ | `excluded_middleware` | Array | standard Rails middleware | Default middleware hidden from config output |
853
+ | `search_extensions` | Array | `rb js erb yml yaml json ts tsx vue svelte haml slim` | File extensions for Ruby fallback search |
854
+ | `concern_paths` | Array | `app/models/concerns app/controllers/concerns` | Where to look for concern source files |
660
855
 
661
856
  ### Root file generation
662
857
 
@@ -731,7 +926,7 @@ config.preset = :full
731
926
 
732
927
  ```ruby
733
928
  # Start with standard, add specific ones
734
- config.introspectors += %i[views turbo auth api stimulus]
929
+ config.introspectors += %i[views turbo auth api]
735
930
 
736
931
  # Or build from scratch
737
932
  config.introspectors = %i[schema models routes gems auth api]
@@ -60,6 +60,26 @@ module RailsAiContext
60
60
  # When false, only generates split rule files (.claude/rules/, .cursor/rules/, etc.)
61
61
  attr_accessor :generate_root_files
62
62
 
63
+ # File size limits (bytes) — increase for larger projects
64
+ attr_accessor :max_file_size # Per-file read limit for tools (default: 2MB)
65
+ attr_accessor :max_test_file_size # Test file read limit (default: 500KB)
66
+ attr_accessor :max_schema_file_size # schema.rb / structure.sql parse limit (default: 10MB)
67
+ attr_accessor :max_view_total_size # Total aggregated view content for UI patterns (default: 5MB)
68
+ attr_accessor :max_view_file_size # Per-view file during aggregation (default: 500KB)
69
+ attr_accessor :max_search_results # Max search results per call (default: 100)
70
+ attr_accessor :max_validate_files # Max files per validate call (default: 20)
71
+
72
+ # Filtering — customize what's hidden from AI output
73
+ attr_accessor :excluded_controllers # Controller classes hidden from listings (e.g. DeviseController)
74
+ attr_accessor :excluded_route_prefixes # Route controller prefixes hidden with app_only (e.g. action_mailbox/)
75
+ attr_accessor :excluded_concerns # Regex patterns for concerns to hide (e.g. /Devise::Models/)
76
+ attr_accessor :excluded_filters # Framework filter names hidden from controller output
77
+ attr_accessor :excluded_middleware # Default middleware hidden from config output
78
+
79
+ # Search and file discovery
80
+ attr_accessor :search_extensions # File extensions for Ruby fallback search (default: rb,js,erb,yml,yaml,json)
81
+ attr_accessor :concern_paths # Where to look for concern source files (default: app/models/concerns)
82
+
63
83
  def initialize
64
84
  @server_name = "rails-ai-context"
65
85
  @server_version = RailsAiContext::VERSION
@@ -87,6 +107,41 @@ module RailsAiContext
87
107
  @live_reload = :auto
88
108
  @live_reload_debounce = 1.5
89
109
  @generate_root_files = true
110
+ @max_file_size = 2_000_000
111
+ @max_test_file_size = 500_000
112
+ @max_schema_file_size = 10_000_000
113
+ @max_view_total_size = 5_000_000
114
+ @max_view_file_size = 500_000
115
+ @max_search_results = 100
116
+ @max_validate_files = 20
117
+ @excluded_controllers = %w[DeviseController Devise::OmniauthCallbacksController]
118
+ @excluded_route_prefixes = %w[action_mailbox/ active_storage/ rails/ conductor/ devise/ turbo/]
119
+ @excluded_concerns = [
120
+ /::Generated/,
121
+ /\A(ActiveRecord|ActiveModel|ActiveSupport|ActionText|ActionMailbox|ActiveStorage)/,
122
+ /\A(ActionDispatch|ActionController|ActionView|AbstractController)/,
123
+ /\A(Devise::Models|Devise::Orm|Bullet::|Turbo::|GlobalID::|Rolify::)/
124
+ ]
125
+ @excluded_filters = %w[
126
+ verify_authenticity_token verify_same_origin_request
127
+ turbo_tracking_request_id handle_unverified_request
128
+ mark_for_same_origin_verification
129
+ ]
130
+ @excluded_middleware = %w[
131
+ Rack::Sendfile ActionDispatch::Static ActionDispatch::Executor
132
+ ActionDispatch::ServerTiming Rack::Runtime
133
+ ActionDispatch::RequestId ActionDispatch::RemoteIp
134
+ Rails::Rack::Logger ActionDispatch::ShowExceptions
135
+ ActionDispatch::DebugExceptions ActionDispatch::Callbacks
136
+ ActionDispatch::Cookies ActionDispatch::Session::CookieStore
137
+ ActionDispatch::Flash ActionDispatch::ContentSecurityPolicy::Middleware
138
+ ActionDispatch::PermissionsPolicy::Middleware ActionDispatch::ActionableExceptions
139
+ Rack::Head Rack::ConditionalGet Rack::ETag Rack::TempfileReaper
140
+ ActiveRecord::Migration::CheckPending ActionDispatch::HostAuthorization
141
+ Rack::MethodOverride ActionDispatch::Session::AbstractSecureStore
142
+ ]
143
+ @search_extensions = %w[rb js erb yml yaml json ts tsx vue svelte haml slim]
144
+ @concern_paths = %w[app/models/concerns app/controllers/concerns]
90
145
  end
91
146
 
92
147
  def preset=(name)
@@ -9,12 +9,9 @@ module RailsAiContext
9
9
  class ControllerIntrospector
10
10
  attr_reader :app
11
11
 
12
- # Framework filters inherited from ActionController::Base — suppress to reduce noise
13
- FRAMEWORK_FILTERS = %w[
14
- verify_authenticity_token verify_same_origin_request
15
- turbo_tracking_request_id handle_unverified_request
16
- mark_for_same_origin_verification
17
- ].freeze
12
+ def excluded_filters
13
+ RailsAiContext.configuration.excluded_filters
14
+ end
18
15
 
19
16
  def initialize(app)
20
17
  @app = app
@@ -164,7 +161,7 @@ module RailsAiContext
164
161
 
165
162
  ctrl._process_action_callbacks.filter_map do |cb|
166
163
  next if cb.filter.is_a?(Proc) || cb.filter.to_s.start_with?("_")
167
- next if FRAMEWORK_FILTERS.include?(cb.filter.to_s)
164
+ next if excluded_filters.include?(cb.filter.to_s)
168
165
 
169
166
  filter = { name: cb.filter.to_s, kind: cb.kind.to_s }
170
167
  filter[:only] = cb.instance_variable_get(:@if)&.filter_map { |c| extract_action_condition(c) }&.flatten
@@ -59,6 +59,7 @@ module RailsAiContext
59
59
  table_name: model.table_name,
60
60
  associations: extract_associations(model),
61
61
  validations: extract_validations(model),
62
+ custom_validates: extract_custom_validates(model),
62
63
  scopes: extract_scopes(model),
63
64
  enums: extract_enums(model),
64
65
  callbacks: extract_callbacks(model),
@@ -109,6 +110,17 @@ module RailsAiContext
109
110
  []
110
111
  end
111
112
 
113
+ # Extract custom validate :method_name calls from source
114
+ # These are business-rule validators that model.validators doesn't include
115
+ def extract_custom_validates(model)
116
+ source_path = model_source_path(model)
117
+ return [] unless source_path && File.exist?(source_path)
118
+
119
+ File.read(source_path).scan(/^\s*validate\s+:(\w+)/).flatten
120
+ rescue
121
+ []
122
+ end
123
+
112
124
  def model_source_path(model)
113
125
  root = app.root.to_s
114
126
  underscored = model.name.underscore
@@ -156,11 +168,8 @@ module RailsAiContext
156
168
 
157
169
  def framework_concern?(name)
158
170
  return true if name.nil?
159
- return true if name.include?("::Generated")
160
- return true if name.match?(/\A(ActiveRecord|ActiveModel|ActiveSupport|ActionText|ActionMailbox|ActiveStorage|ActionDispatch|ActionController|ActionView|AbstractController)/)
161
- return true if name.match?(/\A(Devise::Models|Devise::Orm|Bullet::|Turbo::|GlobalID::|Rolify::)/)
162
171
  return true if %w[Kernel JSON PP Marshal MessagePack].include?(name)
163
- false
172
+ RailsAiContext.configuration.excluded_concerns.any? { |pattern| name.match?(pattern) }
164
173
  end
165
174
 
166
175
  def extract_public_class_methods(model)
@@ -150,7 +150,9 @@ module RailsAiContext
150
150
  File.join(app.root, "db", "structure.sql")
151
151
  end
152
152
 
153
- MAX_SCHEMA_FILE_SIZE = 10_000_000 # 10MB safety limit for schema files
153
+ def max_schema_file_size
154
+ RailsAiContext.configuration.max_schema_file_size
155
+ end
154
156
 
155
157
  # Fallback: parse schema file as text when DB isn't connected.
156
158
  # Tries db/schema.rb first, then db/structure.sql.
@@ -166,7 +168,7 @@ module RailsAiContext
166
168
  end
167
169
 
168
170
  def parse_schema_rb(path)
169
- return { error: "schema.rb too large (#{File.size(path)} bytes)" } if File.size(path) > MAX_SCHEMA_FILE_SIZE
171
+ return { error: "schema.rb too large (#{File.size(path)} bytes)" } if File.size(path) > max_schema_file_size
170
172
  content = File.read(path)
171
173
  tables = {}
172
174
  current_table = nil
@@ -209,7 +211,7 @@ module RailsAiContext
209
211
  end
210
212
 
211
213
  def parse_structure_sql(path) # rubocop:disable Metrics/MethodLength
212
- return { error: "structure.sql too large (#{File.size(path)} bytes)" } if File.size(path) > MAX_SCHEMA_FILE_SIZE
214
+ return { error: "structure.sql too large (#{File.size(path)} bytes)" } if File.size(path) > max_schema_file_size
213
215
  content = File.read(path)
214
216
  tables = {}
215
217
 
@@ -61,15 +61,14 @@ module RailsAiContext
61
61
  partials
62
62
  end
63
63
 
64
- MAX_TOTAL_VIEW_SIZE = 5_000_000 # 5MB cap for aggregated view content
65
- MAX_SINGLE_VIEW_SIZE = 500_000 # 500KB per file
66
-
67
64
  def collect_all_view_content(views_dir)
65
+ max_total = RailsAiContext.configuration.max_view_total_size
66
+ max_single = RailsAiContext.configuration.max_view_file_size
68
67
  content = +""
69
68
  Dir.glob(File.join(views_dir, "**", "*.{erb,haml,slim}")).each do |path|
70
69
  next if File.directory?(path)
71
- next if File.size(path) > MAX_SINGLE_VIEW_SIZE
72
- break if content.bytesize >= MAX_TOTAL_VIEW_SIZE
70
+ next if File.size(path) > max_single
71
+ break if content.bytesize >= max_total
73
72
  content << (File.read(path, encoding: "UTF-8", invalid: :replace, undef: :replace) rescue "")
74
73
  end
75
74
  content