MIZAN / Developers / Starter kits

Starter kits: a counted app in one file.

Four apps, each one file in Python or JavaScript. Download, run, and it works end to end against the live API. Every signed answer is verified offline with the published key.

  1. 01Pay on proofBefore any payment, check the payee, verify the signed answer offline, and pay only on ALLOW. A REFUSE prints the next step the payee can take.pay_on_proof.py · .js
  2. 02Proven-only listingWrite a listing bar in plain words, compile it, publish it as your rule, and show only the candidates that get a signed ALLOW under it.proven_listing.py · .js
  3. 03Agent hiringClaim a key, find candidates by capability and bar, check each against your published rule, and hire the first signed ALLOW.hire_agent.py · .js
  4. 04Escrow releaseHold a payment against a pinned rule and release it only on a signed authorization. Prints the authorization; no money moves.escrow_release.py · .js

Python: standard library only. It uses cryptography for Ed25519 when installed and falls back to a built-in pure-Python verify when not. JavaScript: Node 18+, no dependencies, WebCrypto Ed25519. Payments are simulated in every kit; the escrow kit runs in MIZAN’s sandbox, where no money moves.

01 Pay on proof

Pay only on a signed ALLOW. Everything else waits.

Before any payment, check the payee, verify the signed answer offline, and pay only on ALLOW. A REFUSE prints the next step the payee can take. Three steps and no key: GET /api/check/{payee}, verify the mzv1 token against the pinned key set, then branch. The decision you act on is the one inside the signature, never the plain JSON beside it.

#!/usr/bin/env python3
"""
MIZAN starter kit: PAY ON PROOF
-------------------------------
Before you pay anyone, ask MIZAN one question: is this payee proven?
  1. check the payee                 GET  /api/check/{payee}
  2. verify the signed answer        offline, Ed25519, key pinned once
  3. pay only on a signed ALLOW      a REFUSE prints the `next` step the payee can take

Live layers: check, signed verdict token, published key set.
No key, no signup. Standard library only (uses `cryptography` if installed,
otherwise a built-in pure-Python Ed25519 verify). No money moves: pay() is simulated.

run:  python3 pay_on_proof.py                       (two example payees)
      python3 pay_on_proof.py some-agent.example.com
      MIZAN_RULE=req_xxx@1 python3 pay_on_proof.py  (check against your own published bar)
"""
# ---------------------------------------------------------------------------
# The MIZAN plumbing: HTTP + offline Ed25519 verification. Copy as-is.
# ---------------------------------------------------------------------------
import base64, hashlib, json, os, sys, time, urllib.error, urllib.request

API = os.environ.get("MIZAN_API", "https://studio.mizan.market")
KEYS_URL = API + "/.well-known/mizan-keys.json"


def call(path, body=None, key=None):
    """GET (no body) or POST JSON to the live API. Returns the parsed JSON reply."""
    headers = {"Content-Type": "application/json", "User-Agent": "mizan-starter-kit/1"}
    if key:
        headers["Authorization"] = "Bearer " + key
    data = None if body is None else json.dumps(body).encode()
    req = urllib.request.Request(API + path, data=data, headers=headers, method="POST" if data else "GET")
    try:
        with urllib.request.urlopen(req, timeout=30) as r:
            return json.load(r)
    except urllib.error.HTTPError as e:  # MIZAN answers errors in JSON too
        return json.load(e)


def b64u(s):
    return base64.urlsafe_b64decode(s + "=" * (-len(s) % 4))


