ADR 0175: Rivals Agent is a gameplay skill
Status: accepted (James, 2026-09-20). Amended 2026-10-17 (VUH-2419): the Clankie side moved out of core into an external game extension; see the amendment below.
Decision
Clankie uses Rivals Agent for both Spider-Man tactics and controller execution. Clankie owns the sitting's purpose, conversation, and what he remembers. The Rivals process owns perception, tactical decisions, and the fast guarded pad loop. The Pokémon body seam remains specific to Pokémon.
Contract
POST /v1/rivals and the captain's rivals tool share one validated command
schema. Commands are status, start, objective, observe, share, and
stop. CLI and TUI use the same operator API. The service resolves the
rivals-agent bearer from its broker and reads gameplay.rivalsUrl live.
Redirects are refused; response bodies are bounded.
The server runs in the PC's interactive desktop session. It opens capture and
the pad only when a sitting starts. A start has an idempotency key; subsequent
commands name the observed session ID, so a delayed stop cannot kill a new
sitting. Starts return starting; only a guarded loop tick establishes
running. Each sitting is bounded to 1–1800 seconds (default 300), and stop
requests return stopping until the loop releases its pad. The existing
practice-range guards remain authoritative. This API does not navigate menus,
queue matches, or expose raw inputs or a shell.
Objectives have mode and a prose note. autonomous uses the scripted tactical
policy, combat practices ordinary engagement while preserving its retreat
guard, and disengage asks the controller to withdraw. Notes are retained context;
noteApplied: false states that the current scripted policy does not interpret
them. This is not a claim that a learned policy is installed.
The observer publishes only frames whose range HUD is confirmed. Missing or
older-than-one-second frames refuse. PNG encoding happens on the reader thread,
outside the control loop. A read-only watch capability names one sitting and
expires when it stops; it cannot call control endpoints. Go Live consumes that
same frame source through the existing PNG publisher. A publish request is
requested, not live; the existing Vox media receipt proves delivery. There
is no game-audio feed in this integration.
Alternatives and limits
Generalizing the GBA action schema would mix battle menus and real-time tactics in one contract. A separate small client preserves both domains. Routing each stick input through Clankie's model would put network/model latency in the reflex loop; high-level objectives avoid that.
The bridge's --dry mode runs recorded pixels through real perception, policy,
and controller with a fake pad. It reports execution: replay; it verifies the
integration, not closed-loop gameplay skill. Live PC and Discord delivery need
their own evidence. Only one operator may own the PC desktop at a time, including
other Rivals development scripts. See setup and
VUH-1316.
Amendment: Rivals is an external game extension (James, 2026-10-17, VUH-2419)
James moved Rivals out of Clankie's core. The client, command schema, sitting
service, rivals tool, POST /v1/rivals route and gameplay skill now live in
the Rivals Agent repository under
clankie-extension/, beside the session server they drive. Core keeps no Rivals
code, settings, credentials wiring, CLI/TUI commands or skill: gameplay.rivalsUrl
is retired (dropped on load), clankie rivals and /rivals are gone, and
docs/rivals.md is a pointer.
The boundary above is unchanged. Clankie still owns the sitting's purpose, conversation and memory; Rivals Agent owns perception, tactics and the guarded pad loop. The extension keeps the same contract, exact-stop rules and receipt recovery, and its fault-injection suite runs against a real Clankie core.
It implements the public module contract that ADR 0234's amendment adds to
@clankie/game-extension: the owner installs it with
clankie games extensions add MODULE url=ORIGIN, which records the module path
in gameplay.extensions; the service loads it at start and hands it the durable
play ledger, lifecycle wrapper, its own broker credentials (rivals-agent), a
state directory and the Go Live port. Re-enabling under
VUH-1325 therefore needs only
installing or registering the extension, never a core change. The bridge stays
disabled; installing it authorizes no sitting.
The old core record <state>/body/rivals-session.json is not migrated; the
extension keeps its own under <state>/game-extensions/rivals/. When it moved,
the owner's state root had no such record and no play claim (checked
2026-10-17), so nothing was held across the move.
