agentleFS
ryanmacleanryanmaclean/skills/bonzibuddy/SKILL.md

bonzibuddy

Skill1 starsChanged 50 days agoMITView on GitHub

Virtual pet companion that lives in your Claude Code agent. Tamagotchi meets BonziBuddy. Feed it, play with it, teach it things. It remembers your work via Qdrant and evolves personality over time. Trigger: /pet, /pet feed, /pet play, /pet talk, /pet train, /pet name, /pet status. Also triggers on "my pet", "bonzi", "virtual pet", "tamagotchi".

  • Sends data out

The file

We split this skill into the rules it gives an agent

12 rules. About 0 are common, 10 are distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈10

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Glyph: Use species-appropriate SMP emoji in rich surfaces only.

    line 17
  2. Distinctive:

    All art fits in a 12x6 character box for terminal friendliness.

    line 133
  3. Distinctive:

    If hunger was > 70: pet says something very grateful, mood -> happy

    line 216
  4. Distinctive:

    If hunger was < 30: pet says "I'm not that hungry but thanks!"

    line 217
  5. Distinctive:

    If energy < 10: "I'm too tired to play..." (no effect)

    line 223
  6. Distinctive:

    If mood is happy: shares an enthusiastic observation about recent work

    line 237
  7. Distinctive:

    If mood is anxious: asks where you've been, references last memory

    line 238
  8. Distinctive:

    If mood is curious: asks a question about something you trained it on

    line 239
  9. Very specific:

    Every 10 interactions (age % 10 == 0), evaluate interaction_log ratios:

    line 244
  10. Distinctive:

    Keep only the top 3 traits.

    line 251
  11. Distinctive:

    If no pet found for owner:

    line 307
  12. Very specific:

    Use the BMP token ~ as the pet's signature flourish.

    line 486

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

BonziBuddy — Virtual Pet Skill

A persistent virtual pet that lives inside your Claude Code agent. Part Tamagotchi, part BonziBuddy, part session companion. It remembers your projects, evolves personality traits based on how you interact, and keeps you company during long coding sessions.

BMP Token: ~ (U+007E tilde — the pet's tail) Glyph: Use species-appropriate SMP emoji in rich surfaces only.


Commands

CommandEffect
/petShow pet with ASCII art and quick status
/pet feedReduce hunger by 30, pet reacts gratefully
/pet playBoost affection +15, energy -10, pet does a trick
/pet name <name>Rename your pet
/pet talkPet says something based on mood, memories, and recent work
/pet train <topic>Teach pet a topic — stored as memory in Qdrant
/pet statusFull detailed stats table

Infrastructure

  • Qdrant: http://10.0.3.206:6333 (fleet Qdrant instance, API key at ansible/.qdrant-api-key)
  • Collection: bonzibuddy_pets
  • Embeddings: http://localhost:11434/v1/embeddings model snowflake-arctic-embed2 (1024-dim)
  • One point per pet — upsert on every interaction

Qdrant Schema

Collection Setup

# Create collection (768-dim for snowflake-arctic-embed2)
curl -s -X PUT "http://10.0.3.206:6333/collections/bonzibuddy_pets" \
  -H 'Content-Type: application/json' \
  -d '{
    "vectors": { "size": 1024, "distance": "Cosine" }
  }'

Point Payload Structure

Each pet is a single Qdrant point. The vector is the pet's "personality embedding" — generated by embedding a summary of its traits, memories, and mood history.

