rails_claude 0.1.0
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 +7 -0
- data/LICENSE.txt +17 -0
- data/README.md +270 -0
- data/lib/rails_claude/configuration.rb +55 -0
- data/lib/rails_claude/railtie.rb +28 -0
- data/lib/rails_claude/session.rb +149 -0
- data/lib/rails_claude/version.rb +3 -0
- data/lib/rails_claude.rb +16 -0
- metadata +79 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: cc6cc5ba06b613ea5acd963515c72379e70a66b44a3630516eb6d7c0024f3fba
|
|
4
|
+
data.tar.gz: e63ce9f4d1bb3463bc2bfe5cdeb26d58deff4a89cd5a5adfd71a1f481312de59
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: ff92166206f737689fe2e8c9a7344affeb03583c7bc367796709fbf298cfa0ed2b88a664564ccf7f4d6ebab592d1aa8f52ad3f49c851bd4d531759fcdc8dba0b
|
|
7
|
+
data.tar.gz: c2f7df20a83a1a292204bf4cb456a62f37fc94cf467f94fa93fe31c3a8796a776b241d775096320383dc1906d575301e4447a383b90c46e4c8f9d45383370679
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nick Pendery
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
data/README.md
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# RailsClaude
|
|
2
|
+
|
|
3
|
+
Chat with Claude AI directly inside your Rails console, with automatic Rails context.
|
|
4
|
+
|
|
5
|
+
RailsClaude drops an AI assistant into `rails c` that already knows your app's models, environment, and Ruby/Rails versions. Ask questions in plain English, get back ActiveRecord queries, debugging help, and code you can auto-execute — all without leaving the REPL.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Add the gem to your development group:
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
group :development do
|
|
13
|
+
gem "rails_claude"
|
|
14
|
+
end
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Then run:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
bundle install
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Requirements
|
|
24
|
+
|
|
25
|
+
- Ruby 3.0+
|
|
26
|
+
- Rails 6.0+
|
|
27
|
+
- An [Anthropic API key](https://console.anthropic.com/)
|
|
28
|
+
|
|
29
|
+
## Configuration
|
|
30
|
+
|
|
31
|
+
Set your API key as an environment variable:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
export ANTHROPIC_API_KEY=sk-ant-...
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Optional Configuration
|
|
38
|
+
|
|
39
|
+
Create an initializer at `config/initializers/rails_claude.rb` to customize behavior:
|
|
40
|
+
|
|
41
|
+
```ruby
|
|
42
|
+
RailsClaude.configure do |config|
|
|
43
|
+
config.api_key = ENV["ANTHROPIC_API_KEY"] # default
|
|
44
|
+
config.model = "claude-opus-4-6" # default
|
|
45
|
+
config.max_tokens = 1024 # default
|
|
46
|
+
config.safe_mode = Rails.env.production? # default
|
|
47
|
+
config.system_prompt = "Custom system prompt..." # auto-generated by default
|
|
48
|
+
end
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
| Option | Default | Description |
|
|
52
|
+
|--------|---------|-------------|
|
|
53
|
+
| `api_key` | `ENV["ANTHROPIC_API_KEY"]` | Your Anthropic API key |
|
|
54
|
+
| `model` | `"claude-opus-4-6"` | Claude model to use for requests |
|
|
55
|
+
| `max_tokens` | `1024` | Maximum tokens per response |
|
|
56
|
+
| `safe_mode` | `true` in production, `false` otherwise | Wrap code execution in a rolled-back transaction |
|
|
57
|
+
| `system_prompt` | Auto-generated | System prompt with Rails context (see below) |
|
|
58
|
+
|
|
59
|
+
#### Auto-generated System Prompt
|
|
60
|
+
|
|
61
|
+
By default, RailsClaude builds a system prompt that includes:
|
|
62
|
+
|
|
63
|
+
- Your application name
|
|
64
|
+
- All detected model classes (ApplicationRecord descendants)
|
|
65
|
+
- Current Rails environment
|
|
66
|
+
- Ruby and Rails versions
|
|
67
|
+
|
|
68
|
+
This gives Claude immediate awareness of your app's structure without any manual setup.
|
|
69
|
+
|
|
70
|
+
## Usage
|
|
71
|
+
|
|
72
|
+
When you start `rails c`, RailsClaude loads automatically and prints available commands:
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
✦ RailsClaude ready. (safe mode)
|
|
76
|
+
claude "question" — chat
|
|
77
|
+
claude_run! "question" — chat + auto-eval code
|
|
78
|
+
claude_load_model User — load a model for analysis
|
|
79
|
+
claude_load_file "path/to/f" — load any file for analysis
|
|
80
|
+
claude_safe_mode! / claude_unsafe_mode!
|
|
81
|
+
claude_history / claude_reset!
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### `claude` — Ask a Question
|
|
85
|
+
|
|
86
|
+
Send a message to Claude and get a response. Conversation history is maintained across calls, so follow-up questions work naturally.
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
claude "find users who signed up in the last 7 days"
|
|
90
|
+
claude "now filter those to only verified accounts"
|
|
91
|
+
claude "what indexes would speed that query up?"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### `claude_run!` — Ask and Auto-Execute Code
|
|
95
|
+
|
|
96
|
+
Like `claude`, but automatically extracts Ruby code blocks from Claude's response, executes them in the console, and feeds the result back. Runs up to 3 iterations by default (configurable via `max_iterations`).
|
|
97
|
+
|
|
98
|
+
```ruby
|
|
99
|
+
claude_run! "how many orders are in pending state?"
|
|
100
|
+
# Claude responds with: Order.where(status: "pending").count
|
|
101
|
+
# ⚡ Running: Order.where(status: "pending").count
|
|
102
|
+
# ⮕ Result: 42
|
|
103
|
+
|
|
104
|
+
claude_run! "show me the 5 most recent users", max_iterations: 1
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Code is displayed in yellow before execution, and results appear in green. If the executed code raises an error, the error is captured and sent back to Claude for debugging context.
|
|
108
|
+
|
|
109
|
+
### `claude_load_model` — Load a Model for Analysis
|
|
110
|
+
|
|
111
|
+
Inject a model's full source code into the conversation so Claude can analyze it.
|
|
112
|
+
|
|
113
|
+
```ruby
|
|
114
|
+
claude_load_model User
|
|
115
|
+
claude_load_model "Post" # string names work too
|
|
116
|
+
|
|
117
|
+
claude "what validations does this model have?"
|
|
118
|
+
claude "find any N+1 query risks in the associations"
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The gem finds the source file via `source_location` on the model's instance methods, falling back to `app/models/<name>.rb`.
|
|
122
|
+
|
|
123
|
+
### `claude_load_file` — Load Any File for Analysis
|
|
124
|
+
|
|
125
|
+
Inject any file in your project into the conversation context.
|
|
126
|
+
|
|
127
|
+
```ruby
|
|
128
|
+
claude_load_file "app/services/billing_service.rb"
|
|
129
|
+
claude_load_file "config/routes.rb"
|
|
130
|
+
|
|
131
|
+
claude "walk me through the billing flow"
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Paths are resolved relative to `Rails.root`.
|
|
135
|
+
|
|
136
|
+
### `claude_history` — View Conversation History
|
|
137
|
+
|
|
138
|
+
Display all messages in the current session. User messages appear in cyan, Claude's responses in magenta.
|
|
139
|
+
|
|
140
|
+
```ruby
|
|
141
|
+
claude_history
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### `claude_safe_mode!` / `claude_unsafe_mode!` — Toggle Safe Mode
|
|
145
|
+
|
|
146
|
+
Switch between safe and unrestricted modes during a session without restarting the console.
|
|
147
|
+
|
|
148
|
+
```ruby
|
|
149
|
+
claude_unsafe_mode!
|
|
150
|
+
# ⚠ Safe mode disabled — code will execute with full write access.
|
|
151
|
+
|
|
152
|
+
claude_run! "create a test user" # this will persist
|
|
153
|
+
|
|
154
|
+
claude_safe_mode!
|
|
155
|
+
# 🔒 Safe mode enabled — code runs in rolled-back transactions.
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
`claude_safe_mode!` also accepts a boolean: `claude_safe_mode!(false)` is equivalent to `claude_unsafe_mode!`.
|
|
159
|
+
|
|
160
|
+
### `claude_reset!` — Clear History
|
|
161
|
+
|
|
162
|
+
Start a fresh conversation. Clears all message history while keeping your configuration.
|
|
163
|
+
|
|
164
|
+
```ruby
|
|
165
|
+
claude_reset!
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### `claude_session` — Access the Session Object
|
|
169
|
+
|
|
170
|
+
For advanced usage, access the underlying `RailsClaude::Session` instance directly.
|
|
171
|
+
|
|
172
|
+
```ruby
|
|
173
|
+
session = claude_session
|
|
174
|
+
session.history # inspect raw conversation history
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Examples
|
|
178
|
+
|
|
179
|
+
### Exploring Data
|
|
180
|
+
|
|
181
|
+
```ruby
|
|
182
|
+
claude_run! "how many users signed up this month?"
|
|
183
|
+
claude_run! "show me the top 10 by order count"
|
|
184
|
+
claude_run! "what's the average order value for those users?"
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Debugging a Model
|
|
188
|
+
|
|
189
|
+
```ruby
|
|
190
|
+
claude_load_model Order
|
|
191
|
+
claude "what happens when status transitions from pending to fulfilled?"
|
|
192
|
+
claude "are there any callbacks that could cause side effects?"
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Analyzing a Service
|
|
196
|
+
|
|
197
|
+
```ruby
|
|
198
|
+
claude_load_file "app/services/payment_service.rb"
|
|
199
|
+
claude_load_file "app/models/payment.rb"
|
|
200
|
+
claude "what error cases does the payment service handle?"
|
|
201
|
+
claude_run! "show me an example of calling the main method"
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Multi-Step Investigation
|
|
205
|
+
|
|
206
|
+
```ruby
|
|
207
|
+
claude "are there any orders stuck in processing for more than 24 hours?"
|
|
208
|
+
claude_run! "find them"
|
|
209
|
+
claude_run! "show me the associated user for the oldest one"
|
|
210
|
+
claude "what should I check to debug this?"
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Safe Mode
|
|
214
|
+
|
|
215
|
+
Safe mode prevents `claude_run!` from making any persistent changes to your database. When enabled, all auto-executed code runs inside a database transaction that is **always rolled back** after the result is captured. Read queries work normally; writes are silently undone.
|
|
216
|
+
|
|
217
|
+
Safe mode is **on by default in production** and off in development/test. You'll see the current mode in the startup banner:
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
✦ RailsClaude ready. (safe mode)
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
or:
|
|
224
|
+
|
|
225
|
+
```
|
|
226
|
+
✦ RailsClaude ready. (unrestricted)
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
The system prompt also instructs Claude to only generate read-only code when safe mode is active.
|
|
230
|
+
|
|
231
|
+
### Overriding Safe Mode
|
|
232
|
+
|
|
233
|
+
```ruby
|
|
234
|
+
# Force safe mode on in development
|
|
235
|
+
RailsClaude.configure do |config|
|
|
236
|
+
config.safe_mode = true
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Disable safe mode in production (use with caution)
|
|
240
|
+
RailsClaude.configure do |config|
|
|
241
|
+
config.safe_mode = false
|
|
242
|
+
end
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### What Safe Mode Protects Against
|
|
246
|
+
|
|
247
|
+
- `INSERT`, `UPDATE`, `DELETE` statements — rolled back after execution
|
|
248
|
+
- `ActiveRecord` create/update/destroy calls — rolled back after execution
|
|
249
|
+
- Claude is prompted to avoid generating destructive code entirely
|
|
250
|
+
|
|
251
|
+
### What Safe Mode Does Not Protect Against
|
|
252
|
+
|
|
253
|
+
- Non-database side effects (file I/O, HTTP requests, system commands)
|
|
254
|
+
- Schema changes (`ALTER TABLE`, migrations) — these may auto-commit depending on your database
|
|
255
|
+
|
|
256
|
+
For full isolation in production, consider restricting the database user's permissions as well.
|
|
257
|
+
|
|
258
|
+
## How It Works
|
|
259
|
+
|
|
260
|
+
RailsClaude uses a Rails [Railtie](https://api.rubyonrails.org/classes/Rails/Railtie.html) to hook into console startup. When `rails c` loads:
|
|
261
|
+
|
|
262
|
+
1. **Eager loads** the application to discover all model classes
|
|
263
|
+
2. **Creates a session** with an Anthropic API client and auto-generated system prompt
|
|
264
|
+
3. **Defines helper methods** (`claude`, `claude_run!`, etc.) on `Object` so they're available as top-level console commands
|
|
265
|
+
|
|
266
|
+
Each call to `claude` or `claude_run!` sends the full conversation history to the Claude API, maintaining context across turns. `claude_run!` additionally extracts fenced code blocks (`` ```ruby `` or `` ``` ``) from responses, evaluates them in the console context, and loops the result back for up to `max_iterations` rounds.
|
|
267
|
+
|
|
268
|
+
## License
|
|
269
|
+
|
|
270
|
+
The gem is available as open source under the terms of the [MIT License](LICENSE.txt).
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module RailsClaude
|
|
2
|
+
class Configuration
|
|
3
|
+
attr_accessor :api_key, :model, :max_tokens, :system_prompt, :safe_mode
|
|
4
|
+
|
|
5
|
+
def initialize
|
|
6
|
+
@api_key = ENV["ANTHROPIC_API_KEY"]
|
|
7
|
+
@model = "claude-opus-4-6"
|
|
8
|
+
@max_tokens = 1024
|
|
9
|
+
@safe_mode = defined?(Rails) ? Rails.env.production? : true
|
|
10
|
+
@system_prompt = nil # deferred until first access so safe_mode is settled
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def system_prompt
|
|
14
|
+
@system_prompt || default_system_prompt
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def safe_mode?
|
|
18
|
+
!!@safe_mode
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def default_system_prompt
|
|
24
|
+
app_name = defined?(Rails) ? Rails.application.class.module_parent_name : "Rails"
|
|
25
|
+
models = defined?(ApplicationRecord) ? ApplicationRecord.descendants.map(&:name).join(", ") : "unknown"
|
|
26
|
+
|
|
27
|
+
prompt = <<~PROMPT
|
|
28
|
+
You are a Rails developer assistant embedded inside a live Rails console for the #{app_name} app.
|
|
29
|
+
|
|
30
|
+
You help the user write ActiveRecord queries, debug issues, and explore the app.
|
|
31
|
+
|
|
32
|
+
Known models: #{models}
|
|
33
|
+
Rails environment: #{Rails.env}
|
|
34
|
+
Ruby version: #{RUBY_VERSION}
|
|
35
|
+
Rails version: #{Rails.version}
|
|
36
|
+
|
|
37
|
+
Keep responses concise and practical. When suggesting code, prefer single-line expressions
|
|
38
|
+
that work well in a REPL context. Remind the user if they need to run something manually.
|
|
39
|
+
PROMPT
|
|
40
|
+
|
|
41
|
+
if safe_mode?
|
|
42
|
+
prompt += <<~SAFE
|
|
43
|
+
|
|
44
|
+
IMPORTANT: Safe mode is ON. All executed code runs inside a read-only transaction
|
|
45
|
+
that is automatically rolled back. Only generate read-only code — SELECT queries,
|
|
46
|
+
inspections, and counts. Do NOT generate code that creates, updates, or deletes records,
|
|
47
|
+
runs migrations, modifies files, or executes system commands. Any database writes will
|
|
48
|
+
be rolled back and the user will be warned.
|
|
49
|
+
SAFE
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
prompt
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module RailsClaude
|
|
2
|
+
class Railtie < Rails::Railtie
|
|
3
|
+
console do
|
|
4
|
+
Rails.application.eager_load!
|
|
5
|
+
|
|
6
|
+
session = RailsClaude::Session.new
|
|
7
|
+
|
|
8
|
+
Object.define_method(:claude) { |msg| session.ask(msg) }
|
|
9
|
+
Object.define_method(:claude_run!) { |msg, **opts| session.ask_and_run(msg, **opts) }
|
|
10
|
+
Object.define_method(:claude_load_model) { |model| session.load_model(model) }
|
|
11
|
+
Object.define_method(:claude_load_file) { |path| session.load_file(path) }
|
|
12
|
+
Object.define_method(:claude_reset!) { session.reset! }
|
|
13
|
+
Object.define_method(:claude_history) { session.show_history }
|
|
14
|
+
Object.define_method(:claude_session) { session }
|
|
15
|
+
Object.define_method(:claude_safe_mode!) { |enabled = true| session.set_safe_mode(enabled) }
|
|
16
|
+
Object.define_method(:claude_unsafe_mode!) { session.set_safe_mode(false) }
|
|
17
|
+
|
|
18
|
+
mode = RailsClaude.configuration.safe_mode? ? "\e[32m(safe mode)\e[0m" : "\e[33m(unrestricted)\e[0m"
|
|
19
|
+
puts "\e[35m✦ RailsClaude ready.\e[0m #{mode}"
|
|
20
|
+
puts " \e[36mclaude\e[0m \"question\" — chat"
|
|
21
|
+
puts " \e[36mclaude_run!\e[0m \"question\" — chat + auto-eval code"
|
|
22
|
+
puts " \e[36mclaude_load_model\e[0m User — load a model for analysis"
|
|
23
|
+
puts " \e[36mclaude_load_file\e[0m \"path/to/f\" — load any file for analysis"
|
|
24
|
+
puts " \e[36mclaude_safe_mode!\e[0m / \e[36mclaude_unsafe_mode!\e[0m"
|
|
25
|
+
puts " \e[36mclaude_history\e[0m / \e[36mclaude_reset!\e[0m\n\n"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
require "anthropic"
|
|
2
|
+
|
|
3
|
+
module RailsClaude
|
|
4
|
+
class Session
|
|
5
|
+
attr_reader :history
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
@config = RailsClaude.configuration
|
|
9
|
+
@client = Anthropic::Client.new(api_key: @config.api_key)
|
|
10
|
+
@history = []
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def ask(message)
|
|
14
|
+
@history << { role: "user", content: message }
|
|
15
|
+
|
|
16
|
+
response = @client.messages.create(
|
|
17
|
+
model: @config.model,
|
|
18
|
+
max_tokens: @config.max_tokens,
|
|
19
|
+
system: @config.system_prompt,
|
|
20
|
+
messages: @history
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
reply = response.content.first.text
|
|
24
|
+
@history << { role: "assistant", content: reply }
|
|
25
|
+
pretty_print(reply)
|
|
26
|
+
nil
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def ask_and_run(message, max_iterations: 3)
|
|
30
|
+
@history << { role: "user", content: message }
|
|
31
|
+
|
|
32
|
+
max_iterations.times do
|
|
33
|
+
response = @client.messages.create(
|
|
34
|
+
model: @config.model,
|
|
35
|
+
max_tokens: @config.max_tokens,
|
|
36
|
+
system: @config.system_prompt,
|
|
37
|
+
messages: @history
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
reply = response.content.first.text
|
|
41
|
+
@history << { role: "assistant", content: reply }
|
|
42
|
+
pretty_print(reply)
|
|
43
|
+
|
|
44
|
+
code = extract_code(reply)
|
|
45
|
+
break unless code
|
|
46
|
+
|
|
47
|
+
run_label = @config.safe_mode? ? "\e[33m🔒 Running (safe mode):\e[0m" : "\e[33m⚡ Running:\e[0m"
|
|
48
|
+
puts "#{run_label}\n#{code}\n"
|
|
49
|
+
result = safe_eval(code)
|
|
50
|
+
puts "\e[32m⮕ Result:\e[0m #{result}\n\n"
|
|
51
|
+
|
|
52
|
+
@history << { role: "user", content: "Result of running that code: #{result}" }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
nil
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def load_model(model)
|
|
59
|
+
klass = model.is_a?(Class) ? model : model.to_s.constantize
|
|
60
|
+
path = source_path_for(klass)
|
|
61
|
+
raise "Could not find source file for #{klass}" unless path && File.exist?(path)
|
|
62
|
+
inject_file(path, label: "Model: #{klass}")
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def load_file(path)
|
|
66
|
+
full_path = Rails.root.join(path)
|
|
67
|
+
raise "File not found: #{full_path}" unless File.exist?(full_path)
|
|
68
|
+
inject_file(full_path, label: path)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def set_safe_mode(enabled)
|
|
72
|
+
@config.safe_mode = enabled
|
|
73
|
+
if enabled
|
|
74
|
+
puts "\e[32m🔒 Safe mode enabled — code runs in rolled-back transactions.\e[0m"
|
|
75
|
+
else
|
|
76
|
+
puts "\e[33m⚠ Safe mode disabled — code will execute with full write access.\e[0m"
|
|
77
|
+
end
|
|
78
|
+
nil
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def reset!
|
|
82
|
+
@history = []
|
|
83
|
+
puts "→ Conversation history cleared."
|
|
84
|
+
nil
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def show_history
|
|
88
|
+
if @history.empty?
|
|
89
|
+
puts "No conversation history yet."
|
|
90
|
+
else
|
|
91
|
+
@history.each do |msg|
|
|
92
|
+
label = msg[:role] == "user" ? "\e[36mYou\e[0m" : "\e[35mClaude\e[0m"
|
|
93
|
+
puts "\n#{label}: #{msg[:content]}"
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
nil
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
private
|
|
100
|
+
|
|
101
|
+
def inject_file(path, label:)
|
|
102
|
+
content = File.read(path)
|
|
103
|
+
notice = "I'm sharing this file for context — #{label}:\n\n```ruby\n#{content}\n```"
|
|
104
|
+
@history << { role: "user", content: notice }
|
|
105
|
+
puts "\e[36m→ Loaded #{label} into conversation context.\e[0m"
|
|
106
|
+
puts " Ask Claude about it: claude \"explain this model\" or claude \"find N+1 issues\"\n\n"
|
|
107
|
+
nil
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def extract_code(text)
|
|
111
|
+
text[/```ruby\n(.*?)```/m, 1] || text[/```\n(.*?)```/m, 1]
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def safe_eval(code)
|
|
115
|
+
if @config.safe_mode?
|
|
116
|
+
safe_eval_readonly(code)
|
|
117
|
+
else
|
|
118
|
+
result = eval(code) # rubocop:disable Security/Eval
|
|
119
|
+
result.inspect
|
|
120
|
+
end
|
|
121
|
+
rescue StandardError => e
|
|
122
|
+
err = "#{e.class}: #{e.message}"
|
|
123
|
+
@history << { role: "user", content: "That code raised an error: #{err}" }
|
|
124
|
+
"\e[31mError — #{err}\e[0m"
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def safe_eval_readonly(code)
|
|
128
|
+
output = nil
|
|
129
|
+
ActiveRecord::Base.transaction do
|
|
130
|
+
output = eval(code).inspect # rubocop:disable Security/Eval
|
|
131
|
+
raise ActiveRecord::Rollback
|
|
132
|
+
end
|
|
133
|
+
output
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def source_path_for(klass)
|
|
137
|
+
m = klass.instance_methods(false).first
|
|
138
|
+
if m
|
|
139
|
+
file, = klass.instance_method(m).source_location
|
|
140
|
+
return file if file
|
|
141
|
+
end
|
|
142
|
+
Rails.root.join("app", "models", "#{klass.name.underscore}.rb").to_s
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def pretty_print(text)
|
|
146
|
+
puts "\n\e[35mClaude:\e[0m #{text}\n\n"
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
data/lib/rails_claude.rb
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require "rails_claude/version"
|
|
2
|
+
require "rails_claude/configuration"
|
|
3
|
+
require "rails_claude/session"
|
|
4
|
+
require "rails_claude/railtie" if defined?(Rails)
|
|
5
|
+
|
|
6
|
+
module RailsClaude
|
|
7
|
+
class << self
|
|
8
|
+
def configuration
|
|
9
|
+
@configuration ||= Configuration.new
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def configure
|
|
13
|
+
yield(configuration)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rails_claude
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Nick Pendery
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-04-06 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: anthropic
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: 0.3.0
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: 0.3.0
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: railties
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '6.0'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '6.0'
|
|
41
|
+
description: Provides an interactive Claude AI session directly in rails c, with Rails-aware
|
|
42
|
+
context.
|
|
43
|
+
email:
|
|
44
|
+
- npendery@homebot.ai
|
|
45
|
+
executables: []
|
|
46
|
+
extensions: []
|
|
47
|
+
extra_rdoc_files: []
|
|
48
|
+
files:
|
|
49
|
+
- LICENSE.txt
|
|
50
|
+
- README.md
|
|
51
|
+
- lib/rails_claude.rb
|
|
52
|
+
- lib/rails_claude/configuration.rb
|
|
53
|
+
- lib/rails_claude/railtie.rb
|
|
54
|
+
- lib/rails_claude/session.rb
|
|
55
|
+
- lib/rails_claude/version.rb
|
|
56
|
+
homepage: https://github.com/npendery/rails-claude-console
|
|
57
|
+
licenses:
|
|
58
|
+
- MIT
|
|
59
|
+
metadata: {}
|
|
60
|
+
post_install_message:
|
|
61
|
+
rdoc_options: []
|
|
62
|
+
require_paths:
|
|
63
|
+
- lib
|
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0'
|
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
70
|
+
requirements:
|
|
71
|
+
- - ">="
|
|
72
|
+
- !ruby/object:Gem::Version
|
|
73
|
+
version: '0'
|
|
74
|
+
requirements: []
|
|
75
|
+
rubygems_version: 3.3.26
|
|
76
|
+
signing_key:
|
|
77
|
+
specification_version: 4
|
|
78
|
+
summary: Chat with Claude inside your Rails console
|
|
79
|
+
test_files: []
|