# Dynamic context layers — augmentation, TTL, and intent routing

*Design note (2026-04). **Implemented** in `scripts/context_augmentations.py`, SQLite `context_augmentations`, Telegram listener merge + commands, `session-context.json` field `context_augmentations`, dashboard **Advanced** tuning.*

This extends the **intent routing** direction (micro-brain flags + dedicated handlers): routed intents should be able to **attach temporary context blocks** that **grow** while a topic stays active and **decay** when the conversation idles or pivots — similar in spirit to agentic coding sessions, but with **time- and topic-based shrinkage** instead of relying on an explicit “compact” command (optional compaction remains a safety valve at hard token limits).

---

## 1. Goals

1. **Avoid** paying full design-doc / long-memory / attachment cost on **every** turn.
2. When the user (or model) **steers** toward architecture, skills, deep memory, or a document thread, **promote** relevant material into the active prompt for a **bounded period**.
3. **Renew** TTL while the thread stays on-topic; let slices **expire** when the thread goes quiet or moves elsewhere.
4. **Never evict baseline identity/safety context** — only **augmentations**.
5. Optional **hard cap**: drop oldest / stalest augmentations first if total augmented tokens exceed a budget.

---

## 2. Conceptual model: baseline vs augmentations


| Layer                                               | Examples                                                                                                                                                                            | Policy                                           |
| --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ |
| **Baseline** (always in system prompt for Telegram) | `identity_shell` (`scripts/identity_shell.py`), synthesised user profile + `user_facts`, addressing hint, `behavioral_cues`, core `narrator_briefing` slice, output channel contract, thin recap rules | **Not** subject to TTL eviction from this system |
| **Augmentations** (temporary)                       | Extra `design_docs` chunks, targeted memory bundles, “pinned” excerpt from a file, expanded `conversation_turns` window, callable-skill stdout summaries, intent-handler injections | **TTL + renewal + cap eviction**                 |


Augmentations are **labeled slices**: `{ id, source_type, source_ref, content, created_at, expires_at, last_renewed_at, est_tokens, intent_tags[] }`.

---

## 3. Lifecycle

### 3.1 Load (attach)

Triggers (can combine):

- **Intent router** — e.g. `route_pending_ask_user`, future `route_design_capability_check`, `/commands`.
- **Semantic gate** — micro-brain or cheap embed: “is this turn still about architecture / skills / memory topic X?”
- **Explicit user** — “remember this thread” / “pull in the skills doc” (future).

Handler **fetches** content (Chroma `design_docs`, `memories`, SQLite, file slice), **estimates tokens**, **pushes** an augmentation with initial TTL (e.g. 15–45 minutes wall-clock, or N user turns — product choice).

### 3.2 Renew

On each inbound user message (or assistant turn, configurable):

- If **active augmentations** match the current topic (keyword/intent flag/embed similarity threshold), **extend `expires_at*`* (sliding window).
- Same slice can be **refreshed** (re-query with updated query string from last user message) without duplicating: replace content + reset TTL, or merge.

### 3.3 Expire (natural shrink)

- **Wall-clock:** `now > expires_at` → drop slice.
- **Topic shift:** classifier says “off-topic” for M consecutive turns → shorten TTL or drop tag-specific slices.
- **Session gap:** long silence (reuse `NEW_SESSION_GAP` or stricter) → clear **non-pinned** augmentations.

No user command required; **conversation slowing** = fewer renewals = natural decay.

### 3.4 Hard cap (safety valve)

If **sum(augmentation est_tokens) > AUGMENT_BUDGET_TOKENS** (or total system prompt > ceiling):

- Remove augmentations in order: **lowest priority**, then **soonest expiry**, then **oldest `last_renewed_at`**.
- **Never** remove baseline layers.
- Optional: **summarize** a dropped slice into one short bullet stored as a new low-token “residue” slice (single LLM call, MODEL_FAST) — only if worth the complexity.

This is the closest analog to “auto compact,” but it applies **only to augmentations**, not to core prompt stack.

---

## 4. Relation to intent routing

