lr-gladiator
CLI + Python client for interacting with the Arena PLM.
Install
pip install lr-gladiator
Quick start
Login
Interactive login (prompts for username/password):
gladiator login
Non-interactive (for CI/CD):
export GLADIATOR_USERNAME="<insert username>"
export GLADIATOR_PASSWORD="<insert password>"
gladiator login --ci
By default, this stores session details at:
~/.config/gladiator/login.json
Commands
Get the latest approved revision for an item:
gladiator latest-approved 890-1001
Search for items by number pattern:
gladiator list-items 104*
Output JSON instead of a table:
gladiator list-items 104* --output json
Search for items by free text (matches Item Name and Description):
gladiator search-item "wireless module"
Output JSON instead of a table:
gladiator search-item "wireless module" --output json
List all files on an item (defaults to the latest approved revision):
gladiator list-files 890-1001
Output JSON instead of a table:
gladiator list-files 890-1001 --output json
Display a quick summary for an item revision (number, name, description, category, lifecycle, etc.):
gladiator info 890-1001
Emit machine-readable JSON instead of the Rich table:
gladiator info 890-1001 --output json
The summary includes the Arena web URL (Item URL) so you can click straight into the item from the terminal output.
Download the item's thumbnail (saved as <item>.png/.jpg) while fetching the summary:
gladiator info 890-1001 --picture --rev WORKING
Write metadata to an item's WORKING revision. --version sets the revision
number, which for software items carries the release version — this is what a
CI job stamps on a release candidate so the bundle can be downloaded and
verified before the ECO is approved:
gladiator set-meta 504-1001 --version 0.43.2 --description "CLI + Python client for Arena PLM"
Only the WORKING revision is writable; an approved revision is released
history. Attributes left unset keep their current value, and a run requesting
values Arena already holds makes no request at all, so re-running is free.
Preview first with --dry-run:
gladiator set-meta 504-1001 --version 0.44.0 --dry-run
Clearing an attribute is not supported: an empty value is rejected rather than
written, because clearing needs Arena's setnull. Clear one from the Arena UI.
List the Bill of Materials (BOM) for an item:
gladiator get-bom 890-1001
Recursively expand subassemblies up to two levels deep:
gladiator get-bom 890-1001 --recursive --max-depth 2
Add or update a BOM line on the working revision:
gladiator add-to-bom 890-1001 510-0005 --qty 2 --refdes R1
Target a different revision or inspect the raw API response:
gladiator add-to-bom 890-1001 510-0005 --parent-rev EFFECTIVE --output json
Download attached files to a directory named after the article:
gladiator get-files 890-1001
Specify a different output directory:
gladiator get-files 890-1001 --out downloads/
Recursively download all files in the full BOM tree:
gladiator get-files 890-1001 --recursive
--rev names the revision of the item on the command line. A selector —
EFFECTIVE, WORKING, or no --rev at all — is meaningful for every item, so
it applies to the whole tree. A revision label such as A3 exists only on the
item that carries it, so each sub-assembly is instead downloaded at the
revision its parent's BOM line pins (EFFECTIVE for a line that pins none):
gladiator get-files 890-1001 --recursive --rev A3
--rev WORKING walks the tree at each item's working revision, falling back to
its effective revision for an item with no change in progress. A revision label
that no item carries is still an error, reported against the item you named.
--max-depth stops the walk at a given depth. Rich output warns on stderr and
--output json reports depth_limited: the number of items reached at the
limit, whose children were not visited. Treat a non-zero value as "may be
incomplete" rather than as a truncation count — whether those items have
children is not checked, since that costs a request each. Zero means the tree
is complete.
Also write a .arena.json metadata file (item info + file list) into the
output directory. The file is idempotent for a given revision, so it is safe to
commit and diff:
gladiator get-files 890-1001 --meta-data
Combined with --recursive, a .arena.json is written into every item's
directory across the BOM tree:
gladiator get-files 890-1001 --recursive --meta-data
By default, a file whose local copy is proven byte-identical to the Arena
file is skipped rather than re-downloaded. The proof is content-based: files
uploaded by this tool carry sha256(content)[:16] as their edition, so a
16-lowercase-hex edition is a content fingerprint; the local file's size is
checked against the live size first, and only a match is then hashed and
compared. A file whose edition is not a 16-hex content hash (Arena-UI
uploads, web links, manual labels like A or 1) is always re-downloaded.
Use --no-cache to force a full download:
gladiator get-files 890-1001 --no-cache
--trust-metadata additionally skips a file whose edition is not a content
hash when an existing .arena.json sidecar records the same edition for that
filename and the local size matches the live size. This trusts metadata
rather than content, which is why it is opt-in and requires --cache
(passing it with --no-cache prints a warning and is ignored). Its
documented weakness: a local file matching the recorded edition and size but
not the actual content stays stale.
gladiator get-files 890-1001 --trust-metadata
In every case — --cache, --no-cache, or --trust-metadata — the bytes
written to disk, including .arena.json, are identical; only the reported
counts and the HTTP requests issued differ. --output json reports
downloaded and cached counts alongside count, files, and metadata
(and depth_limited with --recursive).
Upload or update a file on the working revision:
gladiator upload-file 890-1001 ./datasheet.pdf --category "CAD Data" --title "Datasheet"
Preview what would happen without writing anything:
gladiator upload-file 890-1001 ./datasheet.pdf --dry-run
The dry run resolves and validates --category, so a clean dry run guarantees
a real run will not reject the category after the existing attachment has been
removed.
Inspect a change and see which views are affected (columns show * when the view is included in the change):
gladiator get-change CCO-0006
Show the raw change payload instead of the Rich table:
gladiator get-change CCO-0006 --output json
Add an item (WORKING revision by default) to an existing change:
gladiator add-to-change --change CCO-0003 510-0001
Create a new change order (effectivity and deadline flags optional):
gladiator create-change --title "Fan bracket update" --description "Replace bracket" --category "Engineering Change Order"
The command prints a summary table with the newly assigned change number. Use --output json to inspect the raw response payload.
Install the LLM skill
Install the bundled skill for Claude Code and GitHub Copilot (run from your project root):
gladiator install-skill
This installs to:
~/.claude/skills/lr-gladiator/— Claude Code.github/instructions/lr-gladiator.instructions.md— GitHub Copilot.vscode/settings.json— enables Copilot instruction files
Print the skill to stdout (pipe to any LLM):
gladiator install-skill --show
Output control
Most commands support a JSON output mode. Example:
gladiator get-bom 890-1001 --output json
Example sessions
Human-readable
$ gladiator list-files 101-1031
Files for 101-1031 rev (latest approved)
┏━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━┓
┃ Name ┃ Size ┃ Edition ┃ Category ┃ Type ┃ Location ┃
┡━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━┩
│ 101-1907 E.PDF │ 171396 │ 1 │ Firmware │ FILE │ │
└─────────────────┴──────────┴─────────┴──────────┴──────┴──────────┘
JSON output
$ gladiator list-files 101-1031 --output json
{
"article": "101-1031",
"revision": null,
"files": [
{
"id": "00000000000000000000",
"fileGuid": "11111111111111111111",
"name": "101-1907 E.PDF",
"filename": "101-1907 E.PDF",
"size": 171396,
"haveContent": true,
"downloadUrl": "https://api.arenasolutions.com/v1/files/11111111111111111111/content",
"edition": "1",
"updatedAt": "2016-12-06T12:31:33Z",
"attachmentGroupGuid": "22222222222222222222",
"storageMethodName": "FILE",
"location": null,
"category": "Firmware"
}
]
}
Change inspections use a tabular view that highlights impacted areas. Example output for gladiator get-change CCO-0006:
Affected items for CCO-0006
┏━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━━┳━━━━━━┓
┃ Item Number ┃ Affected Rev ┃ New Rev ┃ Disposition ┃ Notes ┃ BOM ┃ Specs ┃ Files ┃ Source ┃ Cost ┃
┡━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━━╇━━━━━━┩
│ 510-0001 │ A │ B │ In Stock: Use │ Review │ * │ │ * │ │ * │
└─────────────┴──────────────┴─────────┴───────────────┴────────┴─────┴───────┴───────┴────────┴──────┘
Programmatic use
Using an existing session
from gladiator import ArenaClient, load_config
client = ArenaClient(load_config())
rev = client.get_latest_approved_revision("890-1001")
files = client.list_files("890-1001", rev)
Programmatic login
Option 1: Direct function call (recommended)
from gladiator import ArenaClient, load_config, arena_login
# Authenticate and save config to current working directory as login.json
arena_login(
username="username@company.com",
password="password",
)
# Now use the client
client = ArenaClient(load_config())
Option 1b: Save to custom path
from pathlib import Path
from gladiator import ArenaClient, load_config, arena_login
# Save config to a specific location
arena_login(
username="username@company.com",
password="password",
config_path=Path.home() / ".config/gladiator/login.json",
)
# Now use the client
client = ArenaClient(load_config())
Option 2: Login without saving to disk
from gladiator import ArenaClient, arena_login
# Authenticate but don't save
config = arena_login(
username="username@company.com",
password="password",
save_to_disk=False,
)
# Use the config directly
client = ArenaClient(config)
Option 3: Using environment variables with CLI
import subprocess
import os
# Set credentials
os.environ["GLADIATOR_USERNAME"] = "username@company.com"
os.environ["GLADIATOR_PASSWORD"] = "password"
# Run login command
subprocess.run(["gladiator", "login", "--ci"], check=True)
# Now use the client
from gladiator import ArenaClient, load_config
client = ArenaClient(load_config())
FAQ
-
Where is the config kept?
- CLI:
~/.config/gladiator/login.json(override withGLADIATOR_CONFIG) - Programmatic
arena_login(): Saves to~/.config/gladiator/login.jsonby default, or custom path viaconfig_pathparameter
- CLI:
-
How do I run non-interactively? Make sure to give all required arguments. Also pass
--cito stop output of sensitive information such as username or passwords. -
What does
--recursivedo? Expands subassemblies and downloads or lists all contained items up to the given--max-depth. -
How does Gladiator handle authentication? It performs a
/logincall and stores the resultingarenaSessionIdfor reuse. If it expires, re-rungladiator login. -
What happens on a transient Arena error (HTTP 429/5xx)? Idempotent requests (GET/HEAD/PUT/DELETE/OPTIONS/TRACE) are retried automatically with exponential backoff — 3 attempts by default, honouring any
Retry-Afterheader. POST is not retried, since uploads and change creation are not guaranteed idempotent. Override the retry count with theGLADIATOR_HTTP_RETRIESenvironment variable. If retries are exhausted the command reports the method, URL, status and body, and notes that Arena returned a server-side error so you can re-run.
Release files for lr-gladiator 0.44.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| lr_gladiator-0.44.0.tar.gz | 76.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| lr_gladiator-0.44.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 142.4 kB
Release files / lr_gladiator-0.44.0.tar.gz
| Download URL | lr_gladiator-0.44.0.tar.gz |
|---|---|
| Size | 76.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
21ac2d9b27995a50764c76d197fa7f4d0aeda2e8c74cf473c24215302f64cb96
|
|
BLAKE2b-256 checksum How to use checksums |
02be3c22dad97010dc09e45476439d18637ed595eb2a3c107301249cf9bac722
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|
Release files / lr_gladiator-0.44.0-py3-none-any.whl
| Download URL | lr_gladiator-0.44.0-py3-none-any.whl |
|---|---|
| Size | 65.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8b41dd7767036f6576a39911ee268d5cca7d557025b024fc9ce71d85d94435c3
|
|
BLAKE2b-256 checksum How to use checksums |
c63a3057ef824c252f35988321f80430d3d11e6ed8e2c752c9ac87801ae4e6db
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|