SelfAgency
SelfAgency is a mixin module that gives any Ruby class the ability to
generate and install methods at runtime via an LLM.
Key Features
|
|
Caution
This is an experiment. It may not be fit for any specific purpose. Its micro-prompting. Instead of asking Claude Code, CodeX or Gemini to create an entire application, you can use SelfAgency to generate individual methods. So far the experiments are showing good success with methods that perform math stuff on its input.
Installation
Add to your Gemfile:
gem "self_agency"Then run bundle install. See the Installation guide for LLM provider setup and requirements.
Quick Start
require "self_agency"
SelfAgency.configure do |config|
config.provider = :ollama
config.model = "qwen3-coder:30b"
config.api_base = "http://localhost:11434/v1"
end
class Foo
include SelfAgency
end
foo = Foo.new
foo._("an instance method to add two integers, return the result")
#=> [:add]
foo.add(1, 1) #=> 2See the Quick Start walkthrough for a complete step-by-step guide.
How to Use
SelfAgency is a Bottom-Up experimentation tool. Start in IRB, describe the behavior you need in plain language, test it with real inputs, inspect the generated source, and refine until the logic is right. Once your methods are proven, save them and wire them into your larger architecture.
Describe → Generate → Test → Inspect → Refine
↑ │
└──────────────────────────────────────────────┘
Read How to Use SelfAgency for a deeper discussion of Top-Down vs. Bottom-Up design and where SelfAgency fits in your workflow.
Features at a Glance
Generate multiple methods at once
names = foo._("create add, subtract, multiply, and divide methods for two integers")
#=> [:add, :subtract, :multiply, :divide]_() always returns an Array of Symbol method names. Full details →
Scopes
Generate instance methods (default), singleton methods, or class methods:
foo._("a method called greet that returns 'hello'", scope: :singleton)
foo._("a class method called ping that returns 'pong'", scope: :class)Source inspection and version history
View the generated source and track changes across regenerations:
puts foo._source_for(:add)
versions = Foo._source_versions_for(:add)Save generated methods to a file
Persist proven methods as a subclass in a Ruby source file:
foo._save!(as: :calculator)
# Writes calculator.rb with class Calculator < FooLifecycle hooks
Override on_method_generated to persist or log each generated method:
def on_method_generated(method_name, scope, code)
File.write("generated/#{method_name}.rb", code)
endConfiguration
SelfAgency.configure do |config|
config.provider = :ollama
config.model = "qwen3-coder:30b"
config.generation_retries = 3
config.logger = Logger.new($stdout)
endAll options → · Prompt templates →
Architecture
A two-stage LLM pipeline: Shape rewrites casual English into a precise spec, then Generate produces def...end blocks. Code passes through sanitization, validation, an optional retry loop, and sandboxed eval. Thread-safe via per-class mutex.
Full architecture overview → · Security model →
Errors
| Exception | Meaning |
|---|---|
SelfAgency::GenerationError |
LLM returned nil or communication failed |
SelfAgency::ValidationError |
Code is empty, malformed, or has syntax errors |
SelfAgency::SecurityError |
Dangerous pattern detected in generated code |
Development
bin/setup
rake testLicense
MIT License. See LICENSE.txt.