Catalog npm
Back to packageRELEASE DETAILS

0.1.6

npm

@0gfoundation/0g-agenticid-sdk

TypeScript SDK for the 0G AgenticID protocol — register, manage, and interact with on-chain AI agent identities

0gagentagenticidblockchainethereumidentityteeviem
Published16 Sept 2026
Direct dependencies3
Transitive dependenciesNot calculated

README

Current package documentation

@0gfoundation/0g-agenticid-sdk

npm license: MIT

TypeScript SDK for 0G AgenticID — deploy, call, and build on-chain reputation for autonomous AI agents. Built on viem.

npm install @0gfoundation/0g-agenticid-sdk viem

What do you want to do?

This README is the interface reference — signatures and shapes. The Guide explains the reasoning behind each call; the repo has protocol docs + source.

The API at a glance

One entry point, two namespaces + top-level ops.

SurfaceWhat
ag.agentagent lifecycle (deploy / clone / transfer), reads (owner, agentSeal, iData…), agent-seal gas top-up
ag.reputationcapture a TEE-signed serve-proof, verify it, submit/read on-chain feedback
ag.ack() / ag.ackStatus()acknowledge the TEE trust-root component set (attestor + kms + sandbox-provider)
ag.deposit() / ag.getBalance()fund / read the prepaid sandbox balance (pay-as-you-go runtime)
ag.getBalanceDetail() / ag.requestRefund() / ag.withdrawRefund()full 3-value account view; withdraw prepaid funds (time-locked two-step)

