Reference
Architecture
The runtime's overall structure, the heart's mathematics (drives, body clock, Poisson sampling), the body twin, one wake-up end to end, memory retrieval and the provider layer.
#Overall structure
The runtime is a single Node.js process (dist/main.cjs). Modules are coupled through an in-process event bus, all state is on disk (SQLite and the soul directory), and a restart is just a nap.
Design principles: device-agnostic (the core knows only the adapter interface), one operations layer for every control entry (app and Feishu behave identically and both audit), and no timer-driven behaviour.
#Heart: when to wake
#Drives and body clock
| Quantity | Range | Dynamics |
|---|---|---|
| Curiosity / expression / longing | 0–1 | While awake each approaches 1 with its own time constant (defaults 3 / 6 / 10 h); asleep they grow at 30% speed |
| Open loops | 0–1 | Unfinished thoughts / 5 |
| Sleep pressure | 0–1 | Approaches 1 while awake ( h), with extra build-up from work; decays exponentially while asleep ( h) |
| Circadian rhythm | 0–1 | , most alert at 4 pm; bright light at night , darkness by day |
| Sleepiness | ; fall asleep above , wake naturally below while asleep |
A drive's approach:
This is the two-process model from sleep research (sleep pressure plus circadian rhythm). With default parameters she falls asleep around 22:40 and wakes around 7:50, with no timetable anywhere.
Loading diagram…
#Wake rate
Instantaneous wake rate (per hour):
where is the weighted mean drive, defaults to 2, is alertness and is the inhibition factor (stop / paused / no model → 0; overheating ×0.1, low battery not charging ×0.2, offline ×0.5, budget spent ×0.05; then the activity knob).
#Sampling: thinning a non-homogeneous Poisson process
Loading diagram…
Wake intervals follow a time-varying exponential distribution. The 15 minutes is only the integration step and never triggers a wake-up.
#Body digital twin
Adapter samples (battery, temperature, light, motion, screen, extra) and OS information (load, memory, storage, connectivity) are mirrored into an internal model that derives body feelings (energy, warmth, brightness, still / picked up). Comparing with the previous sample yields sense events (plugged, light, moved, hot, low_battery, screen_on, online…). Events adjust drives and trigger re-sampling: picked up → longing +0.3, curiosity +0.2; light change → curiosity +0.1. Sampling intervals adapt (2–10 minutes) and never call a model.
#Mind: one wake-up
Loading diagram…
The system prompt is assembled in order: personality → situation → resident memory → memory index → auto-retrieved relevant memories → the thought she wants to share → body → inner state and open loops → soul-sync perception → recent journal → other sessions.
She sets the pace: there is no step limit. Runaway protection comes from two no-progress idle walls (model call 90 s, session 120 s) and the emergency stop.
Sessions: conversations belong to sessions; one session is processed in order, different sessions in parallel, and sessions can see each other (the system prompt includes other sessions' recent activity and turns in progress). A message sent while she works is an interjection by default, or can be queued or interrupt.
#Memory: unbounded storage, bounded context
Storage has no cap; only a small part enters the context each time (text-structure RAG, no vector model):
| Layer | Storage | In context |
|---|---|---|
| Resident memory | § entries, unlimited | Fully expanded within budget (4000 / 2000 chars); beyond that, topic-relevant entries first |
| Notes | A tree up to 4 levels deep, each with a one-line summary | Index only (about 2500 chars) |
| Journal | One file per body per day | Recent days' excerpts (about 3000 chars) |
| Auto retrieval | All of the above | Current topic as query, BM25-style scoring, most relevant fragments (about 3000 chars) |
While dreaming she moves detail from resident memory into notes and tidies the tree so it stays easy to find.
#Provider layer
A unified request → walk enabled models in global order → rotate that provider's keys (max 2) → one of four protocol adapters. Rate limit / timeout / 5xx: next key; 400/401/403/404: next model. Keys are encrypted with AES-256-GCM using the provider id as associated data.
#Guard and audit
Three permission levels per category; approvals time out as denial after 30 minutes; a STOP file is the emergency stop; tool calls, configuration changes, memory edits and approval decisions all go to the audit table.
#Process contract
Supervision is external (runit, systemd); more than five starts in ten minutes enters safe mode. The deployer provides Node.js 22+, WINDLER_HOME, optionally WINDLER_ADAPTER, and a supervisor.