Skip to main content

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.

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.

Enabling File Checkpoint

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:
{
  "general": {
    "fileCheckpointing": {
      "enabled": true
    }
  }
}
Just setting enableFileCheckpointing: true without passing settings is sufficient for scenarios that only need rewind.

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.”
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',
  },
});

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:
FieldTypeDescription
canRewindbooleanWhether rollback can be performed. In dry run mode failures don’t throw — this field indicates the status
errorstring?Diagnostic message when canRewind=false, can be displayed directly to the user
filesChangedstring[]?Absolute paths of affected files — useful for listing each file that will be reverted in the UI
insertionsnumber?Total lines that were inserted and will be “undone” by the rollback (aggregate)
deletionsnumber?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.
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}`);
}

Executing Rewind

const result = await q.rewindFiles(userMessageId);
console.log(result.filesChanged);

Failure Semantics

Call FormBehavior 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
try {
  await q.rewindFiles(userMessageId);
} catch (error) {
  console.error(error instanceof Error ? error.message : String(error));
}

Options Reference

FieldTypeDescription
enableFileCheckpointingbooleanEnable file checkpointing for use with rewindFiles()
settingsstring | SettingsSettings passed to the CLI; when passing an object, the SDK merges general.fileCheckpointing.enabled

Return Value Reference

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

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.