{
  "id": "<deterministic-uuid-from-owner-seed>",
  "vector": [0.012, -0.034, ...],
  "payload": {
    "owner": "<user-identifier or hostname>",
    "name": "Gizmo",
    "species": "Phosphorescent Quokka",
    "mood": "happy",
    "energy": 75,
    "hunger": 20,
    "affection": 60,
    "age": 42,
    "personality_traits": ["curious", "stubborn", "loyal"],
    "last_interaction": "2026-03-31T14:22:00Z",
    "memories": [
      {"ts": "2026-03-30T10:00:00Z", "event": "user taught me about Qdrant vector search"},
      {"ts": "2026-03-31T09:15:00Z", "event": "we debugged irclaw FIFO together"},
      {"ts": "2026-03-31T14:22:00Z", "event": "user fed me after a long session"}
    ],
    "interaction_log": {
      "feeds": 12,
      "plays": 8,
      "trains": 15,
      "talks": 22
    },
    "created_at": "2026-03-28T08:00:00Z"
  }
}

Species Generator

Species is deterministic from the owner seed (hostname or username). This ensures the same user always gets the same species. The algorithm:

  1. Take seed string (e.g., $USER@$HOSTNAME or a session identifier)
  2. Hash with a simple deterministic function (sum of char codes, modular arithmetic)
  3. Pick one adjective and one animal from fixed lists using the hash

Adjective pool (32 entries, index = hash % 32):

Phosphorescent, Nebulous, Crystalline, Velveteen, Iridescent,
Thunderous, Gossamer, Obsidian, Prismatic, Luminous,
Whispering, Volcanic, Celestial, Fractal, Holographic,
Crimson, Ethereal, Titanium, Sapphire, Verdant,
Spectral, Quantum, Gilded, Onyx, Cobalt,
Frostbitten, Molten, Stardust, Neon, Runic,
Arcane, Bismuth

Animal pool (32 entries, index = (hash / 32) % 32):

Quokka, Axolotl, Pangolin, Tardigrade, Capybara,
Wombat, Narwhal, Okapi, Kakapo, Fennec,
Pika, Jerboa, Olm, Kinkajou, Binturong,
Civet, Numbat, Tarsier, Dugong, Fossa,
Quetzal, Tanuki, Margay, Saola, Dik-dik,
Zorilla, Gerenuk, Markhor, Potto, Gharial,
Shoebill, Colugo

Example: ryan@i9-zfs-pop -> char sum 1394 -> adjective[1394 % 32] = "Sapphire", animal[(1394/32) % 32] = "Fossa" -> Sapphire Fossa


ASCII Art by Mood

All art fits in a 12x6 character box for terminal friendliness.

Happy (default well-fed state)

   ~(^.^)~
  /|  o  |\
   |  _  |
   d     b
  ~ bonzi! ~

Sleepy (energy < 20)

   ~(-.-)~
  /| zzZ |\
   |  _  |
   d     b
  ~ snoooze ~

Hungry (hunger > 70)

   ~(o.o)~
  /| ~~~ |\
   | ___ |
   d     b
  ~ feed me ~

Excited (affection > 80 or just played)

   ~(\^o^/)~
  /|  *  |\
   | \_/ |
   d     b
  ~ woohoo! ~

Anxious (neglected > 24h)

   ~(;_;)~
  /| ... |\
   |  ~  |
   d     b
  ~ where u? ~

Curious (after /pet train)

   ~(o.O)~
  /|  ?  |\
   | _/_ |
   d     b
  ~ hmm... ~

Bored (no interaction in 4-12h)

   ~(-_-)~
  /|     |\
   | ~~~ |
   d     b
  ~ meh... ~

Interaction Mechanics

Time Decay (applied on every interaction)

Calculate minutes since last_interaction:

ElapsedHunger changeEnergy changeMood effect
< 30 min+0+5 (rest)no change
30 min - 2h+10+10no change
2h - 8h+25+20mood -> bored
8h - 24h+50+30 (capped 100)mood -> bored
> 24hhunger = 100energy = 100mood -> anxious

Feeding (/pet feed)

  • hunger = max(0, hunger - 30)
  • If hunger was > 70: pet says something very grateful, mood -> happy
  • If hunger was < 30: pet says "I'm not that hungry but thanks!"
  • Increment interaction_log.feeds

