How OfficeCLI Batch Command Implements Atomic Transactions and Rollback on Errors

The OfficeCLI batch command treats document-modifying operations as atomic transactions by executing commands against a temporary copy and only overwriting the original file if every operation succeeds, automatically deleting the temporary file on any error.

The OfficeCLI batch command provides enterprise-grade reliability for document automation by ensuring that multi-step operations either complete entirely or leave the source document untouched. According to the iOfficeAI/OfficeCLI source code, this implementation leverages temporary file copying and atomic file replacement to guarantee data integrity during batch processing.

Atomic Transaction Detection

The batch command first determines whether to run in atomic mode by analyzing the command set and user flags.

Best-Effort vs Atomic Mode

By default, the batch runs atomically unless the --best-effort flag is provided. The code in src/officecli/CommandBuilder.Batch.cs checks whether any batch item contains a mutating verb by verifying if the command exists outside the ReadOnlyBatchVerbs set:

// src/officecli/CommandBuilder.Batch.cs#L29-L37
var atomic = !bestEffort && items.Any(it => !ReadOnlyBatchVerbs.Contains(it.Command ?? ""));

When atomic evaluates to true and at least one operation modifies the document, the system engages full transaction protection. If all commands are read-only operations, atomic mode is unnecessary since no changes are persisted.

Temporary File Isolation

When atomic mode is active, the batch command never opens the original document for write operations. Instead, it creates a temporary working copy in the same directory:

// src/officecli/CommandBuilder.Batch.cs#L44-L52
var tmpStem = TruncateStemForTempName(Path.GetFileNameWithoutExtension(targetPath));
var tmpPath = Path.Combine(tmpDir, $".{tmpStem}.batch-{Guid.NewGuid():N}{tmpExt}");

The temporary filename uses a truncated stem to comply with filesystem length limits while maintaining a unique identifier via GUID. This isolation prevents partial writes or corruption of the original document during command execution.

Execution and Rollback Mechanics

The batch executes against the temporary copy through DocumentHandlerFactory.Open(workPath, editable:true) and RunNonResidentBatch, keeping all modifications in memory until the handler disposes.

Commit or Rollback Decision

After execution completes, the system evaluates batchSuccessLocal to determine if all BatchResult.Success values are true. The rollback logic in CommandBuilder.Batch.cs implements the atomic guarantee:

// src/officecli/CommandBuilder.Batch.cs#L74-L82
if (tmpPath != null)
{
    if (batchSuccessLocal)
        File.Replace(tmpPath, targetPath, null);
    else
        File.Delete(tmpPath);
}

Success path: The temporary file is atomically promoted to replace the original using File.Replace, which preserves file permissions and ensures a crash-free swap.

Failure path: The temporary file is deleted via File.Delete, leaving the original document completely untouched.

Error Handling Controls

The batch command provides additional flags to fine-tune error behavior without compromising atomicity:

  • --stop-on-error: Forces immediate abort on the first failure. While atomic mode already aborts failed batches, this flag specifically controls early-exit behavior for non-atomic (--best-effort) runs.
  • --force: Bypasses document protection checks (such as DOCX read-only settings) while maintaining atomic transaction semantics.

Cleanup of Orphaned Temporary Files

Before creating a new temporary copy, the system sweeps for stale temporary files older than 15 minutes. This prevents disk litter from previous crashes or interrupted processes, ensuring the working directory remains clean without manual intervention.

Practical Code Examples

Run an atomic batch that automatically rolls back on any error:

officecli batch mydoc.docx --commands '[{"command":"add","parent":"/slide[1]","type":"shape","props":{"text":"Hi"}},{"command":"set","path":"/slide[2]/shape[5]","props":{"color":"red"}}]'

Execute in best-effort mode, preserving successful changes if one command fails:

officecli batch mydoc.docx --best-effort --commands '[{"command":"add","parent":"/slide[1]","type":"shape","props":{"text":"Hi"}},{"command":"set","path":"/slide[2]/shape[5]","props":{"color":"red"}}]'

Force immediate abort on first failure (explicit control):

officecli batch mydoc.docx --stop-on-error --commands '[...]'

Summary

  • Atomic by default: The OfficeCLI batch command automatically enables transaction protection when mutating operations are detected, unless --best-effort is specified.
  • Temporary file isolation: All modifications occur on a GUID-named temporary copy (.batch-<guid>), leaving the source document untouched during execution.
  • True atomic replacement: Successful batches use File.Replace for atomic promotion, while failures trigger File.Delete for complete rollback.
  • Automatic cleanup: Orphaned temporary files older than 15 minutes are purged before new batch operations begin.
  • Flexible error control: The --stop-on-error and --force flags provide granular control over failure handling without compromising atomicity.

Frequently Asked Questions

What happens if the batch command crashes midway through execution?

If the process crashes during execution, the temporary file (.batch-<guid>) remains on disk but is isolated from the original document. The next batch operation automatically cleans up temporary files older than 15 minutes, or you can manually delete the orphaned file. The original document remains completely intact because the batch only works on the temporary copy until final promotion.

Can I use atomic transactions with read-only batch operations?

When all batch items consist of read-only verbs (commands contained in the ReadOnlyBatchVerbs set), the system automatically disables atomic mode since no file modifications occur. This optimization skips temporary file creation and works directly on the source document, improving performance for inspection or reporting tasks.

How does the --best-effort flag differ from --stop-on-error?

The --best-effort flag disables atomic transactions entirely, allowing successful commands to persist while logging failures. In contrast, --stop-on-error controls early termination behavior but maintains atomic semantics—when used with the default atomic mode, it ensures the batch aborts immediately on first failure and rolls back all changes.

Does the atomic rollback protect against disk space errors?

Yes. Since the batch operates on a temporary copy, any failure—including disk space exhaustion during the save operation—prevents the File.Replace operation from executing. The system deletes the incomplete temporary file and leaves the original document unchanged, ensuring you never end up with a partially-written or corrupted document due to resource constraints.

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 →