|
1 | | -# PITCH: `ruby_llm-team` — the delegation primitive RubyLLM won't ship, as a gem |
| 1 | +# PITCH: `ruby_llm-team` |
2 | 2 |
|
3 | | -One sentence: **a `RubyLLM::Team` is the one multi-agent primitive that plain Ruby cannot |
4 | | -express on its own — letting the *model* choose which named coworker to route to at |
5 | | -runtime — and it belongs in a small extension gem, not in RubyLLM core and not inside a |
6 | | -CrewAI-style orchestration framework.** |
| 3 | +`ruby_llm-team` packages the repeated plumbing around named RubyLLM coworkers: |
| 4 | +delegation tools, exact result handoffs, bounded calls, concurrent review, and an |
| 5 | +inspectable collaboration record. It is a small extension to RubyLLM, not a process |
| 6 | +engine. |
7 | 7 |
|
8 | | -This document grounds that claim in the rejection of PR #891, the maintainer's stated |
9 | | -philosophy, the CrewAI model and its community pain, and RubyLLM's own issue history. |
| 8 | +## Why a separate gem |
10 | 9 |
|
11 | | ---- |
| 10 | +RubyLLM's Agentic Workflows guidance intentionally uses ordinary Ruby for sequencing, |
| 11 | +routing, parallel work, fan-in, and evaluator/reviser loops. The maintainer closed the |
| 12 | +original Team contribution to RubyLLM core for that reason: the demonstrated workflows |
| 13 | +did not justify another core abstraction. |
12 | 14 |
|
13 | | -## 1. The seed: why this gem exists |
| 15 | +That decision sets the boundary for this gem. Team must remove repeated integration code |
| 16 | +without taking workflow policy away from the application. |
14 | 17 |
|
15 | | -PR [#891](https://github.com/crmne/ruby_llm/pull/891) ("Add RubyLLM::Team for multi-agent |
16 | | -collaboration") was closed by the maintainer. The rejection is the single most important |
17 | | -fact about this gem, because it defines the *correct* scope: |
| 18 | +## What the CrewAI review actually shows |
18 | 19 |
|
19 | | -> "This does not belong in the library. The existing Agentic Workflows documentation |
20 | | -> already shows multi-agent sequencing, routing, handoffs, parallel work, and fan-in |
21 | | -> using plain Ruby and the existing Agent and Tool APIs. Those examples are clearer, use |
22 | | -> less code, and do not require adding another abstraction or public API to RubyLLM." |
23 | | -> — [crmne, PR #891 comment](https://github.com/crmne/ruby_llm/pull/891#issuecomment-5435551502) |
| 20 | +CrewAI offers two related layers: |
24 | 21 |
|
25 | | -Read carefully. The maintainer did **not** say the idea is bad. He said: |
| 22 | +- **Crews** organize autonomous agents into sequential or hierarchical processes. |
| 23 | +- **Flows** give the application explicit, event-driven control over state, branches, and |
| 24 | + execution paths. |
26 | 25 |
|
27 | | -1. The **workflow patterns** (sequencing, routing, handoffs, parallel, fan-in) are already |
28 | | - well served by plain Ruby + Agent + Tool. Adding a process engine would be worse. |
29 | | -2. A new abstraction does not belong in **core**. |
30 | | -3. If a concrete capability can't be expressed with existing APIs, open an issue first. |
| 26 | +CrewAI tasks can name an agent, expected output, prior task context, guardrails, and |
| 27 | +asynchronous execution. A later task that depends on asynchronous tasks forms a clear |
| 28 | +fan-out/fan-in boundary. These are useful collaboration mechanics, independent of |
| 29 | +CrewAI's larger framework. |
31 | 30 |
|
32 | | -`ruby_llm-team` answers all three. It adds **no process, no scheduler, no graph**. It is a |
33 | | -thin tool-layer. And it is a **gem**, not a core addition — precisely the escape hatch the |
34 | | -maintainer's "does not belong in the library" leaves open. |
| 31 | +The review does **not** support describing CrewAI as simply rigid or claiming that its |
| 32 | +framework decides every execution path. CrewAI itself recommends Crews for autonomous |
| 33 | +work, Flows for deterministic work, and a hybrid for applications needing both. |
35 | 34 |
|
36 | | ---- |
| 35 | +## What Team adopts |
37 | 36 |
|
38 | | -## 2. The two ways, compared |
| 37 | +- Named specialists with explicit responsibilities. |
| 38 | +- Exact outputs from completed work as inputs to dependent work. |
| 39 | +- Concurrent execution for independent tasks, followed by a synchronization barrier. |
| 40 | +- Artifact-preserving reviewer handoffs with application-owned revision limits. |
| 41 | +- Visible call limits, errors, inputs, and results. |
| 42 | +- A choice between application-directed calls and model-directed delegation tools. |
39 | 43 |
|
40 | | -### The RubyLLM way (maintainer's stance, current docs) |
| 44 | +These mechanics map naturally to Ruby agents, tools, threads, and fibers. They do not |
| 45 | +require a second workflow language. |
41 | 46 |
|
42 | | -Orchestration is **ordinary Ruby**. `Agent` is a configured chat; `Tool` is a capability; |
43 | | -the docs show sequential, routing, handoff, parallel, fan-in, and evaluator-optimizer as |
44 | | -small plain-Ruby classes. Applications own task order, dependencies, persistence, and |
45 | | -resume. `RubyLLM.workflow` only adds instrumentation correlation — it does not take over |
46 | | -execution. |
| 47 | +## What Team deliberately leaves out |
47 | 48 |
|
48 | | -Strengths: total flexibility, nothing hidden, debuggable, idiomatic, durable (the loop is |
49 | | -interruptible and resumable). Weakness: every team re-writes the same delegation boundary |
50 | | -by hand. |
| 49 | +- `Crew` / `Task` / `Process` or graph DSLs. |
| 50 | +- YAML workflow definitions and generated project structure. |
| 51 | +- A built-in hierarchical manager or automatic planner. |
| 52 | +- Framework-owned state persistence, scheduling, deployment, or remote transport. |
| 53 | +- Built-in memory, knowledge stores, RAG, or MCP clients. |
| 54 | +- Hidden retry, model-selection, or concurrency policy. |
| 55 | +- Runtime quality claims based only on an LLM judge. |
51 | 56 |
|
52 | | -### The CrewAI way |
| 57 | +Those capabilities can be valuable, but RubyLLM, ordinary Ruby, and focused ecosystem |
| 58 | +gems already provide composition points for them. Adding them to Team would turn a small |
| 59 | +collaboration primitive into a competing agent platform. |
53 | 60 |
|
54 | | -`Crew` / `Agent` / `Task` / `Process` abstractions. Agents declare role/goal/backstory; |
55 | | -tasks declare expected output; the crew runs a `sequential` or `hierarchical` process |
56 | | -(hierarchical needs a manager LLM). Simple to explain, fast to prototype. |
| 61 | +## The product boundary |
57 | 62 |
|
58 | | -Strengths: approachable, opinionated, quick demos; CrewAI reports enterprise adoption and |
59 | | -"14x less code" vs graph frameworks. Weakness: a fixed process model that is **not very |
60 | | -flexible** — the exact tradeoff the user named. |
| 63 | +Team owns: |
61 | 64 |
|
62 | | -### The decisive evidence |
| 65 | +- a named coworker registry; |
| 66 | +- `delegate_work` and `ask_question` tools; |
| 67 | +- per-run collaboration state and exact handoffs; |
| 68 | +- immutable named artifacts, revision lineage, and a thin Run API; |
| 69 | +- atomic call budgets; |
| 70 | +- thread or fiber fan-out/fan-in; |
| 71 | +- normalized errors, results, and collaboration traces. |
63 | 72 |
|
64 | | -CrewAI's own engineering blog, after "2 billion agentic workflows", lands on the **RubyLLM |
65 | | -position**, not the Crew abstraction: |
| 73 | +The application owns task dependencies, conditional policy, quality gates, revision and |
| 74 | +escalation limits, persistence, authorization, cancellation, and approvals. A model may |
| 75 | +choose coworkers through `session.tools`; explicit workflows may call `session.ask` and |
| 76 | +`session.parallel` directly. |
66 | 77 |
|
67 | | -> "Architecture choices compound fast... separating the predictable from the |
68 | | -> unpredictable. Having deterministic workflows handling the structure, and agents |
69 | | -> deployed strategically where judgment actually matters." |
70 | | -> |
71 | | -> "Many engineers regret graph-based architectures... too many abstraction layers stacked |
72 | | -> on top of each other... when something breaks, the engineers dig through multiple |
73 | | -> indirections just to try finding which prompt or tool caused it." |
74 | | -> — [Lessons From 2 Billion Agentic Workflows](https://blog.crewai.com/lessons-from-2-billion-agentic-workflows/) |
| 78 | +## Evaluation boundary |
75 | 79 |
|
76 | | -The community reports the same friction: |
| 80 | +Runtime validators protect production invariants such as Ruby syntax and real APIs. |
| 81 | +Tribunal is an optional test-time grader for relevance, faithfulness, hallucination, and |
| 82 | +regression evaluation. Its report is evidence about a saved artifact; it is not a Team |
| 83 | +coworker, runtime gate, or telemetry system. |
77 | 84 |
|
78 | | -- r/crewai: "Overwhelmed with limitations... outdated dependencies, slow performance." |
79 | | -- r/AI_Agents: "it gets fragile and you lose fine-grained control" in production. |
80 | | -- r/LangChain: "LangGraph and CrewAI are overcomplicating agents... So I abandoned these |
81 | | - libraries, as a bonus dropped the necessity to use Python in production." |
82 | | -- r/AI_Agents "Who's using CrewAI really?": few teams report production use. |
| 85 | +## Evidence standard |
83 | 86 |
|
84 | | -**Conclusion: do not ship a CrewAI-style `Crew`/`Task`/`Process` abstraction.** It would |
85 | | -contradict the maintainer's philosophy, the docs, and CrewAI's own hard-won lessons. The |
86 | | -gem's job is the *opposite*: give Ruby developers the one missing low-level primitive and |
87 | | -let them keep orchestration in plain Ruby. |
| 87 | +Product decisions should rely on current primary documentation, source code, and observed |
| 88 | +behavior. Anonymous community complaints may suggest questions to investigate, but they |
| 89 | +are not sufficient evidence for permanent scope decisions. |
88 | 90 |
|
89 | | ---- |
| 91 | +## Sources |
90 | 92 |
|
91 | | -## 3. Shared requests and pains (grounding) |
92 | | - |
93 | | -These are the signals that a delegation primitive is genuinely wanted, from RubyLLM's own |
94 | | -issue tracker and the broader community: |
95 | | - |
96 | | -| Signal | Source | What it says | |
97 | | -|---|---|---| |
98 | | -| Multi-agent is wanted, but not as transport | [#670 A2A protocol](https://github.com/crmne/ruby_llm/issues/670) (declined, `not_planned`) | People want multi-agent; maintainer drew the line at external transport. **Local delegation is the acceptable scope.** | |
99 | | -| Team idea itself | [#891](https://github.com/crmne/ruby_llm/pull/891) | Rejected on process/scope, not on value. The code was correct and fully tested (17 specs, 97.74% coverage). | |
100 | | -| Long-running, resumable work | [#635 "Interrupting the agentic loop"](https://github.com/crmne/ruby_llm/issues/635) (completed) | Real pain: multi-step loops that must pause/resume across deploys. A team that composes with durable agents fits this. | |
101 | | -| The "one more abstraction" fatigue | Maintainer's rejection; CrewAI blog; community threads | Nobody wants another rigid framework. The gem must stay a primitive, not a platform. | |
102 | | -| Ruby landscape gap | langchain.rb (huge/complex), FlowNodes (minimalist) | No Ruby-idiomatic, provider-agnostic multi-agent delegation primitive exists. RubyLLM is the natural host ecosystem. | |
103 | | - |
104 | | -The through-line: **Ruby developers want multi-agent capability without sacrificing |
105 | | -control.** CrewAI-style frameworks sell the former and tax the latter. A small gem that |
106 | | -sells the primitive and leaves control alone is the gap. |
107 | | - |
108 | | ---- |
109 | | - |
110 | | -## 4. What the gem is, and is not |
111 | | - |
112 | | -### Is |
113 | | - |
114 | | -- `RubyLLM::Team` — a named coworker registry. |
115 | | -- Two ordinary `RubyLLM::Tool`s the model calls at runtime: `delegate_work` and |
116 | | - `ask_question`. The model, not the developer, picks the coworker. |
117 | | -- Recoverable error contract (`{ error: ... }`), shared `context:`, attachment |
118 | | - round-tripping, class-vs-instance lifecycle, snapshot concurrency safety. |
119 | | -- Composes with the existing RubyLLM way: plain-Ruby workflow classes, durable agents, |
120 | | - `RubyLLM.workflow` instrumentation. |
121 | | - |
122 | | -### Is not |
123 | | - |
124 | | -- Not a `Crew`/`Task`/`Process` engine. No sequential/hierarchical process, no scheduler, |
125 | | - no executor, no graph. |
126 | | -- Not an A2A transport. No host-boundary communication. |
127 | | -- Not a replacement for the Agentic Workflows patterns — those stay in plain Ruby, per the |
128 | | - maintainer. |
129 | | - |
130 | | -The differentiator in one line: **Team is where the model decides; the workflow is where |
131 | | -the developer decides.** CrewAI lets the framework decide both; plain Ruby leaves both to |
132 | | -you; this gem takes only the part the model must own. |
133 | | - |
134 | | ---- |
135 | | - |
136 | | -## 5. The pitch |
137 | | - |
138 | | -> RubyLLM gives you one beautiful API for every provider, and says "orchestrate with |
139 | | -> plain Ruby." That's right — until you want the *model* to route work to a named |
140 | | -> specialist at runtime. Today every team hand-rolls that delegation boundary: a registry, |
141 | | -> two tool classes, an error contract, attachment handling. `ruby_llm-team` is that |
142 | | -> boundary, extracted, tested, and composable — so your orchestration stays plain Ruby and |
143 | | -> the model's delegation stays first-class. |
144 | | -> |
145 | | -> - **For RubyLLM users:** one line of setup, two tools, no framework. |
146 | | -> - **For the maintainer's philosophy:** no new abstraction in core, no process engine, |
147 | | -> no transport — just a Tool boundary that plain Ruby couldn't express. |
148 | | -> - **For the market:** the Ruby gap between "single agent" and "crew" — without the crew's |
149 | | -> rigidity. |
150 | | -
|
151 | | ---- |
152 | | - |
153 | | -## 6. Sources |
154 | | - |
155 | | -- Maintainer rejection: https://github.com/crmne/ruby_llm/pull/891#issuecomment-5435551502 |
156 | | -- RubyLLM Agentic Workflows docs: `docs/_advanced/agentic-workflows.md` (working tree) |
157 | | -- CrewAI lessons: https://blog.crewai.com/lessons-from-2-billion-agentic-workflows/ |
158 | | -- RubyLLM issues: #670 (A2A, declined), #635 (interrupt loop), #891 (Team), #889 (JSON format) |
159 | | -- Community: r/crewai, r/AI_Agents, r/LangChain threads (linked in section 2) |
| 93 | +- [RubyLLM Agentic Workflows](https://rubyllm.com/agentic-workflows/) |
| 94 | +- [RubyLLM Team PR discussion](https://github.com/crmne/ruby_llm/pull/891) |
| 95 | +- [CrewAI introduction: Crews and Flows](https://docs.crewai.com/core-concepts/Agents) |
| 96 | +- [CrewAI tasks and asynchronous context](https://docs.crewai.com/en/concepts/tasks) |
| 97 | +- [CrewAI source](https://github.com/crewAIInc/crewAI) |
| 98 | +- [RubyLLM ecosystem](https://rubyllm.com/ecosystem/) |
0 commit comments