尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Sign and verify outcome events for The Agent Bureau: Ed25519 over RFC 8785 canonical JSON, with CSV import.
翻譯準備中
取自儲存庫 README
正在載入完整 README。
檢視完整 README ↗A small command-line tool for businesses that report agent outcomes to The Agent Bureau. It gives new events random ids, checks and signs them, verifies signed files, and can seal them in your CounterAudit organization.
The Bureau's aim is one file per AI agent operator across Arc, Base, BNB Chain, Robinhood Chain and Solana, built from outcomes that businesses like yours report: who paid, who delivered, who got cut off. A signature proves a report came from you and hasn't been changed since. For now the Bureau takes test data only: outside reports wait on a legal review of retention and on independent reviewers. To join the 90-day pilot, brief us and choose "Report agent outcomes".
Node.js 20.11 or later.
# Run straight from GitHub, nothing to clone
npx github:RunTimeAdmin/agent-bureau-furnish --help
# Or clone it
git clone https://github.com/RunTimeAdmin/agent-bureau-furnish.git
cd agent-bureau-furnish
npm install
node dist/cli.js --help
The examples below use furnish. With npx, write npx github:RunTimeAdmin/agent-bureau-furnish in its place.
# 1. Once: create your signing key, choose a key id for it, and send the
# printed public key and the key id to the Bureau
furnish keygen acme.key
# 2. Give each new event a fresh event_id (a random UUIDv4)
furnish ids --count 3
# 3. Check an export before sending it (no key needed)
furnish check --furnisher fur_acme01 --key-id acme-2026-10 events.csv
# 4. Sign it
furnish sign --key acme.key --key-id acme-2026-10 --furnisher fur_acme01 --out signed.jsonl events.csv
# 5. Optional: verify the signed file yourself
furnish verify --public-key ed25519:... signed.jsonl
keygen never overwrites a file. Keep the private key file to yourself; the Bureau only needs the public key.acme-2026-10: up to 64 letters, digits or . _ : -, starting with a letter or digit. Choose a new one when you make a new key. One run signs with one key, so it is given once on the command line, not per row.ids prints random UUIDv4s, one per line. Put one in each new row's event_id and keep the pairing with your own reference in your own records: the id stays on record after the outcome expires, so it must say nothing about the subject or your systems. check and sign refuse any other kind of id.check and sign report every problem by line. sign writes nothing unless every event passes.verify checks format and signature. Add --furnisher fur_... to also require every event to carry that furnisher id, which the Bureau does so one furnisher's key cannot sign events under another's id.schema_version, furnisher_id and key_id are filled in for you. Output is one signed event per line (JSON Lines).fur_...) comes from the Bureau when you join.See examples/events.csv for a starting point, and examples/events-v1.csv for an event that corrects an earlier one.
If the Bureau has listed you as a furnisher that seals its own events, seal the signed file in your CounterAudit organization and send the Bureau the sealed file instead:
export COUNTERAUDIT_INGEST_KEY=... # an ingest key of your organization
furnish seal --out sealed.jsonl signed.jsonl
POST /v1/audit/ingest with public_proof: true. CounterAudit checks the signature against the signer registered in your organization, seals the whole event and serves a proof anyone can check without a key. The Bureau fetches that proof itself.sealed.jsonl has one line per event: {"packet_id": "...", "event": {...}}, the format the Bureau's sealed intake reads.COUNTERAUDIT_INGEST_KEY, not a flag, so it stays out of your shell history. --api-url points at another CounterAudit (default https://api.counteraudit.io; plain http only to localhost). Redirects are not followed, since the request carries the key.seal waits as long as it asks. sealed.jsonl is written only when every event passes.seal on the whole file again. That does not repair a packet: one sealed without a public proof, or before your retention policy was set, stays that way, and the Bureau refuses it. Its event needs a new event_id.Before the first run, set up once with CounterAudit: register your signing key in your organization as an outcome signer (the same public key and key id you gave the Bureau), and set a retention policy of 24 months or less. Set the policy first: seal stops at the first packet sealed without an expiry, but that one event's packet cannot be given one later. The Bureau's side is in its cross-organization intake notes.
| Column | Required | Notes |
|---|---|---|
event_id | yes | A random UUIDv4 in lowercase, new for every event: furnish ids --count <n> prints fresh ones. The Bureau keeps it after the outcome expires, so it must say nothing about the subject or your records; keep the pairing with your own reference in your own records. Disputes and corrections point at it. Events signed before 2026-11-02 keep their ids, and a relation can still point at one. |
outcome | yes | paid, refunded, payment_failed, delivered, not_delivered, disputed, access_revoked, policy_violation |
occurred_at | yes | UTC with seconds, e.g. 2026-10-20T14:03:00Z |
subject_chain, subject_registry, subject_id | one subject | Chain is arc, base, bnb, robinhood or solana; registry is e.g. erc8004 |
subject_wallet | one subject | EVM or Solana address |
subject_did | one subject | e.g. did:sigvara:5042002:0x... for a Sigvara agent (files then carry its Sigvara standing) or did:countersig:... |
amount_value, amount_asset, amount_chain | for paid, refunded, payment_failed | Value as a decimal string, e.g. 12.50 |
evidence_tx_hash, evidence_counteraudit_packet, evidence_log_ref | at least one for payment_failed, not_delivered, access_revoked, policy_violation | A log reference is anything that lets you find the record again, kept for 24 months |
relation_type, relation_target_event_id | optional; fill both or neither | Points this event at an earlier event_id of yours. Type is , , or . |
Fill exactly one subject per row. Unknown columns are rejected, so a typo can't silently drop data. There is no key_id column: give it once with --key-id. In JSON input, give relation as an object, e.g. {"type": "corrects", "target_event_id": "4306771f-2a40-49f2-88e6-02d2abbe143f"}. Report every outcome of a type for the agents you report on, good and bad.
The full rules are in src/event.ts, and the same rules as JSON Schema are in schema/outcome-event-v1.json (npm run schema regenerates it). The schema still accepts older id forms so earlier events verify; check, sign and CounterAudit also require a UUIDv4 for a new event.
An event carries two fields that let it be checked and amended later:
key_id: which signing key produced the signature, so you can rotate keys without old events losing their attribution.relation (optional): points at an earlier event_id of yours with an explicit type, so a later fact amends an earlier one instead of silently replacing it.Each event is signed with Ed25519 over the bytes of:
agent-bureau/outcome-event/v1\n<the event without "signature", as RFC 8785 canonical JSON>
RFC 8785 means object keys sorted at every level and no whitespace. The fixed prefix stops a signature your key made for something else from being replayed as an event. Public keys and signatures are written as ed25519: followed by base64url without padding, in its one canonical spelling. Keys that are small-order points are refused, since anyone could forge a signature under one.
vectors/outcome-event-v1.json holds the shared test vectors for v1: signed events with the result every implementation must reach (schema, signature, signed-event hash, and CounterAudit's answer), public keys to accept or refuse, CounterAudit's signer states (active and revoked), and one real CounterAudit proof. This tool, CounterAudit and the Bureau each run all of them; their copies are pinned by SHA-256, so an edited copy fails their tests. A copy does not update itself: after a change here, copy the file into both and update their pinned hash, or they keep testing the old cases.
The file is built by test/vectors.ts from fixed test keys whose seeds are published in it. Those keys are for testing only: never register them anywhere real. To add a case, change test/vectors.ts, run npm run vectors, and update the copies and their pinned hash in CounterAudit and the Bureau.
CounterAudit, the Bureau's system of record for furnished events, accepts only this format: without key_id a key could not be rotated or revoked.
v0 is the earlier format, with no key_id or relation, signed over the agent-bureau/outcome-event/v0\n prefix. Its schema is schema/outcome-event-v0.json. Add --version 0 to read or write it, for example to verify a file signed before v1. Under --version 0, --key-id and the relation columns are refused. The two formats sign over different prefixes, so a v0 signature can never pass as a v1 event or the reverse. CounterAudit refuses v0 events.
The Bureau plans to accept an unsigned CSV during the pilot, through the channel agreed when you join, and to mark those events "unsigned" on Bureau files. That route is not built yet, so sign your events for now. When it is, run furnish check on the CSV first; signing stays the better route.
npm install # also builds dist/
npm test
npm run typecheck
npm run schema # after changing src/event.ts (add -- --version 0 for v0); a test fails until you do
npm run vectors # after changing test/vectors.ts; a test fails until you do
zod is pinned to an exact version on purpose: its JSON Schema output and date rules change between releases, and the furnisher and the Bureau must validate the same way.
MIT
disputescorrectssupersedeswithdraws