How OfficeCLI CommandBuilder.Batch Handles Bulk Operations Across Documents
OfficeCLI's CommandBuilder.Batch executes multiple document commands in a single optimized pass, supporting both resident server and local execution modes with deferred I/O and comprehensive error aggregation.
The CommandBuilder.Batch implementation in the iOfficeAI/OfficeCLI repository provides the central engine for automating complex document manipulations across Word, PowerPoint, and Excel files. This component processes JSON-defined operation sequences, validates schemas against strict definitions, and coordinates execution across hundreds of items while minimizing disk access and memory overhead.
Architecture of the Batch Command Engine
The batch system operates through three distinct layers that transform user input into efficient document mutations.
Command Definition and Input Parsing
The entry point BuildBatchCommand in src/officecli/CommandBuilder.Batch.cs (lines 18-45) constructs the batch sub-command and handles three mutually exclusive input sources: file paths via --input, inline JSON via --commands, or stdin streams. The parser performs BOM stripping and envelope unwrapping to ensure clean JSON deserialization before reaching the validation layer.
Input validation occurs in the loop starting at line 14 (extending through line 64), which verifies that each batch item conforms to the expected schema before execution begins. This early validation prevents partial document corruption by rejecting malformed payloads before any mutations occur.
The Batch Replay Loop
The ApplyBatchItems method (lines 50-78 in CommandBuilder.Batch.cs) serves as the core execution engine. This loop iterates over deserialized BatchItem instances, invoking ExecuteBatchItem for each operation while collecting results and LaTeX warning tokens. The implementation automatically skips resident-only commands such as open and close, wrapping each item in individual try-catch blocks to isolate failures and prevent cascade errors.
Execution Paths: Resident vs Non-Resident
CommandBuilder.Batch dynamically selects between two execution strategies based on server availability, optimizing for either latency or throughput.
Resident Server Mode
When a resident process is detected, the batch system builds a single ResidentRequest containing the entire JSON payload and transmits it via ResidentClient.TrySend. This approach eliminates per-operation document opening overhead by keeping the target file loaded in memory throughout the batch execution, making it ideal for high-frequency automation scenarios.
Local Execution with Deferred Saves
In non-resident mode, the handler opens the document once, sets DeferSave = true to prevent intermediate disk writes, runs the replay loop, and flushes changes exactly once during disposal. This deferred save mechanism significantly reduces I/O bottlenecks when processing hundreds of modifications to large documents.
Protection checks via GetBatchProtectionBlock execute once for the entire batch unless the --force flag is specified, ensuring consistent security validation without redundant prompts for each operation.
Batch Item Format and Schema
Each JSON object in a batch array must contain a command field (the operation verb) and optional sibling fields defined in src/officecli/BatchTypes.cs (lines 66-71). Valid properties include path, parent, type, props, and to, depending on the specific command requirements.
The schema enforces type safety through JSON converters declared in BatchTypes.cs, ensuring that property values match expected formats before reaching the execution layer. This strict typing prevents runtime errors during document manipulation.
Error Handling and Exit Codes
The batch processor implements granular failure management through the --stop-on-error flag. When enabled, execution aborts immediately upon the first failure; otherwise, the loop continues and aggregates per-item errors in the result array.
Exit codes follow a strict hierarchy:
- 0 indicates complete success
- 1 signals that at least one batch item failed
- 2 indicates only unrecognized LaTeX warnings were encountered (mirroring single-command behavior)
All output wraps in a consistent JSON envelope ({ "success": ..., "data": ... }) ensuring identical response structures for both resident and non-resident paths, simplifying downstream automation logic.
Practical Usage Examples
Execute inline JSON commands directly:
officecli batch mydoc.docx \
--commands '[{"command":"add","parent":"/slide[1]","type":"shape","props":{"text":"Hi"}}]' \
--json
Process operations from a file:
cat > ops.json <<'EOF'
[
{"command":"add","parent":"/slide[1]","type":"shape","props":{"text":"Hi","x":"1cm","y":"2cm"}},
{"command":"set","path":"/slide[1]/shape[1]","props":{"bold":"true"}},
{"command":"remove","path":"/slide[2]/shape[3]"}
]
EOF
officecli batch mydoc.pptx --input ops.json
Pipe JSON via stdin:
cat ops.json | officecli batch mydoc.docx
Enable abort-on-failure mode:
officecli batch mydoc.docx --input ops.json --stop-on-error
Bypass document protection checks:
officecli batch mydoc.docx --input ops.json --force
Summary
- Three-layer architecture: Input parsing (
BuildBatchCommand), validation (lines 14-64), and execution (ApplyBatchItems) create a robust pipeline inCommandBuilder.Batch.cs. - Dual execution modes: Resident server mode uses
ResidentClient.TrySendfor single-request processing, while non-resident mode leveragesDeferSaveto minimize disk I/O. - Strict schema validation: Batch items require a
commandfield and optional properties defined inBatchTypes.cs(lines 66-71). - Flexible error handling:
--stop-on-errorprovides immediate failure detection, while aggregated reporting supports exit codes 1 (failure) and 2 (LaTeX warnings only). - Consistent output: JSON envelopes ensure uniform responses across all execution paths.
Frequently Asked Questions
What is the difference between resident and non-resident batch execution?
Resident execution sends the entire batch as a single JSON payload to a running server process via ResidentClient.TrySend, keeping documents open in memory for maximum throughput. Non-resident execution opens the document locally, enables DeferSave to buffer changes, and writes to disk exactly once when the handler disposes, optimizing for stand-alone automation scripts.
How does OfficeCLI handle errors during batch operations?
By default, CommandBuilder.Batch continues processing after individual item failures and returns exit code 1 if any operation fails. When --stop-on-error is specified, the loop terminates immediately on the first exception. Warnings about unrecognized LaTeX tokens result in exit code 2, maintaining parity with single-command behavior.
What fields are required in a batch item JSON object?
Every batch item must include a command field containing the operation verb. According to BatchTypes.cs (lines 66-71), optional fields include path, parent, type, props, and to, with specific requirements varying by command type. The validation loop in CommandBuilder.Batch.cs ensures all provided fields match the expected schema before execution.
How can I optimize batch performance for large document sets?
Use resident mode when available to eliminate per-operation document opening overhead. For non-resident execution, the built-in DeferSave mechanism automatically optimizes disk I/O by flushing changes only once after the entire batch completes. Additionally, avoid --stop-on-error unless necessary, as continuing past recoverable errors maximizes throughput for large operation sets.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →