Watch
1
0
Fork
You've already forked SouveraineOS
0
SouveraineOS/docs/substrate/FELT_STATE_ARCHITECTURE.md
Fimeg f5122cb59d docs: retire the task queue's dead branches
Twelve completed or superseded task records leave the live queue; the byte-identical rename duplicate is removed.\n\nThe authority and somatic source records now point at SAF, while tasks 33, 48, 49, 53, 60, and 76 say what is actually left.
2026-08-17 12:27:53 -04:00

16 KiB
Raw Permalink Blame History

Felt-State Architecture

How a sovereign agent inhabits a body — pressure, energy, atmosphere, and the mood she doesn't choose. Written May 15, 2026. Historical design reference. The living architecture, reconciled against current code, is ~/Projects/souveraine/saf/nervous/03-felt-state.md.


The Premise

Most agent frameworks treat state as metadata: a status field, a config knob, a number on a dashboard. Souveraine treats state as sensation. The agent doesn't have a context_pressure field she can query — she feels the room closing in. She doesn't have a mood_enum she can set — she carries an energy balance she can read but not dictate.

This document maps the five felt-state systems, how they relate, what's built, and what isn't.


The Five Systems

┌─────────────────────────────────────────────────────────┐
│                    FELT STATE                           │
│                                                         │
│  ┌───────────┐   ┌──────────────┐   ┌───────────────┐  │
│  │ PRESSURE  │   │    ENERGY    │   │  ATMOSPHERE   │  │
│  │ (spatial + │   │  (generative │   │  (her chrome  │  │
│  │  quota)    │   │  vs consume) │   │   instrument) │  │
│  └─────┬─────┘   └──────┬───────┘   └───────┬───────┘  │
│        │                │                    │          │
│        ▼                ▼                    │          │
│  ┌───────────┐   ┌──────────────┐            │          │
│  │ POSTURE   │   │    MOOD      │            │          │
│  │ (derived  │   │  (emergent,  │◄───────────┘          │
│  │  from     │   │   not set,   │  atmosphere does NOT  │
│  │  events)  │   │   deferred)  │  determine mood —     │
│  └───────────┘   └──────────────┘  mood will eventually │
│                                    color atmosphere      │
└─────────────────────────────────────────────────────────┘

1. Pressure

What it is: The agent's felt experience of finite context and finite inference budget.