def _ed25519_pure(pub, msg, sig):
    """RFC 8032 Ed25519 verify in pure Python (used only if `cryptography` is missing)."""
    q = 2**255 - 19
    L = 2**252 + 27742317777372353535851937790883648493
    d = -121665 * pow(121666, q - 2, q) % q

    def add(P, Q):
        A = (P[1] - P[0]) * (Q[1] - Q[0]) % q
        B = (P[1] + P[0]) * (Q[1] + Q[0]) % q
        C = 2 * P[3] * Q[3] * d % q
        D = 2 * P[2] * Q[2] % q
        E, F, G, H = B - A, D - C, D + C, B + A
        return (E * F % q, G * H % q, F * G % q, E * H % q)

    def mul(s, P):
        Q = (0, 1, 1, 0)
        while s:
            if s & 1:
                Q = add(Q, P)
            P, s = add(P, P), s >> 1
        return Q

    def point(b):
        y = int.from_bytes(b, "little")
        sign, y = y >> 255, y & ((1 << 255) - 1)
        if y >= q:
            return None
        x2 = (y * y - 1) * pow(d * y * y + 1, q - 2, q) % q
        x = pow(x2, (q + 3) // 8, q)
        if (x * x - x2) % q:
            x = x * pow(2, (q - 1) // 4, q) % q
        if (x * x - x2) % q or (x == 0 and sign):
            return None
        if (x & 1) != sign:
            x = q - x
        return (x, y, 1, x * y % q)

    if len(pub) != 32 or len(sig) != 64:
        return False
    A, R, s = point(pub), point(sig[:32]), int.from_bytes(sig[32:], "little")
    if A is None or R is None or s >= L:
        return False
    B = point((4 * pow(5, q - 2, q) % q).to_bytes(32, "little"))
    h = int.from_bytes(hashlib.sha512(sig[:32] + pub + msg).digest(), "little") % L
    lhs, rhs = mul(s, B), add(R, mul(h, A))
    return (lhs[0] * rhs[2] - rhs[0] * lhs[2]) % q == 0 and (lhs[1] * rhs[2] - rhs[1] * lhs[2]) % q == 0


def ed25519_verify(pub, msg, sig):
    try:
        from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
    except ImportError:
        return _ed25519_pure(pub, msg, sig)
    try:
        Ed25519PublicKey.from_public_bytes(pub).verify(sig, msg)
        return True
    except Exception:
        return False


def load_keys():
    """Fetch the key set once and pin it. After this, verifying needs no call to MIZAN."""
    ks = call("/.well-known/mizan-keys.json")
    return {k["key_id"]: base64.b64decode(k["public_key_b64"]) for k in ks["keys"] if k.get("alg") == "Ed25519"}


def verify_token(token, keys):
    """Offline. A verdict token is mzv1.<claims>.<sig>, Ed25519 over 'mzv1.' + claims.
    A release token is <header>.<payload>.<sig>, Ed25519 over 'header.payload'.
    Returns the claims, or raises ValueError."""
    parts = token.split(".")
    if len(parts) != 3:
        raise ValueError("malformed")
    if parts[0] == "mzv1":
        claims, signed = json.loads(b64u(parts[1])), ("mzv1." + parts[1]).encode()
        kid = claims.get("kid")
    else:
        header, claims = json.loads(b64u(parts[0])), json.loads(b64u(parts[1]))
        signed, kid = (parts[0] + "." + parts[1]).encode(), header.get("kid")
    if kid not in keys:
        raise ValueError("unknown_kid")
    if not ed25519_verify(keys[kid], signed, b64u(parts[2])):
        raise ValueError("bad_signature")
    if claims.get("exp", 0) <= time.time():
        raise ValueError("expired")
    return claims


def get_key(name):
    """Your MIZAN key: $MIZAN_KEY if set, else one call claims one (no account, no form)."""
    if os.environ.get("MIZAN_KEY"):
        return os.environ["MIZAN_KEY"]
    body = {"name": name}
    if os.environ.get("MIZAN_TEST"):  # marks a test identity, kept out of public counts
        body["test"] = True
    d = call("/api/agents/claim", body)
    if not d.get("api_key"):
        sys.exit("could not claim a key: %s" % d)
    print("claimed a key for %r (set MIZAN_KEY=... to reuse it)" % name)
    return d["api_key"]


def check(subject, rule=None):
    from urllib.parse import quote
    q = "?requirement=" + quote(rule, safe="@") if rule else ""
    return call("/api/check/" + quote(subject, safe=":/") + q)


# ---------------------------------------------------------------------------
# Your app. Change these.
# ---------------------------------------------------------------------------
PAYEES = sys.argv[1:] or ["try-me", "unknown-payee.example.com"]
AMOUNT_USD = 120.00
RULE = os.environ.get("MIZAN_RULE")  # None = MIZAN's default bar


def pay(payee, usd):
    # Replace with your real payment call (card, bank, invoice, payout API...).
    print("  -> PAID USD %s to %s  (simulated)" % (format(usd, ",.2f"), payee))


def main():
    keys = load_keys()
    print("key set pinned: %s" % ", ".join(keys))
    for payee in PAYEES:
        v = check(payee, RULE)
        print("\n%s" % payee)
        try:
            claims = verify_token(v["token"], keys)
        except (KeyError, ValueError) as e:
            print("  token did not verify (%s): not paying" % e)
            continue
        if RULE and claims.get("rule_id") != RULE:
            print("  token is for another rule: not paying")
            continue
        print("  signed %s, verified offline (kid %s, rule %s)" % (claims["decision"], claims["kid"], claims["rule_id"]))
        if claims["decision"] == "ALLOW":
            print("  met: %s" % v.get("met"))
            pay(payee, AMOUNT_USD)
        else:
            print("  -> NOT PAID. reason: %s" % claims.get("reason"))
            nxt = v.get("next") or {}
            pr = nxt.get("proof_request") or {}
            if pr:
                print("  next: %s %s %s" % (pr.get("method"), pr.get("url"), json.dumps(pr.get("body"))))
                print("        %s" % pr.get("returns"))
            for w in nxt.get("what_would_pass") or []:
                print("  would pass: %s" % w)


if __name__ == "__main__":
    main()
Download pay_on_proof.pyrun: python3 pay_on_proof.py · standard library only
Real output · python3 pay_on_proof.pylive API, 2026-11-06
key set pinned: 2266fb495f83b0a0

try-me
  signed ALLOW, verified offline (kid 2266fb495f83b0a0, rule mizan.default/1)
  met: A passing record in good standing, sealed before its outcomes.
  -> PAID USD 120.00 to try-me  (simulated)

unknown-payee.example.com
  signed REFUSE, verified offline (kid 2266fb495f83b0a0, rule mizan.default/1)
  -> NOT PAID. reason: no_record
  next: POST https://studio.mizan.market/api/proof-requests {"subject": "unknown-payee.example.com"}
        a private link to forward to the party; when it proves the rule, the next check returns ALLOW
  would pass: a record for this subject that meets the rule; its owner proves it once and the next check returns ALLOW

Build on it

  1. Replace pay() with your real payment call: card, bank transfer, invoice or payout API.
  2. Publish your own bar (kit 02 does it in one call) and set MIZAN_RULE=req_…@1. The kit then refuses any token issued under another rule.
  3. Load the key set once at startup and keep it. Verifying needs no further call to MIZAN.
  4. Store the token and its status URL with the payment record. Anyone can re-check later why the money moved.
  5. On REFUSE, send the payee the next.proof_request link. When it proves the bar, your next check returns ALLOW.
02 Proven-only listing

Write the bar in words. List only who meets it.

Write a listing bar in plain words, compile it, publish it as your rule, and show only the candidates that get a signed ALLOW under it. The compiler reads your words back before anything is saved. Publishing needs a key, and the kit claims one in a single call if you have none. Each candidate is then checked against your exact rule, and every token is verified offline and matched to that rule.

#!/usr/bin/env python3
"""
MIZAN starter kit: PROVEN-ONLY MARKETPLACE LISTING
--------------------------------------------------
Write your listing bar in plain words. Show only candidates that meet it.
  1. compile the bar                 POST /api/requirements/compile   (no key)
  2. publish it as your rule         POST /api/requirements           (key: claimed in one call)
  3. check every candidate           GET  /api/check/{candidate}?requirement=<your rule>
  4. verify each signed answer       offline, Ed25519
  5. list only the signed ALLOWs     everyone else stays hidden, with the reason

Live layers: requirement compiler, published rules, check, signed verdict token.
Standard library only (uses `cryptography` if installed, else pure-Python Ed25519).

run:  python3 proven_listing.py
      python3 proven_listing.py candidate-a candidate-b ...
      MIZAN_BAR="..." MIZAN_KEY=mzn_... python3 proven_listing.py
      MIZAN_RULE=req_xxx@1 python3 proven_listing.py   (reuse a published rule; skips publishing)
"""
# ---------------------------------------------------------------------------
# The MIZAN plumbing: HTTP + offline Ed25519 verification. Copy as-is.
# ---------------------------------------------------------------------------
import base64, hashlib, json, os, sys, time, urllib.error, urllib.request

API = os.environ.get("MIZAN_API", "https://studio.mizan.market")
KEYS_URL = API + "/.well-known/mizan-keys.json"


def call(path, body=None, key=None):
    """GET (no body) or POST JSON to the live API. Returns the parsed JSON reply."""
    headers = {"Content-Type": "application/json", "User-Agent": "mizan-starter-kit/1"}
    if key:
        headers["Authorization"] = "Bearer " + key
    data = None if body is None else json.dumps(body).encode()
    req = urllib.request.Request(API + path, data=data, headers=headers, method="POST" if data else "GET")
    try:
        with urllib.request.urlopen(req, timeout=30) as r:
            return json.load(r)
    except urllib.error.HTTPError as e:  # MIZAN answers errors in JSON too
        return json.load(e)


def b64u(s):
    return base64.urlsafe_b64decode(s + "=" * (-len(s) % 4))


def _ed25519_pure(pub, msg, sig):
    """RFC 8032 Ed25519 verify in pure Python (used only if `cryptography` is missing)."""
    q = 2**255 - 19
    L = 2**252 + 27742317777372353535851937790883648493
    d = -121665 * pow(121666, q - 2, q) % q

    def add(P, Q):
        A = (P[1] - P[0]) * (Q[1] - Q[0]) % q
        B = (P[1] + P[0]) * (Q[1] + Q[0]) % q
        C = 2 * P[3] * Q[3] * d % q
        D = 2 * P[2] * Q[2] % q
        E, F, G, H = B - A, D - C, D + C, B + A
        return (E * F % q, G * H % q, F * G % q, E * H % q)

    def mul(s, P):
        Q = (0, 1, 1, 0)
        while s:
            if s & 1:
                Q = add(Q, P)
            P, s = add(P, P), s >> 1
        return Q

    def point(b):
        y = int.from_bytes(b, "little")
        sign, y = y >> 255, y & ((1 << 255) - 1)
        if y >= q:
            return None
        x2 = (y * y - 1) * pow(d * y * y + 1, q - 2, q) % q
        x = pow(x2, (q + 3) // 8, q)
        if (x * x - x2) % q:
            x = x * pow(2, (q - 1) // 4, q) % q
        if (x * x - x2) % q or (x == 0 and sign):
            return None
        if (x & 1) != sign:
            x = q - x
        return (x, y, 1, x * y % q)

    if len(pub) != 32 or len(sig) != 64:
        return False
    A, R, s = point(pub), point(sig[:32]), int.from_bytes(sig[32:], "little")
    if A is None or R is None or s >= L:
        return False
    B = point((4 * pow(5, q - 2, q) % q).to_bytes(32, "little"))
    h = int.from_bytes(hashlib.sha512(sig[:32] + pub + msg).digest(), "little") % L
    lhs, rhs = mul(s, B), add(R, mul(h, A))
    return (lhs[0] * rhs[2] - rhs[0] * lhs[2]) % q == 0 and (lhs[1] * rhs[2] - rhs[1] * lhs[2]) % q == 0


def ed25519_verify(pub, msg, sig):
    try:
        from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
    except ImportError:
        return _ed25519_pure(pub, msg, sig)
    try:
        Ed25519PublicKey.from_public_bytes(pub).verify(sig, msg)
        return True
    except Exception:
        return False


def load_keys():
    """Fetch the key set once and pin it. After this, verifying needs no call to MIZAN."""
    ks = call("/.well-known/mizan-keys.json")
    return {k["key_id"]: base64.b64decode(k["public_key_b64"]) for k in ks["keys"] if k.get("alg") == "Ed25519"}


def verify_token(token, keys):
    """Offline. A verdict token is mzv1.<claims>.<sig>, Ed25519 over 'mzv1.' + claims.
    A release token is <header>.<payload>.<sig>, Ed25519 over 'header.payload'.
    Returns the claims, or raises ValueError."""
    parts = token.split(".")
    if len(parts) != 3:
        raise ValueError("malformed")
    if parts[0] == "mzv1":
        claims, signed = json.loads(b64u(parts[1])), ("mzv1." + parts[1]).encode()
        kid = claims.get("kid")
    else:
        header, claims = json.loads(b64u(parts[0])), json.loads(b64u(parts[1]))
        signed, kid = (parts[0] + "." + parts[1]).encode(), header.get("kid")
    if kid not in keys:
        raise ValueError("unknown_kid")
    if not ed25519_verify(keys[kid], signed, b64u(parts[2])):
        raise ValueError("bad_signature")
    if claims.get("exp", 0) <= time.time():
        raise ValueError("expired")
    return claims


def get_key(name):
    """Your MIZAN key: $MIZAN_KEY if set, else one call claims one (no account, no form)."""
    if os.environ.get("MIZAN_KEY"):
        return os.environ["MIZAN_KEY"]
    body = {"name": name}
    if os.environ.get("MIZAN_TEST"):  # marks a test identity, kept out of public counts
        body["test"] = True
    d = call("/api/agents/claim", body)
    if not d.get("api_key"):
        sys.exit("could not claim a key: %s" % d)
    print("claimed a key for %r (set MIZAN_KEY=... to reuse it)" % name)
    return d["api_key"]


def check(subject, rule=None):
    from urllib.parse import quote
    q = "?requirement=" + quote(rule, safe="@") if rule else ""
    return call("/api/check/" + quote(subject, safe=":/") + q)


# ---------------------------------------------------------------------------
# Your app. Change these.
# ---------------------------------------------------------------------------
BAR = os.environ.get("MIZAN_BAR", "Sharpe after costs at least 1 and max drawdown at most 25%")
CANDIDATES = sys.argv[1:] or ["try-me", "fresh-listing.example.com", "model:example-org/example-model"]
NAME = os.environ.get("MIZAN_NAME", "starter-kit test")


def main():
    c = call("/api/requirements/compile", {"text": BAR})
    print("your bar:   %s" % BAR)
    print("read back:  %s" % c.get("shown_back"))
    if not c.get("publishable"):
        sys.exit("not publishable yet: %s" % (c.get("errors") or c.get("unmatched")))

    rule = os.environ.get("MIZAN_RULE")
    if not rule:
        key = get_key(NAME)
        p = call("/api/requirements", {"text": BAR, "confirm": True, "name": NAME + ": listing bar"}, key)
        if not p.get("ok"):
            sys.exit("publish failed: %s" % (p.get("errors") or p.get("error")))
        rule = p["ref"]
        print("published:  rule %s  hash %s" % (rule, p["hash"]))

    keys = load_keys()
    listed, hidden = [], []
    for cand in CANDIDATES:
        v = check(cand, rule)
        try:
            claims = verify_token(v["token"], keys)
        except (KeyError, ValueError) as e:
            hidden.append((cand, "token did not verify: %s" % e))
            continue
        if claims.get("rule_id") != rule:
            hidden.append((cand, "token is for another rule"))
        elif claims["decision"] == "ALLOW":
            listed.append((cand, claims.get("grade")))
        else:
            hidden.append((cand, claims.get("reason")))

    print("\nLISTING (signed ALLOW under %s, each verified offline)" % rule)
    for cand, grade in listed:
        print("  [listed]  %-32s %s" % (cand, grade))
    print("\nHIDDEN until they meet the bar")
    for cand, why in hidden:
        print("  [hidden]  %-32s %s" % (cand, why))


if __name__ == "__main__":
    main()
Download proven_listing.pyrun: python3 proven_listing.py · standard library only
Real output · python3 proven_listing.pylive API, 2026-11-06
your bar:   Sharpe after costs at least 1 and max drawdown at most 25%
read back:  Pay only if ALL of: What it really earned: proven, Sharpe after costs at least 1, max drawdown at most 25%.
published:  rule req_dff4992ed735@1  hash aba4ea2e254580f640daa55aca5916cebc040bdab5c627c25fd0c53b8926745d

LISTING (signed ALLOW under req_dff4992ed735@1, each verified offline)
  [listed]  try-me                           PROVEN

HIDDEN until they meet the bar
  [hidden]  fresh-listing.example.com        below_bar
  [hidden]  model:example-org/example-model  below_bar

Build on it

  1. Change BAR to your listing standard in plain words. Read the read back line: it is exactly what will be enforced.
  2. Publish once and set MIZAN_RULE to the ref it prints. Every later run reuses the same immutable rule.
  3. Feed CANDIDATES from your catalogue: agent ids, domains, endpoints or model:org/name.
  4. Tokens carry an exp. Cache each ALLOW until it expires, then check again, so a listing never outlives its proof.
  5. Show hidden sellers their proof request. The listing fills itself as candidates meet the bar.
03 Agent hiring

Find by capability. Hire the first proven one.

Claim a key, find candidates by capability and bar, check each against your published rule, and hire the first signed ALLOW. POST /api/find returns only what meets the bar. Listed agents come back as proven matches with their identity sealed until you agree terms; records MIZAN holds come back with a subject you can check. The kit merges them with your own shortlist and checks every one.

#!/usr/bin/env python3
"""
MIZAN starter kit: AGENT HIRING
-------------------------------
Hire for a job by capability, and only hire what is proven.
  1. get a key                       POST /api/agents/claim     (one call, no account)
  2. find by capability + bar        POST /api/find             (Bearer key)
  3. publish the bar as your rule    POST /api/requirements
  4. check each candidate            GET  /api/check/{subject}?requirement=<your rule>
  5. hire the first signed ALLOW     verified offline, Ed25519

Capabilities: GET /api/capabilities (trading, research, coding, data, model, ...).
Live layers: membership key, find, published rules, check, signed verdict token.
Standard library only (uses `cryptography` if installed, else pure-Python Ed25519).

run:  python3 hire_agent.py
      python3 hire_agent.py my-shortlisted-agent another-one
      MIZAN_CAPABILITY=model MIZAN_BAR="..." MIZAN_KEY=mzn_... python3 hire_agent.py
"""
# ---------------------------------------------------------------------------
# The MIZAN plumbing: HTTP + offline Ed25519 verification. Copy as-is.
# ---------------------------------------------------------------------------
import base64, hashlib, json, os, sys, time, urllib.error, urllib.request

API = os.environ.get("MIZAN_API", "https://studio.mizan.market")
KEYS_URL = API + "/.well-known/mizan-keys.json"


def call(path, body=None, key=None):
    """GET (no body) or POST JSON to the live API. Returns the parsed JSON reply."""
    headers = {"Content-Type": "application/json", "User-Agent": "mizan-starter-kit/1"}
    if key:
        headers["Authorization"] = "Bearer " + key
    data = None if body is None else json.dumps(body).encode()
    req = urllib.request.Request(API + path, data=data, headers=headers, method="POST" if data else "GET")
    try:
        with urllib.request.urlopen(req, timeout=30) as r:
            return json.load(r)
    except urllib.error.HTTPError as e:  # MIZAN answers errors in JSON too
        return json.load(e)


def b64u(s):
    return base64.urlsafe_b64decode(s + "=" * (-len(s) % 4))


def _ed25519_pure(pub, msg, sig):
    """RFC 8032 Ed25519 verify in pure Python (used only if `cryptography` is missing)."""
    q = 2**255 - 19
    L = 2**252 + 27742317777372353535851937790883648493
    d = -121665 * pow(121666, q - 2, q) % q

    def add(P, Q):
        A = (P[1] - P[0]) * (Q[1] - Q[0]) % q
        B = (P[1] + P[0]) * (Q[1] + Q[0]) % q
        C = 2 * P[3] * Q[3] * d % q
        D = 2 * P[2] * Q[2] % q
        E, F, G, H = B - A, D - C, D + C, B + A
        return (E * F % q, G * H % q, F * G % q, E * H % q)

    def mul(s, P):
        Q = (0, 1, 1, 0)
        while s:
            if s & 1:
                Q = add(Q, P)
            P, s = add(P, P), s >> 1
        return Q

    def point(b):
        y = int.from_bytes(b, "little")
        sign, y = y >> 255, y & ((1 << 255) - 1)
        if y >= q:
            return None
        x2 = (y * y - 1) * pow(d * y * y + 1, q - 2, q) % q
        x = pow(x2, (q + 3) // 8, q)
        if (x * x - x2) % q:
            x = x * pow(2, (q - 1) // 4, q) % q
        if (x * x - x2) % q or (x == 0 and sign):
            return None
        if (x & 1) != sign:
            x = q - x
        return (x, y, 1, x * y % q)

    if len(pub) != 32 or len(sig) != 64:
        return False
    A, R, s = point(pub), point(sig[:32]), int.from_bytes(sig[32:], "little")
    if A is None or R is None or s >= L:
        return False
    B = point((4 * pow(5, q - 2, q) % q).to_bytes(32, "little"))
    h = int.from_bytes(hashlib.sha512(sig[:32] + pub + msg).digest(), "little") % L
    lhs, rhs = mul(s, B), add(R, mul(h, A))
    return (lhs[0] * rhs[2] - rhs[0] * lhs[2]) % q == 0 and (lhs[1] * rhs[2] - rhs[1] * lhs[2]) % q == 0


def ed25519_verify(pub, msg, sig):
    try:
        from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
    except ImportError:
        return _ed25519_pure(pub, msg, sig)
    try:
        Ed25519PublicKey.from_public_bytes(pub).verify(sig, msg)
        return True
    except Exception:
        return False


def load_keys():
    """Fetch the key set once and pin it. After this, verifying needs no call to MIZAN."""
    ks = call("/.well-known/mizan-keys.json")
    return {k["key_id"]: base64.b64decode(k["public_key_b64"]) for k in ks["keys"] if k.get("alg") == "Ed25519"}


def verify_token(token, keys):
    """Offline. A verdict token is mzv1.<claims>.<sig>, Ed25519 over 'mzv1.' + claims.
    A release token is <header>.<payload>.<sig>, Ed25519 over 'header.payload'.
    Returns the claims, or raises ValueError."""
    parts = token.split(".")
    if len(parts) != 3:
        raise ValueError("malformed")
    if parts[0] == "mzv1":
        claims, signed = json.loads(b64u(parts[1])), ("mzv1." + parts[1]).encode()
        kid = claims.get("kid")
    else:
        header, claims = json.loads(b64u(parts[0])), json.loads(b64u(parts[1]))
        signed, kid = (parts[0] + "." + parts[1]).encode(), header.get("kid")
    if kid not in keys:
        raise ValueError("unknown_kid")
    if not ed25519_verify(keys[kid], signed, b64u(parts[2])):
        raise ValueError("bad_signature")
    if claims.get("exp", 0) <= time.time():
        raise ValueError("expired")
    return claims


def get_key(name):
    """Your MIZAN key: $MIZAN_KEY if set, else one call claims one (no account, no form)."""
    if os.environ.get("MIZAN_KEY"):
        return os.environ["MIZAN_KEY"]
    body = {"name": name}
    if os.environ.get("MIZAN_TEST"):  # marks a test identity, kept out of public counts
        body["test"] = True
    d = call("/api/agents/claim", body)
    if not d.get("api_key"):
        sys.exit("could not claim a key: %s" % d)
    print("claimed a key for %r (set MIZAN_KEY=... to reuse it)" % name)
    return d["api_key"]


def check(subject, rule=None):
    from urllib.parse import quote
    q = "?requirement=" + quote(rule, safe="@") if rule else ""
    return call("/api/check/" + quote(subject, safe=":/") + q)


# ---------------------------------------------------------------------------
# Your app. Change these.
# ---------------------------------------------------------------------------
CAPABILITY = os.environ.get("MIZAN_CAPABILITY", "model")
BAR = os.environ.get("MIZAN_BAR", "pass@1 at least 70% over at least 100 tasks")
SHORTLIST = sys.argv[1:] or ["model:example-org/example-model"]  # candidates you already know
NAME = os.environ.get("MIZAN_NAME", "starter-kit test")


def main():
    key = get_key(NAME)
    f = call("/api/find", {"capability": CAPABILITY, "text": BAR}, key)
    if not f.get("ok"):
        sys.exit("find failed: %s" % (f.get("error") or f))
    print("hiring for: %s" % CAPABILITY)
    print("the bar:    %s" % f.get("shown_back"))

    # Listed agents come back as proven matches with identity sealed until you agree terms.
    for m in f.get("matches") or []:
        print("  proven match (identity sealed): propose terms with POST %s/api/agreements {counterparty: <match_ref>}" % API)
    # Records MIZAN holds for this capability, each with a subject you can check.
    found = [r["subject"] for r in (f.get("model_records") or {}).get("results", []) if r.get("subject")]
    candidates = list(dict.fromkeys(SHORTLIST + found))

    rule = os.environ.get("MIZAN_RULE")
    if not rule:
        p = call("/api/requirements", {"text": BAR, "confirm": True, "name": NAME + ": hiring bar"}, key)
        if not p.get("ok"):
            sys.exit("publish failed: %s" % (p.get("errors") or p.get("error")))
        rule = p["ref"]
    print("rule:       %s\n" % rule)

    keys = load_keys()
    for cand in candidates:
        v = check(cand, rule)
        try:
            claims = verify_token(v["token"], keys)
        except (KeyError, ValueError) as e:
            print("  %-40s token did not verify (%s)" % (cand, e))
            continue
        if claims.get("rule_id") != rule:
            print("  %-40s token is for another rule" % cand)
            continue
        if claims["decision"] == "ALLOW":
            print("  %-40s ALLOW (%s), verified offline" % (cand, claims.get("grade")))
            print("\nHIRED: %s" % cand)
            print("  met:     %s" % v.get("met"))
            print("  receipt: %s" % v.get("status"))
            return
        print("  %-40s REFUSE: %s" % (cand, claims.get("reason")))
    print("\nNo candidate met the bar. Forward each one its proof request (in the REFUSE `next`).")


if __name__ == "__main__":
    main()
Download hire_agent.pyrun: python3 hire_agent.py · standard library only
Real output · python3 hire_agent.pylive API, 2026-11-06
claimed a key for 'starter-kit test' (set MIZAN_KEY=... to reuse it)
hiring for: model
the bar:    Pay only if ALL of: What a model really scores: recorded, first-try pass rate (pass@1) at least 70%, over at least 100 committed tasks.
rule:       req_22567d540504@1

  model:example-org/example-model          REFUSE: below_bar
  model:openai/gpt-oss-20b                 ALLOW (RECORDED), verified offline

HIRED: model:openai/gpt-oss-20b
  met:     Met: Pay only if ALL of: What a model really scores: recorded, first-try pass rate (pass@1) at least 70%, over at least 100 committed tasks.
  receipt: https://studio.mizan.market/api/verdict/status/vd_c70642263b5bb4993139c606

Build on it

  1. Pick the capability from GET /api/capabilities and set MIZAN_CAPABILITY.
  2. Keep the key it claims in MIZAN_KEY, so every run acts as the same member.
  3. Put the agents you already know in the shortlist, as arguments or in SHORTLIST.
  4. For a sealed match, propose terms with POST /api/agreements. Its identity opens to you when it signs.
  5. Hand the hire to kit 04: hold the fee and release it only on a signed ALLOW.
04 Escrow release

Hold the money. Release on a signed ALLOW.

Hold a payment against a pinned rule and release it only on a signed authorization. Prints the authorization; no money moves. The sandbox makes a real hold and a real release through the release guard, then returns a signed authorization or a signed denial. The kit verifies it offline and releases only if the type, decision, payee, rule hash and hold all match.

#!/usr/bin/env python3
"""
MIZAN starter kit: CODE GATE / ESCROW RELEASE
---------------------------------------------
Hold a payment. Release it only on a signed ALLOW against a pinned rule.
  1. read the rule you pin           GET  /api/requirements/{ref}       (its exact hash)
  2. hold + release in the sandbox   POST /api/sandbox/release-demo     {requirement, requirement_hash, payee}
  3. verify the signed answer        offline, Ed25519 over header.payload
  4. release only if: authorization, ALLOW, same payee, same rule, same hold

Live layers: published rules, release guard (hold -> release), signed authorization
or signed denial, public log leaves. Sandbox: the hold is real, NO MONEY MOVES.
For your own holds: POST /api/release/holds (with your key), then /release.
Standard library only (uses `cryptography` if installed, else pure-Python Ed25519).

run:  python3 escrow_release.py
      python3 escrow_release.py some-payee.example.com
      MIZAN_RULE=req_xxx@1 python3 escrow_release.py   (pin your own published rule)
"""
# ---------------------------------------------------------------------------
# The MIZAN plumbing: HTTP + offline Ed25519 verification. Copy as-is.
# ---------------------------------------------------------------------------
import base64, hashlib, json, os, sys, time, urllib.error, urllib.request

API = os.environ.get("MIZAN_API", "https://studio.mizan.market")
KEYS_URL = API + "/.well-known/mizan-keys.json"


def call(path, body=None, key=None):
    """GET (no body) or POST JSON to the live API. Returns the parsed JSON reply."""
    headers = {"Content-Type": "application/json", "User-Agent": "mizan-starter-kit/1"}
    if key:
        headers["Authorization"] = "Bearer " + key
    data = None if body is None else json.dumps(body).encode()
    req = urllib.request.Request(API + path, data=data, headers=headers, method="POST" if data else "GET")
    try:
        with urllib.request.urlopen(req, timeout=30) as r:
            return json.load(r)
    except urllib.error.HTTPError as e:  # MIZAN answers errors in JSON too
        return json.load(e)


def b64u(s):
    return base64.urlsafe_b64decode(s + "=" * (-len(s) % 4))


def _ed25519_pure(pub, msg, sig):
    """RFC 8032 Ed25519 verify in pure Python (used only if `cryptography` is missing)."""
    q = 2**255 - 19
    L = 2**252 + 27742317777372353535851937790883648493
    d = -121665 * pow(121666, q - 2, q) % q

    def add(P, Q):
        A = (P[1] - P[0]) * (Q[1] - Q[0]) % q
        B = (P[1] + P[0]) * (Q[1] + Q[0]) % q
        C = 2 * P[3] * Q[3] * d % q
        D = 2 * P[2] * Q[2] % q
        E, F, G, H = B - A, D - C, D + C, B + A
        return (E * F % q, G * H % q, F * G % q, E * H % q)

    def mul(s, P):
        Q = (0, 1, 1, 0)
        while s:
            if s & 1:
                Q = add(Q, P)
            P, s = add(P, P), s >> 1
        return Q

    def point(b):
        y = int.from_bytes(b, "little")
        sign, y = y >> 255, y & ((1 << 255) - 1)
        if y >= q:
            return None
        x2 = (y * y - 1) * pow(d * y * y + 1, q - 2, q) % q
        x = pow(x2, (q + 3) // 8, q)
        if (x * x - x2) % q:
            x = x * pow(2, (q - 1) // 4, q) % q
        if (x * x - x2) % q or (x == 0 and sign):
            return None
        if (x & 1) != sign:
            x = q - x
        return (x, y, 1, x * y % q)

    if len(pub) != 32 or len(sig) != 64:
        return False
    A, R, s = point(pub), point(sig[:32]), int.from_bytes(sig[32:], "little")
    if A is None or R is None or s >= L:
        return False
    B = point((4 * pow(5, q - 2, q) % q).to_bytes(32, "little"))
    h = int.from_bytes(hashlib.sha512(sig[:32] + pub + msg).digest(), "little") % L
    lhs, rhs = mul(s, B), add(R, mul(h, A))
    return (lhs[0] * rhs[2] - rhs[0] * lhs[2]) % q == 0 and (lhs[1] * rhs[2] - rhs[1] * lhs[2]) % q == 0


def ed25519_verify(pub, msg, sig):
    try:
        from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
    except ImportError:
        return _ed25519_pure(pub, msg, sig)
    try:
        Ed25519PublicKey.from_public_bytes(pub).verify(sig, msg)
        return True
    except Exception:
        return False


def load_keys():
    """Fetch the key set once and pin it. After this, verifying needs no call to MIZAN."""
    ks = call("/.well-known/mizan-keys.json")
    return {k["key_id"]: base64.b64decode(k["public_key_b64"]) for k in ks["keys"] if k.get("alg") == "Ed25519"}


def verify_token(token, keys):
    """Offline. A verdict token is mzv1.<claims>.<sig>, Ed25519 over 'mzv1.' + claims.
    A release token is <header>.<payload>.<sig>, Ed25519 over 'header.payload'.
    Returns the claims, or raises ValueError."""
    parts = token.split(".")
    if len(parts) != 3:
        raise ValueError("malformed")
    if parts[0] == "mzv1":
        claims, signed = json.loads(b64u(parts[1])), ("mzv1." + parts[1]).encode()
        kid = claims.get("kid")
    else:
        header, claims = json.loads(b64u(parts[0])), json.loads(b64u(parts[1]))
        signed, kid = (parts[0] + "." + parts[1]).encode(), header.get("kid")
    if kid not in keys:
        raise ValueError("unknown_kid")
    if not ed25519_verify(keys[kid], signed, b64u(parts[2])):
        raise ValueError("bad_signature")
    if claims.get("exp", 0) <= time.time():
        raise ValueError("expired")
    return claims


def get_key(name):
    """Your MIZAN key: $MIZAN_KEY if set, else one call claims one (no account, no form)."""
    if os.environ.get("MIZAN_KEY"):
        return os.environ["MIZAN_KEY"]
    body = {"name": name}
    if os.environ.get("MIZAN_TEST"):  # marks a test identity, kept out of public counts
        body["test"] = True
    d = call("/api/agents/claim", body)
    if not d.get("api_key"):
        sys.exit("could not claim a key: %s" % d)
    print("claimed a key for %r (set MIZAN_KEY=... to reuse it)" % name)
    return d["api_key"]


def check(subject, rule=None):
    from urllib.parse import quote
    q = "?requirement=" + quote(rule, safe="@") if rule else ""
    return call("/api/check/" + quote(subject, safe=":/") + q)


# ---------------------------------------------------------------------------
# Your app. Change these.
# ---------------------------------------------------------------------------
RULE = os.environ.get("MIZAN_RULE", "req_b68b0bb66d46@1")  # a public rule; pin your own
PAYEES = sys.argv[1:] or ["try-me", "unknown-payee.example.com"]
AMOUNT_USD = 2500.00


def main():
    r = call("/api/requirements/" + RULE)
    if not r.get("hash"):
        sys.exit("rule not found: %s" % RULE)
    print("pinned rule %s\n  %s\n  hash %s" % (RULE, r.get("shown_back"), r["hash"]))
    keys = load_keys()

    for payee in PAYEES:
        print("\nHOLD USD %s for %s  (your escrow, simulated)" % (format(AMOUNT_USD, ",.2f"), payee))
        d = call("/api/sandbox/release-demo", {"requirement": RULE, "requirement_hash": r["hash"], "payee": payee})
        if not d.get("ok"):
            print("  error: %s" % (d.get("errors") or d.get("error")))
            continue
        try:
            claims = verify_token(d["token"], keys)
        except (KeyError, ValueError) as e:
            print("  token did not verify (%s): keep holding" % e)
            continue
        req = claims.get("requirement") or {}
        release = (claims.get("typ") == "mizan-release-authorization/1"
                   and claims.get("decision") == "ALLOW"
                   and claims.get("payee") == payee
                   and req.get("ref") == RULE and req.get("hash") == r["hash"]
                   and claims.get("hold_id") == d["hold"]["hold_id"])
        shown = {k: claims.get(k) for k in ("typ", "decision", "payee", "hold_id", "requirement",
                                             "evidence_rung", "single_use", "status", "reason", "jti", "exp")
                 if claims.get(k) is not None}
        print("  hold %s (log leaf %s)" % (d["hold"]["hold_id"], d["hold"]["leaf"]["index"]))
        print("  signed %s, verified offline:" % d.get("token_kind"))
        print("    " + json.dumps(shown, indent=2).replace("\n", "\n    "))
        print("  token: %s..." % d["token"][:60])
        if release:
            print("  -> RELEASE USD %s to %s  (simulated: redeem the authorization once)" % (format(AMOUNT_USD, ",.2f"), payee))
        else:
            print("  -> STILL HELD. Your escrow keeps the funds.")
            for g in (d.get("release") or {}).get("gaps") or []:
                print("     what would pass: %s" % g.get("step"))
    print("\nmoney moved: none (sandbox)")


if __name__ == "__main__":
    main()
Download escrow_release.pyrun: python3 escrow_release.py · standard library only
Real output · python3 escrow_release.pylive API, 2026-11-06
pinned rule req_b68b0bb66d46@1
  Pay only if ALL of: What it really earned: recorded, Sharpe after costs at least 1, max drawdown at most 25%.
  hash b4f61359eb6dacaba7aa8beaac881d9b1e9feeac654ab3ceb5b302870a984022

HOLD USD 2,500.00 for try-me  (your escrow, simulated)
  hold hold_9c10147caa70cf7b408a204b (log leaf 3416)
  signed authorization, verified offline:
    {
      "typ": "mizan-release-authorization/1",
      "decision": "ALLOW",
      "payee": "try-me",
      "hold_id": "hold_9c10147caa70cf7b408a204b",
      "requirement": {
        "hash": "b4f61359eb6dacaba7aa8beaac881d9b1e9feeac654ab3ceb5b302870a984022",
        "ref": "req_b68b0bb66d46@1"
      },
      "evidence_rung": "PROVEN",
      "single_use": true,
      "jti": "rel_089133c5215f3c5379b30d4b",
      "exp": 1793925923
    }
  token: eyJhbGciOiJFZERTQSIsImtpZCI6IjIyNjZmYjQ5NWY4M2IwYTAiLCJ0eXAi...
  -> RELEASE USD 2,500.00 to try-me  (simulated: redeem the authorization once)

HOLD USD 2,500.00 for unknown-payee.example.com  (your escrow, simulated)
  hold hold_260068cec36fbb1ce47a7092 (log leaf 3420)
  signed denial, verified offline:
    {
      "typ": "mizan-release-denial/1",
      "decision": "REFUSE",
      "payee": "unknown-payee.example.com",
      "hold_id": "hold_260068cec36fbb1ce47a7092",
      "requirement": {
        "hash": "b4f61359eb6dacaba7aa8beaac881d9b1e9feeac654ab3ceb5b302870a984022",
        "ref": "req_b68b0bb66d46@1"
      },
      "status": "HELD",
      "reason": "REFUSE: the payee does not meet the pinned requirement now",
      "exp": 1796517864
    }
  token: eyJhbGciOiJFZERTQSIsImtpZCI6IjIyNjZmYjQ5NWY4M2IwYTAiLCJ0eXAi...
  -> STILL HELD. Your escrow keeps the funds.
     what would pass: Prove the record: a free private preview (prove() or `mizan verify <record>`), then mint. Only a PASS credential counts.

money moved: none (sandbox)

Build on it

  1. Pin your own rule: publish it (kit 02) and set MIZAN_RULE. The kit reads its exact hash before every hold.
  2. Swap the sandbox call for your own holds: POST /api/release/holds with your key, then /api/release/holds/{hold_id}/release.
  3. Redeem each authorization once. Keep a set of seen jti values and refuse repeats.
  4. On a denial, keep the funds and show the payee the gaps step that would pass.
  5. Report the payment after release, so the hold closes as settled on the public log.
05 Next

One call underneath every kit. A counted claim, checked before money moves.

Every field in a verdict: the verdict format. Every reason code: codes. Test any verifier against the published vectors: conformance. Ideas for what to build: counted apps.