Skip to main content

Production Master — Python SDK

A thin Python client for Production Master. It talks to the same BFF + Stream Gateway every other surface (Web, plugin, CLI) uses — there is no new backend and no privileged back door. The client only marshals requests, attaches a stable Idempotency-Key on mutations, bridges the SSE stream with Last-Event-ID resume, and maps errors.

The runtime is pure Python stdlibpip install pulls no third-party dependencies, so install-to-first-start_investigation stays well under a minute and CI stays hermetic.

Install (beta)

The SDK is pre-release — not on PyPI yet. Use one of the beta paths below.

From git (recommended)

pip install "git+https://github.com/ProductionMasterAI/production-master.git@main#subdirectory=sdk/python"

Pin a tag or commit for reproducible beta installs:

pip install "git+https://github.com/ProductionMasterAI/production-master.git@v0.1.0-beta.1#subdirectory=sdk/python"

From a GitHub Release wheel

When a maintainer attaches build artifacts to a release:

pip install https://github.com/ProductionMasterAI/production-master/releases/download/v0.1.0-beta.1/production_master-0.1.0-py3-none-any.whl

Replace the URL with the wheel attached to the release you are targeting.

PyPI (future)

When the product is ready for public distribution:

pip install production-master

The distribution name is production-master; the import package is production_master.

Point it at your service

Precedence is explicit argument → PM_SERVICE_URL → built-in default:

export PM_SERVICE_URL="https://bff.your-company.internal"   # self-hosted
Client()                                        # PM_SERVICE_URL, else the default
Client(service_url="https://bff.example.com")   # wins over both

PM_SERVICE_URL is the same variable every editor registration in this repo sets, so one variable points the plugin and the SDK at the same service.

The built-in default is the hosted service's own deployment origin rather than a vanity API hostname. That is deliberate: a default pointing at a domain nobody owns would hand the bearer token of every user who does not override it to whoever registers that domain later. It moves to a vanity host once that host is ours and serving the BFF.

Authenticate

The SDK uses the same RFC 8628 device-code flow as the plugin/CLI. The token is cached to ~/.config/production-master/token.json with 0600 permissions.

from production_master import login

# Prints a verification URL + user code, then blocks until you approve it.
login(service_url="https://production-master-service.vercel.app")

Once cached, Client() picks the token up automatically. You can also pass a bearer token explicitly with Client(token="...").

Quickstart: start_investigationstream_eventsget_report

from production_master import Client

client = Client()  # uses the cached device-code token

# 1. Start a run (POST /v1/runs with a stable Idempotency-Key).
inv = client.start_investigation({"ticket": "ACME-123", "title": "checkout 500s"})
print(inv.id, inv.uri)          # inv_… , investigation://inv_…

# 2. Stream events live (SSE with Last-Event-ID resume).
for event in inv.stream_events():
    print(event.sequence, event.type)

# 3. Fetch the rendered report and branch on the verdict.
report = inv.get_report(format="json")
if report["verdict"] == "CONFIRMED":
    print("Root cause:", report.get("rootCause"))

# Markdown is available too:
markdown = inv.get_report(format="md")

start_investigation, stream_events, and get_report are also available directly on the Client (client.stream_events(inv.id), etc.).

Resuming a stream

stream_events reconnects automatically with Last-Event-ID. To resume from a known position:

# Replay the durable slice with sequence > 10, then attach the live stream.
for event in client.stream_events(inv.id, since_seq=10):
    ...

# Or resume from a specific event id.
for event in client.stream_events(inv.id, last_event_id="01J…"):
    ...

Errors

Non-2xx responses raise typed errors that mirror the other SDKs:

Status Exception
409 IdempotencyConflict
402 BudgetExhausted
404 NotFound
403 NotFound (no-enumeration: a forbidden singleton looks like not-found)
other ServiceError (code UNKNOWN)
from production_master import BudgetExhausted, NotFound

try:
    client.start_investigation({"ticket": "ACME-1"})
except BudgetExhausted:
    ...

Testing without a network

The transport is an injectable seam (Transport protocol). Inject a fake to exercise the client offline:

from production_master import Client
from production_master.transport import Response

class FakeTransport:
    def request(self, req):
        return Response(status=201, body={"investigationId": "inv_1"})
    def open_stream(self, req):
        return iter([])

client = Client(transport=FakeTransport())

Development

cd sdk/python
python3 -m pip install -e '.[test]'
python3 -m pytest -q

Publish to PyPI (post-beta, maintainers only)

Not used during beta — CI builds and tests the package on every pull request; beta users install from git or a Release wheel as above.

PRD spec 12 (docs/specs/12-cli-and-python-sdk.md in the dev cockpit) targets pip install production-master once the product is ready for public distribution. Owner decisions (2026-07-07, issue #131 item 2):

  • Distribution name: production-master (import: production_master)
  • Packaging: one combined pip package — not four per-platform wheels

The publish job is .github/workflows/publish-python.yml. It runs on ubuntu-latest (this repo is public — a self-hosted runner here would let a fork's pull request run code on the owner's hardware) and authenticates with PyPI Trusted Publishing: GitHub mints a short-lived OIDC token that PyPI exchanges for a scoped, single-use upload token. There is deliberately no PYPI_API_TOKEN secret in this repository — no long-lived credential to leak, rotate, or scope wrong.

One-time owner setup

  1. Reserve the project on PyPI — sign in at pypi.org as the publisher account and create production-master (it must match [project].name in pyproject.toml).

  2. Register the trusted publisher — project settings → Publishing → add a GitHub publisher with exactly:

    Field Value
    Owner ProductionMasterAI
    Repository production-master
    Workflow publish-python.yml
    Environment pypi
  3. Create the pypi environment on the repository (Settings → Environments). Add required reviewers if you want a human gate on every upload.

Until step 2 exists the upload fails closed with an authentication error — it cannot fall back to some other credential and publish anyway.

Release flow

  1. Bump __version__ in production_master/__init__.py and merge to main.
  2. Tag it: git tag python-v0.1.0 && git push origin python-v0.1.0. The prefix matters — the plugin's own releases use bare v* tags, so python-v* keeps the two release trains from firing each other.
  3. The job re-runs pytest against the tagged tree, asserts the tag matches __version__, builds sdist + wheel, and uploads.
  4. Verify: pip install production-master then python -c "import production_master; print(production_master.__version__)".

Local dry-run (no upload):

cd sdk/python
python3 -m pip install '.[test,dev]'
python3 -m pytest -q
python3 -m build
ls dist/

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

production_master-0.1.0.tar.gz (25.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

production_master-0.1.0-py3-none-any.whl (20.0 kB view details)

Uploaded Python 3

File details

Details for the file production_master-0.1.0.tar.gz.

File metadata

  • Download URL: production_master-0.1.0.tar.gz
  • Upload date:
  • Size: 25.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for production_master-0.1.0.tar.gz
Algorithm Hash digest
SHA256 64580942f10e90f7a94dfcaa58084798f2330642c8f84c3adf53e7582e750832
MD5 05ab93afd1530a7e36cf0bd888851dad
BLAKE2b-256 e09b301248da6c8f79e434ba79fbb08e988823cda45f3c894e579cb4217e21b7

See more details on using hashes here.

Provenance

The following attestation bundles were made for production_master-0.1.0.tar.gz:

Publisher: publish-python.yml on ProductionMasterAI/production-master

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file production_master-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for production_master-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b8abf4fa77306592cbeeb1a5e605424471fc986f3c5383083eb8e723e7fe231b
MD5 26176f0cdf338e1b02745a7093065cd6
BLAKE2b-256 b9bd0b45cbf05d43c96988f107fb30bf73a464ee660835f1e55ac88936fdf350

See more details on using hashes here.

Provenance

The following attestation bundles were made for production_master-0.1.0-py3-none-any.whl:

Publisher: publish-python.yml on ProductionMasterAI/production-master

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

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