✨ feat: collaboration substrate for RubyLLM multi-agent runs - #3
Merged
Conversation
pftg
force-pushed
the
vcr-failure-integration
branch
from
August 28, 2026 12:05
d58bf59 to
32ed0ea
Compare
Team coordinates several RubyLLM agents through one auditable run: named immutable artifact versions with explicit as:/from: handoffs, an atomic call budget bounded by default, thread and fiber fan-out, normalised failures, and a trace recording the exact prompt every coworker received. It stays a small library — your workflow remains ordinary Ruby, and models, prompts, schemas and retries stay with RubyLLM. Correctness the library owns because hand-rolled versions get it wrong, each reproduced before it was fixed: - Artifact versions are reserved at submission under the session lock, so artifact(name) is deterministic when parallel work completes out of order, and a failed call leaves a gap rather than renumbering. - Non-StandardError crashes finalise their call and re-raise instead of leaving it :running with a burned budget slot; fiber siblings settle before a crash propagates; thread joins cannot mask the first failure. - A coworker delegating into its own call fails clearly rather than recursing 51 levels deep, whether registered as a class or instance. - Relayed results carry a per-session random fence, so a coworker — or a fetched web page speaking through one — cannot forge a handoff from a coworker that never ran. - A run is bounded by default. Every framework that loops on paid calls ships a cap; this one claimed spend-bounding as its headline while shipping unbounded. Five examples, smallest first: simple_team (no API key), code_review (parallel fan-out, verdict computed in Ruby because a free model will write "approve" above the injection it just reported), topic_analyst, decision_panel (no Ruby orchestration — a lead model chooses whom to consult), and the seven-pass blog with bounded gates, escalation to a stronger writer, a cold reader that sees only the finished article, and citation provenance checked by comparing strings rather than asking a model. editorial_pipeline composes two teams in plain Ruby and lets the panel argue the analyst's shortlist. Quality policy stays in the examples: deterministic checks are limited to defects a reader cannot forgive, because failing a run over a word count discards writing that cost real money. Docs collapse six roadmap drafts and three contradictory ADRs into docs/ROADMAP.md and docs/DECISIONS.md, which carries the measurement behind every refusal and a known-weaknesses section. 98 examples, RuboCop clean, Ruby 3.1-4.0 in CI, three VCR cassettes replayed without an API key, and a gem package of exactly seven files. Claude-Session: https://claude.ai/code/session_01EtHLQMFyPQEQHwwvVhUdGK
pftg
force-pushed
the
vcr-failure-integration
branch
from
August 28, 2026 12:30
27c679e to
9a4dcf2
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this is
RubyLLM::Teamcoordinates several RubyLLM agents through one auditable run: namedartifact handoffs, a shared call budget, safe fan-out, and a trace showing the exact prompt
every agent received.
It is a small library, not a framework — 658 lines, one runtime dependency, and your workflow
stays ordinary Ruby.
Why you would install it
You do not need it for one agent, or two in a straight line. You start needing it when several
agents share work and you have to answer "which version did the editor actually review?" and
"why did this run cost 40 calls?"
as:/from:handoffsThread.newper agent and a join that swallows a failurerescue => ein six shapesCollaborationError, typedBudgetExceededErrorReview guide
Four commits, smallest surface first:
93c3b67library + packaging — the whole public API. Start atlib/ruby_llm/team.rb.76d4190specs — what a reader cannot verify by inspection: budget reservation acrossthreads, artifact ordering under out-of-order completion, crash handling on both
schedulers, re-entrancy, handoff forgery.
fa65680examples — readexamples/code_review/first (110 lines, exercises the wholelibrary).
examples/blog/is production-scale and deliberately the largest.32ed0eadocs —docs/DECISIONS.mdis the fastest way to judge scope: it carries themeasurement behind every refusal, and a known-weaknesses section.
Correctness worth a second look
Each of these was reproduced before it was fixed, not inferred:
artifact(name)is deterministic when parallel work completes out of order.
coworker delegating into itself recursed 51 levels deep. Now a property of the role,
tracked fiber-locally so concurrent same-role work stays legal.
(or a fetched web page speaking through one) could fabricate a handoff from a coworker that
never ran. Each result now carries a per-session random fence.
max_callsis bounded by default. Every framework that loops on paid calls ships a cap;this one claimed spend-bounding as its headline while shipping unbounded.
Deliberately not here
No graph DSL, YAML workflows, or role/backstory metaphors. No memory, RAG, MCP, or search. No
dashboards or persistence —
ruby_llm-agentsowns that Rails layer and Team composes insideit. Quality loops stay in application Ruby:
refine/repairwere built, measured, and removedbecause upstream teaches the same loop in fewer lines and only one domain ever needed them.
Verification
gem buildproduces exactly 7 files (lib, README, CHANGELOG, LICENSE)Known weaknesses
Recorded in
docs/DECISIONS.mdrather than left for a reviewer to find: a budget boundsdelegation hops rather than provider spend (
ruby_llmhas no internal tool-call cap);exhaustion raises on the Ruby path but returns a hash on the tool path; mutual recursion across
threads defeats the re-entrancy guard; run-total token usage sums across models; and the blog
example is larger than the code it saves.
The API is pre-1.0 and moved late — artifact ordering, error types, trace serialization, and
the read-side accessors all changed shortly before this branch settled.