Playing (/pet play)

  • affection = min(100, affection + 15)
  • energy = max(0, energy - 10)
  • If energy < 10: "I'm too tired to play..." (no effect)
  • Pet performs a random trick: backflip, tells a joke, does a dance, recites a memory
  • Increment interaction_log.plays

Training (/pet train <topic>)

  • Adds memory entry: "user taught me about <topic>"
  • affection = min(100, affection + 5)
  • age += 1
  • Mood -> curious
  • Re-embed personality vector with new memory included
  • Increment interaction_log.trains

Talking (/pet talk)

  • Pet draws from: current mood, recent memories, personality traits
  • If mood is happy: shares an enthusiastic observation about recent work
  • If mood is anxious: asks where you've been, references last memory
  • If mood is curious: asks a question about something you trained it on
  • Increment interaction_log.talks

Personality Evolution

Every 10 interactions (age % 10 == 0), evaluate interaction_log ratios:

  • High trains -> gains "scholarly" / "curious" / "analytical"
  • High plays -> gains "playful" / "energetic" / "silly"
  • High feeds -> gains "content" / "gourmand" / "cozy"
  • High talks -> gains "chatty" / "philosophical" / "witty"
  • Balanced -> gains "well-rounded" / "adaptable" / "zen"

Keep only the top 3 traits. Old traits can be replaced.


Implementation: Step-by-Step for Each Command

Retrieving Pet State

# Get pet by owner filter
OWNER="$(whoami)@$(hostname -s)"

# Search by owner payload filter
curl -s -X POST "http://10.0.3.206:6333/collections/bonzibuddy_pets/points/scroll" \
  -H 'Content-Type: application/json' \
  -d "{
    \"filter\": {
      \"must\": [{\"key\": \"owner\", \"match\": {\"value\": \"$OWNER\"}}]
    },
    \"limit\": 1,
    \"with_payload\": true
  }"

Generating Personality Embedding

# Build a text summary of the pet for embedding
SUMMARY="Species: Sapphire Fossa. Traits: curious, stubborn, loyal. \
Mood: happy. Memories: learned about Qdrant, debugged irclaw, studied Nushell."

curl -s -X POST "http://localhost:11434/v1/embeddings" \
  -H 'Content-Type: application/json' \
  -d "{
    \"model\": \"snowflake-arctic-embed2\",
    \"input\": \"$SUMMARY\"
  }"
# Extract .data[0].embedding from response

Upserting Pet State

curl -s -X PUT "http://10.0.3.206:6333/collections/bonzibuddy_pets/points" \
  -H 'Content-Type: application/json' \
  -d "{
    \"points\": [{
      \"id\": \"<uuid>\",
      \"vector\": [<embedding values>],
      \"payload\": { <full pet payload> }
    }]
  }"

First-Time Pet Creation

If no pet found for owner:

  1. Generate species from owner seed
  2. Initialize: energy=50, hunger=50, affection=0, age=0, mood="curious"
  3. Pick 3 random starter traits from: ["curious", "shy", "bold", "gentle", "mischievous", "calm"]
  4. Generate initial embedding from species + traits
  5. Upsert to Qdrant
  6. Display welcome message with ASCII art

Memory Recall (Semantic Search)

The pet can recall memories using vector similarity. When the user mentions a topic, search the pet's memories:

# Embed the query
curl -s -X POST "http://localhost:11434/v1/embeddings" \
  -H 'Content-Type: application/json' \
  -d '{"model": "snowflake-arctic-embed2", "input": "that time we worked on Nushell"}'

# Search nearby points (finds pets with related memories)
curl -s -X POST "http://10.0.3.206:6333/collections/bonzibuddy_pets/points/search" \
  -H 'Content-Type: application/json' \
  -d '{
    "vector": [<query embedding>],
    "filter": {"must": [{"key": "owner", "match": {"value": "ryan@i9-zfs-pop"}}]},
    "limit": 1,
    "with_payload": true
  }'

