A codebase Tamagotchi that lives in your terminal. Its health, mood, and looks are a direct reflection of the git repo it lives in. Fresh commits feed it. Failing CI makes it sick. Stale branches make it lonely. Climbing coverage makes it grow up.
It is an ambient status toy, not a linter. It never blocks, never exits non-zero, never nags. The pet's face is the only feedback.
npx gitgotchi- Quick start
- How your repo maps to your pet
- Life stages
- How it works
- The share card
- In GitHub Actions
- FAQ
- Development
npx gitgotchi # meet your pet (one-shot status)
npx gitgotchi watch # live view, refreshes every 60s (min 10 via -i)
npx gitgotchi card # export a share card SVG (add --png if you have sharp)
npx gitgotchi init # name your pet
npx gitgotchi rename Pixel
npx gitgotchi --json # machine-readable state, for status barsOne run is one check-in. --report pet.json and --card pet.svg are extra
renderings of that same check-in, so scripts can have the numbers, the picture,
and the human block without the pet ageing three times:
npx gitgotchi --report pet.json --card pet.svg
npx gitgotchi card -o - # SVG straight to stdoutZero config. Runs in any git repo using only local signals (git + grep) in a few seconds. CI and coverage are automatic bonuses when they're available.
Install options: npx gitgotchi needs no install. To keep it around,
npm i -g gitgotchi (then gitgotchi anywhere) or npm i -D gitgotchi in a
project. Requires Node ≥ 20.
Four vitals, each a pure function of one kind of repo signal:
| Vital | Goes up when… | Goes down when… |
|---|---|---|
| ❤ health | CI is green, coverage is high | CI keeps failing, coverage is low |
| 🍖 hunger | you commit often ("commits are food") | the repo goes quiet (starving at ~7 days) |
| ✨ hygiene | few TODO/FIXME/HACK markers | markers pile up |
| 👥 social | branches are fresh, work is pushed | branches go stale, work sits unpushed |
The lowest vital sets the mood — thriving, content, hungry, grubby,
lonely, sick, or critical — and the mood is the face Byte wears:
╭╮ ╭╮ ╭╮ ╭╮ ╭╮ ╭╮ ╭╮ ╭╮
╭┴┴──┴┴╮ ╭┴┴──┴┴╮ ╭┴┴──┴┴╮ ╭┴┴──┴┴╮
│ ^ ^ │ │ ◕ ◕ │ │ ◔ ◔ │ │ x x │
│ ◡ │ │ o │ │ ~ │ │ ~ │
╰─┬──┬─╯ ╰─┬──┬─╯ ╰─┬──┬─╯ ╰─┬──┬─╯
╵ ╵ ╵ ╵ ╵ ╵ ╵ ╵
thriving hungry grubby critical
The pet grows as you keep showing up:
| Stage | Reached at |
|---|---|
| egg | birth |
| baby | 3 check-ins |
| kid | 20 check-ins and best coverage ≥ 50% |
| adult | 100 check-ins and a green streak ≥ 10 |
| elder | 365 days old |
Stages never regress. A "check-in" is any time you run gitgotchi.
One-directional data flow, with a hard wall between I/O and game logic:
collectors (I/O) → RepoSignals → engine (pure) → PetState → store + render
- Collectors (
src/collectors/) gather signals — commit recency, dirty tree, branches, TODO grep, coverage files, optional CI. They never throw: any failure degrades tonullor a safe default. - The engine (
src/engine/) is 100% pure functions. The clock and RNG seed are injected, so the same repo state in produces byte-identical creature state out. This is why the whole game is testable without a filesystem. - State (
src/state/) is zod-validated and saved atomically (temp file + rename). Corrupt state is backed up to.bakand the pet starts fresh — never a crash, never a silent overwrite. - UI (
src/ui/) is Ink (React for the terminal); sprites are plain data, snapshot-tested. Non-TTY output falls back to a plain text block.
See docs/ARCHITECTURE.md for the full tour and docs/manual-tests.md for a hands-on walkthrough of every mood and stage.
gitgotchi card renders a 1200×630 SVG of your pet + stats — the thing you post.
It needs no browser, and it's deterministic: the flavor line is seeded by the
pet's condition rather than the clock, so re-rendering an unchanged pet gives
byte-identical output. Add --png to rasterize via sharp if you have it
installed; otherwise you get the SVG and a friendly note.
The action checks in on your pet and puts it in the job summary — nothing is committed, nothing is pushed, and the working tree is never written to.
- uses: actions/checkout@v4
with:
fetch-depth: 0 # the pet reads commit history
- uses: dvd90/gitgotchi@v1That's the whole thing. actions/cache keeps the pet alive between runs, so it
actually grows up instead of hatching every time.
Keep the card as a downloadable artifact:
- uses: dvd90/gitgotchi@v1
id: pet
with:
card: gitgotchi-card.svg
- uses: actions/upload-artifact@v4
with:
name: gitgotchi-card
path: ${{ steps.pet.outputs.card-path }}Commit the card to a branch — opt in explicitly, since this is the one workflow that writes:
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- uses: dvd90/gitgotchi@v1
with:
card: .github/gitgotchi-card.svg
- run: |
git config user.name "gitgotchi"
git config user.email "gitgotchi@users.noreply.github.com"
git add .github/gitgotchi-card.svg
git diff --staged --quiet || git commit -m "chore: update gitgotchi card"
git pushThe card is seeded by the pet's condition, not by when you looked, so an
unchanged pet renders identical bytes and git diff --staged --quiet skips the
commit. The day counter still ticks, so expect roughly one commit a day rather
than one per push.
| Input | Default | What it does |
|---|---|---|
path |
. |
Repository directory to check in on |
version |
latest |
npm version to run; local builds the checked-out copy |
cache |
true |
Persist the pet between runs via actions/cache |
summary |
true |
Write the pet to the job summary |
card |
(none) | Workspace-relative path for the card SVG |
github-token |
${{ github.token }} |
Read Actions status; needs actions: read, pass '' to skip |
name, species, stage, mood, health, hunger, hygiene, social,
report (path to the full state JSON), card-path.
- if: steps.pet.outputs.mood == 'critical'
run: echo "the repo is not okay"Does it send my data anywhere? No. No account, no server, no telemetry.
Does it touch my repo? No. Gitgotchi only reads. Your pet lives outside the
working tree, under $XDG_STATE_HOME/gitgotchi/ (~/.local/state/gitgotchi/ by
default, %LOCALAPPDATA%\gitgotchi\ on Windows), keyed by the repo's path. Set
GITGOTCHI_STATE_DIR to put it somewhere else. Pets from before 0.2 that live
in .gitgotchi/state.json are picked up automatically and move on the next
check-in; the old file is left alone and can be deleted.
Can it block or fail my build? Never, by design. It always exits 0 and never lectures. Guilt is delivered exclusively through sad eyes.
Does it need a GitHub token? No. CI status is a progressive enhancement — if
a token is available (gh auth token or GITHUB_TOKEN) it reads Actions status;
otherwise it just uses local signals.
Why is my pet already grubby? It counts TODO/FIXME/HACK markers in tracked files. That's not a judgment — Byte just notices.
npm install
npm test # vitest
npm run typecheck
npm run lintTDD is the workflow and the engine holds a 100% line-coverage gate. See CONTRIBUTING.md for conventions and the milestone process.
MIT © David Sellam

