rubyn-code 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (235) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +620 -0
  4. data/db/migrations/000_create_schema_migrations.sql +4 -0
  5. data/db/migrations/001_create_sessions.sql +16 -0
  6. data/db/migrations/002_create_messages.sql +16 -0
  7. data/db/migrations/003_create_tasks.sql +17 -0
  8. data/db/migrations/004_create_task_dependencies.sql +8 -0
  9. data/db/migrations/005_create_memories.sql +44 -0
  10. data/db/migrations/006_create_cost_records.sql +16 -0
  11. data/db/migrations/007_create_hooks.sql +12 -0
  12. data/db/migrations/008_create_skills_cache.sql +8 -0
  13. data/db/migrations/009_create_teams.sql +27 -0
  14. data/db/migrations/010_create_instincts.sql +15 -0
  15. data/exe/rubyn-code +6 -0
  16. data/lib/rubyn_code/agent/conversation.rb +193 -0
  17. data/lib/rubyn_code/agent/loop.rb +517 -0
  18. data/lib/rubyn_code/agent/loop_detector.rb +78 -0
  19. data/lib/rubyn_code/auth/oauth.rb +174 -0
  20. data/lib/rubyn_code/auth/server.rb +126 -0
  21. data/lib/rubyn_code/auth/token_store.rb +153 -0
  22. data/lib/rubyn_code/autonomous/daemon.rb +233 -0
  23. data/lib/rubyn_code/autonomous/idle_poller.rb +111 -0
  24. data/lib/rubyn_code/autonomous/task_claimer.rb +100 -0
  25. data/lib/rubyn_code/background/job.rb +19 -0
  26. data/lib/rubyn_code/background/notifier.rb +44 -0
  27. data/lib/rubyn_code/background/worker.rb +146 -0
  28. data/lib/rubyn_code/cli/app.rb +118 -0
  29. data/lib/rubyn_code/cli/input_handler.rb +79 -0
  30. data/lib/rubyn_code/cli/renderer.rb +205 -0
  31. data/lib/rubyn_code/cli/repl.rb +519 -0
  32. data/lib/rubyn_code/cli/spinner.rb +100 -0
  33. data/lib/rubyn_code/cli/stream_formatter.rb +149 -0
  34. data/lib/rubyn_code/config/defaults.rb +43 -0
  35. data/lib/rubyn_code/config/project_config.rb +120 -0
  36. data/lib/rubyn_code/config/settings.rb +127 -0
  37. data/lib/rubyn_code/context/auto_compact.rb +81 -0
  38. data/lib/rubyn_code/context/compactor.rb +89 -0
  39. data/lib/rubyn_code/context/manager.rb +91 -0
  40. data/lib/rubyn_code/context/manual_compact.rb +87 -0
  41. data/lib/rubyn_code/context/micro_compact.rb +135 -0
  42. data/lib/rubyn_code/db/connection.rb +176 -0
  43. data/lib/rubyn_code/db/migrator.rb +146 -0
  44. data/lib/rubyn_code/db/schema.rb +106 -0
  45. data/lib/rubyn_code/hooks/built_in.rb +124 -0
  46. data/lib/rubyn_code/hooks/registry.rb +99 -0
  47. data/lib/rubyn_code/hooks/runner.rb +88 -0
  48. data/lib/rubyn_code/hooks/user_hooks.rb +90 -0
  49. data/lib/rubyn_code/learning/extractor.rb +191 -0
  50. data/lib/rubyn_code/learning/injector.rb +138 -0
  51. data/lib/rubyn_code/learning/instinct.rb +172 -0
  52. data/lib/rubyn_code/llm/client.rb +218 -0
  53. data/lib/rubyn_code/llm/message_builder.rb +116 -0
  54. data/lib/rubyn_code/llm/streaming.rb +203 -0
  55. data/lib/rubyn_code/mcp/client.rb +139 -0
  56. data/lib/rubyn_code/mcp/config.rb +83 -0
  57. data/lib/rubyn_code/mcp/sse_transport.rb +225 -0
  58. data/lib/rubyn_code/mcp/stdio_transport.rb +196 -0
  59. data/lib/rubyn_code/mcp/tool_bridge.rb +164 -0
  60. data/lib/rubyn_code/memory/models.rb +62 -0
  61. data/lib/rubyn_code/memory/search.rb +181 -0
  62. data/lib/rubyn_code/memory/session_persistence.rb +194 -0
  63. data/lib/rubyn_code/memory/store.rb +199 -0
  64. data/lib/rubyn_code/observability/budget_enforcer.rb +159 -0
  65. data/lib/rubyn_code/observability/cost_calculator.rb +61 -0
  66. data/lib/rubyn_code/observability/models.rb +29 -0
  67. data/lib/rubyn_code/observability/token_counter.rb +42 -0
  68. data/lib/rubyn_code/observability/usage_reporter.rb +140 -0
  69. data/lib/rubyn_code/output/diff_renderer.rb +212 -0
  70. data/lib/rubyn_code/output/formatter.rb +120 -0
  71. data/lib/rubyn_code/permissions/deny_list.rb +49 -0
  72. data/lib/rubyn_code/permissions/policy.rb +59 -0
  73. data/lib/rubyn_code/permissions/prompter.rb +80 -0
  74. data/lib/rubyn_code/permissions/tier.rb +22 -0
  75. data/lib/rubyn_code/protocols/interrupt_handler.rb +95 -0
  76. data/lib/rubyn_code/protocols/plan_approval.rb +67 -0
  77. data/lib/rubyn_code/protocols/shutdown_handshake.rb +109 -0
  78. data/lib/rubyn_code/skills/catalog.rb +70 -0
  79. data/lib/rubyn_code/skills/document.rb +80 -0
  80. data/lib/rubyn_code/skills/loader.rb +57 -0
  81. data/lib/rubyn_code/sub_agents/runner.rb +168 -0
  82. data/lib/rubyn_code/sub_agents/summarizer.rb +57 -0
  83. data/lib/rubyn_code/tasks/dag.rb +208 -0
  84. data/lib/rubyn_code/tasks/manager.rb +212 -0
  85. data/lib/rubyn_code/tasks/models.rb +31 -0
  86. data/lib/rubyn_code/teams/mailbox.rb +128 -0
  87. data/lib/rubyn_code/teams/manager.rb +175 -0
  88. data/lib/rubyn_code/teams/teammate.rb +38 -0
  89. data/lib/rubyn_code/tools/background_run.rb +41 -0
  90. data/lib/rubyn_code/tools/base.rb +84 -0
  91. data/lib/rubyn_code/tools/bash.rb +81 -0
  92. data/lib/rubyn_code/tools/bundle_add.rb +53 -0
  93. data/lib/rubyn_code/tools/bundle_install.rb +41 -0
  94. data/lib/rubyn_code/tools/compact.rb +57 -0
  95. data/lib/rubyn_code/tools/db_migrate.rb +52 -0
  96. data/lib/rubyn_code/tools/edit_file.rb +49 -0
  97. data/lib/rubyn_code/tools/executor.rb +62 -0
  98. data/lib/rubyn_code/tools/git_commit.rb +97 -0
  99. data/lib/rubyn_code/tools/git_diff.rb +61 -0
  100. data/lib/rubyn_code/tools/git_log.rb +59 -0
  101. data/lib/rubyn_code/tools/git_status.rb +59 -0
  102. data/lib/rubyn_code/tools/glob.rb +44 -0
  103. data/lib/rubyn_code/tools/grep.rb +81 -0
  104. data/lib/rubyn_code/tools/load_skill.rb +41 -0
  105. data/lib/rubyn_code/tools/memory_search.rb +77 -0
  106. data/lib/rubyn_code/tools/memory_write.rb +52 -0
  107. data/lib/rubyn_code/tools/rails_generate.rb +54 -0
  108. data/lib/rubyn_code/tools/read_file.rb +38 -0
  109. data/lib/rubyn_code/tools/read_inbox.rb +64 -0
  110. data/lib/rubyn_code/tools/registry.rb +48 -0
  111. data/lib/rubyn_code/tools/review_pr.rb +145 -0
  112. data/lib/rubyn_code/tools/run_specs.rb +75 -0
  113. data/lib/rubyn_code/tools/schema.rb +59 -0
  114. data/lib/rubyn_code/tools/send_message.rb +53 -0
  115. data/lib/rubyn_code/tools/spawn_agent.rb +154 -0
  116. data/lib/rubyn_code/tools/spawn_teammate.rb +168 -0
  117. data/lib/rubyn_code/tools/task.rb +148 -0
  118. data/lib/rubyn_code/tools/web_fetch.rb +108 -0
  119. data/lib/rubyn_code/tools/web_search.rb +196 -0
  120. data/lib/rubyn_code/tools/write_file.rb +30 -0
  121. data/lib/rubyn_code/version.rb +5 -0
  122. data/lib/rubyn_code.rb +203 -0
  123. data/skills/code_quality/fits_in_your_head.md +189 -0
  124. data/skills/code_quality/naming_conventions.md +213 -0
  125. data/skills/code_quality/null_object.md +205 -0
  126. data/skills/code_quality/technical_debt.md +135 -0
  127. data/skills/code_quality/value_objects.md +216 -0
  128. data/skills/code_quality/yagni.md +176 -0
  129. data/skills/design_patterns/adapter.md +191 -0
  130. data/skills/design_patterns/bridge_memento_visitor.md +254 -0
  131. data/skills/design_patterns/builder.md +158 -0
  132. data/skills/design_patterns/command.md +126 -0
  133. data/skills/design_patterns/composite.md +147 -0
  134. data/skills/design_patterns/decorator.md +204 -0
  135. data/skills/design_patterns/facade.md +133 -0
  136. data/skills/design_patterns/factory_method.md +169 -0
  137. data/skills/design_patterns/iterator.md +116 -0
  138. data/skills/design_patterns/mediator.md +133 -0
  139. data/skills/design_patterns/observer.md +177 -0
  140. data/skills/design_patterns/proxy.md +140 -0
  141. data/skills/design_patterns/singleton.md +124 -0
  142. data/skills/design_patterns/state.md +207 -0
  143. data/skills/design_patterns/strategy.md +127 -0
  144. data/skills/design_patterns/template_method.md +173 -0
  145. data/skills/gems/devise.md +365 -0
  146. data/skills/gems/dry_rb.md +186 -0
  147. data/skills/gems/factory_bot.md +268 -0
  148. data/skills/gems/faraday.md +263 -0
  149. data/skills/gems/graphql_ruby.md +514 -0
  150. data/skills/gems/pundit.md +446 -0
  151. data/skills/gems/redis.md +219 -0
  152. data/skills/gems/rubocop.md +257 -0
  153. data/skills/gems/sidekiq.md +360 -0
  154. data/skills/gems/stripe.md +224 -0
  155. data/skills/minitest/assertions.md +185 -0
  156. data/skills/minitest/fixtures.md +238 -0
  157. data/skills/minitest/integration_tests.md +210 -0
  158. data/skills/minitest/mailers_and_jobs.md +218 -0
  159. data/skills/minitest/mocking_stubbing.md +202 -0
  160. data/skills/minitest/service_tests_and_performance.md +246 -0
  161. data/skills/minitest/structure_and_conventions.md +169 -0
  162. data/skills/minitest/system_tests.md +237 -0
  163. data/skills/rails/action_cable.md +160 -0
  164. data/skills/rails/active_record_basics.md +174 -0
  165. data/skills/rails/active_storage.md +242 -0
  166. data/skills/rails/api_design.md +212 -0
  167. data/skills/rails/associations.md +182 -0
  168. data/skills/rails/background_jobs.md +212 -0
  169. data/skills/rails/caching.md +158 -0
  170. data/skills/rails/callbacks.md +135 -0
  171. data/skills/rails/concerns_controllers.md +218 -0
  172. data/skills/rails/concerns_models.md +280 -0
  173. data/skills/rails/controllers.md +190 -0
  174. data/skills/rails/engines.md +201 -0
  175. data/skills/rails/form_objects.md +168 -0
  176. data/skills/rails/hotwire.md +229 -0
  177. data/skills/rails/internationalization.md +192 -0
  178. data/skills/rails/logging.md +198 -0
  179. data/skills/rails/mailers.md +180 -0
  180. data/skills/rails/migrations.md +200 -0
  181. data/skills/rails/multitenancy.md +207 -0
  182. data/skills/rails/n_plus_one.md +151 -0
  183. data/skills/rails/presenters.md +244 -0
  184. data/skills/rails/query_objects.md +177 -0
  185. data/skills/rails/routing.md +194 -0
  186. data/skills/rails/scopes.md +187 -0
  187. data/skills/rails/security.md +233 -0
  188. data/skills/rails/serializers.md +243 -0
  189. data/skills/rails/service_objects.md +184 -0
  190. data/skills/rails/testing_strategy.md +258 -0
  191. data/skills/rails/validations.md +206 -0
  192. data/skills/refactoring/code_smells.md +251 -0
  193. data/skills/refactoring/command_query_separation.md +166 -0
  194. data/skills/refactoring/encapsulate_collection.md +125 -0
  195. data/skills/refactoring/extract_class.md +138 -0
  196. data/skills/refactoring/extract_method.md +185 -0
  197. data/skills/refactoring/replace_conditional.md +211 -0
  198. data/skills/refactoring/value_objects.md +246 -0
  199. data/skills/rspec/build_stubbed.md +199 -0
  200. data/skills/rspec/factory_design.md +206 -0
  201. data/skills/rspec/let_vs_let_bang.md +161 -0
  202. data/skills/rspec/mocking_stubbing.md +209 -0
  203. data/skills/rspec/request_specs.md +212 -0
  204. data/skills/rspec/service_specs.md +262 -0
  205. data/skills/rspec/shared_examples.md +244 -0
  206. data/skills/rspec/system_specs.md +286 -0
  207. data/skills/rspec/test_performance.md +215 -0
  208. data/skills/ruby/blocks_procs_lambdas.md +204 -0
  209. data/skills/ruby/classes.md +155 -0
  210. data/skills/ruby/concurrency.md +194 -0
  211. data/skills/ruby/data_struct_openstruct.md +158 -0
  212. data/skills/ruby/debugging_profiling.md +204 -0
  213. data/skills/ruby/enumerable_patterns.md +168 -0
  214. data/skills/ruby/exception_handling.md +199 -0
  215. data/skills/ruby/file_io.md +217 -0
  216. data/skills/ruby/hashes.md +195 -0
  217. data/skills/ruby/metaprogramming.md +170 -0
  218. data/skills/ruby/modules.md +210 -0
  219. data/skills/ruby/pattern_matching.md +177 -0
  220. data/skills/ruby/regular_expressions.md +166 -0
  221. data/skills/ruby/result_objects.md +200 -0
  222. data/skills/ruby/strings.md +177 -0
  223. data/skills/ruby_project/bundler_dependencies.md +181 -0
  224. data/skills/ruby_project/cli_tools.md +224 -0
  225. data/skills/ruby_project/rake_tasks.md +146 -0
  226. data/skills/ruby_project/structure.md +261 -0
  227. data/skills/sinatra/application_structure.md +241 -0
  228. data/skills/sinatra/middleware_and_deployment.md +221 -0
  229. data/skills/sinatra/testing.md +233 -0
  230. data/skills/solid/dependency_inversion.md +195 -0
  231. data/skills/solid/interface_segregation.md +237 -0
  232. data/skills/solid/liskov_substitution.md +263 -0
  233. data/skills/solid/open_closed.md +212 -0
  234. data/skills/solid/single_responsibility.md +183 -0
  235. metadata +397 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 145ce97f1dd515f20c3fed6dbe8d84526f37d8d9c20c44ecc2fd69de60257caf
