# Python Bridge — Use NexArt from Python

URL: https://docs.nexart.io/docs/python-bridge

Use NexArt from Python via a thin bridge to the canonical JavaScript SDK, shipped inside @nexart/agent-kit (>=0.5.2).

## Why a bridge and not a native SDK

NexArt's core promise is vendor-independent verification: a Certified Execution Record produced by any NexArt tool MUST be verifiable by any other NexArt tool, by an independent third party, and by the public` verify.nexart.io` endpoint, all producing byte-identical hashes. That guarantee depends on a single canonical implementation of hashing, canonicalization, and signing. Maintaining a parallel native Python SDK would introduce two implementations of the same cryptographic surface, and the smallest divergence between them - one library sorting object keys differently, one floating point edge case, one Unicode normalization choice - silently breaks cross-tool verification.

The bridge resolves this by keeping the JavaScript SDK as the single source of truth and exposing a Python-shaped surface on top of it. The tradeoff is explicit and honest: Python users must carry a Node.js runtime dependency. In exchange, every CER produced from Python is byte-identical to one produced from JavaScript, and the verification story stays unified.

## Requirements

- Node.js >= 18
- Python >= 3.10
- `@nexart/agent-kit` >= 0.5.2 installed via npm
- Python-only Docker images need Node added to the base image. Full deployment guidance lives in `PYTHON_BRIDGE_INSTRUCTIONS.md`inside the npm package.

## Performance

The bridge ships two transports. Pick by call volume.

- `BridgeOneShot` — spawns a fresh Node subprocess per call. Roughly 130ms per invocation. Conservative default. Use for scripts, batch jobs, low-frequency certification.
- `BridgePersistent` — keeps a long-lived Node worker alive and dispatches calls over its stdio. Roughly 0.4ms per invocation - about a 300x speedup. Use for servers, hot loops, and per-request certification.

Start with `BridgeOneShot` until you measure that the subprocess cost matters. Switching is a one-line change.

## API

Every bridge function takes the bridge instance as its first positional argument. Without it, the function has no Node process to dispatch to. The shape mirrors `@nexart/agent-kit`'s JS API, with Python casing.

certify_decision_example.py

```
from nexart_bridge.nexart_bridge import (
    BridgeOneShot,
    certify_decision,
    verify_cer,
)

br = BridgeOneShot()

bundle = certify_decision(
    br,
    decision="Recommend product X to user 123",
    output="product_x",
    provider="openai",
    model="gpt-4o",
)

result = verify_cer(br, bundle, verificationMode="detailed")
if result["status"] != "VERIFIED":
    raise RuntimeError(f"CER verification failed: {result['reasonCodes']}")

print("Certified:", bundle["certificateHash"])
print("Status:   ", result["status"])
```

For default (non-detailed) verification, omit `verificationMode`:

```
ok = verify_cer(br, bundle)  # returns boolean-shaped result
```

## Where the bridge lives

The bridge is not published on PyPI. It is shipped as two files inside the `@nexart/agent-kit` npm package, at:

```
node_modules/@nexart/agent-kit/python-bridge/
  ├── nexart_bridge.mjs              # Node-side dispatcher
  ├── nexart_bridge.py               # Python-side client
  └── PYTHON_BRIDGE_INSTRUCTIONS.md  # full setup reference
```

Setup is three steps:

- Install the npm package in a directory accessible to your Python process: `npm install @nexart/agent-kit@>=0.5.2`.
- Copy both `nexart_bridge.mjs` and `nexart_bridge.py` from `node_modules/@nexart/agent-kit/python-bridge/` into a `nexart_bridge/` folder inside your Python project.
- Import with `from nexart_bridge.nexart_bridge import ...`. Full instructions, including container deployment, are in `PYTHON_BRIDGE_INSTRUCTIONS.md`.

Do not `pip install` anything. There is no PyPI package and none is planned.

## Verification parity

Bundles produced through the bridge are byte-identical to bundles produced by the JavaScript SDK directly. The same `certificateHash` falls out of either path, and the same signatures verify. That means a Python-produced CER verifies cleanly with:

- `verify.nexart.io/c/{certificateHash}`
- The JavaScript SDK (`verifyAiCerBundleDetailed`)
- The NexArt CLI
- The bridge's own `verify_cer`

All paths agree because all paths run the same canonical implementation underneath.

## Related

- Certified Execution Records
- How Verification Works
- Certifying LLM Conversations
- Agent Kit
- Agent-Kit Instructions for AI Agents
