operational-synthesis-finding-prompt-duplication-review.md

Operational synthesis Markdown finding/deep-dive

/home/matrix-lite/state/persistent-chat/operational-synthesis/findings/prompt-duplication-review.md

Prompt Duplication Review

Date: 2026-05-19

Context: Persistent-chat runs with auto-compaction OFF, long sessions (hours/days), and external file-based memory (turn packets, session packets, curated memory). Every turn injects ~1850 tokens of memory context.

Current Per-Turn Prompt Structure

Session-level (set once at ACPX session creation, ~5k cached)

  1. Character card (JSON: name, pronouns, personality, scenario, style, goals)
  2. Bootstrap prompt (/home/matrix-lite/app/prompts/persistent-chat/bootstrap.md)
  3. Agent build prompt from OpenCode config (agent.build.prompt)
  4. Agent config (model, temperature, steps, permissions)

Per-turn (injected fresh on every user message)

  1. Intro line - "You are Persistent Assistant..."
  2. Conversation metadata - key, session_label, room_id, event_ids
  3. Memory context - turn-packet.md (lean, ~5 lines since tail removal)
  4. Runtime capability context - same hints every turn
  5. Recent room-local conversation - full conversation history tail
  6. Incomplete/failed turns - prior session failures
  7. Attachment metadata - per-message
  8. Replied-to context - per-message
  9. Batched messages - per-turn
  10. Per-turn volatile reminders - 6 identical bullet points every turn
  11. User message

Duplication Analysis

1. Recent room-local conversation (ITEM 5)

Duplicates with: ACPX session's retained conversation history (since no compaction)

Why it's there: Designed for sessions that may compact or reload; ensures continuity

Reality: With auto-compaction OFF, the ACPX session never forgets prior turns

Recommendation: Skip injection when session already has history. Only inject on first turn after session creation or compaction.

Savings: Variable (grows with conversation length); at 20+ turns this is substantial

2. Per-turn volatile reminders (ITEM 10)

Duplicates with: Bootstrap prompt rules and character card instructions

Content: 6 bullet points about <matrix_lite_final> tags, tool approvals, etc.

Reality: Identical every turn; already covered in session-level system prompt

Recommendation: Move to session-level bootstrap prompt or OpenCode agent.build.prompt

Savings: ~400 chars / ~100 tokens per turn → ~30k tokens over 300 turns

3. Intro line (ITEM 1)

Duplicates with: Character card + bootstrap prompt (session-level)

Content: "You are Persistent Assistant running through Matrix-lite..."

Reality: This is already the system identity set at session creation

Recommendation: Remove from per-turn prompt; keep in session-level only

Savings: ~200 chars / ~50 tokens per turn

4. Runtime capability context (ITEM 4)

Duplicates with: Itself (same content every turn)

Reality: Static hints to use MCP tools for dynamic runtime info

Recommendation: Move to session-level bootstrap prompt. The content rarely changes

Savings: ~300 chars / ~75 tokens per turn

5. Turn packet "Current thread" section

Duplicates with: Recent room-local conversation (ITEM 5)

Reality: Both summarize the same conversation from slightly different angles

Recommendation: Already trimmed keyword triggers (removed 'test', 'reload'). Consider removing the "Current thread" section from the turn packet entirely since the room-local conversation handles continuity

Savings: ~200-500 chars per turn depending on action items

6. Conversation metadata (ITEM 2) - partially

Duplicates with: Session-level identifiers

Reality: Static fields (conversation_key, session_label) don't change per turn

Recommendation: Move static metadata to session-level; keep only dynamic event IDs per-turn

Savings: ~100 chars per turn

Recommended Changes (Priority Order)

HIGH - Immediate savings, no behavioral impact

  1. Remove per-turn volatile reminders → merge into bootstrap prompt (+100 tok/turn)
  2. Remove intro line → already in session-level (+50 tok/turn)
  3. Move runtime capability context → to bootstrap prompt (+75 tok/turn)

MEDIUM - Architectural, needs testing

  1. Skip conversation history injection when session has existing context (variable, biggest saving)
  2. Move static metadata to session-level (+25 tok/turn)

LOW - Polish

  1. Further trim turn packet "Current thread" or remove entirely
  2. Multi-tier decision state (active decisions + archive)

Total Estimated Savings

| Change | Per turn | Over 300 turns |

|--------|----------|----------------|

| Volatile reminders → session | ~100 tok | ~30k tok |

| Intro line → session | ~50 tok | ~15k tok |

| Capability hints → session | ~75 tok | ~22.5k tok |

| Skip conversation tail (non-fresh turns) | ~200-500 tok | ~60k-150k tok |

| Total | ~425-725 tok | ~127k-217k tok |

The conversation tail is by far the biggest saving, but even the smaller items compound to significant numbers over long sessions.

Raw Markdown
# Prompt Duplication Review

