Skip to content

Latest commit

 

History

History
418 lines (325 loc) · 14.1 KB

File metadata and controls

418 lines (325 loc) · 14.1 KB

platecli API Reference

The plate command provides structured JSON output for programmatic integration (AI agents, scripts, CI). This document is the human contract; machine-checkable schemas live in docs/schemas/.

Enabling JSON output

Pass the --json global flag to any command to receive machine-readable JSON on standard output (stdout). Log messages and warnings go to standard error (stderr), so you can safely pipe stdout to jq or an agent context window.

--json may appear before or after the subcommand:

plate status --json
plate --json --version
# or without installing:
python3 scripts/bambu.py status --json

Standard envelopes

Success

{
  "status": "ok",
  "command": "<command>"
}

Some commands use a more specific status string ("sliced", "downloaded", "saved", "sent", "confirmation_required", …). Schema files document the allowed values per command.

Error

Shared shape: schemas/error_envelope.json.

{
  "status": "error",
  "command": "slice",
  "error": "Timeout waiting for OrcaSlicer to finish.",
  "exit_code": 6,
  "failed_step": "slicer"
}

Job failures may use the superset schemas/job_error.json (includes summary fields such as would_slice, remote_name, printed, next_command, recovery_hint).

Path fields under the current home directory are compacted to ~ in agent JSON.

Exit codes

Stable for a given major version (bambu_cli.constants):

Code Constant Meaning
0 EXIT_SUCCESS Success
1 EXIT_CONFIG_ERROR Missing/invalid config or required tool
2 EXIT_NETWORK_ERROR Connectivity / MQTT / FTPS failure
3 EXIT_FILE_ERROR Local file I/O
4 EXIT_PRINTER_ERROR Printer reported error
5 EXIT_COMMAND_ERROR Invalid usage / command refused
6 EXIT_TIMEOUT Operation timed out

Refusal contract: every command that causes physical printer motion or destroys printer-side data — print, stop, pause, resume, gcode, delete — refuses without --confirm, exits 5, and (with --json) emits "status": "confirmation_required" plus a next_command array. job / send without --confirm is not a refusal: the download/slice/upload really happened, so it exits 0 with "status": "uploaded_not_printed".

Domain code raises BambuError / abort(); only cli.main() calls sys.exit.

When a print fails with a printer-reported code, the error envelope carries both printer_error_code (decimal, as the printer sends it) and printer_error_code_hex (e.g. "0x0500C010"). Bambu documents HMS/print error codes in hex, so use the hex form when looking a code up; the human-readable log line shows both.

Schema inventory

Schema file Covers
ok_envelope.json Generic success envelope
error_envelope.json Generic error envelope
version.json --json --version
status.json status --json snapshot
status_event.json status --monitor --json NDJSON events
doctor.json doctor
preflight.json preflight
config_cmd.json config show / config validate
download.json download success
slice.json slice success
slice_list_settings.json slice --list-settings
job_ok.json job / send success / dry-run
job_error.json job / send failure
print.json print (incl. confirmation_required)
gcode.json gcode
delete.json delete
light.json light
pause.json pause
resume.json resume
stop.json stop (incl. confirmation_required)
snapshot.json snapshot
upload.json upload success / --dry-run
files.json files listing
setup.json setup summary
go.json go error envelope (--json always errors)

Every --json-emitting subcommand now has a dedicated schema. That is enforced, not asserted: tests/contracts/test_schema_validation.py derives the subcommand list from build_parser() and fails if any command lacks a schema, if a schema's $id does not match its filename, if a schema file is unreferenced, or if this table omits one. Payloads are validated against the published files, mostly from real --sim invocations rather than hand-written fixtures.

Contract tests: tests/contracts/test_schema_validation.py and tests/test_json_contracts.py.

Command payloads

version

{"status": "ok", "command": "version", "version": "X.Y.Z"}

version is the installed platecli release (the same string plate --version prints); it is not a fixed value and is deliberately shown as a placeholder here.

Schema: version.json.

status

One-shot query returns printer state, temperatures, and a normalized AMS block:

{
  "status": "ok",
  "command": "status",
  "printer": { "...raw printer map..." },
  "gcode_state": "IDLE",
  "mc_percent": 0,
  "ams": null
}

ams is either null (no AMS) or:

{
  "active_tray": 1,
  "units": [
    {
      "id": 0,
      "humidity": 4,
      "temp": 28.5,
      "trays": [
        {"slot": 0, "type": "PLA", "color": "F2F2F2", "remain": 80, "empty": false, "active": false}
      ]
    }
  ]
}

Top-level keys also mirror common fields from the raw printer map for convenience.

printer is always a complete state snapshot. The printer publishes incremental deltas on its MQTT report topic and answers pushall with the whole state, so status merges report messages and keeps waiting (re-requesting on each retry) until gcode_state, mc_percent, bed_temper, and nozzle_temper are all present. If the printer is too busy to answer with a full snapshot before the timeout, status fails with exit code 6 and "failed_step": "status" rather than emitting a partial printer object:

{
  "status": "error",
  "command": "status",
  "exit_code": 6,
  "error": "Printer returned only partial status updates, never a full snapshot (missing gcode_state, mc_percent). It may be busy mid-print; retry the command.",
  "failed_step": "status",
  "detail": {"missing_keys": ["gcode_state", "mc_percent"], "received_keys": ["nozzle_temper"]}
}

status --monitor (NDJSON)

Streams one JSON object per line until a terminal state. Schema: status_event.json.

{"event":"update","command":"status","gcode_state":"RUNNING","mc_percent":42}
{"event":"terminal","command":"status","gcode_state":"FINISH","mc_percent":100}

