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

> Discover how the checkpointed model system enables conversation undo by using write-ahead logs, immutable snapshots, and idempotent delete operations to manage transcript history effectively.

- Repository: [Moonshot AI/kimi-code](https://github.com/MoonshotAI/kimi-code)
- Tags: internals
- Published: 2026-08-16

---

**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`](https://github.com/MoonshotAI/kimi-code/blob/main/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`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/transcript/src/ops/operation.ts):

```typescript
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`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/transcript/src/store/apply.ts) handles this op by removing referenced items from the materialized state:

```typescript
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`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/kap-server/src/session/undo.ts):

```typescript
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`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/protocol/src/rest/session.ts) exposes this functionality through a typed endpoint:

```typescript
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):

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

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

```

**Undo multiple prompts explicitly**:

```typescript
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`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/transcript/src/ops/operation.ts) | Defines `ItemsRemoveOp` and all transcript operation types |
| [`packages/protocol/src/rest/session.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/protocol/src/rest/session.ts) | REST schemas for `POST /v1/sessions/{id}:undo` |
| [`packages/kap-server/src/session/undo.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/kap-server/src/session/undo.ts) | Translates undo requests into `ItemsRemoveOp` instances |
| [`packages/minidb/src/generation.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/minidb/src/generation.ts) | Checkpoint generation and WAL management |
| [`packages/transcript/src/store/apply.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/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.