PetForge
Live · npm v3.6.0Local-first RPG progression layer for Claude Code — a deterministic ASCII pet that evolves from real coding activity (5 official hooks, 6 phases, 46 medal achievements, 19 species, embedded OTel collector, mobile PWA web view). Shipped on npm in 2 days / 64 commits / 9 releases.
Why I built it
Anthropic shipped Claude Buddy in April 2026 — a terminal tamagotchi natively integrated in Claude Code, with 18 species, 5 rarities, 5 stats. Brilliant product. But it stops there: no levels, no evolution, no progression. The community asks for it on GitHub the first week. No one delivers. I saw a structural gap — not cosmetic — and built the missing layer. PetForge is neither a fork, nor an extension, nor a copy: it's an independent engine that can display Buddy when present, and generate its own pet when not. 64 commits / 9 public releases in 2 calendar days, shipped on npm as `@mindvisionstudio/petforge`.
Structural technical decisions
All state lives in ~/.petforge/state.json (file-locked via proper-lockfile on a dedicated sentinel, atomic tmp+fsync+rename writes). Zero telemetry, zero account, zero phone-home. Windows-specific hardening: retry EPERM/EBUSY/ENOENT/EACCES on fs.rename (Defender, OneDrive, indexers) with exponential backoff 50/150/400 ms, max 4 attempts under the 1s hook timeout. Silent recovery: a corrupt state.json is saved as .corrupt.<ts>.json then recreated — a hook never crashes Claude Code.
Not a single 'claude' or 'buddy' in the package name, repo name, CLI name, or assets. Buddy is invoked at runtime only via `claude /buddy card` (= reading public stdout). The `petforge buddy import` integration parses an Anthropic ASCII card from stdin/file, strips out stat lines to avoid duplicates, and stores the visual locally without redistribution. No scraping, no automatic fetch, no internal file copy.
The deterministic engine is the product (19 species × 6 phases × 5 rarities × shiny = 570 visual combos). Beyond that: an OTLP/HTTP/JSON daemon (`petforge collect`) that ingests official Claude Code metrics (code.lines.added, tokens.in/out, cost.usd, pull_request.created…) and unlocks 12 achievements gated on real session quality (Code Architect 10K, Cache Lord ≥80 %, Frugal Coder 100p ≤ $1). Single-file web view (`page.ts`, 1,033 lines of HTML+CSS+JS in one template literal) served over SSE in real time + installable PWA manifest for mobile.
v1: sprites + VS Code extension (rejected — install friction, audience too narrow). v2: RPG layer wrapping Buddy directly (rejected after license review + dependency risk). v3 (shipped): standalone engine, Buddy as opt-in, trademark-clean Apache 2.0. Three iterations of design before the first line of code, then 9 npm releases in 2 days (v1.0, v1.1, v1.2, v2.0, v2.0.1, v2.0.2, v2.1, v3.0, v3.1, v3.2, v3.3, v3.4) — fast iteration capability demonstrated. No tech debt: 0 TS errors, 1 `any` across 9,596 lines, biome clean.
The non-trivial challenge
Three parallel risks: (1) Anthropic ships the same feature (medium probability, low impact if the PetForge engine is core and Buddy just optional); (2) Buddy gets deprecated or changes format (mitigated — runtime detection + silent fallback); (3) trademark complaint if we flirt with Buddy/Claude in naming or copy assets (very low probability, critical impact — covered by absolute separation: zero Anthropic words, zero copied assets, runtime invoke only). The real challenge isn't technical, it's legal-strategic: finding the right cleavage that lets you exist without depending, copying, or provoking. Plus the cross-platform challenge: keeping 5 Claude Code hooks under 50ms without blocking the user's workflow, on Windows where Defender sometimes holds state.json post-write.
Lesson learned
Build on top of validated concepts when the gap is structural, not cosmetic. Buddy validated the appetite for a terminal companion — the community has already voted with GitHub issues on what's missing. Building the missing layer as a real independent product is more defensive (not an Anthropic extension at their mercy) and more instructive (the spec was rewritten three times to minimize dependency) than waiting for them to ship it themselves. Shipping in 2 days / 9 releases doesn't happen without `Spec → Plan → Blitz → Polish`: 5 design specs + 6 implementation plans existed BEFORE the first commit.
Features
Egg → Hatchling → Junior → Adult → Elder → Mythic, triggered by level milestones
13 families bronze/silver/gold (+platinum on streak), idempotent backfill, 12 OTel-gated
Octopus, Dragon, Capybara, Axolotl… seed = SHA-256(user + host), rarity buckets 60/25/10/4/1 %
UserPromptSubmit, PostToolUse, Stop, SessionStart, SessionEnd — sub-50ms, never blocking
OTLP/HTTP/JSON daemon (port 7879, 127.0.0.1 bind) — cumulative-delta ingest, Datadog/Honeycomb fan-out
`petforge serve` + SSE + manifest + 512×512 icon — installable from mobile Safari/Chrome
State in ~/.petforge/state.json, file-locked, atomic writes, Windows EPERM retry, silent recovery
`petforge buddy import` parses an Anthropic ASCII card — local visual, zero redistribution, zero scraping