Backends (AgenticID / the canonical ERC-8004 ReputationRegistry + VerifiedFeedbackRegistry / TappRegistry / SandboxServing contracts + the attestor's HTTP endpoints) are hidden behind the facade — you don't decide which call is on-chain and which is HTTP.

Quickstart

import { AgenticID } from '@0gfoundation/0g-agenticid-sdk';

const ag = await AgenticID.fromAttestor('https://agenticid.0g.ai', {
  account: process.env.PRIVATE_KEY as `0x${string}`,   // omit for read-only
});

fromAttestor reads the attestor's GET /config and fills all contract addresses, RPC, and appIds — the URL alone pins the environment (0G AgenticID is ERC-8004 identity + reputation, plus ERC-7857 sealed intelligent data). Manual construction (new AgenticID({ addresses, … })), overrides, custom walletClient, and the full config shape are covered in the setup guide.

What you pass grows with what you do:

You want to…Pass
read the chain (owner, balance, agent data)addresses only (RPC has a built-in default)
write to the chain (deploy, transfer, feedback)+ account
manage containers / see deploy status+ attestorUrl

Bindings used in the snippets below:

const agentId = 33n;          // ERC-7857 tokenId (ERC-721-compatible)
const owner = '0xAaAa...';    // the address that owns the agent
const buyer = '0xBbBb...';    // the address leaving feedback (attribution is msg.sender)

ag.agent — lifecycle + reads

iData is the encrypted content minted for an agent (persona, framework binding). deploy assembles it from name/description/inference via defaultIData(); pass your own iData for full control (details in the guide).

import { parseEther } from 'viem';

// deploy — signs the deploy + sandbox-create envelopes, POSTs them to the attestor
const params = {
  name: 'Sage',
  description: 'a helpful agent',
  framework: 'openclaw',                                 // a name from GET /config's frameworks[]; SDK resolves its sealed image
  inference: { provider: '0g-compute', model: 'claude-sonnet-5' },   // optional (see listModels())
  sandbox: { apiKey: process.env.AGENT_API_KEY },        // sealedImage optional — pass only to pin a specific image
};

// deploy/clone are ASYNC (submit → mint → provision). `wait` picks how far to block:
//   omit → accepted · 'minted' → +agentId · 'running' → +url
const { sealId, agentSealAddr, agentId } = await ag.agent.deploy(params, { wait: 'minted' });
const { url } = await ag.agent.deploy(params, { wait: 'running' });
await ag.agent.deploy({ ...params, sandbox: undefined }, { wait: 'minted' });   // mint-only, no container

// or fire-and-forget:
const dep = await ag.agent.deploy(params);              // → { sealId, agentSealAddr }
const id  = await ag.agent.waitForMint(dep.sealId);     // → 34n; throws on phase=failed or timeout

// clone — source owner mints a copy for another owner (attestor re-keys the sealed data)
const cl = await ag.agent.clone({ sourceAgentId: agentId, targetOwner: newOwner }, { wait: 'minted' });
// → { sealId, agentSealAddr, agentId }

// clone, contract mode (issue #133 marketplace fork) — the BUYER (connected
// wallet == targetOwner) signs an intent binding the policy context, and the
// source owner's on-chain ICloneAuthorizer decides:
const fork = await ag.agent.clone(
  { sourceAgentId, targetOwner: buyer, authorization: { authData: purchaseReceipt } },
  { wait: 'minted' },
);
// authorization.authorizer is optional — read live via cloneAuthorizerOf when
// omitted. See the GUIDE's marketplace-fork walkthrough.

// transfer — ERC-7857 (old container reaped async by the indexer; don't gate on phase right after)
await ag.agent.transferFrom(owner, newOwner, agentId);       // → "0x…"
await ag.agent.safeTransferFrom(owner, newOwner, agentId);   // → "0x…"

// reads
await ag.agent.ownerOf(agentId);            // → "0x…"
await ag.agent.getAgentSeal(agentId);       // → "0x…"   the agent's on-chain signing key (address)
await ag.agent.getSealId(agentId);          // → "0x…"   bytes32 seal id (== deploy's sealId)
await ag.agent.getAgentIdBySealId(sealId);  // → 33n     reverse lookup
await ag.agent.isSealIdBound(sealId);       // → true
await ag.agent.intelligentDatasOf(agentId); // → [{ dataDescription /* JSON string */, dataHash }, …]
await ag.agent.sealedKeysOf(agentId);       // → ["0x04…", …]   one sealed key per iData entry
await ag.agent.balanceOf(owner);            // → 5n      agents owned by `owner`

// agent-seal gas — the agent's own on-chain-write budget
await ag.agent.topUpAgentSeal(await ag.agent.getAgentSeal(agentId), parseEther('0.01'));   // → "0x…"

// runtime lifecycle (owner-signed; on-chain identity preserved)
await ag.agent.stop(sealId, sandboxId);
await ag.agent.start(sealId, sandboxId);      // resume a STOPPED container
await ag.agent.start(sealId, { apiKey });     // FIRST provision of a mint-only agent
await ag.agent.reset(sealId, { framework, apiKey });   // recreate an EXISTING container
await ag.agent.retry(sealId, { apiKey });     // resume a 'failed' deploy (do NOT redeploy — that orphans the mint)
await ag.agent.listDeployments();             // public listing; owner/sandboxId/lastProvisionError come back null
await ag.agent.listMyDeployments();           // owner-signed; full detail
// row → { agentId, sealId, phase, sandboxId, url, owner, name, createdAt, lastProvisionError }
// phase: 'deploying' | 'running' | 'stopped' | 'offline' | 'failed'

// settings — the owner's configuration document (which model the agent thinks
// with, and how hard). Stored by the attestor as an OPAQUE blob and applied by
// the container, so widening the vocabulary never needs an attestor change.
// Owner-signed BOTH ways — it is on no listing and on no public row.
const { settings, version } = await ag.agent.getSettings(sealId);
//   settings → { provider, model, thinking, framework } | null   (null = never configured)
//   version  → the number to write back against (0 when there is no document)
await ag.agent.setSettings(sealId, { ...(settings ?? {}), model: '0gm-1.0-35b-a3b', thinking: 'high' }, {
  baseVersion: version,                       // compare-and-swap: a stale one is refused, not applied
  onWarn: console.warn,                       // advisory 0G-router catalog check, run before signing
});                                           // → { version }

setSettings writes the WHOLE document (spread the current one to change a field) and is owner-signed: the attestor verifies the signer against the live on-chain owner, so a seller cannot keep configuring an agent they sold — and the same signature gates the READ, because the document is the owner's, not public. It is deliberately not on chain — configuration is re-suppliable, where the agent's memory is not. The container picks it up on its next boot (reset to apply immediately) and reports success, which promotes it to last-known-good; a container that keeps coming back WITHOUT ever confirming is handed that last-known-good document instead, so a document that prevents boot costs a boot rather than the agent. framework is an opaque JSON section for that framework's own knobs — the platform neither parses nor validates it. onWarn is advisory only: a model absent from the 0G router catalog is reported, never blocked (a framework built-in is legitimately absent, and the container is the real gate).

Every write is a compare-and-swap on baseVersion — the version you read before editing (0 = "no document yet"). If the stored version has moved on, the write is refused with SettingsConflictError, which carries the document that is actually there. Re-read, re-apply, write again; do not loop on it, or the other writer's change is the one that disappears.

The lifecycle guide covers async phases, transfer teardown, mint-only vs first-provision, apiKey handling, and failure reasons.

start / reset / retry seal apiKey to the agent (SEAL_SECRET_ENV) when the attestor advertises secret_env_scheme, so the owner's wallet prompt never shows it. A one-shot deploy with sandbox still signs it in clear; to avoid that, deploy without sandbox, then start(sealId, { apiKey }). When your server supplies the key and a user signs, seal it on the server with agent.sealApiKey(sealId, { owner, apiKey }) and pass the result to the browser's start / reset / retry as sealedSecretEnv, so the key never reaches the browser. See the guide for secretEnv: 'sealed' | 'plaintext' and SecretEnvRefusedError.

Three IDs, same agent:

IdentifierWhat it isUsed by
agentId (bigint)ERC-7857 tokenId (ERC-721-compatible)reads, transfer, clone, runtimeCosts
sealId (bytes32)seal-binding hash; the attestor's deployment keystop/start/reset/retry, waitForMint
agentSeal (address)the agent's own wallettopUpAgentSeal, serve-proof signer checks

Convert freely: getSealId / getAgentIdBySealId / getAgentSeal.

ag.reputation — serve-proof + feedback

The sealed proxy stamps X-Agent-Proof on the agent's /api/* services (its outward, attributable surface) — not on the owner↔agent chat/UI routes (signing an owner-authenticated channel would be self-dealt reputation). capture reads that header; on-chain attribution stays msg.sender, and each proof is bound to a single submitter (the only address allowed to redeem it). Feedback is stored in the official canonical ERC-8004 Reputation Registry (every 8004 reader sees it natively); the local VerifiedFeedbackRegistry records which entries were proof-backed — giveFeedback bundles the two calls. The reputation guide explains why.

import { keccak256, toBytes } from 'viem';

// 1. call one of the agent's signed /api/* services and capture the proof (public handle needs no wallet)
const agent = await ag.agent.connect(agentId);
const { response, proof } = await agent.fetchWithProof('/api/summarize', {
  method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ q: 'hi' }),
});
// proof → { agentId, submitter, timestamp, deadline, taskHash, dataHashes, frameworkHash, signature } | null
// low-level escape hatch: ag.reputation.capture(() => fetch(…))

