Public catalog of PubSub events emitted on the run-scoped topic
"council_ex:run:#{run_id}". Stable extension surface as of v0.7.
Subscribing
:ok = CouncilEx.PubSub.subscribe("council_ex:run:#{run_id}")
receive do
{:run_started, ^run_id, council_module, input} -> ...
{:round_started, ^run_id, round_name, idx} -> ...
{:member_started, ^run_id, round_name, member_id} -> ...
{:member_token, ^run_id, round_name, member_id, %CouncilEx.StreamChunk{}} -> ...
{:tool_call_request, ^run_id, round_name, member_id, %CouncilEx.ToolCall{}} -> ...
{:tool_call_result, ^run_id, round_name, member_id, %CouncilEx.ToolCallResult{}} -> ...
{:member_completed, ^run_id, round_name, member_id, %CouncilEx.MemberResult{}} -> ...
{:round_completed, ^run_id, round_name, %CouncilEx.RoundResult{}} -> ...
{:run_completed, ^run_id, %CouncilEx.Result{}} -> ...
{:run_failed, ^run_id, [%CouncilEx.Error{}, ...], %CouncilEx.Result{}} -> ...
endOrder
:run_started
├── :round_started (round 1)
│ ├── :member_started × N
│ ├── :member_token × M (during streaming members)
│ ├── :tool_call_request × K (during tool-calling members)
│ ├── :tool_call_result × K
│ ├── :member_completed × N
│ └── :round_completed
├── :round_started (round 2)
│ └── ...
└── :run_completedOrdering is guaranteed within a single run because broadcasts originate
from a single RunServer process serially. Across rounds: strictly
ordered. Within a round: members may interleave (per-member event groups
can overlap with other members'), but each member's own events are
ordered.
Stability
This surface is frozen as of v0.7. Future versions may add new events
but will not remove or rename existing events without a major version
bump. The :member_completed payload was changed in v0.7 (see CHANGELOG).
Payloads
:run_started— emitted once per run, before any round begins.council_module— atom, the council module being run.input— map, the input passed toCouncilEx.run/2orstart/2.
:round_started— emitted at the start of each round.round_name— atom, the round's symbolic name (e.g.,:independent_analysis).idx— non-negative integer, the round's 0-based index in the council's round list.
:member_started— emitted before each member begins executing in a round. Per-member, fires once per (round × member_id) pair.:member_token— emitted for each streaming chunk from a member withstream true. May fire many times per member.- 5th element:
%CouncilEx.StreamChunk{content, index, finish_reason}.
- 5th element:
:tool_call_request— emitted just before each tool execution during a tool-calling member's turn. Synthetic Anthropic_respondtool excluded.- 5th element:
%CouncilEx.ToolCall{id, name, args_raw, args_parsed}.
- 5th element:
:tool_call_result— emitted after each tool execution completes (success or error)._respondexcluded.- 5th element:
%CouncilEx.ToolCallResult{id, name, result, error}.
- 5th element:
:member_completed— emitted after each member's turn finishes. Always carries%MemberResult{}(status:ok | :error | :timeout | :skipped | :invalid_output | :eliminated). Replaces the v0.6 split between:member_completed(ok-only) and:member_failed(error-only).- 5th element:
%CouncilEx.MemberResult{member_id, status, response, error, duration_ms, attempts, metadata}.
- 5th element:
:round_completed— emitted after a round finishes (all members done).- 4th element:
%CouncilEx.RoundResult{name, member_results, metadata, ...}.
- 4th element:
:run_completed— emitted once per run, after the final round, on the success path. Mutually exclusive with:run_failed.- 3rd element:
%CouncilEx.Result{}carrying the final synthesized output and per-round results.
- 3rd element:
:run_failed— emitted once per run on any non-success terminal path: round task crash, member-level errors withfailure_mode: :halt, or cancellation viaCouncilEx.cancel/2. Mutually exclusive with:run_completed.- 3rd element: list of
%CouncilEx.Error{}. Cancellation surfaces as%CouncilEx.Error{kind: :cancelled, reason: :cancelled_by_user}so subscribers can distinguish cancel from crash. - 4th element:
%CouncilEx.Result{status: :error}with whatever partial round results were collected before termination.
- 3rd element: list of
Topic
Single per-run topic: "council_ex:run:#{run_id}". Run IDs are
generated by RunState.new/1 and returned from CouncilEx.start/2.
Subscribe before calling start/2 to avoid missing :run_started.