Skip to content

Valence and Reflex

Daniel Nevoigt edited this page Jul 18, 2026 · 1 revision

Valence & Reflex — human-like memory axes

How memories carry feeling (salience, emotion) and fire as reflexes (recall_mode), and how the curator completes the human-memory model.


🇬🇧 English

Human memory doesn't treat every moment equally: emotionally charged moments consolidate harder and resurface faster, and some cues fire reflexively — no deliberate search involved. bastra-recall mirrors both axes (issue #217).

Valence — emotional salience

Two optional frontmatter fields carry the charge of the capture moment:

Field Values Meaning
salience 01 How strongly the moment should be remembered.
emotion frustration | success | risk | neutral The tone of the moment.

They are stamped by the capture rules — the same signals that already trigger a save now get stored:

  • Recurring frustration ("schon wieder", emphatic caps) → emotion: frustration, salience: 0.8
  • A hard-won fix after >2 iterations → emotion: success, salience: 0.7
  • An explicit "remember this well" → salience: 0.9

Routine saves carry neither field — the assistant never invents them. On overwrite without the fields, existing values are preserved (same rule as write_origin).

What valence does:

  • Slower forgetting — the effective expiration window is days × (1 + salience): a salience: 1 memory lives twice as long before aging to stale/expired. Emotional memories fade last.
  • Ranking (shadow-first) — a bounded score multiplier (1 + salience × cap, cap default 0.25) runs in shadow mode: the would-be re-ranking is logged as salience_shadow on recall telemetry, but served results stay untouched. npm run salience-lift (eval workspace) joins the shadow logs with engagement episodes; only after a measured positive lift is the multiplier switched live via BASTRA_SALIENCE_RANK=live. Same discipline as the trust multiplier (#160).
  • Visible feeling — in the Vault Map, salient memories glow: the aura scales with salience (size-independent, visible zoomed out) and takes the emotion's color — green (success), red (frustration), amber (risk).

Reflex — memories that fire without a query

recall_mode: reflex marks a memory as self-firing. On every non-trivial prompt, the prompt hook posts the text to POST /hook/reflex; the daemon hard-matches it against the recall_when phrases of reflex memories:

  • Deterministic token-AND — every content token of a phrase (≥3 chars, function words stripped) must appear in the prompt. No fuzzy, no prefix, no scores.
  • Single-word triggers only for identifiers — a phrase reduced to one token fires only if it looks like an identifier (npm-shrinkwrap, es2022), never for a plain word like "deployment" — that would be a scatter trigger.
  • Strictly budgeted — max 2 injections per prompt (BASTRA_REFLEX_MAX_PER_TURN, clamp 1–5), max once per memory per 4 h session window. Reflex hits bypass the empty-streak backoff (user-wired = never noise) and render as a dedicated trigger="reflex" hint block.
  • Execution-traced — every firing is a hook_reflex telemetry event (matched phrase, pool size, served ids).

Promotion is always your call. The assistant never sets recall_mode: reflex on its own. The curator watches usage: a memory that was acted on ≥3 times within 30 days becomes a candidate, relayed as a <reflex-candidate> block into your next session — the assistant asks, and only your explicit yes promotes it. Floors stay the manual pin; reflex is the rule-based, self-firing sibling.

Completing the model — consolidation & heat

  • Episodic → semantic — when ≥3 project-facts share a scope+topic and are all older than 30 days, the curator proposes a <consolidation-candidate>: distill ONE lesson (linking the episodes via wikilinks) together with the user. The episodes stay; regular decay handles their fade — sleep-style consolidation, no LLM inside the daemon.
  • Usage heat — the per-memory usage counters (#154) are joined into GET /api/v1/graph as a heat value (0–1, log-scaled): often-applied memories carry a bright core in the map. Heat is the second demand clock next to valence.

Environment knobs

Env var Default Effect
BASTRA_SALIENCE_RANK shadow off | shadow | live (case-insensitive)
BASTRA_SALIENCE_RANK_CAP 0.25 Max score boost: 1 + salience × cap
BASTRA_REFLEX on off disables the reflex lane
BASTRA_REFLEX_MAX_PER_TURN 2 Reflex injection budget per prompt (1–5)
BASTRA_REFLEX_PROMOTION_MIN 3 Acted-on recalls (30 d) before the curator proposes promotion

Settings file: reflex: { enabled, maxPerTurn } in ~/.bastra/cli-settings.json (env wins).


🇩🇪 Deutsch

Menschliches Gedächtnis behandelt nicht jeden Moment gleich: Emotional aufgeladene Momente konsolidieren stärker und tauchen schneller wieder auf, und manche Reize feuern reflexhaft — ganz ohne bewusste Suche. bastra-recall bildet beide Achsen ab (Issue #217).

Valenz — emotionale Salience

Zwei optionale Frontmatter-Felder tragen die Ladung des Erfassungsmoments:

Feld Werte Bedeutung
salience 01 Wie stark der Moment nachwirken soll.
emotion frustration | success | risk | neutral Der Ton des Moments.

Gestempelt werden sie von den Capture-Regeln — dieselben Signale, die einen Save heute schon auslösen, werden jetzt gespeichert:

  • Wiederkehrende Frustration („schon wieder", Caps) → emotion: frustration, salience: 0.8
  • Ein hart erkämpfter Fix nach >2 Iterationen → emotion: success, salience: 0.7
  • Ein explizites „merk dir das gut" → salience: 0.9

Routine-Saves tragen keines der Felder — der Assistent erfindet sie nie. Bei Overwrite ohne die Felder bleiben Bestandswerte erhalten (gleiche Regel wie write_origin).

Was Valenz bewirkt:

  • Langsameres Vergessen — das effektive Ablauffenster ist Tage × (1 + salience): ein Memory mit salience: 1 lebt doppelt so lang, bevor es zu stale/expired altert. Emotionale Erinnerungen verblassen zuletzt.
  • Ranking (shadow-first) — ein begrenzter Score-Multiplikator (1 + salience × cap, Cap default 0.25) läuft im Shadow-Modus: Die Would-be-Reihenfolge wird als salience_shadow in die Recall-Telemetrie geloggt, die servierten Ergebnisse bleiben unangetastet. npm run salience-lift (eval-Workspace) joint die Shadow-Logs mit Engagement-Episoden; erst nach gemessenem positivem Lift wird via BASTRA_SALIENCE_RANK=live scharf geschaltet. Gleiche Disziplin wie beim Trust-Multiplier (#160).
  • Sichtbares Gefühl — in der Vault Map glühen saliente Memories: Die Aura skaliert mit der Salience (größenunabhängig, auch rausgezoomt sichtbar) und trägt die Emotionsfarbe — grün (success), rot (frustration), amber (risk).

Reflex — Memories, die ohne Suchanfrage feuern

recall_mode: reflex markiert ein Memory als selbst-feuernd. Bei jedem non-trivialen Prompt schickt der Prompt-Hook den Text an POST /hook/reflex; der Daemon matcht ihn hart gegen die recall_when-Phrasen der Reflex-Memories:

  • Deterministisches Token-AND — jedes Inhaltstoken einer Phrase (≥3 Zeichen, Funktionswörter gefiltert) muss im Prompt vorkommen. Kein Fuzzy, kein Prefix, keine Scores.
  • Ein-Wort-Trigger nur für Identifier — eine auf ein Token reduzierte Phrase feuert nur, wenn sie wie ein Identifier aussieht (npm-shrinkwrap, es2022), nie für ein Alltagswort wie „deployment" — das wäre ein Streutrigger.
  • Streng budgetiert — max. 2 Injektionen pro Prompt (BASTRA_REFLEX_MAX_PER_TURN, Clamp 1–5), max. 1× pro Memory pro 4-h-Session-Fenster. Reflex-Hits umgehen den Empty-Streak-Backoff (vom User verdrahtet = nie Noise) und erscheinen als eigener trigger="reflex"-Hinweisblock.
  • Execution-traced — jede Feuerung ist ein hook_reflex-Telemetrie-Event (gematchte Phrase, Pool-Größe, servierte ids).

Promotion ist immer deine Entscheidung. Der Assistent setzt recall_mode: reflex nie eigenmächtig. Der Curator beobachtet die Nutzung: Ein Memory, das ≥3× in 30 Tagen angewandt wurde, wird Kandidat und landet als <reflex-candidate>-Block in deiner nächsten Session — der Assistent fragt, erst dein explizites Ja promotet. Floors bleiben der manuelle Pin; Reflex ist das regelbasierte, selbst-feuernde Geschwister.

Das Modell vervollständigen — Konsolidierung & Heat

  • Episodisch → semantisch — teilen ≥3 project-facts Scope+Topic und sind alle älter als 30 Tage, schlägt der Curator einen <consolidation-candidate> vor: gemeinsam mit dem User EINE Lesson destillieren (Episoden per Wikilink verlinkt). Die Episoden bleiben; das reguläre Altern erledigt ihr Verblassen — Konsolidierung wie im Schlaf, ohne LLM im Daemon.
  • Usage-Heat — die Nutzungszähler pro Memory (#154) fließen als heat-Wert (0–1, log-skaliert) in GET /api/v1/graph: Oft angewandte Memories tragen in der Map einen hellen Kern. Heat ist die zweite Nachfrage-Uhr neben der Valenz.

Environment-Schalter

Env-Var Default Wirkung
BASTRA_SALIENCE_RANK shadow off | shadow | live (case-insensitiv)
BASTRA_SALIENCE_RANK_CAP 0.25 Max. Score-Boost: 1 + salience × cap
BASTRA_REFLEX on off deaktiviert die Reflex-Lane
BASTRA_REFLEX_MAX_PER_TURN 2 Reflex-Budget pro Prompt (1–5)
BASTRA_REFLEX_PROMOTION_MIN 3 Acted-on-Recalls (30 T) bis der Curator eine Promotion vorschlägt

Settings-Datei: reflex: { enabled, maxPerTurn } in ~/.bastra/cli-settings.json (Env gewinnt).

Clone this wiki locally