Products › lamboot-tools › CLI Contract
CLI Contract
Universal flags, exit codes, and the JSON envelope that every tool shares.
One shape, all tools
Every command in lamboot-tools 0.9.1 follows one structure. Learn one tool and you can predict the rest.
<tool> [GLOBAL FLAGS] SUBCOMMAND [SUBCOMMAND FLAGS] [POSITIONAL ARGS]
Global flags come before the subcommand; subcommand-specific flags come after. The -- separator is honored for positional arguments that resemble flags. Short aliases exist only for the four highest-frequency flags: -h, -v, -q, -y.
Flags that behave identically across all tools
| Flag | Behavior |
|---|---|
| --help, -h | Show terse help with an after-help summary of subcommands. |
| --version | Print <tool> <version> (lamboot-tools <toolkit-version>). |
| --json | Emit the unified JSON envelope (schema v1). All human output goes to stderr; color codes suppressed on stdout. |
| --json-schema | Print the JSON Schema (draft 2020-12) this tool emits. Safe to pipe through jq. |
| --verbose, -v | Informational output beyond the defaults. |
| --quiet, -q | Warnings and errors only. Silent on info. |
| --no-color | Disable ANSI color. Auto-disabled on non-TTY stdout, when NO_COLOR is set, or when TERM=dumb. |
| --dry-run | Print planned actions and make no changes. Available on every mutating tool. |
| --yes, -y | Answer yes to interactive confirmations. |
| --force | Skip safety checks. Per-tool semantics are documented in each tool's help. |
| --auto | Non-interactive automation. Implies --yes. |
| --offline DISK | Operate on an unmounted disk or image. Supported by every tool except lamboot-migrate. |
| --suggest-next-command | Print the recommended follow-up command based on the output. |
Root and color notes
-
Read operations and informational paths (
--help,--version,--json-schema) run unprivileged. - Mutating operations require root and refuse with exit code 7 when run without it.
-
Tools never self-escalate.
--offline DISKalways requires root. -
Color is enabled on TTY stdout by default.
--no-colorstrips ANSI codes from output only; textual content is byte-for-byte identical.
Eight exit codes, shared by every shell tool
lamboot-toolkit dispatcher share one exit-code contract. The two bundled Rust binaries (lamboot-capcheck, lamboot-reader) use their own 0 through 3 contract.| Code | Constant | Meaning | Use in automation |
|---|---|---|---|
| 0 | EXIT_OK | Success. All requested operations completed. | Continue the pipeline. |
| 1 | EXIT_ERROR | Fatal error. Some state may have changed; see output. | Log and alert. |
| 2 | EXIT_PARTIAL | Mixed success. Some operations succeeded; some failed. | Log and re-run idempotent subcommands. |
| 3 | EXIT_NOOP | Nothing to do. System already in the requested state. | Idempotent-OK. Do not log as a failure. |
| 4 | EXIT_UNSAFE | Refused due to a safety check. No state changed. | Inspect output, then override or fix. |
| 5 | EXIT_ABORT | User declined an interactive confirmation. No state changed. | Expected when the user aborts. |
| 6 | EXIT_NOT_APPLICABLE | Operation does not apply to this system. | Skip silently. Not a failure. |
| 7 | EXIT_PREREQUISITE | Required tool or capability is missing. | Install the missing thing and retry. |
Key insight: warnings alone do not fail. A diagnostic tool that emits only info and warning findings exits 0. A finding at severity error or critical exits 2.
Read-only vs. mutation: read-only runs report what was found (healthy exits 0, issues found exits 2). Mutation runs report what was done (all applied exits 0, some failed exits 2, refused exits 4).
sudo lamboot-migrate to-uefi
rc=$?
case $rc in
0) echo "Migration complete" ;;
3) echo "Already UEFI; nothing to do" ;;
4) echo "Refused by a safety check. Inspect output and fix." ;;
5) echo "Aborted by user" ;;
*) echo "Migration failed with exit $rc" >&2; exit $rc ;;
esac
The stable schema v1 envelope
--json, every tool emits the same top-level envelope. Additive changes do not bump schema_version; breaking changes bump it and the toolkit major version in lockstep. Pin on schema_version == "v1".{
"schema_version": "v1",
"tool": "lamboot-diagnose",
"version": "0.9.1",
"toolkit_version": "0.9.1",
"timestamp": "2026-06-23T14:37:22Z",
"host": "laptop-01",
"run_id": "2026-06-23T14-37-22-a1b2c3",
"command": "lamboot-diagnose --json",
"dry_run": false,
"exit_code": 0,
"summary": {
"status": "warn",
"findings_total": 24,
"findings_by_severity": {"critical": 0, "error": 0, "warning": 1, "info": 23}
},
"findings": [ /* one object per observation */ ],
"actions_taken": [ /* one object per mutation; empty for read-only tools */ ],
"backup_dir": null
}
Top-level fields
| Field | Type | Description |
|---|---|---|
| schema_version | string | Always "v1" in this toolkit major version. |
| tool | string | Executable name, e.g. lamboot-diagnose. |
| version | string | Per-tool semver. Each tool versions independently. |
| toolkit_version | string | The lamboot-tools release bundling this tool. |
| timestamp | string | ISO-8601 UTC with a Z suffix. No local time, no fractional seconds. |
| run_id | string | Unique within a host across time. Correlates log lines, backup directories, and JSON from one invocation. |
| command | string | Exact argv joined by single spaces. Passwords redacted to ***. |
| dry_run | boolean | true if --dry-run was passed. |
| exit_code | integer | The code the process will return. Set at emit time, always accurate. |
| summary | object | Aggregate counts and an overall verdict. |
| findings | array | Observations. One object per finding. |
| actions_taken | array | Mutations performed. Empty for read-only tools. |
| backup_dir | string or null | Path to the backup directory when one was created. |
summary.status values
| Value | Meaning |
|---|---|
| pass | No issues. |
| warn | Only warning-severity findings. |
| fail | Critical or error-severity findings present. |
| noop | Nothing to do. |
| error | The tool itself hit an error. |
| unsafe | Refused by a safety check. |
| abort | User declined a confirmation. |
findings[] entry
{
"id": "esp.free_space",
"category": "esp",
"severity": "warning",
"status": "warn",
"title": "ESP is 89% full",
"message": "ESP at /boot/efi has 54 MB free of 512 MB (10.1% free)",
"context": {
"esp_mount": "/boot/efi",
"free_bytes": 56623104,
"total_bytes": 536870912,
"percent_free": 10.1
},
"remediation": {
"summary": "Remove stale kernel images to free space",
"command": "sudo lamboot-esp clean --dry-run",
"doc_url": "https://github.com/lamco-admin/lamboot-tools"
}
}
Finding IDs are dotted-path stable identifiers of the form <category>.<specific>[.<subspecific>], for example esp.free_space, bootloader.grub.pe_format, vm.lamboot_state. IDs are semver-stable within the toolkit major version: adding new IDs is additive, renaming an existing ID is a major-version event.
severity answers "how bad is this if unaddressed?" (critical, error, warning, info). status answers "what did this check report?" (pass, warn, fail, skip). The two fields are orthogonal.
actions_taken[] entry (mutation tools only)
{
"action": "partition.create",
"target": "/dev/sda2",
"result": "ok",
"reversible": true,
"backup_ref": "/var/backups/lamboot-migrate-2026-06-23T14-37-22-a1b2c3/",
"dry_run": false,
"details": {
"partition_number": 2,
"size_mb": 512,
"typecode": "EF00"
}
}
Four properties that always hold
Valid JSON on stdout
Every tool's --json output passes jq -e . on stdout, regardless of exit code.
Valid JSON Schema
Every tool's --json-schema output is a valid JSON Schema (draft 2020-12) describing the envelope and that tool's context shape.
No log lines on stdout
No log lines go to stdout when --json is active. All human output goes to stderr.
No color codes on stdout
ANSI color codes are suppressed on stdout when --json is active.
# Extract remediation commands for all warning-or-above findings
lamboot-diagnose --json | \
jq -r '.findings[] | select(.severity != "info") | .remediation.command'
# Fail if any warning-or-above finding is present
count=$(lamboot-diagnose --json | jq '[.findings[] | select(.severity != "info")] | length')
if [[ "$count" -gt 0 ]]; then exit 1; fi