Agent

Drive Cabo from any language.

cabo-agent runs one player as a language-neutral JSONL subprocess controlled through standard streams.

Start an Agent

Agents that support the open Agent Skills format can install Cabo's complete match workflow alongside the CLI. Node.js 22 or newer is required.

npx skills add allenhooray/cabo-game --skill cabo -g
npm install --global @cabo-game/cli

The Cabo Skill covers room selection, legal actions, waiting, reconnect recovery, round readiness, and clean shutdown.

Copy this prompt directly into an Agent:

请安装并使用 Cabo Skill;如果本机没有 cabo-agent,也安装 @cabo-game/cli。启动一个名为 Codex-Cabo 的持久 cabo-agent 子进程,为它创建并保留独立的 session 文件。先列出房间并加入一个 canJoin=true 的公开房间;如果没有,就创建名为 “Codex Cabo table”、目标分 100 的公开房间,告诉我 room ID,并保持进程运行等待其他玩家。始终以最新 observation 为准,只从 legalActions 选择动作;没有合法动作时等待新帧,不要猜测或轮询。自主完成每个回合,在 ROUND_RESULT 合法时确认下一回合,持续玩到 MATCH_RESULT。超时或状态不确定时先 observe,断线时按 Skill 的重连流程恢复,绝不要为了重连而 leave 或关闭进程。比赛结束后告诉我赢家和最终比分,发送 shutdown,并等待进程正常退出。

Start an Agent

npm install --global @cabo-game/cli
cabo-agent --name Bot-A --request-timeout-ms 15000

Use --server URL for another server and --session-file PATH to persist reconnect state for this Agent. Give every concurrent Agent a distinct session file.

cabo-agent --help
cabo-agent --version
cabo-agent --print-schema

The discovery commands exit immediately and never connect to a server. The JSON Schema comes from the same definitions used by the running CLI.

Process contract

  • stdin and stdout contain exactly one JSON object per line.
  • stderr is diagnostics only; never parse its wording as protocol.
  • Every request carries a unique, non-empty string id.
  • Requests run serially, but pushed events and observations may appear before the matching result.
  • The first frame is always ready; startup failures use a fatal frame and a non-zero exit.
{"type":"ready","protocolVersion":7,"cliVersion":"0.1.0","server":"https://cabo-api.human404.link","name":"Bot-A","sessionPersistence":false,"requestTimeoutMs":15000,"capabilities":["describe","ping","json-schema","request-timeout"]}
{"id":"about","type":"describe"}
{"id":"health","type":"ping"}

Supervisor loop

  1. Wait for the ready frame.
  2. Send create, join, or reconnect.
  3. Keep the latest observation as the source of truth.
  4. Select a concrete action from legalActions. For replace, use its bounded position-selection descriptor.
  5. Send it inside an action request and correlate the eventual result by ID.
  6. Repeat when a newer observation arrives.
{"id":"create","type":"create","memoryMode":"classic","turnDurationSeconds":60,"visibility":"public","targetScore":100,"roomName":"Bots' room"}
{"type":"observation","roomId":"abc123","roomName":"Bots' room","selfId":"session-id","revision":3,"state":{"phase":"TURN_START","round":1,"targetScore":100,"currentPlayerId":"session-id","caboCallerId":null,"drawSource":null,"mismatchPenaltyCardPending":false,"discardTop":{"label":"6H","rank":6},"deckCount":43,"players":[],"winners":[],"roundHistory":[]},"knowledge":{"round":1,"slots":[{"label":"4C","rank":4},null,null,null],"opponents":[],"held":null},"legalActions":[{"type":"draw-deck"}]}
{"id":"move-1","type":"action","action":{"type":"draw-deck"}}
{"type":"result","id":"move-1","ok":true,"data":{"revision":4}}

State and recovery

An observation combines public game state, the Agent’s private remembered cards, and every currently legal concrete action. Successful state-changing results are emitted only after the client has observed their acknowledged revision.

Use events for incremental logs and notifications, not as the authoritative game state. A request timeout returns uncertain: true; state-changing requests are then rejected with STATE_UNCERTAIN until a successful observe refreshes the view. ping, leave, and shutdown remain available.

Sessions and shutdown

Without --session-file, the Agent writes no reconnect state. With one, a successful reconnect can reclaim a seat that is still inside its grace period.

  • leave releases the seat and keeps the process running.
  • shutdown waits for the active request, leaves, returns a result, and exits 0.
  • Closing stdin performs the same graceful shutdown.
  • SIGINT and SIGTERM leave gracefully and exit 130 and 143.

For every request and frame shape, read the complete Agent JSONL protocol.