Getting started

Install Furoshiki from PyPI

Python 3.11+, an OpenRouter API key, and a few CLI steps. No git clone required.

furoshiki onboard furoshiki db migrate furoshiki start

Emotion state, needs, and user needs

Furoshiki keeps a vector of nine emotions (0–1), derives five Furoshiki needs for behavior, and separately tracks seven user-need dimensions about the human’s inferred state. This page orients you; the canonical technical write-up is docs/EMOTION-STATE-AND-NEEDS.md in the repo.

Python vs LLM. Drift, clamps, and persistence are deterministic code. Interpreting what a message means for feelings is done by the same chat model when it chooses to call adjust_emotions (bounded nudges)—not by a keyword table.

Three layers

LayerRoleWhere it lives
Emotions Raw inner state (loneliness, joy, …) heartbeat-state.json, emotion_history
Furoshiki needs Derived from emotions (communication, connection, …) needs in heartbeat, needs_history
User needs Inference about the user (space, conflict, …) with confidence user_needs, user_needs_history

How emotion changes (overview)

Background
Natural levels
lazy drift on read
↓ (every 15 min)
soul_engine tick
During chat
Chat model
↓ calls
Tool loop
↓ invokes
adjust_emotions
Persistence
heartbeat-state.json
· soul_engine + adjust_emotions write here ·
emotion_history
· soul_engine snapshots each tick ·
derived on read →
needs / mood score
(apply_lazy_drift() computes from heartbeat on every read)

Natural levels (drift attractors)

Shipped defaults live in emotion_model.EMOTION_NATURAL_LEVEL. Operators can override per emotion in memory/operator_settings.json under emotion_natural_levels, or use the dashboard Emotions → Emotion lab (save / revert to code defaults). Drift pulls emotions toward these targets over time when nothing else is firing.

adjust_emotions during chat

When model tools are enabled (default), the Telegram reply model receives tool schemas from model_tools.py. It may call adjust_emotions with small deltas; execution updates the heartbeat and logs a row viewable under Emotions → Model tools. This is optional per turn—the tool description tells the model not to call it on every message.

Dashboard

Unified contact (gray markers on charts)

The same merged timeline is used for analytics: user conversation_turns (excluding dismiss bookkeeping), user_input system events, and outreach rows triggered by user_message, then deduped within ~90 seconds. One real interaction can still produce more than one raw row—check raw_by_source before assuming “message volume.”