Phronomy
⚠️ Development Notice This project is primarily developed and maintained by AI coding agents. As a result,
mainreceives frequent, large, and unannounced changes. External contributors should expect significant churn and potential conflicts at any time. We apologise for the instability this may cause.
Phronomy is a Ruby AI agent framework for stateful Agents, Workflows, Tools, context management, filtering, tracing, and multi-agent coordination. Large Language Model (LLM) access is provided through RubyLLM.
Phronomy is pre-1.0. Pin to a released gem version for production use rather than
tracking main directly.
Core concepts
- Agent — stateful, persistence-backed LLM agent with canonical execution history.
- Workflow — state-machine-driven application workflow with explicit events and wait states.
- Tool / Capability — callable application capability exposed to an Agent.
- EventLoop + FSMSession — the framework control plane for logical lifecycle coordination.
- OffloadPool — bounded operating-system-thread execution boundary for synchronous work that must not run on EventLoop.
- Task — thread-free completion handle for asynchronous Phronomy lifecycles.
- Journal / Context Policy / Manifest — canonical history plus per-LLM-call context selection.
See Features and Application Programming Interface (API) stability for the full feature matrix.
Installation
Add Phronomy to your Gemfile:
gem "phronomy"
Then run:
bundle install
Configure RubyLLM with the provider credentials and transport policy required by your application. Phronomy does not add another LLM transport retry/timeout layer.
RubyLLM.configure do |c|
c.openai_api_key = ENV["OPENAI_API_KEY"]
c.request_timeout = 120
c.max_retries = 3
end
See Getting started for installation details, optional dependencies, stateful Agent setup, streaming, and Workflow examples.
Quick start
class WebSearch < Phronomy::Agent::Context::Capability::Base
description "Search the web"
param :query, type: :string, desc: "Search query"
def execute(query:)
"Mock search result for: #{query}"
end
end
class ResearchAgent < Phronomy::Agent::Base
agent_definition id: "research-agent", version: 1
model "gpt-4o"
instructions "You are a research assistant. Use tools to answer questions."
tools(WebSearch => nil)
max_iterations 5
end
result = ResearchAgent.new.invoke("What happened in AI research this week?")
puts result[:output]
For non-blocking top-level use, call invoke_async and keep the returned
Phronomy::Task. Inside Phronomy lifecycle callbacks, do not block waiting for
another Task; continue through explicit events instead.
task = ResearchAgent.new.invoke_async("Research Ruby AI frameworks")
result = task.wait_result # top-level/external caller only
Runtime model
Phronomy uses one explicit lifecycle model:
Runtime
├─ EventLoop
│ └─ FSMSession
│ ├─ Agent
│ ├─ Workflow
│ ├─ ToolInvocation
│ └─ MultiAgent fan-out
├─ OffloadPool
└─ EventLoop-driven timers
Task = completion handle
Logical waiting remains in EventLoop/FSMSession state. Synchronous work that would block EventLoop uses the bounded OffloadPool. See Runtime and concurrency for the detailed contracts, timeout/cancellation semantics, metrics, and callback rules.
Documentation
- Getting started — installation, RubyLLM setup, Agent/Workflow basics, persistence, streaming.
- Features and API stability — public feature matrix and stability labels.
- Runtime and concurrency — EventLoop, FSMSession, Task, OffloadPool, cancellation, observability.
- MCP client — Model Context Protocol (MCP) integration and supported schema subset.
- Migration from 0.15-era APIs.
- 0.16 cleanup migration.
- Architecture Decision Records — design rationale and superseding decisions.
- CHANGELOG — current development and recent release history.
- Changelog archive: 0.14.0 and earlier.
Examples
Runnable examples covering major features are maintained in the phronomy-examples repository.
Development
After checking out the repository:
bin/setup
bundle exec rspec spec/phronomy
Integration tests can be run with:
bundle exec rspec spec/integration --tag integration
Contributing
Bug reports and pull requests are welcome. See CONTRIBUTING.md.
Security and privacy
- Provider credentials are handled by RubyLLM; Phronomy does not persist LLM API keys.
- Trace payloads are redacted by default when
trace_pii: false. - Tools and MCP servers are external trust boundaries; apply approval and application-specific policy to side-effecting capabilities.
PromptInjectionFilteris a useful baseline, not a complete untrusted-input defence.- Report vulnerabilities privately through GitHub Security Advisories rather than a public issue.
License
The gem is available as open source under the terms of the MIT License.