Skip to content

Architecture: coding agent integration ​

Scope ​

This describes the current structure of the path through which coding agents (Claude Code, Codex, Gemini CLI, Cursor, and tools that use MCP) tell PlayPets friends their status. It is for people adding a new integration or building tools on the agent side. The architecture of the whole app is in PlayPets app architecture.

The bridge stays inside this computer. Hook adapters omit user prompts and tool inputs, but they forward short notifications and Codex’s last answer. MCP and direct commands can also supply sentences. The app retains recent reports and includes them as labeled status notes in the connected friend’s AI prompt when you chat. That AI may run outside this computer.

Diagram ​

A container-level diagram. It shows everything from what the agent runs to what appears on the friend.

Components ​

ComponentLocationResponsibility
CLI modesrc-tauri/src/agent/cli.rsRunning the app executable with a command argument (hook, mcp, status, say, react, pets, run) runs it in this mode with no window. Node.js is not needed
Hook translationagent::cli::hook_eventTurns each agent's hook payload into a state and a code. Prompts and tool inputs are not sent
MCP serveragent::cli::mcp_replyAn MCP server that takes JSON-RPC one line at a time over standard input and output. Four tools
Bridgesrc-tauri/src/agent/bridge.rsThe HTTP server inside the app. A random port on 127.0.0.1, a token check on every request, browser requests refused
Event handlingsrc-tauri/src/agent/mod.rsTurns codes into sentences in the current language, remembers them as recent activity, and shows them as the friend's status
Settings snippetsconnection_snippet in agent/snippets.rs (the agent list is in agent/kinds.rs)The Settings tab's "Copy settings" builds the snippet to paste into each agent's settings file. It contains the executable path and the bridge.json path, and if a friend was picked for that agent in the Settings tab, it adds --pet <friend id> (PLAYPETS_PET for MCP). The assignment is saved in AppData.agent_pets and removed when that friend is sent away

Data flow ​

  1. When the app launches: The bridge opens on 127.0.0.1:0, and the app writes the port it got and a new token (64 random characters) to bridge.json in the data folder. Both change every time the app restarts.
  2. Hooks: At each step the agent runs playpets hook claude --bridge <bridge.json> and passes the hook JSON on standard input (Codex passes the notification JSON as the last argument). CLI mode turns it into a state and a code and sends it with POST /events. So it never blocks the agent's work, a hook is quiet, finishes within 3 seconds, and exits with code 0 even when it fails.
  3. MCP: The agent starts playpets mcp as an MCP server and sends initialize, tools/list and tools/call. Tool calls go through the same bridge path.
  4. Commands: A person or script can call it directly, as in playpets say "Tests passed". playpets run -- npm test sends working while the command runs, then done or error when it ends.
  5. Inside the app: The bridge checks the token and the payload and finds the friend (pet/petId is an id or a name; if absent, the first friend). A code turns into the current language, as in @tool Bash → "Using Bash", shows above the friend, and is remembered among that friend's 8 most recent activities.

When a gallery adds a playpets://import?url=<pet page address> link, the operating system hands the link to PlayPets (src-tauri/src/links.rs), and the app imports the pet through the same path as a pasted address, then opens the Invite tab. The scheme is registered under plugins.deep-link in tauri.conf.json, and a link received by a second launch is handed over by the single-instance plugin. Other kinds of links are ignored.

Interfaces ​

CLI commands: the common options are --pet <id or name> (default: the first friend, or PLAYPETS_PET) and --bridge <path to bridge.json> (default: the data folder, or PLAYPETS_BRIDGE).

CommandWhat it does
playpets petsFriend list and states
playpets status <state> [message]Status notification
playpets say <message>Only a speech bubble, without changing the state
playpets react <wave|jump|pet>A one-off reaction
playpets run -- <command…>Status notifications while a command runs
playpets hook <claude|gemini|cursor>Handles hook JSON on standard input
playpets hook codex <json>Handles a Codex notification
playpets mcpMCP server (standard input and output)

States and reactions: the states are idle, working, waiting, done and error; the reactions are wave, jump and pet.

Hook translation: events not in the table are not sent. The app turns codes into the current language.

Agent eventStateSentence sent
Claude UserPromptSubmit, Gemini BeforeAgent, Cursor afterAgentThoughtworking@thinking
Claude PreToolUse, Gemini BeforeTool, Cursor postToolUseworking@tool <tool name>, or @tool_any when there is no name
Cursor afterFileEdit, afterShellExecution, subagentStartworking@editing, @command, @subtask
Claude, Gemini NotificationwaitingThe agent's notification sentence, or @confirm when there is none
Claude Stop, Gemini AfterAgent, Cursor stopdone@done
Claude, Gemini SessionEnd, Cursor sessionEndidleNone
Codex agent-turn-completedoneThe last answer (120 characters), or @done when there is none
playpets run start, failureworking, error@running <command>, @failed <exit code>

HTTP bridge: every request needs Authorization: Bearer <token from bridge.json>. Requests with an Origin header (browsers) are refused. The body is JSON of 8KB or less, and sentences are cut at 240 characters.

RequestBodyResponse
GET /petsNone[{id, name, state}]
POST /events{pet or petId, state, message}{ok, petId}
POST /say{pet, message}{ok, petId}
POST /react{pet, action}{ok, petId}

Error responses are 400 (bad payload), 401 (missing or wrong token), 403 (browser request), 404 (unknown path or friend) and 413 (over 8KB).

MCP tools: protocol version 2024-11-05.

ToolInputWhat it does
list_petsNoneFriend list and states
set_pet_statestate (required), message, petStatus notification
saymessage (required), petSpeech bubble
reactaction (required), petReaction

Environment and touchpoints ​

The Settings tab's "Copy settings" tells you which file to paste into.

AgentSettings fileWhat you paste
Claude Code~/.claude/settings.jsonA hook claude command for each event
Codex CLITop of ~/.codex/config.tomlnotify = [executable, "hook", "codex", …]
Gemini CLI~/.gemini/settings.jsonA hook gemini command for each event
Cursor~/.cursor/hooks.jsonA hook cursor command for each event
Other MCP toolsEach tool's MCP settingsThe playpets mcp server

When installed through MSIX on Windows, the executable lives under WindowsApps and cannot be run by path from outside. In that case the settings snippet points at the execution alias (%LOCALAPPDATA%\Microsoft\WindowsApps\playpets.exe).

Change history ​

  • 2026-09-29 Moved hooks, MCP and status commands into the CLI mode of the app executable (no Node needed)
  • 2026-09-30 Hook states are sent as codes so they show in the app's language. CLI and MCP text is fixed to English
  • 2026-09-30 With an MSIX install, the settings snippet points at the execution alias

Free and open source under the MIT license. Not affiliated with OpenAI; Codex is a trademark of OpenAI.