Problem Statement
Agents accumulate conversation history over many turns. This history consumes the provider context window (Codex has a finite context budget) and eventually causes the agent to lose track of early turns or degrade response quality. Users need a way to prune conversation context without losing their worktree, git history, or the ability to undo changes.
Currently, there is no mechanism to trim context. Users are stuck with ever-growing threads until they manually create a new thread, losing the worktree association and git checkpoint history.
Solution
Three slash commands that give users explicit control over conversation context pruning:
- /clear [N]: Prune all messages before the last N turns, insert a trim point divider. The surviving last N turns are used to bootstrap a restarted provider session.
- /compact: Ask the provider to compact (summarize) the full conversation history, then insert a summary banner and trim point divider. The compacted summary bootstraps a restarted provider session.
- /new: Archive the current thread and create a new one that inherits the worktree, branch, and project — a clean slate with no conversation history.
All three commands restart the provider session rather than pruning messages in-place (per ADR 0003), because provider SDKs maintain their own internal conversation state. Git checkpoints are preserved so users can still revert to filesystem states from pruned turns.
User Stories
- As a developer in a long agent session, I want to type
/clear 3 to keep only my last 3 turns, so that the agent stops being confused by irrelevant early conversation without losing my worktree state.
- As a developer whose agent session is hitting context limits, I want to type
/clear (no argument) to wipe all messages and start fresh in the same thread, so that I can continue working on the same branch without creating a new thread.
- As a developer who wants to preserve the gist of a long conversation, I want to type
/compact to have the agent summarize everything before trimming, so that the bootstrapped session still knows the high-level context of what we were working on.
- As a developer who wants a true clean slate, I want to type
/new to archive my current thread and create a new one inheriting my worktree, so that I can start fresh without losing my filesystem state.
- As a developer reviewing a trimmed thread, I want to see a visual divider (Context Trim Point) marking where the conversation was pruned, so that I know which messages are still in the agent context.
- As a developer reading a compacted thread, I want to see the compacted summary above the trim point divider, so that I can quickly understand what was covered before the trim.
- As a developer, I want to expand/collapse messages before a trim point divider, so that I can still read the full history when needed but it stays out of the way by default.
- As a developer who trimmed context, I want git checkpoints from pruned turns to still be available for
thread.checkpoint.revert, so that I can undo to any previous filesystem state even if the messages are hidden.
- As a developer, I want to see
/clear, /compact, and /new in the slash command autocomplete menu, so that I can discover and use them easily.
- As a developer, I want these commands to be blocked while an agent turn is active, so that I don not accidentally disrupt an in-progress generation.
- As a developer who accidentally typed
/clear, I want the command to not execute if there is an active turn, with a clear indication of why it was blocked.
- As a developer using
/clear 5, I want only the last 5 turns to be preserved in the bootstrapped session, so that the agent has exactly the context I specified.
- As a developer, I want the trim point divider in the UI to show how many messages were pruned, so that I can understand the scope of what was removed from context.
- As a developer working across multiple threads, I want compacted threads to show a summary banner that is visually distinct from normal messages, so that I can immediately tell this thread has been compacted.
- As a developer, I want multiple trim points to be supported (e.g., clear, work more, then compact), so that the UI handles repeated trimming operations on the same thread.
- As a developer archiving a thread with
/new, I want the archived thread to remain accessible in the thread list, so that I can still reference its full history if needed.
Implementation Decisions
Command types and payloads
Three new orchestration commands:
thread.context.trim — User-initiated context pruning. Dispatched by both /clear and /compact (after the provider compact call for the latter).
keepLastNTurns?: number — when present, preserve the last N turns; when absent, trim everything before the current message
summary?: string — compaction summary text (only set when dispatched from /compact)
thread.context.summarize — Records a compaction summary. This is a separate command because /compact is a two-step process: first ask the provider to compact (which updates provider-internal state), then trim the H-code database and insert the summary.
thread.archive-and-new — Archives the current thread and creates a new one inheriting the worktree/branch/project. Dispatched by /new.
Domain events
thread.trim-point-created — Fired when a trim point is applied to a thread:
threadId, trimPointId, createdAt
beforeEntryId — the ID of the last message/entry before the trim boundary
prunedMessageCount — how many messages fall before this trim point
prunedTurnIds — the turn IDs whose messages are excluded from context
thread.context-summarized — Fired when a summary is associated with a trim point:
threadId, trimPointId, summary, compactDurationMs
thread.archived-and-new-created — Fired when /new is dispatched:
archivedThreadId, newThreadId
- The new thread inherits
worktreeId, branchName, projectId from the archived thread
Read model changes
Add to OrchestrationThread:
contextTrimPoints: Array<ContextTrimPoint> where ContextTrimPoint has: id, createdAt, beforeEntryId, prunedMessageCount, prunedTurnIds, summary?
- Trim points are an ordered array (oldest first). The "active context" starts after the latest trim point
No changes needed to OrchestrationMessage — trimming is a read-model concern. Messages before the latest trim point are excluded from deriveTimelineEntries (or included with a trimmed: true flag for the expandable section).
Provider session restart
Per ADR 0003, trim operations restart the provider session:
- Client dispatches
thread.context.trim
- Decider emits
thread.trim-point-created
- A reactor (or the decider case itself via
thread.session.stop) stops the current provider session
- A new provider session is started with a resume cursor pointing past the trim boundary
- For
/compact: the provider compaction is requested first (via thread/compact/start or similar JSON-RPC call), and the resulting summary is recorded via thread.context.summarize
The session restart flow reuses the existing thread.session.stop → startSession pipeline in ProviderService, but needs a new bootstrap mechanism: for /clear N, the bootstrap messages are the last N turns; for /compact, the bootstrap is the summary text; for /new, there is no bootstrap.
Slash command registration
Add to builtInSlashCommandItems in ChatComposer.tsx:
/clear [N] — dispatches thread.context.trim with keepLastNTurns if N is provided
/compact — dispatches thread.context.trim (with two-phase compaction first)
/new — dispatches thread.archive-and-new
Add /clear, /compact, /new to parseStandaloneComposerSlashCommand() regex.
These commands are standalone-only (no combined message). If there is trailing text after the command, the entire input is the command. These are blocked during active turns.
UI components
ContextTrimPointDivider: A horizontal divider bar with:
- "Earlier messages" label
- Hidden message count (e.g., "47 messages pruned")
- Expand/collapse chevron
ContextSummaryBanner: A callout card above the trim divider showing:
- "Context compacted" header
- The summary text
Collapsed message section: Messages and activities before the oldest non-expanded trim point are hidden. Expanding shows them in a visually distinct (dimmed, collapsed-by-default) section.
Session bootstrap after trim
When restarting the session after a trim:
- The resume cursor targets the first message after the latest trim point
- For
/clear N: the last N turns are sent as the initial conversation context
- For
/compact: the summary text is sent as a system message or initial context
- For
/new: a fresh session with no prior context
Testing Decisions
What makes a good test
- Test external behavior through the CQRS command pipeline, not internal implementation
- Verify domain events are produced with correct payloads
- Verify the read model reflects trim points correctly
- Verify timeline derivation produces the right entries with trim points
- Verify session stop events fire when trim commands are dispatched
Modules to test
- Command dispatch pipeline — dispatch
thread.context.trim, verify thread.trim-point-created event with correct payloads. Verify decider rejects trim when thread does not exist or turn is active.
- Projector — apply
thread.trim-point-created to a thread with known messages, verify contextTrimPoints array is populated correctly and timeline derivation excludes trimmed messages.
- Slash command parsing — verify
/clear, /clear 3, /compact, /new parse correctly and dispatch the right orchestration commands.
- Session lifecycle — verify that
thread.context.trim causes a thread.session-stop-requested event to fire (per ADR 0003).
- Timeline rendering — given a thread with trim points from
orchestration.subscribeThread, verify deriveTimelineEntries() produces trim entries and the UI shows the divider.
- Checkpoint preservation — after a trim, verify that
thread.checkpoint.revert can still restore to a pruned turn checkpoint.
Prior art for tests
- Existing CQRS tests in the codebase test command → event flows through the decider and projector
ChatView.test.tsx tests the composer and slash command handling
session-logic.test.ts tests timeline derivation
Out of Scope
- Automatic/background compaction (provider-triggered
thread.state.changed with state: "compacted" is already observed but only as an activity — it does not create trim points)
- Combined command + message syntax (e.g.,
/clear 3 fix the login page) — all three commands are standalone-only
- Custom compaction prompts or summary style configuration
- Trim point cleanup of git checkpoints (checkpoints are explicitly preserved)
- Undo of trim operations (revert already works via
thread.checkpoint.revert which prunes trim points beyond the revert boundary)
- Trim operations during an active turn (explicitly blocked)
Further Notes
- The term "Context Trim Point" and "Context Summary" are defined in CONTEXT.md as canonical domain terms
- ADR 0003 (
docs/adr/0003-context-trim-restarts-session.md) establishes the architectural decision that trim operations restart the provider session
- Multiple trim points per thread are supported — each
/clear or /compact creates a new trim point after the previous one
- The existing
context-compaction activity (from provider auto-compaction) is informational only and does not interact with user-initiated trims
- The
RuntimeThreadState "compacted" value is set by the provider and is orthogonal to H-code trim points
- Thread ID is preserved through
/clear and /compact so worktree/branch bindings survive
/new creates a new thread ID but inherits worktree/branch/project so the user continues working on the same files
Problem Statement
Agents accumulate conversation history over many turns. This history consumes the provider context window (Codex has a finite context budget) and eventually causes the agent to lose track of early turns or degrade response quality. Users need a way to prune conversation context without losing their worktree, git history, or the ability to undo changes.
Currently, there is no mechanism to trim context. Users are stuck with ever-growing threads until they manually create a new thread, losing the worktree association and git checkpoint history.
Solution
Three slash commands that give users explicit control over conversation context pruning:
All three commands restart the provider session rather than pruning messages in-place (per ADR 0003), because provider SDKs maintain their own internal conversation state. Git checkpoints are preserved so users can still revert to filesystem states from pruned turns.
User Stories
/clear 3to keep only my last 3 turns, so that the agent stops being confused by irrelevant early conversation without losing my worktree state./clear(no argument) to wipe all messages and start fresh in the same thread, so that I can continue working on the same branch without creating a new thread./compactto have the agent summarize everything before trimming, so that the bootstrapped session still knows the high-level context of what we were working on./newto archive my current thread and create a new one inheriting my worktree, so that I can start fresh without losing my filesystem state.thread.checkpoint.revert, so that I can undo to any previous filesystem state even if the messages are hidden./clear,/compact, and/newin the slash command autocomplete menu, so that I can discover and use them easily./clear, I want the command to not execute if there is an active turn, with a clear indication of why it was blocked./clear 5, I want only the last 5 turns to be preserved in the bootstrapped session, so that the agent has exactly the context I specified./new, I want the archived thread to remain accessible in the thread list, so that I can still reference its full history if needed.Implementation Decisions
Command types and payloads
Three new orchestration commands:
thread.context.trim— User-initiated context pruning. Dispatched by both/clearand/compact(after the provider compact call for the latter).keepLastNTurns?: number— when present, preserve the last N turns; when absent, trim everything before the current messagesummary?: string— compaction summary text (only set when dispatched from/compact)thread.context.summarize— Records a compaction summary. This is a separate command because/compactis a two-step process: first ask the provider to compact (which updates provider-internal state), then trim the H-code database and insert the summary.thread.archive-and-new— Archives the current thread and creates a new one inheriting the worktree/branch/project. Dispatched by/new.Domain events
thread.trim-point-created— Fired when a trim point is applied to a thread:threadId,trimPointId,createdAtbeforeEntryId— the ID of the last message/entry before the trim boundaryprunedMessageCount— how many messages fall before this trim pointprunedTurnIds— the turn IDs whose messages are excluded from contextthread.context-summarized— Fired when a summary is associated with a trim point:threadId,trimPointId,summary,compactDurationMsthread.archived-and-new-created— Fired when/newis dispatched:archivedThreadId,newThreadIdworktreeId,branchName,projectIdfrom the archived threadRead model changes
Add to
OrchestrationThread:contextTrimPoints: Array<ContextTrimPoint>whereContextTrimPointhas:id,createdAt,beforeEntryId,prunedMessageCount,prunedTurnIds,summary?No changes needed to
OrchestrationMessage— trimming is a read-model concern. Messages before the latest trim point are excluded fromderiveTimelineEntries(or included with atrimmed: trueflag for the expandable section).Provider session restart
Per ADR 0003, trim operations restart the provider session:
thread.context.trimthread.trim-point-createdthread.session.stop) stops the current provider session/compact: the provider compaction is requested first (viathread/compact/startor similar JSON-RPC call), and the resulting summary is recorded viathread.context.summarizeThe session restart flow reuses the existing
thread.session.stop→startSessionpipeline inProviderService, but needs a new bootstrap mechanism: for/clear N, the bootstrap messages are the last N turns; for/compact, the bootstrap is the summary text; for/new, there is no bootstrap.Slash command registration
Add to
builtInSlashCommandItemsinChatComposer.tsx:/clear [N]— dispatchesthread.context.trimwithkeepLastNTurnsif N is provided/compact— dispatchesthread.context.trim(with two-phase compaction first)/new— dispatchesthread.archive-and-newAdd
/clear,/compact,/newtoparseStandaloneComposerSlashCommand()regex.These commands are standalone-only (no combined message). If there is trailing text after the command, the entire input is the command. These are blocked during active turns.
UI components
ContextTrimPointDivider: A horizontal divider bar with:
ContextSummaryBanner: A callout card above the trim divider showing:
Collapsed message section: Messages and activities before the oldest non-expanded trim point are hidden. Expanding shows them in a visually distinct (dimmed, collapsed-by-default) section.
Session bootstrap after trim
When restarting the session after a trim:
/clear N: the last N turns are sent as the initial conversation context/compact: the summary text is sent as a system message or initial context/new: a fresh session with no prior contextTesting Decisions
What makes a good test
Modules to test
thread.context.trim, verifythread.trim-point-createdevent with correct payloads. Verify decider rejects trim when thread does not exist or turn is active.thread.trim-point-createdto a thread with known messages, verifycontextTrimPointsarray is populated correctly and timeline derivation excludes trimmed messages./clear,/clear 3,/compact,/newparse correctly and dispatch the right orchestration commands.thread.context.trimcauses athread.session-stop-requestedevent to fire (per ADR 0003).orchestration.subscribeThread, verifyderiveTimelineEntries()produces trim entries and the UI shows the divider.thread.checkpoint.revertcan still restore to a pruned turn checkpoint.Prior art for tests
ChatView.test.tsxtests the composer and slash command handlingsession-logic.test.tstests timeline derivationOut of Scope
thread.state.changedwithstate: "compacted"is already observed but only as an activity — it does not create trim points)/clear 3 fix the login page) — all three commands are standalone-onlythread.checkpoint.revertwhich prunes trim points beyond the revert boundary)Further Notes
docs/adr/0003-context-trim-restarts-session.md) establishes the architectural decision that trim operations restart the provider session/clearor/compactcreates a new trim point after the previous onecontext-compactionactivity (from provider auto-compaction) is informational only and does not interact with user-initiated trimsRuntimeThreadState"compacted"value is set by the provider and is orthogonal to H-code trim points/clearand/compactso worktree/branch bindings survive/newcreates a new thread ID but inherits worktree/branch/project so the user continues working on the same files