Date: 2026-05-19
Context: Persistent-chat runs with auto-compaction OFF, long sessions (hours/days), and external file-based memory (turn packets, session packets, curated memory). Every turn injects ~1850 tokens of memory context.

## Current Per-Turn Prompt Structure

### Session-level (set once at ACPX session creation, ~5k cached)
1. Character card (JSON: name, pronouns, personality, scenario, style, goals)
2. Bootstrap prompt (`/home/matrix-lite/app/prompts/persistent-chat/bootstrap.md`)
3. Agent build prompt from OpenCode config (`agent.build.prompt`)
4. Agent config (model, temperature, steps, permissions)

### Per-turn (injected fresh on every user message)
1. **Intro line** - "You are Persistent Assistant..."
2. **Conversation metadata** - key, session_label, room_id, event_ids
3. **Memory context** - turn-packet.md (lean, ~5 lines since tail removal)
4. **Runtime capability context** - same hints every turn
5. **Recent room-local conversation** - full conversation history tail
6. **Incomplete/failed turns** - prior session failures
7. **Attachment metadata** - per-message
8. **Replied-to context** - per-message
9. **Batched messages** - per-turn
10. **Per-turn volatile reminders** - 6 identical bullet points every turn
11. **User message**

## Duplication Analysis

### 1. Recent room-local conversation (ITEM 5)
**Duplicates with:** ACPX session's retained conversation history (since no compaction)
**Why it's there:** Designed for sessions that may compact or reload; ensures continuity
**Reality:** With auto-compaction OFF, the ACPX session never forgets prior turns
**Recommendation:** Skip injection when session already has history. Only inject on first turn after session creation or compaction.
**Savings:** Variable (grows with conversation length); at 20+ turns this is substantial

### 2. Per-turn volatile reminders (ITEM 10)
**Duplicates with:** Bootstrap prompt rules and character card instructions
**Content:** 6 bullet points about `<matrix_lite_final>` tags, tool approvals, etc.
**Reality:** Identical every turn; already covered in session-level system prompt
**Recommendation:** Move to session-level bootstrap prompt or OpenCode `agent.build.prompt`
**Savings:** ~400 chars / ~100 tokens per turn → ~30k tokens over 300 turns

### 3. Intro line (ITEM 1)
**Duplicates with:** Character card + bootstrap prompt (session-level)
**Content:** "You are Persistent Assistant running through Matrix-lite..." 
**Reality:** This is already the system identity set at session creation
**Recommendation:** Remove from per-turn prompt; keep in session-level only
**Savings:** ~200 chars / ~50 tokens per turn

### 4. Runtime capability context (ITEM 4)
**Duplicates with:** Itself (same content every turn)
**Reality:** Static hints to use MCP tools for dynamic runtime info
**Recommendation:** Move to session-level bootstrap prompt. The content rarely changes
**Savings:** ~300 chars / ~75 tokens per turn

### 5. Turn packet "Current thread" section
**Duplicates with:** Recent room-local conversation (ITEM 5)
**Reality:** Both summarize the same conversation from slightly different angles
**Recommendation:** Already trimmed keyword triggers (removed 'test', 'reload'). Consider removing the "Current thread" section from the turn packet entirely since the room-local conversation handles continuity
**Savings:** ~200-500 chars per turn depending on action items

### 6. Conversation metadata (ITEM 2) - partially
**Duplicates with:** Session-level identifiers
**Reality:** Static fields (conversation_key, session_label) don't change per turn
**Recommendation:** Move static metadata to session-level; keep only dynamic event IDs per-turn
**Savings:** ~100 chars per turn

## Recommended Changes (Priority Order)

### HIGH - Immediate savings, no behavioral impact
1. **Remove per-turn volatile reminders** → merge into bootstrap prompt (+100 tok/turn)
2. **Remove intro line** → already in session-level (+50 tok/turn)
3. **Move runtime capability context** → to bootstrap prompt (+75 tok/turn)

### MEDIUM - Architectural, needs testing
4. **Skip conversation history injection** when session has existing context (variable, biggest saving)
5. **Move static metadata** to session-level (+25 tok/turn)

### LOW - Polish
6. **Further trim turn packet "Current thread"** or remove entirely
7. **Multi-tier decision state** (active decisions + archive)

## Total Estimated Savings

| Change | Per turn | Over 300 turns |
|--------|----------|----------------|
| Volatile reminders → session | ~100 tok | ~30k tok |
| Intro line → session | ~50 tok | ~15k tok |
| Capability hints → session | ~75 tok | ~22.5k tok |
| Skip conversation tail (non-fresh turns) | ~200-500 tok | ~60k-150k tok |
| **Total** | **~425-725 tok** | **~127k-217k tok** |

The conversation tail is by far the biggest saving, but even the smaller items compound to significant numbers over long sessions.