rails-agent-kit 0.1.0 → 0.2.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 +4 -4
- data/CHANGELOG.md +62 -2
- data/README.md +275 -59
- data/exe/rails-agent-kit +94 -4
- data/lib/rails_agent_kit/client_config.rb +147 -0
- data/lib/rails_agent_kit/routes_inspector.rb +22 -4
- data/lib/rails_agent_kit/ruby_env.rb +174 -0
- data/lib/rails_agent_kit/schema_inspector.rb +125 -26
- data/lib/rails_agent_kit/server.rb +24 -8
- data/lib/rails_agent_kit/skill_installer.rb +105 -19
- data/lib/rails_agent_kit/version.rb +1 -1
- data/lib/rails_agent_kit.rb +2 -0
- data/skills/rails-8-conventions/SKILL.md +3 -2
- metadata +13 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a76627b569e56f98f6e73636bcad9c04907c5b78a8efecec7989a65111ee1045
|
|
4
|
+
data.tar.gz: e8330c54dec1898177123c346e237b6b0cc4265aeebc337208b8bdecc00d2d5e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cfe28fdedbe2391c946c06ce4c0265bc735572b6f61de61546c52d577c346faa5d4bdddf2bd23c97551c1a9b917760e2b0cd5acef6e0a231f71d8205eaff1e39
|
|
7
|
+
data.tar.gz: 8d6978a64aa800220d23748be96bf1ba8ad219673b2d1e06311999df8f04a336270371fa1608bbf882ac5fc54dedcc6c9af794c79a99999fb98df80c0c5784d4
|
data/CHANGELOG.md
CHANGED
|
@@ -2,10 +2,69 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project are documented here. The format follows
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project uses
|
|
5
|
-
[Semantic Versioning](https://semver.org/).
|
|
5
|
+
[Semantic Versioning](https://semver.org/). Each version's section becomes its GitHub release notes; see
|
|
6
|
+
[RELEASING.md](RELEASING.md#writing-the-changelog) for the entry style.
|
|
6
7
|
|
|
7
8
|
## [Unreleased]
|
|
8
9
|
|
|
10
|
+
## [0.2.0] - 2026-10-23
|
|
11
|
+
|
|
12
|
+
rails-agent-kit 0.2.0 keeps large schemas out of your agent's context and makes setup one command:
|
|
13
|
+
`rails_schema` starts with a compact overview and can search and fetch several tables at once,
|
|
14
|
+
`rails-agent-kit init` connects Cursor, Claude Code, VS Code and Codex, the Rails 8 skill now reaches every agent
|
|
15
|
+
that reads `AGENTS.md`, and `rails_routes` boots your app with the Ruby it pins.
|
|
16
|
+
|
|
17
|
+
### Upgrading
|
|
18
|
+
|
|
19
|
+
`rails_schema` with no arguments now returns a compact overview instead of the whole schema. Pass
|
|
20
|
+
`detail: "full"` for the previous output, or `table:` for the tables you need. If you configured clients by hand,
|
|
21
|
+
you can keep that config; `rails-agent-kit init` only adds what's missing.
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- **Connect every agent with one command.** `rails-agent-kit init` writes `.cursor/mcp.json`, `.mcp.json` (Claude
|
|
26
|
+
Code) and `.vscode/mcp.json` with project-relative paths, merges into existing files without touching other
|
|
27
|
+
servers, chooses `bundle exec` when the app's Gemfile has the gem, installs the bundled skills, and prints the
|
|
28
|
+
`~/.codex/config.toml` snippet for Codex. It's idempotent; `--dry-run` previews, `--agent` picks clients and
|
|
29
|
+
`--force` replaces an edited entry. By @afurm. (#5)
|
|
30
|
+
- **Give Codex, Copilot and Gemini CLI the Rails 8 skill.** `install-skills --agent codex` adds the skill to
|
|
31
|
+
`AGENTS.md`, which Codex, Cursor, GitHub Copilot, Windsurf, Zed and others read; `--agent copilot` writes
|
|
32
|
+
`.github/copilot-instructions.md` and `--agent gemini` writes `GEMINI.md`. The text sits between
|
|
33
|
+
`<!-- rails-agent-kit:start -->` and `<!-- rails-agent-kit:end -->` markers, so the rest of your file is never
|
|
34
|
+
touched and re-running updates only that block. `init` does this for Codex. By @afurm. (#7)
|
|
35
|
+
- **`rails_routes` boots the app with the app's own Ruby.** It reads the pinned version from `.ruby-version`,
|
|
36
|
+
`.tool-versions`, `mise.toml` or the Gemfile `ruby` directive and runs the matching mise, rbenv, asdf or chruby
|
|
37
|
+
install directly, so it works even when the editor starts the server without your shell profile. The answer
|
|
38
|
+
reports the Ruby it used as `ruby`. If the pinned Ruby isn't installed, it says which version to install instead
|
|
39
|
+
of returning a boot error. `RAILS_AGENT_KIT_ROUTES_COMMAND` still overrides everything. By @afurm. (#6)
|
|
40
|
+
- **Ask for several tables at once.** `rails_schema` takes `table` as an array or a comma-separated list, so
|
|
41
|
+
related tables come back in one call. Names that don't exist are listed in `missing_tables`. By @afurm.
|
|
42
|
+
- **Find tables and columns by name.** `rails_schema` `search` is a case-insensitive match on table and column
|
|
43
|
+
names, for example `search: "email"`. By @afurm.
|
|
44
|
+
- **Choose how much schema you get.** `rails_schema` `detail` is `overview` or `full`. By @afurm.
|
|
45
|
+
- **A documentation site** at <https://afurm.github.io/rails-agent-kit/>: getting started, a page per tool with
|
|
46
|
+
example output, the CLI reference, supported agents, the agent skill and compatibility. The gemspec links to it
|
|
47
|
+
as `documentation_uri`. By @afurm. (#3)
|
|
48
|
+
|
|
49
|
+
### Changed
|
|
50
|
+
|
|
51
|
+
- **`rails_schema` with no arguments returns a compact overview** instead of the whole schema: each table's
|
|
52
|
+
column count, non-default primary key and foreign key targets. On a generated 300-table schema the default
|
|
53
|
+
answer drops from about 1.2 MB to 23 KB. By @afurm.
|
|
54
|
+
- **Large answers stay bounded.** A `rails_schema` answer over 60 KB is replaced by the overview with
|
|
55
|
+
`truncated: true` and a note on how to narrow the request. By @afurm.
|
|
56
|
+
- **Smaller responses.** Tools return compact JSON instead of pretty-printed JSON, which roughly halves their
|
|
57
|
+
size, and the server instructions describe the overview, then `table:` / `search:` flow. By @afurm.
|
|
58
|
+
- **Tested on Ruby 4.0.** CI runs Ruby 3.2, 3.3, 3.4 and 4.0, plus `ruby-head` (allowed to fail). By @afurm.
|
|
59
|
+
- **Project docs and automated releases.** A rewritten README; CONTRIBUTING, CODE_OF_CONDUCT (Contributor
|
|
60
|
+
Covenant 2.1), SECURITY, RELEASING and ROADMAP; issue and PR templates. Releases are published from a tag with
|
|
61
|
+
RubyGems trusted publishing. By @afurm. (#1)
|
|
62
|
+
|
|
63
|
+
### Known limitations
|
|
64
|
+
|
|
65
|
+
- `db/structure.sql` parsing is best effort: foreign keys and constraints aren't extracted yet.
|
|
66
|
+
- Multi-database apps: only the primary database's schema is read.
|
|
67
|
+
|
|
9
68
|
## [0.1.0] - 2026-10-17
|
|
10
69
|
|
|
11
70
|
### Added
|
|
@@ -20,5 +79,6 @@ All notable changes to this project are documented here. The format follows
|
|
|
20
79
|
- `rails-agent-kit install-skills [--agent cursor|claude] [--force]`, which installs the bundled skills into an app.
|
|
21
80
|
- CI on Ruby 3.2, 3.3 and 3.4.
|
|
22
81
|
|
|
23
|
-
[Unreleased]: https://github.com/afurm/rails-agent-kit/compare/v0.
|
|
82
|
+
[Unreleased]: https://github.com/afurm/rails-agent-kit/compare/v0.2.0...HEAD
|
|
83
|
+
[0.2.0]: https://github.com/afurm/rails-agent-kit/compare/v0.1.0...v0.2.0
|
|
24
84
|
[0.1.0]: https://github.com/afurm/rails-agent-kit/releases/tag/v0.1.0
|
data/README.md
CHANGED
|
@@ -1,66 +1,192 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
(Cursor, Claude Code, …) **ground truth about your Rails app**: its database schema and its routes.
|
|
3
|
+
<h1>rails-agent-kit</h1>
|
|
5
4
|
|
|
6
|
-
>
|
|
5
|
+
<strong>Ground truth about your Rails app, for coding agents</strong>
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
<p>A read-only MCP server that gives Cursor, Claude Code, Codex and other MCP clients your app's real schema and
|
|
8
|
+
routes, plus a Rails 8 skill that tells the agent to check them before it writes code.</p>
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
is the helper `post_comments_path` or `comments_path`?* Wrong guesses become broken code and wasted review cycles.
|
|
12
|
-
With rails-agent-kit the agent just asks:
|
|
10
|
+
[Documentation](https://afurm.github.io/rails-agent-kit/) · [Install](#installation) · [Connect your agent](#connect-your-agent) · [Tools](#tools) · [Changelog](CHANGELOG.md) · [Roadmap](ROADMAP.md)
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
[](https://rubygems.org/gems/rails-agent-kit)
|
|
13
|
+
[](https://rubygems.org/gems/rails-agent-kit)
|
|
14
|
+
[](https://github.com/afurm/rails-agent-kit/actions/workflows/ci.yml)
|
|
15
|
+
[](#compatibility)
|
|
16
|
+
[](LICENSE)
|
|
17
|
+
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
> [!NOTE]
|
|
21
|
+
> rails-agent-kit is early (v0.2.0), and the API may change before 1.0. Using it? Tell us how it went in
|
|
22
|
+
> [Discussions](https://github.com/afurm/rails-agent-kit/discussions) or [open an issue](https://github.com/afurm/rails-agent-kit/issues).
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Look it up instead of guessing
|
|
27
|
+
|
|
28
|
+
Agents writing Rails code guess all the time. *Is it `user.full_name` or `user.name`? Is the column nullable? Is
|
|
29
|
+
the helper `post_comments_path` or `comments_path`?* Each wrong guess is broken code and another review round.
|
|
30
|
+
rails-agent-kit lets the agent ask your app.
|
|
31
|
+
|
|
32
|
+
* **Schema:** tables, columns, indexes and foreign keys from `db/schema.rb`, parsed statically. It never boots
|
|
33
|
+
the app or connects to a database. `db/structure.sql` gets a best-effort parse.
|
|
34
|
+
* **Schema overview and search:** a compact overview by default, several tables
|
|
35
|
+
in one call, and a name search across tables and columns, so large schemas don't flood the agent's context.
|
|
36
|
+
* **Routes:** every route with its name, verb, path, `controller#action` and source line, from your app's own
|
|
37
|
+
`bin/rails routes --expanded`. Engines and route concerns resolve exactly as Rails sees them.
|
|
38
|
+
* **The app's own Ruby:** routes boot with the Ruby your app pins in `.ruby-version`,
|
|
39
|
+
`.tool-versions` or `mise.toml`, found through mise, rbenv, asdf or chruby.
|
|
40
|
+
* **Routes without booting:** point it at a saved routes dump, or run the routes command in Docker.
|
|
41
|
+
* **One-command setup:** `rails-agent-kit init` connects Cursor, Claude Code, VS Code
|
|
42
|
+
and Codex, and installs the skill.
|
|
43
|
+
* **Rails 8 conventions skill:** an Agent Skill for Cursor and Claude Code, or a managed block in `AGENTS.md`
|
|
44
|
+
(Codex and others), `.github/copilot-instructions.md` or `GEMINI.md`, installed with `rails-agent-kit install-skills`.
|
|
45
|
+
* **Read-only and local:** a stdio server your client starts. It doesn't listen on a network port.
|
|
46
|
+
|
|
47
|
+
## See what your agent sees
|
|
48
|
+
|
|
49
|
+
The agent calls the tools itself. These are real answers for the small blog app in
|
|
50
|
+
[`test/fixtures/blog_app`](test/fixtures/blog_app), pretty-printed (the server sends compact JSON).
|
|
51
|
+
|
|
52
|
+
```js
|
|
53
|
+
// rails_schema {} (the overview; trimmed)
|
|
54
|
+
{
|
|
55
|
+
"source": "db/schema.rb",
|
|
56
|
+
"table_count": 4,
|
|
57
|
+
"tables": [
|
|
58
|
+
{ "name": "comments", "columns": 6, "references": ["posts", "users"] },
|
|
59
|
+
{ "name": "posts", "columns": 10, "references": ["users"] },
|
|
60
|
+
{ "name": "posts_tags", "columns": 2, "primary_key": false },
|
|
61
|
+
{ "name": "users", "columns": 7 }
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
```
|
|
18
65
|
|
|
19
|
-
|
|
66
|
+
```js
|
|
67
|
+
// rails_schema { "search": "email" } (trimmed)
|
|
68
|
+
{ "match_count": 1, "matches": [{ "table": "users", "columns": [{ "name": "email", "type": "string", "null": false }] }] }
|
|
69
|
+
```
|
|
20
70
|
|
|
21
|
-
|
|
71
|
+
```js
|
|
72
|
+
// rails_schema { "table": "comments" } (trimmed)
|
|
73
|
+
{
|
|
74
|
+
"tables": [{
|
|
75
|
+
"name": "comments",
|
|
76
|
+
"columns": [
|
|
77
|
+
{ "name": "post_id", "type": "bigint", "null": false },
|
|
78
|
+
{ "name": "body", "type": "text", "null": false }
|
|
79
|
+
],
|
|
80
|
+
"indexes": [{ "name": "index_comments_on_post_id", "columns": ["post_id"], "unique": false }]
|
|
81
|
+
}],
|
|
82
|
+
"foreign_keys": [{ "from_table": "comments", "to_table": "users", "column": "user_id", "on_delete": "cascade" }]
|
|
83
|
+
}
|
|
84
|
+
```
|
|
22
85
|
|
|
23
|
-
|
|
86
|
+
```js
|
|
87
|
+
// rails_routes { "filter": "comments" } (trimmed)
|
|
88
|
+
{
|
|
89
|
+
"total": 7,
|
|
90
|
+
"count": 2,
|
|
91
|
+
"routes": [
|
|
92
|
+
{ "name": "post_comments", "verb": "POST", "path": "/posts/:post_id/comments(.:format)",
|
|
93
|
+
"controller_action": "comments#create", "source_location": "config/routes.rb:3" }
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Installation
|
|
24
99
|
|
|
25
100
|
```sh
|
|
26
|
-
|
|
27
|
-
cd rails-agent-kit
|
|
28
|
-
bundle install
|
|
29
|
-
# try it against an app:
|
|
30
|
-
BUNDLE_GEMFILE=$PWD/Gemfile bundle exec rails-agent-kit --root /path/to/your/rails/app
|
|
101
|
+
gem install rails-agent-kit
|
|
31
102
|
```
|
|
32
103
|
|
|
33
|
-
|
|
104
|
+
or, inside your Rails app:
|
|
34
105
|
|
|
35
|
-
|
|
106
|
+
```sh
|
|
107
|
+
bundle add rails-agent-kit --group development
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Requires Ruby 3.2+.
|
|
36
111
|
|
|
37
|
-
##
|
|
112
|
+
## Connect your agent
|
|
38
113
|
|
|
114
|
+
### One command
|
|
115
|
+
|
|
116
|
+
From your app's root:
|
|
117
|
+
|
|
118
|
+
```sh
|
|
119
|
+
bundle add rails-agent-kit --group development
|
|
120
|
+
bundle exec rails-agent-kit init
|
|
39
121
|
```
|
|
40
|
-
rails-agent-kit [--root PATH] [--routes-file FILE]
|
|
41
122
|
|
|
42
|
-
|
|
43
|
-
|
|
123
|
+
`init` writes the MCP config for Cursor (`.cursor/mcp.json`), Claude Code (`.mcp.json`) and VS Code
|
|
124
|
+
(`.vscode/mcp.json`), using project-relative paths so you can commit the files for your whole team. It adds
|
|
125
|
+
rails-agent-kit next to the servers you already have, picks `bundle exec` or the installed gem for you, installs the
|
|
126
|
+
Rails 8 skill for Cursor and Claude Code, adds it to `AGENTS.md` for Codex, and prints the snippet for Codex's
|
|
127
|
+
global `~/.codex/config.toml`.
|
|
128
|
+
Running it again changes nothing. Preview with `--dry-run`, or pick clients with `--agent cursor,claude`.
|
|
129
|
+
|
|
130
|
+
### By hand
|
|
131
|
+
|
|
132
|
+
Replace `/path/to/your/rails/app` with the absolute path to your app.
|
|
133
|
+
|
|
134
|
+
<details open>
|
|
135
|
+
<summary><b>Cursor</b></summary>
|
|
136
|
+
|
|
137
|
+
`.cursor/mcp.json` in your app (or `~/.cursor/mcp.json`):
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
{
|
|
141
|
+
"mcpServers": {
|
|
142
|
+
"rails-agent-kit": {
|
|
143
|
+
"command": "rails-agent-kit",
|
|
144
|
+
"args": ["--root", "/path/to/your/rails/app"]
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
44
148
|
```
|
|
45
149
|
|
|
46
|
-
|
|
150
|
+
</details>
|
|
151
|
+
|
|
152
|
+
<details open>
|
|
153
|
+
<summary><b>Claude Code</b></summary>
|
|
154
|
+
|
|
155
|
+
```sh
|
|
156
|
+
claude mcp add rails-agent-kit -- rails-agent-kit --root /path/to/your/rails/app
|
|
157
|
+
```
|
|
47
158
|
|
|
48
|
-
|
|
49
|
-
- `RAILS_AGENT_KIT_ROUTES_COMMAND` — override the routes command, e.g. `"bundle exec rails routes --expanded"`
|
|
50
|
-
or `"docker compose exec -T web bin/rails routes --expanded"`. Runs in `--root`.
|
|
159
|
+
</details>
|
|
51
160
|
|
|
52
|
-
|
|
161
|
+
<details open>
|
|
162
|
+
<summary><b>Codex</b></summary>
|
|
53
163
|
|
|
54
164
|
```sh
|
|
55
|
-
|
|
56
|
-
|
|
165
|
+
codex mcp add rails-agent-kit -- rails-agent-kit --root /path/to/your/rails/app
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
or in `~/.codex/config.toml`:
|
|
169
|
+
|
|
170
|
+
```toml
|
|
171
|
+
[mcp_servers.rails-agent-kit]
|
|
172
|
+
command = "rails-agent-kit"
|
|
173
|
+
args = ["--root", "/path/to/your/rails/app"]
|
|
57
174
|
```
|
|
58
175
|
|
|
59
|
-
|
|
176
|
+
</details>
|
|
60
177
|
|
|
61
|
-
|
|
178
|
+
<details>
|
|
179
|
+
<summary><b>Claude Desktop and other MCP clients</b></summary>
|
|
62
180
|
|
|
63
|
-
|
|
181
|
+
Any client that launches stdio MCP servers works. Claude Desktop's `claude_desktop_config.json` takes the same
|
|
182
|
+
`mcpServers` block as Cursor above.
|
|
183
|
+
|
|
184
|
+
</details>
|
|
185
|
+
|
|
186
|
+
<details>
|
|
187
|
+
<summary><b>Installed with <code>bundle add</code> instead of <code>gem install</code>?</b></summary>
|
|
188
|
+
|
|
189
|
+
Run it through the app's bundle:
|
|
64
190
|
|
|
65
191
|
```json
|
|
66
192
|
{
|
|
@@ -68,51 +194,141 @@ Replace the paths with absolute paths on your machine.
|
|
|
68
194
|
"rails-agent-kit": {
|
|
69
195
|
"command": "bundle",
|
|
70
196
|
"args": ["exec", "rails-agent-kit", "--root", "/path/to/your/rails/app"],
|
|
71
|
-
"env": { "BUNDLE_GEMFILE": "/path/to/rails
|
|
197
|
+
"env": { "BUNDLE_GEMFILE": "/path/to/your/rails/app/Gemfile" }
|
|
72
198
|
}
|
|
73
199
|
}
|
|
74
200
|
}
|
|
75
201
|
```
|
|
76
202
|
|
|
77
|
-
**Claude Code**:
|
|
78
|
-
|
|
79
203
|
```sh
|
|
80
|
-
claude mcp add rails-agent-kit \
|
|
81
|
-
-e BUNDLE_GEMFILE=/path/to/rails-agent-kit/Gemfile \
|
|
204
|
+
claude mcp add rails-agent-kit -e BUNDLE_GEMFILE=/path/to/your/rails/app/Gemfile \
|
|
82
205
|
-- bundle exec rails-agent-kit --root /path/to/your/rails/app
|
|
83
206
|
```
|
|
84
207
|
|
|
85
|
-
|
|
208
|
+
</details>
|
|
86
209
|
|
|
87
|
-
|
|
88
|
-
not rails-agent-kit's.
|
|
210
|
+
To also add the Rails 8 conventions skill (optional), see [Agent skill](#agent-skill-rails-8-conventions):
|
|
89
211
|
|
|
90
|
-
|
|
212
|
+
```sh
|
|
213
|
+
rails-agent-kit install-skills --root /path/to/your/rails/app # Cursor
|
|
214
|
+
rails-agent-kit install-skills --root /path/to/your/rails/app --agent claude # Claude Code
|
|
215
|
+
rails-agent-kit install-skills --root /path/to/your/rails/app --agent codex # AGENTS.md
|
|
216
|
+
rails-agent-kit install-skills --root /path/to/your/rails/app --agent copilot # GitHub Copilot
|
|
217
|
+
rails-agent-kit install-skills --root /path/to/your/rails/app --agent gemini # Gemini CLI
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Tools
|
|
221
|
+
|
|
222
|
+
Both tools are read-only and return JSON.
|
|
223
|
+
|
|
224
|
+
| Tool | Parameters | Returns | Boots the app? |
|
|
225
|
+
| --- | --- | --- | --- |
|
|
226
|
+
| `rails_schema` | All optional. `table`: one exact name, an array or a comma-separated list. `search`: case-insensitive part of a table or column name. `detail`: `overview` or `full` | With no arguments, a compact overview (each table's column count, non-default primary key and foreign key targets). With `table`, full columns (type, null, default, limit, …), indexes and foreign keys. With `search`, the matching tables and columns | **No.** Parses `db/schema.rb` statically, with a best-effort fallback to `db/structure.sql` |
|
|
227
|
+
| `rails_routes` | `filter` (optional, case-insensitive substring of name, path, verb or `controller#action`) | Each route's name, verb, path, `controller#action` and source location | **Yes.** Runs `bin/rails routes --expanded`. If that fails or times out, it explains why and returns the raw `config/routes.rb` |
|
|
228
|
+
|
|
229
|
+
Responses are compact (single-line) JSON. Agents usually call `rails_schema` with no arguments first, so that
|
|
230
|
+
answer stays small even on large apps: a generated 300-table schema gives about 23 KB, where the full dump is
|
|
231
|
+
over 1 MB. Any `rails_schema` answer over 60 KB comes back as the overview plus a note on how to narrow the
|
|
232
|
+
request (`truncated: true`).
|
|
91
233
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
234
|
+
## CLI reference
|
|
235
|
+
|
|
236
|
+
```text
|
|
237
|
+
rails-agent-kit [--root PATH] [--routes-file FILE] # start the MCP server on stdio
|
|
238
|
+
rails-agent-kit init [--root PATH] [--agent LIST] [--dry-run] [--force] [--no-skills]
|
|
239
|
+
rails-agent-kit install-skills [--root PATH] [--agent AGENT] [--force] [SKILL...]
|
|
240
|
+
rails-agent-kit --version
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
| Option / env var | Purpose |
|
|
244
|
+
| --- | --- |
|
|
245
|
+
| `--root PATH` | Rails app root (default: the current directory) |
|
|
246
|
+
| `--routes-file FILE` | Use a saved `bin/rails routes --expanded` dump instead of booting the app |
|
|
247
|
+
| `RAILS_AGENT_KIT_ROUTES_TIMEOUT` | Seconds to wait for `bin/rails routes` (default `60`) |
|
|
248
|
+
| `RAILS_AGENT_KIT_ROUTES_COMMAND` | Override the routes command, e.g. `"docker compose exec -T web bin/rails routes --expanded"`. Runs in `--root` |
|
|
249
|
+
|
|
250
|
+
If your app can't boot locally (it needs a DB, secrets or Docker), dump the routes once and point the server at
|
|
251
|
+
the file:
|
|
98
252
|
|
|
99
253
|
```sh
|
|
100
|
-
rails
|
|
101
|
-
rails-agent-kit
|
|
254
|
+
bin/rails routes --expanded > tmp/routes.txt
|
|
255
|
+
rails-agent-kit --root . --routes-file tmp/routes.txt
|
|
102
256
|
```
|
|
103
257
|
|
|
104
|
-
|
|
258
|
+
## How it works
|
|
259
|
+
|
|
260
|
+
- **Transport:** a stdio MCP server built on the official [`mcp` Ruby SDK](https://github.com/modelcontextprotocol/ruby-sdk).
|
|
261
|
+
Your agent client starts it and talks JSON-RPC over stdin/stdout. Nothing listens on a network port.
|
|
262
|
+
- **Schema:** read from `db/schema.rb` with a static parser. It never loads your app or connects to a database,
|
|
263
|
+
so it's fast and safe on any checkout. Apps that use `db/structure.sql` get a best-effort SQL parse.
|
|
264
|
+
- **Routes:** generated by your app itself (`bin/rails routes --expanded`), so engines and route concerns
|
|
265
|
+
resolve exactly as Rails sees them. It runs with the app's pinned Ruby and with Bundler's environment cleared,
|
|
266
|
+
so the app uses its own Ruby and Gemfile.
|
|
267
|
+
- **Skill:** a Markdown [Agent Skill](https://cursor.com/docs/skills) copied into your app. It tells the agent to
|
|
268
|
+
call these tools before it writes model attributes, queries, URL helpers or migrations.
|
|
269
|
+
|
|
270
|
+
## Agent skill: Rails 8 conventions
|
|
271
|
+
|
|
272
|
+
[`skills/rails-8-conventions/SKILL.md`](skills/rails-8-conventions/SKILL.md) makes the agent check `rails_schema`,
|
|
273
|
+
`rails_routes` and `Gemfile.lock` before it edits code. It then follows the Rails 8 defaults: `params.expect`, the
|
|
274
|
+
built-in authentication generator, `rate_limit`, Solid Queue/Cache/Cable, Hotwire with importmap/Propshaft,
|
|
275
|
+
reversible migrations, and tests in the framework the app already uses. It also covers a paired Next.js
|
|
276
|
+
frontend.
|
|
277
|
+
|
|
278
|
+
There's one source for every agent. `install-skills` installs it where each agent looks:
|
|
105
279
|
|
|
106
|
-
|
|
280
|
+
| `--agent` | Writes | Read by |
|
|
281
|
+
| --- | --- | --- |
|
|
282
|
+
| `cursor` (default) | `.cursor/skills/<name>/SKILL.md` | Cursor |
|
|
283
|
+
| `claude` | `.claude/skills/<name>/SKILL.md` | Claude Code (and Cursor, Copilot) |
|
|
284
|
+
| `codex` | A managed block in `AGENTS.md` | Codex, Cursor, GitHub Copilot, Windsurf, Zed and other `AGENTS.md` readers |
|
|
285
|
+
| `copilot` | A managed block in `.github/copilot-instructions.md` | GitHub Copilot |
|
|
286
|
+
| `gemini` | A managed block in `GEMINI.md` | Gemini CLI |
|
|
287
|
+
|
|
288
|
+
Running it again is safe. It never overwrites a skill file you've edited unless you pass `--force`. In
|
|
289
|
+
`AGENTS.md`, `copilot-instructions.md` and `GEMINI.md` it only touches the text between
|
|
290
|
+
`<!-- rails-agent-kit:start -->` and `<!-- rails-agent-kit:end -->`, appending the block if it isn't there yet,
|
|
291
|
+
so the rest of your file stays yours.
|
|
292
|
+
|
|
293
|
+
## Compatibility
|
|
294
|
+
|
|
295
|
+
| | Versions | Status |
|
|
296
|
+
| --- | --- | --- |
|
|
297
|
+
| Ruby | 3.2, 3.3, 3.4, 4.0 | Tested in CI (`ruby-head` runs too, allowed to fail) |
|
|
298
|
+
| Rails (`db/schema.rb` format) | 8.0 | Covered by test fixtures |
|
|
299
|
+
| Rails | 7.2, 8.1 | Expected to work, but not yet covered by CI ([planned](ROADMAP.md)) |
|
|
300
|
+
| MCP clients | Cursor, Claude Code, Codex, Claude Desktop, or any stdio MCP client | Configuration shown above |
|
|
301
|
+
|
|
302
|
+
The bundled skill targets Rails 8 conventions. On Rails 7.x, the tools work the same, but some skill advice
|
|
303
|
+
(e.g. `params.expect` and Solid Queue defaults) won't apply.
|
|
304
|
+
|
|
305
|
+
## Documentation
|
|
306
|
+
|
|
307
|
+
The full guide lives at **[afurm.github.io/rails-agent-kit](https://afurm.github.io/rails-agent-kit/)**: getting
|
|
308
|
+
started, a page per tool with example output, the CLI reference, the agent skill and compatibility.
|
|
309
|
+
|
|
310
|
+
[Connect your agent](#connect-your-agent) · [Tools](#tools) · [CLI reference](#cli-reference) ·
|
|
311
|
+
[Changelog](CHANGELOG.md) · [Roadmap](ROADMAP.md) · [Releasing](RELEASING.md) · [Security](SECURITY.md)
|
|
312
|
+
|
|
313
|
+
## Community
|
|
314
|
+
|
|
315
|
+
* **Questions and ideas:** [GitHub Discussions](https://github.com/afurm/rails-agent-kit/discussions)
|
|
316
|
+
* **Bugs:** [open an issue](https://github.com/afurm/rails-agent-kit/issues/new/choose) with your Ruby, Rails
|
|
317
|
+
and MCP client versions
|
|
318
|
+
* **Vulnerabilities:** report them privately, as described in [SECURITY.md](SECURITY.md)
|
|
319
|
+
|
|
320
|
+
Everyone taking part follows the [Code of Conduct](CODE_OF_CONDUCT.md).
|
|
321
|
+
|
|
322
|
+
## Contributing
|
|
323
|
+
|
|
324
|
+
Pull requests are welcome. Read [CONTRIBUTING.md](CONTRIBUTING.md), then:
|
|
107
325
|
|
|
108
326
|
```sh
|
|
327
|
+
gh repo fork afurm/rails-agent-kit --clone && cd rails-agent-kit
|
|
109
328
|
bundle install
|
|
110
329
|
bundle exec rake test
|
|
111
330
|
```
|
|
112
331
|
|
|
113
|
-
Tests use small fixture apps in `test/fixtures` (a `schema.rb`, a `structure.sql`, captured `rails routes`
|
|
114
|
-
output and a stand-in `bin/rails`), plus an end-to-end test that drives `exe/rails-agent-kit` over stdio JSON-RPC.
|
|
115
|
-
|
|
116
332
|
## License
|
|
117
333
|
|
|
118
|
-
MIT
|
|
334
|
+
[MIT](LICENSE) © Andrii Furmanets
|
data/exe/rails-agent-kit
CHANGED
|
@@ -4,14 +4,99 @@
|
|
|
4
4
|
require "optparse"
|
|
5
5
|
require_relative "../lib/rails_agent_kit"
|
|
6
6
|
|
|
7
|
+
if ARGV.first == "init"
|
|
8
|
+
ARGV.shift
|
|
9
|
+
opts = { root: Dir.pwd, agent: "all", force: false, dry_run: false, skills: true }
|
|
10
|
+
init_parser = OptionParser.new do |o|
|
|
11
|
+
o.banner = "Usage: rails-agent-kit init [--root PATH] [--agent LIST] [--dry-run] [--force] [--no-skills]\n\n" \
|
|
12
|
+
"Writes the MCP config that starts rails-agent-kit for each agent and installs the bundled skills\n" \
|
|
13
|
+
"(skill files for Cursor and Claude Code, a managed AGENTS.md block for Codex)."
|
|
14
|
+
o.on("--root PATH", "Rails app root (default: current directory)") { |v| opts[:root] = v }
|
|
15
|
+
o.on("--agent LIST", "Comma-separated: cursor, claude, vscode, codex, or all (default: all)") { |v| opts[:agent] = v }
|
|
16
|
+
o.on("--dry-run", "Show what would change without writing anything") { opts[:dry_run] = true }
|
|
17
|
+
o.on("--force", "Replace a rails-agent-kit entry or skill you have edited") { opts[:force] = true }
|
|
18
|
+
o.on("--no-skills", "Only write the MCP config (no skills, no AGENTS.md block)") { opts[:skills] = false }
|
|
19
|
+
o.on("-h", "--help", "Show this help") do
|
|
20
|
+
puts o
|
|
21
|
+
exit
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
begin
|
|
26
|
+
init_parser.parse!(ARGV)
|
|
27
|
+
raise RailsAgentKit::Error, "unexpected argument #{ARGV.first.inspect}" unless ARGV.empty?
|
|
28
|
+
|
|
29
|
+
agents = RailsAgentKit::ClientConfig.parse_agents(opts[:agent])
|
|
30
|
+
root = File.expand_path(opts[:root])
|
|
31
|
+
raise RailsAgentKit::Error, "--root #{root} is not a directory" unless File.directory?(root)
|
|
32
|
+
rescue OptionParser::ParseError, RailsAgentKit::Error => e
|
|
33
|
+
warn "rails-agent-kit: #{e.message}"
|
|
34
|
+
exit 64
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
config = RailsAgentKit::ClientConfig.new(root, force: opts[:force], dry_run: opts[:dry_run])
|
|
38
|
+
relative = ->(path) { path.start_with?("#{root}/") ? path.delete_prefix("#{root}/") : path }
|
|
39
|
+
planned = { created: "would create", added: "would add", updated: "would update" }
|
|
40
|
+
label = ->(status) { ((opts[:dry_run] && planned[status]) || status.to_s).ljust(12) }
|
|
41
|
+
|
|
42
|
+
puts "rails-agent-kit init#{' (dry run, nothing written)' if opts[:dry_run]}"
|
|
43
|
+
puts "Command: #{config.bundled? ? 'bundle exec rails-agent-kit (found in the Gemfile)' : 'rails-agent-kit (installed gem)'}"
|
|
44
|
+
puts
|
|
45
|
+
|
|
46
|
+
results = config.write(agents)
|
|
47
|
+
results.reject { |r| r.status == :print }.each do |r|
|
|
48
|
+
note =
|
|
49
|
+
case r.status
|
|
50
|
+
when :skipped then " (has a different rails-agent-kit entry; use --force to replace it)"
|
|
51
|
+
when :error then " (#{r.message})"
|
|
52
|
+
else ""
|
|
53
|
+
end
|
|
54
|
+
puts "#{label.call(r.status)} #{relative.call(r.path)}#{note}"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
skill_note = lambda do |r|
|
|
58
|
+
if r.message then " (#{r.message})"
|
|
59
|
+
elsif r.status == :skipped then " (differs from bundled copy; use --force to overwrite)"
|
|
60
|
+
else ""
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
if opts[:skills]
|
|
65
|
+
(agents & RailsAgentKit::SkillInstaller::TARGETS.keys).each do |agent|
|
|
66
|
+
installer = RailsAgentKit::SkillInstaller.new(root, agent: agent, force: opts[:force])
|
|
67
|
+
skill_results = opts[:dry_run] ? installer.plan : installer.install
|
|
68
|
+
skill_results.each do |r|
|
|
69
|
+
puts "#{label.call(r.status)} #{relative.call(r.path)}#{skill_note.call(r)}"
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
if (codex = results.find { |r| r.status == :print })
|
|
75
|
+
puts
|
|
76
|
+
puts "Codex reads MCP servers from the global ~/.codex/config.toml, so add this yourself:"
|
|
77
|
+
puts
|
|
78
|
+
puts codex.snippet
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
puts
|
|
82
|
+
if results.any? { |r| r.status == :error }
|
|
83
|
+
warn "rails-agent-kit: some files could not be updated; see above"
|
|
84
|
+
exit 65
|
|
85
|
+
end
|
|
86
|
+
puts "Done. Restart your agent (or reload its MCP servers) to pick up rails-agent-kit." unless opts[:dry_run]
|
|
87
|
+
exit 0
|
|
88
|
+
end
|
|
89
|
+
|
|
7
90
|
if ARGV.first == "install-skills"
|
|
8
91
|
ARGV.shift
|
|
9
92
|
opts = { root: Dir.pwd, agent: "cursor", force: false }
|
|
10
93
|
skills_parser = OptionParser.new do |o|
|
|
11
|
-
o.banner = "Usage: rails-agent-kit install-skills [--root PATH] [--agent
|
|
12
|
-
"
|
|
94
|
+
o.banner = "Usage: rails-agent-kit install-skills [--root PATH] [--agent AGENT] [--force] [SKILL...]\n\n" \
|
|
95
|
+
"Installs the bundled agent skills into the app: as skill files for Cursor (.cursor/skills/) and\n" \
|
|
96
|
+
"Claude Code (.claude/skills/), or as a managed block in AGENTS.md (codex),\n" \
|
|
97
|
+
".github/copilot-instructions.md (copilot) or GEMINI.md (gemini)."
|
|
13
98
|
o.on("--root PATH", "Rails app root (default: current directory)") { |v| opts[:root] = v }
|
|
14
|
-
o.on("--agent AGENT", "cursor (default) or
|
|
99
|
+
o.on("--agent AGENT", "cursor (default), claude, codex, copilot or gemini") { |v| opts[:agent] = v }
|
|
15
100
|
o.on("--force", "Overwrite skills you have edited locally") { opts[:force] = true }
|
|
16
101
|
o.on("-h", "--help", "Show this help") do
|
|
17
102
|
puts o
|
|
@@ -28,7 +113,11 @@ if ARGV.first == "install-skills"
|
|
|
28
113
|
exit 64
|
|
29
114
|
end
|
|
30
115
|
results.each do |r|
|
|
31
|
-
note =
|
|
116
|
+
note =
|
|
117
|
+
if r.message then " (#{r.message})"
|
|
118
|
+
elsif r.status == :skipped then " (differs from bundled copy; use --force to overwrite)"
|
|
119
|
+
else ""
|
|
120
|
+
end
|
|
32
121
|
puts "#{r.status.to_s.ljust(9)} #{r.path}#{note}"
|
|
33
122
|
end
|
|
34
123
|
exit 0
|
|
@@ -37,6 +126,7 @@ end
|
|
|
37
126
|
options = { root: Dir.pwd, routes_file: nil }
|
|
38
127
|
parser = OptionParser.new do |o|
|
|
39
128
|
o.banner = "Usage: rails-agent-kit [--root PATH] [--routes-file FILE]\n" \
|
|
129
|
+
" rails-agent-kit init --help\n" \
|
|
40
130
|
" rails-agent-kit install-skills --help\n\n" \
|
|
41
131
|
"Starts an MCP server on stdio exposing the Rails app's schema and routes."
|
|
42
132
|
o.on("--root PATH", "Rails app root (default: current directory)") { |v| options[:root] = v }
|