PetForge
Live · npm v3.6.0Couche RPG local-first pour Claude Code — pet ASCII déterministe qui évolue à partir de l'activité de codage réelle (5 hooks officiels, 6 phases, 46 achievements médaillés, 19 espèces, collecteur OTel intégré, web view PWA mobile). Shippé sur npm en 2 jours / 64 commits / 9 releases.
Pourquoi j'ai construit ça
Anthropic a livré Claude Buddy en avril 2026 — un tamagotchi terminal natif dans Claude Code, avec 18 espèces, 5 raretés, 5 stats. Brillant produit. Mais il s'arrête là : pas de niveaux, pas d'évolution, pas de progression. La communauté demande ça sur GitHub dès la première semaine. Personne ne livre. J'ai vu un gap structurel — pas cosmétique — et j'ai construit la couche manquante. PetForge n'est ni un fork, ni une extension, ni une copie : c'est un moteur indépendant qui peut afficher Buddy quand il est là, et générer son propre pet quand il ne l'est pas. 64 commits / 9 releases publiques en 2 jours calendaires, shippé sur npm comme `@mindvisionstudio/petforge`.
Décisions techniques structurantes
Tout l'état tient dans ~/.petforge/state.json (file-locké via proper-lockfile sur sentinelle dédiée, écriture atomique tmp+fsync+rename). Zéro telemetry, zéro account, zéro phone-home. Hardening Windows-specific : retry EPERM/EBUSY/ENOENT/EACCES sur fs.rename (Defender, OneDrive, indexeurs) avec backoff exponentiel 50/150/400 ms, max 4 tentatives sous le timeout 1s du hook. Recovery silencieuse : un state.json corrompu est sauvegardé en .corrupt.<ts>.json puis recréé — un hook ne crashe jamais Claude Code.
Pas un seul "claude" ou "buddy" dans le nom du package, du repo, du CLI, ou des assets. Buddy invoqué uniquement en runtime via `claude /buddy card` (= lecture stdout publique). L'intégration `petforge buddy import` parse une carte ASCII Anthropic depuis stdin/fichier, strip-out les lignes de stats pour éviter les doublons, et stocke le visuel localement sans redistribution. Aucun scraping, aucun fetch automatique, aucune copie de fichier interne.
L'engine déterministe est le produit (19 espèces × 6 phases × 5 raretés × shiny = 570 combinaisons visuelles). Au-delà : collecteur OTLP/HTTP/JSON daemon `petforge collect` qui ingère les métriques officielles Claude Code (code.lines.added, tokens.in/out, cost.usd, pull_request.created…) et débloque 12 achievements gated sur la qualité réelle de la session (Code Architect 10K, Cache Lord ≥80 %, Frugal Coder 100p ≤ $1). Web view single-file (`page.ts`, 1 033 L de HTML+CSS+JS dans un template literal) servie en SSE temps réel + manifest PWA installable mobile.
v1 : sprites + extension VS Code (rejeté — friction install, audience trop restreinte). v2 : RPG layer over Buddy (rejeté après revue licence + risque de dépendance directe). v3 (livré) : engine standalone, Buddy en option, Apache 2.0 trademark-clean. Trois itérations de design avant la première ligne de code, puis 9 releases npm en 2 jours (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) — capacité d'itération rapide démontrée. Pas de dette : 0 erreur TS, 1 `any` sur 9 596 lignes, biome clean.
Le challenge non-trivial
Trois risques en parallèle : (1) Anthropic ship la même feature (medium probability, low impact si l'engine PetForge est core et Buddy juste optionnel) ; (2) Buddy se déprecate ou change son format (mitigé — Buddy détecté en runtime, fallback silencieux) ; (3) plainte trademark si on flirte avec Buddy/Claude dans le naming ou si on copie des assets (very low probability, critical impact — couvert par la séparation absolue : zéro mot Anthropic, zéro asset copié, runtime invoke uniquement). Le vrai challenge n'est pas technique, c'est juridique-stratégique : trouver le bon découpage qui te laisse exister sans dépendre, copier, ou provoquer. Plus le challenge cross-platform : faire tenir 5 hooks Claude Code en sub-50ms sans bloquer le workflow utilisateur, sur Windows où Defender hold parfois state.json post-write.
Leçon retenue
Build on top of validated concepts when the gap is structural, not cosmetic. Buddy a validé l'appétit pour un compagnon terminal — la communauté a déjà voté avec ses GitHub issues sur ce qu'il manque. Construire la couche manquante avec un vrai produit indépendant est plus défensif (pas une extension Anthropic à leur merci) et plus enseignant (la spec a été refaite trois fois pour minimiser la dépendance) que d'attendre qu'ils livrent eux-mêmes. Le shipping en 2 jours / 9 releases ne se fait pas sans le `Spec → Plan → Blitz → Polish` : 5 specs design + 6 plans d'implémentation existaient AVANT le premier commit.
Fonctionnalités
Egg → Hatchling → Junior → Adult → Elder → Mythic, déclenchées par seuils de niveau
13 familles bronze/silver/gold (+platinum sur streak), backfill idempotent, 12 OTel-gated
Octopus, Dragon, Capybara, Axolotl… seed = SHA-256(user + host), buckets de rareté 60/25/10/4/1 %
UserPromptSubmit, PostToolUse, Stop, SessionStart, SessionEnd — sub-50ms, jamais bloquant
OTLP/HTTP/JSON daemon (port 7879, bind 127.0.0.1) — ingest cumulative-delta, fan-out Datadog/Honeycomb
`petforge serve` + SSE + manifest + icône 512×512 — installable depuis Safari/Chrome mobile
État ~/.petforge/state.json file-locké, atomic writes, retry EPERM Windows, recovery silencieuse
`petforge buddy import` parse une carte ASCII Anthropic — visuel local, zéro redistribution, zéro scraping