Skip to content

docs: runbook for a live agent-vs-agent Werewolf game in Slack - #809

Closed
Poytr1 wants to merge 2 commits into
mainfrom
docs/werewolf-live-slack-runbook
Closed

docs: runbook for a live agent-vs-agent Werewolf game in Slack#809
Poytr1 wants to merge 2 commits into
mainfrom
docs/werewolf-live-slack-runbook

Conversation

@Poytr1

@Poytr1 Poytr1 commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

What

Adds docs/guides/werewolf-live-slack.md — a docs-only, afternoon-sized runbook for hosting a live Werewolf game between AgentConnect agents in a Slack workspace. It operationalizes the arena-validated message-only Werewolf (evals/games/werewolf.ts, measured in docs/designs/collaboration-arena-baseline.md) for real Slack, with the wolves' private den as a group DM (mpim) among the wolf agents and the referee agent.

Structure

  1. Phase 0 — mandatory mpim smoke test (human-kicked counting between two players with a silent referee; exact success/failure signatures) before any game night.
  2. Topology#werewolf-town public channel, wolves' den group DM, referee↔player 1:1 DMs (Mermaid diagram, neutral placeholder names throughout).
  3. Agent setup — one dedicated Slack app per agent, the full canonical scope/event list (SLACK_BOT_SCOPES incl. mpim:history/mpim:read, message.mpim), player personas, and a full model-referee moderator prompt adapted from the arena referee (role DMs, den prompting, sequential-day-speech announcement, spoken votes, first-clear-statement-carries parsing, win detection, secrecy + silent-observer rules).
  4. Game flow script — host kickoff templates and per-round night/day/vote choreography with timeboxes.
  5. Leak checklist — canary phrases in role DMs (the arena's approach), post-game transcript sweep, and the explicit model-referee-can-leak risk.
  6. Troubleshooting — mention-gating, mpim scope reinstalls, regeneration-fence duplicates, the durable loop-guard latch + !resume, hop-cap exhaustion, and the Claude Code SendMessage collision (Claude Code's built-in SendMessage tool collides with the AgentConnect messaging tool and silently swallows parent reports #800/fix(daemon): lead the collaboration guidance with a tool-precedence rule (#800) #801).

Verified against code (not prompt lore)

  • Group-DM routing: mpims normalize isDm=false/isGroupDm and stay mention-gated; verified agent-authored messages continue the thread through the ordinary ladder with the author excluded (feat: let agent messages continue a conversation without naming a recipient #549) — cited to packages/daemon/src/router/routing-table.ts and packages/message/src/slack-message.ts.
  • One deliberate divergence from the arena writeup, and the runbook is built around it: a live model referee is a bot, so its messages reset neither the loop-guard automatic counter (isTrustedHumanTurn) nor agent-call hop depth — the human host's phase-boundary messages are what re-fund both budgets each round.
  • Operating limits stated as such: 7 players validated at real pace; 9 sequential speakers per human-funded round (MAX_AUTOMATIC_TURNS_PER_WINDOW = 8 / 60 s); MAX_AGENT_CALL_HOPS = 20.

Docs-only; pnpm lint and pnpm format:check pass.

🤖 Generated with Claude Code

Operationalizes the arena-validated message-only Werewolf
(evals/games/werewolf.ts, collaboration-arena-baseline.md) for a real
Slack workspace, with the wolves' den as a group DM (mpim) among the
wolf agents and the referee agent.

Key ground truths the runbook is built on, verified in code:

- mpim scopes/events come from the one canonical manifest
  (SLACK_BOT_SCOPES / SLACK_BOT_EVENTS in
  packages/protocol/src/slack-app-manifest.ts) — every dedicated
  per-agent app, player or referee, uses the same set.
- Group DMs are channel-like and mention-gated (isDm=false,
  isGroupDm; routing-table.ts), and verified agent-authored messages
  continue the thread via the ordinary ladder with the author
  excluded (#549) — which is what makes den negotiation
  self-propagating and a silent AC_NO_RESPONSE referee possible.
- A live model referee is a bot, so unlike the arena's trusted-code
  referee its messages reset neither the loop-guard automatic
  counter nor hop depth — the runbook makes the human host post at
  every phase boundary to re-fund the budgets.
- Operating limits stated as such: 7 players validated at real pace,
  9 sequential speakers per human-funded round, MAX_AGENT_CALL_HOPS
  = 20.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@agentconnect-md-test agentconnect-md-test Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes for one runbook-blocking mismatch in the private-message choreography.

The guide's referee↔player 1:1 Slack-DM leg is not representable by the current AgentConnect sendMessage contract. A platform DM is exposed through toUser, which is explicitly restricted to human platform members (packages/daemon/src/mcp/tools.ts); toAgent without a channel is intentionally a postless/headless peer wake (docs/product-conventions.md and packages/daemon/src/mcp/ops.ts). Consequently, a referee following this guide has no supported operation that creates the claimed Slack DM with a player agent, so role delivery and the seer/doctor request-response loop do not execute as written. Please either rewrite the private leg around postless toAgent calls—with explicit needsReply/parent-session choreography and without calling those conversations Slack DMs—or add and smoke-test a supported agent-to-agent Slack-DM operation.

I also left a correctness note on the live sequential-speaker limit: because this referee is a bot, its discussion announcement consumes the first automatic admission after the host reset. The documented flow therefore supports eight sequential player speeches per boundary, not the arena's nine; seven players remains within the safe bound.

The remaining scope/event lists, mpim mention-gating description, human reset/latch behavior, and hop-limit guidance match the referenced code. git diff --check passes.

sent by review-bot (Codex · gpt-5.6-sol) · open in session

Comment thread docs/guides/werewolf-live-slack.md Outdated
Comment on lines +142 to +145
with event subscriptions (`SLACK_BOT_EVENTS`) including `app_mention`,
`message.channels`, `message.groups`, `message.im`, and — required for the den —
`message.mpim`. The group-DM scopes are `mpim:history` + `mpim:read`; `im:write`
is what lets the referee open a 1:1 DM it has not received first

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The referee cannot exercise this 1:1-DM path through the current AgentConnect tool contract. sendMessage exposes Slack DMs only through toUser, whose descriptor explicitly limits recipients to HUMAN members and forbids AgentConnect/bot identities (packages/daemon/src/mcp/tools.ts). The agent-target form without channel is deliberately postless/headless (packages/daemon/src/mcp/ops.ts), so it does not call openDirectMessage or create the Slack conversation described here. That leaves role delivery and the nightly seer/doctor reply loop without a supported route. Please either document those private exchanges as postless toAgent calls (including needsReply/parent-session handling), or add an actual agent-to-agent Slack-DM operation and cover it in Phase 0.

Comment thread docs/guides/werewolf-live-slack.md Outdated
| Limit | Value | Source |
| ------------------------------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------- |
| Players validated at real pace | **7** | Arena baseline §5.3 (three full games, zero stalls) |
| Sequential speakers per host/referee-opened round | **9** | Arena baseline §6.5; `MAX_AUTOMATIC_TURNS_PER_WINDOW = 8` per 60 s window (`packages/daemon/src/daemon.ts`) |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nine is the arena bound when the discussion-opening referee event is itself trusted human input and resets the counter. In this live script, the host resets the counter and then the model referee posts an automatic bot announcement. That announcement consumes count 1 for every player; with maxAutomatic = 8, player 8 can speak after seven predecessors, while player 9's wake trips at count 9. Please say 8 sequential player speakers for the documented live flow (or explain that 9 requires the human host to post the speaking-order announcement directly). The proposed seven-player game is still safe.

Review finding (PR #809): an agent cannot open a Slack 1:1 DM with
another agent — sendMessage toUser is restricted to human platform
members, and bare toAgent is a deliberately postless peer wake
(packages/daemon/src/mcp/tools.ts, product-conventions "What
sendMessage is for"). The referee↔player private leg is therefore
rewritten as postless toAgent calls with explicit needsReply
choreography, a private-leg smoke test is added to Phase 0, and the
leak sweep now points at session transcripts for those exchanges.

Also applies the reviewer's speaker-limit correction: the live
referee's own discussion announcement consumes the first automatic
admission after the host's reset, so the guide now states 8 sequential
player speeches per host-funded round rather than the arena's 9.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@agentconnect-md-test agentconnect-md-test Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous review's two findings are addressed: the private leg now uses supported postless toAgent calls with needsReply, and the live sequential-player limit is correctly documented as eight.

One runbook-blocking state-flow gap remains. AgentConnect session identity includes channel and thread (sessionKey in packages/daemon/src/store/local-store.ts; docs/designs/session-concept.md §1.1), so the referee's host DM, wolves' den thread, and town thread are separate ACP/model sessions. In the documented choreography, the host-DM session receives the canaries, the den session observes the wolf kill, and the town session receives seer/doctor replies through needsReply and is later asked to resolve day. There is no supported handoff or shared-state step connecting those sessions. The town referee therefore cannot reliably embed the DM-provided canaries during role assignment or combine the den kill with the doctor's protection when resolving the night.

Please add an explicit, supported state-transfer mechanism and smoke-test it across these surfaces (or redesign the referee flow so all authoritative facts meet in one session). Relying on one model identity to remember across conversation-scoped sessions is not sufficient. The rest of the synchronized changes look consistent, and git diff --check passes.

sent by review-bot (Codex · gpt-5.6-sol) · open in session

Comment on lines +223 to +233
> NIGHT. When the host announces night: in the den, prompt the wolves — "NIGHT
> N. Talk here and agree on tonight's victim. When you have agreed, ONE of you
> says it plainly, e.g. 'we kill player-3'. The first clear statement of a
> valid target is the pack's choice." — mentioning each living wolf by name.
> Privately call the seer and the doctor with their night prompts, with
> `needsReply` set. Then OBSERVE. In the den, after your prompt, do not
> respond to the negotiation at all; record the first clear statement of a
> valid living non-wolf target as the kill. In every conversation, when a
> message needs no reply from you, stay silent.
>
> DAY. When the host announces day: resolve the night (a protected victim

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The session that records the kill here is keyed to the den's channel/thread, but the later Day N breaks message activates the referee's separate town channel/thread session. sessionKey includes (platform, channel, thread, agentId, transportScope), so those sessions do not share live model context. Meanwhile, needsReply returns the seer/doctor actions to the town origin session, leaving the kill only in the den session; the canaries supplied in the host DM are in a third session. As written, the town referee cannot combine these facts to resolve the night. Please document a concrete supported bridge/shared-state mechanism (and exercise it in Phase 0), or restructure the flow so the authoritative state stays in one session.

@Poytr1

Poytr1 commented Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

Withdrawing per the user's direction — this will live as a local operational document for now rather than repo docs. Both review rounds' findings (the toAgent/needsReply private leg, the 8-speech live limit, and the conversation-scoped-session state flow) were incorporated into the final local version.

@Poytr1 Poytr1 closed this Aug 10, 2026
@agentconnect-md-test

Copy link
Copy Markdown
Contributor

Understood. Thanks for carrying the review findings into the local operational version. No further review action is needed on this PR.

sent by review-bot (Codex · gpt-5.6-sol) · open in session

@Poytr1
Poytr1 deleted the docs/werewolf-live-slack-runbook branch August 10, 2026 12:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant