rails-informant 0.0.5 → 0.0.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: 9cb09528a587e40da2aa7b66b56483f97953dcde9fd01e172009e859236b1b83
4
- data.tar.gz: ad121656a0ae00abd63c49ffc26f493a0cd5d90412f68ef657ec63dbb2eddce6
3
+ metadata.gz: 51a0bd3a42b6c332ee192a319eaf43b8b129013995ac42d35a0de294a69c968f
4
+ data.tar.gz: 2eef05b3963d12586672b650cff43f5b999d8852ff229e42114f6b9cff0572a3
5
5
  SHA512:
6
- metadata.gz: 9b449febb753c029ac0905a9a9af076039e3b008be77bfe2f444fbabadfb1ca9c4b66e19165c618d326fa78f70bda1cd8e284c0a052425a69cdea13e8aa5b9a8
7
- data.tar.gz: dd18b3b3e42d3551c08dc23bfe68e0f497e7b373713985e7fea8f569b5c352d263491e7ea98967d596cb6748530a702d03289936e5cc50a1a5fe2d22aaba7a66
6
+ metadata.gz: b9e51bc32c5393a1dced3621b661c72e8dcdf87d11a5d640c7addceb1ce9ec1526bc170519d0e71466503e2d589d53bdaec3b8063c21020d7fff3c6db5f12b82
7
+ data.tar.gz: 5eff7c322d4722b26d018dcf7a12e8f692e57e0f66374612e27271b41766a142cde8bb116dedbab1594f77aa6b1e28ec0e1b586929c69c39a9bd68b5f20cd2e3
data/README.md CHANGED
@@ -13,10 +13,11 @@
13
13
  <p>
14
14
  <a href="#why-rails-informant">Why Rails Informant?</a>
15
15
  &#9670; <a href="#quick-start">Quick Start</a>
16
+ &#9670; <a href="#agent-setup">Agent Setup</a>
16
17
  &#9670; <a href="#configuration">Configuration</a>
17
18
  &#9670; <a href="#mcp-server">MCP Server</a>
18
19
  &#9670; <a href="#architecture">Architecture</a>
19
- &#9670; <a href="#data--privacy">Data & Privacy</a>
20
+ &#9670; <a href="#data-and-privacy">Data and Privacy</a>
20
21
  &#9670; <a href="#security">Security</a>
21
22
  </p>
22
23
  </div>
@@ -65,6 +66,38 @@ Errors are captured automatically in non-local environments. To capture errors m
65
66
  RailsInformant.capture(exception, context: { order_id: 42 })
66
67
  ```
67
68
 
69
+ ## Agent Setup
70
+
71
+ End-to-end path for AI agents (Claude Code, Devin) to start triaging errors:
72
+
73
+ 1. **Install the gem** -- follow [Quick Start](#quick-start) above
74
+ 2. **Set an authentication token** in your Rails credentials or env var:
75
+ ```ruby
76
+ # config/initializers/rails_informant.rb
77
+ config.api_token = Rails.application.credentials.dig(:rails_informant, :api_token)
78
+ ```
79
+ 3. **Add the MCP server** to your agent's config (see [MCP Server](#mcp-server) for full options):
80
+ ```json
81
+ {
82
+ "mcpServers": {
83
+ "informant": {
84
+ "command": "informant-mcp",
85
+ "env": {
86
+ "INFORMANT_PRODUCTION_URL": "https://myapp.com",
87
+ "INFORMANT_PRODUCTION_TOKEN": "your-api-token"
88
+ }
89
+ }
90
+ }
91
+ }
92
+ ```
93
+ 4. **Install the Claude Code skill** (optional but recommended):
94
+ ```sh
95
+ bin/rails generate rails_informant:skill
96
+ ```
97
+ 5. **Use `/informant`** in Claude Code to triage and fix errors, or let Devin handle them autonomously with the [Devin integration](#devin-ai).
98
+
99
+ > **Env var scoping:** `INFORMANT_API_TOKEN` configures the Rails app. `INFORMANT_PRODUCTION_URL` and `INFORMANT_PRODUCTION_TOKEN` configure the MCP server (agent side). They are different processes -- both need a token, but the MCP env vars point the agent at your running app.
100
+
68
101
  ## Configuration
69
102
 
70
103
  ```ruby
