How the Checkpointed Model System Enables Conversation Undo in Kimi-Code

The checkpointed model system supports conversation undo by storing operations to a write-ahead log, periodically creating immutable snapshots (checkpoints), and applying idempotent items.remove operations to logically delete targeted transcript items without rewinding state.

Kimi-Code implements a durable, restart-safe undo mechanism through its checkpointed model architecture. Every user interaction, AI response, and state mutation is captured as a granular operation (op) in a transcript stream. This design enables precise rewinding of conversation history through logical deletion rather than physical state reversal, as implemented in the MoonshotAI/kimi-code repository.

The Checkpointed Model Architecture

The transcript engine separates durability concerns into two layers:

  • Checkpoints: Immutable snapshots of the entire transcript at designated points in time
  • Write-Ahead Log (WAL): All operations occurring after the most recent checkpoint, stored sequentially

This separation, visible in packages/minidb/src/generation.ts, allows the system to reconstruct any historical state by loading a checkpoint and replaying WAL entries up to the desired point.

How Operations Represent State Changes

Every mutation to the conversation state is encoded as a TranscriptOperation. These ops are intentionally small and declarative, describing what changed rather than how to change it.

The core undo mechanism relies on the ItemsRemoveOp, defined in packages/transcript/src/ops/operation.ts:

export interface ItemsRemoveOp {
  readonly op: 'items.remove';
  readonly ids: readonly string[];
}

This operation is idempotent — applying it multiple times produces the same result as applying it once. The transcript store in packages/transcript/src/store/apply.ts handles this op by removing referenced items from the materialized state:

function applyOp(state, op) {
  if (op.op === 'items.remove') {
    for (const id of op.ids) {
      delete state.items[id];
    }
  }
  // …handle other op kinds
}

The Undo Flow: From API to State Mutation

When a user requests to undo, the system performs two distinct phases: identification and emission.

Phase 1: Identify Target Items

The session service queries the transcript to determine which items must disappear — turns, steps, frames, markers, or nested structures. From packages/kap-server/src/session/undo.ts:

function makeUndoOps(session, count) {
  const idsToRemove = session.transcript.getLastIds(count);
  return {
    op: 'items.remove',
    ids: idsToRemove,
  } as ItemsRemoveOp;
}

Phase 2: Emit the Removal Operation

The generated ItemsRemoveOp is appended to the current TranscriptOpBatch and applied through AgentTranscript.apply, the single convergence point for all state changes in the system.

REST API for Conversation Undo

The protocol layer in packages/protocol/src/rest/session.ts exposes this functionality through a typed endpoint:

export const undoSessionRequestSchema = z.preprocess(
  // default: undo one prompt if body is missing
);

export type UndoSessionRequest = z.infer<typeof undoSessionRequestSchema>;

export const undoSessionResponseSchema = z.object({
  // … details of the new transcript window
});

Client-Side Usage Examples

Undo a single last prompt (no body required):

import { fetch } from '@moonshot-ai/klient';

await fetch('/v1/sessions/abc123:undo', {
  method: 'POST',
  // no body → defaults to `count: 1`
});

Undo multiple prompts explicitly:

await fetch('/v1/sessions/abc123:undo', {
  method: 'POST',
  body: JSON.stringify({ count: 2 })
});

Two Strategies for State Reconstruction

The checkpointed model enables undo through two equivalent paths:

Strategy Mechanism Use Case
WAL truncation Replay only WAL entries up to checkpoint, discard remainder Bulk rollback, compaction scenarios
Logical removal Append items.remove op to active batch Interactive undo, audit trail preservation

Both strategies yield consistent earlier views. The logical removal approach is preferred for user-facing undo because it preserves complete operation history — critical for debugging, compliance, and collaborative features.

Persistence Across Restarts

The checkpointed model ensures undo works even after server restart:

  1. On startup, load the most recent checkpoint from durable storage
  2. Replay all WAL entries to reconstruct current state
  3. New items.remove operations continue appending to the WAL
  4. Next checkpoint creation includes the undo operations themselves

This design eliminates the need for complex "undo stacks" or in-memory history buffers that would be vulnerable to process termination.

Key Source Files

File Responsibility
packages/transcript/src/ops/operation.ts Defines ItemsRemoveOp and all transcript operation types
packages/protocol/src/rest/session.ts REST schemas for POST /v1/sessions/{id}:undo
packages/kap-server/src/session/undo.ts Translates undo requests into ItemsRemoveOp instances
packages/minidb/src/generation.ts Checkpoint generation and WAL management
packages/transcript/src/store/apply.ts Centralized operation application logic

Summary

  • The checkpointed model combines immutable snapshots with sequential WAL entries for durable conversation state
  • Undo is implemented as an items.remove operation that logically deletes targeted items by ID
  • This approach is idempotent, auditable, and restart-safe — no in-memory state required
  • The AgentTranscript.apply method serves as the single convergence point for all state mutations
  • Client access follows standard REST patterns through the /v1/sessions/{id}:undo endpoint

Frequently Asked Questions

How does Kimi-Code handle undo after a server restart?

The system reconstructs state by loading the most recent checkpoint and replaying all subsequent WAL entries. Because items.remove operations are themselves stored in the WAL, undo history persists across restarts without special handling.

What makes the items.remove operation idempotent?

The operation contains an explicit list of IDs to delete. Applying it once or multiple times produces identical state — the second attempt finds no matching IDs and silently completes. This property simplifies error recovery and network retry logic.

Why use logical removal instead of WAL truncation for interactive undo?

Logical removal preserves complete operation history, enabling forensic analysis and collaborative conflict resolution. WAL truncation is reserved for administrative compaction operations where history loss is acceptable.

Can users undo an undo operation?

Yes. Since items.remove is itself a transcript operation, it can be targeted by subsequent undo requests. The system treats undo operations identically to user-generated content — they exist in the observable history and can be reversed through the same mechanism.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →