nexart.iodocs

    Python Bridge — Use NexArt from Python

    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.mdinside 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:

    1. Install the npm package in a directory accessible to your Python process: npm install @nexart/agent-kit@>=0.5.2.
    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.
    3. 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.