{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://github.com/jenkinpan/cargo-fresh/blob/master/docs/json-schema.json",
"title": "cargo-fresh JSON report",
"description": "Schema for the single JSON object emitted to stdout when cargo-fresh runs with --format=json. Stability: schema_version=2 is the current contract. schema_version bumps on rename/remove (1→2 in 0.12.0 renamed updates_available[].binstall → prebuilt); additive within a major. Status lines, prompts, and progress all go to stderr; stdout contains exactly one JSON object per invocation.",
"type": "object",
"required": [
"schema_version",
"format",
"version",
"include_prerelease",
"dry_run",
"registry_url",
"updates_available",
"fresh",
"skipped",
"version_check_errors",
"results",
"summary",
"aborted"
],
"properties": {
"schema_version": {
"type": "integer",
"const": 2,
"description": "Schema major version. Bumps on rename/remove; additive within a major."
},
"format": {
"type": "string",
"const": "cargo-fresh-v1",
"description": "Format discriminator. Lets downstream scripts pin a known shape without parsing semver. Note: this is the wire-format family, versioned independently of `schema_version` (the field-level schema major) — `cargo-fresh-v1` and `schema_version=2` coexisting is expected, they version different things."
},
"version": {
"type": "string",
"description": "The cargo-fresh release that produced this report (its crate version, e.g. \"0.12.5\"). Self-describing for archived JSON and bug reports; not a stability discriminator — branch on `schema_version`/`format`, not this."
},
"include_prerelease": {
"type": "boolean",
"description": "Whether --include-prerelease was active for this run."
},
"dry_run": {
"type": "boolean",
"description": "Whether --dry-run was active. If true, `results` reflects what would have happened, not what did."
},
"registry_url": {
"type": ["string", "null"],
"description": "Resolved sparse-index base URL used for the run, or null when the default (https://index.crates.io) was used."
},
"updates_available": {
"type": "array",
"description": "Every package with at least one update candidate found, regardless of whether it was selected for install.",
"items": { "$ref": "#/$defs/updateCandidate" }
},
"fresh": {
"type": "array",
"description": "Names of packages already at their latest applicable version.",
"items": { "type": "string" }
},
"skipped": {
"type": "array",
"description": "Packages whose version check was skipped (non-crates source or unknown registry).",
"items": { "$ref": "#/$defs/skipped" }
},
"version_check_errors": {
"type": "array",
"description": "crates.io packages whose latest-version lookup failed; fresh[] excludes these so an empty updates list can be trusted.",
"items": { "$ref": "#/$defs/checkError" }
},
"results": {
"type": "array",
"description": "Outcomes of actual `cargo install` invocations. Empty when no updates were applied (e.g. dry-run still records each attempt; --no-interactive with no selection yields an empty array).",
"items": { "$ref": "#/$defs/result" }
},
"summary": { "$ref": "#/$defs/summary" },
"aborted": {
"type": "boolean",
"description": "True when the run was interrupted (Ctrl-C / SIGINT). Combine with exit code 130 to detect partial runs."
}
},
"$defs": {
"updateCandidate": {
"type": "object",
"required": ["name", "current", "latest", "source", "prerelease", "prebuilt"],
"properties": {
"name": { "type": "string" },
"current": {
"type": ["string", "null"],
"description": "Installed version, or null if `cargo install --list` did not report one."
},
"latest": {
"type": "string",
"description": "Latest applicable version (respects --include-prerelease)."
},
"source": { "$ref": "#/$defs/sourceKind" },
"prerelease": {
"type": "boolean",
"description": "True when `latest` is a SemVer prerelease (only possible with --include-prerelease)."
},
"prebuilt": {
"type": ["string", "null"],
"enum": ["prebuilt", "source", "unknown", null],
"description": "Downloader prebuilt-binary availability, populated only when --check-prebuilt was used: 'prebuilt' = downloader would fetch a prebuilt binary (fast), 'source' = downloader would fall back to compiling from source (slow), 'unknown' = probe could not reach a verdict (network errors / 5xx / timeout). null when --check-prebuilt was not passed."
}
}
},
"skipped": {
"type": "object",
"required": ["name", "source", "reason_code", "reason"],
"properties": {
"name": { "type": "string" },
"source": { "$ref": "#/$defs/sourceKind" },
"reason_code": {
"type": "string",
"enum": ["path_source", "git_source", "unknown_source"],
"description": "Stable machine-readable skip reason. Branch on this, not on `reason`."
},
"reason": {
"type": "string",
"description": "Human-readable skip reason; stable enough to log, not to branch on — use reason_code instead."
}
}
},
"result": {
"type": "object",
"required": ["name", "old_version", "new_version", "success", "install_method"],
"properties": {
"name": { "type": "string" },
"old_version": { "type": ["string", "null"] },
"new_version": {
"type": ["string", "null"],
"description": "Version observed after the install attempt. May equal `old_version` if the update ran but the binary didn't actually change."
},
"success": { "type": "boolean" },
"install_method": {
"type": ["string", "null"],
"enum": ["prebuilt", "source", null],
"description": "Which install path actually ran: 'prebuilt' = the self-hosted downloader fetched a prebuilt GitHub Release binary, 'source' = fell back to `cargo install` (compiled from source). null when the install did not complete (failure / Ctrl-C abort). Shares the 'prebuilt'/'source' vocabulary with updates_available[].prebuilt so scripts can compare the --check-prebuilt prediction against the actual outcome."
}
}
},
"checkError": {
"type": "object",
"required": ["name", "kind", "error"],
"properties": {
"name": { "type": "string" },
"kind": {
"type": "string",
"enum": ["not_found", "unavailable"],
"description": "not_found = absent from the registry index (permanent: renamed crate or misconfigured registry); unavailable = network/timeout/5xx/parse (transient: a retried run may succeed)."
},
"error": { "type": "string", "description": "Human-readable message; not stable, do not branch on it." }
}
},
"summary": {
"type": "object",
"required": ["checked", "available", "succeeded", "failed", "skipped", "selected", "attempted", "check_errors", "duration_ms"],
"properties": {
"checked": { "type": "integer", "minimum": 0, "description": "Total packages discovered (counts every discovered package, including skipped and check-errored ones)." },
"available": { "type": "integer", "minimum": 0 },
"succeeded": { "type": "integer", "minimum": 0 },
"failed": { "type": "integer", "minimum": 0 },
"skipped": { "type": "integer", "minimum": 0 },
"selected": { "type": "integer", "minimum": 0, "description": "Packages chosen for update this run. When --format=json is used without --batch, selection is skipped (equivalent to --no-interactive), so this is always 0 in that mode." },
"attempted": { "type": "integer", "minimum": 0, "description": "Packages an install command was actually run for (equals succeeded + failed)." },
"check_errors": { "type": "integer", "minimum": 0, "description": "Number of crates.io packages whose version lookup failed this run. Equals the length of version_check_errors[]; convenient to read without iterating the array." },
"duration_ms": {
"type": "integer",
"minimum": 0,
"description": "Total wall-clock time from start of run to JSON emission."
}
}
},
"sourceKind": {
"type": "string",
"enum": ["crates", "git", "path", "unknown"],
"description": "Short tag derived from PackageSource. `crates` = crates.io / mirror, `git` = git+URL[#rev], `path` = local path, `unknown` = a registry cargo-fresh doesn't speak."
}
}
}