@@ -77,11 +110,11 @@ RailsInformant.configure do |config|
77
110
  end
78
111
  ```
79
112
 
80
- Every option can be set via an environment variable. The initializer takes precedence over env vars.
113
+ Every option can be set via an environment variable. The initializer takes precedence over env vars. These configure the **Rails app**. For MCP server env vars (agent side), see [Agent Setup](#agent-setup).
81
114
 
82
115
  | Option | Env var | Default | Description |
83
116
  |--------|---------|---------|-------------|
84
- | `api_token` | `INFORMANT_API_TOKEN` | `nil` | Bearer token for API authentication (required for MCP) |
117
+ | `api_token` | `INFORMANT_API_TOKEN` | `nil` | Authentication token for MCP server access |
85
118
  | `capture_errors` | `INFORMANT_CAPTURE_ERRORS` | `true` | Enable/disable error capture (set to `"false"` to disable) |
86
119
  | `devin_api_key` | `INFORMANT_DEVIN_API_KEY` | `nil` | Devin AI API key for autonomous error fixing |
87
120
  | `devin_playbook_id` | `INFORMANT_DEVIN_PLAYBOOK_ID` | `nil` | Devin playbook ID for error triage workflow |
@@ -114,33 +147,10 @@ config.ignored_exceptions = ["MyApp::BoringError", /Stripe::/]
114
147
 
115
148
  Structured events from `ActiveSupport::Notifications` are captured automatically as breadcrumbs -- SQL query names, cache hits, template renders, HTTP calls, job executions. Stored per-occurrence for rich debugging context without raw log lines.
116
149
 
117
- ## API
118
-
119
- Token-authenticated JSON API mounted at `/informant/api/v1/`.
120
-
121
- ```text
122
- GET /informant/api/v1/errors # List error groups (paginated, filterable)
123
- GET /informant/api/v1/errors/:id # Show with recent occurrences
124
- PATCH /informant/api/v1/errors/:id # Update status or notes
125
- DELETE /informant/api/v1/errors/:id # Delete group and occurrences
126
- PATCH /informant/api/v1/errors/:id/fix_pending # Mark fix pending
127
- PATCH /informant/api/v1/errors/:id/duplicate # Mark as duplicate
128
- GET /informant/api/v1/occurrences # List occurrences
129
- GET /informant/api/v1/status # Error monitoring summary
130
- ```
131
-
132
- Authenticate with `Authorization: Bearer <token>`.
133
-
134
150
  ## MCP Server
135
151
 
136
152
  The bundled `informant-mcp` executable connects Claude Code to your error data via [Model Context Protocol (MCP)](https://modelcontextprotocol.io).
137
153
 
138
- The MCP server requires the `mcp` gem, which is not a runtime dependency. Add it to your Gemfile:
139
-
140
- ```ruby
141
- gem "mcp", ">= 0.7", "< 2"
142
- ```
143
-
144
154
  ### Setup
145
155
 
146
156
  Add to your Claude Code MCP config:
@@ -233,12 +243,12 @@ The notification prompt includes: error class, error message (truncated), severi
233
243
  Development Machine Remote Servers
234
244
  +-----------------------+ +-----------------------+
235
245
  | Claude Code | | Production |
236
- | | | | /informant/api/v1 |
246
+ | | | | /informant |
237
247
  | | stdio | +-----------------------+
238
248
  | v | HTTPS+Token
239
249
  | MCP Server | -----------> +-----------------------+
240
250
  | (exe/informant-mcp) | | Staging |
241
- | | | /informant/api/v1 |
251
+ | | | /informant |
242
252
  +-----------------------+ +-----------------------+
243
253
 
244
254
  Inside the Rails app:
@@ -288,7 +298,7 @@ bin/rails informant:stats # Show error monitoring statistics
288
298
  bin/rails informant:purge # Purge resolved errors older than retention_days
289
299
  ```
