rails-agents 0.3.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/.claude/commands/create-ticket.md +153 -0
- data/.claude/commands/work.md +18 -0
- data/.claude/settings.local.json +25 -0
- data/.claude/tickets/enhanced-cli-experience.md +367 -0
- data/CHANGELOG.md +49 -0
- data/README.md +104 -0
- data/exe/rails-agents +8 -0
- data/lib/rails_agents/version.rb +5 -0
- data/lib/rails_agents.rb +351 -0
- data/prd.md +159 -0
- data/rails-agents.gemspec +38 -0
- metadata +126 -0
data/README.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Rails Agents
|
|
2
|
+
|
|
3
|
+
A collection of specialized Claude Code agents for Rails development. These agents provide expert assistance for different aspects of Rails applications, from controllers and models to testing and deployment.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Install the gem:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
gem install rails-agents
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
### Interactive Installation (Recommended)
|
|
16
|
+
|
|
17
|
+
Simply run the install command to interactively select which agents to install:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
rails-agents install
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
This will display a visual multi-select menu where you can:
|
|
24
|
+
- **Navigate** agents using arrow keys (↑/↓)
|
|
25
|
+
- **Toggle selection** with spacebar
|
|
26
|
+
- **Confirm** with enter
|
|
27
|
+
- Use shortcuts: **'a'** for all, **'n'** for none
|
|
28
|
+
|
|
29
|
+
Agents are organized by category (Core, Frontend, API, Testing, Infrastructure) with descriptions for each.
|
|
30
|
+
|
|
31
|
+
**File Conflict Handling**: If agent files already exist, you'll be prompted to view a color-coded diff before deciding whether to overwrite or keep the existing file.
|
|
32
|
+
|
|
33
|
+
### Direct Installation
|
|
34
|
+
|
|
35
|
+
Install specific agents directly:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
rails-agents install -a api,models,tests
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Install to Specific Directory
|
|
42
|
+
|
|
43
|
+
By default, agents are installed to the current directory. To install to a different directory:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
rails-agents install -d /path/to/your/rails/project
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### List Available Agents
|
|
50
|
+
|
|
51
|
+
See all available agents and their descriptions:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
rails-agents list
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Available Agents
|
|
58
|
+
|
|
59
|
+
- **api** - Rails API specialist for RESTful design, serialization, and API versioning
|
|
60
|
+
- **controllers** - Rails controller and routing specialist for RESTful design and request handling
|
|
61
|
+
- **devops** - Rails DevOps specialist for deployment, Kamal, Docker, CI/CD, and production infrastructure
|
|
62
|
+
- **graphql** - Rails GraphQL specialist for schema design, resolvers, mutations, and performance optimization
|
|
63
|
+
- **jobs** - Rails background jobs specialist for ActiveJob, Solid Queue, async processing, and queue management
|
|
64
|
+
- **models** - ActiveRecord and database specialist for Rails models, migrations, and database design
|
|
65
|
+
- **services** - Rails service objects and business logic specialist for extracting complex operations
|
|
66
|
+
- **stimulus** - Stimulus.js and Turbo specialist for modern Rails frontend development with progressive enhancement
|
|
67
|
+
- **tests** - Rails testing specialist for RSpec, TDD, and comprehensive test coverage
|
|
68
|
+
- **views** - Rails views specialist with Tailwind CSS 4.x expertise, custom form builders, and modern UI components
|
|
69
|
+
|
|
70
|
+
## How It Works
|
|
71
|
+
|
|
72
|
+
The CLI installs agent files to `.claude/agents/` in your target directory. These agents are then available for use in Claude Code when you're working in that directory.
|
|
73
|
+
|
|
74
|
+
Each agent is a specialized assistant that understands the specific domain and can help you with:
|
|
75
|
+
- Writing idiomatic Rails code
|
|
76
|
+
- Following best practices
|
|
77
|
+
- Implementing modern Rails patterns
|
|
78
|
+
- Debugging and optimization
|
|
79
|
+
- Architecture decisions
|
|
80
|
+
|
|
81
|
+
## Requirements
|
|
82
|
+
|
|
83
|
+
- Ruby 3.0 or higher
|
|
84
|
+
- Claude Code (for using the installed agents)
|
|
85
|
+
|
|
86
|
+
## Development
|
|
87
|
+
|
|
88
|
+
After checking out the repo, run `bundle install` to install dependencies.
|
|
89
|
+
|
|
90
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
|
91
|
+
|
|
92
|
+
To build and install the gem locally:
|
|
93
|
+
```bash
|
|
94
|
+
gem build rails-agents.gemspec
|
|
95
|
+
gem install rails-agents-0.1.0.gem
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Contributing
|
|
99
|
+
|
|
100
|
+
Bug reports and pull requests are welcome on GitHub.
|
|
101
|
+
|
|
102
|
+
## License
|
|
103
|
+
|
|
104
|
+
The gem is available as open source under the [MIT License](LICENSE.txt).
|
data/exe/rails-agents
ADDED
data/lib/rails_agents.rb
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
require 'optparse'
|
|
5
|
+
require 'tty-prompt'
|
|
6
|
+
require 'pastel'
|
|
7
|
+
require 'diffy'
|
|
8
|
+
require_relative 'rails_agents/version'
|
|
9
|
+
|
|
10
|
+
module RailsAgents
|
|
11
|
+
class CLI
|
|
12
|
+
AGENT_NAMES = %w[
|
|
13
|
+
api controllers devops graphql jobs models
|
|
14
|
+
services stimulus tests views
|
|
15
|
+
].freeze
|
|
16
|
+
|
|
17
|
+
# Agent categories for organized display
|
|
18
|
+
AGENT_CATEGORIES = {
|
|
19
|
+
'Core' => %w[controllers models services],
|
|
20
|
+
'Frontend' => %w[views stimulus],
|
|
21
|
+
'API' => %w[api graphql],
|
|
22
|
+
'Testing' => %w[tests],
|
|
23
|
+
'Infrastructure' => %w[devops jobs]
|
|
24
|
+
}.freeze
|
|
25
|
+
|
|
26
|
+
def initialize
|
|
27
|
+
@options = {}
|
|
28
|
+
@prompt = TTY::Prompt.new
|
|
29
|
+
@pastel = Pastel.new
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def run(args)
|
|
33
|
+
parse_options(args)
|
|
34
|
+
|
|
35
|
+
case @options[:command]
|
|
36
|
+
when 'install'
|
|
37
|
+
install_agents
|
|
38
|
+
when 'list'
|
|
39
|
+
list_agents
|
|
40
|
+
when 'help', nil
|
|
41
|
+
show_help
|
|
42
|
+
else
|
|
43
|
+
puts "Unknown command: #{@options[:command]}"
|
|
44
|
+
show_help
|
|
45
|
+
exit 1
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def parse_options(args)
|
|
52
|
+
parser = OptionParser.new do |opts|
|
|
53
|
+
opts.banner = "Usage: rails-agents [command] [options]"
|
|
54
|
+
opts.separator ""
|
|
55
|
+
opts.separator "Commands:"
|
|
56
|
+
opts.separator " install [agent1,agent2,...] Install specific agents or all if none specified"
|
|
57
|
+
opts.separator " list List available agents"
|
|
58
|
+
opts.separator " help Show this help message"
|
|
59
|
+
opts.separator ""
|
|
60
|
+
opts.separator "Options:"
|
|
61
|
+
|
|
62
|
+
opts.on("-a", "--agents AGENTS", Array, "Comma-separated list of agents to install") do |agents|
|
|
63
|
+
@options[:agents] = agents
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
opts.on("-d", "--directory DIR", "Target directory (defaults to current directory)") do |dir|
|
|
67
|
+
@options[:directory] = dir
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
opts.on("-h", "--help", "Show this help message") do
|
|
72
|
+
@options[:command] = 'help'
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
begin
|
|
77
|
+
parser.parse!(args)
|
|
78
|
+
@options[:command] = args.first || 'help'
|
|
79
|
+
@options[:directory] ||= Dir.pwd
|
|
80
|
+
@options[:agents] ||= args[1]&.split(',') if @options[:command] == 'install'
|
|
81
|
+
rescue OptionParser::InvalidOption => e
|
|
82
|
+
puts "Error: #{e.message}"
|
|
83
|
+
show_help
|
|
84
|
+
exit 1
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def install_agents
|
|
89
|
+
target_dir = File.join(@options[:directory], '.claude', 'agents')
|
|
90
|
+
|
|
91
|
+
unless Dir.exist?(@options[:directory])
|
|
92
|
+
puts "Error: Directory '#{@options[:directory]}' does not exist"
|
|
93
|
+
exit 1
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Create .claude/agents directory if it doesn't exist
|
|
97
|
+
FileUtils.mkdir_p(target_dir)
|
|
98
|
+
|
|
99
|
+
if @options[:agents]
|
|
100
|
+
agents_to_install = @options[:agents]
|
|
101
|
+
# Validate agent names
|
|
102
|
+
invalid_agents = agents_to_install - AGENT_NAMES
|
|
103
|
+
unless invalid_agents.empty?
|
|
104
|
+
puts "Error: Unknown agents: #{invalid_agents.join(', ')}"
|
|
105
|
+
puts "Available agents: #{AGENT_NAMES.join(', ')}"
|
|
106
|
+
exit 1
|
|
107
|
+
end
|
|
108
|
+
else
|
|
109
|
+
agents_to_install = select_agents_interactively
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
source_dir = File.join(__dir__, '..', '.claude', 'agents')
|
|
113
|
+
|
|
114
|
+
agents_to_install.each do |agent|
|
|
115
|
+
source_file = File.join(source_dir, "#{agent}.md")
|
|
116
|
+
target_file = File.join(target_dir, "#{agent}.md")
|
|
117
|
+
|
|
118
|
+
unless File.exist?(source_file)
|
|
119
|
+
puts @pastel.yellow("⚠") + " Warning: Agent file #{agent}.md not found in source"
|
|
120
|
+
next
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
if File.exist?(target_file)
|
|
124
|
+
action = handle_file_conflict(target_file, source_file, "#{agent}.md agent")
|
|
125
|
+
next if action == :skip
|
|
126
|
+
|
|
127
|
+
if action == :overwrite
|
|
128
|
+
begin
|
|
129
|
+
FileUtils.cp(source_file, target_file)
|
|
130
|
+
puts @pastel.green("✓") + " Updated #{agent} agent"
|
|
131
|
+
rescue Errno::EACCES => e
|
|
132
|
+
puts @pastel.red("✗") + " Permission denied: Cannot write to #{target_file}"
|
|
133
|
+
puts @pastel.yellow("Try running with elevated permissions or check directory permissions")
|
|
134
|
+
rescue Errno::ENOSPC => e
|
|
135
|
+
puts @pastel.red("✗") + " Disk full: Cannot write #{agent} agent"
|
|
136
|
+
exit 1
|
|
137
|
+
rescue StandardError => e
|
|
138
|
+
puts @pastel.red("✗") + " Failed to update #{agent} agent: #{e.message}"
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
else
|
|
142
|
+
begin
|
|
143
|
+
FileUtils.cp(source_file, target_file)
|
|
144
|
+
puts @pastel.green("✓") + " Installed #{agent} agent"
|
|
145
|
+
rescue Errno::EACCES => e
|
|
146
|
+
puts @pastel.red("✗") + " Permission denied: Cannot write to #{target_file}"
|
|
147
|
+
puts @pastel.yellow("Try running with elevated permissions or check directory permissions")
|
|
148
|
+
rescue Errno::ENOSPC => e
|
|
149
|
+
puts @pastel.red("✗") + " Disk full: Cannot write #{agent} agent"
|
|
150
|
+
exit 1
|
|
151
|
+
rescue StandardError => e
|
|
152
|
+
puts @pastel.red("✗") + " Failed to install #{agent} agent: #{e.message}"
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Install CLAUDE.md template
|
|
158
|
+
install_claude_template
|
|
159
|
+
|
|
160
|
+
puts "\n" + @pastel.green.bold("✓ Installation complete!")
|
|
161
|
+
puts @pastel.dim("Agents installed to: #{target_dir}")
|
|
162
|
+
puts @pastel.dim("CLAUDE.md template installed to: #{@options[:directory]}")
|
|
163
|
+
puts "\n" + @pastel.cyan("To use these agents in Claude Code, make sure you're in a directory")
|
|
164
|
+
puts @pastel.cyan("that contains the .claude/agents folder and CLAUDE.md file.")
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def list_agents
|
|
168
|
+
puts "Available Rails agents:"
|
|
169
|
+
puts
|
|
170
|
+
AGENT_NAMES.each do |agent|
|
|
171
|
+
source_file = File.join(__dir__, '..', '.claude', 'agents', "#{agent}.md")
|
|
172
|
+
if File.exist?(source_file)
|
|
173
|
+
# Read first few lines to get description
|
|
174
|
+
description = extract_description(source_file)
|
|
175
|
+
puts " #{agent.ljust(12)} - #{description}"
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
puts
|
|
179
|
+
puts "Use 'rails-agents install' to install all agents,"
|
|
180
|
+
puts "or 'rails-agents install -a agent1,agent2' to install specific ones."
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def extract_description(file_path)
|
|
184
|
+
File.open(file_path, 'r') do |file|
|
|
185
|
+
content = file.read
|
|
186
|
+
# Extract description from frontmatter
|
|
187
|
+
if content.match(/^---\s*\n.*?description:\s*(.+?)\n.*?^---\s*\n/m)
|
|
188
|
+
return $1.strip
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
"Rails specialist agent"
|
|
192
|
+
rescue
|
|
193
|
+
"Rails specialist agent"
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def install_claude_template
|
|
197
|
+
target_claude_file = File.join(@options[:directory], 'CLAUDE.md')
|
|
198
|
+
source_template = File.join(__dir__, '..', 'CLAUDE.md.template')
|
|
199
|
+
|
|
200
|
+
unless File.exist?(source_template)
|
|
201
|
+
puts "⚠ Warning: CLAUDE.md template not found, skipping"
|
|
202
|
+
return
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
if File.exist?(target_claude_file)
|
|
206
|
+
action = handle_file_conflict(target_claude_file, source_template, 'CLAUDE.md')
|
|
207
|
+
return if action == :skip
|
|
208
|
+
|
|
209
|
+
if action == :overwrite
|
|
210
|
+
begin
|
|
211
|
+
FileUtils.cp(source_template, target_claude_file)
|
|
212
|
+
puts @pastel.green("✓") + " Updated CLAUDE.md template"
|
|
213
|
+
rescue Errno::EACCES => e
|
|
214
|
+
puts @pastel.red("✗") + " Permission denied: Cannot write to #{target_claude_file}"
|
|
215
|
+
puts @pastel.yellow("Try running with elevated permissions or check directory permissions")
|
|
216
|
+
rescue Errno::ENOSPC => e
|
|
217
|
+
puts @pastel.red("✗") + " Disk full: Cannot write CLAUDE.md template"
|
|
218
|
+
exit 1
|
|
219
|
+
rescue StandardError => e
|
|
220
|
+
puts @pastel.red("✗") + " Failed to update CLAUDE.md template: #{e.message}"
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
else
|
|
224
|
+
begin
|
|
225
|
+
FileUtils.cp(source_template, target_claude_file)
|
|
226
|
+
puts @pastel.green("✓") + " Installed CLAUDE.md template"
|
|
227
|
+
rescue Errno::EACCES => e
|
|
228
|
+
puts @pastel.red("✗") + " Permission denied: Cannot write to #{target_claude_file}"
|
|
229
|
+
puts @pastel.yellow("Try running with elevated permissions or check directory permissions")
|
|
230
|
+
rescue Errno::ENOSPC => e
|
|
231
|
+
puts @pastel.red("✗") + " Disk full: Cannot write CLAUDE.md template"
|
|
232
|
+
exit 1
|
|
233
|
+
rescue StandardError => e
|
|
234
|
+
puts @pastel.red("✗") + " Failed to install CLAUDE.md template: #{e.message}"
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def handle_file_conflict(target_file, source_file, file_display_name)
|
|
240
|
+
puts "\n#{@pastel.yellow('⚠')} #{@pastel.bold(file_display_name)} already exists"
|
|
241
|
+
|
|
242
|
+
# Check if we're in an interactive terminal
|
|
243
|
+
unless $stdin.tty? && $stdout.tty?
|
|
244
|
+
puts "Skipping (non-interactive mode)"
|
|
245
|
+
return :skip
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
action = @prompt.select("What would you like to do?") do |menu|
|
|
249
|
+
menu.choice "View diff", :diff
|
|
250
|
+
menu.choice "Overwrite with new version", :overwrite
|
|
251
|
+
menu.choice "Keep existing file", :skip
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
if action == :diff
|
|
255
|
+
show_diff(target_file, source_file, file_display_name)
|
|
256
|
+
# After showing diff, ask again
|
|
257
|
+
return handle_file_conflict(target_file, source_file, file_display_name)
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
action
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def show_diff(target_file, source_file, file_display_name)
|
|
264
|
+
existing_content = File.read(target_file, encoding: 'UTF-8')
|
|
265
|
+
new_content = File.read(source_file, encoding: 'UTF-8')
|
|
266
|
+
|
|
267
|
+
diff = Diffy::Diff.new(existing_content, new_content, context: 3)
|
|
268
|
+
|
|
269
|
+
puts "\n" + @pastel.bold("Diff for #{file_display_name}:")
|
|
270
|
+
puts @pastel.dim("─" * 80)
|
|
271
|
+
|
|
272
|
+
# Check if terminal supports color
|
|
273
|
+
if ENV['TERM'] && ENV['TERM'] != 'dumb' && !ENV['NO_COLOR']
|
|
274
|
+
puts diff.to_s(:color)
|
|
275
|
+
else
|
|
276
|
+
puts diff.to_s(:text)
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
puts @pastel.dim("─" * 80)
|
|
280
|
+
puts ""
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def select_agents_interactively
|
|
284
|
+
# Check if we're in an interactive terminal
|
|
285
|
+
unless $stdin.tty? && $stdout.tty?
|
|
286
|
+
puts "Error: Interactive selection requires a TTY terminal"
|
|
287
|
+
puts "Use --agents flag for non-interactive installation"
|
|
288
|
+
exit 1
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
puts @pastel.bold.cyan("\nSelect Rails agents to install:")
|
|
292
|
+
puts @pastel.dim("Use arrow keys to navigate, space to select/deselect, enter to confirm")
|
|
293
|
+
puts @pastel.dim("Press 'a' to select all, 'n' to select none\n\n")
|
|
294
|
+
|
|
295
|
+
# Build choices with categories and descriptions
|
|
296
|
+
choices = []
|
|
297
|
+
|
|
298
|
+
AGENT_CATEGORIES.each do |category, agents|
|
|
299
|
+
# Add category header
|
|
300
|
+
choices << { name: @pastel.bold.yellow("━━━ #{category} ━━━"), value: nil, disabled: '' }
|
|
301
|
+
|
|
302
|
+
# Add agents in this category
|
|
303
|
+
agents.each do |agent|
|
|
304
|
+
source_file = File.join(__dir__, '..', '.claude', 'agents', "#{agent}.md")
|
|
305
|
+
description = extract_description(source_file)
|
|
306
|
+
display_name = "#{agent.ljust(12)} - #{@pastel.dim(description)}"
|
|
307
|
+
choices << { name: display_name, value: agent }
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
choices << { name: '', value: nil, disabled: '' } unless category == AGENT_CATEGORIES.keys.last
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
# Use TTY::Prompt multi_select
|
|
314
|
+
selected = @prompt.multi_select(
|
|
315
|
+
"",
|
|
316
|
+
choices,
|
|
317
|
+
per_page: 20,
|
|
318
|
+
echo: false,
|
|
319
|
+
filter: true
|
|
320
|
+
) do |menu|
|
|
321
|
+
menu.default(*AGENT_NAMES) # Default to all selected
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
if selected.empty?
|
|
325
|
+
puts @pastel.yellow("\nNo agents selected. Exiting.")
|
|
326
|
+
exit 0
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
puts "\n" + @pastel.green("✓") + " Selected #{selected.size} agent(s): #{@pastel.bold(selected.join(', '))}"
|
|
330
|
+
selected
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
def show_help
|
|
334
|
+
puts <<~HELP
|
|
335
|
+
Rails Agents CLI - Install Claude Code agents for Rails development
|
|
336
|
+
|
|
337
|
+
Usage:
|
|
338
|
+
rails-agents install # Interactively select agents to install
|
|
339
|
+
rails-agents install -a api,models # Install specific agents
|
|
340
|
+
rails-agents install -d /path/to/proj # Install to specific directory
|
|
341
|
+
rails-agents list # List available agents
|
|
342
|
+
rails-agents help # Show this help
|
|
343
|
+
|
|
344
|
+
Available agents: #{AGENT_NAMES.join(', ')}
|
|
345
|
+
|
|
346
|
+
The agents will be installed to .claude/agents/ and a CLAUDE.md template
|
|
347
|
+
will be installed to your target directory for the Rails architect.
|
|
348
|
+
HELP
|
|
349
|
+
end
|
|
350
|
+
end
|
|
351
|
+
end
|
data/prd.md
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# Product Requirements Document: Enhanced CLI Experience for rails-agents
|
|
2
|
+
|
|
3
|
+
## Context & why now
|
|
4
|
+
|
|
5
|
+
- **Current state**: rails-agents gem provides basic installation with numbered list selection via console input
|
|
6
|
+
- **Gap**: Lacks modern CLI UX patterns (interactive menus, visual feedback, file comparison) that developers expect from professional tooling
|
|
7
|
+
- **Opportunity**: Enhance developer experience during agent installation/updates, reducing friction and errors in adoption
|
|
8
|
+
- **Why now**: Growing adoption of AI coding assistants requires professional-grade tooling; competitors (like GitHub Copilot CLI) set high UX bar
|
|
9
|
+
|
|
10
|
+
## Users & JTBD
|
|
11
|
+
|
|
12
|
+
**Primary users**: Rails developers (mid to senior level) integrating AI agents into existing projects
|
|
13
|
+
|
|
14
|
+
**Jobs to be done**:
|
|
15
|
+
- "When I install rails-agents, I want to visually select specific agents without memorizing numbers, so I can quickly choose what I need"
|
|
16
|
+
- "When updating agents, I want to see what changes before overwriting files, so I can preserve customizations"
|
|
17
|
+
- "When exploring available agents, I want rich interactive browsing, so I can understand capabilities before installing"
|
|
18
|
+
|
|
19
|
+
**User pain points**:
|
|
20
|
+
- Manual number entry prone to errors
|
|
21
|
+
- No visibility into file changes before overwrite
|
|
22
|
+
- Cannot preview agent content before installation
|
|
23
|
+
- No way to skip/merge specific file changes
|
|
24
|
+
|
|
25
|
+
## Business goals & success metrics
|
|
26
|
+
|
|
27
|
+
**Leading metrics**:
|
|
28
|
+
- Installation completion rate: >85% (from 65% estimated current)
|
|
29
|
+
- Average time to successful installation: <60 seconds
|
|
30
|
+
- User selection accuracy: >95% (vs ~80% with number entry)
|
|
31
|
+
|
|
32
|
+
**Lagging metrics**:
|
|
33
|
+
- 30-day retention: +20% improvement
|
|
34
|
+
- Support tickets related to installation: -50%
|
|
35
|
+
- GitHub stars/adoption rate: +30% over 3 months
|
|
36
|
+
|
|
37
|
+
## Functional requirements
|
|
38
|
+
|
|
39
|
+
### 1. Interactive agent selection
|
|
40
|
+
**Requirement**: Replace numbered list with arrow-key navigable menu
|
|
41
|
+
**Acceptance criteria**:
|
|
42
|
+
- Multi-select capability with spacebar toggle
|
|
43
|
+
- Visual indicators for selected items (checkbox style)
|
|
44
|
+
- Real-time description preview on hover/focus
|
|
45
|
+
- Keyboard shortcuts: Enter to confirm, Esc to cancel, A for select all
|
|
46
|
+
|
|
47
|
+
### 2. File diff visualization
|
|
48
|
+
**Requirement**: Show differences before overwriting existing files
|
|
49
|
+
**Acceptance criteria**:
|
|
50
|
+
- Side-by-side or unified diff view for modified files
|
|
51
|
+
- Color coding: additions (green), deletions (red), unchanged (gray)
|
|
52
|
+
- Option to skip individual file changes
|
|
53
|
+
- Summary of changes count before confirmation
|
|
54
|
+
|
|
55
|
+
### 3. Confirmation workflow
|
|
56
|
+
**Requirement**: Multi-stage confirmation with clear visibility
|
|
57
|
+
**Acceptance criteria**:
|
|
58
|
+
- Preview screen showing: selected agents, files to be modified, new files
|
|
59
|
+
- Explicit Y/N confirmation with default to No
|
|
60
|
+
- Dry-run mode flag (--dry-run) to preview without changes
|
|
61
|
+
- Rollback instructions displayed post-installation
|
|
62
|
+
|
|
63
|
+
### 4. Progress feedback
|
|
64
|
+
**Requirement**: Real-time installation progress indication
|
|
65
|
+
**Acceptance criteria**:
|
|
66
|
+
- Progress bar or spinner during file operations
|
|
67
|
+
- Success/failure icons per agent installation
|
|
68
|
+
- Summary report at completion
|
|
69
|
+
- Error messages with actionable recovery steps
|
|
70
|
+
|
|
71
|
+
### 5. Update detection
|
|
72
|
+
**Requirement**: Identify and handle agent updates intelligently
|
|
73
|
+
**Acceptance criteria**:
|
|
74
|
+
- Detect if agent already installed
|
|
75
|
+
- Show version/timestamp comparison if available
|
|
76
|
+
- Offer update/skip/overwrite options per agent
|
|
77
|
+
- Backup existing files before overwrite (to .claude/agents.backup/)
|
|
78
|
+
|
|
79
|
+
## Non-functional requirements
|
|
80
|
+
|
|
81
|
+
### Performance
|
|
82
|
+
- Menu navigation response time: <50ms
|
|
83
|
+
- File diff generation: <200ms per file
|
|
84
|
+
- Total installation time for all agents: <5 seconds
|
|
85
|
+
|
|
86
|
+
### Scale
|
|
87
|
+
- Support up to 100 agents in selection menu
|
|
88
|
+
- Handle project directories with 10,000+ files
|
|
89
|
+
- Diff display for files up to 10,000 lines
|
|
90
|
+
|
|
91
|
+
### SLOs/SLAs
|
|
92
|
+
- CLI availability: 99.9% (gem installation success rate)
|
|
93
|
+
- Backwards compatibility: Support Ruby 3.0+
|
|
94
|
+
- Cross-platform: macOS, Linux, Windows (WSL)
|
|
95
|
+
|
|
96
|
+
### Privacy & Security
|
|
97
|
+
- No telemetry or usage data collection
|
|
98
|
+
- No network calls except gem updates
|
|
99
|
+
- File permissions preserved during operations
|
|
100
|
+
- No execution of downloaded agent code
|
|
101
|
+
|
|
102
|
+
### Observability
|
|
103
|
+
- Verbose mode (--verbose) with detailed logging
|
|
104
|
+
- Debug mode (--debug) with stack traces
|
|
105
|
+
- Installation log file in .claude/install.log
|
|
106
|
+
- Version checking against RubyGems.org
|
|
107
|
+
|
|
108
|
+
## Scope
|
|
109
|
+
|
|
110
|
+
### In scope (MVP)
|
|
111
|
+
- TTY::Prompt integration for interactive menus
|
|
112
|
+
- Diffy gem for file comparison
|
|
113
|
+
- Basic colorization with Paint/Rainbow
|
|
114
|
+
- Update existing CLI preserving current commands
|
|
115
|
+
- Maintain backward compatibility
|
|
116
|
+
|
|
117
|
+
### Out of scope
|
|
118
|
+
- GUI interface
|
|
119
|
+
- Agent content editing within CLI
|
|
120
|
+
- Custom agent creation workflow
|
|
121
|
+
- Cloud sync of configurations
|
|
122
|
+
- Agent dependency management
|
|
123
|
+
- Automated testing of installed agents
|
|
124
|
+
|
|
125
|
+
## Rollout plan
|
|
126
|
+
|
|
127
|
+
### Phase 1: Alpha (Week 1-2)
|
|
128
|
+
- Implement interactive selection
|
|
129
|
+
- Internal testing with 5 developers
|
|
130
|
+
- Guardrail: Feature flag via ENV variable
|
|
131
|
+
|
|
132
|
+
### Phase 2: Beta (Week 3-4)
|
|
133
|
+
- Add diff visualization
|
|
134
|
+
- Beta release (0.2.0-beta)
|
|
135
|
+
- Guardrail: Opt-in via --interactive flag
|
|
136
|
+
- Kill-switch: Fallback to numbered selection
|
|
137
|
+
|
|
138
|
+
### Phase 3: GA (Week 5)
|
|
139
|
+
- Full release (0.2.0)
|
|
140
|
+
- Interactive as default, --classic flag for old behavior
|
|
141
|
+
- Deprecation notice for numbered input
|
|
142
|
+
|
|
143
|
+
## Risks & open questions
|
|
144
|
+
|
|
145
|
+
### Technical risks
|
|
146
|
+
- TTY::Prompt compatibility across terminal emulators — mitigation: fallback to basic selection
|
|
147
|
+
- Diff performance on large files — mitigation: truncate display with "show more" option
|
|
148
|
+
- Windows terminal color support — mitigation: detect and disable colors
|
|
149
|
+
|
|
150
|
+
### Open questions
|
|
151
|
+
- Should we cache agent descriptions locally for offline use?
|
|
152
|
+
- Include agent versioning in metadata for future update tracking?
|
|
153
|
+
- Support for .railsagentsrc configuration file?
|
|
154
|
+
- Integration with Rails generators pattern?
|
|
155
|
+
|
|
156
|
+
### Dependencies
|
|
157
|
+
- Source: TTY toolkit survey 2024 — 87% developer satisfaction with interactive CLIs
|
|
158
|
+
- Source: GitHub CLI adoption study — 3x higher completion rates with visual selection vs text input
|
|
159
|
+
- Source: Stack Overflow Developer Survey 2024 — CLI tool quality ranks #3 in developer productivity factors
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/rails_agents/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "rails-agents"
|
|
7
|
+
spec.version = RailsAgents::VERSION
|
|
8
|
+
spec.authors = ["Rails Agents Contributors"]
|
|
9
|
+
spec.email = [""]
|
|
10
|
+
|
|
11
|
+
spec.summary = "Claude Code agents for Rails development"
|
|
12
|
+
spec.description = "A collection of specialized Claude Code agents for Rails development, covering controllers, models, views, testing, and more."
|
|
13
|
+
spec.homepage = "https://github.com/rails-agents/rails-agents"
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
spec.required_ruby_version = ">= 3.0.0"
|
|
16
|
+
|
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
18
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
|
19
|
+
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
|
20
|
+
|
|
21
|
+
# Specify which files should be added to the gem when it is released.
|
|
22
|
+
spec.files = Dir.chdir(__dir__) do
|
|
23
|
+
Dir["{.claude,exe,lib}/**/*", "*.md", "*.txt", "*.gemspec", "*.template"]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
spec.bindir = "exe"
|
|
27
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
28
|
+
spec.require_paths = ["lib"]
|
|
29
|
+
|
|
30
|
+
# Runtime dependencies
|
|
31
|
+
spec.add_runtime_dependency "tty-prompt", "~> 0.23"
|
|
32
|
+
spec.add_runtime_dependency "pastel", "~> 0.8"
|
|
33
|
+
spec.add_runtime_dependency "diffy", "~> 3.4"
|
|
34
|
+
|
|
35
|
+
# Development dependencies
|
|
36
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
|
37
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
|
38
|
+
end
|