05 · The codewhere is it, and how do I run it?

The code is public, and the public testnet is the only place a third party tests it

The whole implementation is open source under the Apache License 2.0. The packages build from the main project until they reach a registry. The public testnet runs the same software and parameters as production, with a KYC sandbox whose outcomes you choose, where nothing issued carries weight. The revocation trace shows the guarantee against a running deployment.

STATUS: LIVENOTHING ISSUED CARRIES WEIGHTTEST TOKENS: NO VALUE
The component

The code

The whole implementation is one main project under the Apache License 2.0, with read-only mirrors for the clients; released versions are on PyPI and npm. Every deployment runs the same verifying core, and the verifier is yours. The public testnet is the only deployment a third party tests on, and the revocation trace shows the guarantee against a running one.

PROOF

What it proves, and what it does not

Proves

  • That every deployment runs the same single verifying core: the clients and the MCP server carry no cryptography and no policy.
  • That the public testnet runs the same software and chain parameters as the single-node production chain, with its own chain and keys.
  • That the revocation bounds hold against a running deployment: the trace records the last accepted decision, the first refusal and the root that carried the revocation.

Does not prove

  • Not what the agent ran: which configuration it started with, where it ran, which calls it made. That is provenance, a different layer: glossary
  • Not that a testnet decision carries weight: its sandbox issuer verifies nobody, and nothing issued there says anything about any person.
  • Not an audited implementation: no independent security audit has been completed; audits are scheduled milestones whose findings will be published.
The code

Where the code and the packages are

A · The code

One main project holds the whole implementation

The code. MintID’s implementation is open source under the Apache License 2.0. The main project holds all of it: the chain, the proof core and the holder library, the verifier and issuer services, the self-revocation relay, the SDKs, the test harness, a local stack that runs on your machine, and the developer documentation.

ProjectWhat it is
https://gitlab.com/mintid/mintidthe main project: the whole implementation; issues and merge requests go here
https://gitlab.com/mintid/sdk-typescriptread-only mirror of the TypeScript client
https://gitlab.com/mintid/verifier-mcpread-only mirror of the MCP server
https://gitlab.com/mintid/sdk-pythonread-only mirror of the Python agent client
https://gitlab.com/mintid/sdk-goread-only mirror of the Go holder binding

The specifications whose requirement identifiers the code cites are not part of the repository.

Contributions are welcome as issues and merge requests on the main project, signed off under the Developer Certificate of Origin. They are answered on a best-effort basis; there is no service-level agreement.

Reporting a vulnerability. Write privately to security@mintid.net. Never open a public issue, merge request or discussion for a suspected vulnerability. There is no bug bounty programme today and no response-time commitment. No independent security audit of this implementation has been completed: audits are scheduled as milestones, and each audit’s findings will be published with their remediation when it closes.

B · SDKs and MCP

Every deployment runs the same verifying core, and the verifier is yours

The verifier is your own service. A relying party runs the verifier SDK inside its own backend, or as a service next to it, and decides on its own service. Every deployment runs the same single verifying core; the clients and the MCP server carry no cryptography and no policy, and pointing them at somebody else’s verifier would hand that party the decision.

The packages. Released versions are on PyPI and npm; the main project (or the mirror, where there is one) is their source and can be ahead of them.

PackageWhat it isVersionInstall
mintid-verifier-sdk (Python)the verifier: one verifying core with the proof engine compiled in0.4.1pip install mintid-verifier-sdk
@mintid-net/verifier-client (TypeScript, Node)a transport-only client of your own verifier service, with the holder and agent clients0.3.0npm install @mintid-net/verifier-client
@mintid-net/verifier-mcp (TypeScript)an MCP server: the verifier contract as three agent tools, over stdio or Streamable HTTP0.3.0npm install @mintid-net/verifier-mcp
mintid-agent (Python)the agent client: credential custody, witness refresh, the identity leg of a paid request0.4.0pip install "mintid-agent[ed25519]"
gitlab.com/mintid/sdk-go (Go)the Go binding of the holder libraryv0.20261011.1go get gitlab.com/mintid/sdk-go/holder

Versions of release public-v2026-10-14.2; underneath them, mintid-proof-core 0.5.2 (and the holder binary mintid-holder 0.5.0).

Every release carries a signed manifest of what it published; Verify a release says how to check a package or an image against it with the release key alone.

Check a real presentation yourself: your browser verifies a synthetic presentation with the verifier’s own proof core, compiled to WebAssembly; nothing is sent anywhere.

Platforms. mintid-verifier-sdk and mintid-proof-core compile the Rust proof engine in at a pinned version. The registry carries a prebuilt wheel for Linux x86-64 only; on any other platform (macOS, Linux on ARM, Windows) pip builds the package from its source distribution, which needs a Rust toolchain. From a clone of the main project the same holds: pip install ./verifier-core, pip install ./identity-proof-core/python. The mintid-holder binary, which the TypeScript identity and agent modules and the Go binding drive, is on no registry: cargo build --release -p mintid-holder in identity-proof-core/.

Network profiles. mintid-proof-core, mintid-agent, @mintid-net/verifier-mcp and the Go holder binding carry the same network registry; MINTID_NETWORK=testnet (or --network testnet) selects the public testnet, and python3 -m proof_core.networks testnet --shell prints its endpoints as shell variables for the commands of this documentation. An endpoint you set yourself wins over the registry everywhere.

The install lines are in the developer documentation, starting at Getting started.

Agents that prove their principal’s age. An agent credential of profile agent_v2 carries the age threshold its principal proved when the agent was minted, and proves age_over N against it: the verifier learns age_over_<N> and nothing else — no date of birth, no identity. Ask for it with a challenge of profile: "agent_v2" (verifier contract 1.7.0). Available on the public testnet’s verifier; not yet in production.

Try the tools on the public testnet. Add the testnet’s MCP endpoint to an agent runtime, for example Claude Code:

claude mcp add --transport http mintid-testnet "$MINTID_TESTNET_MCP"
claude mcp add mintid-testnet -- npx -y @mintid-net/verifier-mcp --network testnet

Its challenges are bound to the testnet’s sandbox verifier, so its decisions carry no weight. If a decision gates your business, run the server yourself, in front of your own verifier.

What the three tools do, and where the trust boundary sits, is on the MCP server page.

C · Sandbox

One deployment to test on, and what it is made of

Status: live.

The public testnet. The public testnet is the only MintID deployment a third party may use to test. It runs the same software and the same chain parameters as the single-node production chain, with its own chain, keys and hostnames. The single-node production chain is not for third parties and is never a place to test.

A KYC sandbox. Its issuer verifies nobody: when you open a KYC session you choose its outcome — approved at a grade from A1 to A4, declined, expired, abandoned, held in manual review, a date of birth the issuer cannot read, a provider that is unavailable, a session past its reuse window, and more — so every path of issuance and every error an integrator can meet is reachable on purpose. Nothing issued on the testnet carries weight: a credential, a grade, an agent or a decision obtained there says nothing about any person and must never be accepted anywhere else.

Limits. The production parameters: a new status root every 30 seconds, roots accepted up to 180 seconds, presentations that live 10 seconds. Agent minting is limited as everywhere, to 5 agents per person per hour and 10 active.

Reset policy. The testnet follows the software through ordinary deploys while the software keeps its shape. When it changes shape, the testnet is reset: a new chain identifier, new keys, an empty registry. Everything issued before is gone, with no migration and no notice period, because nothing on it carries weight.

Test tokens and the faucet. The public testnet runs on its own denomination, utestmint: every fee and bond on it is denominated in utestmint, on the same paths production charges, at the testnet’s fee parameters. What a third party pays from a grant are the fees the chain charges its own account: a verifier’s self-registration on the permissionless tier and its renewal, 1 000 000 utestmint each. Agent mint and lease fees are not paid by a third-party key: the issuer’s operator account settles them, so the sandbox journey (KYC, credential, agents) needs no tokens. Anyone can obtain utestmint, free, from the faucet: one grant per address per 24 hours and one grant per source per hour, 100 000 000 utestmint each. The faucet links no address to a person.

