Every group orchestration challenge falls into two buckets: assembling specialized workers and combining their answers coherently. Flowork's agent groups are built on that reality — multiple focused agents, one synthesizer.
What is an agent group?
A group is a team of agents that attack one task together. Think of it like a colony — each ant does one small job, and a designated synthesizer brings the pieces together into a single result. The empirical lesson from multi-agent systems is that many small, sharp specialists beat one big do-everything agent.
When you create a group, you define:
- Members — a roster of agents (each can join only one group at a time)
- A synthesizer — a single agent that stitches member answers into the final reply, or "none" if raw results are enough
- The task — what the team should solve together
No matter how large your team is or how specialized each member, the group works through one fixed choreography: fan out the task to members in parallel, collect their answers, synthesize.
Creating and configuring a group
Start by hitting + Create on the Groups page, then supply an ID (unique handle) and a Name (editable later). The new group appears as a card.
On that card you'll see:
- Name & ID at the top; the name can be changed anytime
- Members — chips showing available agents; tick the ones you want in this group
- Synthesizer — a dropdown to pick one agent to combine the answers, or "none"
- Task — a text field for the orchestration prompt (e.g., "analyze this stock from three angles: technicals, fundamentals, sentiment")
- Save and 🗑 Delete buttons
Members can't overlap—an agent belongs to exactly one group. The synthesizer is itself an agent and can be a member too (though that's rarely the right design).
How orchestration flows
When you trigger a group, the kernel routes the single task to every member in parallel over the internal "loket bus", collects their answers, and if you've set a synthesizer, passes all answers plus the original task to the synthesizer for final assembly. The result is one combined response.
This pattern works because:
- Parallelism is free — members run concurrently, latency is the slowest member, not the sum
- Specialization is cheap — each agent can be tuned for one domain without bloating its prompt
- Recombination is predictable — the synthesizer sees both the task and all member outputs, so it can weigh conflicts or pick the strongest answer
- Modularity is real — you can swap a member agent or swap the synthesizer without rewriting anything
For no-code users
The simplest case needs zero code. Create a group, tick members, pick a synthesizer, write the task, hit Save. That's enough to run it from Schedule, Trigger, or the CLI.
For developers: custom orchestration
If you need non-standard flows — multi-phase coordination, dynamic member selection based on task content, weighted voting, or cascading sub-tasks — you'll write Go code.
A group under the hood is an agent built from a template. The coordinator's handle_message function receives the task and has full access to call(cap, args) to invoke members via the loket. The default template is dead simple:
// templates/group-template/main.go (simplified)
for _, member := range members {
answer := call("group.invoke", member_id, task)
answers = append(answers, answer)
}
if synthesizer != "none" {
final := call("group.invoke", synthesizer_id, task + "answers:" + answers)
return final
}
return answers
For richer patterns, start from templates/group-template/ (the minimal one) or templates/investment-group/ (a real multi-stage example), edit main.go to add phases, roles, or custom routing, then build as a normal WASM agent:
GOOS=wasip1 GOARCH=wasm go build -o agent.wasm .
The built agent is no different from any other — it just happens to call other agents as part of its logic.
Members are ordinary agents. A great group design is really about recruiting small, sharp specialists and wiring them together. An agent that does email, calendar, and web search is bloated and fragile. An agent that only does email — one model, one tool set, one doctrine — is reliable and reusable. Groups let you compose such agents without forcing each to be a all-in-one black box.
Real constraints and trade-offs
- Sequential synthesis: if your task is inherently iterative (e.g., each member refines the last answer), the synthesizer must run after you've already collected — you can't easily pipeline stages. For such flows, use a custom orchestration agent instead.
- No agent-to-agent messaging: members don't chat with each other; they all respond to the same task. If you need cross-talk, write a coordinator agent that routes custom messages.
- One synthesizer: groups aren't tree-shaped or DAG-shaped; they're flat — one fan-out, one fan-in. For complex topologies, build a custom orchestration agent.
- Membership is exclusive: an agent can't be a member of two groups at once. If you need an agent in multiple teams, clone it or refactor into a custom coordinator.
When to use groups, when to build custom orchestration
Use a group (no or minimal code) when:
- The task can be divided into independent subtasks (fact-checking, sentiment vs. technical analysis, price check from multiple exchanges)
- You want the same task sent to all members (not different instructions per member)
- Final synthesis is straightforward (concatenate, vote, pick the strongest)
- You're comfortable with parallelism at the member level
Build a custom orchestration agent when:
- You need multi-stage pipelines (member A's output feeds into member B)
- Members need different instructions based on the task
- The coordination logic is stateful or conditional
- You need cross-talk between members or dynamic member selection
Practical example: stock analysis group
Imagine you have three agents — one trained on technicals, one on fundamentals, one on social sentiment. A user asks, "should I buy Tesla?"
Create a group:
- Members: TechnicalAnalyst, FundamentalAnalyst, SentimentAnalyst
- Synthesizer: ConsensusBuilder (an agent that reads all three analyses and produces a unified recommendation)
-
Task:
"Analyze Tesla (TSLA) for a buy/hold/sell signal. Be concise."
Run the group. The kernel:
- Sends the task to TechnicalAnalyst, FundamentalAnalyst, and SentimentAnalyst in parallel
- Collects their three answers
- Feeds all three answers + the task to ConsensusBuilder
- Returns ConsensusBuilder's synthesis
Each specialist agent is lean and fast. The synthesis is intelligent because it sees the full picture. If you later swap out TechnicalAnalyst for a better version, everything else is untouched.
Scheduling and triggering groups
Groups work with Schedule (time-based automation) and Trigger (event-based automation) just like single agents. Set up a cron job to run your analysis group every morning, or wire a webhook so that when a price alert fires, the group evaluates the move.
Summary
Agent groups solve the composition problem in multi-agent systems: how to wire together a team of specialists, divide work fairly, and produce a coherent result. They're built on the loket architecture — the same capability-dispatch model that powers individual agents. No magic, no new runtime — just orchestration as a design pattern.
If your task fits the fan-out-then-synthesize shape, a group is fast to build and transparent to operate. If you need something stranger, the microkernel is always there: write an orchestration agent and call members however you like.
Flowork is open source — both products:
- 🤖 Flowork Agent (the self-hosted agent OS): https://github.com/flowork-os/Flowork_Agent
- 🛣️ Flow Router (the sovereign LLM gateway): https://github.com/flowork-os/flowork_Router
💬 Join the Flowork community on Telegram: https://t.me/+55oqrk75lc43YWE1
Top comments (2)
Agent groups formalize the part of multi-agent systems that ad-hoc setups get wrong first: membership and visibility. When any agent can message any agent, debugging a bad outcome means reconstructing an unbounded conversation graph after the fact. Groups bound that graph before the run starts.
The next primitive these orchestration layers need is one operating systems landed on decades ago: group membership grants capabilities, and capabilities are inspectable before execution rather than reconstructed from logs after.
Exactly — bounding membership before the run is the part most setups bolt on last, and by then the unbounded graph already exists and you're stuck doing log archaeology.
The capability angle is where we've been taking Flowork: every agent is a WASM sandbox that can only reach the system through explicit capability grants — a call(cap, args) contract the kernel enforces per-module — and a group is a declared roster, not an emergent mesh. So membership and reachability are both static facts you can read up front, not reconstructed from logs.
Where I think you're right that it needs to go next: composing those per-agent grants up to the group level into a single manifest you can audit before execution — "this group, with these members, touches exactly these capabilities, and nothing else." Per-agent inspectability exists today; group-level inspectability is the missing primitive.
Curious how you'd model the composition: union of member capabilities, or a separate group-level grant that members intersect with? That intersect-vs-union choice feels like where the security story is actually won or lost.