0077 — Agent Force is the dispatcher: an @-mention of it makes ONE pick of the driver, and both seats work the ask

1. The decision

  1. @Agent Force <question> is an ask of every agent in the channel, and the ONLY door (amended 2026-10-30, below). A person's message that @-mentions the Agent Force bot user is admitted by agents_ask.mention_ask, with the mention stripped from the question, in channels and threads. Agent Force's uid is found by name (users.list) with an AGENT_FORCE_USER_ID override; unfound, the mention means nothing.
  2. The pick is one function. thread_driver.ask_pick holds the rules (a seat the question names alone; the thread's driver; a sticker on the thread's root; the area rule on the asker), and every caller (both seats, the dispatcher) runs it. Membership follows: a pick outside the channel goes to a seat that is in it.
  3. Agent Force makes the pick; the seats obey it. The dispatcher (Agent Force's own Socket Mode connection, its own tokens) receives app_mention, runs the pick, and posts ONE thread reply under the ask: <@driver> drives · <@other> adds after, carrying metadata agent_force_pick {ask_ts, asker, driver}. On an @Agent Force ask each seat waits a bounded ~8 s for that post and takes its role from it.
  4. A missing dispatcher degrades to the seats' own pick, never to silence. No pick post within the wait (the daemon is down, its tokens unset, or the seat is on code without the wait) → the seat runs the same ask_pick itself, exactly as agents: does. This is one path with a bounded wait, not a switch: the seats cannot know whether the dispatcher is up (Trinity's seat is another machine), and a configured "dispatcher on" flag would be a second driver of the same decision.
  5. Both seats work the ask. The driver answers. The other seat, once the driver took it, waits for the driver's answer to turn final (ADR-0071 turn-taking, bounded by the same 180 s) and then takes ONE turn whose brief quotes that answer and asks only for what improves it: a correction, a missed risk, a missing step. It never restates the answer (one voice per point), @-mentions the driver only for a correction, and abstains when it has nothing to add. (As first written, agents: and /agents kept one answer and a 👀; both are retired, see the amendment.)
  6. Agent Force never answers a question and is never a seat. It is not on the seat roster, it is removed from every seat set the pick sees, and its only post is the dispatch line.

2. Why this shape

3. Consequences

4. Slices

Part What Repo
1 the @Agent Force door, uid by name, never a seat agent-harness #1752
1b the teammate turn after the driver's final (§1.5) agent-harness
2a the dispatcher daemon, dark: receives the mention, logs its pick; ask_pick hoisted agent-harness
2b the dispatch post, and the seats' bounded wait for it (§1.3-1.4) agent-harness

Amendment 2026-10-30: @Agent Force is the one door

Gera, the same day, after the first live test: "That was just like a hack. I really like the Agent Force idea a lot better." The /agents slash command (2026-10-28) and the agents: message prefix (its in-thread stand-in) are retired; @Agent Force is the one way to call in the agents. Two doors to one engine would be a switch, and a fix is one path, never a switch.