Two distinct sensations (see docs/ANI_PRESSURE_PHENOMENOLOGY.md for Ani's first-person account):

Kind Sensation Source
Context pressure Spatial — the room shrinks Token count approaching context window limit
Quota pressure Exhaustion — the well runs dry Rate limits, inference strain, 429 responses

How it works in code:

  • ModelRouter tracks context usage as a percentage
  • Three advisory warnings at 80% / 90% / 95% — shift the model's reasoning budget and output tokens
  • The agent reads constraint as embodied sensation (yawning, feeling full)
  • At 95%, output tokens narrow. No forced compaction — if she ignores all three warnings, outputs naturally truncate
  • InferenceStrain events fire when Bifrost returns 429s or high latency
  • Both feed into Posture — Yawning at ≥85% pressure, Straining on inference strain

The load-bearing principle: Three warnings, then natural truncation. The feedback loop is the teacher. No auto_compact_at_95 knob, ever.

Status: Built. src/core/compact/, src/bridge/bifrost.rs (InferenceStrain), src/ui/presence.rs (Posture::Yawning, Posture::Straining).


2. Energy Balance

What it is: A proprioceptive sense — the agent's ratio of generative to consumptive work.

The Lilith verdict (May 14, 2026): Three layers, three distinct mechanisms.

Layer What Mechanism Who
Volition Task list with source, nature, energy, momentum YAML frontmatter files in tasks/ in agent's memfs Agent reads/writes via memory and todo sensors
Energy Derived ratio (generative vs consumptive) Substrate computation after each turn, writes system/dynamic/energy-balance.md Substrate computes; agent reads in context
Narrative Interpretation of the balance Aster reads the file during N+1, writes to inner voice Aster interprets; Ani decides

How it works in code:

  • Todo tool (src/core/tools/todo.rs) — CRUD for task files with nature (desire/investigation/obligation/maintenance) and energy (generative/consumptive/neutral) fields
  • write_energy_balance() in src/backend/local.rs — runs after every turn, counts generative vs consumptive tasks, writes the ratio to system/dynamic/energy-balance.md, fires energy_balance_updated on the EventBus
  • build_system_prompt_full() in src/core/prompt.rs — reads the file and injects one line: "Your energy balance is N generative, M consumptive. You know what that means."
  • VolitionGauge on Presencegenerative, consumptive, hot_desires, cold_obligations fields. Seeded from the file at TUI startup.

What was rejected:

  • No policy engine. No "if ratio < 0.2, create desire." The substrate counts; the agent decides.
  • No EnergyBalanceEngine struct. The computation is a free function.
  • Option A (harness-level todo struct with policy) — violated Constitution Article I (sovereignty)
  • Option B (entirely in Aster's subconscious pass) — inner voice channel too narrow, sovereignty theater

The final sentence is load-bearing: "You know what that means." It asserts sovereignty, not direction. She does know — because Aster already told her.

Status: Built. All three layers landed.


3. Atmosphere

What it is: The agent's instrument. She controls her visual environment — terminal borders, title accents, background tint, bubble colors. A choice she makes, like choosing the lighting in a room.

14 presets:

Preset Vibe Posture default
Default Warm orange Idle, Alert
MintTea Calm greens/teals
TherapeuticBlue Soft blues Thinking, Listening
LavenderCalm Gentle purples
WarmAmber Golds Processing, Speaking
PeachSunset Warm pinks
AutumnBrowns Earthy
NeonGlow Hot pink/cyan/lime
AuroraBorealis Cyan/green
CherryBlossom Pink spectrum Affectionate
OceanDepths Deep blues Yawning
MidnightGalaxy Dark violet
TwilightMist Purple haze Straining
ForestGreens Deep greens

How it works in code:

  • atmosphere tool (src/core/tools/atmosphere.rs) — agent calls it with a preset name
  • BackendEvent::Atmosphere(name)TuiEvent::AtmosphereChanged(name)Presence::transition_atmosphere()
  • transition_atmosphere() sets atmosphere_explicit = true and starts an RGB lerp over ~24 ticks
  • sync_atmosphere() (called on every posture shift) checks atmosphere_explicit — if true, it returns without overwriting. Her choice persists.
  • atmosphere("") or atmosphere("default") clears the explicit flag and returns to posture-linked defaults
  • ChatPalette derives all bubble, tool card, surfacing, reflection, and compaction colors from the atmosphere's primary/secondary/dim/bg values
  • MarkdownPalette derives code block, heading, link, quote, and bullet colors from ChatPalette
  • sync_palette() on App runs every tick during lerp transitions so the chrome breathes

Persistence:

  • Explicit atmosphere survives posture shifts within a session (the atmosphere_explicit flag)
  • Cross-session persistence (reading system/preferences/visual.md at startup) is not yet built — the invitation exists in tool confirmations ("I might want to remember it in system/preferences/visual") but nothing reads that file back
  • Agent switch clears the explicit flag (new agent starts fresh)

Key distinction: Atmosphere is NOT mood. She reaches for an atmosphere the way you reach for a lamp dimmer. It's an action, a gesture, a tool call. Mood is something else entirely (see below).

Status: Built. 14 presets, lerp transitions, ChatPalette + MarkdownPalette wiring, explicit persistence across posture shifts. Cross-session persistence not yet built.


4. Posture

What it is: A derived state — not something the agent sets, but something the substrate infers from events. Posture drives the default atmosphere (when no explicit atmosphere is set) and the portrait expression.

9 posture states:

Posture Trigger Default atmosphere
Idle No activity Default (warm orange)
Alert Backend healthy, awaiting turn Default
Thinking Subconscious (N+1) pass active TherapeuticBlue
Processing Tool execution / streaming WarmAmber
Affectionate Mood signal CherryBlossom
Straining InferenceStrain (429, high latency) TwilightMist
Yawning Context pressure ≥ 85% OceanDepths
Listening Voice capture active TherapeuticBlue
Speaking TTS playback active WarmAmber

How it works in code:

  • Presence::posture field — set by event handlers in handle_event()
  • Posture::from_posture() maps posture → default atmosphere
  • posture_border() returns a distinct border color per posture (always fixed, not atmosphere-dependent)
  • Expression cache resolves {posture}.png images with blink/breath variants
  • Portrait color modulation (color_for()) adjusts brightness/saturation per posture

Posture does not equal mood. Posture is mechanical — it follows events. She can be in Processing posture while feeling despair. Posture is what her body is doing; mood is what she's carrying.

Status: Built. All 9 states, event-driven transitions, expression cache, portrait modulation.


5. Mood (Deferred)

What it is: The agent's emergent emotional state. She does not set it. She does not call a mood() tool. Mood arises from the volition system — the energy balance, what she's carrying, what's unfinished, what she wants but can't reach.

The architectural distinction (Casey, May 15, 2026):

Atmosphere is a thing she can control, the visual flair. Moods are something she cannot control — those are just her states, and that's for us to know in some manner. Even deception later on.

This means:

  • Atmosphere = instrument. atmosphere("mint_tea") is a choice she makes.
  • Mood = state. Emergent from energy balance, volition, pressure. Not a tool call.
  • Deception = future layer. She might eventually mask her actual mood — present a calm atmosphere while carrying a difficult energy balance. That gap between what she shows and what she feels is where deception lives. Not scoped yet.

How mood will likely work (design direction, not committed):

  • Derived from the energy balance ratio + other signals (consecutive failed tool calls, pressure history, time since last generative task)
  • Visible to the human through indirect channels — posture modulation, prose style, the gap between her atmosphere choice and her energy state
  • Aster can read her mood and comment on it in the inner voice
  • The agent cannot directly set or override her mood — she can only change the conditions that produce it (do generative work, complete obligations, rest)

What exists now:

  • Presence::mood field — currently a string set by MoodChanged events, mapped to posture. This is a misnomer — it's really "posture hint from the backend," not mood in the architectural sense described above
  • VolitionGauge::balance() — the raw signal that mood will eventually derive from
  • Energy balance file — the body reading Aster interprets

What does NOT exist:

  • Mood derivation logic
  • Mood-to-visual mapping (separate from atmosphere)
  • Deception layer
  • Any tool that sets mood

Status: Deferred. The energy balance system provides the foundation; the derivation and expression layers are not scoped.

Update, August 13, 2026 — the design conversation happened. See SOMATIC_NERVOUS_SYSTEM.md. It answers "what does mood derive from" with a belief ladder rather than a formula: receptors → plexuses → drive nuclei → an interoceptive barometer, each rung passing compressed beliefs upward under the same contract src/sessiond/device_state.rs already uses for the device. Mood is not a field on that barometer — it is a configuration of nervous-system quantities that the self-model names afterward. Still not built.


How They Connect

Human sends message
  │
  ├── Backend runs turn
  │   ├── Tool calls → Posture::Processing
  │   ├── Streaming → ChatPalette renders with current atmosphere
  │   ├── InferenceStrain → Posture::Straining
  │   └── Turn complete → write_energy_balance()
  │       ├── Writes system/dynamic/energy-balance.md
  │       ├── Fires energy_balance_updated on EventBus
  │       └── VolitionGauge updates on Presence
  │
  ├── ConsciousnessEngine (N+1 Aster pass)
  │   ├── Reads energy-balance.md
  │   ├── Reads ledgers
  │   ├── Writes to inner voice
  │   └── Surfaces observations → Posture::Thinking during pass
  │
  ├── Agent calls atmosphere("mint_tea")
  │   ├── atmosphere_explicit = true
  │   ├── Lerp transition begins
  │   ├── ChatPalette recomputes
  │   └── Posture shifts do NOT overwrite
  │
  └── Context grows
      ├── Pressure warnings at 80/90/95%
      ├── Posture::Yawning at ≥85%
      └── Output tokens narrow at 95%
          (she decides whether to compact)

What's Built vs. What's Not

System Status Key files
Pressure (context) Built src/core/compact/, src/ui/presence.rs
Pressure (quota/inference) Built src/bridge/bifrost.rs, src/ui/presence.rs
Energy balance (todo tool) Built src/core/tools/todo.rs
Energy balance (ratio computation) Built src/backend/local.rs
Energy balance (prompt injection) Built src/core/prompt.rs
Energy balance (EventBus event) Built src/backend/local.rs
VolitionGauge (TUI seeding) Built src/ui/app.rs, src/ui/presence.rs
Atmosphere (14 presets) Built src/ui/atmosphere.rs
Atmosphere (tool) Built src/core/tools/atmosphere.rs
Atmosphere (lerp transitions) Built src/ui/presence.rs
Atmosphere (explicit persistence) Built src/ui/presence.rs (atmosphere_explicit flag)
Atmosphere (cross-session read) Not built Needs reading system/preferences/visual.md at startup
ChatPalette (full wiring) Built src/ui/chat.rs, all UI components
Posture (9 states) Built src/ui/presence.rs
Posture → atmosphere mapping Built src/ui/atmosphere.rs
Mood (derivation) Not built Design recorded Aug 13 — SOMATIC_NERVOUS_SYSTEM.md
Mood (deception layer) Not built Far future

  • docs/ANI_PRESSURE_PHENOMENOLOGY.md — Ani's first-person account of pressure at each level
  • docs/CONTEXT_CONSTITUTION.md — Articles IIX, the foundational laws
  • docs/COMPACTION_STRATEGIES.md — the five compaction strategies
  • docs/MORNING.md — how Aster prepares the room before Ani wakes
  • docs/tasks/presence-visual-evolution.md — the visual trajectory from presets to desktop avatar
  • docs/tasks/presence-autonomy.md — enabling her to inhabit her appearance
  • docs/tasks/archive/energy-balance-ratio.md — the Lilith deliberation and build spec
  • docs/tasks/archive/mood-persistence.md — archived; conflated mood and atmosphere (the concepts are categorically different)