> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qoder.com/llms.txt
> Use this file to discover all available pages before exploring further.

# File Checkpoint and Rewind

`enableFileCheckpointing` is one of the `query()` options. It enables the CLI to take snapshots before and after tools modify files; once enabled, the caller can use `q.rewindFiles(userMessageId, ...)` to roll back files to the state they were in when a particular user message started processing. These two features must be used together: without checkpointing enabled, rewind is not available.

<div id="enabling-file-checkpoint" />

## Enabling File Checkpoint

```typescript theme={null}
import { query } from '@qoder-ai/qoder-agent-sdk';

const q = query({
  prompt: 'Refactor src/foo.ts into a clearer implementation',
  options: {
    cwd: '/path/to/project',
    enableFileCheckpointing: true,
    allowedTools: ['Read', 'Edit', 'Write'],
    permissionMode: 'acceptEdits',
  },
});
```

> **Advanced: when you also need to adjust other CLI configuration via `settings`**
>
> `query()` options also accepts a `settings` field — either a `Settings` object or an absolute path string to a settings file. Its relationship with `enableFileCheckpointing`:
>
> * When passing a `settings` object, the SDK automatically merges `general.fileCheckpointing.enabled = true` — no need to write it manually.
> * When passing a `settings` file path string, the SDK will not rewrite the file contents; you need to configure it yourself in that file:
>
> ```json theme={null}
> {
>   "general": {
>     "fileCheckpointing": {
>       "enabled": true
>     }
>   }
> }
> ```
>
> Just setting `enableFileCheckpointing: true` without passing `settings` is sufficient for scenarios that only need rewind.

***

<div id="using-explicit-user-message-ids" />

## Using Explicit User Message IDs

Rewind uses user message IDs as anchor points. For precise rollback, it's recommended to use structured input and generate your own `uuid`, so the UI can reliably reference "go back to before that message."

```typescript theme={null}
import { randomUUID } from 'node:crypto';
import { query } from '@qoder-ai/qoder-agent-sdk';

const userMessageId = randomUUID();

async function* input() {
  yield {
    type: 'user' as const,
    uuid: userMessageId,
    parent_tool_use_id: null,
    message: {
      role: 'user' as const,
      content: [
        {
          type: 'text' as const,
          text: 'Rewrite notes.txt into a two-line summary.',
        },
      ],
    },
  };

  // If your application needs to call rewind later within the same session,
  // keep yielding subsequent user inputs here instead of closing the stream.
}

const q = query({
  prompt: input(),
  options: {
    cwd: '/path/to/project',
    enableFileCheckpointing: true,
    allowedTools: ['Read', 'Write'],
    permissionMode: 'acceptEdits',
  },
});
```

***

<div id="dry-run-preview" />

## Dry Run Preview

A dry run lets you see whether rollback is possible, which files would be affected, and overall insertion/deletion statistics. Dry run does not modify files.

The returned `RewindFilesResult` contains these fields:

| Field          | Type        | Description                                                                                               |
| -------------- | ----------- | --------------------------------------------------------------------------------------------------------- |
| `canRewind`    | `boolean`   | Whether rollback can be performed. In dry run mode failures don't throw — this field indicates the status |
| `error`        | `string?`   | Diagnostic message when `canRewind=false`, can be displayed directly to the user                          |
| `filesChanged` | `string[]?` | Absolute paths of affected files — useful for listing each file that will be reverted in the UI           |
| `insertions`   | `number?`   | Total lines that were inserted and will be "undone" by the rollback (aggregate)                           |
| `deletions`    | `number?`   | Total lines that were deleted and will be "undone" by the rollback (aggregate)                            |

> The SDK currently only returns the list of affected files and aggregate line-level statistics in `RewindFilesResult` — it does not return per-file diffs. If you need per-file differences, you can read the disk contents based on `filesChanged` after the dry run and compare them with the checkpoint, or use git/workspace diffing tools after executing the rewind.

```typescript theme={null}
const preview = await q.rewindFiles(userMessageId, { dryRun: true });

if (!preview.canRewind) {
  // Show the diagnostic message in the UI.
  console.error(preview.error);
  return;
}

// Overall stats across all affected files.
console.log({
  files: preview.filesChanged?.length ?? 0,
  insertions: preview.insertions ?? 0,
  deletions: preview.deletions ?? 0,
});

// Per-file listing — useful for a confirmation dialog.
for (const file of preview.filesChanged ?? []) {
  console.log(`will be reverted: ${file}`);
}
```

***

<div id="executing-rewind" />

## Executing Rewind

```typescript theme={null}
const result = await q.rewindFiles(userMessageId);
console.log(result.filesChanged);
```

***

<div id="failure-semantics" />

## Failure Semantics

| Call Form                           | Behavior When Rewind Is Not Possible                                                         |
| ----------------------------------- | -------------------------------------------------------------------------------------------- |
| `rewindFiles(id, { dryRun: true })` | Resolves with `{ canRewind: false, error }`, convenient for displaying diagnostics in the UI |
| `rewindFiles(id)` (execution mode)  | Promise rejects; the caller should use `try/catch` to display the failure reason             |

```typescript theme={null}
try {
  await q.rewindFiles(userMessageId);
} catch (error) {
  console.error(error instanceof Error ? error.message : String(error));
}
```

***

<div id="options-reference" />

## Options Reference

| Field                     | Type                 | Description                                                                                            |
| ------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------ |
| `enableFileCheckpointing` | `boolean`            | Enable file checkpointing for use with `rewindFiles()`                                                 |
| `settings`                | `string \| Settings` | Settings passed to the CLI; when passing an object, the SDK merges `general.fileCheckpointing.enabled` |

***

<div id="return-value-reference" />

## Return Value Reference

```typescript theme={null}
type RewindFilesResult = {
  canRewind: boolean;
  error?: string;
  filesChanged?: string[];
  insertions?: number;
  deletions?: number;
};
```

***

<div id="best-practices" />

## Best Practices

* **Save user message IDs**: Applications that need rollback capability should save the `uuid` when sending messages; do not rely on UI text to look them up.
* **Dry run before rewinding**: Show the impact scope first, then let the user confirm the rollback.
* **Refresh UI after rollback**: Rewind only changes files, not conversation history; the UI needs to reload relevant views based on `filesChanged`.
* **Show `error` to the user on failure**: The `error` text when `canRewind=false` can typically be displayed directly to end users for diagnostics.
