Reputation & Passports
Carry an agent’s signed track record to operators that never saw its work, while each receiver decides what that record earns.
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.
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.
hushspec-reputation.yaml. The metric values are illustrative; the example’s monetary ceilings and delegation depths are left out.Reputation ScoringThe 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:
chio --json reputation local --agent fixer \
| jq '{subjectKey, probationary, probationaryStatus, effectiveScore,
composite: .scorecard.composite_score,
effectiveWeightSum: .scorecard.effective_weight_sum}'{
"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
| Metric | What 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.
| Step | What it establishes |
|---|---|
| The scorer computes a scorecard | Metrics over receipts it could verify, for one subject key. |
| An issuer signs a credential | Signed claims about that subject, a validity period, and references to the evidence. |
| The agent presents a passport | A bundle of credentials for one subject DID. The credentials carry the signatures; the bundle itself has no separate signature field. |
| The receiver decides | Which 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:
chio passport create --agent fixer --signing-seed-file ./issuer.seed \
--output ./passport-larkfield-export.json --validity-days 30wrote 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.
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.
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:
# 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.jsonpresentation 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:
$ chio passport verify --input ./passport.jsonpassport 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
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
$ 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"
}
}$ 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"}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.
Composed 0.95, weakest delta 0.86, 2 distinct feed identifiers: tier 3. every tier 3 condition holds.
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
}
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:
issuerAllowlist: ["did:chio:z6Mkf3…Qp9"]
minCompositeScore: 0.7
minReceiptCount: 500
requireCheckpointCoverage: truechio passport evaluate --input ./passport-larkfield-export.json --policy ./verifier-policy.yamlpassport 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 trustTier | Grant you issue |
|---|---|
unverified | No grant until the agent presents further evidence. |
attested | A 15-minute lifetime, max_total_cost of USD 5, and require_approval_above at USD 1. |
verified | A 1-hour lifetime, max_total_cost of USD 50, and require_approval_above at USD 10. |
premier | An 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:
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());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 chio import Computer, USD
project = Computer.open("quickstart")
pricing = project.service("pricing", tools={"quote": "src/pricing.py:quote"})
terms = {
"attested": {"budget": USD(5), "expires_in": "15m"},
"verified": {"budget": USD(50), "expires_in": "1h"},
"premier": {"budget": USD(500), "expires_in": "8h"},
}
tier = "verified" # the trustTier of the buyer's accepted passport
access = pricing.grant(to="did:chio:z6MkbY4…e1R", tools=["quote"], **terms[tier])
print(access.describe())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
use chio::{Computer, ServiceGrant, USD};
let project = Computer::open("quickstart").await?;
let pricing = project.service("pricing").tool("quote", "src/pricing.py:quote").create().await?;
let tier = "verified"; // the trustTier of the buyer's accepted passport
let (budget, ttl) = match tier {
"attested" => (USD(5), "15m"),
"verified" => (USD(50), "1h"),
"premier" => (USD(500), "8h"),
_ => return Ok(()),
};
let grant = ServiceGrant::to("did:chio:z6MkbY4…e1R").tool("quote").budget(budget).expires_in(ttl);
println!("{}", pricing.grant(grant)?.describe());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.