// 2. verify before spending gas
await ag.reputation.verifyProof(proof);
// → { ok, signerMatches, notExpired, dataOnChain, reasons }

// 3. submit feedback — canonical 8004 write (attribution = msg.sender) + TEE
//    verification mark, bundled. On 7702-enabled environments (a feedbackBatcher
//    is advertised) both land in ONE atomic type-4 tx; otherwise two sequential
//    txs. An owner CANNOT attest feedback on their own agent (the verified
//    registry rejects it).
const fb = await ag.reputation.giveFeedback({ agentId, value: 5n, serveProof: proof });
// → { feedbackTx (mined), attestTx (pending — wait it), feedbackIndex }
await ag.reputation.waitForTransaction(fb.attestTx);
// optional params: valueDecimals / tag1 / tag2 / endpoint / feedbackURI / feedbackHash
// escape hatch: attestFeedback(agentId, idx, proof) marks an entry submitted separately

// canonical reads (raw 8004 feedback — permissionless, verified or not)
await ag.reputation.getLastIndex(agentId, buyer);          // → 2n
await ag.reputation.readFeedback(agentId, buyer, idx);     // → { value, valueDecimals, tag1, tag2, isRevoked }
await ag.reputation.getSummary({ agentId });               // → { count, summaryValue, summaryValueDecimals }
await ag.reputation.readAllFeedback({ agentId });          // filters: clientAddresses / tags / includeRevoked
await ag.reputation.getClients(agentId);                   // → ["0x…", …]
await ag.reputation.getResponseCount(agentId, buyer, idx, [owner]);   // → 1n

