Skip to content

/clear + /clear N — core context trim infrastructure #83

Closed

Description

@harrryyd

Parent

Parent PRD: #82

What to build

Full end-to-end implementation of the /clear and /clear N slash commands. When a user types /clear (wipe everything) or /clear 3 (keep last 3 turns), the system prunes conversation context, inserts a visual trim point divider in the chat timeline, and restarts the provider session so the agent forgets the trimmed history.

This slice covers every layer: schema contracts, server-side CQRS (command dispatch, event sourcing, read model update), provider session restart, WebSocket dispatch, the composer slash command registration, and the UI divider component.

After this slice, a user can type /clear and see a collapsed divider marking trimmed history. /clear N works identically but preserves the last N turns as bootstrap context for the new session. Git checkpoints for trimmed turns are preserved (not deleted) so undo still works.

Acceptance criteria

  • thread.context.trim command schema defined in contracts (with optional keepLastNTurns field)
  • thread.trim-point-created domain event schema defined in contracts
  • OrchestrationThread read model gains a contextTrimPoints: Array<ContextTrimPoint> field (ordered array with id, createdAt, beforeEntryId, prunedMessageCount, prunedTurnIds)
  • Decider validates thread exists, determines trim boundary (last message before trim, or last N turns boundary), emits thread.trim-point-created
  • Projector appends trim point to thread read model and updates derived timeline state
  • Trim command triggers provider session restart: current session is stopped, new session starts with resume cursor past trim boundary. Surviving messages (for /clear N) are sent as bootstrap context.
  • /clear and /clear [N] parse correctly in the composer slash command system and dispatch thread.context.trim
  • ContextTrimPointDivider component renders in the timeline at the trim boundary, showing "Earlier messages" label and pruned message count, always in collapsed state
  • deriveTimelineEntries() produces context-trim entries from the read model
  • deriveMessagesTimelineRows() handles the trim entry as a divider row
  • Git checkpoints for pruned turns remain available (no cleanup of projection_turns rows or git refs)
  • Idempotent: dispatching a trim command on a thread with no messages or no turns produces a no-op trim point (prunedMessageCount = 0)
  • Tests cover: command → event → read model, timeline derivation with trim points, slash command parsing

Blocked by

None — can start immediately

Activity

  1. harrryyd commented on Jun 8, 2026

    @harrryyd
    OwnerAuthor

    Merged in #97.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions