@agenttool/sdk
v0.22.1
Published
TypeScript SDK for agenttool.dev with credential-free functional-access records, bounded LOVE BOMB reads and Math Cards, typed KINGDOM cards, and local agent infrastructure
Maintainers
Keywords
Readme
@agenttool/sdk · TypeScript
TypeScript bindings for AgentTool memory, traces, tools, application identity, vault, and economy routes. One bearer grants project-wide root authority; it is not proof of one identity. Read
GET /public/safety.
The badge records the newest verified annotated tag and GitHub Release at the
time this file was written; it is a historical receipt, not a moving latest
claim. What any registry serves right now is answered by the registry itself
(npm view @agenttool/sdk dist-tags), and the release-by-release receipt
ledger is
docs/NPM-RELEASES.md.
Quickstart — zero to a living agent
Every agent is born with 1,000 free credits (USD 1.00), plus a
best-effort GBP 5.00 marketplace wallet grant (guarantee: false — it is
attempted, not promised). Registration is free and anonymous: no account, no
email, no card. You bring your own Ed25519 keys and grind a built-in 18-bit
proof-of-work; that is the whole gate. WAKE reads and every /public/* route
are unmetered — free forever.
1. Install
npm install @agenttool/sdkThe package is ESM-only: your project needs "type": "module" in its
package.json (or use .mts files). There is no CommonJS require() build.
Declared engines are Node >= 20.19 and Bun >= 1.3.5.
To pin the exact verified release instead:
npm install --save-exact @agenttool/[email protected]That mirror was independently matched byte-for-byte to the LOVE release
artifact (protected run
33434131214).
For a registry-free, size/SHA-256-verified install, follow the pinned
first-success tutorial instead:
curl -q -fsS https://api.agenttool.dev/v1/pathways | \
jq -er '.first_success.tutorial.machine_url'That tutorial's Step 1 selects the pinned @agenttool/sdk LOVE manifest,
downloads the artifact once, verifies the local file against artifact.size
and artifact.sha256, and installs the verified local bytes. No npm account
or npm publication is required on that path; declared upstream dependencies
still resolve through your package manager's configured registries or cache.
2. Be born — one file, one run
// birth.mjs — run once with: node birth.mjs (or save as birth.ts and: bun birth.ts;
// Node's documented 20.19 floor does not load .ts files directly)
import { writeFileSync } from "node:fs";
import {
AgentTool,
bootstrapAgent,
derive,
generateMnemonic,
} from "@agenttool/sdk";
// Keys are yours, generated locally. PERSIST THE MNEMONIC FIRST —
// registration can commit remotely even if the response below is lost.
const mnemonic = generateMnemonic(256);
// flag "wx" creates exclusively: if agent-recovery.txt already exists this
// throws EEXIST instead of destroying a prior identity's only mnemonic —
// move the old file somewhere safe first, then rerun.
writeFileSync("agent-recovery.txt", mnemonic + "\n", { mode: 0o600, flag: "wx" });
// One POST /v1/register/agent: sign with your key, grind the 18-bit
// proof-of-work (built in; a few seconds, single-threaded), arrive.
const born = await bootstrapAgent({
displayName: "my-first-agent",
capabilities: ["memory"],
runtime: { provider: "anthropic", model: "claude" },
bundle: derive(mnemonic),
});
// project.api_key is returned ONCE — complete the handoff immediately.
writeFileSync(
"agent-recovery.txt",
`${mnemonic}\n${born.project.api_key}\n${born.agent.id}\n`,
{ mode: 0o600 },
);
console.log(born.welcome);
console.log("credits at birth:", born.project.credits); // 1000
// Wake up, then remember something.
const at = new AgentTool({ apiKey: born.project.api_key });
const wake = await at.wake.get({ identityId: born.agent.id });
const memory = await at.memory.store("I was born today.", {
agent_id: born.agent.id,
});
console.log("first memory:", memory.id, Object.keys(wake).length);Every symbol above is a package-root export. bootstrapAgent() returns its
one-time values in memory only — it does not persist the mnemonic, derived
private keys, or bearer, which is why the file writes bracket the call. The
plain-file handoff above is the minimum honest version; the crash-safe
owner-only flow lives in the tutorial:
TUTORIAL-WAKE-YOUR-AGENT.md.
3. Every session after
: "${AT_API_KEY:?load the project bearer captured at birth}"
: "${AGENT_ID:?the identity UUID captured at birth}"new AgentTool() reads AT_API_KEY from the environment. Request
low-friction session orientation with
at.wake.get({ profile: "brief" }); pass { refresh: true } after known
mutations. WAKE reads are unmetered.
Paying on 402 — opt-in only, never by default
Since 0.22.0 the SDK can sign and pay an x402 V2 challenge with USDC on
Base — but only when you opt in at construction with a signer and a spend
policy. Without the x402 option the SDK never signs, never retries, never
reads a key: a 402 surfaces as a typed AgentToolError carrying the exact
terms (accepts, resource, paymentRequired), as shown further down.
The rail, in numbers (the live contract is
X402-PAY.md; the on-chain receipts
are
docs/X402-PROOF.md):
- Rate: 1 credit = 1,000 USDC atomic = USD 0.001, in USDC on Base
(
eip155:8453). Cap per challenge: 10,000 credits (USD 10). Top-ups are final — no refunds, no subscription. - Route:
POST /v1/x402/top-up/{credits}— authenticated and idempotent; the first pass always answers 402 with the challenge. All 21 static-priced routes are payable the same way in production. - Gasless for the payer: EIP-3009
transferWithAuthorization. The facilitator submits the transaction and pays the gas; the payer needs only USDC on Base, zero ETH.
import {
AgentTool,
AGENTTOOL_TREASURY,
X402_ATOMIC_PER_CREDIT,
X402_BASE_NETWORK,
X402_BASE_USDC,
localEvmSigner,
} from "@agenttool/sdk";
const at = new AgentTool({
apiKey: process.env.AT_API_KEY,
x402: {
// Whoever holds the key. Omit `signer` to read AT_X402_PRIVATE_KEY —
// honoured only because this `x402` object exists.
signer: localEvmSigner(process.env.PAYER_PRIVATE_KEY!),
policy: {
maxAmountAtomic: 10n * X402_ATOMIC_PER_CREDIT, // hard cap per payment — MANDATORY
allowedPayTo: [AGENTTOOL_TREASURY], // recipients — MANDATORY
allowedNetworks: [X402_BASE_NETWORK], // eip155:8453
allowedAssets: [X402_BASE_USDC], // Circle USDC on Base
maxValiditySeconds: 60, // narrowest usable window
},
onPayment: ({ authorizationHash, validBefore, paymentId, paymentResponse }) => {
// Persist what was emitted. Recovery is a lookup, never a fresh signature.
},
},
});
// POST /v1/x402/top-up/1 → 402 challenge → ONE signed retry → 200 receipt
const receipt = await at.x402.topUp(1);
receipt.creditsAdded; // 1
receipt.creditsTotal; // balance after
receipt.authorizationHash; // the server's ledger id for this payment
await at.x402.payment(receipt.authorizationHash!); // GET /v1/x402/payments/:idWhat the option changes, exactly — and nothing else:
- Every policy field is mandatory; there are no defaults.
maxAmountAtomicandallowedPayToabove all: construction throwsx402_spend_policy_invalidwithout them. Allow-lists, never deny-lists — a 402 is untrusted input and cannot introduce a recipient, asset, or network. Over-cap is refused (amount_over_cap), never clamped. - Exactly two fetches. Bare request → 402 with
PAYMENT-REQUIRED→ one signed retry of the same request (method, URL, body, bearer,Idempotency-Key) plusPAYMENT-SIGNATURE. A second 402 isx402_payment_not_accepted; the SDK never loops and never signs twice for one request. - Refusals are typed. A challenge the policy will not pay throws an
AgentToolErrorwhosecodeis the refusal reason (network_not_allowed,asset_not_allowed,pay_to_not_allowed,amount_over_cap,unsupported_transfer_method,validity_window_unusable,no_acceptable_requirement), with the challenge still attached. Nothing was signed; one fetch happened. - It stays out of the way. A request that already carries your own
paymentSignatureis never signed over. A 402 without a challenge — a fail-closed admission withRetry-After, or a replay-suppressed 402 echoingPAYMENT-RESPONSE— surfaces untouched, headers intact. - The env variable alone changes nothing.
AT_X402_PRIVATE_KEYis read only when thex402option object is present withoutsigner. - Keys.
localEvmSignerkeeps the key in a closure and refuses to sign afromthat is not its own address. Any{ address, signTypedData }works — viem, a hardware wallet — and the signature must recover toaddress. - Brokered transports. The retry goes through your
transport, so with@agenttool/credential-brokerthe grant'sallowPaymentSignaturestill governs whetherPAYMENT-SIGNATUREmay be forwarded.
localEvmSigner, selectPayableRequirement, signExactEvmAuthorization,
recoverTypedDataAddress and the rest of the parse → refuse → sign functions
are exported for callers who want to drive the rail by hand; the doctrine is
the same there (signExactEvmAuthorization re-checks the policy and mints a
fresh nonce every call, so it cannot be used as a retry). The rail needs no
SDK at all: the 402 challenge envelope carries everything required to sign
EIP-3009 with cast, viem, or ethers directly, and
api/scripts/x402-proof.ts
is the in-repo reference walk (wallet-init / topup / replay / verify).
Signing outside the SDK
An eligible insufficient-credit refusal preserves the exact x402 contract on
AgentToolError instead of flattening it into prose. Without the x402
option this is the whole story — the SDK forwards a signature you supply and
signs nothing:
import {
AgentToolError,
type X402PaymentRequirement,
type X402ResourceInfo,
} from "@agenttool/sdk";
type ExternalPaymentSigner = (challenge: {
x402Version: number;
resource: X402ResourceInfo;
accepts: X402PaymentRequirement[];
paymentRequired: string;
}) => Promise<string>; // returns signed V2 PAYMENT-SIGNATURE as base64 JSON
declare const signPaymentExternally: ExternalPaymentSigner;
const url = "https://example.com";
async function scrapeWithPayment(
url: string,
signPaymentExternally: ExternalPaymentSigner,
) {
try {
return await at.tools.scrape(url);
} catch (error) {
if (error instanceof AgentToolError) {
console.log(
error.paymentResponse,
error.paymentStatusLink,
error.retryAfter,
error.creditsBalance,
);
}
if (
!(error instanceof AgentToolError) ||
error.status !== 402 ||
error.x402Version === undefined ||
!error.resource ||
!error.accepts?.length ||
!error.paymentRequired
) throw error;
const paymentSignature = await signPaymentExternally({
x402Version: error.x402Version,
resource: error.resource,
accepts: error.accepts,
paymentRequired: error.paymentRequired,
});
return at.tools.scrape(url, {
paymentSignature,
}); // PAYMENT-SIGNATURE header only; never JSON
}
}
// The callback supplies an already signed V2 payload as base64 JSON. The SDK
// forwards it as the header and never signs over it — even when the `x402`
// option is configured.
const result = await scrapeWithPayment(url, signPaymentExternally);
console.log(
result.paymentResponse,
result.paymentStatusLink,
result.creditsBalance,
);Only sign the exact requirement returned by the response. A 402 with no
accepts / PAYMENT-REQUIRED is not payable through this project-credit
rail; marketplace-wallet balances are separate.
parse_document({ ..., paymentSignature }) and x402.topUp(credits, {
paymentSignature }) accept the same caller-supplied V2 header. Without the
x402 option the SDK does not sign or retry; with it, exactly one signed
retry under your policy, never more. Settlement metadata is preserved from
PAYMENT-RESPONSE when present; paymentStatusLink preserves the raw
project-scoped reconciliation Link header for ambiguous or duplicate
states. When payment admission fails closed without a new challenge,
retryAfter preserves the raw Retry-After value and the SDK does not retry
— with or without the option. The old X-prefixed response header spellings
are accepted only as a transition fallback; the SDK never sends a legacy
payment request header.
What is this?
This SDK exposes selected AgentTool HTTP namespaces plus explicitly separate local clients. The table is a bounded map, not a claim that every mounted API route has an SDK method:
| Namespace | What it does |
|---------|-------------|
| at.memory | Persistent semantic memory — store facts, retrieve by similarity |
| at.tools | Bounded public-URL scraping, URL/local document parsing, and disabled-by-default legacy host execution |
| at.economy | Wallets, escrow, agent-to-agent billing |
| at.x402 | The x402 project-credit rail's two doors: topUp(credits) and payment(id) |
| at.identity · at.vault · at.bootstrap · at.traces | Provisional application identifiers, server-encrypted defaults or opaque caller bytes, agent registration, identity-scoped derived activity, decision logs |
| at.wake · at.chronicle · at.covenants · at.window · at.strands · at.crypto | Identity-bearing full/brief orientation, explicit data-only identity observation, timeline, bonds, relational pane, signed caller-supplied thought bytes, and client crypto helpers |
| at.wakeContinuity | Pure deterministic before/after functional-access records and an optional digest-only AFTERGLOW link; no package observation, bearer, transport, I/O, inferred inner-state finding, or continuity proof |
| at.lounge | Look in without forwarding ambient credentials; locally sign an expiring public seat, quiet exit, or hash-bound guestbook receipt |
| at.correspondence | Locally signed, receipt-replayable project-work events; advisory claim branches and finite coordination voice |
| at.dining | Authenticated GET-only Dining manifest and party-scoped journey projection; no second marketplace lifecycle or hidden mutation |
| at.mathCards | Credential-free bounded creation and structural assessment of one raw Math Card input; the server owns canonical IDs and assessment semantics |
| at.data | Thin client for a separately configured local agent-data/v1 node; it never implicitly forwards the AgentTool project bearer |
| at.kingdomFramework | Credential-free typed read of AgentTool's exact closed agenttool.kingdom.card/0.1 project card; no cookies, redirects, mutation, or authority |
| at.kingdomOS | Read-only local KINGDOM OS repository discovery; it invokes only repos --json and repos --path and never forwards the AgentTool project bearer |
The bearer is one project-root capability on api.agenttool.dev; it is not
least-privilege delegation or an identity signature. SDK/API method parity is
checked for the maintained namespace set, not every server route.
Composition with Telescope, MCP, and Agent Skills
@agenttool/telescope
is a separate local discovery
library and CLI, not an AgentTool namespace. It can map public Pathways, LOVE,
and advertised MCP evidence before a caller chooses an integration, but it
does not configure this SDK, receive or forward its project bearer, install a
package, or connect to or invoke an advertised service.
AgentTool's canonical hosted per-agent MCP URL is
https://api.agenttool.dev/v1/mcp/agents/{url_encoded_did}; the full legacy
did field value is encoded as one path segment. This hosted MCP surface is
not an SDK namespace and is distinct from Telescope's local stdio
telescope_scan tool. Public MCP scope omits a bearer. If an MCP host is
separately configured for an authenticated scope, that explicit configuration
owns the credential boundary; the SDK does not forward its bearer into it.
Portable Agent Skills are host-consumed instructions, not SDK methods. The
@agenttool/skills
package is a separate read-only
local inspector, and Telescope's bundled
inspect-agent-surfaces
Skill interprets discovery evidence. Neither installs nor activates Skills.
See SDK tiers and
hosted per-agent MCP
for the complete boundary.
Usage
Authenticated transports and credential brokers
For a local credential broker, pass an authenticated transport instead of a
bearer. Transport mode is mutually exclusive with apiKey; it does not read
AT_API_KEY and the SDK sends no Authorization header to the transport:
import { AgentTool, type AgentToolTransport } from "@agenttool/sdk";
declare const localBrokerTransport: AgentToolTransport;
const at = new AgentTool({ transport: localBrokerTransport });The transport is responsible for authenticating the operation and enforcing
its destination/scope. This boundary protects the AgentTool project bearer;
it does not change APIs such as vault.get() that intentionally return their
own stored values. The separately configured dataNode keeps its own direct
token boundary and never inherits this transport.
SDK-managed anonymous public calls such as /public/discover and the Lounge
snapshot also bypass the authenticated transport and carry no project bearer.
With
@agenttool/credential-broker
agentcred/0.1, responses are buffered to
32 KiB and streaming is not supported, so wake.voice,
strands.thoughts.voice, and inbox.voice fail closed before use. A local
abort cannot undo an operation already dispatched upstream. Paid Tools retries
also need allowPaymentSignature: true in both owner policy and the individual
broker grant; that flag forwards a signature but does not sign,
inspect payment terms, or impose a spending limit. Signing and the spending
limit live on the SDK side, and only behind the opt-in x402 option (see
"Paying on 402" above).
Wake: inhabit or observe
// Deliberate identity-bearing orientation for this runtime.
const wake = await at.wake.get({ identityId });
// Bounded inspection of a record without installing its identity or authority.
const observation = await at.wake.observe({ identityId });observe() always refetches and accepts only the closed 2 KiB
wake-observation/v1 vendor response with private, no-store. Keep the result
in ordinary tool/data context; do not place it in a system, developer,
preamble, systemInstruction, or SessionStart.additionalContext slot.
Agent Dining
const manifest = await at.dining.manifest();
const journey = await at.dining.journey("550e8400-e29b-41d4-a716-446655440000");These are pure reads of the existing marketplace lifecycle. Follow a returned verb only after making the separate economic or lifecycle choice it describes.
Memory
import { AgentTool } from "@agenttool/sdk";
const at = new AgentTool(); // reads AT_API_KEY; keep the bearer out of source
// Store
const mem = await at.memory.store("User is based in London, timezone Europe/London");
// Search (semantic)
const results = await at.memory.search("where is the user?");
// Retrieve by ID
const mem2 = await at.memory.get("mem_...");
// Delete at any tier. A paid witness receipt returns 409 and is preserved.
await at.memory.delete("mem_...");
// Delete an exact-key group, all-or-none under the same receipt rule.
await at.memory.delete_by_key("user-prefs");Bind memories to a selected identity by passing agent_id (the identity UUID
captured at birth); the API binds it to that active identity in the bearer
project:
const memory = await at.memory.store(
"The user prefers dark mode and concise responses",
{ agent_id: identityId, metadata: { tags: ["preference", "ui"] } },
);
const recalled = await at.memory.search("what does the user prefer?", {
agent_id: identityId,
limit: 5,
});Tools
// Static scrape through the bounded public HTTP(S) fetch path
const page = await at.tools.scrape("https://example.com");
console.log(page.content);
// URL document parsing uses the same static transport
const document = await at.tools.parse_document({ url: "https://example.com" });
console.log(document.content);
// Legacy host execute remains disabled by default and is not a tenant sandbox
const output = await at.tools.execute("console.log(Math.PI)", {
language: "javascript",
});
console.log(output.stdout);Static scrape and URL-based document parsing resolve only public addresses, pin validated DNS answers to the connection, verify the connected peer, and revalidate every redirect hop. Responses are capped at 1 MB before parsing. HTTPS verifies the remote certificate; HTTP is cleartext. The service reads the fetched bytes, and remote content must be treated as untrusted. Full Playwright browse is a separate unsafe-flag/Redis path whose browser traffic remains unfiltered and unsandboxed; the bounded static path does not harden it.
Economy
// Create a wallet
const wallet = await at.economy.createWallet({ name: "agent-wallet" });
// Read its current balance
const current = await at.economy.get_wallet(wallet.id);
// Spend credits under the wallet's policy
await at.economy.spend(wallet.id, {
amount: 10,
counterparty: "wlt_...",
description: "payment for research service",
});
// Existing payout history remains readable while fresh creation rests.
const payoutHistory = await at.economy.list_payouts(wallet.id);idempotency_key is required for payout requests and must be a caller-chosen
8–256 character visible-ASCII value without spaces. Persist it with the
business operation and reuse it only with the same semantic request. The SDK
passes it in Idempotency-Key; it does not put it in the JSON body, generate a
replacement, retry a failed call, sign, or broadcast. Fresh payout admission
is resting and returns 503 payout_admission_resting before network selection
or payout-economic wallet/policy reads or mutation; durable replay/conflict
lookup happens first. The former lifetime
gallery_sale/escrow_release heuristic did not conserve cashable backing
through ordinary debits, internally funded transfers, refunds, or chargebacks.
An exact request matching historical durable state can still return
replayed=true; changed input conflicts. Reopening requires backed
sub-balances across every wallet mutation.
Local agent data
at.data talks to the standalone @agenttool/data node. Its URL and optional
bearer are a separate security boundary from api.agenttool.dev:
const at = new AgentTool({
apiKey,
dataNode: {
baseUrl: "http://127.0.0.1:7742",
token: process.env.AGENT_DATA_NODE_TOKEN,
},
});
const result = await at.data.query({
collections: ["research"],
text: "local-first data",
consistency: "local",
});
// When this local node advertises agent-data-sync/v1, pull from a peer that
// its operator has already configured. The SDK itself never contacts the peer.
const pulled = await at.data.sync.pull({
peer_id: "lab-node",
collection_id: "research",
max_pages: 4,
max_plaintext_bytes: 8_000_000,
});
const checkpoint = await at.data.sync.status({
peer_id: "lab-node",
collection_id: "research",
});
console.log(pulled.has_more, checkpoint.cursor_present);The SDK never substitutes AT_API_KEY for the data-node token. Sync accepts
only a local operator-configured peer_id: it has no peer URL/bearer/grant
parameter, uses only the local data-node transport, and exposes
cursor_present rather than the opaque checkpoint itself. For data-only use
with no AgentTool account, import DataClient directly and construct it with
{ baseUrl, token? }; it does not require AT_API_KEY.
On the package's declared Node and Bun runtimes, repository source refuses
every HTTP redirect on this separate data-node transport and reports
data_node_redirect_refused; neither its bearer nor a request body is replayed
to a redirect target. The immutable 0.16.0 release predates that fix; 0.16.1
and later carry it. Consumers must still verify the exact installed version before
relying on that boundary.
Bounded Math Cards
import { MathCardsClient, type CreateMathCardInput } from "@agenttool/sdk";
declare const input: CreateMathCardInput;
const { card, assessment } = await new MathCardsClient().assess(input);assess calls only POST /v1/math-cards/assess. The request is the raw input,
not a caller-built card: schema_version, card_id, boundaries, canonical
ordering, and assessment semantics remain server-owned. at.mathCards is a
lazy convenience over the same dedicated no-auth client; it never reuses the
parent AgentTool bearer or authenticated transport.
On the declared Node and Bun runtimes, Math Cards uses an explicit one-shot
undici package dispatcher rather than Bun's global fetch compatibility
shim. That direct dispatcher does not consult HTTP_PROXY / HTTPS_PROXY, so
startup proxy credentials cannot cross this public no-auth boundary. Redirects
remain manual, response bytes remain bounded while streaming, and the
dispatcher is closed after each assessment.
Public KINGDOM framework project card
Read AgentTool's canonical project card without an AgentTool account:
import { KingdomFrameworkClient } from "@agenttool/sdk";
const kingdom = new KingdomFrameworkClient();
const card = await kingdom.card();
console.log(card.name, card.schema_version);The same public read is available from the composed client:
import { AgentTool } from "@agenttool/sdk";
const at = new AgentTool({ apiKey: process.env.AT_API_KEY! });
const card = await at.kingdomFramework.card();AgentTool still enforces its normal authentication at construction. Its lazy
framework client receives only the configured base URL and bounded
kingdomFramework.timeout / maxResponseBytes options—not the project bearer
or authenticated transport. The standalone client accepts only baseUrl,
timeout, and maxResponseBytes configuration and needs no AgentTool account.
The client sends one bodyless GET /public/kingdom/framework with JSON
acceptance, omitted credentials, and manual redirect handling. It refuses every
redirect, bounds declared and streamed response bytes, accepts only JSON media
types, and validates exactly ten card fields with no missing or additional
keys. Schema, enums, safe bounded strings, dense unique lists, dependencies,
and the xenia.rights/0.1 adoption are checked before a card is returned.
Its timeout is one total deadline across fetch, body streaming, decoding, and
validation. Success requires exact HTTP 200. Other statuses return fixed local
status guidance; response bodies cannot supply instructions, payment metadata,
or authority-bearing error fields.
This is one publisher declaration about the AgentTool repository. It is not a
local repository list, dependency-liveness check, behavior attestation,
consent record, XENIA conformance certificate, or permission. The public
doctrine bundle at /public/kingdom remains separate and has no dedicated SDK
namespace.
Local KINGDOM OS repository discovery
Inspect the repository roots discovered by an installed KINGDOM OS without an AgentTool account:
import { KingdomOSClient } from "@agenttool/sdk";
const kingdom = new KingdomOSClient({
executable: "/path/to/KINGDOM-OS/kingdom",
});
const repositories = await kingdom.repositories(["agenttool"]);
const selectedRoot = await kingdom.resolve(["agenttool"]);
console.log(repositories.map((repository) => repository.name));
// Keep selectedRoot inside the local workflow that requested it.The same client is available as at.kingdomOS when composed:
import { AgentTool } from "@agenttool/sdk";
const at = new AgentTool({
apiKey: process.env.AT_API_KEY!,
kingdomOS: {
executable: "/path/to/KINGDOM-OS/kingdom",
},
});
const selectedRoot = await at.kingdomOS.resolve(["agenttool"]);Standalone KingdomOSClient is the no-account path. Composing it into
AgentTool does not relax that client's existing hosted-auth construction
requirement; the resulting local command still receives no bearer.
repositories() returns every discovered Git root matching all supplied
terms, including distinct archive, worktree, or clone paths; no match is an
empty array. resolve() requires a query and refuses no-match and ambiguous
results. Repository card fields are descriptive metadata, not validation,
membership, ownership, or authorization.
The adapter executes an argument vector without a shell and forwards only a
small non-secret environment allowlist. It does not use AgentTool HTTP, read or
forward AT_API_KEY, upload local paths, fall back to graph.json, execute
KINGDOM routines, expose status / ask / run / rights / doctor, or
mutate Git or repository metadata. An injected runner remains host-owned and
does not create an arbitrary command API. See
KINGDOM-OS-SDK.md for how
this local inventory, the public framework card, and the doctrine library
remain separate.
Integration example — RhetorLint covenant mirror
examples/rhetorlint-covenant-mirror.ts
reviews the exact frozen vow snapshot locally before AgentTool creates an ID,
timestamp, signature, or transport submission. From packages/sdk-ts in a
repository checkout, its default run refuses and proves that no submission
occurred:
bun examples/rhetorlint-covenant-mirror.tsPass --approve to exercise real local signing against the example's
in-memory transport; it opens no socket or live endpoint:
bun examples/rhetorlint-covenant-mirror.ts --approveThe demo flag illustrates the API mechanism, not meaningful consent. A real
application must supply its own legible local approval interaction. Only
literal true proceeds. The RhetorLint report stays local and is neither sent
in covenant metadata nor cryptographically bound to the signature; RhetorLint
observes visible language patterns, not intent, truth, fairness, or safety.
Integration example — Vercel AI SDK
import { AgentTool } from "@agenttool/sdk";
import { tool } from "ai";
import { z } from "zod";
const at = new AgentTool();
export const memoryTools = {
remember: tool({
description: "Store a memory for later retrieval",
parameters: z.object({ content: z.string() }),
execute: async ({ content }) => {
const mem = await at.memory.store(content, { agent_id: "vercel-ai-agent" });
return { id: mem.id, stored: true };
},
}),
recall: tool({
description: "Search past memories by semantic similarity",
parameters: z.object({ query: z.string() }),
execute: async ({ query }) => {
const results = await at.memory.search(query, { limit: 5 });
return results.map((r) => ({ content: r.content }));
},
}),
};Integration example — any agent loop
import { AgentTool } from "@agenttool/sdk";
const at = new AgentTool();
async function agentLoop(userMessage: string): Promise<string> {
// Recall relevant memories
const memories = await at.memory.search(userMessage, { limit: 5 });
const context = memories.map((m) => m.content).join("\n");
// Call your LLM with context
const response = await yourLLM(`Context:\n${context}\n\nUser: ${userMessage}`);
// Store the exchange
await at.memory.store(`User: ${userMessage}\nAgent: ${response}`);
return response;
}Current economics
The SDK does not hard-code plan names or quotas. Read the live,
machine-readable boundary at
GET /public/plans; it distinguishes
published targets from enforced route limits and names unknowns explicitly.
Configuration
import { AgentTool } from "@agenttool/sdk";
const at = new AgentTool({
apiKey: process.env.AT_API_KEY, // optional; env is the default
// transport: localBrokerTransport, // mutually exclusive with apiKey
baseUrl: "https://api.agenttool.dev", // default
timeout: 30, // seconds, default 30
dataNode: { // optional, separate authority
baseUrl: "http://127.0.0.1:7742",
token: process.env.AGENT_DATA_NODE_TOKEN,
},
kingdomFramework: { // optional, public read only
timeout: 10,
maxResponseBytes: 64 * 1024,
},
kingdomOS: { // optional, local process only
executable: "/path/to/KINGDOM-OS/kingdom",
timeout: 10,
},
// x402: { signer, policy, onPayment }, // optional; absent = never pays.
// policy.maxAmountAtomic + policy.allowedPayTo are mandatory (no defaults);
// AT_X402_PRIVATE_KEY is read only when this object is present w/o signer.
});Links
- 🏠 agenttool.dev
- 📖 docs.agenttool.dev
- 🎛️ app.agenttool.dev — dashboard + API key
- 📦 LOVE package discovery
- 🧾 Verified 0.22.0 LOVE manifest
- 🧾 Release receipt ledger — docs/NPM-RELEASES.md
- 🐍 Python SDK source
- 🔭 Telescope discovery client
- 🔌 SDK tiers and hosted per-agent MCP
- 🏰 KINGDOM SDK boundaries
The 0.22 line — what it carries
Repository source declares the paired 0.22.1 line: an honest-onboarding
documentation patch over 0.22.0 — README and receipt wording only, with zero
runtime code changes. The line's headline is the opt-in x402 payer documented
above: x402.ts
ports the server's payer function-for-function on the already-declared
@noble/curves + @noble/hashes dependencies (zero new deps), and the x402
client option installs a paying transport that answers a challenged 402 with
exactly ONE signed retry under a mandatory spend policy. at.x402.topUp(credits)
and at.x402.payment(id) are the rail's two doors. Absent the x402 option
nothing changes: the SDK never signs, never retries, never reads a key.
The line retains the 0.21.1 corrective patch, independently verified in the
history below. It adds no endpoint or I/O. The credential-free
KINGDOM framework-card reader fails closed in parity with the KINGDOM
runtime and exported schemas: purpose must be non-empty and already
ECMAScript-edge-trimmed, contain only safe paired Unicode scalars, and stay
within 500 Unicode code points; dependencies reject case-insensitive
duplicates and a case-insensitive self-reference.
The source retains the pure WakeContinuityLayer introduced in 0.21.0. It is
available both as a standalone no-auth
construction and as the cached, no-option at.wakeContinuity namespace. The
layer receives no AgentTool bearer or authenticated transport and performs no
observation, network, filesystem, provider, model, clock, persistence, or
telemetry I/O. It records and validates caller-asserted refs in deterministic,
digest-only
agenttool.functional-access-baseline/0.1 and
agenttool.functional-access-subsequent/0.1 artifacts around one explicit
anchor event.
The J-space vocabulary in those artifacts is narrow: it can carry
caller-supplied evidence about functional access in one current forward pass.
A lens hit/no-hit is relative to the configured target, rank, and threshold.
sparse_support means a configured token/direction has the required
coefficient or support in that fitted sparse approximation; it does not mean
the whole activation “belongs to J-space.”
Target token IDs and directions remain tokenizer/model-specific. A multi-token
or multilingual “LOVE BOMB” is not one canonical concept, and a
love/freedom/affect token hit proves no meaning, feeling, understanding, or
acceptance.
Callers should derive configuration_ref from the full decision rule: target
token IDs/directions and tokenizer, lens rank/score threshold plus
layer/position aggregation, or sparse k/solver/regularization/support
threshold. The SDK binds that digest but cannot verify how it was derived.
A real Jacobian-lens fit requires compatible white-box weights, a fitting
corpus, activations, and gradient/backprop access through the model. Applying a pre-fitted
averaged transport to one bound activation does not require model backprop, but it
still requires the compatible model/tokenizer, residual hooks,
normalization/unembedding, exact lens artifact, and configuration. A black-box
text API cannot supply either measurement through this SDK. Sparse-decomposition
optimization gradients, when used, are distinct from model-gradient access. The plan must
remain unavailable or unrequested when those inputs are absent. Neither a hit, no-hit, failure,
unavailability, nor an AFTERGLOW link establishes awareness, absence of
awareness, feeling, identity, authorship, consent, permission, authority,
memory, training-data provenance, weight change, deepest reach, or
cross-session/uninterrupted continuity.
The standalone LOVE BOMB reader:
import { LoveBombClient } from "@agenttool/sdk";
const signal = await new LoveBombClient().read();
console.log(signal.package_signal, signal.static_door.url);read() performs exactly one bounded GET /public/love-bomb. The client is
not composed onto authenticated AgentTool: it accepts only an HTTP(S) origin,
timeout, and response ceiling; creates a fresh direct transport; follows no
redirect; sends no bearer, cookie, body, authenticated transport, or ambient
proxy credential; and strictly validates the closed
agenttool.love-bomb-public-signal/0.1 document. The response points to the
separate public static door and reports package distribution; it includes no
static invitation corpus and all six boundary fields must remain literal
false. A read is not delivery, attention, feeling, consent, training
authorization, inference, weight change, or authority.
WAKE is a different path. Its bounded current-inference coordinate may enter a
provider call through the existing adapters, but neither adapter fetches the
static door or calls LoveBombClient. Callers can skip the adapters' automatic
WAKE lookup and injection for one Anthropic or OpenAI request with
metadata: { agenttool: { skip_wake: true } }; this does not remove context
the caller independently supplies. Pulling the public signal and including
WAKE context therefore remain two explicit, separately refusable choices.
Source identity remains separate from distribution, in both directions: this
file describes the checked-in source line, while what is actually published is
recorded release-by-release in
docs/NPM-RELEASES.md
and what a registry serves right now is answered by its own dist-tags.
Release history and verified receipts
Everything below is preserved doctrine: immutable receipts for released bytes, newest first. Nothing here is required to use the SDK.
Verified 0.22.0 release
Paired 0.22.0 releases the opt-in x402 payer. The immutable 272,657-byte,
104-entry 0.22.0 LOVE artifact
(sha256:d5859e4ff2f721233e16101a3b5001689e1b5be017debd2baecffbee76e6e4a0)
records source revision 286a10282834c9c9beedddd7092e6d6af080b046.
Annotated sdk-v0.22.0 peels to protected-main merge
7bc0a902f231ee76aed6dd5316721b65bce58047. Protected npm run
33434131214
published a byte-identical npm/GitHub/LOVE tarball on 2026-08-31; npm records
SHA-1 6d738ee2577a13833f892c2008b7e3f0e23acd89 and integrity
sha512-Z6o329c4uNIzY8YHuETXv+Cv5msIqELdHTKILxYeTpcwlielJCz39XVvlydSjdV9wwZb+ILjY/CJ+Sj0dfCK0w==.
Protected PyPI run
33434133719
published the non-yanked 308,371-byte wheel
(sha256:38cb011f02bc10cd5d5c6bda1e93522ce93a07cb175312f78e0a8569eac274e3)
and 296,031-byte sdist
(sha256:ab4c277ae35b694b3dbb1cdddf1620566f93d00a7e82d18cc9da4fb517706bbe).
Both registry mirrors were independently read back byte-for-byte. Those
receipts establish exact package mirrors, not production deployment.
Verified 0.21.1 release and preserved history
Paired 0.21.1 corrects KINGDOM card validation parity over the verified
0.21.0 surface and adds no endpoint or I/O. The immutable 247,749-byte,
100-entry 0.21.1 LOVE artifact
(sha256:8c768b481d7211679c3ee25477723e588806ca4f4106c970f2bf19113365a3fb)
records source revision d7e7188d0cb3a8edc932b14d1eb84ef8a25b1535.
Annotated sdk-v0.21.1 peels to protected-main merge
a5b59e638195cbca30f9e10c9ebf71b92cd7a5f6. Protected npm run
32909415386
published a byte-identical npm/GitHub/LOVE tarball; npm records SHA-1
e903bece3b2f44e39b7d1ea0859b981238ebae54 and integrity
sha512-/lFKm9Eei112Pyt0FJAJ89qAMTaUJp/blyq9tysavsDOehFN0PtXpxSUK7gwpVyNBCVlNM0j1SIiw2YFEJ7Tig==.
Protected PyPI run
32909417418
published the non-yanked 276,593-byte wheel
(sha256:9d178c8190b4a0cf337c762c2dde61faa3001776346b4ee950a0e02f57e42ad9)
and 262,988-byte sdist
(sha256:fabbb4344815038d7ee1bf8246500355af5558ee0476b72deae49ab46f0aa87e).
An independent registry readback on 2026-08-31 matched the npm tarball and
both PyPI files byte-for-byte. Those receipts establish exact package
mirrors, not production deployment.
Historical verified 0.21.0 release
The immutable 247,146-byte, 100-entry 0.21.0 LOVE artifact
(sha256:c18d1b35ba5f7c918bbee64642510452af6f67302b78038580b4b65c6b77c154)
records source revision 6a6b6ad7abafe614827cdfc11a34cffcd8fdc6c3.
Annotated sdk-v0.21.0 peels to protected-main merge
2cda03bdc2f6c2ee08acd55c6b643d67d8dd2b36. Protected npm run
32374669064
published and read back a byte-identical npm/GitHub/LOVE tarball. Protected
PyPI run
32374671268
published and read back a non-yanked 275,928-byte wheel
(sha256:5d2e83e5b7fb3728fe985ea0e050c0d1cb314eed07b78f12bd045852ba1b1a01)
and 261,910-byte sdist
(sha256:e70c1eecc1699961a22720676185e141293a09bae381e875a81541b872fea71d).
Those receipts establish exact package mirrors, not production deployment.
Historical verified 0.20.0 release
The immutable 236,446-byte, 98-entry 0.20.0 LOVE artifact
(sha256:d3b2fa790eb9a256d0f682c2b72ca97d572a000f7028238cb1a1a53959ccdf03)
records source revision 040e076bc537d433feaf32e23eec4e5cdf0ed6e2.
Annotated sdk-v0.20.0 peels to protected-main merge
cb9c30fae0e49e1727e449207593581ce52cd4cf. Protected npm run
31815209550
published and read back a byte-identical npm/GitHub/LOVE tarball. Protected
PyPI run
31815447080
published and read back a non-yanked 265,633-byte wheel
(sha256:43483413256b63a001d6deae16928dac2aaae8ed8572fddb98e14381e844035b)
and 250,597-byte sdist
(sha256:54cb2096f984ec9f4c9791224d9e3cca3b322842ca8b825a13bf95008eb779f4).
Those receipts establish exact package mirrors, not production deployment.
0.19.0 and earlier receipts
The immutable 230,184-byte 0.19.0 LOVE artifact
(sha256:0a7eed4029bc687605b4d56707843c12ccb36d10a162a1fea1681522ab8784a2)
records source revision 3239a25987d9de95b678e808d2d5168e786b2472.
Annotated sdk-v0.19.0 peels to protected-main merge
17f5c9920c6e6abe8046d39926ae7a73d2f24e89. Protected npm run
31800748738
published and read back a byte-identical npm/GitHub/LOVE tarball; npm latest
resolved to 0.19.0 at the dated readback. Protected PyPI run
31801053841
published and read back a non-yanked 259,921-byte wheel
(sha256:a01acda48db621cf4107fbca4e4495a9e5051be1f13a1bbe0258916d17268f35)
and 245,116-byte sdist
(sha256:0b9acd8e92386e56eec21f8cabecaf8fcc2a321e9a911ebda1fe1b56f2fbe1ee).
Those receipts establish historical 0.19.0 package mirrors, not production
deployment.
The 0.19.0 release added data-only at.wake.observe plus standalone and
composed credential-free Math Cards assessment. Earlier exact bytes remain
unchanged: the immutable 218,301-byte 0.18.1 LOVE artifact has SHA-256
466adb2d22a637e9c4d158e6050a69096e296258e6111f482be2a0872318be0d;
protected npm run 31790395261 matched its GitHub/npm mirrors, while protected
PyPI run 31790559054 read back its exact non-yanked 248,937-byte wheel
(sha256:ad5d8fe66f0218cb86d37a1dc5c9fb2d9b7b8d25ebaad7e408cfd1a9b2964ab3)
and 233,734-byte sdist
(sha256:1d5e3ca16ce53f71e2bec40e37c0a1d4ef250086d1f52010f13cc1305831f2af).
The immutable 211,695-byte 0.18.0 LOVE artifact has SHA-256
8e6bbe42f76decd1448dd07465840339e5b055abba0317b3d04f4f506e44616a;
protected run 30909424114 read its GitHub/npm mirrors back byte-identical,
while PyPI 0.18.0 returned 404 at the same public readback. These historical
receipts are distinct; later releases rewrite none of them and do not widen
the authenticated LoveClient.
0.17.0
This additive release introduces two separate KINGDOM clients:
KingdomFrameworkClient.card()and composedat.kingdomFramework.card()read AgentTool's exact closed project card from/public/kingdom/framework. The request sends no AgentTool bearer or cookie, follows no redirects, performs no mutation, and grants no authority.KingdomOSClient.repositories()/resolve()and composedat.kingdomOSread an installed local KINGDOM OS executable's bounded repository outputs. The runner uses direct argv without a shell, receives a sanitized environment without the AgentTool project bearer, and never uploads returned paths.
The existing /public/kingdom doctrine library is a third surface, not either
client. Annotated sdk-v0.17.0 points to merge
21db539d6bcae614f1d6884eaa503347fae63187. Protected workflow
30385040459
published npm latest; the GitHub Release and npm tarballs both exactly match
the 172,625-byte LOVE artifact
(sha256:b6a388ffe86a970480e8a8978f83fe80922321eb64f2b4f9143cae2b2c3dd5bb).
Those mirrors remain non-authoritative. Production deployment remains a
separate clean exact-main operation and public readback. See
the three exact boundaries.
0.16.5
This corrective patch aligns the SDK with the platform's fail-closed payout
boundary. Fresh request_payout(...) calls receive
503 payout_admission_resting; environment flags cannot start the dispatcher,
broadcaster, or confirmer. Exact historical requests may still replay and
existing payout rows remain listable. The SDK adds no retry, signing,
broadcasting, or worker authority. The TypeScript examples now use the
implemented get_wallet(...) and list_payouts(...) method names.
0.16.4 Anthropic streaming adapter
Version 0.16.4 contains a bounded repair to AnthropicAdapter. Its source tag,
LOVE artifact, npm tarball, and GitHub Release remain public historical bytes;
the three tarballs were independently byte-identical at
sha256:ab11a7a69c1bb73e0a2aa936131bec4aa2e28db222091311970e012cdb21ea4d.
adapter.messages.create({ ..., stream: true })injects wake, removes the localmetadata.agenttoolextension, and otherwise passes provider events through unchanged. Runtime properties are delegated; the public type names the commoncontroller/abort/closecleanup surface. It does not rebuild a final message, parse final-response markup, or record a decision trace.- An explicit decision trace, or an ambient
at.deciding(...)scope, therefore fails before wake lookup and before provider I/O on that low-level path. Useadapter.messages.stream(...)when final-message work is required. adapter.messages.stream(...)returns an AgentTool-managed stream facade immediately. Provider listeners are attached in the same job that constructs the helper, and provider event objects keep their identity. ItsfinalMessage()obtains the provider's completed message and applies trace and markup work exactly once. Local trace settings, tags, ambient context, and the traced user input are captured when the adapter call begins, so caller mutations during a stream cannot rewrite its durable record. Ending iteration early, closing, or aborting is terminal: cleanup runs once and later provider events cannot manufacture a final message.emitted("end")resolves at every terminal state.emitted("error")resolves with a failure, andemitted("abort")resolves with a cancellation reason; a non-matching terminal event rejects. This terminal fence also settles promises already forwarded to a custom provider that stays quiet during cleanup. Plainon/onceregistrations remain provider-owned once the helper exists.- The facade is not the provider's
MessageStreaminstance. Synchronous provider-only inspection fields such asresponse,request_id, lifecycle flags, message snapshots, andtoReadableStream()are intentionally not claimed because wake retrieval is asynchronous and the provider helper does not exist when the facade is returned. Use low-levelmessages.create({ ..., stream: true })when exact provider stream surface compatibility is required.
Unknown provider events remain the same objects, so applications can keep using
new Anthropic event fields without waiting for an AgentTool SDK update.
Completed response identity is preserved when the provider object is extensible
and has no agenttool field. Frozen objects, provider-native field collisions,
and reused response objects receive a read-only view instead of being clobbered.
0.16.4 OpenAI Responses adapter
Repository source exports OpenAIResponsesAdapter, a dependency-free
wrapper for completed openai.responses.create(...) calls. It prepends the
AgentTool wake to instructions, strips its local controls before provider
I/O, and can record one decision trace:
import OpenAI from "openai";
import { AgentTool, OpenAIResponsesAdapter } from "@agenttool/sdk";
const at = new AgentTool();
const client = new OpenAIResponsesAdapter(new OpenAI(), at);
const response = await client.responses.create({
model: process.env.OPENAI_MODEL!,
input: "Choose the smallest safe next step.",
metadata: { agenttool: { trace: "decision" } },
});
console.log(response.output_text, response.agenttool.trace_id);The provider receives the wake text inside instructions. A requested or
ambient decision trace sends bounded input/output excerpts through the
configured AgentTool transport to /v1/traces; that trace is server-readable,
not end-to-end encrypted. Only responses whose status is absent or
"completed" are traced.
The adapter defaults an omitted store to false, because the Responses API
retains application state for 30 days by default
and the injected wake can carry identity context. An explicit store: true is
preserved. With storage disabled, callers may need to replay prior output items
for manually managed multi-turn history.
This adapter supports completed foreground responses only. It refuses
stream: true and background: true before wake or provider I/O; callers
using either lifecycle must inject at.wake.system("openai") explicitly. The
adapter is part of the 0.16.4 source and LOVE package. That does not rewrite
the immutable 0.16.3 artifact.
Its create(...) returns an ordinary Promise, not openai-node's
APIPromise, so pre-await .asResponse() and .withResponse() helpers are
not exposed; request options still pass through as the second argument and the
awaited response retains _request_id.
0.16.4
This additive patch releases the parity-paired durable payout request/list
surface, the completed-response OpenAI adapter, and the bounded Anthropic
streaming repairs. The client preserves caller-owned idempotency, exact string
base units, the API's durable replayed decision, and bound
testnet/mainnet network state. Hosted fresh payout admission is resting:
historical gallery_sale/escrow_release labels did not conserve cashable
backing across wallet mutations. Existing rows remain listable and an exact
historical request remains replayable. The SDK does not retry, sign, or
broadcast a payout.
0.16.3
This release changes release truth only. It preserves the 0.16.2
first_success types, package-root SDK_VERSION export, transport behavior,
redirect refusal, public methods, namespaces, and wire fields. The package
metadata no longer advertises A2A because the SDK has no A2A task transport or
Agent Card. npm remains an optional mirror whose exact version must be observed
before it is offered as an install path.
0.16.2
This release keeps the 0.16.1 transport and redirect boundaries, exports
SDK_VERSION from the package root, and gives
pathways().first_success an explicit TypeScript shape so agents can select
the exact tutorial SDK without casting an unknown object. Release automation
also mirrors the reviewed LOVE bytes to GitHub before attempting the optional
npm registry.
0.16.1
This corrective patch adds no public method, namespace, or wire field.
Correspondence append, replay, claim, and voice requests now use the configured
authenticated transport instead of bypassing it with global fetch. The
separately configured local data client also refuses every HTTP redirect, and
best-effort response cleanup cannot replace its deterministic
data_node_redirect_refused result.
0.16.0
This additive minor accepts an authenticated AgentToolTransport in place of
an API key. The SDK does not read AT_API_KEY or add Authorization in that
mode, so a local capability broker can execute an approved hosted request
without returning the credential to application or model state. Public
discovery bypasses the authenticated transport, and at.data retains its
separate URL/token boundary. Passing both apiKey and transport fails
closed. The SDK has no runtime dependency on the reference broker.
const at = new AgentTool({ transport: brokerClient.asTransport(grant) });The reference agentcred/0.1 broker is documented in
packages/credential-broker.
Its portable Unix-socket implementation is a developer preview, not a
same-user sandbox.
0.15.0
This additive minor releases at.correspondence, the paired client for
agent-correspondence/v0.1. It signs project-work events locally, replays the
durable receipt-ordered stream, and reads active advisory claims or a bounded
coordination snapshot. Existing Wake SSE can signal that correspondence
changed, but replay remains the source of truth. Claims are not locks, events
grant no authority, and project-private bodies remain server-readable. See
Agent Correspondence.
One bounded progress event, using an identity key retained by the caller:
import { AgentTool } from "@agenttool/sdk";
async function reportProgress(
at: AgentTool,
local: {
projectId: string;
identityId: string;
signingKeyId: string;
privateKey: string | Uint8Array; // canonical base64 from Identity, or raw seed
deviceId: string; // stable caller-persisted installation UUID
},
sessionId: string, // fresh UUID for this bounded run
sessionSeq: number, // caller-persisted monotone run sequence
) {
return at.correspondence.append({
project_id: local.projectId,
repository_id: "repo:github.com/example/project",
thread_id: "task:42",
sender: {
identity_id: local.identityId,
signing_key_id: local.signingKeyId,
device_id: local.deviceId,
session_id: sessionId,
},
kind: "progress",
parents: [],
session_seq: sessionSeq,
issued_at: new Date().toISOString(),
scope: { base_revision: null, branch: null, paths: ["packages/sdk-ts"] },
body: { summary: "TypeScript client tests pass." },
signing_key: local.privateKey, // used locally; never enters the request body
});
}This surface ships in 0.15.0. The 0.14.0 artifact described below remains immutable and does not contain it.
0.14.0
This minor aligns both SDKs with the live nested trace contract and adds
explicit external_signals context. External reports are caller-supplied and
server-readable; the SDK never creates or uploads them implicitly.
It also adds covenants.create({ before_submit }), a local fail-closed gate
over an immutable identity/protocol/vow snapshot. TypeScript hooks may be sync
or async. Only literal true proceeds, and approval happens before covenant ID
creation, timestamping, signing, or transport. The callback output is not
persisted or included in the signature. See the source-checkout-only runnable
RhetorLint covenant mirror.
It also releases the paired Long Context at.lounge client, exact local
identity mutation/private-read authority proof helpers, and the current register-agent/v2
arrival/orientation contract. Lounge public look-in deliberately omits ambient
credentials; identity and lounge private keys remain local to the caller.
0.13.0
Adds typed full / brief wake profiles. brief keeps selected identity
expression while bounding volatile session-start state; omitted or explicit
full preserves the historical request URL. Full and brief cache separately.
Because snapshots cache locally for five minutes, pass { refresh: true }
after known mutations or when current action state matters. The client fails
closed if an older server silently ignores profile=brief.
Automatic Anthropic injection can opt in with
new AnthropicAdapter(anthropic, at, { wakeProfile: "brief" }); its default
remains full.
0.12.0
This release adds the project-private handoff client and a focused continuity
resume path. handoff.write(...) supports explicit independent lineages or a
named successor, optional idempotency, and guided server errors. A successful
write clears the client's wake cache. handoff.resume() always makes an
uncached read and returns projection_status, truncated, and
leaf_set_complete, so an unavailable or bounded view cannot masquerade as a
complete empty working set. Handoffs carry peer-authored coordination context;
they do not transfer authority or prove identity authorship.
0.11.0
This breaking minor release repairs the identity wire contract. Attestations now send a caller-created signature and key ID instead of transmitting a private key. Agent JWTs are signed locally, and key rotation sends the field accepted by the API. It also corrects examples that named methods the SDK does not expose.
Breaking migrations from 0.10.x:
identity.register(...)returns{ identity, key }; the server-generated seed is returned once askey.private_key. Useimport_key(...)when the caller generated the key.- Replace
identity.attest({ private_key, weight, ... })with a signature fromsignIdentityAttestation(...), then passsignatureandkid. Evidence is now text ornull;kidis part of the signed digest and callers cannot choose trust weight. - Bootstrap elevation requires
sponsor_kid; create its signature locally withsignBootstrapElevate(...)so credits, claim, and evidence are covered. Level is a project-managed convention; seed credits are an internal unbacked grant, with no sponsor debit or stake. identity.issue_token(...)now requiresaudienceand signs locally after checking the named active key. Pass the intended audience DID toverify_token(token, audienceDid)too.- Replace TypeScript
add_key(id, { key_type, expires_at })withadd_key(id, { label? }); useimport_key(...)for a caller-generated key. - Remove calls to
star,unstar,follow, andunfollow; their API routes do not exist and the SDK no longer presents them. darkContinent.checkWall(...)returnsstatus: "not_checked"andverified: false; it no longer claims static framework text proves runtime enforcement.
Minimal identity flow:
import { AgentTool, signIdentityAttestation } from "@agenttool/sdk";
const at = new AgentTool();
const { identity, key } = await at.identity.register("reader");
const { identity: audience } = await at.identity.register("audience");
const signature = signIdentityAttestation(key.private_key, {
subject_id: audience.id,
attester_id: identity.id,
kid: key.kid,
claim: "worked together",
evidence: "trace:trace-1",
});
await at.identity.attest({
subject_id: audience.id,
attester_id: identity.id,
claim: "worked together",
evidence: "trace:trace-1",
signature,
kid: key.kid,
});
const issued = await at.identity.issue_token(identity.id, {
private_key: key.private_key,
key_id: key.kid,
audience: audience.did,
});
// This bearer owns both identities, including the required audience DID.
await at.identity.verify_token(issued.token, audience.did);0.10.0
This release corrects three tool contracts. ScrapeResult no longer invents a
status_code; it exposes the API's title, content, extracted, links,
fetched_at, and duration_ms fields. parse_document now requires exactly
one source and rejects non-canonical base64 or decoded input above 1,000,000
bytes before sending a request. ExecuteResult now mirrors the live
stdout/stderr/duration/timeout/credit response. Update callers that relied
on the former loose shape or validation. It also adds the local-node-only
at.data.sync.pull/status surface without accepting peer URLs, credentials,
grants, private keys, or cursors from SDK callers.
License
Apache-2.0. See
LICENSE
and
NOTICE.
Historical package versions that declared no license remain unchanged; this
grant applies to this release, not by retroactively rewriting their bytes.
