packages/cli/docs/non-interactive-mode.md
This document is for two audiences:
vercel with --non-interactive and parse stdout. It describes the JSON contract: status, reason, next[], and how to use suggested commands without manual substitution when possible.When vercel runs with --non-interactive (or in an agent/CI context where non-interactive is implied), commands should behave predictably for automation: structured output, copy-pasteable next steps, and no ANSI in JSON.
action_required — User/agent must run a follow-up command (missing args, confirmation, scope choice). Payload includes status, reason, message, and next[] with suggested commands.error — Unrecoverable or invalid input. Payload includes status, reason, message, and optional next[].Implementations use outputActionRequired / outputAgentError (packages/cli/src/util/agent-output.ts): they write a single JSON object to stdout and process.exit(exitCode) when client.nonInteractive is true. Agents should parse the first JSON object on stdout to get status, reason, and next[].
buildCommandWithYes(client.argv) for confirmation flows: the next[].command is the exact command the user ran, with --yes added or retained. The agent can copy-paste it as-is.vercel redirects add <source> <destination> --yes so the agent only substitutes <source> and <destination> and preserves global flags if you append them.<slug>, <name>, <source>, <destination>, <file>, <version-id>, <email>, <description>, etc.... as placeholders in next[].command.vercel routes add --ai <description> --yes — the agent replaces <description> with the actual text (and quotes it if it contains spaces).getCommandNamePlain() for anything serialized into JSON (next[].command, message examples). Do not use getCommandName() or param() / chalk in JSON paths—agents parse stdout and ANSI breaks parsing.next[] commands (implementers)--cwd, --scope, --token, --non-interactive, etc.) should be appended to every suggested command when the agent is expected to run from the same context. That way the suggested command works when run from the same directory/config.getGlobalFlagsOnlyFromArgs(client.argv.slice(2)) (arg-common.ts) collects only global flags so cross-subcommand suggestions (e.g. redirects add → redirects promote, teams invite → teams switch) do not forward flags that would parse-error on the target subcommand.teams add still missing --name) should preserve subcommand-specific flags via getSameSubcommandSuggestionFlags() (args after the subcommand, minus positionals) so the user does not retype --slug, --status, etc.getCommandNamePlain(\${template} ${flags.join(' ')}`.trim())` after collecting flags.missing_arguments before other errors that depend on config state (e.g. stale currentTeam). Otherwise agents see the wrong reason (e.g. current_team_invalid instead of missing slug).process.exit to throw and capture stdout (or the function that writes the payload); parse JSON from the first JSON object on stdout.outputActionRequired / outputAgentError (stdout contains the payload).next (implementers)teams switch <slug> not switch <team>) so copy-paste works regardless of alias.--yes instead of prompting. In next[], suggest the exact command to re-run with --yes using buildCommandWithYes(client.argv) so the agent (or user) can copy-paste it without substituting anything.outputAgentError with a stable reason (e.g. payment_required, rate_limited, slug_unavailable, timeout, domain_not_found, confirmation_required) and a plain message—never chalk/param() in JSON (agents parse stdout).teams add non-interactive path: create-team and patch-team catches should emit JSON instead of only output.error, so agents get parseable stdout.next entry whose command is a shell one-liner to open the URL (open / start / xdg-open by platform) so the user or agent can run it locally.bailOn429: For flows that would otherwise sleep/retry on 429 (e.g. PATCH after create), use bailOn429: true on the fetch or fail fast so the CLI does not spin indefinitely.| Area | Notes |
|---|---|
packages/cli/src/util/agent-output.ts | outputActionRequired, outputAgentError, buildCommandWithYes, enrichActionRequiredWithInvokingCommand |
packages/cli/src/util/arg-common.ts | globalCommandOptions; add getGlobalFlagsOnlyFromArgs / getSameSubcommandSuggestionFlags when missing so next[] can preserve context safely |
packages/cli/src/util/pkg-name.ts | getCommandNamePlain, packageName |