rails-informant 0.0.5 → 0.0.7
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 +4 -4
- data/README.md +60 -40
- data/exe/informant-mcp +1 -5
- data/lib/generators/rails_informant/install_generator.rb +49 -0
- data/lib/generators/rails_informant/skill/templates/SKILL.md +1 -1
- data/lib/generators/rails_informant/templates/create_informant_tables.rb.erb +7 -7
- data/lib/generators/rails_informant/templates/initializer.rb.erb +1 -1
- data/lib/rails_informant/engine.rb +12 -6
- metadata +21 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b66bd1a6283f2a349a57994f529a0b57b71053c979c874268283d97477928873
|
|
4
|
+
data.tar.gz: d17e62d7ba21318f94205d9365d293ce1110fe58e9c56b4c82cc0c334e4f65bf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cf7f02ec548bbd755dc411b3f08a9a74807d45e333ccd3aedaf99b02be909ec4b4a046146ca913943dc41b88dc3e78cafcdf140163cdb1de2537c5d3f5a5b170
|
|
7
|
+
data.tar.gz: dd582dce1ccee4a3e6eaa3678c118416f9dff50afeafc00ad0a9a65a59e50760188541817f859d374f8aec5d139b5febb3024c54340b2b5fd98e36aa47fcfcf1
|
data/README.md
CHANGED
|
@@ -13,10 +13,11 @@
|
|
|
13
13
|
<p>
|
|
14
14
|
<a href="#why-rails-informant">Why Rails Informant?</a>
|
|
15
15
|
◆ <a href="#quick-start">Quick Start</a>
|
|
16
|
+
◆ <a href="#agent-setup">Agent Setup</a>
|
|
16
17
|
◆ <a href="#configuration">Configuration</a>
|
|
17
18
|
◆ <a href="#mcp-server">MCP Server</a>
|
|
18
19
|
◆ <a href="#architecture">Architecture</a>
|
|
19
|
-
◆ <a href="#data
|
|
20
|
+
◆ <a href="#data-and-privacy">Data and Privacy</a>
|
|
20
21
|
◆ <a href="#security">Security</a>
|
|
21
22
|
</p>
|
|
22
23
|
</div>
|
|
@@ -65,6 +66,33 @@ 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. The install generator creates `.mcp.json` automatically.
|
|
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. **Set env vars** for the MCP server (e.g., via `.envrc` + [direnv](https://direnv.net)):
|
|
80
|
+
```sh
|
|
81
|
+
# .envrc
|
|
82
|
+
export INFORMANT_PRODUCTION_URL=https://myapp.com
|
|
83
|
+
export INFORMANT_PRODUCTION_TOKEN=your-api-token
|
|
84
|
+
```
|
|
85
|
+
The MCP server process inherits environment variables from your shell, so `INFORMANT_*` vars set via `.envrc` (or any other method) are picked up automatically -- no need to inline them in `.mcp.json`.
|
|
86
|
+
4. **Install the Claude Code skill** (optional but recommended):
|
|
87
|
+
```sh
|
|
88
|
+
bin/rails generate rails_informant:skill
|
|
89
|
+
```
|
|
90
|
+
5. **Use `/informant`** in Claude Code to triage and fix errors, or let Devin handle them autonomously with the [Devin integration](#devin-ai).
|
|
91
|
+
|
|
92
|
+
> **Connecting the tokens:** The `api_token` in your Rails credentials and `INFORMANT_PRODUCTION_TOKEN` must be the **same value**. The first authenticates incoming requests to your app; the second tells the MCP server what token to send.
|
|
93
|
+
|
|
94
|
+
> **Secrets hygiene:** `.envrc` contains secrets and should be in `.gitignore`. `.mcp.json` is safe to commit -- it only contains the command name, no tokens.
|
|
95
|
+
|
|
68
96
|
## Configuration
|
|
69
97
|
|
|
70
98
|
```ruby
|
|
@@ -77,11 +105,11 @@ RailsInformant.configure do |config|
|
|
|
77
105
|
end
|
|
78
106
|
```
|
|
79
107
|
|
|
80
|
-
Every option can be set via an environment variable. The initializer takes precedence over env vars.
|
|
108
|
+
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
109
|
|
|
82
110
|
| Option | Env var | Default | Description |
|
|
83
111
|
|--------|---------|---------|-------------|
|
|
84
|
-
| `api_token` | `INFORMANT_API_TOKEN` | `nil` |
|
|
112
|
+
| `api_token` | `INFORMANT_API_TOKEN` | `nil` | Authentication token for MCP server access |
|
|
85
113
|
| `capture_errors` | `INFORMANT_CAPTURE_ERRORS` | `true` | Enable/disable error capture (set to `"false"` to disable) |
|
|
86
114
|
| `devin_api_key` | `INFORMANT_DEVIN_API_KEY` | `nil` | Devin AI API key for autonomous error fixing |
|
|
87
115
|
| `devin_playbook_id` | `INFORMANT_DEVIN_PLAYBOOK_ID` | `nil` | Devin playbook ID for error triage workflow |
|
|
@@ -114,52 +142,27 @@ config.ignored_exceptions = ["MyApp::BoringError", /Stripe::/]
|
|
|
114
142
|
|
|
115
143
|
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
144
|
|
|
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
145
|
## MCP Server
|
|
135
146
|
|
|
136
147
|
The bundled `informant-mcp` executable connects Claude Code to your error data via [Model Context Protocol (MCP)](https://modelcontextprotocol.io).
|
|
137
148
|
|
|
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
149
|
### Setup
|
|
145
150
|
|
|
146
|
-
|
|
151
|
+
The install generator creates `.mcp.json` for you. To set it up manually:
|
|
147
152
|
|
|
148
153
|
```json
|
|
149
154
|
{
|
|
150
155
|
"mcpServers": {
|
|
151
156
|
"informant": {
|
|
152
|
-
"command": "informant-mcp"
|
|
153
|
-
"env": {
|
|
154
|
-
"INFORMANT_PRODUCTION_URL": "https://myapp.com",
|
|
155
|
-
"INFORMANT_PRODUCTION_TOKEN": "your-api-token"
|
|
156
|
-
}
|
|
157
|
+
"command": "informant-mcp"
|
|
157
158
|
}
|
|
158
159
|
}
|
|
159
160
|
}
|
|
160
161
|
```
|
|
161
162
|
|
|
162
|
-
|
|
163
|
+
Set `INFORMANT_PRODUCTION_URL` and `INFORMANT_PRODUCTION_TOKEN` as environment variables (e.g., via `.envrc` + direnv). The MCP server inherits env vars from your shell -- no need to put secrets in `.mcp.json`.
|
|
164
|
+
|
|
165
|
+
For multi-environment setups, create `~/.config/informant-mcp.yml`:
|
|
163
166
|
|
|
164
167
|
```yaml
|
|
165
168
|
environments:
|
|
@@ -188,6 +191,23 @@ environments:
|
|
|
188
191
|
| `get_informant_status` | Summary with counts and top errors |
|
|
189
192
|
| `list_occurrences` | List occurrences with filtering |
|
|
190
193
|
|
|
194
|
+
### Local Development
|
|
195
|
+
|
|
196
|
+
The MCP server enforces HTTPS by default. When pointing at a local HTTP URL (e.g., `http://localhost:3000`), pass `--allow-insecure`:
|
|
197
|
+
|
|
198
|
+
```json
|
|
199
|
+
{
|
|
200
|
+
"mcpServers": {
|
|
201
|
+
"informant": {
|
|
202
|
+
"command": "informant-mcp",
|
|
203
|
+
"args": ["--allow-insecure"]
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
This is only needed for local development/testing. Production setups over HTTPS don't need it.
|
|
210
|
+
|
|
191
211
|
## Claude Code Skill
|
|
192
212
|
|
|
193
213
|
Use `/informant` in Claude Code to triage and fix errors interactively. The skill:
|
|
@@ -233,12 +253,12 @@ The notification prompt includes: error class, error message (truncated), severi
|
|
|
233
253
|
Development Machine Remote Servers
|
|
234
254
|
+-----------------------+ +-----------------------+
|
|
235
255
|
| Claude Code | | Production |
|
|
236
|
-
| | | | /informant
|
|
256
|
+
| | | | /informant |
|
|
237
257
|
| | stdio | +-----------------------+
|
|
238
258
|
| v | HTTPS+Token
|
|
239
259
|
| MCP Server | -----------> +-----------------------+
|
|
240
260
|
| (exe/informant-mcp) | | Staging |
|
|
241
|
-
| | | /informant
|
|
261
|
+
| | | /informant |
|
|
242
262
|
+-----------------------+ +-----------------------+
|
|
243
263
|
|
|
244
264
|
Inside the Rails app:
|
|
@@ -288,7 +308,7 @@ bin/rails informant:stats # Show error monitoring statistics
|
|
|
288
308
|
bin/rails informant:purge # Purge resolved errors older than retention_days
|
|
289
309
|
```
|
|
290
310
|
|
|
291
|
-
## Data
|
|
311
|
+
## Data and Privacy
|
|
292
312
|
|
|
293
313
|
Each occurrence stores the following PII:
|
|
294
314
|
|
|
@@ -314,18 +334,18 @@ This replaces email values with `[FILTERED]` in occurrence data. IP addresses ca
|
|
|
314
334
|
|
|
315
335
|
## Security
|
|
316
336
|
|
|
317
|
-
-
|
|
337
|
+
- MCP server requires token authentication (`secure_compare`)
|
|
318
338
|
- All stored context is filtered through `ActiveSupport::ParameterFilter`
|
|
319
339
|
- MCP server enforces HTTPS by default
|
|
320
340
|
- Security headers: `Cache-Control: no-store`, `X-Content-Type-Options: nosniff`
|
|
321
341
|
- Error capture never breaks the host application
|
|
322
342
|
- Webhook payloads strip PII by default
|
|
323
|
-
- **Rate limiting** -- the
|
|
343
|
+
- **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
344
|
|
|
325
345
|
```ruby
|
|
326
346
|
# config/initializers/rack_attack.rb
|
|
327
|
-
Rack::Attack.throttle("informant
|
|
328
|
-
req.ip if req.path.start_with?("/informant/
|
|
347
|
+
Rack::Attack.throttle("informant", limit: 60, period: 1.minute) do |req|
|
|
348
|
+
req.ip if req.path.start_with?("/informant/")
|
|
329
349
|
end
|
|
330
350
|
```
|
|
331
351
|
|
data/exe/informant-mcp
CHANGED
|
@@ -3,11 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
5
5
|
|
|
6
|
-
|
|
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"
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require "json"
|
|
1
2
|
require "rails/generators"
|
|
2
3
|
require "rails/generators/active_record"
|
|
3
4
|
|
|
@@ -20,5 +21,53 @@ module RailsInformant
|
|
|
20
21
|
def mount_engine
|
|
21
22
|
route "mount RailsInformant::Engine => '/informant'"
|
|
22
23
|
end
|
|
24
|
+
|
|
25
|
+
def create_or_update_mcp_json
|
|
26
|
+
mcp_path = File.join(destination_root, ".mcp.json")
|
|
27
|
+
informant_entry = { "command" => "informant-mcp" }
|
|
28
|
+
|
|
29
|
+
if File.exist?(mcp_path)
|
|
30
|
+
existing = JSON.parse(File.read(mcp_path))
|
|
31
|
+
existing["mcpServers"] ||= {}
|
|
32
|
+
existing["mcpServers"]["informant"] = informant_entry
|
|
33
|
+
create_file ".mcp.json", JSON.pretty_generate(existing) + "\n", force: true
|
|
34
|
+
else
|
|
35
|
+
create_file ".mcp.json", JSON.pretty_generate(
|
|
36
|
+
"mcpServers" => { "informant" => informant_entry }
|
|
37
|
+
) + "\n"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def print_next_steps
|
|
42
|
+
say ""
|
|
43
|
+
say "Rails Informant installed!", :green
|
|
44
|
+
say ""
|
|
45
|
+
say "Next steps:", :yellow
|
|
46
|
+
say " 1. Run migrations:"
|
|
47
|
+
say " bin/rails db:migrate"
|
|
48
|
+
say ""
|
|
49
|
+
say " 2. Set a token (required for MCP server access):"
|
|
50
|
+
say " bin/rails credentials:edit"
|
|
51
|
+
say " # Add: rails_informant:"
|
|
52
|
+
say " # api_token: #{SecureRandom.hex 32}"
|
|
53
|
+
say ""
|
|
54
|
+
say " 3. Configure env vars for the MCP server (e.g., via .envrc + direnv):"
|
|
55
|
+
say " export INFORMANT_PRODUCTION_URL=https://your-app.com"
|
|
56
|
+
say " export INFORMANT_PRODUCTION_TOKEN=your-api-token"
|
|
57
|
+
say ""
|
|
58
|
+
say " The token must match the api_token in your Rails credentials."
|
|
59
|
+
say " Add .envrc to .gitignore — it contains secrets."
|
|
60
|
+
say ""
|
|
61
|
+
say " 4. Optional — install the Claude Code skill:"
|
|
62
|
+
say " bin/rails generate rails_informant:skill"
|
|
63
|
+
say ""
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def json_column_type
|
|
69
|
+
adapter = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).first&.adapter.to_s
|
|
70
|
+
adapter.match?(/postgres/i) ? "jsonb" : "json"
|
|
71
|
+
end
|
|
23
72
|
end
|
|
24
73
|
end
|
|
@@ -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
|
|
42
|
-
t
|
|
43
|
-
t
|
|
44
|
-
t
|
|
45
|
-
t
|
|
46
|
-
t
|
|
47
|
-
t
|
|
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
|
-
#
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
4
|
+
version: 0.0.7
|
|
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
|