Chio/Docs
LOGIN · JOIN

Reputation & Passports

Carry an agent’s signed track record to operators that never saw its work, while each receiver decides what that record earns.

Concept chio@5f63e6e

On this page

A reputation travels only as far as its evidence can be checked. Chio scores an agent from receipts the scorer verified, an issuer signs that score as a credential, and the agent carries the credential to operators that never saw the work. Each step adds a signature, and none adds authority.

Verifying a passport establishes what an issuer signed and about which key. What work, scope, or budget that earns stays the receiver’s decision, written in the receiver’s own policy. Marketplace tiers are a separate mechanism, computed from feed deltas.

A scorecard counts only receipts it can verify

Chio’s local scorecard combines receipts, capability-lineage records, budget usage, and optional incident reports for a subject public key. Before it accepts a receipt into scoring, it checks the trusted kernel key, the receipt identifier, the signature, and the action hash. A record the scorer cannot verify does not count.

Local scorecardChoose a subject’s history.
boundary_pressure0.20× 0.90resource_stewardship0.10unknownleast_privilege0.15unknownhistory_depth0.10unknowntool_diversity0.05unknowndelegation_hygiene0.15unknownreliability0.15× 0.80incident_correlation0.10unknownccomposite0.857weight 0.3500.400.650.851probationarystandardtrustedelevated0.60standard · read, get, invoke500 invocations · 300 sboundary_pressure0.20resource_stewardship0.10least_privilege0.15history_depth0.10tool_diversity0.05delegation_hygiene0.15reliability0.15incident_correlation0.10ccomposite0.857 · weight 0.3500.400.650.851probationarystandardtrustedelevated0.60standard · 500 invocations · 300 sread, get, invoke

Probation caps the score before the tier lookup

A subject with fewer than 1,000 receipts or under 30 days of observed history is probationary, and its effective score is capped at 0.60. The same composite now selects standard: read, get, and invoke, 500 invocations, 300 seconds. Capabilities.

The eight local scorecard metrics at their default weights, the weighted mean over the known ones, and the score-to-tier lookup over the example policy hushspec-reputation.yaml. The metric values are illustrative; the example’s monetary ceilings and delegation depths are left out.Reputation Scoring

The scorecard measures pressure on authorization boundaries, use of granted resources, and delegation discipline, and it records how much history supports each figure. A missing input leaves its metric unknown, so a sparse history stays visible to whoever reads the score. Score your own fixer from the receipts your kernel signed:

Terminalbash
chio --json reputation local --agent fixer \
  | jq '{subjectKey, probationary, probationaryStatus, effectiveScore,
         composite: .scorecard.composite_score,
         effectiveWeightSum: .scorecard.effective_weight_sum}'
Output
{
  "subjectKey": "5a2d…e7c4",
  "probationary": true,
  "probationaryStatus": { "belowReceiptTarget": true, "belowDayTarget": false },
  "effectiveScore": 0.6,
  "composite": { "state": "known", "value": 0.857 },
  "effectiveWeightSum": 0.35
}

Two known metrics give a composite of 0.857 from 0.35 of the default weight. The fixer has fewer than 1,000 receipts, so it is probationary and its effective score is capped at 0.60. A score is reproducible only from the same subject, evidence corpus, configuration, evaluation time, and implementation; a receiver that holds those inputs can recompute it, and verifying a passport does not.

The eight metric families
MetricWhat it helps assess
Boundary pressure
How the agent’s recorded requests interact with authorization limits.
Resource stewardship
How the agent uses its granted resource budget.
Least privilege
How granted authority compares with authority used.
History depth
How much evidence supports the assessment.
Specialization
Which tools and operations occur in the history.
Delegation hygiene
How the agent structures delegated authority.
Reliability
What recorded execution outcomes show.
Incident correlation
What supplied incident reports associate with the agent.

An issuer signs the assessment; a passport carries it

An assessment passes through four roles, each responsible for a different check or record.

StepWhat it establishes
The scorer computes a scorecardMetrics over receipts it could verify, for one subject key.
An issuer signs a credentialSigned claims about that subject, a validity period, and references to the evidence.
The agent presents a passportA bundle of credentials for one subject DID. The credentials carry the signatures; the bundle itself has no separate signature field.
The receiver decidesWhich issuers it trusts and what authority, work, or budget it offers. Nothing in the passport makes that decision.

Sign the fixer’s scorecard with your issuer key and write the passport you will hand to other operators:

Terminalbash
chio passport create --agent fixer --signing-seed-file ./issuer.seed \
  --output ./passport-larkfield-export.json --validity-days 30
Output
wrote passport to ./passport-larkfield-export.json
subject:          did:chio:z6MkrT2…8wd
credential_count: 1
merkle_roots:     1
enterprise_provenance: 0
valid_until:      2026-10-05T06:16:56Z

Passport verification checks the bundle as a whole. It refuses a passport with no credentials, verifies each credential’s signature and time window, and requires every credential to name the passport’s subject. A passport cannot outlast the credentials inside it: its validUntil must fall at or before the earliest credential expiration.

Passport validityChoose a passport, then drag t.
passport verified
min⁡iei\min_i e_i
c1issuer σ1z6MkrT2…8wdSep 5Oct 5c2issuer σ2z6MkrT2…8wdSep 20Oct 20πpassportz6MkrT2…8wdvalidUntil Oct 5Sep 1Sep 15Oct 1Oct 15Oct 31t = Sep 28
passport verified
min⁡iei\min_i e_i
c1 issuer σ1 z6MkrT2…8wdSep 5Oct 5c2 issuer σ2 z6MkrT2…8wdSep 20Oct 20π passport z6MkrT2…8wdvalidUntil Oct 5Sep 1Oct 1Oct 31t = Sep 28
∣C∣≥1,si≤t≤ei,sub(ci)=sub(π),π.validUntil≤min⁡iei\begin{aligned} &|C| \ge 1, \qquad s_i \le t \le e_i, \\ &\mathrm{sub}(c_i) = \mathrm{sub}(\pi), \qquad \pi.\mathit{validUntil} \le \min_i e_i \end{aligned}

A passport ends no later than its earliest credential

The passport’s validUntil is Oct 5, the earlier of its two credential expirations, so it cannot outlast what it carries. At the verification time t, each credential’s issuer signature and window are checked, and each must name the passport’s subject. Agent Passports.

Two issuer-signed credentials about the fixer and the passport that carries them, on a September to October 2026 axis. Signature verification is folded into each credential’s row; lifecycle status, verifier policy, and enterprise provenance are left out.Agent Passport guide

The history must belong to the key that presents it

The scorecard groups evidence by subject public key, and credential verification checks that this key agrees with the credential’s subject DID. An interactive presentation adds a holder-signed response to the verifier’s challenge, so the receiver learns that the presenter controls the subject key, not only that it holds the file:

Terminalbash
# your partner, as the verifier
chio passport challenge create --verifier kernel.halden.example --output ./challenge.json
# you, holding the fixer's subject key
chio passport challenge respond --input ./passport-larkfield-export.json \
  --challenge ./challenge.json --holder-seed-file ./fixer.seed --output ./response.json
# your partner
chio passport challenge verify --input ./response.json --challenge ./challenge.json
Output
presentation verified
subject:          did:chio:z6MkrT2…8wd
holder:           response signed by the subject key
verifier:         kernel.halden.example
issuer:           did:chio:z6Mkf3…Qp9
credential_count: 1
challenge:        consumed, 300 s lifetime

The challenge can also carry an issuer allowlist or a verifier policy, which the receiver applies before it relies on any claim. Workload identity describes the runtime behind a request, a separate dimension: a SPIFFE path does not become the scorecard’s grouping key. Keep the agent key, the workload identity, and receipt attribution consistent when assembling the evidence corpus.

A verified passport states what was signed

This passport was created from a local receipt corpus and signed with an issuer key. Its evidence lists one receipt and one lineage record; the receipt is uncheckpointed and the bundle carries no Merkle roots, so verification covers the credential’s signature and window, not checkpoint inclusion. After creating a passport from your receipt corpus, verify its bundle the same way:

Passport verification · captured outputtranscript
$ chio passport verify --input ./passport.json
passport verified
subject:          did:chio:4daeca6fd9edd85aaa143e9059f9395d457152127e2162896afe650a4391f851
passport_id:      b42ec4bb375f69d131be95bf1f05dd6018200314accd9ddfc03679e00d42cdf5
issuer:           did:chio:4cb5abf6ad79fbf5abbccafcc269d85cd2651ed4b885b5869f241aedf0a5ba29
issuer_count:     1
credential_count: 1
merkle_roots:     0
enterprise_provenance: 0
valid_until:      2026-10-05T06:16:56Z
exit 0

The verifier reports passport verified, the subject and issuer, one credential, and the validity deadline. Those results cover the embedded signed credentials and the bundle’s consistency. They do not establish that the issuer’s assessment predicts the agent’s future behavior.

When verification refuses, check the credential set and its issuer before adjusting a receiver’s trust policy. An empty credential set, for one, is rejected before any comparison runs.

Captured credential evidence and an empty-bundle refusal
Signed credential · evidence and prooftranscript
$ jq '.credentials[0] | {issuer, issuanceDate, expirationDate, evidence, proof}' ./passport.json
{
  "issuer": "did:chio:4cb5abf6ad79fbf5abbccafcc269d85cd2651ed4b885b5869f241aedf0a5ba29",
  "issuanceDate": "2026-09-05T06:16:56Z",
  "expirationDate": "2026-10-05T06:16:56Z",
  "evidence": {
    "query": {
      "until": 1788589016
    },
    "receiptCount": 1,
    "receiptIds": [
      "38d92b9b698aa09b3c9c5195dfb19d2ec530c15669aa5f74d56f92a82008ec0b"
    ],
    "checkpointRoots": [],
    "lineageRecords": 1,
    "uncheckpointedReceipts": 1
  },
  "proof": {
    "type": "Ed25519Signature2020",
    "created": "2026-09-05T06:16:56Z",
    "proofPurpose": "assertionMethod",
    "verificationMethod": "did:chio:4cb5abf6ad79fbf5abbccafcc269d85cd2651ed4b885b5869f241aedf0a5ba29#key-1",
    "proofValue": "f9625bcfc650ea984f856054de534df5b80b67e93765ce5b374ad869cb3351f31f064de0aaba9dc5f2d5e015f0132ab9d72247385c482eebf40007f40a625e09"
  }
}
exit 0
Empty credential set · captured refusaltranscript
$ chio --json --receipt-db ./receipts.db reputation compare \
    --subject-public-key bff663535a5cf58658cc38595d20dc4501f6dfc076ddf07e20571d413a3ceb5a \
    --passport ./no-credentials.json
{"code":"urn:chio:error:trust:passport-empty","message":"the passport carries no credential","context":{"domain":"trust","severity":"error","stability":"stable","string_code":"CHIO-TRUST-PASSPORT-EMPTY"},"suggested_fix":"create the passport from receipts with chio passport create, which writes at least one credential"}
exit 1

Marketplace tiers are regions over feed deltas

Marketplace reputation tiers use a different mechanism from the scorecard. A feed turns observations into a score delta, and the tier function evaluates the submitted deltas. A local scorecard does not become a feed delta by itself, and a delta does not carry a signature.

