You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Build an omadia Facilitator: a configurable agent plugin that is invited into a
group conversation, moderates the group to a predefined outcome like a professional
facilitator, keeps a protocol of how the result was reached and which insights
emerged along the way, and reports the result (or failure) back to the initiator.
It is a meta-feature: the Facilitator itself is a plugin, but a clean implementation
requires extending omadia Conductor (ephemeral / JIT workflows) and omadia Core
(group-conversation primitives). Step 1 targets virtual meetings as chat groups
(MS Teams group chat first; Telegram/Discord/etc. follow). Step 2 (audio / online /
hybrid meetings) is prepared and documented here but not built.
Depends on omadia Conductor (spec in #321, not yet merged). The Facilitator runs
on Conductor + the channel plugins + the Office plugin + the session transcript/KG.
Concrete scenario (the role-distribution case)
The owner tells the team to agree on a role distribution. A document lists all roles;
by the end each role should carry exactly one name. The team sorts this out among
themselves — the owner only wants the result.
It all happens in a Teams group chat.
The owner invites an omadia Facilitator into the chat to moderate the group to the
result.
The Facilitator must know the goal and create a temporary workflow to run it.
The system must not accumulate endless dead workflows: the agent generates a workflow
with an expiry; after acceptance or abort it is removed again.
The Facilitator reports the result or failure to the owner per the workflow, and
optionally interim status via an alternate channel (e.g. a Teams DM).
The Facilitator interacts the way professional moderators do — equipped out of the box
with systemic coaching, NLP and other facilitation techniques.
Solution at a glance — three workstreams
The unifying idea: a facilitated meeting is an inherently free-form conversation
wrapped in a deterministic scaffold. Moderating is creative (the agent's job); termination, goal-adherence, reminders, reporting, and cleanup are deterministic
(Conductor's job). This is exactly the Conductor harness theme, applied to a group of
humans plus a moderator — without it, a facilitation can run forever, drift off-goal, or
never report.
The owner's explicit constraint: an agent that creates a workflow on the fly must not
clutter the system with snowflake workflows nobody needs.
origin: manual | ephemeral on a workflow. manual = user-authored business
processes (the existing library). ephemeral = agent-generated, run-scoped, JIT.
Generated from a validated pattern, not arbitrary graphs. An ephemeral workflow is
an instance of a known, engine-validated facilitation pattern; the agent fills its
slots (goal, machine-checkable definition-of-done, rounds, escalation, report targets,
deadline, interim cadence). It stays generative and validatable, and cannot produce
garbage graphs.
Lifecycle bound to the run. On a terminal run state (completed | failed | aborted) or TTL expiry the ephemeral workflow definition is removed. The run's audit trace / protocol is retained — we discard the scaffold, never the minutes.
Programmatic seam: an agent capability conductor.createEphemeralRun(patternId, params) (permission-gated, deny-by-default) creates + starts in one call — no
Designer, no entry in the main workflow library.
Storage & Admin-UI separation: ephemeral workflows are flagged (origin) and live
in a separate namespace; the main workflow library shows only manual workflows. The
Admin UI surfaces ephemeral ones in a separate, read-only "Live / ephemeral runs" view
with TTL, owning agent, and run link. A reaper job (reuse the scratchPromotionReaper pattern) prunes expired/terminal ephemeral rows.
Guardrails against runaway generation: per-agent quota + rate-limit on ephemeral
creation, a cap on concurrent ephemeral runs per agent, and a mandatory TTL with an
upper bound.
Workstream B — Core: Group-conversation primitives (channel-SDK contract + Teams adapter)
Verified gaps today: the channel SDK carries per-speaker identity (IncomingTurn.userRef)
and a shared per-conversation session (scope = ${channelId}::${conversationId}), but
has no roster, no group-vs-1:1 signal, no bot-invited event, and no way to DM one
specific person separately from posting to the group. Define these generically at the
SDK level; implement Teams first; Telegram/Discord follow.
B1 — Multi-party model:conversationType: 'group' | 'direct' and a participant roster accessor (resolve current members + the agent's own identity in the
conversation).
B2 — Bot-lifecycle event: an "agent invited / members changed" event (incl. who
added the bot), so the Facilitator can detect being invited and by whom.
B3 — Targeted send: post to a specific participant (DM) distinct from posting to
the group — a per-user conversation reference plus a recipient target on the outbound
path. Enables "report to me / interim status via Teams DM".
B4 (optional, fast-follow) — Addressing:@mention a participant in an outbound
message.
These are reusable Core capabilities (any group-aware agent benefits), not
Facilitator-private.
Workstream C — Facilitator agent plugin
A configurable agent plugin; its skill (system prompt) covers systemic coaching, NLP,
and classic facilitation techniques — round-robin, surfacing silent voices, reflective
summarizing, conflict mediation, decision frameworks, timeboxing, neutrality.
Admin-configurable via manifest setup.fields + ctx.config: default models,
default reminder/timebox cadence, default reporting behavior (result-only vs interim),
max meeting duration / workflow TTL, moderation intensity/tone, language, and an enable_audio flag (Step 2).
Flow: invited to a group (B2) → reads the goal + a machine-checkable
definition-of-done (e.g. "the target artifact has every role filled with exactly one
participant, and the group explicitly confirmed") → calls conductor.createEphemeralRun( 'facilitation', { goal, definitionOfDone, participants, initiator, reportChannel, deadline, interimCadence }). Conductor then drives:
a moderation step (agentic) whose inner loop runs the conversational facilitation
against the shared group session until the DoD postcondition is met,
reminder / timebox ticks (reuse scheduleWorker) to nudge a stalled group,
a deadline / abort fallback (in-graph transition),
a report step that sends result/failure to the initiator (B3 DM) and optional
interim status,
a protocol step that renders minutes (Office create_docx) capturing how the
result was reached and the insights, sourced from sessionLogger + the KG.
On terminal state the ephemeral workflow is auto-removed; the protocol is retained.
The evolving result artifact (e.g. roles→names) is maintained by the agent and can
be rendered back into the chat; the DoD is checked against it.
Protocol & reporting
Protocol reuses the existing substrate: sessionLogger (Markdown transcript + KG Turn nodes with entity anchors) + sessionBriefing summaries. The protocol records
the path to the result and the insights, and survives the workflow's disposal.
Reporting uses B3: final result/failure to the initiator; interim status optional
per facilitation config (default: final + abort only).
Step 1 vs Step 2 — the MeetingSource abstraction (forward-compat)
Define the Facilitator to consume an abstract MeetingSource = an attributed-utterance
stream + a roster, independent of origin.
Step 1 — ChatMeetingSource (this issue): group chat (Teams first).
Step 2 — AudioMeetingSource (future): online / real / hybrid meetings via audio.
Transcription + speaker diarization produce the same attributed-utterance stream.
The IncomingAttachment.kind === 'audio' seam already exists in the channel SDK; what is
missing is a transcription/diarization service. Everything above the source layer (the
facilitation loop, DoD, protocol, reporting, JIT workflow) is unchanged — Step 2 is a
source plugin, not a rewrite. Documented here; not built.
Proposed design decisions (recommendations baked in; open to change)
Generation model: ephemeral workflows are generated by filling slots in a
validated facilitation pattern, not by emitting arbitrary graphs. Keeps "generative"
while staying safe, validatable, and clutter-free. (Alternative: free-form graph
generation — rejected: unvalidatable, clutter-prone.)
Ephemeral storage: same workflow table + origin flag + separate namespace +
reaper job, rather than a separate store. Minimal new schema; clean Admin-UI filter.
Channel scope for Step 1: define the group primitives generically at the channel-SDK
level, implement Teams first, with Telegram/Discord as fast-follow.
Acceptance criteria (Step 1)
An admin can install + configure the Facilitator plugin via its setup.fields.
A user can invite the Facilitator into a Teams group chat; the Facilitator detects the
invitation and who invited it (B2), and reads the stated goal + definition-of-done.
The Facilitator creates exactly one ephemeral workflow run per facilitation via createEphemeralRun; it does not appear in the main workflow library and is
visible in the Admin-UI ephemeral view with a TTL.
The Facilitator moderates the group (distinguishing speakers) until the
definition-of-done postcondition is met, sends timebox reminders on stall, and fires the
in-graph fallback on deadline/abort.
On success it reports the result to the initiator via a Teams DM (B3) and produces a
minutes document; on failure it reports the failure.
After a terminal state (or TTL), the ephemeral workflow is removed while the run's
protocol/trace is retained.
The same flow works on at least one additional channel (Telegram or Discord) with no
Facilitator-side changes above the MeetingSource abstraction.
The HR/role-movement policy (Conductor's role resolver, separate concern).
Drafted with Claude Code as the conception artifact for this feature; refine inline as needed.
Clarification — Principal (user | role) is the universal addressee, including report targets
Anywhere the Facilitator (or any Conductor workflow) addresses a person — not only
decision/approval steps but also report and interim-status targets — the addressee is a Principal: user:<id>orrole:<key>. This reuses the Conductor role machinery
(resolver seam + late binding) already defined for human steps.
Examples:
A) "report to me" → user:<owner-id>.
B) "report to the management" → role:management, currently held by two people
(owner + colleague).
Semantics differ by purpose:
Purpose
A role with multiple holders resolves to…
Decision / approval (a response is required)
its current holder(s); the step's quorum: any | all governs completion (existing behavior).
Notification / report / interim status (no response required)
all current holders at send time, with the message fanned out to each (one delivery per holder via B3 targeted send — e.g. two Teams DMs for a two-person management role). No quorum — nothing is awaited; it is a broadcast to the current holders.
Resolution is late-bound for both: if the role's membership changes before the report
is sent, it goes to whoever holds the role at that moment.
Implications:
Workstream B3 (targeted send) MUST accept a Principal, not only a single user,
and for a role MUST resolve to N recipients and deliver to each.
Workstream C: the Facilitator's report target and interim-status target are
Principals, configurable as either a specific user or a role.
Unreachable / empty role on a report follows the existing rule: a holder unreachable
on the channel is logged/diagnosed; a role with no current holder surfaces a delivery
diagnostic / escalation rather than a silent drop.
Acceptance addition (Step 1): reporting to a two-person role:management delivers the
result to both current holders; moving the role to a different person before the
report sends it to the new holder.
Invocation, mode lifecycle & transparency
Yes — the Facilitator is an explicit agent plugin with its own identity. It participates
under its own recognizable name/avatar (its own channel bot/handle), never as a generic
"omadia". A distinct, visible participant is the foundational anti-obfuscation property:
nobody is moderated by an invisible observer.
Scope: there is no global "Facilitator mode"
Facilitation mode is per-conversation / per-run, not a global instance toggle. A specific
group has an active facilitation while the rest of omadia runs normally. "Mode active" == the
ephemeral Conductor run for that conversation is in progress — so the mode state is the run
lifecycle (auditable, announceable), not an opaque flag.
Lifecycle (how it's used)
Admin installs + configures the Facilitator plugin (skill, defaults).
A user invites the Facilitator into the group chat (the "agent invited" event,
Workstream B2) — the explicit entry; nobody is moderated covertly.
Opening handshake (visible in the chat): the Facilitator immediately posts its purpose — "I'm the omadia Facilitator. Goal: X. Definition-of-done: Y. I report to Z. Deadline: D.
I'll moderate until we reach the result. /facilitator stop ends it." Mode start is an
announced, visible transition.
It creates the ephemeral Conductor run (JIT workflow) — the run is the active mode.
On result / abort / deadline: a visible closing message + the report, and the JIT workflow
is disposed. Mode end is announced too.
Transparency mechanisms (mode MUST NOT be obfuscated)
Mechanism
Effect
Own agent identity
Every moderation message is visibly "from the Facilitator", not generic.
Announced start/stop transitions
Mode never begins or ends silently — always a handshake + closing summary in the conversation.
Persistent status
Web-UI banner + (where the channel supports it) a pinned card: "Facilitation active: goal, definition-of-done, deadline, report target."
/facilitator status
Any participant can ask at any time "are we being moderated, by whom, reported to whom?" and gets a truthful answer.
No silent mode switching
An agent MUST NOT slip into facilitation mode without the handshake; entering/leaving is always explicit and logged.
Admin-UI ephemeral runs + protocol
The active mode is visible outside the chat too (owner, TTL, run trace).
Disclosure of the report target (default)
Participants are being moderated and their result (and possibly insights) is reported to
someone. Default: the report target is disclosed to the group (e.g. "the result goes to the
management") — not merely courtesy but often a transparency / GDPR requirement. Disclosure is the
default; it is configurable only where a different legal basis applies. (Decision confirmed
2026-06-17.)
Skill vs. dedicated agent
The moderation capability could technically be a skill attached to any agent. For transparency the recommended deployment is a dedicated Facilitator agent with its own identity — a recognizable
moderator beats a general-purpose agent that sometimes moderates covertly.
Acceptance additions
Inviting the Facilitator triggers a visible opening handshake stating goal, definition-of-done,
deadline, and report target before any moderation begins.
At any time, /facilitator status returns who is moderating, toward what goal, and to whom the
result is reported.
Entering and leaving facilitation mode are announced in-conversation and recorded in the run
trace; there is no silent mode.
The report target is disclosed to participants by default.
Bot identity model & rationale — when a separate in-channel bot is justified
Recorded so the reasoning isn't lost or re-litigated. Refines the "Skill vs. dedicated agent"
note above: the Facilitator is the Convener agent in facilitate mode, not a bot-per-function.
Context / the tension. omadia's architecture is one user-facing orchestrator per channel
binding; everything else is sub-agents behind that front-door. Introducing co-present
user-facing bots (a Facilitator joining a group chat) competes with that. This section resolves
the tension and keeps the reasoning.
Principle
Bot identities track accountabilities toward the people in the room, not internal agent
topology. Internally omadia stays orchestrator + sub-agents. Externally, a distinct in-channel
identity appears only when the bot's stance toward the humans is non-assistive — moderating,
recording, representing, or challenging them. Default: one front-door per conversation; a
second co-present identity is the deliberate, justified, ephemeral exception.
The litmus (sharpened)
Two identities only if they could be present in the same room at the same time with contradicting accountabilities. If two functions share the same accountability and can never
conflict, they are modes of one identity, not two bots.
Applying it — the taxonomy collapses
Convener / Session-Steward — one identity, multiple modes.facilitate (steer to an
outcome), record (observe + minute), timekeep, … All share one accountability: "present on
behalf of the session's outcome/record; the attendees are the subject; reports to a target." Recording is a mode / sub-feature-set of the Convener, NOT a separate bot — a silent Convener is the recorder. The active mode is announced for transparency (e.g. "I'm here only to take
minutes; I won't steer.").
Representative — genuinely separate. Partisan: speaks for a specific party in a
multi-party / cross-org room. It cannot be the same entity as a neutral Convener (neutral vs.
partisan), and both may be needed simultaneously → a distinct identity.
Challenger / Red-team — borderline. A separate identity only when a visibly neutral
Convener and a deliberately adversarial voice are needed at the same time; otherwise it is
a devil's-advocate mode of the Convener. (The litmus explains exactly why it's borderline.)
Net: not "a bot per function" — one Convener identity with modes, plus the Representative as the
one clearly separate second class. Identity count stays tied to perceived accountability; bot
proliferation is prevented structurally.
Stays behind the front-door (sub-agent or mode, never a separate bot)
Domain specialists (HR, finance, Odoo, web-search), skills, tools, personas/tones, and a private
"notetaker just for me". Boundary test for the notetaker: it becomes a (Convener-mode) recorder only when its presence changes what the other attendees must know ("now we're on the
record") — i.e. when it changes the social contract for the room, not merely my private
convenience.
Consequence for this issue
Model the plugin as a Convener agent with modes, not as "Facilitator + separate Recorder". The
Facilitator is the Convener in facilitate mode; minutes/recording is a Convener mode reusing the
same infrastructure (announced presence, floor arbitration, ephemeral Conductor run, protocol).
Prerequisite this implies (Core — Workstream B)
Any co-present multi-bot scenario (Convener + Representative, or a Convener alongside the general
front-door bot) requires conversation floor / turn arbitration — today omadia is
one-agent-per-binding. Rules:
Exactly one bot owns a given message: explicit @mention → that bot; an active Convener run holds the floor for its goal and the general front-door defers; otherwise the default
front-door.
No bot replies to another bot unless explicitly addressed (no bot-to-bot loops).
Sub-agents never get a channel identity (Spec 001 separation stays hard; the Convener is an
Agent, not a sub-agent).
Co-presence is explicit and ephemeral, with announced join/leave.
This is new Core work and a prerequisite for the Facilitator — without it, multi-bot = noise.
Summary
Build an omadia Facilitator: a configurable agent plugin that is invited into a
group conversation, moderates the group to a predefined outcome like a professional
facilitator, keeps a protocol of how the result was reached and which insights
emerged along the way, and reports the result (or failure) back to the initiator.
It is a meta-feature: the Facilitator itself is a plugin, but a clean implementation
requires extending omadia Conductor (ephemeral / JIT workflows) and omadia Core
(group-conversation primitives). Step 1 targets virtual meetings as chat groups
(MS Teams group chat first; Telegram/Discord/etc. follow). Step 2 (audio / online /
hybrid meetings) is prepared and documented here but not built.
Concrete scenario (the role-distribution case)
by the end each role should carry exactly one name. The team sorts this out among
themselves — the owner only wants the result.
result.
The system must not accumulate endless dead workflows: the agent generates a workflow
with an expiry; after acceptance or abort it is removed again.
optionally interim status via an alternate channel (e.g. a Teams DM).
with systemic coaching, NLP and other facilitation techniques.
Solution at a glance — three workstreams
The unifying idea: a facilitated meeting is an inherently free-form conversation
wrapped in a deterministic scaffold. Moderating is creative (the agent's job);
termination, goal-adherence, reminders, reporting, and cleanup are deterministic
(Conductor's job). This is exactly the Conductor harness theme, applied to a group of
humans plus a moderator — without it, a facilitation can run forever, drift off-goal, or
never report.
Workstream A — Conductor: Ephemeral / JIT workflows ("generative, governed, self-disposing")
The owner's explicit constraint: an agent that creates a workflow on the fly must not
clutter the system with snowflake workflows nobody needs.
origin: manual | ephemeralon a workflow.manual= user-authored businessprocesses (the existing library).
ephemeral= agent-generated, run-scoped, JIT.an instance of a known, engine-validated facilitation pattern; the agent fills its
slots (goal, machine-checkable definition-of-done, rounds, escalation, report targets,
deadline, interim cadence). It stays generative and validatable, and cannot produce
garbage graphs.
completed | failed | aborted) or TTL expiry the ephemeral workflow definition is removed. The run'saudit trace / protocol is retained — we discard the scaffold, never the minutes.
conductor.createEphemeralRun(patternId, params)(permission-gated, deny-by-default) creates + starts in one call — noDesigner, no entry in the main workflow library.
origin) and livein a separate namespace; the main workflow library shows only
manualworkflows. TheAdmin UI surfaces ephemeral ones in a separate, read-only "Live / ephemeral runs" view
with TTL, owning agent, and run link. A reaper job (reuse the
scratchPromotionReaperpattern) prunes expired/terminal ephemeral rows.creation, a cap on concurrent ephemeral runs per agent, and a mandatory TTL with an
upper bound.
Workstream B — Core: Group-conversation primitives (channel-SDK contract + Teams adapter)
Verified gaps today: the channel SDK carries per-speaker identity (
IncomingTurn.userRef)and a shared per-conversation session (
scope = ${channelId}::${conversationId}), buthas no roster, no group-vs-1:1 signal, no bot-invited event, and no way to DM one
specific person separately from posting to the group. Define these generically at the
SDK level; implement Teams first; Telegram/Discord follow.
conversationType: 'group' | 'direct'and a participantroster accessor (resolve current members + the agent's own identity in the
conversation).
added the bot), so the Facilitator can detect being invited and by whom.
the group — a per-user conversation reference plus a
recipienttarget on the outboundpath. Enables "report to me / interim status via Teams DM".
@mentiona participant in an outboundmessage.
These are reusable Core capabilities (any group-aware agent benefits), not
Facilitator-private.
Workstream C — Facilitator agent plugin
and classic facilitation techniques — round-robin, surfacing silent voices, reflective
summarizing, conflict mediation, decision frameworks, timeboxing, neutrality.
setup.fields+ctx.config: default models,default reminder/timebox cadence, default reporting behavior (result-only vs interim),
max meeting duration / workflow TTL, moderation intensity/tone, language, and an
enable_audioflag (Step 2).definition-of-done (e.g. "the target artifact has every role filled with exactly one
participant, and the group explicitly confirmed") → calls
conductor.createEphemeralRun( 'facilitation', { goal, definitionOfDone, participants, initiator, reportChannel, deadline, interimCadence }). Conductor then drives:against the shared group session until the DoD postcondition is met,
scheduleWorker) to nudge a stalled group,interim status,
create_docx) capturing how theresult was reached and the insights, sourced from
sessionLogger+ the KG.be rendered back into the chat; the DoD is checked against it.
Protocol & reporting
sessionLogger(Markdown transcript + KGTurnnodes with entity anchors) +sessionBriefingsummaries. The protocol recordsthe path to the result and the insights, and survives the workflow's disposal.
per facilitation config (default: final + abort only).
Step 1 vs Step 2 — the
MeetingSourceabstraction (forward-compat)Define the Facilitator to consume an abstract
MeetingSource= an attributed-utterancestream + a roster, independent of origin.
ChatMeetingSource(this issue): group chat (Teams first).AudioMeetingSource(future): online / real / hybrid meetings via audio.Transcription + speaker diarization produce the same attributed-utterance stream.
The
IncomingAttachment.kind === 'audio'seam already exists in the channel SDK; what ismissing is a transcription/diarization service. Everything above the source layer (the
facilitation loop, DoD, protocol, reporting, JIT workflow) is unchanged — Step 2 is a
source plugin, not a rewrite. Documented here; not built.
What exists vs. what we extend/build (grounded)
channels/coreApi.ts(scope),harness-channel-sdk/src/incoming.ts(userRef)harness-orchestrator/src/sessionLogger.ts,plugin-api/src/sessionBriefing.tsharness-plugin-office(create_docx/create_xlsx)setup.fields,ctx.config,agent_plugins.configplatform/flowState.ts,plugins/jobScheduler.ts,scratchPromotionReaperharness-channel-sdk/src/incoming.ts(IncomingAttachment.kind: 'audio')specs/005-omadia-conductor)origin, TTL,createEphemeralRun, UI separation, reaper, quotas)conversationType@mentionaddressingProposed design decisions (recommendations baked in; open to change)
validated facilitation pattern, not by emitting arbitrary graphs. Keeps "generative"
while staying safe, validatable, and clutter-free. (Alternative: free-form graph
generation — rejected: unvalidatable, clutter-prone.)
originflag + separate namespace +reaper job, rather than a separate store. Minimal new schema; clean Admin-UI filter.
level, implement Teams first, with Telegram/Discord as fast-follow.
Acceptance criteria (Step 1)
setup.fields.invitation and who invited it (B2), and reads the stated goal + definition-of-done.
createEphemeralRun; it does not appear in the main workflow library and isvisible in the Admin-UI ephemeral view with a TTL.
definition-of-done postcondition is met, sends timebox reminders on stall, and fires the
in-graph fallback on deadline/abort.
minutes document; on failure it reports the failure.
protocol/trace is retained.
Facilitator-side changes above the
MeetingSourceabstraction.Dependencies & sequencing
AudioMeetingSource+ atranscription/diarization service are new.
Out of scope
Drafted with Claude Code as the conception artifact for this feature; refine inline as needed.
Clarification — Principal (
user|role) is the universal addressee, including report targetsAnywhere the Facilitator (or any Conductor workflow) addresses a person — not only
decision/approval steps but also report and interim-status targets — the addressee is a
Principal:
user:<id>orrole:<key>. This reuses the Conductor role machinery(resolver seam + late binding) already defined for human steps.
Examples:
user:<owner-id>.role:management, currently held by two people(owner + colleague).
Semantics differ by purpose:
quorum: any | allgoverns completion (existing behavior).Resolution is late-bound for both: if the role's membership changes before the report
is sent, it goes to whoever holds the role at that moment.
Implications:
and for a role MUST resolve to N recipients and deliver to each.
Principals, configurable as either a specific user or a role.
"any workflow addressee", and define role-as-notification = fan-out to all current
holders (distinct from the decision
quorum). A small extension to the existing rolemodel, not a new concept.
on the channel is logged/diagnosed; a role with no current holder surfaces a delivery
diagnostic / escalation rather than a silent drop.
Acceptance addition (Step 1): reporting to a two-person
role:managementdelivers theresult to both current holders; moving the role to a different person before the
report sends it to the new holder.
Invocation, mode lifecycle & transparency
Yes — the Facilitator is an explicit agent plugin with its own identity. It participates
under its own recognizable name/avatar (its own channel bot/handle), never as a generic
"omadia". A distinct, visible participant is the foundational anti-obfuscation property:
nobody is moderated by an invisible observer.
Scope: there is no global "Facilitator mode"
Facilitation mode is per-conversation / per-run, not a global instance toggle. A specific
group has an active facilitation while the rest of omadia runs normally. "Mode active" == the
ephemeral Conductor run for that conversation is in progress — so the mode state is the run
lifecycle (auditable, announceable), not an opaque flag.
Lifecycle (how it's used)
Workstream B2) — the explicit entry; nobody is moderated covertly.
"I'm the omadia Facilitator. Goal: X. Definition-of-done: Y. I report to Z. Deadline: D.
I'll moderate until we reach the result.
/facilitator stopends it." Mode start is anannounced, visible transition.
is disposed. Mode end is announced too.
Transparency mechanisms (mode MUST NOT be obfuscated)
/facilitator statusDisclosure of the report target (default)
Participants are being moderated and their result (and possibly insights) is reported to
someone. Default: the report target is disclosed to the group (e.g. "the result goes to the
management") — not merely courtesy but often a transparency / GDPR requirement. Disclosure is the
default; it is configurable only where a different legal basis applies. (Decision confirmed
2026-06-17.)
Skill vs. dedicated agent
The moderation capability could technically be a skill attached to any agent. For transparency the
recommended deployment is a dedicated Facilitator agent with its own identity — a recognizable
moderator beats a general-purpose agent that sometimes moderates covertly.
Acceptance additions
deadline, and report target before any moderation begins.
/facilitator statusreturns who is moderating, toward what goal, and to whom theresult is reported.
trace; there is no silent mode.
Bot identity model & rationale — when a separate in-channel bot is justified
Recorded so the reasoning isn't lost or re-litigated. Refines the "Skill vs. dedicated agent"
note above: the Facilitator is the Convener agent in
facilitatemode, not a bot-per-function.Context / the tension. omadia's architecture is one user-facing orchestrator per channel
binding; everything else is sub-agents behind that front-door. Introducing co-present
user-facing bots (a Facilitator joining a group chat) competes with that. This section resolves
the tension and keeps the reasoning.
Principle
Bot identities track accountabilities toward the people in the room, not internal agent
topology. Internally omadia stays orchestrator + sub-agents. Externally, a distinct in-channel
identity appears only when the bot's stance toward the humans is non-assistive — moderating,
recording, representing, or challenging them. Default: one front-door per conversation; a
second co-present identity is the deliberate, justified, ephemeral exception.
The litmus (sharpened)
Applying it — the taxonomy collapses
facilitate(steer to anoutcome),
record(observe + minute),timekeep, … All share one accountability: "present onbehalf of the session's outcome/record; the attendees are the subject; reports to a target."
Recording is a mode / sub-feature-set of the Convener, NOT a separate bot — a silent Convener
is the recorder. The active mode is announced for transparency (e.g. "I'm here only to take
minutes; I won't steer.").
multi-party / cross-org room. It cannot be the same entity as a neutral Convener (neutral vs.
partisan), and both may be needed simultaneously → a distinct identity.
Convener and a deliberately adversarial voice are needed at the same time; otherwise it is
a devil's-advocate mode of the Convener. (The litmus explains exactly why it's borderline.)
Net: not "a bot per function" — one Convener identity with modes, plus the Representative as the
one clearly separate second class. Identity count stays tied to perceived accountability; bot
proliferation is prevented structurally.
Stays behind the front-door (sub-agent or mode, never a separate bot)
Domain specialists (HR, finance, Odoo, web-search), skills, tools, personas/tones, and a private
"notetaker just for me". Boundary test for the notetaker: it becomes a (Convener-mode) recorder
only when its presence changes what the other attendees must know ("now we're on the
record") — i.e. when it changes the social contract for the room, not merely my private
convenience.
Consequence for this issue
Model the plugin as a Convener agent with modes, not as "Facilitator + separate Recorder". The
Facilitator is the Convener in
facilitatemode; minutes/recording is a Convener mode reusing thesame infrastructure (announced presence, floor arbitration, ephemeral Conductor run, protocol).
Prerequisite this implies (Core — Workstream B)
Any co-present multi-bot scenario (Convener + Representative, or a Convener alongside the general
front-door bot) requires conversation floor / turn arbitration — today omadia is
one-agent-per-binding. Rules:
@mention→ that bot; an active Convener runholds the floor for its goal and the general front-door defers; otherwise the default
front-door.
Agent, not a sub-agent).
This is new Core work and a prerequisite for the Facilitator — without it, multi-bot = noise.