- **Intent router** (micro-brain fields + slash + regex) decides **which loader** runs (`load_design_context`, `load_memory_bundle`, …).
- **Context manager** (new component) owns **insert / renew / expire / cap**.
- Callable **tools** can still add augmentations (“tool result stays visible for K turns”) under the same manager.

Keep **routing** and **storage** separate: intents stay dumb thin; manager enforces global budgets.

---

## 5. Storage and harness scope

**Telegram (primary):**

- Prefer **durable but local** store: e.g. `memory/conversation_context_overlay.json` or SQLite table `context_augmentations` keyed by `chat_id` (single-user default) + optional `session_id`.
- Listener **reads** overlays on each `build_system_prompt` / pre-reply assembly and **merges** augmentations below baseline sections (or after `narrator` per readability).

**Other harnesses:**

- Same contract: read/write overlay by harness id so the design stays **harness-agnostic** (see `docs/INTEGRATION.md`).

---

## 6. Observability

- **Dashboard / trace:** list active augmentations (label, tokens, expires_in, intent_tags) for debugging.
- **Logs:** intent fired → slice id → renewals / evictions.

---

## 7. Implementation phases (suggested)

1. **Schema + manager** — CRUD, TTL, renew hook, cap eviction, no new intents yet.
2. **Wire one intent** — e.g. design-deep-dive or extend ask-user roundup to register a small slice.
3. **Renewal classifier** — cheap micro-brain field or embed similarity on user text vs slice tags.
4. **Token estimator** — rough char/4 + model-specific fudge; refine with usage metadata if available.

---

## 8. Open questions

- **Turn-based vs wall-clock TTL** — hybrid often works: wall-clock max + renew per substantive user message.
- **Whether augmentations appear in `session-context.json`** — could mirror summaries for non-Telegram harnesses, or keep overlays listener-only until unified.
- **Pinning** — operator “keep design open until I say done” → `pinned: true` bypasses auto-expiry until cleared.

---

## 9. Trace visibility (OpenRouter payload)

- Every Telegram main reply writes `logs/context-trace.jsonl` with **`final_messages`**: the exact `messages` array sent on the **first** chat completion call (system string including augmentations, stamped history turns, user text).
- **`context_augmentation:design_docs`** pieces in the trace mirror the SQLite augmentation body; Chroma rows are truncated for the **live** prompt (short excerpts in `_format_design_chunks`).
- **Optional** (off by default): Advanced → **Context trace debug** or `FUROSHIKI_CONTEXT_TRACE_FULL_DESIGN=1` adds a **`debug`** object on **every** traced turn while enabled:
  - **`augmentations_in_prompt`** — rows actually merged after TTL/budget (with `expires_at`, `pinned`, etc.).
  - **`design_docs_augmentation_in_prompt`** — whether the design bundle is in that turn’s prompt.
  - **`full_design_chroma_status`** — e.g. `ok`, `skipped_no_design_augmentation_in_prompt`, `no_hits_above_threshold`.
  - **`design_docs_chroma_full_text`** — longer per-hit text **only when** design augmentation is active **and** Chroma returns hits (still trace-only; does not change the live prompt).

### Listener logs (lifecycle)

Search `logs/` for the listener log and strings:

- `context_augmentations: attached design_docs bundle` — first attach for this session/topic gate.
- `context_augmentations: refreshed design_docs bundle` — content re-queried from Chroma on renew.
- `context_augmentations: renewed design_docs TTL only (no Chroma hits)` — TTL extended but query returned nothing above threshold.
- `context_augmentations: expired …` — past `expires_at`.
- `context_augmentations: cleared … (session gap` — idle gap ≥ gap-clear minutes.
- `context_augmentations: evicted … for token budget` — row dropped to stay under budget.

---

## Related docs

- Intent routing brainstorm (micro-brain vs callable tools): `docs/OPENROUTER-TOOL-CALLING-AND-SKILLS.md` (ask-user roundup pointer).
- Integration contract: `docs/INTEGRATION.md` (`session-context.json` fields).
- Design embedding: `furoshiki design query` / `design_docs` Chroma collection.