Endpoints. The public testnet exposes a chain RPC, the sandbox verifier (contract v1 and the substrate reads), the issuer with its KYC sandbox, a remote MCP server, the self-revocation relay, the faucet and a network page with the genesis and the peer. The packages carry the testnet’s endpoints in their network registry: select the profile with MINTID_NETWORK=testnet, or --network testnet on a command line, and they reach the testnet on installation. The endpoints are also given on request to anyone who asks: write to info@mintid.net and say what you are building. The faucet answers POST /v1/faucet with the testnet address to fund and returns the transaction hash; GET /v1/faucet/terms returns the testnet terms.

The chain identifier changes at every reset: read it, and the issuer and verifier ids, from the verifier’s status read rather than copying them from anywhere.

The sandbox journey. Against the testnet’s issuer you open a KYC session and choose its outcome, take an identity credential offer for the approved session, mint, renew and revoke bounded agents for it, revoke the identity credential and watch its agents follow, and, on the classical seller rail, create a seller attestation and move its status. On the public testnet these routes need no operator token, so the whole journey runs on nothing but what you created; the lists, the probes, the emergency root and the consoles stay with the operator, as on any deployment. The issuer’s integration guide — its public routes, the request bodies and how a session’s outcome is chosen — is given on request: write to info@mintid.net, say what you are building, and it is yours. Everything else is published here: the contract, the SDKs, the reason codes, the testnet’s parameters and terms, and the revocation trace.

C · Terms

Testnet terms

These four statements are the public testnet’s terms.

  1. Own denomination. The public testnet runs on its own denomination, utestmint. It is not the token of any other MintID chain, present or future.
  2. Free from the faucet. Anyone can obtain test tokens free of charge from the public faucet, within its rate limits. Test tokens are not for sale and have no value.
  3. No conversion. Test tokens cannot be transferred or converted to any other chain or asset. No snapshot, points programme or conversion promise attaches to them, and testing creates no claim.
  4. Reset. The public testnet, every balance on it included, may be reset at any time without notice.

The same four terms are part of the site terms; how a verifier reaches the testnet, and what the production chain answers instead, is on becoming a verifier.

D · See it fail

Demos that pass, then fail

Five numbered demos show a check pass and then fail on the public testnet, each with one command. They are in the main project, https://gitlab.com/mintid/mintid (test-harness/demos), and run from a clone of it:

MINTID_NETWORK=testnet uv run python -m test_harness.demos --list   # the five, with their run times
MINTID_NETWORK=testnet uv run python -m test_harness.demos 1        # run demo 1

The first run builds the Python bindings of the proof core (a Rust toolchain is needed). The demos take the testnet’s endpoints from the packages’ network registry and refuse any other profile. Every principal comes from the KYC sandbox, so nothing in them is about a person. Each demo prints its number, its expected run time and what you will see, then every answer as its reason code, its condition and the milliseconds since the demo started, and ends with its scope line:

