CLI for AI agents
The plm CLI is designed for AI agents as a first-class user. Every command has stable JSON output, predictable exit codes, and idempotent semantics. This page covers the patterns that make agent-written automation reliable.
Discovery
Three discovery surfaces, in increasing detail:
/llms.txt— a curated index of every docs page, one bullet per page. Good for “what is this product?”/llms-full.txt— the entire docs corpus concatenated in markdown. Stream once at the start of a session and you have everything.- Per-page markdown — every
/docs/<slug>/has a.mdalternate at/docs/<slug>.mdand a<link rel="alternate" type="text/markdown">in the<head>.
For per-command machine-readable structure, each CLI reference page has an <details>Agent-readable summary</details> block containing JSON with arguments, options, defaults, and subcommands.
plm <noun> --help works too, but tends to be terser than the docs.
Output
plm parts list --format json--format json is the agent default. Schemas are stable per command and versioned in the per-command reference page. --format table and --format yaml are also supported.
Exit codes
| Code | Meaning |
|---|---|
0 | Success. |
1 | User error (bad flag, validation failure, missing argument). |
2 | Network or auth failure. The credential at ~/.config/plm/credentials may need refresh — try plm login again. |
3 | Conflict — a write-time collision in plm-data/. Retry after pulling the latest state. |
Agents should distinguish exit 1 (don’t retry, fix the call) from 2/3 (transient, retry with backoff).
Idempotency
Writes are addressed by deterministic IDs (part numbers, BOM revision hashes, ECO IDs). Re-running the same plm parts create --file foo.yaml is a no-op if the existing part already matches the input bit-for-bit. If it differs, you get exit 3 unless you pass --update.
This means an agent can safely retry a failed write without worrying about creating duplicates.
Authentication for headless agents
For non-interactive contexts (CI, scheduled tasks, agent runners):
plm login --token <PAT>PATs are generated in the dashboard at Settings → API tokens. Set the PLM_TOKEN env var to pre-populate, then plm login --token "$PLM_TOKEN". Tokens are scoped to one org by default; pass --org at command time to operate on others if your PAT has cross-org permission.
Where the data lives
plm-data/ in a Git repo, one repo per org. Branch + commit semantics are standard Git. Agents that want raw read access can clone the org’s plm-data repo directly — the CLI exists for write paths and for surface area that’s expensive to reimplement (validation, indexes, ECO state).
A sample agent loop
import subprocess, json
# 1) Discover the surface.corpus = subprocess.check_output(["curl", "-fsSL", "https://simple-plm.com/llms-full.txt"]).decode()
# 2) Read a per-command JSON summary from the reference page.ref = subprocess.check_output(["curl", "-fsSL", "https://simple-plm.com/docs/cli/parts.md"]).decode()
# 3) Execute. JSON output, retry on exit 2/3.def call(args, retries=3): for _ in range(retries): r = subprocess.run(["plm", *args, "--format", "json"], capture_output=True, text=True) if r.returncode == 0: return json.loads(r.stdout) if r.returncode in (2, 3): continue raise RuntimeError(f"plm {args} → exit {r.returncode}: {r.stderr}") raise RuntimeError("retries exhausted")
print(call(["parts", "list"]))