Use --sim to exercise the shape without a printer.

doctor

Runs connectivity checks and reports the live TLS certificate fingerprint. Schema: doctor.json. Serial and other secrets are redacted.

{
  "status": "ok",
  "command": "doctor",
  "ok": true,
  "output": "/tmp/printer_capabilities.json",
  "printer_ip": "<redacted>",
  "certificate_fingerprint": "0123456789abcdef...",
  "capabilities": { }
}

In interactive TTY (not --json), doctor may offer to write cert_fingerprint into config when none is pinned. That prompt never runs in JSON or non-TTY mode.

preflight

Local config/health checks without requiring a full live print path. Schema: preflight.json. Supports --strict.

slice

Success after OrcaSlicer produces a valid .gcode.3mf (schema: slice.json):

{
  "status": "sliced",
  "command": "slice",
  "file": "~/models/cube.stl",
  "path": "~/models/cube.gcode.3mf",
  "filename": "cube.gcode.3mf",
  "bytes": 4096,
  "step_converted": false
}

Errors use error_envelope.json. Missing profiles errors may include profiles_dir and detected_profiles_dir.

slice --list-settings [--json]: slice_list_settings.json.

Without --json, the listing is written to stdout — one [process]/[filament] key per line, unwrapped — so it can be piped or redirected. The header and the closing hint go to stderr like other human chrome, which keeps a redirect to a file free of anything but data:

plate slice --list-settings | grep layer_height
plate slice --list-settings > settings.txt

download

Schema: download.json.

{
  "status": "downloaded",
  "command": "download",
  "source": "https://example.com/model.stl",
  "normalized_source": null,
  "download_url": "https://example.com/model.stl",
  "path": "/tmp/model.stl",
  "filename": "model.stl",
  "bytes": 1024
}

Archive downloads may also include archive_entry. Errors redact source / download_url. Private IPs are refused unless --allow-private-ips.

config

config show and config validate share config_cmd.json (named config_cmd so the schema is not blocked by a config.json gitignore).

Show (secrets redacted):

{
  "status": "ok",
  "command": "config",
  "action": "show",
  "config_path": "~/.config/bambu/config.json",
  "config": {
    "printer_ip": "192.168.1.10",
    "access_code": "<redacted>"
  }
}

Validate includes checks[], ok, errors, warnings, exit_code, and strict.

job / send

send is an alias of job.
Success / dry-run: job_ok.json.
Failure: job_error.json.

Print start requires --confirm; without it the job may upload but will not print.

go

go is the interactive guided-print wizard and has no machine contract: it requires a TTY and drives real prompts. With --json it never runs the wizard — it emits the error envelope in go.json (exit_code 5, failed_step parse) and exits. Piped/non-TTY stdin is refused the same way. Agents should use job / send with --confirm instead.

gcode

Without --confirm (schema: gcode.json):

{
  "status": "confirmation_required",
  "command": "gcode",
  "gcode": "G28",
  "sent": false,
  "next_command": ["gcode", "G28", "--confirm", "--json"]
}

After send: "status": "sent", "sent": true.

print

Without --confirm (schema: print.json):

{
  "status": "confirmation_required",
  "command": "print",
  "file": "cube.gcode.3mf",
  "printed": false,
  "next_command": ["print", "cube.gcode.3mf", "--confirm", "--json"]
}

delete

Without --confirm (schema: delete.json): "status": "confirmation_required", "deleted": false.

stop

Requires --confirm (same intent pattern as delete/print). Schema: stop.json.

Without --confirm: "status": "confirmation_required", "stopped": false. With --confirm: "status": "stopped", "stopped": true.

light / pause / resume

  • light.json: "status": "light_changed", "action": "on"|"off", "changed": true
  • pause.json: dual success-or-confirmation envelope — "status": "paused" with "paused": true on success, or "status": "confirmation_required" with "paused": false plus next_command when --confirm is absent
  • resume.json: dual success-or-confirmation envelope — "status": "resumed" with "resumed": true on success, or "status": "confirmation_required" with "resumed": false plus next_command when --confirm is absent

pause and resume require --confirm (since 0.3.0). Without it they emit "status": "confirmation_required" with "paused": false / "resumed": false plus next_command, and exit 5. light does not require --confirm: it changes no motion, thermal, or material state. See SECURITY.md.

snapshot

Schema: snapshot.json"status": "saved", "output", "size_bytes", "captured_at" (ISO-8601 UTC), "sha256" (hex digest of JPEG bytes), plus method (direct) or Docker-related fields when the streamer path is used. Use --unique to get a timestamped filename so repeated captures never overwrite/confuse. Agents should compare sha256 / captured_at to verify a new frame was captured before sending the image to a user.

Global API flags

  • Timeouts (also optional config keys):
    • --network-timeout <seconds>
    • --slicer-timeout <seconds>
    • --command-timeout <seconds>
    • --upload-timeout <seconds>
  • Security & confinement:
    • --allow-private-ips: opt in to private/LAN model fetches (default deny). Not sticky config.
    • --max-download-mb: size cap for URL download and ZIP members (default 2048).
  • Simulation:
    • --sim: no real printer traffic for supported paths.

Stability policy (1.0 intent)

JSON fields documented here and validated under docs/schemas/ are part of the agent contract. Fields may be added in minor releases. Fields may be removed or renamed only after a deprecation window of at least one minor release (or a major version bump). Exit codes in bambu_cli.constants are stable for a given major version.

Config keys: prefer additive changes; deprecate with a warning (as with inline access_code) before removal.

Machine-checkable schemas live in docs/schemas/. Contract tests under tests/contracts/ load those schemas against live CLI output.

Related docs