Problem
nango dryrun (and the related sync-debug flow in dryrun.service.ts) prints its results through chalk to stdout. The output mixes progress logs, formatted request/response dumps, color codes, and chalk.gray('no output') strings. A user — or a CI step, or an agent harness like Claude Code / Codex — cannot parse the action output, log counts, or error code without scraping formatted text.
For local interactive use this is fine, but it blocks the most common automation paths:
- CI pipelines that want to assert the dry-run produced a specific number of records or didn't error.
- Agent harnesses (Claude Code, Codex, Cursor) that call
nango dryrun as a tool and need to feed the result back into a model.
- PR-check bots that diff
nango dryrun output against a baseline.
Today the only output-format signal is --validate / --save-responses (writes to a fixed test-fixture file). There is no structured "what happened" channel on stdout.
Proposed change
Add a --json flag to nango dryrun that, when set:
-
Suppresses chalk colors, the inquirer prompts, and the spinner.
-
Emits a single JSON object to stdout of the form:
{
"ok": true,
"error": null,
"output": <action output or sync records>,
"logs": { "counts": {...}, "messages": [...] },
"requests": [...],
"diagnostics": <only when --diagnostics is set>
}
-
Exits with the same codes as today (DryrunError, CompileError, etc.) so CI can detect failure without parsing JSON.
Implementation sketch (mirrors how --diagnostics and --save-responses are already wired in packages/cli/lib/index.ts and packages/cli/lib/services/dryrun.service.ts):
- Extend
RunArgs in dryrun.service.ts with outputJson?: boolean.
- In the existing
console.log / console.error call sites, branch on this.outputJson — emit process.stdout.write(JSON.stringify(...) + '\n') instead of formatted text.
- Add the flag to the commander definition in
packages/cli/lib/index.ts next to --diagnostics.
- Add a small section to
docs/integrations/cli.md covering --json and the schema.
Distinct from --save-responses (which writes a fixture for replay) — --json is the runtime result in a single machine-readable envelope.
Use case
A .github/workflows/integration-validate.yml job runs nango dryrun my-sync <connection> --validate --json on every PR. The job:
- Pipes the JSON through
jq to assert .ok == true and .logs.counts.success > 0.
- On failure, posts the parsed
error.code and the first 5 logs.messages as a PR comment.
Today the same job has to either run the dry-run twice (once with --save-responses and parse the fixture) or grep through chalk-colored output. Both are fragile and break on every minor CLI text change.
Why this is small
The data is already computed in dryrun.service.ts — resultOutput, logMessages.counts, validation errors, diagnostics. The change is: collect them into one envelope, branch on the new flag at the print sites, add one CLI option. No new dependencies, no schema migration, fully backward compatible.
Problem
nango dryrun(and the related sync-debug flow indryrun.service.ts) prints its results throughchalkto stdout. The output mixes progress logs, formatted request/response dumps, color codes, andchalk.gray('no output')strings. A user — or a CI step, or an agent harness like Claude Code / Codex — cannot parse the action output, log counts, or error code without scraping formatted text.For local interactive use this is fine, but it blocks the most common automation paths:
nango dryrunas a tool and need to feed the result back into a model.nango dryrunoutput against a baseline.Today the only output-format signal is
--validate/--save-responses(writes to a fixed test-fixture file). There is no structured "what happened" channel on stdout.Proposed change
Add a
--jsonflag tonango dryrunthat, when set:Suppresses chalk colors, the inquirer prompts, and the spinner.
Emits a single JSON object to stdout of the form:
{ "ok": true, "error": null, "output": <action output or sync records>, "logs": { "counts": {...}, "messages": [...] }, "requests": [...], "diagnostics": <only when --diagnostics is set> }Exits with the same codes as today (
DryrunError,CompileError, etc.) so CI can detect failure without parsing JSON.Implementation sketch (mirrors how
--diagnosticsand--save-responsesare already wired inpackages/cli/lib/index.tsandpackages/cli/lib/services/dryrun.service.ts):RunArgsindryrun.service.tswithoutputJson?: boolean.console.log/console.errorcall sites, branch onthis.outputJson— emitprocess.stdout.write(JSON.stringify(...) + '\n')instead of formatted text.packages/cli/lib/index.tsnext to--diagnostics.docs/integrations/cli.mdcovering--jsonand the schema.Distinct from
--save-responses(which writes a fixture for replay) —--jsonis the runtime result in a single machine-readable envelope.Use case
A
.github/workflows/integration-validate.ymljob runsnango dryrun my-sync <connection> --validate --jsonon every PR. The job:jqto assert.ok == trueand.logs.counts.success > 0.error.codeand the first 5logs.messagesas a PR comment.Today the same job has to either run the dry-run twice (once with
--save-responsesand parse the fixture) or grep through chalk-colored output. Both are fragile and break on every minor CLI text change.Why this is small
The data is already computed in
dryrun.service.ts—resultOutput,logMessages.counts, validation errors, diagnostics. The change is: collect them into one envelope, branch on the new flag at the print sites, add one CLI option. No new dependencies, no schema migration, fully backward compatible.