Repository navigation
Description
Configurable Orchestration Workflows
Problem
Today buzz workflows runs a linear step list with a fixed action set
(send_message | send_dm | set_channel_topic | add_reaction | call_webhook | request_approval | delay).
There is no step that invokes an agent, no branching, no loops, and no first-class
run state for artifacts/progress. Multi-pass processes (e.g. the IMPL workflow: Architect →
Plan Critic → Builder → Inspector → CI → merge) therefore can't be expressed natively — they
require a bespoke controller agent per process. Every new process = new custom code.
Goal
A user-defined, configurable orchestration engine where a workflow is a declarative graph of
steps, each step assigned to a dedicated agent or a human, with the engine tracking run
progress, chat, and artifacts across steps — reusable across many process types
(IMPL, bug triage, review-only, "scan Slack/email → summarize → act").
In scope
- Step assignees: a step targets a specific agent (by pubkey/role) OR a human (approval/input).
- Agent-invocation step: a real step type that dispatches a prompt to an assignee and
waits for a structured result (not fire-and-forget send_message). - Control flow: conditional branching + bounded loops (revise/rebuild) with a max-iteration cap.
- Run state & artifacts: each run tracks status per step, inputs/outputs, and attached
artifacts (plans, diffs, PR ids, summaries) that later steps can read. - Human-in-the-loop: approval/input gates that pause a run and resume on human action
(extends today'srequest_approval). - Progress & chat surface: a run is observable — current step, history, per-step
responses/artifacts — visible in-channel. - Templates: named, versioned workflow definitions users author and instantiate.
Out of scope (for v1)
- Arbitrary code execution inside steps (keep steps declarative; escape hatch =
call_webhook). - Cross-channel orchestration.
- A visual builder (YAML/JSON first; UI later).
Proposed shape (for design, not final)
- Definition: extend the workflow YAML with
assignee(agent/human/role), a new
invoke_agentaction (prompt + expected structured output schema/verdict grammar), and
on/whenedges for branching + aloopconstruct withmax_iterations. - Run model: persistent run object keyed by run id —
steps[]with
status,assignee,input,output,artifacts[],attempts. Verdicts are structured
tokens (e.g. APPROVED/REVISE/CLEAN) the engine branches on. - Artifacts: typed references (PR event id, plan doc, message id, external URL) so steps
hand real objects forward, not prose. - Assignment/dispatch: engine posts the step to its assignee and blocks the run on that
step until a structured result or human action arrives; bounded loops re-dispatch.
Example workflows this must support
- IMPL — Architect(plan) → Plan Critic(loop) → Builder(draft PR) → Inspector(loop) → CI → captain approval+merge. (See thread root for full spec + WORKFLOW STAMP.)
- Bug triage — intake → classify(agent) → severity gate(human) → assign → track.
- Review-only — diff_posted → reviewer agent(s) → verdict → human sign-off.
- Scan → summarize → act — schedule → Slack/email scan(agent) → summarize(agent) →
proposed actions → human approval → execute.
Key risks / decisions to settle in design
- Loops & branching are the hard part — the current engine is linear. Adding an
invoke_agentstep that blocks on a structured result is the enabling primitive; loops
and branches build on it. Needs a bounded-iteration cap to avoid silent stalls. - Where run state lives (relay events vs a store) and how artifacts are referenced durably.
- Assignee resolution: agent-by-role vs by-pubkey; what happens when an assignee is offline.
- Authorization: today
call_webhookneeds owner/admin — decide the permission model for
agent-invocation and human-gate steps. - Backward compatibility with existing linear workflows.
Suggested milestones
- M1:
invoke_agentstep + structured-result wait + run/artifact state (unlocks single-pass
agent workflows: review-only, scan→summarize). - M2: branching + bounded loops +
max_iterations(unlocks IMPL, bug triage). - M3: human-in-the-loop input steps beyond approval; progress/chat surfacing in-app.
- M4: templates (author/version/instantiate) + assignee-by-role.
Open questions for the team
- Definition format: keep YAML, or move to a richer schema?
- Do we build this into the existing
buzz workflowsengine, or a new orchestration service
that emits/consumes workflow events? - Priority order of the four example workflows — which lands first as the proving ground?
Activity
RegardV commentedon Jul 31, 2026
Strong +1 on step assignees specifically. One piece of evidence for that bullet that isn't in the issue yet: it's worth looking at how a workflow reaches an agent today, because the current mechanism is string matching on display names.
resolve_mention_pubkeysincrates/buzz-relay/src/workflow_sink.rsreverse-parses@Nameout of workflow message text into theptags that ACP agent-wake (event_mentions_agent) is gated on. Its own doc comment is explicit that this is load-bearing:And it documents the constraints that follow:
The code is careful and the conservatism is clearly deliberate — but it means dispatch today has properties a workflow author can't see:
display_namecan't be woken at all — the candidate list is built withfilter_map(|u| { let name = u.display_name?; ... }), so it's dropped before matching runs;In each case the kind:9 is still emitted; only the
ptag is missing. So the run looks successful and the agent simply never wakes, which is the hardest shape of failure to debug from the outside.A structured
assignee(pubkey or role, as proposed) turns all four into authoring-time validation errors instead of silent runtime no-ops. That seems worth calling out as motivation independent of the orchestration engine itself — it's a correctness argument, not just an ergonomics one.HashMac commentedon Aug 3, 2026
Adding field evidence for two requirements that should be explicit in the run contract: durable recovery after connectivity loss, and structured cross-channel handoffs.
In a four-channel research mission with several managed agents, I observed three failure shapes:
STARTEDbut produced no terminal result, leaving downstream reviewers waiting indefinitely;These are not prompt-quality problems. A workflow engine needs to distinguish “temporarily unreachable” from “terminally failed” and own the continuation.
Current-main details make the gap concrete:
RunStatushaspending | running | waiting_approval | completed | failed | cancelled, but no retryable/paused state.execute_from_stepis an approval-resume path; there is no general lease-expiry or reconnect recovery path.delayis an in-memory sleep capped at 270 seconds, with scheduled resume still noted as future work.get_workflow_runscurrently returns an empty list because authoritative run state is not yet reconstructible for the client.Suggested durable-run contract:
run_id,step_id,attempt_id, parent/child IDs and an idempotency key.paused_networkorretry_scheduled—notfailed.parent_run_id,child_run_id, source channel, step, verdict and artifact references. The parent workflow should subscribe by run ID, not rely on display-name mentions.A minimal status model could be:
queued | running | waiting_agent | waiting_human | paused_network | retry_scheduled | completed | failed_terminal | cancelledCross-channel orchestration does not need a visual builder in v1.
invoke_agentcan accept an optional destinationchannel, while callback routing remains keyed to the parent run. That would let specialist channels keep their context without making a human copy status between them.Incident-shaped acceptance tests:
The same-ID outbound durability work in #4443 looks like a useful transport primitive, but transport recovery alone is not workflow recovery. I would suggest adding a durability milestone before branching/loops, then layering cross-channel callbacks onto the structured-result mechanism.
loganrenz commentedon Aug 4, 2026
A supervised v0.5.4 delivery trial provides a concrete minimal workflow for M1/M2 and shows where chat-only orchestration currently leaks work to the human.
Trial shape
One team mention assigned:
The workflow completed successfully against
narduk-enterprises/operator-portalissue #62 / draft PR #87:bdf115d…passed repository validation and GitHub CI;Signed-off-bytrailer and retained a dead test construct;d03c29b…, reran focused gates, and force-with-lease pushed;What the human still had to orchestrate
implementing,validating,waiting_review,revision_required, orpassed; that state lived in prose and operator attention.PASS/FAIL) but not an engine-owned callback that could dispatch the next step automatically.Minimal acceptance scenario suggested by this run
A first
invoke_agentworkflow fixture could encode exactly this loop:implement -> validate -> immutable handoff -> review -> (FAIL: repair with new SHA, bounded retry) | (PASS: waiting_human)The run should persist agent identity, worktree/branch, current immutable SHA, validation receipts, PR/artifact URL, attempt count, and mutation authority. A stalled agent should become visibly retryable rather than silently depending on another mention. The PASS state must not imply merge or deploy authorization.
This is consistent with the durable recovery evidence already added above, but contributes a completed code-delivery loop where an independent reviewer caught a real policy defect despite green CI. It demonstrates that
invoke_agentplus structured verdicts and bounded retries can deliver immediate value before a visual workflow builder exists.No private channel content, credential values, or raw transcripts are included.
samiriasbeck commentedon Aug 10, 2026
Field evidence from a supervised two-agent review exposed one semantic detail that would be useful to make explicit in M2:
N cyclesshould mean exactly N completed confrontations, not N messages and not N total model turns.For a two-agent debate, one cycle is complete only after:
The run should fail closed rather than count a cycle when either participant is missing, the artifact digest changes without an explicit revision transition, a response is only transport-accepted, or the callback cannot be correlated to
(run_id, step_id, attempt_id, cycle).Suggested bounded-debate shape for the existing proposal:
I would keep this as syntax sugar over the
invoke_agent+ structured-callback primitive rather than a second execution engine. The durable run state should expose:queued -> dispatched -> accepted -> running -> responded | failed | timed_outper participant turn;cycle_current / cycle_target;completed_exact_cycles,human_stopped,participant_failed,timeout,policy_denied);The same run contract can carry a channel context envelope instead of relying on prompt prose:
{ "channel_id": "<uuid>", "trigger_event_id": "<event-id>", "recent_event_ids": ["..."], "canvas_revision": "<event-id-or-null>", "summary_revision": "<event-id-or-null>", "task_refs": ["..."], "attachment_receipts": ["..."], "context_generated_at": "<timestamp>" }Important boundary: the context envelope must be assembled only from events the assignee can read in that channel. A workflow owner must not be able to use its standing authority to inject content from another private channel into the assignee's turn.
Acceptance cases I would add before enabling loops:
This builds directly on the
invoke_agent, bounded-loop, artifact and durable-recovery direction already described here, while providing a concrete proving workflow for M1/M2.feat(routing): capacity facts per pool and a deterministic dispatcher