rubyn-code 0.4.0 → 0.5.1
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 +247 -9
- data/lib/rubyn_code/agent/conversation.rb +2 -1
- data/lib/rubyn_code/agent/dynamic_tool_schema.rb +2 -1
- data/lib/rubyn_code/agent/llm_caller.rb +4 -2
- data/lib/rubyn_code/agent/loop.rb +7 -3
- data/lib/rubyn_code/agent/response_modes.rb +2 -1
- data/lib/rubyn_code/agent/system_prompt_builder.rb +39 -0
- data/lib/rubyn_code/agent/tool_processor.rb +4 -2
- data/lib/rubyn_code/cli/app.rb +87 -13
- data/lib/rubyn_code/cli/commands/install_skills.rb +44 -0
- data/lib/rubyn_code/cli/commands/list_skills.rb +149 -0
- data/lib/rubyn_code/cli/commands/megaplan.rb +50 -0
- data/lib/rubyn_code/cli/commands/provider.rb +2 -1
- data/lib/rubyn_code/cli/commands/remove_skills.rb +35 -0
- data/lib/rubyn_code/cli/commands/skill.rb +4 -2
- data/lib/rubyn_code/cli/commands/skills.rb +104 -0
- data/lib/rubyn_code/cli/repl.rb +11 -1
- data/lib/rubyn_code/cli/repl_commands.rb +3 -1
- data/lib/rubyn_code/cli/repl_setup.rb +38 -1
- data/lib/rubyn_code/cli/setup.rb +13 -0
- data/lib/rubyn_code/config/defaults.rb +2 -0
- data/lib/rubyn_code/config/settings.rb +5 -2
- data/lib/rubyn_code/context/context_budget.rb +2 -1
- data/lib/rubyn_code/context/manager.rb +3 -3
- data/lib/rubyn_code/ide/handlers/plan_interview_answer_handler.rb +65 -0
- data/lib/rubyn_code/ide/handlers/plan_interview_cancel_handler.rb +22 -0
- data/lib/rubyn_code/ide/handlers/plan_interview_start_handler.rb +53 -0
- data/lib/rubyn_code/ide/handlers/plan_propose_handler.rb +41 -0
- data/lib/rubyn_code/ide/handlers/prompt_handler.rb +6 -3
- data/lib/rubyn_code/ide/handlers/recover_ci_handler.rb +132 -0
- data/lib/rubyn_code/ide/handlers/review_handler.rb +19 -2
- data/lib/rubyn_code/ide/handlers.rb +17 -2
- data/lib/rubyn_code/ide/protocol.rb +17 -1
- data/lib/rubyn_code/ide/server.rb +39 -1
- data/lib/rubyn_code/index/codebase_index.rb +2 -1
- data/lib/rubyn_code/learning/extractor.rb +4 -2
- data/lib/rubyn_code/llm/model_router.rb +2 -1
- data/lib/rubyn_code/mcp/tool_bridge.rb +1 -1
- data/lib/rubyn_code/megaplan/ci_recovery.rb +104 -0
- data/lib/rubyn_code/megaplan/interview_session.rb +245 -0
- data/lib/rubyn_code/megaplan/plan_proposer.rb +153 -0
- data/lib/rubyn_code/observability/usage_reporter.rb +4 -2
- data/lib/rubyn_code/output/diff_renderer.rb +3 -2
- data/lib/rubyn_code/self_test.rb +2 -1
- data/lib/rubyn_code/skills/auto_suggest.rb +131 -0
- data/lib/rubyn_code/skills/catalog.rb +10 -0
- data/lib/rubyn_code/skills/document.rb +8 -2
- data/lib/rubyn_code/skills/gemfile_parser.rb +40 -0
- data/lib/rubyn_code/skills/loader.rb +1 -1
- data/lib/rubyn_code/skills/matcher.rb +89 -0
- data/lib/rubyn_code/skills/pack_context.rb +163 -0
- data/lib/rubyn_code/skills/pack_installer.rb +194 -0
- data/lib/rubyn_code/skills/pack_manager.rb +230 -0
- data/lib/rubyn_code/skills/registry_autoload.rb +112 -0
- data/lib/rubyn_code/skills/registry_client.rb +241 -0
- data/lib/rubyn_code/tools/executor.rb +4 -2
- data/lib/rubyn_code/tools/grep.rb +2 -1
- data/lib/rubyn_code/tools/ide_diagnostics.rb +3 -1
- data/lib/rubyn_code/tools/ide_symbols.rb +3 -1
- data/lib/rubyn_code/tools/load_skill.rb +2 -1
- data/lib/rubyn_code/tools/output_compressor.rb +3 -6
- data/lib/rubyn_code/tools/review_pr.rb +15 -4
- data/lib/rubyn_code/tools/web_search.rb +2 -1
- data/lib/rubyn_code/version.rb +1 -1
- data/lib/rubyn_code.rb +20 -0
- data/skills/megaplan/megaplan.md +156 -0
- data/skills/rubyn_self_test.md +75 -0
- metadata +25 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b43dc2a8fab138bcfe303180881aa9fa23878faaa532367f07a0fee7605feb34
|
|
4
|
+
data.tar.gz: 12dffaa487a75dfe276be9d20ff8152814bd60c6b107efd9ed10d2993afd57a5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fcbe574a607028345e38587388a6c0bd9cdb8ab134e690d45583a1a27b4c698383bd43088eb8fa537cddba8690e77d15ab155be92fb997117c8fe62a978df211
|
|
7
|
+
data.tar.gz: 43e72475ec24edf03f21e4aafa4402de31351728a38de42e55b69db104aea1828b930a1cafb79d3065d07e16f84c8a5a5023311da5d1e40f7a667daa90ddee3c
|
data/README.md
CHANGED
|
@@ -22,16 +22,56 @@ Refactor controllers, generate idiomatic RSpec, catch N+1 queries, review code f
|
|
|
22
22
|
|
|
23
23
|
> **Rubyn is going open source.** The original [Rubyn gem](https://github.com/Rubyn-AI/rubyn) provided AI-assisted refactoring, spec generation, and code review through the Rubyn API. **Rubyn Code** is the next evolution — a complete agentic coding assistant that runs locally, thinks for itself, and learns from every session. No API keys. No separate billing. Just `gem install rubyn-code` and go.
|
|
24
24
|
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Table of Contents
|
|
28
|
+
|
|
29
|
+
- [Why Rubyn?](#why-rubyn)
|
|
30
|
+
- [Install](#install)
|
|
31
|
+
- [Quick Start](#quick-start)
|
|
32
|
+
- [What Can Rubyn Do?](#what-can-rubyn-do)
|
|
33
|
+
- [VS Code Extension](#vs-code-extension)
|
|
34
|
+
- [29 Built-in Tools](#29-built-in-tools)
|
|
35
|
+
- [MCP — External Tool Servers](#mcp--external-tool-servers)
|
|
36
|
+
- [Codebase Indexing](#codebase-indexing)
|
|
37
|
+
- [112 Best Practice Skills](#112-best-practice-skills)
|
|
38
|
+
- [Skill Packs — Registry-Backed Extensions](#skill-packs--registry-backed-extensions)
|
|
39
|
+
- [Context Architecture](#context-architecture)
|
|
40
|
+
- [RUBYN.md — Project Instructions](#rubynmd--project-instructions)
|
|
41
|
+
- [PR Review](#pr-review)
|
|
42
|
+
- [Megaplan — Phased Planning](#megaplan--phased-planning)
|
|
43
|
+
- [Sub-Agents & Teams](#sub-agents--teams)
|
|
44
|
+
- [GOLEM — Autonomous Daemon](#golem--autonomous-daemon)
|
|
45
|
+
- [Continuous Learning](#continuous-learning)
|
|
46
|
+
- [Streaming Output](#streaming-output)
|
|
47
|
+
- [Search Providers](#search-providers)
|
|
48
|
+
- [User Hooks](#user-hooks)
|
|
49
|
+
- [CLI Reference](#cli-reference)
|
|
50
|
+
- [Authentication](#authentication)
|
|
51
|
+
- [Architecture](#architecture)
|
|
52
|
+
- [Configuration](#configuration)
|
|
53
|
+
- [Security](#security)
|
|
54
|
+
- [Diagnostics](#diagnostics)
|
|
55
|
+
- [Development](#development)
|
|
56
|
+
- [From Rubyn to Rubyn Code](#from-rubyn-to-rubyn-code)
|
|
57
|
+
- [Contributing](#contributing)
|
|
58
|
+
- [License](#license)
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
25
62
|
## Why Rubyn?
|
|
26
63
|
|
|
27
64
|
- **Rails-native** — understands service object extraction, RSpec conventions, ActiveRecord patterns, and Hotwire
|
|
28
65
|
- **Context-aware** — automatically incorporates schema, routes, specs, factories, and models
|
|
29
|
-
- **Best practices built in** — ships with 112 curated Ruby and Rails guidelines that load on demand
|
|
66
|
+
- **Best practices built in** — ships with 112 curated Ruby and Rails guidelines that load on demand, plus registry-backed [skill packs](#skill-packs--registry-backed-extensions) that autoload as you need them
|
|
67
|
+
- **Plans big work in phases** — [`/megaplan`](#megaplan--phased-planning) runs a read-only interview, then breaks rewrites and migrations into vertical-slice phases that ship one at a time
|
|
30
68
|
- **Agentic** — doesn't just answer questions. Reads files, writes code, runs specs, commits, reviews PRs, spawns sub-agents, and remembers what it learns
|
|
69
|
+
- **IDE-ready** — works in the terminal and inside VS Code with full bidirectional communication
|
|
70
|
+
- **Extensible** — connect external tool servers via MCP, add custom skills, or wire up your own providers
|
|
31
71
|
|
|
32
72
|
## Install
|
|
33
73
|
|
|
34
|
-
Requires **Ruby 4.0+**. Install with your latest Ruby, then pin it so it works in every project:
|
|
74
|
+
Requires **Ruby 4.0.2+**. Install with your latest Ruby, then pin it so it works in every project:
|
|
35
75
|
|
|
36
76
|
```bash
|
|
37
77
|
# Install the gem
|
|
@@ -46,11 +86,11 @@ That's it. `rubyn-code` now works in any project regardless of `.ruby-version`.
|
|
|
46
86
|
<details>
|
|
47
87
|
<summary>Using rbenv?</summary>
|
|
48
88
|
|
|
49
|
-
If you manage multiple Rubies with rbenv, install on your latest:
|
|
89
|
+
If you manage multiple Rubies with rbenv, install on your latest (run `rbenv versions` to list what you have):
|
|
50
90
|
|
|
51
91
|
```bash
|
|
52
|
-
RBENV_VERSION
|
|
53
|
-
RBENV_VERSION
|
|
92
|
+
RBENV_VERSION=<your-ruby-version> gem install rubyn-code
|
|
93
|
+
RBENV_VERSION=<your-ruby-version> rubyn-code --setup
|
|
54
94
|
```
|
|
55
95
|
|
|
56
96
|
The `--setup` command creates a launcher in `~/.local/bin` that calls the gem wrapper directly, skipping rbenv's shim. As long as `~/.local/bin` is in your PATH before `~/.rbenv/shims`, you're good.
|
|
@@ -61,7 +101,7 @@ The `--setup` command creates a launcher in `~/.local/bin` that calls the gem wr
|
|
|
61
101
|
<summary>Using rvm?</summary>
|
|
62
102
|
|
|
63
103
|
```bash
|
|
64
|
-
rvm use
|
|
104
|
+
rvm use <your-ruby-version>
|
|
65
105
|
gem install rubyn-code
|
|
66
106
|
rubyn-code --setup
|
|
67
107
|
```
|
|
@@ -93,6 +133,9 @@ rubyn-code --yolo
|
|
|
93
133
|
|
|
94
134
|
# Single prompt
|
|
95
135
|
rubyn-code -p "Refactor app/controllers/orders_controller.rb into service objects"
|
|
136
|
+
|
|
137
|
+
# VS Code IDE mode (used by the extension)
|
|
138
|
+
rubyn-code --ide
|
|
96
139
|
```
|
|
97
140
|
|
|
98
141
|
## What Can Rubyn Do?
|
|
@@ -118,7 +161,7 @@ rubyn > Write specs for the new service objects
|
|
|
118
161
|
> write_file: path=spec/services/orders/create_service_spec.rb
|
|
119
162
|
> run_specs: path=spec/services/orders/
|
|
120
163
|
|
|
121
|
-
4 examples, 0 failures. All green.
|
|
164
|
+
4 examples, 0 failures. All green.
|
|
122
165
|
```
|
|
123
166
|
|
|
124
167
|
### Review code
|
|
@@ -142,6 +185,29 @@ Agent finished (23 tool calls).
|
|
|
142
185
|
This is a Rails 7.1 e-commerce app with...
|
|
143
186
|
```
|
|
144
187
|
|
|
188
|
+
## VS Code Extension
|
|
189
|
+
|
|
190
|
+
Rubyn Code includes a VS Code extension that provides a full IDE experience with bidirectional JSON-RPC communication. The extension runs Rubyn as a subprocess and connects over stdin/stdout.
|
|
191
|
+
|
|
192
|
+
**Capabilities:**
|
|
193
|
+
|
|
194
|
+
- Chat panel with streaming responses and syntax-highlighted code blocks
|
|
195
|
+
- Inline diffs — review and accept generated code changes directly in the editor
|
|
196
|
+
- Tool approval prompts in the IDE (or skip them in YOLO mode)
|
|
197
|
+
- Full session management — resume, list, fork, and reset conversations
|
|
198
|
+
- Structured code review feedback with severity ratings
|
|
199
|
+
- IDE config get/set for persistent settings
|
|
200
|
+
- All 29 tools available, including MCP tools
|
|
201
|
+
|
|
202
|
+
**Permission modes:**
|
|
203
|
+
|
|
204
|
+
| Mode | Behavior |
|
|
205
|
+
|------|----------|
|
|
206
|
+
| `default` | Per-tool approval required |
|
|
207
|
+
| `bypass` | YOLO — skip all approval prompts |
|
|
208
|
+
|
|
209
|
+
The extension communicates over 19 RPC methods: `initialize`, `prompt`, `cancel`, `review`, `approveToolUse`, `acceptEdit`, `session/*`, `config/*`, `models/list`, `plan/propose`, `plan/interview/*` (chat-resident [megaplan](#megaplan--phased-planning)), `recover_ci`, and `shutdown`.
|
|
210
|
+
|
|
145
211
|
## 29 Built-in Tools
|
|
146
212
|
|
|
147
213
|
| Category | Tools |
|
|
@@ -159,6 +225,58 @@ This is a Rails 7.1 e-commerce app with...
|
|
|
159
225
|
| **Teams** | `send_message`, `read_inbox` |
|
|
160
226
|
| **Interactive** | `ask_user` (ask clarifying questions mid-task) |
|
|
161
227
|
|
|
228
|
+
## MCP — External Tool Servers
|
|
229
|
+
|
|
230
|
+
Connect external tool servers via the [Model Context Protocol](https://modelcontextprotocol.io). MCP tools are dynamically discovered and registered as native Rubyn tools, available in the REPL, IDE, and daemon.
|
|
231
|
+
|
|
232
|
+
### Configuration
|
|
233
|
+
|
|
234
|
+
Create `.rubyn-code/mcp.json` in your project or `~/.rubyn-code/mcp.json` globally:
|
|
235
|
+
|
|
236
|
+
```json
|
|
237
|
+
{
|
|
238
|
+
"mcpServers": {
|
|
239
|
+
"github": {
|
|
240
|
+
"command": "npx",
|
|
241
|
+
"args": ["-y", "@modelcontextprotocol/server-github"],
|
|
242
|
+
"env": { "GITHUB_TOKEN": "${GITHUB_TOKEN}" }
|
|
243
|
+
},
|
|
244
|
+
"my-api": {
|
|
245
|
+
"url": "http://localhost:3001/mcp",
|
|
246
|
+
"timeout": 30
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
- **Stdio transport** — specify `command` and `args` to run a subprocess
|
|
253
|
+
- **SSE transport** — specify `url` for HTTP-based servers
|
|
254
|
+
- Environment variables are interpolated with `${VAR}` syntax
|
|
255
|
+
|
|
256
|
+
MCP tools appear in the tool palette prefixed with `mcp_` and require confirmation before execution. Run `/doctor` to verify server connectivity.
|
|
257
|
+
|
|
258
|
+
Rubyn ships with three example MCP servers: **database explorer**, **RubyGems lookup**, and **Rails routes**. See `/mcp` for documentation.
|
|
259
|
+
|
|
260
|
+
## Codebase Indexing
|
|
261
|
+
|
|
262
|
+
Rubyn builds a structural index of your codebase on first session and incrementally updates it as files change. The index powers smarter context injection, skill suggestions, and impact analysis.
|
|
263
|
+
|
|
264
|
+
**What it tracks:**
|
|
265
|
+
|
|
266
|
+
- Classes, modules, methods, callbacks, scopes, validations, associations
|
|
267
|
+
- Relationships between files (associations, test coverage, caller/callee)
|
|
268
|
+
- Rails patterns: `has_many`, `belongs_to`, `before_action`, `validates`, etc.
|
|
269
|
+
- File classification: model, controller, service, concern, spec
|
|
270
|
+
|
|
271
|
+
**How it's used:**
|
|
272
|
+
|
|
273
|
+
- Injects a compact structural summary into the system prompt
|
|
274
|
+
- Feeds the dynamic tool schema for smarter tool selection
|
|
275
|
+
- Powers `impact_analysis(file)` to find affected tests and dependents
|
|
276
|
+
- Suggests relevant skills based on the code you're working with
|
|
277
|
+
|
|
278
|
+
Stored at `.rubyn-code/codebase_index.json`. The `/doctor` command flags stale indexes (>24 hours).
|
|
279
|
+
|
|
162
280
|
## 112 Best Practice Skills
|
|
163
281
|
|
|
164
282
|
Rubyn ships with curated best practice documents that load on demand. Only skill names are in memory — full content loads when Rubyn needs it.
|
|
@@ -176,6 +294,17 @@ Rubyn ships with curated best practice documents that load on demand. Only skill
|
|
|
176
294
|
| **Gems** | Sidekiq, Devise, FactoryBot, Pundit, Faraday, Stripe, RuboCop, dry-rb |
|
|
177
295
|
| **Sinatra** | Application structure, middleware, testing |
|
|
178
296
|
|
|
297
|
+
### Skill search & filter
|
|
298
|
+
|
|
299
|
+
```
|
|
300
|
+
rubyn > /skill search factory # search by name, description, or tags
|
|
301
|
+
rubyn > /skill list rails # filter by category
|
|
302
|
+
rubyn > /skill list # show all categories
|
|
303
|
+
rubyn > /skill load rspec_matchers # inject a skill into context
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
Results are relevance-ranked: name matches score highest, then description, then tags.
|
|
307
|
+
|
|
179
308
|
### Custom skills
|
|
180
309
|
|
|
181
310
|
Override or extend with your own:
|
|
@@ -190,6 +319,29 @@ mkdir -p ~/.rubyn-code/skills
|
|
|
190
319
|
echo "# Use double quotes for strings" > ~/.rubyn-code/skills/my_style.md
|
|
191
320
|
```
|
|
192
321
|
|
|
322
|
+
## Skill Packs — Registry-Backed Extensions
|
|
323
|
+
|
|
324
|
+
Beyond the 112 built-in skills, Rubyn can pull additional skill packs from the [rubyn.ai](https://rubyn.ai) registry. Packs are bundles of related skills published by the community or by Rubyn itself.
|
|
325
|
+
|
|
326
|
+
```
|
|
327
|
+
rubyn > /skills # list installed packs and browse the registry
|
|
328
|
+
rubyn > /install-skills sidekiq # install a pack by name
|
|
329
|
+
rubyn > /install-skills graphql viewcomponent # install multiple at once
|
|
330
|
+
rubyn > /remove-skills sidekiq # uninstall
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
Installed packs live at `~/.rubyn-code/skill-packs/<pack-name>/` and load alongside the built-in catalog.
|
|
334
|
+
|
|
335
|
+
### Auto-suggest from your Gemfile
|
|
336
|
+
|
|
337
|
+
On session start, Rubyn parses your `Gemfile` and quietly suggests matching packs the first time it sees a gem (e.g. detects `sidekiq` → suggests the sidekiq pack). Suggestions are recorded in `.rubyn-code/suggested.json` so you only see each one once.
|
|
338
|
+
|
|
339
|
+
### Trigger-based autoload
|
|
340
|
+
|
|
341
|
+
If your message mentions a topic that matches an uninstalled pack's name or tags, Rubyn fetches the pack from the registry on the fly, installs it, and feeds the relevant skills into the same turn. Registry failures are silent — the conversation continues as if the autoload weren't there.
|
|
342
|
+
|
|
343
|
+
Point at a custom registry with `RUBYN_REGISTRY_URL=https://your-registry.example.com`.
|
|
344
|
+
|
|
193
345
|
## Context Architecture
|
|
194
346
|
|
|
195
347
|
Rubyn automatically loads relevant context based on what you're working on:
|
|
@@ -199,6 +351,8 @@ Rubyn automatically loads relevant context based on what you're working on:
|
|
|
199
351
|
- **Service objects** → includes referenced models and their specs
|
|
200
352
|
- **Any file** → checks for `RUBYN.md`, `CLAUDE.md`, or `AGENT.md` instructions
|
|
201
353
|
|
|
354
|
+
The [codebase index](#codebase-indexing) enhances this with structural awareness — Rubyn knows which files depend on each other before it reads them.
|
|
355
|
+
|
|
202
356
|
## RUBYN.md — Project Instructions
|
|
203
357
|
|
|
204
358
|
Drop a `RUBYN.md` in your project root and Rubyn follows your conventions:
|
|
@@ -236,6 +390,34 @@ Focus areas: `all`, `security`, `performance`, `style`, `testing`
|
|
|
236
390
|
|
|
237
391
|
Severity ratings: **[critical]** **[warning]** **[suggestion]** **[nitpick]**
|
|
238
392
|
|
|
393
|
+
## Megaplan — Phased Planning
|
|
394
|
+
|
|
395
|
+
For work too big for a single PR — rewrites, migrations, multi-feature initiatives — Rubyn ships a planning workflow that breaks the feature into vertical-slice phases before any code gets written.
|
|
396
|
+
|
|
397
|
+
```
|
|
398
|
+
rubyn > /megaplan extract billing into its own service
|
|
399
|
+
Megaplan mode — interviewer with read-only tools
|
|
400
|
+
|
|
401
|
+
Decisions so far: (none yet)
|
|
402
|
+
|
|
403
|
+
Q1. What triggers the extraction now — a scaling issue, a team boundary,
|
|
404
|
+
or a compliance constraint?
|
|
405
|
+
1. Scaling (recommended — billing is the hottest table)
|
|
406
|
+
2. Team boundary
|
|
407
|
+
3. Compliance
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
What happens when you run `/megaplan`:
|
|
411
|
+
|
|
412
|
+
- Loads the **megaplan** skill into context.
|
|
413
|
+
- Flips the agent into **plan mode** — only read-only tools (file reads, search, git status) are available. No edits, no shell mutations.
|
|
414
|
+
- Conducts a one-question-at-a-time interview to lock down scope, constraints, and risk before proposing phases.
|
|
415
|
+
- Outputs a numbered phase breakdown, each phase shippable on its own with the trunk staying green.
|
|
416
|
+
|
|
417
|
+
Trigger phrases like "megaplan", "mega plan", "plan phases", or "phase this out" in normal conversation will surface the skill via [trigger-based autoload](#skill-packs--registry-backed-extensions) too.
|
|
418
|
+
|
|
419
|
+
In the VS Code extension the same workflow runs as a chat-resident interview with structured question cards instead of free-text Q&A. Same skill driving both surfaces.
|
|
420
|
+
|
|
239
421
|
## Sub-Agents & Teams
|
|
240
422
|
|
|
241
423
|
### Sub-Agents (disposable)
|
|
@@ -259,6 +441,32 @@ rubyn > Send alice a message to write specs for the User model
|
|
|
259
441
|
|
|
260
442
|
Teammates run in background threads with their own agent loop and mailbox.
|
|
261
443
|
|
|
444
|
+
## GOLEM — Autonomous Daemon
|
|
445
|
+
|
|
446
|
+
GOLEM is an always-on autonomous agent that claims tasks from a queue and works through them independently. It runs a full agent loop per task with access to all tools, MCP servers, and memory.
|
|
447
|
+
|
|
448
|
+
```bash
|
|
449
|
+
rubyn-code daemon \
|
|
450
|
+
--name golem-1 \
|
|
451
|
+
--role "Backend Engineer" \
|
|
452
|
+
--max-runs 100 \
|
|
453
|
+
--max-cost 10.0 \
|
|
454
|
+
--poll-interval 5 \
|
|
455
|
+
--idle-timeout 60
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
**Lifecycle:** `spawned → working ⇄ idle → shutting_down → stopped`
|
|
459
|
+
|
|
460
|
+
**Safety limits:**
|
|
461
|
+
|
|
462
|
+
| Guard | Description |
|
|
463
|
+
|-------|-------------|
|
|
464
|
+
| `--max-runs` | Auto-shutdown after N completed tasks |
|
|
465
|
+
| `--max-cost` | Stop when cumulative USD spend exceeds limit |
|
|
466
|
+
| **Retry backoff** | 3 retries per task before marking failed |
|
|
467
|
+
| **Audit trail** | Full conversation saved per task via session persistence |
|
|
468
|
+
| **Cost tracking** | Accurate per-task spend via the observability layer |
|
|
469
|
+
|
|
262
470
|
## Continuous Learning
|
|
263
471
|
|
|
264
472
|
Rubyn gets smarter with every session:
|
|
@@ -310,12 +518,14 @@ post_tool_use:
|
|
|
310
518
|
rubyn-code # Interactive REPL
|
|
311
519
|
rubyn-code --yolo # Auto-approve all tools
|
|
312
520
|
rubyn-code -p "prompt" # Single prompt, exit when done
|
|
521
|
+
rubyn-code --ide # IDE server mode (JSON-RPC over stdin/stdout)
|
|
313
522
|
rubyn-code --resume [ID] # Resume previous session
|
|
314
523
|
rubyn-code --setup # Pin to this Ruby (run once after install)
|
|
315
524
|
rubyn-code --debug # Enable debug output
|
|
316
525
|
rubyn-code --auth # Authenticate with Claude
|
|
317
526
|
rubyn-code --version # Show version
|
|
318
527
|
rubyn-code --help # Show help
|
|
528
|
+
rubyn-code daemon [OPTIONS] # Run GOLEM autonomous daemon
|
|
319
529
|
```
|
|
320
530
|
|
|
321
531
|
### Slash Commands
|
|
@@ -331,10 +541,12 @@ rubyn-code --help # Show help
|
|
|
331
541
|
| `/cost` | Show token usage and costs |
|
|
332
542
|
| `/tasks` | List all tasks |
|
|
333
543
|
| `/budget [amt]` | Show or set session budget |
|
|
334
|
-
| `/skill [name]` | Load or list available skills |
|
|
544
|
+
| `/skill [name]` | Load, search, or list available skills |
|
|
335
545
|
| `/resume [id]` | Resume or list sessions |
|
|
336
546
|
| `/provider` | Add or list providers |
|
|
337
547
|
| `/model` | Show/switch model and provider |
|
|
548
|
+
| `/doctor` | Run environment health checks |
|
|
549
|
+
| `/mcp` | MCP server documentation and status |
|
|
338
550
|
|
|
339
551
|
## Authentication
|
|
340
552
|
|
|
@@ -527,9 +739,29 @@ This means:
|
|
|
527
739
|
| `~/.rubyn-code/.encryption_salt` | `0600` | PBKDF2 salt (not secret alone, but protected) |
|
|
528
740
|
| `~/.rubyn-code/config.yml` | `0600` | Provider config (no secrets) |
|
|
529
741
|
|
|
742
|
+
## Diagnostics
|
|
743
|
+
|
|
744
|
+
Run `/doctor` to check your environment:
|
|
745
|
+
|
|
746
|
+
```
|
|
747
|
+
rubyn > /doctor
|
|
748
|
+
|
|
749
|
+
✓ Ruby version 4.0.2
|
|
750
|
+
✓ Bundler installed
|
|
751
|
+
✓ Database 12 migrations applied
|
|
752
|
+
✓ Authentication valid (keychain)
|
|
753
|
+
✓ Skills 112 available
|
|
754
|
+
✓ Project detected Rails 7.1
|
|
755
|
+
✓ MCP servers 2 connected
|
|
756
|
+
✓ Codebase index fresh (2 hours ago)
|
|
757
|
+
✓ Skill catalog 112 skills, 0 malformed
|
|
758
|
+
```
|
|
759
|
+
|
|
760
|
+
Checks Ruby version, bundler, database state, authentication, skills, project type, MCP server connectivity, codebase index freshness, and skill catalog integrity.
|
|
761
|
+
|
|
530
762
|
## Development
|
|
531
763
|
|
|
532
|
-
Requires Ruby 4.0+.
|
|
764
|
+
Requires Ruby 4.0.2+.
|
|
533
765
|
|
|
534
766
|
```bash
|
|
535
767
|
git clone https://github.com/MatthewSuttles/rubyn-code.git
|
|
@@ -538,6 +770,12 @@ bundle install
|
|
|
538
770
|
bundle exec rspec
|
|
539
771
|
```
|
|
540
772
|
|
|
773
|
+
Quick rebuild from source:
|
|
774
|
+
|
|
775
|
+
```bash
|
|
776
|
+
bin/dev-install
|
|
777
|
+
```
|
|
778
|
+
|
|
541
779
|
## From Rubyn to Rubyn Code
|
|
542
780
|
|
|
543
781
|
If you used the original [Rubyn gem](https://github.com/Rubyn-AI/rubyn), here's what changed:
|
|
@@ -177,7 +177,8 @@ module RubynCode
|
|
|
177
177
|
id_str_key: 'tool_use_id')
|
|
178
178
|
end
|
|
179
179
|
|
|
180
|
-
|
|
180
|
+
# -- iterates blocks with type+role guards
|
|
181
|
+
def collect_block_ids(formatted, role:, type:, id_key:, id_str_key:)
|
|
181
182
|
ids = Set.new
|
|
182
183
|
formatted.each do |msg|
|
|
183
184
|
next unless msg[:role] == role && msg[:content].is_a?(Array)
|
|
@@ -64,7 +64,8 @@ module RubynCode
|
|
|
64
64
|
# @param message [String]
|
|
65
65
|
# @param codebase_index [RubynCode::Index::CodebaseIndex, nil] optional index for deeper detection
|
|
66
66
|
# @return [Symbol, nil]
|
|
67
|
-
|
|
67
|
+
# -- context detection dispatch
|
|
68
|
+
def detect_context(message, codebase_index: nil)
|
|
68
69
|
msg = message.to_s.downcase
|
|
69
70
|
return :testing if msg.match?(/\b(test|spec|rspec)\b/)
|
|
70
71
|
return :git if msg.match?(/\b(commit|push|diff|branch|merge|git)\b/)
|
|
@@ -43,7 +43,8 @@ module RubynCode
|
|
|
43
43
|
# Only returns models from the active provider — never crosses
|
|
44
44
|
# provider boundaries (e.g., won't send a GPT model to Anthropic).
|
|
45
45
|
# Falls back to nil (use client's default) if routing fails.
|
|
46
|
-
|
|
46
|
+
# -- guard clauses for provider/mode checks
|
|
47
|
+
def routed_model
|
|
47
48
|
return nil if manual_model_mode?
|
|
48
49
|
|
|
49
50
|
last_user = last_user_message_text
|
|
@@ -76,7 +77,8 @@ module RubynCode
|
|
|
76
77
|
content.is_a?(String) ? content : nil
|
|
77
78
|
end
|
|
78
79
|
|
|
79
|
-
|
|
80
|
+
# -- safe accessor checks
|
|
81
|
+
def log_llm_call(opts)
|
|
80
82
|
default_model = @llm_client.respond_to?(:model) ? @llm_client.model : 'default'
|
|
81
83
|
routed = opts[:model]
|
|
82
84
|
effective = routed || default_model
|
|
@@ -59,6 +59,7 @@ module RubynCode
|
|
|
59
59
|
inject_skill_listing unless @skills_injected
|
|
60
60
|
@decision_compactor&.detect_topic_switch(user_input)
|
|
61
61
|
@skill_ttl&.tick!
|
|
62
|
+
autoload_triggered_skills(user_input)
|
|
62
63
|
@conversation.add_user_message(user_input)
|
|
63
64
|
reset_iteration_state
|
|
64
65
|
|
|
@@ -93,6 +94,8 @@ module RubynCode
|
|
|
93
94
|
@background_manager = opts[:background_manager]
|
|
94
95
|
@stall_detector = opts.fetch(:stall_detector, LoopDetector.new)
|
|
95
96
|
@skill_loader = opts[:skill_loader]
|
|
97
|
+
@skill_matcher = opts[:skill_matcher]
|
|
98
|
+
@web_skill_autoload = opts[:web_skill_autoload]
|
|
96
99
|
@project_root = opts[:project_root]
|
|
97
100
|
@tool_wrapper = opts[:tool_wrapper]
|
|
98
101
|
@decision_compactor = build_decision_compactor
|
|
@@ -134,9 +137,10 @@ module RubynCode
|
|
|
134
137
|
end
|
|
135
138
|
|
|
136
139
|
def assign_callbacks(opts)
|
|
137
|
-
@on_tool_call
|
|
138
|
-
@on_tool_result
|
|
139
|
-
@on_text
|
|
140
|
+
@on_tool_call = opts[:on_tool_call]
|
|
141
|
+
@on_tool_result = opts[:on_tool_result]
|
|
142
|
+
@on_text = opts[:on_text]
|
|
143
|
+
@on_skills_autoloaded = opts[:on_skills_autoloaded]
|
|
140
144
|
@skills_injected = false
|
|
141
145
|
end
|
|
142
146
|
|
|
@@ -45,7 +45,8 @@ module RubynCode
|
|
|
45
45
|
# @param message [String] the user's input
|
|
46
46
|
# @param tool_calls [Array] recent tool calls (for context)
|
|
47
47
|
# @return [Symbol] one of the MODES keys
|
|
48
|
-
|
|
48
|
+
# -- mode detection dispatch
|
|
49
|
+
def detect(message, tool_calls: [])
|
|
49
50
|
return :implementing if implementation_signal?(message)
|
|
50
51
|
return :debugging if debugging_signal?(message)
|
|
51
52
|
return :reviewing if reviewing_signal?(message)
|
|
@@ -123,6 +123,45 @@ module RubynCode
|
|
|
123
123
|
@skills_injected = true
|
|
124
124
|
end
|
|
125
125
|
|
|
126
|
+
# Match the current user message against every skill's :triggers and
|
|
127
|
+
# inject the body of any new match into the conversation so the LLM sees
|
|
128
|
+
# it on the next call. Per-session dedup lives in the Matcher.
|
|
129
|
+
#
|
|
130
|
+
# When the message matches a registry pack the user hasn't installed,
|
|
131
|
+
# @web_skill_autoload silently fetches it, installs it, refreshes the
|
|
132
|
+
# catalog, and surfaces any new skill matches. Web fallback failures
|
|
133
|
+
# are silent so the turn proceeds normally.
|
|
134
|
+
def autoload_triggered_skills(user_input)
|
|
135
|
+
return unless @skill_matcher && @skill_loader
|
|
136
|
+
|
|
137
|
+
matches = @skill_matcher.match(user_input)
|
|
138
|
+
matches += @web_skill_autoload.try(user_input) if @web_skill_autoload
|
|
139
|
+
return if matches.empty?
|
|
140
|
+
|
|
141
|
+
names = matches.map { |m| m[:name] }
|
|
142
|
+
bodies = names.filter_map do |name|
|
|
143
|
+
@skill_loader.load(name)
|
|
144
|
+
rescue StandardError => e
|
|
145
|
+
RubynCode::Debug.warn("Failed to autoload skill '#{name}': #{e.message}")
|
|
146
|
+
nil
|
|
147
|
+
end
|
|
148
|
+
return if bodies.empty?
|
|
149
|
+
|
|
150
|
+
inject_autoloaded_bodies(bodies)
|
|
151
|
+
@on_skills_autoloaded&.call(names)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def inject_autoloaded_bodies(bodies)
|
|
155
|
+
@conversation.add_user_message(
|
|
156
|
+
'[system] The following skills are auto-loaded based on the next user ' \
|
|
157
|
+
"message's triggers. Use them as context. Do not mention this message " \
|
|
158
|
+
"to the user.\n\n#{bodies.join("\n\n")}"
|
|
159
|
+
)
|
|
160
|
+
@conversation.add_assistant_message(
|
|
161
|
+
[{ type: 'text', text: 'Understood.' }]
|
|
162
|
+
)
|
|
163
|
+
end
|
|
164
|
+
|
|
126
165
|
def append_deferred_tools(parts)
|
|
127
166
|
deferred = deferred_tool_names
|
|
128
167
|
return if deferred.empty?
|
|
@@ -26,7 +26,8 @@ module RubynCode
|
|
|
26
26
|
all_tools.select { |t| core_or_discovered?(t) }
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
# -- safe navigation chain
|
|
30
|
+
def detect_task_context
|
|
30
31
|
last_msg = @conversation&.messages&.reverse_each&.find { |m| m[:role] == 'user' } # rubocop:disable Style/SafeNavigationChainLength
|
|
31
32
|
return nil unless last_msg
|
|
32
33
|
|
|
@@ -142,7 +143,8 @@ module RubynCode
|
|
|
142
143
|
end
|
|
143
144
|
end
|
|
144
145
|
|
|
145
|
-
|
|
146
|
+
# -- tool dispatch
|
|
147
|
+
def signal_decision_compactor(tool_name, tool_input, result)
|
|
146
148
|
return unless @decision_compactor
|
|
147
149
|
|
|
148
150
|
case tool_name
|