Reputation tiers as regions over the weakest and the strongest feed deltam = c: equal deltastier_0tier_1tier_2tier_30.300.500.750.9010.300.500.801weakest delta mcomposed score cfeed_a δ = 0.95feed_b δ = 0.86|F| =12distinct feed ids
c=min⁡(max⁡iδi, 1),m=min⁡iδi\htmlClass{role-call}{c} = \min(\max_i \htmlClass{role-call}{\delta_i},\, 1), \quad \htmlClass{role-call}{m} = \min_i \htmlClass{role-call}{\delta_i}
tier={3if c≥0.90∧m≥0.80∧∣F∣≥22else if c≥0.751else if c≥0.500otherwise\mathrm{tier} = \begin{cases} \htmlClass{role-seal}{3} & \text{if } \htmlClass{role-call}{c} \ge \htmlClass{role-grant}{0.90} \wedge \htmlClass{role-call}{m} \ge \htmlClass{role-grant}{0.80} \wedge \htmlClass{cor-parent}{|F|} \ge 2 \\ 2 & \text{else if } \htmlClass{role-call}{c} \ge \htmlClass{role-grant}{0.75} \\ 1 & \text{else if } \htmlClass{role-call}{c} \ge \htmlClass{role-grant}{0.50} \\ 0 & \text{otherwise} \end{cases}
c=0.95, m=0.86, ∣F∣=2  ⇒  tier_3\htmlClass{role-call}{c} = 0.95,\ \htmlClass{role-call}{m} = 0.86,\ \htmlClass{cor-parent}{|F|} = 2 \;\Rightarrow\; \htmlClass{role-seal}{\texttt{tier\_3}}
every tier 3 condition holds
Reputation tiers as regions over the weakest and the strongest feed deltatier_0tier_1tier_2tier_30.300.500.750.9010.300.500.801weakest delta mcomposed score cfeed_a 0.95feed_b 0.86|F| =12distinct feed idsc = 0.95, m = 0.86 ⇒ tier_3every tier 3 condition holds

Composed 0.95, weakest delta 0.86, 2 distinct feed identifiers: tier 3. every tier 3 condition holds.

c=min⁡(max⁡iδi, 1)m=min⁡iδitier 3⇐c≥0.90∧m≥0.80⇐ ∧∣F∣≥2else 2⇐c≥0.75else 1⇐c≥0.50else 0\begin{aligned} \htmlClass{role-call}{c} &= \min(\max_i \htmlClass{role-call}{\delta_i},\, 1) \\ \htmlClass{role-call}{m} &= \min_i \htmlClass{role-call}{\delta_i} \\[6pt] \htmlClass{role-seal}{\text{tier}\ 3} &\Leftarrow \htmlClass{role-call}{c} \ge \htmlClass{role-grant}{0.90} \wedge \htmlClass{role-call}{m} \ge \htmlClass{role-grant}{0.80} \\ &\phantom{\Leftarrow}\ \wedge \htmlClass{cor-parent}{|F|} \ge 2 \\ \text{else}\ 2 &\Leftarrow \htmlClass{role-call}{c} \ge \htmlClass{role-grant}{0.75} \\ \text{else}\ 1 &\Leftarrow \htmlClass{role-call}{c} \ge \htmlClass{role-grant}{0.50} \\ \text{else}\ 0 & \end{aligned}
In Rust · tier.rs:9826 lines
pub fn tier_from_deltas(deltas: &[ScoreDelta]) -> ReputationTier {
    let composed = match compose_deltas(deltas) {
        Some(value) => value,
        None => return ReputationTier::Tier0,
    };
    let per_feed_min = match min_delta(deltas) {
        Some(value) => value,
        None => return ReputationTier::Tier0,
    };

    if qualifies_for_tier_3(deltas, composed, per_feed_min) {
        ReputationTier::Tier3
    } else if composed >= TIER_2_THRESHOLD {
        ReputationTier::Tier2
    } else if composed >= TIER_1_THRESHOLD {
        ReputationTier::Tier1
    } else {
        ReputationTier::Tier0
    }
}
// …
fn qualifies_for_tier_3(deltas: &[ScoreDelta], composed: f64, per_feed_min: f64) -> bool {
    composed >= TIER_3_THRESHOLD
        && per_feed_min >= TIER_3_PER_FEED_THRESHOLD
        && distinct_feed_count(deltas) >= 2
}
Two illustrative feed deltas mapped by tier_from_deltas; feeds are counted by feed_id, not by the number of deltas. Distinct identifiers satisfy the composition condition; they do not show that the feeds are independent.

The composed score is the largest delta, capped at 1. A composed score of at least 0.50 reaches tier_1, and at least 0.75 reaches tier_2. The highest tier, tier_3, asks for more than a high score: a composed score of at least 0.90, a smallest delta of at least 0.80, and at least two distinct feed identifiers.

The per-feed floor is the tier function’s Sybil-resistance measure: every shipped feed must clear 0.80 independently, so a flood of arena rounds alone cannot promote a publisher past tier_2. With the distinct-feed count, one strong delta repeated from a single feed cannot reach the top tier.

Distinct identifiers establish a composition condition only. Deployment controls must establish that the feeds are independent and their observations sound. Reputation scoring documents the feed API and tier rules.

The receiver decides what authority to grant

A receiver verifies the presented credentials, checks which issuers it trusts, and judges whether the history covers the work in question. Your partner writes that judgment as a verifier policy and evaluates your fixer’s passport against it:

verifier-policy.yaml · your partner’syaml
issuerAllowlist: ["did:chio:z6Mkf3…Qp9"]
minCompositeScore: 0.7
minReceiptCount: 500
requireCheckpointCoverage: true
Terminalbash
chio passport evaluate --input ./passport-larkfield-export.json --policy ./verifier-policy.yaml
Output
passport evaluated
subject:             did:chio:z6MkrT2…8wd
issuer:              did:chio:z6Mkf3…Qp9
accepted:            false
matched_credentials: 0
credential_count:    1
valid_until:         2026-10-05T06:16:56Z
rejections:
  credential 0 (did:chio:z6Mkf3…Qp9):
    - receipt_count 212 is below required minimum 500
    - credential evidence has 3 uncheckpointed receipt(s)

The signatures verify and the composite clears 0.70, but the history is too short and partly uncheckpointed for this policy, so your partner offers nothing yet. The kernel does not derive authority from a passport score; an operator writes the rule that turns accepted credentials into a grant, and every operator keeps control of its own resources.

The rule can be as small as a table. Here is yours, for callers of the pricing service such as an outside buyer’s agent: its rows are the values of a passport’s optional trustTier field, each grant uses terms the kernel enforces, and the numbers are your choices.

Accepted trustTierGrant you issue
unverifiedNo grant until the agent presents further evidence.
attestedA 15-minute lifetime, max_total_cost of USD 5, and require_approval_above at USD 1.
verifiedA 1-hour lifetime, max_total_cost of USD 50, and require_approval_above at USD 10.
premierAn 8-hour lifetime, max_total_cost of USD 500, and require_approval_above at USD 100.

The issuing operator synthesizes trustTier from its compliance score and behavioral-anomaly signal, not from the feed composition above: below 300 of 1,000 is unverified, 300 reaches attested, 700 verified, and 900 premier, which an active anomaly holds back at verified. Issue the grant after the buyer’s passport verifies and its issuer is one you accept:

pricing.tspricing.pysrc/main.rs · in main
import { Computer, USD } from "@chio-protocol/sdk";

const project = await Computer.open("quickstart");
const pricing = await project.service("pricing", { tools: { quote: "src/pricing.py:quote" } });

const terms = {
  attested: { budget: USD(5), expiresIn: "15m" },
  verified: { budget: USD(50), expiresIn: "1h" },
  premier: { budget: USD(500), expiresIn: "8h" },
};
const tier = "verified"; // the trustTier of the buyer's accepted passport
const access = pricing.grant({ to: "did:chio:z6MkbY4…e1R", tools: ["quote"], ...terms[tier] });
console.log(access.describe());
Output
grant      cap-01ab…77d1, signed by your kernel
to         did:chio:z6MkbY4…e1R
allows     pricing.quote
budget     USD 50.00, USD 0.01 per call
expires    in 1 hour

From then on the kernel enforces the grant on every call: the token expires, spend stops at max_total_cost, and a call whose governed intent names an amount at or above the approval threshold needs a person’s signed approval. The reputation-priced autonomy entry in What You Can Build starts from this rule, and the Cognition Market supplies the separate mechanisms for governed delivery and payment.

Wallet interoperability and issuer migration

Chio implements OID4VCI credential issuance, OID4VP presentation, and SD-JWT projections for its supported credential profiles. Compatible wallets and verifiers must support those profiles and the requested disclosures. A projection exposes the selected claims; it does not transfer the full receipt corpus.

Cross-issuer migration requires the participating issuers and the receiving party to accept the migration and its trust configuration. Agent Passports covers issuance, presentation, lifecycle, and migration.

Present credentials and authorize work