Multi-user desktop pet
- Multiple pets — Compatible with Codex pet packs.
- Custom pet states — Define arbitrary states per pet.
- Multiplayer remote sessions — Sync pet status and chat with peers.
- Agent hooks — Render local hook events as pet bubbles.
- Skills — Built-in compatibility with the community Skills ecosystem.
- Plugins — Claude Code and Codex plugin packages with built-in hook bubbles for prompts, tool calls, permissions, and stop events.
If you drive Eggs through Claude Code, Codex, or another agent that supports the community Skills ecosystem, install it as a skill and let the agent run the commands for you:
npx skills add larchliu/eggsThat drops the eggs skill into your agent's skills directory. The skill ships a tiny launcher (./eggs on macOS/Linux, eggs.cmd on Windows) — on first use it downloads the right prebuilt binary into ~/.eggs/bin/ and caches it. No Rust toolchain, Python, or local build required.
From then on, ask the agent in plain language and it will map the request to the skill's CLI:
| You say | Agent runs |
|---|---|
/eggs or "spawn the desktop pet" |
./eggs start |
| "stop eggs" / "kill the pet" | ./eggs stop |
| "is eggs running?" | ./eggs status |
| "switch eggs to waving" | ./eggs state waving |
| "use local kebo" | ./eggs pet local kebo |
| "join remote random match" | ./eggs remote |
| "join remote room ABC123" | ./eggs remote room ABC123 |
| "leave the remote room" | ./eggs remote leave |
./eggs start and ./eggs restart must run unsandboxed (the GUI has to reach WindowServer / X / Wayland); in Claude Code that means dangerouslyDisableSandbox: true on the launching Bash call. Pure state mutations (state, pet, remote, install, stop, status) are safe to run sandboxed.
See eggs/SKILL.md for the full surface the agent has access to.
The skill-only install lets an agent drive Eggs on demand. The plugin install goes one step further: it also wires up hooks so that prompt submissions, tool calls, permission requests, and stop events from the agent automatically show up as pet bubbles on the desktop — no manual prompting required.
Two plugin packages ship from this repo:
- claude-plugin/ — Claude Code plugin (
SessionStart,UserPromptSubmit,Notification,PreToolUsematcher per tool,Stop,SubagentStop) - codex-plugins/ — Codex plugin (
UserPromptSubmit,PostToolUse,PermissionRequest,Stop)
Both plugins bundle the full eggs skill internally, so installing the plugin gives you both the agent-driven CLI surface and the live hook bubbles.
The repo ships a Claude marketplace manifest at .claude-plugin/marketplace.json. Inside a Claude Code session:
/plugin marketplace add larchliu/eggs
/plugin install eggs@eggs
Restart the session if prompted. After install:
/eggslaunches the desktop companion via the bundled skill.- Hook events fire automatically — every
UserPromptSubmit,PreToolUse(Bash / Read / Write|Edit / Grep|Glob / WebSearch / WebFetch /mcp__*),Notification,Stop, andSubagentStopis rendered as a bubble by claude-plugin/hooks/eggs-claude-notify.js. - Hook commands resolve via
${CLAUDE_PLUGIN_ROOT}, so the install path is portable.
To remove: /plugin uninstall eggs@eggs (and /plugin marketplace remove eggs if you also want to drop the marketplace entry).
The Codex plugin manifest lives at codex-plugins/.codex-plugin/plugin.json, exposed via the marketplace at .agents/plugins/marketplace.json with installation: AVAILABLE.
-
Add the marketplace from your shell:
codex plugin marketplace add larchliu/eggs
-
Launch Codex by running
codexin your terminal. -
Inside Codex, open the plugin browser:
/plugins -
Pick the Eggs marketplace, then the Eggs plugin, and confirm install.
After install:
- The bundled skill exposes the same
$eggsnatural-language surface. - codex-plugins/hooks/hooks.json wires
UserPromptSubmit,PostToolUse(matcher.*),PermissionRequest, andStopto codex-plugins/hooks/eggs-codex-notify.js, each emitting aeggs hook "<text>"bubble.
To remove, reopen /plugins and uninstall from the same UI. Run codex plugin marketplace remove eggs if you also want to drop the marketplace entry.
Heads-up — Codex 0.130.0+ hook regression. Codex's hook dispatch is being reworked. On 0.130.0 and 0.131.0-alpha.4 the lifecycle event still fires (
hook: SessionStart Completedappears in stderr) but the configured command is never invoked — no side-effect files, noadditionalContextreaching the model. This is consistent with the new trust UX: project-level hooks appear to require an interactive TUI trust prompt that headlesscodex execsessions can't surface. 0.128.0 still works end-to-end. Until the trust workflow stabilises, pin tocodex@0.128.0if you need the Eggs hook bubbles in CI / wrapper tools. Upstream tracking: openai/codex#21639. The skill-only install path above is unaffected — only hook-driven bubbles are.
- Node.js must be on
$PATH— both hook scripts are plainnodeinvocations with no extra dependencies. - The hook scripts shell out to the cached
eggsbinary, so the desktop companion must be runnable (./eggs startoreggs startfrom$PATH). The plugin's bundled skill handles the first-time download. - Hooks only render bubbles when a GUI is already running. The plugin does not auto-start the companion on
SessionStart— call/eggsonce per session (or runeggs startfrom your shell) to bring it up. - Hook scripts must run unsandboxed only if they themselves invoke
eggs start. Pure bubble-emit calls (eggs hook "...") are file-driven and safe under sandboxed Bash.
Build and run the desktop binary:
./desktop/dev fast
./desktop/src-tauri/target/release-fast/eggsOr run through wrapper helpers:
./desktop/dev run
./desktop/dev run remoteCommon helper targets:
./desktop/dev fast
./desktop/dev release
./desktop/dev check
./desktop/dev clean
./desktop/dev testThe same binary is both GUI and CLI:
eggs
eggs run
eggs start
eggs stop
eggs restart
eggs status
eggs list
eggs pet <source> <id>
eggs state <name>
eggs install <pet-dir>
eggs hook "<text>"
eggs message "<text>"
eggs remote help
eggs uninstall-cliNotes:
eggs startlaunches detached and writes PID to~/.eggs/eggs.pid.- CLI mutations are file-driven (
state.json/remote.json) and picked up by the running GUI via polling + single-instance forwarding. - First GUI launch from packaged builds attempts best-effort CLI install into PATH (platform-specific).
Remote state is stored in ~/.eggs/remote.json and defaults to:
server_url:http://localhost:8787mode:randomroom_limit:5
Key commands:
eggs remote
eggs remote random
eggs remote room <code> [limit]
eggs remote leave
eggs remote off
eggs remote server <url>
eggs remote status
eggs remote upload [pet_id]Behavior highlights:
remoteandremote onkeep the saved mode/room.remote room <code> [limit]persists invite room mode and cap.remote randomswitches mode without clearing saved room code.- Pet switch in remote mode gates local change on successful upload to keep local/peer view consistent.
eggs pet <source> <id>targets an exact pet source:builtin,local, orremote.- Upload is source-aware (
pet_source + pet) while peer downloads are content-addressed bycontent_idfrom server-provided asset URLs. - The detailed upload/download protocol is documented in
desktop/README.mdunderRemote Asset Flow.
See ## Install as a Plugin (Hooks-Enabled) → Codex above for the recommended path. The Codex plugin bundles the same hook scripts and registers them automatically.
Runtime data is in ~/.eggs/ (or EGGS_APP_DIR override):
state.json: current pet, pet source, state, scale, window positionclient.json: device identityremote.json: remote configeggs.pid: detached GUI pidpets/<id>/: installed petsremote/: cached peer sprite assets and blobsbubble-spool/: queued local bubble events
Pet lookup priority:
EGGS_PETS_DIR(if set, exclusive)~/.eggs/pets$CODEX_HOME/petsor~/.codex/pets- Remote cache under
~/.eggs/remote
Each pet folder:
<pet-id>/
pet.json
spritesheet.webp # or png
pet.json fields used by desktop runtime:
iddisplayNamedescription(optional)spritesheetPath
If you already have 9 horizontal strip images for custom pet states, you can turn them into 192x208 frames and compose a Codex-style 8x9 atlas with:
uv run --with pillow python scripts/build_custom_pet_atlas.py \
--input-dir /absolute/path/to/custom-strips \
--output-dir /absolute/path/to/custom-buildInput expectations:
--input-dirmust contain exactly 9 strip images.- Supported formats are
png,webp,jpg, andjpeg. - The script assumes a chroma-key background and uses
#FF00FFby default. - Rows are ordered by filename sort order, so name the files in the row order you want.
- Each detected frame is centered into a
192x208cell, and unused cells in the8x9atlas remain transparent.
Optional chroma-key override:
uv run --with pillow python scripts/build_custom_pet_atlas.py \
--input-dir /absolute/path/to/custom-strips \
--output-dir /absolute/path/to/custom-build \
--chroma-key '#00FF00'Outputs written under --output-dir:
spritesheet.pngspritesheet.webpcontact-sheet.pngcustom-frames-manifest.jsonframes/<state>/<index>.png
Go server lives in server/:
cd server
go build -o eggs-server .
./eggs-server -addr :8787 -data ./data -base-url http://localhost:8787It uses pure-Go SQLite (modernc.org/sqlite) and does not require system SQLite shared libraries on target hosts.
For app bundles:
cd desktop/src-tauri
cargo tauri buildOutputs are under desktop/src-tauri/target/release/bundle/ (.dmg, .msi, .deb, .AppImage, etc, depending on platform/toolchain).
desktop/ Tauri app (GUI + CLI binary)
server/ Go remote backend
eggs/ Skill assets, scripts, tools, compatibility wrappers
claude-plugin/ Claude Code plugin package (bundled skill + hooks)
codex-plugins/ Codex plugin package (bundled skill + hooks)
.claude-plugin/ Claude Code marketplace manifest
.agents/ Codex marketplace manifest
assets/ Source art and helper assets
scripts/ Release helpers
eggs/scripts/egg_desktop.pyremains useful for compatibility and tooling, but feature development is centered ondesktop/src-tauri.- Existing legacy
state.jsonfields likespriteare still accepted by the desktop runtime (spritealiases topet).
linux.do: an active Chinese tech community focused on AI, software development, resource sharing, and frontier technology discussions. Its vision is "a new ideal community", and its community culture emphasizes sincerity, friendliness, unity, and professionalism.
