Claw'd lives on your desktop and shows you what Claude Code is doing.
Every state, in order. Rendered from the sprite rig, not screen-recorded.
Claude Code tells you what it is doing inside the terminal. The moment you switch to a browser, a design tool, or another repo, that goes dark β and if you run several sessions at once, it was never visible in the first place.
Claude Pet puts it back where you can see it. Claw'd sits on the desktop, always on top, and reflects your sessions continuously: what tool is running, what task is in progress, which one just finished, and which one is stuck waiting on you. No window to check, no tab to switch to. You just glance at him.
He floats above your windows, follows you across Spaces, and can be dragged anywhere β including onto a second display. He watches every running Claude Code session, mirrors whichever one is busiest, and clicking him opens a roster of them all so you can pin one.
Each one is driven by something real on disk, and each says what it is reacting to.
Every seven seconds, one of six unprompted little things β picked per window and played through as a shape rather than a frequency, so it never stutters halfway.
![]() Jump |
![]() Stretch |
![]() Look around |
![]() Scuttle |
![]() Wave |
![]() Wiggle |
Clicking him opens every live session at once: what each is doing, which project it is in, and which one he is currently mirroring. Click a row to pin him to that session; click it again to go back to following the busiest.
These sessions are invented. The real panel lists your actual project directories β which is exactly why the picture does not.
Download the .dmg from
Releases, open it, and
drag Claw'd to Applications.
First launch shows "unidentified developer". This is expected. The app is ad-hoc signed and deliberately not notarized β notarizing would publish the author's legal name and Apple Team ID inside every copy. To open it:
Right-click the app β Open β Open. Once only.
Or, if you prefer the terminal:
xattr -dr com.apple.quarantine /Applications/ClaudePet.appIf you would rather not run someone else's binary at all β completely fair β build it yourself. It takes about thirty seconds.
Claw'd has no Dock icon. He lives in the menu bar: click the little crab there for size, sounds, notifications, Open at login, session pinning, and hook installation. He reappears wherever you last dragged him, on whichever display you left him on.
git clone https://github.com/internetdialup/claude-pet.git
cd claude-pet
./run.shThat builds the executable, assembles build/ClaudePet.app, ad-hoc signs it, and
launches it. Requires macOS 14+ and a Swift 6 toolchain (Xcode 16 or newer).
swift build --product ClaudePet # the Build Target from AGENT.md
swift test # unit tests; synthetic fixtures, never touches ~/.claude/
./scripts/make-icon.sh # regenerate the app icon from the sprite rig
./scripts/make-dmg.sh # build the installerThree offline modes are useful when working on it:
.build/debug/ClaudePet --render-sheet out.png # contact sheet of every mood and prop
.build/debug/ClaudePet --render-gif docs/media # the GIFs above
.build/debug/ClaudePet --probe # print the PetState from your real sessions
.build/debug/ClaudePet --probe 320 # ...after watching for 320s, past the decay horizons
.build/debug/ClaudePet --render-marketing out/ # large transparent stills and loopsEverything Claw'd says lives in two files β no strings scattered through the codebase, no localisation framework, no config format to learn:
| File | Holds | |
|---|---|---|
| π¬ | Support/vocab.swift |
What he says in the speech bubble |
| π | Support/notification-nudge.swift |
What the macOS banners say |
Both are the same shape β an exhaustive switch returning [String] β so
learning one teaches the other. Edit the arrays, run ./run.sh, and he says
your words instead.
| Occasion | When he says it | Ships with | |
|---|---|---|---|
| π¬ | .idle |
Sessions are live but Claude is between tasks | "Let's build something awesome!" Β· "Ooo that's a spicy idea πΆοΈ" |
| π | .thinking |
Reasoning, no tool running | "Thinking it through" Β· "Give me a second" |
| βοΈ | .working |
A tool is in flight | "On it" Β· "This is the fun part" |
| π₯ | .cooking |
Going hard β rapid calls, or a subagent fan-out | "Absolutely cooking π₯" Β· "Do not disturb" |
| π | .planReady |
A plan is up and he wants your verdict | "Plan's ready π" Β· "Shall we?" |
| β | .finished |
A turn just ended | "Nailed it" Β· "That's a wrap π¬" Β· "Chef's kiss" |
.needsYou |
Claude is blocked on you β usually a permission prompt | "Psst β I need you" Β· "One quick question" | |
| π΄ | .sleeping |
Nothing is running at all | "zzzβ¦" Β· "Resting my claws" |
This is the one thing worth reading before you edit, because otherwise it looks like your lines are being ignored:
| Precedence | Example | |
|---|---|---|
| 1οΈβ£ | A rule matching the current task | git commit β¦ β "Committing the good stuff π¦" |
| 2οΈβ£ | The real task text, whenever there is one | "Running the test suite" |
| 3οΈβ£ | The state's lines | "This is the fun part" |
Rank 2οΈβ£ is deliberate: while Claude is actually running something, the bubble
shows what it is running. A pet that hides "Running the test suite" behind a
joke is a worse pet. So your .working and .cooking lines fill the gaps
between tools rather than replacing anything useful, and .sleeping speaks
only occasionally β a sleeping pet that talks constantly is not asleep.
Find the occasion, change the strings. That is the whole job:
// π¬ Between tasks. Encouragement, mostly.
case .idle: [
"Let's build something awesome!",
"Now we're cooking with crisco π³",
"your line here", // β add as many as you like
]Rules let him say something specific when the task matches a pattern. The first match wins, so put the specific ones first:
public static let rules: [VocabRule] = [
VocabRule(#"\btest(s|ing)?\b"#, [
"Writing tests, the good kind π§ͺ",
"Red, green, refactor",
]),
VocabRule(#"\bdeploy\b"#, ["Shipping it π"]), // β yours here
]| Ships with | Fires on | |
|---|---|---|
| π§ͺ | tests | test, tests, testing |
| π¦ | commits | commit, git |
| π | debugging | fix, bug, debug |
| π | docs | README, doc, docs, document |
Patterns are case-insensitive regular expressions. A pattern that doesn't compile is skipped, not fatal β a typo in your vocabulary should never take the pet down.
Add a case to ShoutoutOccasion and the build will fail until you give it
lines. That is deliberate β lines(for:) is a switch, not a dictionary, so
the compiler catches a half-added occasion instead of Claw'd silently saying
nothing at runtime.
| Keep it short | The bubble cuts off at 29 characters β it caps at 210pt, the font advances 6.62pt per character, and 194 Γ· 6.62 β 29. A test enforces it. |
| Emoji are welcome | They render fine β but count each as two characters, since they draw about twice as wide. π³ πΆοΈ π¬ all ship by default. |
| He deals a deck | Lines are dealt like a shuffled deck: every line is used once before any repeats, and the shuffle is reseeded each pass. A plain random pick would show one line four times and another never. |
One bubble per state. The fill, the glyph and the text all come from the two files above.
Same idea, second file. notification-nudge.swift holds the title and body for
each banner, and Claw'd's own icon rides along with it:
| Event | Fires when | Default | |
|---|---|---|---|
| β | .finished |
A turn ends while you are looking elsewhere | on |
.needsYou |
Claude is blocked on you | on | |
| π | .planReady |
A plan is waiting for approval | on |
| π₯ | .cooking |
A session starts really going | off |
.cooking ships off because it fires often; turn it on from the menu bar under
Notify when cooking π₯. All four respect the master Notifications toggle.
Banner copy has a tighter budget than the bubble: titles under 40 characters, bodies under 80, because macOS truncates. The session name is appended for you, so don't repeat it. A test enforces both limits.
Selection is driven by a seed, never random() β the bubble is recomputed on
a timer, so a real RNG would rewrite the sentence out from under you mid-read.
Claude Code already writes everything needed, and the pet only reads it:
| Source | What it gives |
|---|---|
~/.claude/sessions/<pid>.json |
Live session registry. The filename is the PID, so liveness is kill(pid,0) plus a procStart match to guard PID reuse. |
~/.claude/projects/<encoded-cwd>/<id>.jsonl |
The transcript. tool_use blocks give the running tool and its description; thinking blocks and stop_reason give the rest. Also the model and git branch. |
~/.claude/tasks/<id>/*.json |
Todos. The in-progress item's activeForm is already phrased for a human, so it wins the bubble. |
| Hooks (optional) | PreToolUse / PostToolUse / Stop / Notification for sub-100ms reactions, and the only way to see a permission prompt. |
Filesystem watching is the ground truth; hooks are a latency optimisation on top. That ordering is deliberate β hooks are blind to sessions that started before they were installed, so the pet has to be correct without them.
While idle, Claw'd rotates encouragement with a status ticker: the model answering, how many sessions are live, how long you have been coding today, and the project and branch.
The weekly and 5-hour usage lines will probably not appear. Claude Code no longer publishes rate-limit percentages to disk, and this app will not invent a number it cannot measure. The code reads the usage cache and freshness-gates it, so those lines light up on their own if the data ever comes back. An empty line is the honest answer; a made-up percentage is not.
~/.claude/ is your live working data. The rules are in Bamboo.md Β§5 and Β§6:
- Read-only for everything Claude Code owns β sessions, transcripts, todos,
settings. The pet writes in exactly two places, neither of which is Claude's
data: its own event drop-directory
~/.claude/claude-pet-events/, and the hook installer, which is user-initiated from the menu bar, shows you the exact change first, and copiessettings.jsontosettings.json.bak.<timestamp>before writing. - Every read is a bounded tail. Transcripts reach 85 MB; a full read is a hang, not a slow path.
- No network. At all.
Package.swifthas an emptydependenciesarray, which makes that checkable rather than promised. Nothing is uploaded, no telemetry, no analytics, no crash reporting. - Tests never touch
~/.claude/.
Claw'd is Anthropic's mascot. He is drawn, not imported β a parametric rig
rasterised into a 32Γ32 indexed buffer each frame
(Sources/ClaudePet/View/). Flat colour, no outline,
no shading ramp, whole-pixel motion. He is not a sprite sheet, so a new pose is a
few numbers rather than a new asset, and the app icon is rendered from the same
rig so the two can never drift apart.
Every prop, from the same rig β no sprite sheet anywhere.
This project is unofficial and not affiliated with or endorsed by Anthropic. See LICENSE.
See CHANGELOG.md. Currently v1.3.0.
The repo follows Bamboo, a governance discipline for AI-assisted codebases. Start
at AGENT.md, then Bamboo.md, then
docs/ctx-orientation.md for why things are the way
they are. development/swift-development.md
is the structural standard for the Swift itself.
Two rules worth knowing before you open a PR:
- Exit codes are the evidence. "It builds" needs
swift buildexiting 0. - Never read a transcript whole. Bounded tails only.
MIT licensed.





















