JSON Output
All commands accept the global --json flag.
{
"status": "ok",
"command": "lint",
"error": null,
"logs": []
}Failures set status to failed and populate error:
{
"status": "failed",
"command": "run",
"error": {
"code": "macro_failed",
"message": "Main Err 5: inputPath is required",
"phase": "invoke_macro"
},
"logs": []
}When another xlflow process is using the same workbook, workbook-bound commands fail immediately with error.code: "workbook_busy". error.details includes workbook, operation, resource_scope, and retryable. It may also include diagnostic owner metadata such as pid, stable command name, operation kind, and start time. Owner metadata can be missing after a crash or during cleanup; the error code, not the presence of owner, is the stable contention signal.
Retryable workbook commands may add global --wait. Waiting defaults to 30 seconds and can be changed with --wait-timeout. Timeout and cancellation use workbook_busy_timeout and workbook_busy_cancelled; their details include wait_timeout. JSON mode never writes wait progress to stderr or mixes it into stdout, so the result remains one valid envelope.
Workbook recovery quarantine is separate from lock contention. After acquiring the normal lock, an unsafe workbook command returns immediately with workbook_recovery_required when a recovery marker exists:
{
"status": "failed",
"command": "push",
"error": {
"code": "workbook_recovery_required",
"message": "The workbook is in an uncertain Excel state after a previous operation. Explicit recovery is required before this command can run; --wait will not resolve it.",
"phase": "coordination.recovery",
"details": {
"workbook": "C:\\projects\\sample\\sample.xlsm",
"operation": "run",
"reason": "vba_may_still_be_running",
"recorded_at": "2026-07-16T09:30:00Z",
"retryable": false,
"wait_will_resolve": false,
"recovery_actions": [
"xlflow session stop --discard",
"xlflow process cleanup 23456",
"xlflow recovery clear",
"xlflow recovery clear --force"
]
}
},
"logs": []
}--wait does not poll or bypass this state. A command whose own termination is uncertain keeps its primary failure and adds top-level recovery:
{
"recovery": {
"required": true,
"published": true,
"reason": "vba_may_still_be_running",
"operation": "run",
"recorded_at": "2026-07-16T09:30:00Z",
"excel_pid": 23456,
"worker_pid": 34567,
"session": {
"active": true,
"owner": "managed"
}
}
}PID and session fields are omitted when xlflow could not observe them.
Unknown commands are also structured when --json appears before the invalid command:
{
"status": "failed",
"command": "xlflow",
"error": {
"code": "unknown_command",
"message": "unknown command \"pussh\"",
"suggestions": ["push"]
},
"logs": []
}Command-specific fields are top-level fields such as issues, analysis, macro, macros, tests, diff, inspect, ui, debug, backups, backup_prune, rollback, target, session, coordination, recovery, warnings, hints, output, forms, edit, runner, version, and capabilities. output carries fmt result summaries, export-image output paths, and form command artifacts.
Capabilities
xlflow capabilities --json is project-independent and returns a versioned, advisory view of command coordination metadata. It is generated by xlflow's central policy registry, so integrations do not need a duplicated table of which commands need a workbook, mutate it, execute VBA, use the UserForm Designer, or can run concurrently.
{
"status": "ok",
"command": "capabilities",
"capabilities": {
"capability_version": 1,
"commands": {
"push": {
"cli_paths": ["push"],
"resource_scope": "workbook",
"operation_kind": "mutate",
"parallel_safe": false,
"retryable_when_busy": true,
"default_wait_policy": "fail",
"recovery_behavior": "block"
}
}
}
}Version 1 keeps command IDs, cli_paths, and all listed field meanings stable. New commands and fields may be added, so consumers must ignore entries or fields they do not recognize. Older xlflow versions may not support the command; an unavailable, malformed, failed, or unsupported-version response means the metadata is unavailable, not that a command is safe. The metadata is advisory: the CLI lock remains authoritative when other processes start operations.
Top-level status and session status add coordination without removing existing fields. Successful observation always distinguishes OS lock ownership from quarantine with busy and recovery_required. A busy object may add resource_scope, operation_kind, command, pid, and started_at. A recovery object adds reason, previous operation, recorded_at, and optional excel_pid / session ownership. Both states may briefly be true. The value is observational command-start state. Probe failure omits the field and adds warning coordination_status_unavailable.
While recovery is required, status avoids unsafe workbook COM access. Session fields may include dirty: null, source_of_truth: "uncertain", and discard_required: true.
backup_prune is returned by xlflow backup prune and may also appear on successful push or rollback when automatic retention deleted entries, skipped invalid or legacy entries, or encountered a pruning failure. Automatic results include "automatic": true; pruning failures are warnings and do not change the successful workbook operation status.
xlflow run --json uses a compact failure payload by default. This keeps the fields that are usually relevant for fixing user VBA code and hides xlflow-internal diagnostic detail unless --verbose is specified.
Default failure example:
{
"status": "failed",
"command": "run",
"error": {
"code": "macro_failed",
"message": "実行時エラー '9':\n\nインデックスが有効範囲にありません。",
"number": 9,
"phase": "invoke_macro"
},
"macro": {
"name": "Main.Run",
"duration_ms": 1115
},
"location": {
"source_path": "src/modules/QRCode.bas",
"component": "QRCode",
"component_type": "module",
"procedure": "AddErrorCorrection",
"line": 449,
"end_line": 449,
"text": " dividend(i + j + 1) = dividend(i + j + 1) Xor genCoef",
"confidence": "high",
"method": "vbe.selection"
},
"session": {
"active": true,
"mode": "explicit",
"dirty": true,
"save_required": true,
"source_of_truth": "live_workbook",
"workbook_path": "C:\\dev\\test\\QRCode\\build\\Book.xlsm"
},
"target": {
"kind": "live_session",
"path": "C:\\dev\\test\\QRCode\\build\\Book.xlsm"
},
"warnings": [
{
"code": "save_required",
"message": "The live workbook is newer than disk. Run xlflow save --session to persist workbook changes."
}
],
"suggestion": "Inspect src/modules/QRCode.bas:449 in AddErrorCorrection. Add targeted XlflowDebug.Log calls around the failing block and rerun."
}Use xlflow run --json --verbose when you need xlflow-internal diagnostics such as full run_diagnostic, workbook/bridge/runtime metadata, dialog snapshots, or location-capture attempt details for bug reports or dialog-watcher debugging.
run --ui-stream and test --ui-stream may add a top-level ui object when XlflowUI dialogs are resolved. The stable field is ui.events, where each event may contain keys such as kind, dialog_id, response_source, resolved_result, resolved_value, redacted, and error.
Example:
{
"status": "ok",
"command": "run",
"ui": {
"events": [
{
"kind": "msgbox",
"dialog_id": "confirm-save",
"response_source": "default",
"resolved_result": "yes",
"redacted": false
},
{
"kind": "inputbox",
"dialog_id": "customer-name",
"response_source": "default",
"resolved_value": "[redacted]",
"redacted": true
}
]
}
}When --ui-stream is enabled, xlflow also writes realtime XlflowUI summaries to stderr. Those streamed lines are not part of stdout JSON.
fmt --json returns output with changed, unchanged, skipped, and total summary fields. fmt --stdin --json returns the same envelope shape instead of formatted text; the formatted source body is not included in the JSON output.
Example:
{
"status": "ok",
"command": "fmt",
"output": {
"changed": 2,
"unchanged": 5,
"skipped": 1,
"total": 8
},
"logs": []
}Source: docs/specs/cli-contract.md.