zhi 08f42bfd92 fix: skip rules-based no-reply override when turn manager allows agent
When the turn manager determines it's an agent's turn (checkTurn.allowed),
the rules engine's evaluateDecision() could still override the model to
no-reply with reason 'rule_match_no_end_symbol'. This happened because:

1. The sender of the triggering message (another agent) was not in the
   humanList, so the rules fell through to the end-symbol check.
2. getLastChar() operates on the full prompt (including system content
   like Runtime info), so it never found the end symbol even when the
   actual message ended with one.

Fix: return early from before_model_resolve after the turn check passes,
skipping the rules-based no-reply override entirely. The turn manager is
the authoritative source for multi-agent turn coordination.

Tested: 3-agent counting chain ran successfully (3→11) with correct
NO_REPLY handling when count exceeded threshold.
2026-03-09 21:16:53 +00:00

Dirigent

Rule-based no-reply gate + turn manager for OpenClaw (Discord).

Formerly known as WhisperGate. Renamed to Dirigent in v0.2.0.

What it does

Dirigent adds deterministic logic before model selection and turn-based speaking for multi-agent Discord channels:

  • Rule gate (before_model_resolve)

    1. Non-Discord → skip
    2. Sender in bypass list / human list → skip
    3. Message ends with configured end symbol → skip
    4. Otherwise → route to no-reply model/provider
  • End-symbol enforcement

    • Injects instruction: Your response MUST end with 🔚…
    • In group chats, also injects: "If not relevant, reply NO_REPLY"
  • Scheduling identifier (moderator handoff)

    • Configurable identifier (default: ➡️) used by the moderator bot
    • Handoff format: <@TARGET_USER_ID>➡️ (non-semantic, just a scheduling signal)
    • Agent receives instruction explaining the identifier is meaningless — check chat history and decide
  • Turn-based speaking (multi-bot)

    • Only the current speaker is allowed to respond
    • Others are forced to no-reply
    • Turn advances on end-symbol or NO_REPLY
    • If all bots NO_REPLY, channel becomes dormant until a new human message
  • Agent identity injection

    • Injects agent name, Discord accountId, and Discord userId into group chat prompts
  • Human @mention override

    • When a humanList user @mentions agents, temporarily overrides turn order
    • Only mentioned agents cycle; original order restores when cycle completes
  • Per-channel policy runtime

    • Policies stored in a standalone JSON file
    • Update at runtime via dirigent_policy_set / dirigent_policy_delete tools
  • Discord control actions (optional)

    • Private channel create/update + member list
    • Via dirigent_channel_create, dirigent_channel_update, dirigent_member_list tools

Repo layout

  • plugin/ — OpenClaw plugin (gate + turn manager + moderator presence)
  • no-reply-api/ — OpenAI-compatible API that always returns NO_REPLY
  • Discord admin actions are now handled in-plugin via direct Discord REST API calls (no sidecar service)
  • docs/ — rollout, integration, run-mode notes, turn-wakeup analysis
  • scripts/ — smoke/dev/helper checks
  • Makefile — common dev commands (make check, make check-rules, make test-api, make smoke-discord-control, make up)
  • CHANGELOG.md — milestone summary

Quick start (no Docker)

cd no-reply-api
node server.mjs

Then render config snippet:

node scripts/render-openclaw-config.mjs

See docs/RUN_MODES.md for Docker mode. Discord extension capabilities: docs/DISCORD_CONTROL.md.


Runtime tools & commands

Tools (6 individual tools)

Discord control:

  • dirigent_discord_channel_create — Create private channel
  • dirigent_discord_channel_update — Update channel permissions
  • dirigent_discord_member_list — List guild members

Policy management:

  • dirigent_policy_get — Get all policies
  • dirigent_policy_set — Set/update channel policy
  • dirigent_policy_delete — Delete channel policy

Turn management is internal to the plugin (not exposed as tools).

See FEAT.md for full feature documentation.

Slash command (Discord)

/dirigent status
/dirigent turn-status
/dirigent turn-advance
/dirigent turn-reset

Config highlights

Common options (see docs/INTEGRATION.md):

  • listMode: human-list or agent-list
  • humanList, agentList
  • endSymbols
  • schedulingIdentifier (default ➡️)
  • waitIdentifier (default 👤) — agent ends with this to pause all agents until human replies
  • channelPoliciesFile (per-channel overrides)
  • moderatorBotToken (handoff messages)
  • enableDebugLogs, debugLogChannelIds

Development plan (incremental commits)

  • Task 1: project docs + structure
  • Task 2: no-reply API MVP
  • Task 3: plugin MVP with rule chain
  • Task 4: sample config + quick verification scripts
  • Task 5: plugin rule extraction + hardening
  • Task 6: containerization + compose
  • Task 7: plugin usage notes
  • Task 8: sender normalization + TTL + one-shot decision
  • Task 9: auth-aware no-reply API
  • Task 10: smoke test helpers
  • Task 11: plugin structure checker
  • Task 12: rollout checklist
Description
Rule-based no-reply gate for OpenClaw
Readme 1.6 MiB
Languages
TypeScript 75.7%
JavaScript 23.8%
Shell 0.4%
Makefile 0.1%