4
+ data.tar.gz: 1506876211d73ea5f6aef672fc501b9e924771bf7498e75f34384d98c6afe78f
5
+ SHA512:
6
+ metadata.gz: 11f8a71b925fa02fc60a97dfae217498df7d17cb4cd95ba82aa2a6c94524f7a95182488ce209242069791ad5bd46c0e32b0e03b1170643cda6492dd683fa0ed5
7
+ data.tar.gz: 741916a0fb8085b4baef4a0514e387f54c0a38720435e2cda50fa92dcd4d00d004866986e1d148dadbf0e120105d24f14c509e5df48c367c72d12f3c52490e96
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 fadedmaturity
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,620 @@
1
+ # Rubyn Code
2
+
3
+ An AI-powered CLI coding assistant built in Ruby, specialized for Ruby and Rails development. Powered by Claude Opus 4.6, authenticating via your existing Claude subscription (OAuth) — no API keys required.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ # Install the gem
9
+ gem install rubyn-code
10
+
11
+ # Start the interactive REPL
12
+ rubyn-code
13
+
14
+ # YOLO mode — no tool approval prompts
15
+ rubyn-code --yolo
16
+
17
+ # Run a single prompt and exit
18
+ rubyn-code -p "Add authentication to the users controller"
19
+ ```
20
+
21
+ **Authentication:** Rubyn Code automatically reads your Claude Code OAuth token from the macOS Keychain. Just make sure you've logged into Claude Code at least once (`claude` in your terminal). No separate auth step needed.
22
+
23
+ ## RUBYN.md — Project Instructions
24
+
25
+ Just like Claude Code has `CLAUDE.md`, Rubyn Code looks for instruction files to understand your project's conventions, preferences, and rules.
26
+
27
+ **Rubyn Code detects all three conventions:**
28
+ - `RUBYN.md` — Rubyn Code native
29
+ - `CLAUDE.md` — Claude Code compatible (works out of the box)
30
+ - `AGENT.md` — Generic agent convention
31
+
32
+ If your project already has a `CLAUDE.md` or `AGENT.md`, Rubyn Code will read it automatically. No migration needed.
33
+
34
+ ```bash
35
+ # Create project instructions
36
+ cat > RUBYN.md << 'EOF'
37
+ # My Project
38
+
39
+ - Always use RSpec, never Minitest
40
+ - Use FactoryBot for test data
41
+ - Follow the service object pattern for business logic
42
+ - API endpoints use Grape, not Rails controllers
43
+ - Run rubocop before committing
44
+ EOF
45
+ ```
46
+
47
+ ### Where to put RUBYN.md
48
+
49
+ Rubyn Code loads `RUBYN.md` from multiple locations, all merged together:
50
+
51
+ | Location | Scope | Loaded |
52
+ |----------|-------|--------|
53
+ | `~/.rubyn-code/RUBYN.md` | Global | Always — applies to all projects |
54
+ | Parent directories above project root | Monorepo | Auto — walks up to find shared instructions |
55
+ | `./RUBYN.md` / `./CLAUDE.md` / `./AGENT.md` | Project | Auto — main project instructions |
56
+ | `./.rubyn-code/RUBYN.md` | Project | Auto — alternative location |
57
+ | `./subdir/RUBYN.md` (or CLAUDE.md, AGENT.md) | Subfolder | Auto — one level deep at startup |
58
+ | Any directory Rubyn navigates to | Dynamic | On demand — Rubyn checks when entering new dirs |
59
+
60
+ **Priority:** Project-level instructions override global ones. All files are concatenated into the system prompt.
61
+
62
+ ### Example: Monorepo with multiple services
63
+
64
+ ```
65
+ my-monorepo/
66
+ ├── RUBYN.md # Shared conventions (loaded for all services)
67
+ ├── api/
68
+ │ ├── RUBYN.md # API-specific: "Use Grape, JSON:API format"
69
+ │ └── ...
70
+ ├── web/
71
+ │ ├── RUBYN.md # Web-specific: "Use Hotwire, ViewComponents"
72
+ │ └── ...
73
+ └── workers/
74
+ ├── RUBYN.md # Worker-specific: "Use Sidekiq, idempotent jobs"
75
+ └── ...
76
+ ```
77
+
78
+ ## Skills — 112 Ruby/Rails Best Practice Documents
79
+
80
+ Rubyn Code ships with 112 best practice documents organized by topic. Skills load **on-demand** — only their names appear in memory until Rubyn needs the full content.
81
+
82
+ ### Built-in skill categories
83
+
84
+ | Category | Topics |
85
+ |----------|--------|
86
+ | **Ruby** | Collections, error handling, metaprogramming, concurrency |
87
+ | **Rails** | Controllers, models, views, migrations, ActiveRecord |
88
+ | **RSpec** | Matchers, factories, request specs, performance |
89
+ | **Minitest** | Assertions, system tests, fixtures |
90
+ | **Design Patterns** | Observer, strategy, decorator, builder, and more |
91
+ | **SOLID** | All five principles with Ruby examples |
92
+ | **Refactoring** | Extract method, replace conditional, code smells |
93
+ | **Code Quality** | Naming, YAGNI, value objects, null object |
94
+ | **Gems** | Development, versioning, publishing |
95
+ | **Sinatra** | Application structure, middleware, testing |
96
+
97
+ ### Custom skills
98
+
99
+ Add your own skills or override built-in ones:
100
+
101
+ ```bash
102
+ # Project-specific skills
103
+ mkdir -p .rubyn-code/skills
104
+ cat > .rubyn-code/skills/our_api_conventions.md << 'EOF'
105
+ # Our API Conventions
106
+
107
+ - All endpoints return JSON:API format
108
+ - Use Grape for API controllers
109
+ - Version APIs with /v1/ prefix
110
+ - Always paginate collections with Kaminari
111
+ EOF
112
+
113
+ # Global skills (apply to all projects)
114
+ mkdir -p ~/.rubyn-code/skills
115
+ cat > ~/.rubyn-code/skills/my_preferences.md << 'EOF'
116
+ # My Coding Preferences
117
+
118
+ - Use double quotes for strings
119
+ - Prefer guard clauses over nested conditionals
120
+ - Always add frozen_string_literal comment
121
+ EOF
122
+ ```
123
+
124
+ **Skill priority:** Project `.rubyn-code/skills/` > User `~/.rubyn-code/skills/` > Bundled defaults
125
+
126
+ ## PR Review — Best Practice Code Review
127
+
128
+ Rubyn Code can review your current branch against Ruby/Rails best practices, giving you line-by-line suggestions before you open a PR.
129
+
130
+ ### Quick usage
131
+
132
+ ```bash
133
+ rubyn > /review # Review current branch vs main
134
+ rubyn > /review develop # Review against develop branch
135
+ rubyn > /review main security # Security-focused review only
136
+ ```
137
+
138
+ ### Focus areas
139
+
140
+ | Focus | What it checks |
141
+ |-------|---------------|
142
+ | `all` *(default)* | Everything — code quality, security, performance, testing, conventions |
143
+ | `security` | SQL injection, XSS, CSRF, mass assignment, auth gaps, sensitive data exposure |
144
+ | `performance` | N+1 queries, missing indexes, eager loading, caching, pagination |
145
+ | `style` | Ruby idioms, naming, method length, DRY violations, dead code |
146
+ | `testing` | Missing coverage, test quality, factory usage, edge cases, flaky test risks |
147
+
148
+ ### What it does
149
+
150
+ 1. Gets the diff of your current branch vs the base branch
151
+ 2. Categorizes changed files (Ruby, templates, specs, migrations, config)
152
+ 3. Loads relevant best practice skills automatically
153
+ 4. Reviews every change with actionable suggestions
154
+ 5. Rates each issue by severity:
155
+
156
+ | Severity | Meaning |
157
+ |----------|---------|
158
+ | **[critical]** | Must fix — security vulnerability, data loss risk, or broken functionality |
159
+ | **[warning]** | Should fix — performance issue, missing test, or convention violation |
160
+ | **[suggestion]** | Nice to have — cleaner approach, better naming, or Ruby idiom |
161
+ | **[nitpick]** | Optional — style preference or minor readability improvement |
162
+
163
+ ### Example output
164
+
165
+ ```
166
+ [warning] app/models/user.rb:15
167
+ User.where(active: true).each { |u| u.posts.count }
168
+ ↳ N+1 query — `posts.count` fires a separate query per user.
169
+ Fix: User.where(active: true).includes(:posts).each { ... }
170
+ Or use counter_cache: true on the association.
171
+
172
+ [critical] app/controllers/admin_controller.rb:8
173
+ params[:user_id] used directly in SQL
174
+ ↳ SQL injection risk. Use parameterized queries.
175
+ Fix: User.where(id: params[:user_id])
176
+
177
+ [suggestion] app/services/create_order.rb:22
178
+ Method `process` is 45 lines long
179
+ ↳ Extract into smaller private methods for readability.
180
+ Consider: extract_line_items, calculate_totals, apply_discounts
181
+ ```
182
+
183
+ ### Natural language works too
184
+
185
+ ```bash
186
+ rubyn > Review my PR against best practices
187
+ rubyn > Check this branch for security issues
188
+ rubyn > Are there any N+1 queries in my changes?
189
+ ```
190
+
191
+ ## Architecture
192
+
193
+ Rubyn Code implements a 16-layer agentic architecture:
194
+
195
+ ```
196
+ ┌──────────────────────────────────────────────────────────────┐
197
+ │ Layer 16: Continuous Learning (pattern extraction) │
198
+ │ Layer 15: MCP (external tool servers via protocol) │
199
+ │ Layer 14: Hooks & Events (pre/post tool interception) │
200
+ │ Layer 13: Observability (cost tracking, token counting) │
201
+ │ Layer 12: Memory (persistent knowledge across sessions) │
202
+ │ Layer 11: Autonomous Operation (idle polling, KAIROS) │
203
+ │ Layer 10: Protocols (shutdown handshake, plan approval) │
204
+ │ Layer 9: Teams (persistent teammates, mailbox messaging) │
205
+ │ Layer 8: Background Execution (async tasks, notifications) │
206
+ │ Layer 7: Task System (persistent DAG, dependencies) │
207
+ │ Layer 6: Sub-Agents (isolated context, summary return) │
208
+ │ Layer 5: Skills (112 Ruby/Rails best practice docs) │
209
+ │ Layer 4: Context Management (compression pipeline) │
210
+ │ Layer 3: Permissions (tiered access, deny lists) │
211
+ │ Layer 2: Tool System (28 tools, dispatch map) │
212
+ │ Layer 1: THE AGENT LOOP (while tool_use → execute → repeat) │
213
+ └──────────────────────────────────────────────────────────────┘
214
+ ```
215
+
216
+ The core is six lines:
217
+
218
+ ```ruby
219
+ while response.tool_use?
220
+ results = execute_tools(response)
221
+ conversation.add_tool_results(results)
222
+ response = llm.chat(conversation.messages)
223
+ end
224
+ ```
225
+
226
+ Everything else is a layer around that loop.
227
+
228
+ ## Tools (28 built-in)
229
+
230
+ | Category | Tools |
231
+ |----------|-------|
232
+ | **File I/O** | `read_file`, `write_file`, `edit_file` |
233
+ | **Search** | `glob`, `grep` |
234
+ | **Execution** | `bash` (sandboxed, dangerous commands blocked) |
235
+ | **Web** | `web_search` (DuckDuckGo), `web_fetch` (fetch any URL as text) |
236
+ | **Git** | `git_status`, `git_diff`, `git_log`, `git_commit` |
237
+ | **Rails** | `rails_generate`, `db_migrate`, `run_specs`, `bundle_install`, `bundle_add` |
238
+ | **Review** | `review_pr` (diff-based best practice code review) |
239
+ | **Agents** | `spawn_agent` (isolated sub-agent), `spawn_teammate` (persistent named agent), `background_run` |
240
+ | **Agent** | `compact`, `load_skill`, `task` |
241
+ | **Memory** | `memory_search`, `memory_write` |
242
+ | **Teams** | `send_message`, `read_inbox` |
243
+
244
+ ## CLI Commands
245
+
246
+ ### Flags
247
+
248
+ ```bash
249
+ rubyn-code # Start interactive REPL
250
+ rubyn-code --yolo # Auto-approve all tool calls
251
+ rubyn-code -p "prompt" # Run a single prompt and exit
252
+ rubyn-code --resume [ID] # Resume a previous session
253
+ rubyn-code --auth # Set up authentication
254
+ rubyn-code --version # Show version
255
+ rubyn-code --help # Show help
256
+ ```
257
+
258
+ ### Interactive Commands
259
+
260
+ Type `/` to see all available commands, or `/` + Tab for autocomplete:
261
+
262
+ ```
263
+ /help Show help
264
+ /quit Exit Rubyn Code
265
+ /review [base] PR review against best practices (default: main)
266
+ /spawn name role Spawn a persistent teammate agent
267
+ /compact Compress conversation context
268
+ /cost Show token usage and costs
269
+ /clear Clear the terminal
270
+ /undo Remove last exchange
271
+ /tasks List all tasks
272
+ /budget [amt] Show or set session budget
273
+ /skill [name] Load or list available skills
274
+ /resume [id] Resume or list sessions
275
+ /version Show version
276
+ ```
277
+
278
+ ### Tips
279
+
280
+ - Use `@filename` to include file contents in your message
281
+ - End a line with `\` for multiline input
282
+ - Ctrl-C once to interrupt, twice to exit
283
+ - `/` + Tab autocompletes slash commands
284
+
285
+ ## Permission Modes
286
+
287
+ | Mode | Flag | Behavior |
288
+ |------|------|----------|
289
+ | **Allow Read** | *(default)* | Read tools auto-approved, writes need approval |
290
+ | **YOLO** | `--yolo` | Everything auto-approved — no prompts |
291
+
292
+ ## Streaming Output
293
+
294
+ Rubyn Code streams responses in real-time — text appears character-by-character as the model generates it, just like Claude Code. No more waiting for the full response to render.
295
+
296
+ When Rubyn calls tools mid-response, you see each tool call and result live:
297
+
298
+ ```
299
+ rubyn > Fix the N+1 query in UsersController
300
+ > read_file: path=app/controllers/users_controller.rb
301
+ class UsersController < ApplicationController...
302
+ > edit_file: path=app/controllers/users_controller.rb, old_text=User.all, new_text=User.includes(:posts).all
303
+ Edited app/controllers/users_controller.rb
304
+ > run_specs: path=spec/controllers/users_controller_spec.rb
305
+ 3 examples, 0 failures
306
+
307
+ Fixed the N+1 by adding `.includes(:posts)` to the query. Specs pass. ✓
308
+ ```
309
+
310
+ ## Sub-Agents & Teams
311
+
312
+ ### Sub-Agents (disposable)
313
+
314
+ Rubyn can spawn isolated sub-agents for research or parallel work. Sub-agents get their own fresh context and return only a summary — keeping Rubyn's main conversation clean.
315
+
316
+ ```bash
317
+ rubyn > Go explore the app/services directory and summarize the patterns used
318
+
319
+ Spawning explore agent...
320
+ > sub-agent > glob: pattern=app/services/**/*.rb
321
+ > sub-agent > read_file: path=app/services/create_user.rb
322
+ > sub-agent > read_file: path=app/services/process_payment.rb
323
+ Agent finished.
324
+
325
+ ## Sub-Agent Result (explore)
326
+ The services directory uses a consistent .call pattern...
327
+ ```
328
+
329
+ Two types:
330
+ - **Explore** (`agent_type: "explore"`) — read-only tools, for research
331
+ - **Worker** (`agent_type: "worker"`) — full write access, for doing work
332
+
333
+ ### Teams (persistent)
334
+
335
+ Spawn named teammates that persist, have their own inbox, and communicate via messages:
336
+
337
+ ```bash
338
+ rubyn > /spawn alice tester
339
+ Spawned teammate alice as tester
340
+
341
+ rubyn > Send alice a message to write specs for the User model
342
+ > send_message: to=alice, content=Write specs for the User model...
343
+ ```
344
+
345
+ Teammates run in background threads with their own agent loop, can claim tasks from the task board, and communicate via mailbox messaging.
346
+
347
+ ## User Hooks
348
+
349
+ Customize Rubyn's behavior with `.rubyn-code/hooks.yml` in your project or `~/.rubyn-code/hooks.yml` globally:
350
+
351
+ ```yaml
352
+ # Block dangerous operations
353
+ pre_tool_use:
354
+ - tool: bash
355
+ match: "rm -rf"
356
+ action: deny
357
+ reason: "Destructive recursive delete blocked"
358
+
359
+ - tool: write_file
360
+ path: "db/migrate/**"
361
+ action: deny
362
+ reason: "Use rails generate migration instead"
363
+
364
+ - tool: bash
365
+ match: "git push --force"
366
+ action: deny
367
+ reason: "Force push blocked — use regular push"
368
+
369
+ # Audit trail for file writes
370
+ post_tool_use:
371
+ - tool: write_file
372
+ action: log
373
+ - tool: edit_file
374
+ action: log
375
+ ```
376
+
377
+ Hook actions:
378
+ - **`deny`** — block the tool call with a reason (shown to the model)
379
+ - **`log`** — append to `.rubyn-code/audit.log`
380
+
381
+ Matching:
382
+ - **`tool`** — exact tool name match
383
+ - **`match`** — string match anywhere in the parameters
384
+ - **`path`** — glob pattern match on the `path` parameter
385
+
386
+ ## Continuous Learning
387
+
388
+ Rubyn learns from every session and gets smarter over time.
389
+
390
+ ### How it works
391
+
392
+ 1. **During conversation** — Rubyn saves preferences and patterns via `memory_write`
393
+ 2. **On session end** — extracts reusable patterns ("instincts") with confidence scores
394
+ 3. **On next startup** — injects top instincts and recent memories into the system prompt
395
+ 4. **Over time** — unused instincts decay, reinforced ones strengthen
396
+
397
+ ### Instinct lifecycle
398
+
399
+ ```
400
+ Session 1: You correct Rubyn → instinct saved (confidence: 0.5)
401
+ Session 2: Same pattern confirmed → confidence: 0.7
402
+ Session 3: Not used → confidence: 0.65 (decay)
403
+ Session 4: Reinforced again → confidence: 0.8
404
+ Session 10: Never used again → deleted (below 0.05)
405
+ ```
406
+
407
+ ### Feedback reinforcement
408
+
409
+ Rubyn detects your feedback and adjusts:
410
+ - **"yes that fixed it"** / **"perfect"** → reinforces recent instincts
411
+ - **"no, use X instead"** / **"that's wrong"** → penalizes and learns the correction
412
+
413
+ ## Web Tools
414
+
415
+ Rubyn can search the web and fetch documentation:
416
+
417
+ ```bash
418
+ rubyn > Search for how to set up Sidekiq with Rails 8
419
+ > web_search: query=Sidekiq Rails 8 setup guide
420
+
421
+ rubyn > Fetch the Sidekiq README
422
+ > web_fetch: url=https://github.com/sidekiq/sidekiq/blob/main/README.md
423
+ ```
424
+
425
+ ### Search Providers
426
+
427
+ Rubyn auto-detects the best available search provider based on your environment variables. No configuration needed — just set the key and it switches automatically.
428
+
429
+ | Provider | Env Variable | Free Tier | Notes |
430
+ |----------|-------------|-----------|-------|
431
+ | **DuckDuckGo** | *(none needed)* | Unlimited | Default. No API key required |
432
+ | **Tavily** | `TAVILY_API_KEY` | 1,000/mo | Built for AI agents. Includes AI-generated answer |
433
+ | **Brave** | `BRAVE_API_KEY` | 2,000/mo | Fast, good quality results |
434
+ | **SerpAPI** | `SERPAPI_API_KEY` | 100/mo | Google results via API |
435
+ | **Google** | `GOOGLE_SEARCH_API_KEY` + `GOOGLE_SEARCH_CX` | 100/day | Official Google Custom Search |
436
+
437
+ **Priority order:** Tavily > Brave > SerpAPI > Google > DuckDuckGo
438
+
439
+ To switch providers, just export the key:
440
+
441
+ ```bash
442
+ export TAVILY_API_KEY=tvly-xxxxxxxxxxxxx
443
+ rubyn-code # Now uses Tavily automatically
444
+ ```
445
+
446
+ ## Git Integration
447
+
448
+ Full git workflow without leaving the REPL:
449
+
450
+ ```bash
451
+ rubyn > What files have I changed?
452
+ > git_status
453
+
454
+ rubyn > Show me the diff
455
+ > git_diff: target=unstaged
456
+
457
+ rubyn > Commit these changes
458
+ > git_commit: message=Fix N+1 query in UsersController, files=all
459
+
460
+ rubyn > Review my branch before I open a PR
461
+ > /review
462
+ ```
463
+
464
+ ## Authentication
465
+
466
+ Rubyn Code uses your existing Claude subscription — no API keys needed.
467
+
468
+ ### How it works
469
+
470
+ 1. You log into Claude Code once (`claude` in terminal)
471
+ 2. Rubyn Code reads the OAuth token from your macOS Keychain
472
+ 3. It authenticates directly with the Anthropic API using your subscription
473
+
474
+ ### Fallback chain
475
+
476
+ | Priority | Source | How |
477
+ |----------|--------|-----|
478
+ | 1 | macOS Keychain | Reads Claude Code's OAuth token automatically |
479
+ | 2 | `~/.rubyn-code/tokens.yml` | Manual token file |
480
+ | 3 | `ANTHROPIC_API_KEY` env var | Standard API key (pay-per-use) |
481
+
482
+ ### Supported plans
483
+
484
+ Works with Claude Pro, Max, Team, and Enterprise subscriptions. Default model: **Claude Opus 4.6**.
485
+
486
+ ## Context Compression
487
+
488
+ Three-layer pipeline for infinite sessions:
489
+
490
+ 1. **Micro Compact** — runs every turn, replaces old tool results with placeholders (zero cost)
491
+ 2. **Auto Compact** — triggers at 50K tokens, saves transcript to disk, LLM-summarizes
492
+ 3. **Manual Compact** — `/compact` at strategic moments (between phases of work)
493
+
494
+ ## Task System
495
+
496
+ SQLite-backed DAG with dependency resolution:
497
+
498
+ ```
499
+ Task 1: Set up database schema
500
+ Task 2: Build API endpoints (blocked by: Task 1)
501
+ Task 3: Write integration tests (blocked by: Task 2)
502
+ ```
503
+
504
+ ## Memory
505
+
506
+ Three-tier persistence with full-text search:
507
+
508
+ - **Short-term** — current session
509
+ - **Medium-term** — per-project (`.rubyn-code/`)
510
+ - **Long-term** — global (`~/.rubyn-code/`)
511
+
512
+ ## MCP Support
513
+
514
+ Connect external tool servers via Model Context Protocol:
515
+
516
+ ```json
517
+ // .rubyn-code/mcp.json
518
+ {
519
+ "servers": {
520
+ "github": {
521
+ "command": "npx",
522
+ "args": ["-y", "@anthropic/github-mcp-server"]
523
+ }
524
+ }
525
+ }
526
+ ```
527
+
528
+ ## Configuration
529
+
530
+ ### Global config
531
+
532
+ `~/.rubyn-code/config.yml`:
533
+
534
+ ```yaml
535
+ model: claude-opus-4-6
536
+ permission_mode: allow_read
537
+ session_budget: 5.00
538
+ daily_budget: 10.00
539
+ max_iterations: 200
540
+ ```
541
+
542
+ ### Project config
543
+
544
+ `.rubyn-code/config.yml` (overrides global):
545
+
546
+ ```yaml
547
+ model: claude-sonnet-4-6
548
+ permission_mode: autonomous
549
+ ```
550
+
551
+ ## Data Storage
552
+
553
+ All data stored locally in SQLite:
554
+
555
+ | Location | Purpose |
556
+ |----------|---------|
557
+ | `~/.rubyn-code/config.yml` | Global settings |
558
+ | `~/.rubyn-code/tokens.yml` | Auth tokens (0600 permissions) |
559
+ | `~/.rubyn-code/rubyn_code.db` | Sessions, tasks, memories, costs |
560
+ | `~/.rubyn-code/RUBYN.md` | Global project instructions |
561
+ | `~/.rubyn-code/skills/*.md` | Global custom skills |
562
+ | `.rubyn-code/config.yml` | Project settings |
563
+ | `.rubyn-code/skills/*.md` | Project custom skills |
564
+ | `RUBYN.md` | Project instructions |
565
+
566
+ ## Development
567
+
568
+ ```bash
569
+ # Run tests
570
+ bundle exec rspec
571
+
572
+ # Run a specific test
573
+ bundle exec rspec spec/rubyn_code/agent/loop_spec.rb
574
+
575
+ # Interactive console
576
+ ruby -Ilib bin/console
577
+ ```
578
+
579
+ ## Project Structure
580
+
581
+ ```
582
+ rubyn-code/
583
+ ├── exe/rubyn-code # CLI entry point
584
+ ├── lib/rubyn_code/
585
+ │ ├── agent/ # Layer 1: Core agent loop
586
+ │ ├── tools/ # Layer 2: 18 tool implementations
587
+ │ ├── permissions/ # Layer 3: Tiered access control
588
+ │ ├── context/ # Layer 4: Compression pipeline
589
+ │ ├── skills/ # Layer 5: Skill loader
590
+ │ ├── sub_agents/ # Layer 6: Isolated child agents
591
+ │ ├── tasks/ # Layer 7: Task DAG
592
+ │ ├── background/ # Layer 8: Async execution
593
+ │ ├── teams/ # Layer 9: Agent teams
594
+ │ ├── protocols/ # Layer 10: Coordination
595
+ │ ├── autonomous/ # Layer 11: KAIROS daemon
596
+ │ ├── memory/ # Layer 12: Persistence
597
+ │ ├── observability/ # Layer 13: Cost tracking
598
+ │ ├── hooks/ # Layer 14: Event system
599
+ │ ├── mcp/ # Layer 15: MCP client
600
+ │ ├── learning/ # Layer 16: Continuous learning
601
+ │ ├── llm/ # Claude API client (OAuth + API key)
602
+ │ ├── auth/ # Token management (Keychain + file + env)
603
+ │ ├── db/ # SQLite connection & migrations
604
+ │ ├── cli/ # REPL, input handling, rendering
605
+ │ └── config/ # Settings management
606
+ ├── skills/ # 112 Ruby/Rails best practice docs
607
+ │ ├── ruby/ # Ruby language patterns
608
+ │ ├── rails/ # Rails framework conventions
609
+ │ ├── rspec/ # RSpec testing patterns
610
+ │ ├── design_patterns/ # GoF and Ruby patterns
611
+ │ ├── solid/ # SOLID principles
612
+ │ ├── refactoring/ # Refactoring techniques
613
+ │ └── ... # + code_quality, gems, minitest, sinatra
614
+ ├── db/migrations/ # 11 SQL migration files
615
+ └── spec/ # 48 RSpec test files (314 examples)
616
+ ```
617
+
618
+ ## License
619
+
620
+ MIT
@@ -0,0 +1,4 @@
1
+ CREATE TABLE IF NOT EXISTS schema_migrations (
2
+ version INTEGER PRIMARY KEY,
3
+ applied_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now'))
4
+ );
@@ -0,0 +1,16 @@
1
+ CREATE TABLE IF NOT EXISTS sessions (
2
+ id TEXT PRIMARY KEY,
3
+ project_path TEXT NOT NULL,
4
+ title TEXT,
5
+ status TEXT NOT NULL DEFAULT 'active' CHECK(status IN ('active','paused','completed')),
6
+ model TEXT NOT NULL DEFAULT 'claude-sonnet-4-20250514',
7
+ total_input_tokens INTEGER NOT NULL DEFAULT 0,
8
+ total_output_tokens INTEGER NOT NULL DEFAULT 0,
9
+ total_cost_usd REAL NOT NULL DEFAULT 0.0,
10
+ metadata TEXT DEFAULT '{}',
11
+ created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now')),
12
+ updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now'))
13
+ );
14
+
15
+ CREATE INDEX IF NOT EXISTS idx_sessions_project ON sessions(project_path);
16
+ CREATE INDEX IF NOT EXISTS idx_sessions_status ON sessions(status);
@@ -0,0 +1,16 @@
1
+ CREATE TABLE IF NOT EXISTS messages (
2
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
3
+ session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
4
+ role TEXT NOT NULL CHECK(role IN ('system','user','assistant')),
5
+ content TEXT,
6
+ tool_calls TEXT,
7
+ tool_use_id TEXT,
8
+ tool_name TEXT,
9
+ token_count INTEGER,
10
+ is_compacted INTEGER NOT NULL DEFAULT 0,
11
+ created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ','now'))
12
+ );
13
+
14
+ CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id);
15
+ CREATE INDEX IF NOT EXISTS idx_messages_role ON messages(session_id, role);
16
+ CREATE INDEX IF NOT EXISTS idx_messages_tool_use ON messages(tool_use_id);