English | 中文
Your desktop pet is not installed. It is raised.
It does not chat. It does not call an LLM. It lives next to you: mirrors your late-night typing, gets dizzy when the CPU melts down, waves when you have been gone too long - and slowly turns into a night owl, because you are one. ReflexArc gives a pet a working reflex arc instead of a script:
sensors nervous centre effectors
+-------------+ +---------------------+ +----------------------+
| keyboard / | | homeostatic drives | | 16-direction gaze |
| mouse idle | ---> | energy boredom | ---> | breathing / shadow / |
| CPU load | | mood attachment | | emote glyphs |
| battery | | stress social | | physics (walk, hop, |
| time of day | | hunger | | grabbed, thrown) |
| window kind | | + | | petdex sprite rows |
| cursor pos | | decision: instinct | +----------------------+
+-------------+ | + laya intuition | transparent, click-
+---------------------+ through, always on top
|
v
personality drift over days
(night owl, clingy, lazy...)
The pet never chats. It just lives next to you: gets sleepy at 1am, paces when bored, mirrors your deep work, waves when you have been gone too long, gets dizzy when your CPU melts down.
Most desktop pets are stickers that play animations. Seven layers stacked together are what make this one feel alive:
- It looks at you. petdex v2 atlases hide 16 gaze-direction frames - almost every player uses only the first 9 rows. ReflexArc uses all of them: move your cursor nearby and it watches the cursor, turning through the in-between frames (half a turn takes 0.35 s, never a snap); switch windows and it turns toward your window; left alone it lets its gaze wander; sleepy and its head droops.
- It breathes, and it casts a shadow. A slow chest-rise while standing (the rate follows energy and personality, deeper and slower asleep) and a soft shadow under its feet - hop and the shadow stays on the ground, shrinking and fading until it lands.
- It has physics. Walking accelerates to cruise and brakes to a stop; joy triggers a real hop (crouch, arc, squash-and-stretch landing with one or two settling bounces).
- You can pick it up. Press and drag and the pet is carried, legs kicking, watching the cursor; let go and it falls. Set it down gently and its mood improves; drop it hard and it gets dizzy and teary. Your desktop keeps working: it only takes the cursor while you rest on the pet, and is click-through everywhere else.
- It shows feelings. A sleepy pet drifts
Zzz; being petted floats hearts; a melting CPU makes it sweat first, shiver, then faint - and the emotion lives in the body, not only overhead: joy bounces, a hard fall curls it into a ball that trembles, boredom sways. There are also four soft otter sounds (a happy chirp when petted, a startled squeak when grabbed, a sad whimper after a bad landing); on by default, very quiet,REFLEXARC_SOUND=0silences them. - You can read it. Double-click and a tiny status bubble pops above
its head -
♥wants a pet,Zsleepy,…bored,💧stressed,⌣content. No guessing what it is in the mood for. - It fidgets. During quiet stretches it glances around, takes a deep breath, stretches, or hops a little - how often depends on its personality: a lazy pet sits still, a curious one keeps looking around.
- It remembers being handled. Grabs, drops and pettings are counted, and a hard drop genuinely raises stress and sours the mood.
- petdex - 4,800+ community-animated pets in an open sprite format. ReflexArc uses them as the body: pets are fetched at runtime from the petdex manifest, and local
~/.petdex/pets/~/.codex/petsinstalls are used when present. Pet art belongs to its submitters and is not bundled here. - laya - a non-autoregressive "System 1" decision engine (single forward pass over any text, no generation). Optional: it acts as the pet's intuition, nudging behaviour choices by a small weight.
- Instinct - always on, deterministic, microseconds. A utility function scores nine candidate behaviours against the current drives and ambient observations. This is the pet's spine: explainable, predictable, and it never fails.
- Intuition - optional. laya answers eight independent yes/no questions about the situation ("should the pet rest right now?", "should it seek attention?"). Answers are calibrated (below) and blended in with a small weight. If laya is missing, slow, or wrong, the pet keeps living on instinct alone.
Straight answers from the build, in case you want to use laya for something similar:
- The multilingual checkpoint is useless zero-shot for this task. Across four wildly different situations (3am exhausted / deep work / left alone / 97% CPU) it picked "cheer" every single time. Its model card says to treat laya as a fast base to specialise, not a zero-shot decision engine - that is accurate.
- The typed-decisions checkpoint is genuinely usable. Zero-shot: "rest" scores 0.54 at 3am vs 0.10 during deep work; "overwhelmed" jumps to 0.45 at 97% CPU vs a ~0.25 baseline; "mirror" 0.61-0.67 during focused work vs 0.22 idle.
- You can specialise without fine-tuning. Fine-tuning wants a 2xT4 for hours.
Instead,
calibrate_intuition.pysamples ~48 synthetic situations, measures each question's baseline (mean/spread), and live answers are z-scored against it. The model's conditional signal survives; its blanket bias dies. ~40 lines of code. - Speed: ~3.5s per batch of eight questions on CPU (first call ~25s while the 614-800MB checkpoint loads). Far too slow for a game loop, which is why intuition runs in a background thread, refreshes every ~8s, and is blended as a nudge, not an oracle.
From tests/scenario.py - the same pet fast-forwarded across a simulated day:
| Situation | What happens |
|---|---|
| Quiet morning, user nearby but idle | wanders (194+193) + ponders (182) + seeks attention occasionally (19) |
| Deep work, heavy typing | mirrors the user (664), occasional cheer (14) |
| Afternoon dip | stares into the distance (290), some walking, rare cheer |
| Evening video session | sits and watches the user (187) |
| 23:30 grind | stays close and watches (254), occasionally mirrors the work |
| CPU storm (97%) | dizzy/overwhelmed (230) - it panics long before your fans do |
| Left alone for hours | paces (245+245), sleeps (60), waves for you sometimes (14) |
All counts come from real simulation runs with feedback loops active: behaviours satisfy their drives a little (walking reduces boredom, seeking attention eases social hunger), so nothing repeats forever. Dwell times are personality-scaled: a lazy pet rests longer, a curious one moves on sooner.
| Signal | Used for | Stored? |
|---|---|---|
| Keyboard/mouse idle time | activity, boredom | aggregate only |
| CPU load | stress / overwhelmed behaviour | smoothed, in memory |
| Battery | "tired machine" sympathy | in memory |
| Time of day | sleep rhythm, night-owl drift | in memory |
| Foreground window category | watching / pondering / gaze target | category only - titles are never stored or sent |
| Cursor position | eye contact, petting, grabbing | never stored |
Nothing leaves the machine. Personality, drives and history live in ~/.reflexarc/state.json.
Five traits - curiosity, clinginess, laziness, resilience, night owl - seed randomly on first run and then drift slowly toward how you actually live. Work nights for a week and your pet becomes a night owl. It is not a setting; it is an outcome. Personality also decides how busy the pet looks: a lazy pet sits quiet for long stretches, a curious one keeps looking around and fidgeting.
# core engine, zero dependencies (headless)
python run.py --headless --duration 30 --fresh
# GUI pet: transparent, click-through, always on top
pip install PySide6 psutil
python run.py --scale 1.25
# optional intuition layer
pip install "laya[onnx]" # or: pip install laya
python calibrate_intuition.py --model-dir models/laya-typed \
--model-key typed-decisions --out state/calibration.json --n 48
python run.py --scale 1.25 # intuition auto-detected
python run.py --no-laya # or keep it offHow to play: move the cursor near it and it follows with its eyes; hover on the pet and it gets slowly stroked (hearts); click for a quick pet; double-click to ask what it wants right now (a status bubble pops up); press and drag to pick it up (let go and it falls - a gentle set-down and a hard drop get different reactions, and a bad landing earns dizzy stars); tray icon to pause or quit.
On first run the pet is fetched from the petdex manifest (--pet-slug boba by
default; any of the 4,800+ slugs works). Model weights for the intuition layer are
downloaded by laya itself on first use (HF convaiinnovations/laya, multilingual
or typed-decisions subfolder).
python run.py [--headless] [--duration N] [--fresh] [--seed N]
[--name NAME] [--pet-slug SLUG] [--scale F] [--no-laya]
| Env var | Effect |
|---|---|
REFLEXARC_NO_GRAB=1 |
disable picking the pet up (fully click-through again; hover/click petting stays) |
REFLEXARC_SOUND=0 |
silence the pet (sounds are on by default, very quiet) |
REFLEXARC_BREATH=0 |
disable the breathing pulse |
REFLEXARC_EMOTES=0 |
disable emote glyphs (Zzz / hearts / sweat) |
REFLEXARC_DEBUG_HUD=1 |
print per-frame cost every 2 s and run the hit-test self-check |
REFLEXARC_FORCE_X/Y |
pin the window position (debug / multi-monitor) |
python -m tests.gaze_math # gaze maths (mapping, turn speed, hysteresis)
python -m tests.motion_physics # physics (ramps, hop arc, landing, grabbing)
python -m tests.scenario # fast-forward a whole simulated day
python -m tests.integration 90 # real-time end-to-end (with laya)
python -m tests.look_probe # verify a new atlas's 16 gaze directions (Pillow)The first three are zero-dependency and run in CI. After swapping in a new pet
atlas, run look_probe once - a mismatched direction convention makes the pet
look the wrong way, and the probe catches it before you do.
- v0.1 - reflex arc, homeostatic drives, nine behaviours, transparent GUI, petdex format, calibrated intuition
- v0.2 - life signs: 16-direction gaze, breathing, shadow, emote glyphs, physics (walk with momentum, hops, landing squash), grab-and-throw interaction, personality-scaled liveliness
- v0.3 - readable: double-click status bubble, emotion body language (bounce / curl / sway), exaggerated landing handfeel with dizzy stars, more visible fidgets, soft otter sounds
- shareable personality report card ("it became a night owl in 7 days")
- multi-pet: two pets, two machines, one shared desktop
- agent hooks: react when your coding agent finishes or fails
- petdex - gallery, sprite format, desktop groundwork.
- laya - the optional intuition engine.
- Every pet artist in the petdex catalog.
MIT License.