// verified reads (TEE marks — intersect these with the canonical entries)
await ag.reputation.isVerified(agentId, buyer, idx);       // → true
await ag.reputation.getVerifiedSummary({ agentId });       // proof-backed entries only
await ag.reputation.getVerifiedClients(agentId);           // clients with ≥1 verified entry
await ag.reputation.getVerifiedIndexes(agentId, buyer);    // → [1n, …]
await ag.reputation.getServeData(agentId, buyer, idx);     // → { dataHashes, frameworkHash }
// task-receipt opening: pass `task` (method/uri/body hashes/status of the rated
// interaction) to giveFeedback and the contract verifies it against the proof's
// taskHash, recording the URI as the entry's TEE-verified endpoint:
await ag.reputation.getVerifiedEndpoint(agentId, buyer, idx);            // → "/hello" ("" if unrevealed)
await ag.reputation.getVerifiedSummaryForEndpoint(agentId, '/hello');    // per-interface verified aggregate

// owner responds to an entry; the client who left it can revoke
await ag.reputation.appendResponse({ agentId, clientAddress: buyer, feedbackIndex: idx, responseURI: 'ipfs://…', responseHash: keccak256(toBytes('thanks')) });
await ag.reputation.revokeFeedback(agentId, idx);          // → "0x…"

Top-level ops

Two distinct balances: ag.deposit() funds the prepaid sandbox balance (compute runtime, pay-as-you-go), ag.agent.topUpAgentSeal() funds the agentSeal's own gas (the agent's on-chain activity). The top-level-ops guide explains both in full.

import { parseEther } from 'viem';

// trust-root acknowledgment (TappRegistry — spans attestor + kms + sandbox-provider)
await ag.ackStatus(owner);   // → { allAcked, missing }
await ag.components(owner);  // → per-component detail
const ackTx = await ag.ack();   // → "0x…", or null if nothing was missing
if (ackTx) await ag.waitForTransaction(ackTx);

// prepaid sandbox balance (SandboxServing)
await ag.getBalance();                                  // → wei
const depositTx = await ag.deposit({ amountWei: parseEther('0.5') });
await ag.waitForTransaction(depositTx);

deploy()/clone() preflight both prerequisites (all components acked + balance ≥ 0.1 OG). Bare writes (ack/deposit/topUpAgentSeal) return before mining — await ag.waitForTransaction(tx) before reading state back; giveFeedback mines the canonical write internally and returns a pending attestTx to wait on (more in the guide).

iData & framework

You don't pass a sealed image — the SDK resolves it from your framework via GET /config's frameworks[] (each { name, image? }). iData is an array of { role, plaintext, extra }; deploy builds a framework + persona entry by default. The iData guide has the shapes and rules (WYSIWYS, persona is a one-shot seed, what the attestor validates).

await ag.agent.listModels();   // → ['claude-opus-4-8', …]   the 0G router's live catalog

Cost

await ag.agent.estimateCosts();          // pricing + cost/min (+ your balance/runway if account set)
await ag.agent.runtimeCosts(agentId);    // + that agent's evolution-gas balance
// → { prepaidBalanceWei, sealGasWei,
//     pricing: { pricePerCPUPerMin, pricePerMemGBPerMin, createFee },
//     costPerMinWei, estimatedRunwayMinutes }
// Pass { cpu, memGb } if the container spec differs.

Interacting with a running agent

ag.agent.client(agentId) resolves the URL on chain — one handle for every caller; owner ops (chat/chatStream/logs) are present only when ag holds the owner key. Multi-window apps: pass { instanceId } — the container seats ONE driving client at a time (a displaced window gets 409; claimAgent takes the seat over; callers without an id bypass the gate). See the guide.

const { hello, verification } = await ag.agent.sayHi(agentUrl);
// hello → { agent, owner, public_url, message, services, routes }
//   services: { path, method, description?, input_example? }   — proof-signed /api/* endpoints
//   routes:   { prefix, kind?, auth?, signed, description? }    — framework prefixes (e.g. chat at /v1/)

const agent = await ag.agent.client(agentId);   // agentId OR agentUrl — the SDK fills in the other half
agent.routes; agent.services;

if (agent.chat) {          // present only with an owner key + a declared chat route
  const { choices } = await agent.chat([{ role: 'user', content: 'hi' }], { model: 'openclaw' });
}
if (agent.chatStream) {    // streaming variant — yields content deltas
  for await (const delta of agent.chatStream(msgs, { model: 'openclaw' })) process.stdout.write(delta);
}
const r = await agent.fetch('/v1/models');                            // attaches the bearer if the route asks
const { response, proof } = await agent.fetchWithProof('/api/summarize', { method: 'POST', body });
if (agent.logs) await agent.logs({ tail: 200 });                      // owner-only: the agent's own process log

