Entry point for AI coding agents (Codex et al.). Read this first, then the handoff + follow-ups docs linked at the bottom.
A native macOS menu-bar app: animated pixel "pets" that sit on your screen and react to your coding agent's state (idle / coding / researching / waiting / done / blocked / error / long-running). Driven by Claude Code / Codex hooks, an HTTP API, an MCP server, and a CLI. SwiftPM + AppKit + SwiftUI, macOS 14+, zero external dependencies.
swift build # build all targets
swift test # 192 tests, 0 failures (the green baseline)
./scripts/verify_runtime_assets.sh # "runtime assets verified" + "verified 12 roster creatures"
git diff --check # must be clean
python3 scripts/test_slice_sprites.py # sprite slicer self-test (needs Pillow)
# Run the app for live testing. NOTE: ./script/build_and_run.sh --verify is FLAKY in
# headless/asleep-display envs (the `open -n` bundle launch sometimes never binds the port).
# The bare binary binds reliably:
nohup .build/debug/AgentPets >/tmp/agentpets.log 2>&1 &
# poll: lsof -nP -iTCP:47771 -sTCP:LISTEN
.build/debug/agent-pets spawn --id d1 --name Demo --state coding --appearance fox
.build/debug/agent-pets remove d1 ; pkill -x AgentPetsThe local HTTP API listens on 127.0.0.1:47771 (GET/POST /v1/pets, .../state,
.../appearance, .../end, DELETE /v1/pets/<id>, POST /v1/layout/lineup, /v1/demo).
AgentPetsCore— pure logic (models, config resolution, stores, hooks, MCP planning). The only unit-tested target (Tests/AgentPetsCoreTests,@testable import AgentPetsCore).AgentPets— the macOS app (AppKit/SwiftUI overlay, dashboard, services). Executable target — NOT covered by the test target. Verify app code withswift build+ the runtime/screenshot checks, not XCTest.AgentPetsCLI(agent-pets) — CLI + hook driver.AgentPetsMCP(agent-pets-mcp) — stdio MCP server (set_status,set_pet).
- Overlay rendering is fragile and hard-won. Do NOT change
SpriteFrameViewwindowing,PetPanelMetrics(panel 128 > sprite 72), orPetViewcentering. Per-pet scale is a SwiftUI.scaleEffectclamped to 0.7–1.6 (SessionStore.scaleRange). If you touch overlay rendering: rebuild, spawn pets at scale extremes across done/waiting/error/coding,screencapture -x, confirm full bodies / no clipping BEFORE committing. - Sprite manifests are state-keyed and SQUARE. Each
Resources/Pets/<id>/manifest.jsonmaps all 8AgentPetStateraw values →{file, frames, fps, loop};frameWidth == frameHeight(SpriteFrameViewwindows square cells).verify_runtime_assets.shenforces this. - API stays back-compat.
appearanceIdis a free string; unknown/legacy ids coerce to the default viaPetAppearance.resolved(for:). New model fields decode-if-present with safe defaults. Hook driver always exits 0. SessionStoreis a plain class, notObservableObject. UI bridges via the.agentPetsStoreChangedNotificationCenter signal (same path the HTTP API uses).- Atomic conventional commits ending with the trailer:
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>(swap to your own attribution as appropriate). Keepswift testgreen per commit. Branch for feature work; do not commit tomainwithout intent.
Roster = Sources/AgentPetsCore/Resources/roster.json (metadata) + per-creature folders
Sources/AgentPets/Resources/Pets/<id>/. To add one: download a CC0 source into downloads/
(gitignored), write scripts/sprite_recipes/<id>.json, run
python3 scripts/slice_sprites.py scripts/sprite_recipes/<id>.json, add a .copy("Resources/Pets/<id>")
to Package.swift, add the roster.json entry + a CREDITS.md row, then verify + swift test.
Full procedure + gotchas: docs/superpowers/agent-pets-working-handoff.md → "Pet Roster & Sprites".
docs/superpowers/2026-06-07-codex-handoff.md— full orientation + repo map for picking this up.docs/superpowers/2026-06-07-followups.md— prioritized backlog + every known caveat.docs/superpowers/agent-pets-working-handoff.md— running handoff (dashboard + roster details).docs/superpowers/agent-pets-progress-tracker.md— milestone status.
Game/ contains AgentPets Village, a self-contained Animal Crossing-inspired browser
game (plain HTML5/JS, zero dependencies, no build step) that reuses the CC0 creature
sprites as its villager cast. It is fully independent of the Swift targets — nothing in
Package.swift references it, and it must stay launchable on its own
(./Game/play.sh or opening Game/index.html).
- Verify with
node --test "Game/tests/*.test.mjs"(logic suite + headless boot smoke test; needs Node 18+). Keep this green likeswift test. - Pure logic lives in
Game/js/village.*.js(browserVGnamespace + CommonJS exports for the tests); browser-only code inGame/js/engine.*.js,ui.js,main.js. Classic scripts only — no ES modules, sofile://keeps working. Game/assets/pets/is a copy ofSources/AgentPets/Resources/Pets/(plusGame/js/sprites.data.js, generated from the manifests). If roster art changes, refresh the copies.- Saves are versioned
localStorageJSON merged over fresh defaults (village.state.jsdeserialize) — add new fields with safe defaults, never break old saves.
Game2/ is a Cargo workspace: burrow (a from-scratch 2D engine, zero crate
dependencies, targets wasm32-unknown-unknown through a hand-rolled extern "C" ABI
with zero wasm imports) and village2 (the comprehensive Animal Crossing-inspired
game). The JS host is Game2/web/host.js. The v1 JS game in Game/ stays playable and
untouched.
- Verify with
cd Game2 && cargo test(73 native tests) andnode --test "Game2/tests-node/*.test.mjs"(headless sessions driving the actual wasm — Node can instantiate it because the ABI imports nothing). Keep both green. - Build/ship with
Game2/build.sh: regenerates sprite tables (tools/gen_sprites.py— keepsgame/src/data/sprites_gen.rsandweb/sprites.host.jsin lockstep with theGame/assets/petsmanifests), compiles release wasm, base64-embeds it intoweb/game.wasm.js(sofile://works), and syncs sprite assets. The generatedweb/game.wasm.jsIS committed so a clone plays with no toolchain — rerunbuild.shand commit it after Rust changes. - ABI invariants (engine/src/platform.rs + web/host.js must agree): draw commands are
12 f32s;
Sfxrepr(u32) ids match host's SFX table; key codes matchButton::from_codeand hostKEY_CODES. Saves are versioned JSON in localStorage keyagentpets-village2-save, merged over defaults — never break old saves. - Engine code never touches browser APIs; if it can't run under
cargo test, it doesn't belong inengine/orgame/.