Skip to main content

lr-serial

CLI + Python client for interacting with the LumenRadio Serial Number Generation Service.

Install

pip install lr-serial

AI assistant integration

lr-serial ships a bundled skill/instruction file that teaches AI coding assistants about the CLI commands, Python API, data models, and common workflows.

Run this once from the root of your project:

serial --install-skill

This does three things:

  • Claude Code — copies the skill to ~/.claude/skills/lr-serial/ (global, available in all projects)
  • GitHub Copilot — writes .github/instructions/lr-serial.instructions.md in the current directory
  • VSCode — sets github.copilot.chat.codeGeneration.useInstructionFiles: true in .vscode/settings.json (creates the file if it doesn't exist; merges if it does)

To inspect the skill content without installing:

serial --show-skill

Python API

lr-serial exposes a SerialClient class for programmatic use — no CLI parsing, no sys.exit(). All errors are raised as typed exceptions from lr_serial.exceptions.

Quick start

from lr_serial import SerialClient

# From stored credentials (after `serial login`)
client = SerialClient.from_config()

# Or from M2M credentials directly
client = SerialClient.from_m2m(
    client_id="<CLIENT_ID>",
    client_secret="<CLIENT_SECRET>",
    token_url="https://login.microsoftonline.com/<TENANT_ID>/oauth2/v2.0/token",
)

# List articles
articles = client.list_articles()   # -> list[ArticleListItem]

# Generate serial numbers
serials = client.generate("PROD-01", quantity=5, fields={"site": "2"})  # -> list[str]

# Look up a serial
info = client.lookup("PROD-STH-000001")  # -> SerialInfo

# Full article details
article = client.article_get("PROD-01")  # -> Article

Exception handling

from lr_serial.exceptions import AuthenticationError, NotFoundError, SerialError

try:
    info = client.lookup("UNKNOWN-000")
except NotFoundError:
    print("Serial not found")
except AuthenticationError:
    print("Token expired — run `serial login` again")
except SerialError as exc:
    print(f"API error: {exc}")

Reference

Method Returns Description
SerialClient.from_config(path?) SerialClient Load from ~/.config/serial/login.json
SerialClient.from_m2m(client_id, client_secret, token_url, scope?) SerialClient OAuth2 client credentials
client.list_articles() list[ArticleListItem] All articles
client.article_get(article_no) Article Full article details
client.article_create(article_no, description, prefix, schema, disabled?) dict Create article
client.article_update(article_no, *, description?, prefix?, disabled?, schema?) dict Partial update
client.article_delete(article_no) None Delete article
client.article_set_sequence(article_no, sequence_no) dict Set serial counter
client.generate(article_no, quantity?, fields?) list[str] Generate serials
client.lookup(serial_no) SerialInfo Serial metadata
client.site_list() list[Site] All sites
client.site_create(site_no, name) dict Create site
client.site_update(site_no, name, *, client_id?, contact_email?, disabled?) dict Update site
client.site_delete(site_no) None Delete site
client.audit_list(limit?) list[AuditEntry] Audit log (admin scope)
client.audit_restore(audit_id) dict Undo audited change (admin scope)

Models

Model Key fields
ArticleListItem article, description
Article article, description, prefix, disabled, schema_
ArticleSchema version, format, regexp, fields
SerialInfo serial_no, article, created_by, created_at
Site site_no, name, client_id, contact_email, disabled
AuditEntry id, touched_table, touched_key, change_type, changed_by, changed_at

CLI Usage

Login Command

The login command supports two authentication modes:

User login (default)

Opens the system browser for interactive sign-in via OAuth 2.0 Authorization Code + PKCE. No client secret required — suitable for human operators.

LumenRadio employees can log in with no arguments (client ID and tenant ID are baked in):

serial login

If the browser does not open automatically the auth URL is printed to the terminal so you can paste it manually.

Machine-to-machine (M2M) login

Uses the OAuth 2.0 client credentials grant — suitable for automated pipelines.

serial login --mode m2m \
  --client-id <CLIENT_ID> \
  --client-secret <CLIENT_SECRET> \
  --tenant-id <TENANT_ID>

Common options

  • --mode [user|m2m] — authentication mode (default: user) [env: SERIAL_AUTH_MODE]
  • --client-id — Azure AD application client ID [env: SERIAL_CLIENT_ID]
  • --client-secret — client secret, required for m2m [env: SERIAL_CLIENT_SECRET]
  • --tenant-id — Azure AD tenant ID [env: SERIAL_TENANT_ID]
  • --token-url — token endpoint URL override (m2m only) [env: SERIAL_TOKEN_URL]
  • --scope — OAuth2 scope override [env: SERIAL_SCOPE]
  • --config-path — override the login.json location

Stores the bearer token (and refresh token for user logins) in your config directory for subsequent CLI commands.

Status Command

Check backend reachability and token validity:

serial status

Reports:

  • Backend reachable ✓ / unreachable ✗
  • Token valid ✓ / invalid ✗

Global Options

Most commands support:

  • --output [rich|json] — output format (rich table default, json for scripting)
  • --config-path PATH — override the login.json location

Article Commands

List Articles

serial list-articles
serial list-articles --output json

Get Article

serial article get ARTICLE_NO
serial article get 710-4130 --output json

Returns full article details: article number, description, prefix, schema (version, fields, format, regexp), disabled flag.

Create Article

serial article create \
  --article PROD-01 \
  --description "Production line 1" \
  --prefix PROD \
  --schema-file schema.json

The --schema-file must be a JSON file with the ArticleSchema object:

{
  "version": 1,
  "fields": { "site": "string" },
  "format": "{prefix}-{site}-{counter:06d}",
  "regexp": "^[A-Z0-9]+-[A-Z0-9]+-[0-9]{6}$"
}

Options:

  • --article TEXT — article number (1-32 chars, [A-Za-z0-9-]) [required]
  • --description TEXT — human-readable description (1-100 chars) [required]
  • --prefix TEXT — serial prefix (1-10 chars, [A-Za-z0-9]) [required]
  • --schema-file PATH — path to JSON file containing the ArticleSchema [required]
  • --disabled / --no-disabled — create as disabled (default: enabled)

Update Article

serial article update ARTICLE_NO --description "New description"
serial article update ARTICLE_NO --prefix NEWP --disabled

At least one option must be provided. Options: --description, --prefix, --disabled/--no-disabled, --schema-file.

Delete Article

serial article delete ARTICLE_NO

Idempotent — succeeds even if the article does not exist.

Set Sequence Counter

serial article set-sequence ARTICLE_NO SEQUENCE_NO
serial article set-sequence 710-4130 1000

Sets the current counter value (integer ≥ 0) for the article.


Serial Number Commands

Generate Serial Numbers

serial generate ARTICLE_NO
serial generate ARTICLE_NO --quantity 5
serial generate ARTICLE_NO --field site=2 --field year=2024
serial generate ARTICLE_NO --quantity 3 --output json

Options:

  • --quantity INT — number of serials to generate (1-1000, default 1)
  • --field KEY=VALUE — extra field value consumed by the article schema (repeatable). The conventional site field should be a site_no from the sites table, but the backend does not enforce this — any string value is accepted.

Lookup a Serial Number

serial lookup SERIAL_NO
serial lookup QWDNA010000001 --output json

Returns: serial value, article, created_by, created_at.

Note: The site field is not returned by lookup — it is embedded in the serial string itself according to the article's schema format. To find the production site of a serial: look up the serial to get its article, get the article schema to understand the format, parse the site_no digits from the serial string, then resolve it via serial site list.


Site Commands

List Sites

serial site list
serial site list --output json

Create Site

serial site create --site-no 5 --name "Helsinki"

Options:

  • --site-no INT — site number (1-99) [required]
  • --name TEXT — site name [required]

Update Site

serial site update 5 --name "Helsinki" --contact-email ops@example.com
serial site update 5 --name "Helsinki" --disabled

Note: --name is required by the API even when only updating other fields.

Options:

  • --name TEXT — new site name [required]
  • --client-id TEXT — associated client ID (or empty to clear)
  • --contact-email TEXT — contact email address (or empty to clear)
  • --disabled / --no-disabled — enable or disable the site

Delete Site

serial site delete 5

Idempotent — succeeds even if the site does not exist.


Audit Commands

These commands require the app.admin.api scope.

List Audit Entries

serial audit list
serial audit list --limit 50 --output json

Returns audit entries newest-first: id, touched_table, touched_key, change_type (create/update/delete), changed_by, changed_at.

Options:

  • --limit INT — max entries to return (1-500, default 100)

Restore an Audit Entry

serial audit restore AUDIT_ID

Undoes the audited change:

  • create → deletes the created row
  • update → restores previous values
  • delete → re-inserts the deleted row

If the token lacks the admin scope, the API returns 403 and the CLI will display: Access denied. Ensure your credentials include the admin scope (app.admin.api).

Release files for lr-serial 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for lr-serial 1.1.0
File Size Uploaded
lr_serial-1.1.0.tar.gz 43.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for lr-serial 1.1.0
File Interpreter ABI Platform
lr_serial-1.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 77.0 kB

Release files / lr_serial-1.1.0.tar.gz

Download URL lr_serial-1.1.0.tar.gz
Size 43.5 kB
Tags Source
SHA-256 checksum
How to use checksums
83ebd073eb86646e0f885a222a275ae41abd50ee1d2ab4a4b81f1bacfe881caf
BLAKE2b-256 checksum
How to use checksums
cb7814722381ef803ac3b251ec3b74a2130a1ad0ea53f8d115eb486fb19fd9b0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.14

Release files / lr_serial-1.1.0-py3-none-any.whl

Download URL lr_serial-1.1.0-py3-none-any.whl
Size 33.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
494fde246f0524864582d2416332b751226d324c5d34537302e4fe9a19056de2
BLAKE2b-256 checksum
How to use checksums
cdffc8d5735396247bd5633ca016fce9be17c52d152f729693e172b5f213694b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.14

Release history Release notifications | RSS feed

This release

1.1.0 This release

2 release files

1.0.0

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

1 release file

0.1.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page