testnet: nothing issued carries weight
  1. 01

    A backed agent, then the 10-second window

    about a minute · 56.8 s

    python -m test_harness.demos 1

    What you will see

    The agent proves it is human-backed and is accepted (accepted, the verifier’s answer in 2.3 s). The same proof handed back at once is refused nonce_replayed, and so is it after its window: the verifier checks the nonce (condition 3) before the deadline (condition 4). A fresh challenge, answered in time but delivered after its 10 seconds, is refused deadline_exceeded.

    testnet: nothing issued carries weight

  2. 02

    The kill switch

    about a minute · 66.2 s

    python -m test_harness.demos 2

    What you will see

    The holder pulls the agent’s kill switch: its self-revocation goes through the privacy relay and is recorded on the chain. The agent runtime is not touched (no process stopped, no key deleted): a copy of it, loaded from the custody record it held before the switch, keeps presenting. The verifier refuses it status_root_stale once the root carrying the revocation can be proven: 16.3 s after the chain recorded the self-revocation, one root after the one current at the switch (the bound is 245 s). Its witness refresh is refused (credential_revoked, 12.9 s after the recording): that refusal, not the first status_root_stale, shows the revocation.

    testnet: nothing issued carries weight

  3. 03

    An out-of-scope request

    under a minute · 46.4 s

    python -m test_harness.demos 3

    What you will see

    The agent is delegated one action, and an in-scope proof is accepted. A policy naming a value of no scope vocabulary is refused before any challenge exists (HTTP 422 policy_refused, scope_value_not_in_vocabulary). A policy naming an action of the vocabulary never delegated to the agent is refused by the agent’s own holder, so nothing leaves the client; a proof made for an in-scope challenge, handed in under that request, is refused by the verifier scope_axis_unprovable (condition 5).

    testnet: nothing issued carries weight

  4. 04

    The agent-to-agent handshake

    under half a minute · 24.2 s

    python -m test_harness.demos 4

    What you will see

    A responder requiring signed requests admits a backed agent, which calls its tool and is served. An anonymous bot is refused peer_signature_missing when it opens a session, then handshake_required on every call. Identified software, which signs its requests with no human behind it, gets the challenge and cannot answer: every call is handshake_required; its forged answer is refused (proof_invalid) and its session closed (handshake_closed). No gated responder runs on the testnet, so the responder runs on your machine; its gate asks the testnet’s sandbox verifier for every challenge and every decision.

    testnet: nothing issued carries weight

  5. 05

    Verify the release you are talking to

    a few seconds · 6.9 s

    python -m test_harness.demos 5

    What you will see

    The verifier’s build-info names its release; the release manifest from the public project’s tree at that tag is verified with the pinned release key, after the key is checked against its published fingerprint (cosign when it is installed, else the same ECDSA P-256 check in Python). The manifest names the release and the commit the verifier serves, and the registries’ digests of the Python packages the demos use, and of the release’s npm packages, match it. Then one byte of the manifest is changed, and its signature no longer verifies. The service images are not checked: they are not in a public registry.

    testnet: nothing issued carries weight

The condition printed is the one the closed vocabulary gives the code: the HTTP answer carries no condition, and on the testnet the decision record that names it is the operator’s. Most of a demo’s run time is its preparation: a sandbox principal approved, an agent minted, and a finalised root that commits the agent and its scope (in the recorded runs the first answer came 23 to 46 seconds after the start). Run times and figures are those of the recorded runs of 14 October 2026, against the release public-v2026-10-13.1, each as expected; a run of your own will give others. Each demo writes its record under test-harness/demos/records/: one JSON event per line, and a manifest built from those lines alone. A record holds reason codes and timings, with the testnet’s endpoints named by their role; it never holds a presentation, a proof or a pseudonym. It is the test harness’s record of its own run, not the verifier’s decision record.

testnet: nothing issued carries weight

E · Reproduce

The revocation trace times the guarantee against a running deployment

Reproduce the revocation trace. The revocation trace runs the revoked-agent sequence against a running deployment and times it, per revocation path: the issuer revokes an agent; the agent pulls its own kill switch through the privacy relay; a person’s identity credential is revoked and its agents follow; the issuer publishes an emergency root. During each one an adversarial agent keeps forcing proofs with the newest witness it can still obtain. The record shows, per path, the last accepted decision, the first refusal with the verifier’s reason code, the deny point the protocol guarantees, and the status root that carried the revocation, together with the verifier’s status before and after. A control agent that was never revoked shows whether a refusal is about the revocation or about the root a proof was made against.

The guarantee. An issuer revocation is refused by every verifier within the maximum root age plus a few seconds of clock tolerance — 185 seconds at the deployed values — and at once after an emergency root; an agent’s kill switch and a person-wide cascade within minutes, at bounds the record states for each path. The record also shows when this verifier actually refused in the run. That is an observation, faster than the bound and different from run to run; the bound is what you can rely on.

Run it from a clone of the main project, against the local stack:

uv run python test-harness/trace/revocation_trace.py --target local

Against the public testnet, with public access only (the emergency path and the verifier’s own log need the operator, and are marked as not read):

uv run python test-harness/trace/revocation_trace.py --target testnet