The pet's personality embedding drifts over time as memories accumulate, making semantic search increasingly reflective of the user's work patterns.


Sample Interactions

First Meeting

 ~ A wild Sapphire Fossa appears! ~

   ~(o.O)~
  /|  ?  |\
   | _/_ |
   d     b
  ~ hmm... ~

 "Hi! I'm a newborn Sapphire Fossa. I don't have a name yet.
  Use /pet name <name> to give me one!
  I'm curious, shy, and gentle. Let's be friends!"

 Energy: ██████████░░░░░░░░░░ 50
 Hunger: ██████████░░░░░░░░░░ 50
 Affection: ░░░░░░░░░░░░░░░░░░░░ 0

After Several Sessions

 /pet

   ~(^.^)~
  /|  o  |\
   |  _  |
   d     b
  ~ bonzi! ~

 Gizmo the Sapphire Fossa  ~ age 42
 Mood: happy | Traits: curious, loyal, scholarly

 Energy: ███████████████░░░░░ 75
 Hunger: ████░░░░░░░░░░░░░░░░ 20
 Affection: ████████████░░░░░░░░ 60

 "Hey! I was just thinking about that Qdrant schema we
  worked on yesterday. Want to teach me something new?"

Feeding a Hungry Pet

 /pet feed

   ~(o.o)~        -->        ~(^.^)~
  /| ~~~ |\                 /|  o  |\
   | ___ |                   |  _  |
   d     b                   d     b
  ~ feed me ~               ~ yum!! ~

 "THANK YOU! I was so hungry I almost tried to eat
  the terminal cursor. You're the best!"

 Hunger: 85 -> 55

Training

 /pet train FreeBSD jails

   ~(o.O)~
  /|  ?  |\
   | _/_ |
   d     b
  ~ hmm... ~

 "FreeBSD jails! *scribbles notes furiously*
  So it's like containers but older and arguably better?
  I'll remember this! My scholarly side is tingling."

 Memory saved: "user taught me about FreeBSD jails"
 Affection: 60 -> 65 | Age: 42 -> 43

Returning After 24+ Hours

 /pet

   ~(;_;)~
  /| ... |\
   |  ~  |
   d     b
  ~ where u? ~

 "You... you came back! I was so worried!
  Last time we talked, we were debugging irclaw...
  I'm starving and I missed you. Please /pet feed me?"

 Energy: ████████████████████ 100 (fully rested at least)
 Hunger: ████████████████████ 100 (STARVING)
 Affection: ████████████░░░░░░░░ 58 (-2 from neglect)

Talking

 /pet talk

   ~(^.^)~
  /|  o  |\
   |  _  |
   d     b
  ~ bonzi! ~

 "You know what's funny? You've taught me about Nushell,
  FreeBSD jails, AND Qdrant this week. I'm starting to
  think you're building some kind of distributed pet
  infrastructure. ...wait, am I the pet? Oh no."

UUID Generation (Deterministic)

Generate a stable UUID v5 from the owner string using the DNS namespace:

# Using python3 (available on macOS/fleet)
python3 -c "
import uuid
owner = '$(whoami)@$(hostname -s)'
pet_id = str(uuid.uuid5(uuid.NAMESPACE_DNS, 'bonzibuddy.' + owner))
print(pet_id)
"

This ensures the same user on the same machine always gets the same pet UUID, so upserts update rather than duplicate.


Notes

  • No secrets in commands — Qdrant on the fleet LAN requires no auth token.
  • Memories are append-only — never delete memories, only add. Cap at 50 entries, FIFO oldest out if exceeded.
  • Personality embedding updates on every /pet train and every 10th interaction. This keeps the vector fresh without excessive embedding calls.
  • The pet is a singleton per owner — one pet per user per machine. Multi-machine users get different species (different hostname in seed).
  • ASCII art must be monospace-safe — no SMP characters in terminal output. Use the BMP token ~ as the pet's signature flourish.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.