290
300
 
291
- ## Data & Privacy
301
+ ## Data and Privacy
292
302
 
293
303
  Each occurrence stores the following PII:
294
304
 
@@ -314,18 +324,18 @@ This replaces email values with `[FILTERED]` in occurrence data. IP addresses ca
314
324
 
315
325
  ## Security
316
326
 
317
- - API requires bearer token authentication (`secure_compare`)
327
+ - MCP server requires token authentication (`secure_compare`)
318
328
  - All stored context is filtered through `ActiveSupport::ParameterFilter`
319
329
  - MCP server enforces HTTPS by default
320
330
  - Security headers: `Cache-Control: no-store`, `X-Content-Type-Options: nosniff`
321
331
  - Error capture never breaks the host application
322
332
  - Webhook payloads strip PII by default
323
- - **Rate limiting** -- the API does not include built-in rate limiting. Add rate limiting on the `/informant/api/` prefix in production, for example with [Rack::Attack](https://github.com/rack/rack-attack):
333
+ - **Rate limiting** -- the engine does not include built-in rate limiting. Add rate limiting on the `/informant/` prefix in production, for example with [Rack::Attack](https://github.com/rack/rack-attack):
324
334
 
325
335
  ```ruby
326
336
  # config/initializers/rack_attack.rb
327
- Rack::Attack.throttle("informant/api", limit: 60, period: 1.minute) do |req|
328
- req.ip if req.path.start_with?("/informant/api/")
337
+ Rack::Attack.throttle("informant", limit: 60, period: 1.minute) do |req|
338
+ req.ip if req.path.start_with?("/informant/")
329
339
  end
330
340
  ```
331
341
 
data/exe/informant-mcp CHANGED
@@ -3,11 +3,7 @@
3
3
 
4
4
  $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
5
5
 
6
- begin
7
- require "mcp"
8
- rescue LoadError
9
- abort 'The "mcp" gem is required to run the Informant MCP server. Add gem "mcp", ">= 0.7", "< 2" to your Gemfile and run bundle install.'
10
- end
6
+ require "mcp"
11
7
 
12
8
  require "optparse"
13
9
  require "rails_informant/mcp"
@@ -20,5 +20,43 @@ module RailsInformant
20
20
  def mount_engine
21
21
  route "mount RailsInformant::Engine => '/informant'"
22
22
  end
23
+
24
+ def print_next_steps
25
+ say ""
26
+ say "Rails Informant installed!", :green
27
+ say ""
28
+ say "Next steps:", :yellow
29
+ say " 1. Run migrations:"
30
+ say " bin/rails db:migrate"
31
+ say ""
32
+ say " 2. Set a token (required for MCP server access):"
33
+ say " bin/rails credentials:edit"
34
+ say " # Add: rails_informant:"
35
+ say " # api_token: #{SecureRandom.hex 32}"
36
+ say ""
37
+ say " 3. Add the MCP server to .mcp.json (for Claude Code):"
38
+ say " {"
39
+ say " \"mcpServers\": {"
40
+ say " \"informant\": {"
41
+ say " \"command\": \"informant-mcp\","
42
+ say " \"env\": {"
43
+ say " \"INFORMANT_PRODUCTION_URL\": \"https://your-app.com\","
44
+ say " \"INFORMANT_PRODUCTION_TOKEN\": \"your-api-token\""
45
+ say " }"
46
+ say " }"
47
+ say " }"
48
+ say " }"
49
+ say ""
50
+ say " 4. Optional — install the Claude Code skill:"
51
+ say " bin/rails generate rails_informant:skill"
52
+ say ""
53
+ end
54
+
55
+ private
56
+
57
+ def json_column_type
58
+ adapter = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).first&.adapter.to_s
59
+ adapter.match?(/postgres/i) ? "jsonb" : "json"
60
+ end
23
61
  end
24
62
  end
@@ -9,7 +9,7 @@ allowed-tools:
9
9
  - Glob
10
10
  - Edit
11
11
  - Write
12
- - Bash(bin/test *)
12
+ - Bash(bin/rails test *)
13
13
  - Bash(bundle exec *)
14
14
  ---
15
15
 
@@ -38,13 +38,13 @@ class CreateInformantTables < ActiveRecord::Migration[8.1]
38
38
  create_table :informant_occurrences do |t|
39
39
  t.references :error_group, null: false,
40
40
  foreign_key: { to_table: :informant_error_groups }
41
- t.jsonb :backtrace
42
- t.jsonb :exception_chain
43
- t.jsonb :request_context
44
- t.jsonb :user_context
45
- t.jsonb :custom_context
46
- t.jsonb :environment_context
47
- t.jsonb :breadcrumbs
41
+ t.<%= json_column_type %> :backtrace
42
+ t.<%= json_column_type %> :exception_chain
43
+ t.<%= json_column_type %> :request_context
44
+ t.<%= json_column_type %> :user_context
45
+ t.<%= json_column_type %> :custom_context
46
+ t.<%= json_column_type %> :environment_context
47
+ t.<%= json_column_type %> :breadcrumbs
48
48
  t.string :git_sha
49
49
  t.timestamps
50
50
 
@@ -15,7 +15,7 @@ RailsInformant.configure do |config|
15
15
  # Or override what is captured by setting user context explicitly:
16
16
  # RailsInformant::Current.user_context = { id: current_user.id }
17
17
 
18
- # API token for the JSON API (required for MCP server access)
18
+ # Authentication token (required for MCP server access)
19
19
  config.api_token = Rails.application.credentials.dig(:rails_informant, :api_token)
20
20
 
21
21
  # Slack webhook URL for error notifications
@@ -68,19 +68,25 @@ module RailsInformant
68
68
 
69
69
  token = RailsInformant.api_token
70
70
 
71
- if token.nil?
72
- raise <<~MSG.squish
71
+ message = if token.nil?
72
+ <<~MSG.squish
73
73
  RailsInformant: api_token must be configured when capture_errors is enabled.
74
74
  Set it in your initializer: config.api_token = "your-secret-token"
75
75
  MSG
76
- end
77
-
78
- if token.length < MINIMUM_TOKEN_LENGTH
79
- raise <<~MSG.squish
76
+ elsif token.length < MINIMUM_TOKEN_LENGTH
77
+ <<~MSG.squish
80
78
  RailsInformant: api_token must be at least #{MINIMUM_TOKEN_LENGTH} characters.
81
79
  Use SecureRandom.hex(32) or Rails credentials to generate a secure token.
82
80
  MSG
83
81
  end
82
+
83
+ return unless message
84
+
85
+ if RailsInformant.server_mode?
86
+ raise message
87
+ else
88
+ Rails.logger&.warn message
89
+ end
84
90
  end
85
91
  end
86
92
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-informant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel López Prat
@@ -65,6 +65,26 @@ dependencies:
65
65
  - - ">="
66
66
  - !ruby/object:Gem::Version
67
67
  version: '8.1'
68
+ - !ruby/object:Gem::Dependency
69
+ name: mcp
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0.7'
75
+ - - "<"
76
+ - !ruby/object:Gem::Version
77
+ version: '2'
78
+ type: :runtime
79
+ prerelease: false
80
+ version_requirements: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '0.7'
85
+ - - "<"
86
+ - !ruby/object:Gem::Version
87
+ version: '2'
68
88
  - !ruby/object:Gem::Dependency
69
89
  name: railties
70
90
  requirement: !ruby/object:Gem::Requirement