Skip to content

Repository files navigation

🥚 Gitgotchi

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.

Byte, a gitgotchi, idling in the terminal with its stat bars

npx gitgotchi

How to use — a 30-second tour

A walkthrough of the gitgotchi commands: check in, watch, how the repo drives the mood, and export a card

Contents

Quick start

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 bars

One 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 stdout

Zero 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.

Gitgotchi share card

How your repo maps to your pet

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

Life stages

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.

How it works

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 to null or 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 .bak and 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.

The share card

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.

In GitHub Actions

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@v1

That'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 push

The 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.

Inputs

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

Outputs

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"

FAQ

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.

Development

npm install
npm test            # vitest
npm run typecheck
npm run lint

TDD is the workflow and the engine holds a 100% line-coverage gate. See CONTRIBUTING.md for conventions and the milestone process.

License

MIT © David Sellam

About

Codebase Tamagotchi

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages