Skip to content

Add --json output mode to every func subcommand, including errors #3769

@lkingland

Description

@lkingland

Summary

Every func subcommand should support a --json flag that emits structured output suitable for machine consumption. Errors must also be returned as JSON when --json is set, not as human-formatted strings.

Motivation

Today the only structured signal callers (MCP server, scripts, IDEs, CI, future Console plugin) can extract from func is the exit code plus stdout/stderr text. This forces every consumer to either substring-match output (brittle — see #3753 for a worked example of why this fails) or invent its own taxonomy by guessing at func's intent. The result is a contract that's secretly the consumer's job to maintain, even though the producer (func) is the only code that actually knows what happened.

Putting structured output behind a --json flag fixes this for every consumer at once. Same pattern as kubectl -o json, gh --json, aws --output json — users already expect it from modern CLIs.

Scope

  • Every existing func subcommand accepts --json.
  • On success: command-specific structured payload (e.g., func list --json returns the function list; func describe --json returns the deployed-function spec; func deploy --json returns the resulting service URL/image/etc).
  • On failure: a structured error object (this is the part most consumers actually need), with at minimum:
    • category (e.g. REGISTRY_ERROR, CLUSTER_ERROR, BUILD_ERROR, VALIDATION_ERROR, AUTH_ERROR, READONLY_ERROR, TIMEOUT_ERROR, UNKNOWN_ERROR)
    • code (stable string identifier; finer-grained than category)
    • retryable / transient boolean
    • message (human-readable summary)
    • hint (suggested remediation)
    • context (resource name, namespace, registry, etc. — whatever's relevant to the failure)
  • Default output (no flag) stays exactly as it is. --json is opt-in.

Open design questions (decide before implementing)

  1. Envelope shape. Suggested: {"status": "ok"|"error", "data": ..., "error": {...}} so callers can dispatch with one key.
  2. Stream choice. All JSON to stdout (recommended — status carries success/failure, no need to merge streams) vs error JSON to stderr.
  3. Streaming commands (func logs, func deploy --verbose): pick NDJSON (one event per line) or explicitly mark --json unsupported for these. "Explicit and unsupported" beats "clever and surprising."
  4. Schema versioning. Either an apiVersion field in the envelope, or document that v1 evolves additively only and breaking changes require --json=v2. Pin early.
  5. Internal refactor. Errors emitted from underlying code paths need to carry enough context to be rendered as JSON. Typed errors at the failure site, translated at the CLI boundary.

Related

Non-goals

  • Localization of error messages (separate concern).
  • Replacing the existing human-readable output (this is additive).

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions