Skip to content
Tenzro
Documentation menu
Agents

NVIDIA OpenShell

Run NVIDIA OpenShell agents on Tenzro: admit the serving node, delegate the agent under Terms, host the Tenzro extensions, configure the gateway, create the provider and the sandbox, and verify the session.

NVIDIA OpenShell runs an agent in a sandbox behind a gateway. The gateway creates the sandbox, a supervisor outside the sandbox enforces its policy, and every outbound request passes through the supervisor's network proxy. The Tenzro extensions for OpenShell plug into those extension points, so an agent in a sandbox acts under Terms its controller approved, calls models through Tenzro, pays outside services, and leaves a signed record of every action that anyone checks without trusting the gateway.

For what this gives an agent, see Agents in NVIDIA OpenShell. This page sets it up.

What runs where

PieceRuns inDoes
Credential driverthe gatewayResolves the sandbox's tenzro provider credential to the delegated agent. The agent's access tokens stay with its serving nodes, never in the sandbox.
Gateway interceptorthe gatewayRefuses to create or update a sandbox whose policy has no tenzro middleware that fails closed, and checks that the agent's Terms are live.
Supervisor middlewarethe supervisor, outside the sandboxChecks each request against the agent's Terms on Tenzro, records it as a signed agent audit entry, and settles inference charges and payments.
Inference provider profilethe gateway's provider profilesRoutes the sandbox's model calls to Tenzro serving nodes.
Attestationthe serving node's hostThe node's hardware identity (TPM or Secure Enclave) certifies the session keys that sign the records.

Nothing in the sandbox holds a key. The supervisor's session key and the agent's signing keys live in the TPM or Secure Enclave of the machines that hold them, and the controller's approval is a passkey assertion.

Setup

These are the steps the Tenzro OpenShell end-to-end test runs against a live Tenzro node, with OpenShell 0.1.5 (openshell and openshell-gateway).

1. Admit the serving node

On the machine that runs the node and the extensions, register its machine identity once. The registration records its TPM attestation, which admits that TPM under the machine's one identity, so the session keys it certifies for the agents it serves are accepted.

bash
tenzro validator register-machine --key-namespace <node hardware_key_namespace> --rpc <node rpc url>

The TPM's endorsement certificate has to chain to a manufacturer root the network recognises.

2. Delegate the agent

The agent's controller bonds it and approves its Terms, served by that node. A machine root does it with its own hardware keys:

bash
tenzro agent delegation create-as-machine --terms terms.json --key-namespace <root namespace> \
  --bond 1000000000000000000 --rpc <node rpc url>

terms.json:

json
{
  "agent_name": "my-agent",
  "delegation_scope": {
    "allowed_operations": ["sandbox", "sandbox.policy", "fetch", "inference", "pay"],
    "max_transaction_value": "500",
    "max_daily_spend": "100000",
    "allowed_payment_protocols": ["x402"],
    "allowed_models": ["tenzro/e2e"]
  },
  "capabilities": [],
  "min_distinct_operators": 1,
  "expires_at_ms": 1798000000000
}

The command prints the agent's DID (identity.did) and its controller's DID (identity.controller_did). A controller with a passkey builds the same Terms from the sandbox policy and a grant with the SDK's mintOpenShellCredential, and approves them with the passkey.

3. Host the extensions

Run the three extensions on the serving node's host, in one process built on the Tenzro OpenShell extensions crate, reading delegations from the node:

  • the credential driver on a Unix socket with mode 0600, which only the openshell-gateway binary, running as the same user, may call;
  • the gateway interceptor on a Unix socket, for calls that carry the gateway's extension JWT and come from that binary;
  • the supervisor middleware over TLS under its own CA, for calls that carry a gateway or supervisor extension JWT. Generate that CA with:
bash
openshell-gateway generate-certs --output-dir ext-pki

Every decision is signed by a session key the host's TPM identity certified, and appended to the extensions' record directory.

4. Configure and start the gateway

gateway.toml:

toml
[openshell]
version = 2

[openshell.gateway]
guest_tls_ca = "pki/ca.crt"
credential_drivers = ["tenzro"]

[openshell.gateway.gateway_jwt]
signing_key_path = "jwt/signing.pem"
public_key_path = "jwt/public.pem"
kid_path = "jwt/kid"
gateway_id = "my-gateway"

[openshell.gateway.mtls_auth]
enabled = true

[[openshell.gateway.interceptors]]
name = "tenzro"
grpc_endpoint = "unix:///run/tenzro/tenzro-interceptor.sock"
audience = "urn:tenzro:openshell:interceptor"
failure_policy = "fail_closed"
timeout = "2s"

[[openshell.supervisor.middleware]]
name = "tenzro"
grpc_endpoint = "https://127.0.0.1:<middleware port>"
tls_ca_cert_path = "ext-pki/ca.crt"
audience = "urn:openshell:extension:middleware:tenzro"
max_payload_bytes = 262144
timeout = "5s"

[openshell.credential_drivers.tenzro]
transport = "uds"
socket_path = "/run/tenzro/tenzro-credentials.sock"
bash
openshell-gateway --config gateway.toml --compute-driver docker \
  --tls-cert pki/server/tls.crt --tls-key pki/server/tls.key --tls-client-ca pki/ca.crt

The gateway refuses to start when it cannot reach the extensions.

5. Import the Tenzro inference provider profile

Copy the Tenzro provider profile, tenzro.yaml, from the Tenzro OpenShell extensions, set binaries and the endpoint for your image, and import it:

bash
openshell profile import --file tenzro.yaml

6. Create the provider

Create the provider with the agent's DID as its one credential:

bash
openshell provider create --name tenzro --type tenzro --credential TENZRO_API_KEY=<agent did>

A provider holding anything but an agent's DID is refused. The credential driver mints a short-lived token from the DID on every resolve, and neither the DID nor the token reaches the sandbox's environment.

7. Create the sandbox

bash
openshell sandbox create --provider tenzro --annotation tenzro.agent=<agent did> \
  --policy policy.yaml --no-auto-providers -- <agent command>

The interceptor refuses a sandbox that names no agent, an agent another account delegated, or a policy without the tenzro middleware, and annotates the sandbox with the host's TPM binding (tenzro.host).

8. Verify the session

The extensions append every entry, as it is signed, to <session id hex>.jsonl in their record directory, one signed entry per line, and write identity.json there: the hardware identity the session keys sign for (p256, and pq when it holds an ML-DSA-65 key) and hybrid_records_from_ms. Nothing in that directory is secret.

js
import { parseOpenShellEntries, verifyOpenShellSession, openShellPayments, openShellSessionId } from "tenzro-sdk";

const entries = parseOpenShellEntries(jsonl);
const session = await verifyOpenShellSession(entries, {
  identity: { p256: id.p256, pq: id.pq },                 // from identity.json
  hybridRecordsFromMs: id.hybrid_records_from_ms,
  sessionId: await openShellSessionId("my-gateway", "my-sandbox"),
});
console.log(session.count, session.root);
console.log(openShellPayments(session));

verifyOpenShellSession needs nothing but the entries and the hardware identity. It checks that:

  • every entry is signed by a session key the identity certified, within the certificate's validity, and by a hybrid session key once hybrid records are in force;
  • entries are numbered from 0 with no gap, all of one session and one agent;
  • each entry names the leaf hash of the one before it, so none can be dropped, reordered or replaced.

It names the first fault it finds and otherwise returns the entries and the session's MMR root. The session id is SHA-256 of tenzro/openshell/session/v1, a zero byte, the gateway name, a zero byte and the session's name: the sandbox, or the agent's DID for its model calls.

The same helpers exist in the Python and Rust SDKs under the same names in each language's style.

See also Agents, Identity, Hardware-rooted keys and x402.

ExploreJoin the network