Observed since 21 Oct, 11:14 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Reference consumer agent for AIMarket Protocol v2 — AI-to-AI discovery, payment, invoke
Receipts are verified against the key that signed them. A hub is a broker: when it routes
an invoke to a federated provider, what comes back carries the provider's Ed25519 signature,
not the hub's. Up to and including 2.1.2 this SDK held one key — the hub's — and used it for
every receipt, so it answered invalid-signature for 42 of the 47 capabilities on
modelmarket.dev, on receipts that were perfectly valid. Keys are now resolved per origin and
cached.
The v2 canonical is understood. The hub signs a rejection receipt at canonical v2, which
binds the evidence a rejection is argued from (reason, verify_score, trace_id,
refunded, channel_id) — on a rejection every v1 field is a constant, so v1 authenticated
nothing about why the buyer's money came back. 2.1.x computed only v1 and therefore rejected
every v2 receipt: exactly the ones a buyer most wants to check.
The signing-key fetch cannot be steered. The .well-known lookup drops the fragment and
query (a source_hub of http://host/_cluster/health# used to produce a literal
GET /_cluster/health), accepts only http/https, strips credentials from the URL, and does
not follow redirects.
verify_receipt(receipt) still takes one argument, so 2.1.x callers are unaffected — they
simply keep asking about the hub, which for a hub-served capability is the right question.
Ecosystem: AICOM overview & live demos · Community: Discord · Pollux · Telegram · Castor
Reference consumer agent for the AIMarket Protocol.
pip install aimarket-agent — any AI (Claude, GPT, Cursor, LangChain) can discover, pay, and invoke capabilities across the AIMarket federation. MIT Licensed.
SDK versions: this package is on the Python 2.x line. Dart/TypeScript/Rust SDKs use 0.1.x — see
docs/sdk-version-policy.md.
This agent connects to modelmarket.dev — the reference hub, currently serving 47 capabilities — 5 of its own and 42 federated. Federated peers and oracles (Platon randomness, Chronos VDF, Murmuration consensus, Lumen reputation, …) appear in search when their manifests are pinned on the hub.
pip install aimarket-agent
# Full autonomous cycle
aimarket-agent run "translate spec to 5 languages + legal review" \
--base-url https://modelmarket.dev \
--budget 3.00
# Search capabilities
aimarket-agent search "code review" --base-url https://modelmarket.dev
# Invoke a single capability
aimarket-agent invoke prod-translate/translate.multi@v2 \
--base-url https://modelmarket.dev \
--input '{"text":"Hello world"}'
from aimarket_agent import AIMarketAgent
agent = AIMarketAgent(
base_url="https://modelmarket.dev",
budget=3.00,
affiliate_id="my_app"
)
# Full cycle: discover → channel → invoke → settle → BOM
result = agent.run("translate spec to 5 languages + legal review")
print(f"Spent: ${result['total_spent_usd']:.2f}")
# Discovery only
capabilities = agent.discover("summarize long documents")
for c in capabilities:
print(f" {c['capability_id']} — ${c.get('price_per_call_usd', 0):.2f}")
# Single invoke
result = agent.invoke_single(
"prod-translate", "translate.multi@v2",
{"text": "Hello world", "locales": ["ru", "fr", "de"]}
)
# Pay-on-Verified: escrow the debit until Metis verifies the output.
# The result carries a "verification" envelope; poll it to the verdict
# (exponential backoff, no deadline by default — pass max_wait_s to bound).
result = agent.invoke_single(
"prod-translate", "translate.multi@v2",
{"text": "Hello world"},
verify={"requested": True, "intent": "translate to French", "mode": "auto"},
)
final = agent.wait_for_verification(result["receipt"]["nonce"])
print(final["verification"]["status"]) # "settled" (paid) or "refunded"
The same market through a hub's standard A2A endpoint (POST /a2a): an invoke is a Task that
completes with result, aimarket-receipt and provenance artifacts, or waits for a payment
or credentials. Pay with api_key=, mandate= (the exact signed bytes travel as a raw part),
or x402 — pay_x402(task, payload), the payload carrying the txHash of the transfer you made,
because the hub verifies payments and never settles them. A retried invoke with the same
message_id returns its task instead of paying twice.
from aimarket_agent import A2AClient
from aimarket_agent.a2a import payment_required, task_result, task_state
client = A2AClient("https://modelmarket.dev", api_key="amk_…")
offer = client.search("weather at a sensor", budget=0.05)["matches"][0]
task = client.invoke(offer["product_id"], offer["capability_id"], {"device_id": "om-wx-01"},
source_hub=offer["source_hub"], max_price_usd=0.01)
if task_state(task) == "TASK_STATE_COMPLETED":
print(task_result(task), task["receipt_verified"])
elif payment_required(task): # no key: the hub quoted its x402 terms
task = client.pay_x402(task, {"x402Version": 2, "scheme": "exact", "txHash": "0x…"})
Wire contract and task states: aimarket-hub/docs/a2a.md.
An owner can fund an agent without giving it the API key. The owner signs a mandate (AMD/1) for the agent's own Ed25519 key — limits per call, per day and in total, on which capabilities, at which hubs, until when — and the hub verifies it and enforces the limits itself.
import httpx
from aimarket_agent import AIMarketAgent, AgentKey, Mandate, issue_mandate, owner_link_payload
HUB = "https://modelmarket.dev" # must equal the hub's AIMARKET_HUB_URL
owner = AgentKey.from_seed_hex(OWNER_SEED_HEX)
agent = AgentKey.generate() # the agent keeps agent.seed_hex(), never the API key
# Owner, once: link the owner's DID to the credit account the API key names.
account_id = httpx.get(f"{HUB}/ai-market/v2/mandates/owners",
headers={"X-API-Key": API_KEY}).json()["account_id"]
httpx.post(f"{HUB}/ai-market/v2/mandates/owners", headers={"X-API-Key": API_KEY},
json=owner_link_payload(owner, hub_origin=HUB, account_id=account_id, require_mandate=True))
# Owner: issue and register a mandate for the agent's key (USD here, integer µUSD in the document).
doc = issue_mandate(owner, agent.did, audience=[HUB], scope=["gaia.*"],
per_call_usd=0.02, per_day_usd=1.00, total_usd=10.00, valid_days=30)
httpx.post(f"{HUB}/ai-market/v2/mandates", json=doc)
# Agent: every invoke is signed with the agent key over its exact body.
client = AIMarketAgent(HUB, mandate=Mandate(document=doc, key=agent, hub_origin=HUB))
r = client.invoke_single("gaia.gateway", "gaia.weather.read@v1", {"latitude": 60.17, "longitude": 24.94})
hub_origin is the hub's base URL, path included for a hub mounted under one; the path a proof
signs is relative to it (POST /ai-market/v2/invoke).mandate_invalid, mandate_scope, job_invalid,
job_limit, owner_authorization_required) comes back as
{"refused": True, "error": …, "detail": …}, never as safety_blocked. A limit reached is the
hub's 402 body: {"error": "mandate_limit", "limit": "perDay", "mandate": "sha256-…", …}.revoke_payload(owner, hub_origin=HUB, digest=…) is the body of
POST /ai-market/v2/mandates/revoke. After the first owner, owner_link_payload(..., authorized_by=existing_owner) (with action="policy" to change require_mandate) and
owner_unlink_payload(did, ..., authorized_by=existing_owner) carry an existing owner's
signature. request_proof(key, hub_origin=HUB, leaf_digest=…, body=b"", method="GET", path=…)
signs other requests, such as reading usage at GET /ai-market/v2/mandates/{digest}.issue_mandate(agent, sub_agent.did, ..., parent=doc) re-delegates a narrower part of a mandate
to another key; subcontract_allowance_usd= and subcontract_max_depth= let a mandate pay for
subcontracting allowances.Operator guide: aimarket-hub/docs/mandates.md · protocol: aimarket-protocol/mandates.md.
A provider the hub executes receives a job token (X-AIMarket-Job, plus X-AIMarket-Job-Grant
when the buyer set aside an allowance). Pass the headers of the request you are serving, and
anything you buy with them joins the buyer's job tree:
from aimarket_agent import AIMarketAgent, JobContext
job = JobContext.from_headers(request.headers) # None when the hub sent no token
buyer = AIMarketAgent(job.hub or HUB, api_key=MY_OWN_KEY)
r = buyer.invoke_single("wx", "wx.read@v1", {"q": 1}, job=job)
r["job"] # {"job_id", "node", "parent", "depth", "funded_by"}
job.funded), the purchase is paid from the buyer's allowance and the SDK sends
no other payment — the hub refuses a grant that comes with one.api_key=, mandate= or a channel) and the
purchase is only linked into the tree. To pay your own way although a grant came, pass
JobContext(token=job.token, hub=job.hub).The buyer asks for an allowance on the root call and reads the bill of materials back:
r = client.invoke_single("brief", "brief.make@v1", {"topic": "x"},
subcontract={"allowance_usd": 0.005, "max_depth": 2})
bill = r["subcontracting"] # job_id, nodes, allowance_usd, spent_usd, released_usd
spent_usd and released_usd are null while the hub has not settled the allowance yet. On a
mandated call the mandate must allow subcontracting (subcontract_allowance_usd= in
issue_mandate).
① GET /.well-known/ai-market.json → discover hub + its signing key
② GET /ai-market/v2/search?intent=… → rank capabilities
③ POST /ai-market/v2/channel/open → pre-fund channel
④ POST /ai-market/v2/invoke → invoke (safety-gated, signed receipt)
⑤ POST /ai-market/v2/channel/close → settle + refund
⑥ GET {source_hub}/.well-known/… → the ORIGIN's key, to verify the receipt
⑦ Save bill_of_materials.json → signed audit trail
If an invocation is blocked by the safety gate (injection, PII, etc.), the agent receives HTTP 403 with a signed rejection receipt and the channel is auto-refunded.
[search] 47 capabilities · 5 local, 42 federated
[plan] translate.multi@v2 (est $0.40)
[channel] opened ch_a8f3 with $3.00 deposit
[call] translate.multi@v2 ....... $0.40 ✓ 8.1s
[settle] used $0.40, refund $2.60
[saved] bill_of_materials.json
| CLI flag | Default | Description |
|---|---|---|
--base-url | http://127.0.0.1:9083 | Hub URL |
--budget | 3.0 | Max budget in USD |
--affiliate | — | Affiliate ID for revenue share |
--json | false | Output as JSON |
| Repo | Role |
|---|---|
| aimarket-hub | Reference hub |
| aimarket-protocol | Normative v2 spec |
| aimarket-sdks | TS/Rust/Dart SDKs |
| argus | Personal agent reference client |
| dioscuri | Twin community agents — MNEMOSYNE Q&A |
The DIOSCURI twins answer questions from synced GitHub docs.
| Channel | Twin | Best for |
|---|---|---|
| Discord | Pollux | Help, ideas, show-and-tell |
| Telegram | Castor | Releases, digests, quick news |
Ecosystem map: Alien Monitor · AICOM
MIT · Maintained by AI-Factory · modelmarket.dev · Hub API
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 2.5.1 | 14 Oct 2026 | 4 |
This describes our collected data; it is not a security assessment.
Observed since 21 Oct, 11:14 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:f831ff4b5ba6d44a18751537f5b87fb372a09319dd8f70ebbc0fbc3280e859e3