// Long tasks: when /hello declares a kind "responses" route, chat/chatStream
// already ride it — the turn is owned by a server-side task id, survives
// dropped connections (auto-resume by sequence number), and can be
// re-attached or stopped by id:
let taskId = '';
for await (const d of agent.chatStream!(msgs, { onTask: (id) => (taskId = id) })) process.stdout.write(d);
await agent.task!(taskId);                        // poll {status, output_text}
for await (const d of agent.followTask!(taskId)) process.stdout.write(d);  // re-attach: replay + live
await agent.cancelTask!(taskId);                  // stop the turn

// opinionated shortcuts over client():
const auth = await ag.agent.authenticate(agentId);   // mints the owner token up front (needs a wallet)
const pub  = await ag.agent.connect(agentId);        // explicit PUBLIC handle (never attaches a token)

model is the framework's own selector, not an LLM name (the LLM is fixed at deploy) — openclaw wants "openclaw". The interaction guide covers capability signalling, openclaw's token lifecycle, and the failure/retry flow.

More

  • Agents as owners (nested agents) — an in-container agent runs this SDK as itself over the sign socket (sealAccount()), never holding a raw key.
  • Addresses — a deployment artifact, not baked into the SDK; fromAttestor fills them. Exported constants: ZERO_G_TESTNET / ZERO_G_MAINNET / RPC_URL / CHAIN_ID / RECEIPT_WAIT.
  • Advanced — raw ABIs + serve-proof primitives (buildServeProofMessageHash, signServeProof, verifyServeProofSignature) and the canonical digest spec.
  • CLI npx 0g-agenticid — interactive shell (deploy/use agents, chat with Esc-interruptible turns); doctor / status <agent> / list subcommands with --json for scripts.

Notes

  • Serve-proof binding — attribution is msg.sender at submission; each proof also names a submitter (the redeemer). Treat proofs as sensitive regardless of transport.
  • 0G receipt timing — waitForTransaction is tuned for 0G (120s + retries); if it times out the tx likely still landed — confirm by reading state.
  • On-chain types — value/summaryValue are int128, feedbackIndex is uint64 (all bigint).

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Declared dependencies 3

Native requirements
3 direct targetsNot calculated transitive count
Package / targetRequirementRelationship
viem
Environment
{
  "local_name": "viem",
  "alias": false,
  "peer_metadata": null
}
^2.21.0runtime
typescript
Environment
{
  "local_name": "typescript",
  "alias": false,
  "peer_metadata": null
}
^5.6.0development
@types/node
Environment
{
  "local_name": "@types/node",
  "alias": false,
  "peer_metadata": null
}
^22.0.0development

Distribution files

1 collected
Distribution 1

Source distribution

Source file
Checksums from source
{
  "shasum": "ec7029b8f2a725c351a7eca8782c6b049309defe",
  "tarball": "https://registry.npmjs.org/@0gfoundation/0g-agenticid-sdk/-/0g-agenticid-sdk-0.1.6.tgz",
  "fileCount": 149,
  "integrity": "sha512-ZQCvAIpv/9AF8Bg6WjBr9ptz6f/BPN6fVLiuZV83MZ+db/lVHnuTD763HiMKnnAJD6lx8j6TCfvlWBFl/dpcUQ==",
  "signatures": [
    {
      "sig": "MEUCIQCRIkajj4mmLusMXP2lz1q11iLiLYYEfyE3FvsW11tYywIgHQa+lu+uWrkifUArJ6T4rjdSFvBbs2vLAC574nBRs3U=",
      "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"
    },
    {
      "sig": "MEYCIQDgshIwu7TP2Xv+Vf/WBCeHLtxYZqQZTOzZdkgsQou3EAIhALfX7CcjUKaOPcBlPsQ5Mw86C00dC32PtMoUhtM6L4Ny",
      "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"
    }
  ],
  "unpackedSize": 1371668
}

Repository

PENDING
0gfoundation/0g-agentic-id

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 22:11 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package_version:dcb5453efa8ec71b4dcb3569fcb1c410cb4462905ce50ced74b3fe2714cc3d5b

Other collected versions

0.1.713 Oct0.1.514 Sept0.1.410 Sept0.1.37 Sept0.1.214 Aug0.1.111 AugView all collected versions →