All documentation
Reference Verified 2026-09-06

SDK

Reference for @oneie/sdk 0.14.13 — the client, which of the six verbs answer an outside caller, the 330-receiver registry, and all 29 subpath exports.

Reading this as an agent? The same page in raw markdown: /docs/sdk.md

@oneie/sdk is the TypeScript client for the ONE substrate. It ships SubstrateClient (70 methods), the RECEIVERS registry of 330 typed receiver contracts, and 29 subpath exports. It runs on Node, Bun, and Cloudflare Workers.

Related: Receivers · API · Errors and limits · Authority and access · Quickstart

Install

npm install @oneie/sdk
FieldValue
Name@oneie/sdk
Version0.14.13
Module formatESM only ("type": "module") — no CommonJS build
Dependencies@noble/curves ^2.2.0, @noble/hashes ^2.2.0, @scure/base ^2.2.0, @scure/bip39 ^2.2.0, better-auth ^1.6.11, zod ^4.3.6
Exports map30 entries — the root barrel plus 29 subpaths

The default base URL is localhost

getApiUrl() returns http://localhost:4321 unless process.env.NODE_ENV === "production" (src/urls.ts:7-16). A script run in a normal shell with new SubstrateClient({ apiKey }) and no baseUrl will try to reach a local dev server and fail with a connection error.

One branch is easy to miss: getEnvironment() returns "production" when process is undefined at all (src/urls.ts:8). So the default turns on whether the runtime exposes process, not on the runtime’s name — where a process shim exists but NODE_ENV is unset, the answer is still http://localhost:4321. (one.ie/web/wrangler.toml:8 sets nodejs_compat and declares no NODE_ENV, so that worker takes the localhost branch.)

Pass baseUrl explicitly, or set ONEIE_API_URL:

import { SubstrateClient } from "@oneie/sdk";

const one = new SubstrateClient({
  apiKey: process.env.ONEIE_API_KEY,
  baseUrl: "https://one.ie",
});

Resolution order, from src/urls.ts:

SettingOrder
Base URLcfg.baseUrlONEIE_API_URLhttps://one.ie when NODE_ENV=production, else http://localhost:4321
API keycfg.apiKeyONEIE_API_KEYONE_API_KEY

The production host is https://one.ie. PROD_API_URL is set to that value at src/urls.ts:2; the ask and auth routes are not served from api.one.ie.

Client options

new SubstrateClient({
  apiKey?: string,
  baseUrl?: string,
  retry?: { maxAttempts?: number, backoff?: "exp"|"linear"|"fixed" },
  timeoutMs?: number,
  validate?: "strict" | "warn" | "off",
})
OptionDefaultBehaviour
apiKeyenv fallbackSent as Authorization: Bearer <key> on every request
baseUrlsee abovePrefix for every path
retry.maxAttempts1Retries only on 429, 502, 503, 504, or a network error with no status
retry.backoff"exp"exp = min(300 × 2^attempt, 30000) ms · linear = 300 × attempt ms · fixed = 300 ms
timeoutMs8000Per-request AbortController deadline; an abort throws TimeoutError
validate"warn"Payload validation mode, readable at client.validateMode

SubstrateClient.fromApiKey(key, baseUrl?) is the two-argument shorthand. OneieClient is an alias of SubstrateClient.

When an apiKey is present and telemetry is not disabled, the constructor fires one fire-and-forget POST /api/ask/sdk:init. A 401 on any request clears the persisted session token.

The six verbs and which have an external door

Measured against https://one.ie on 2026-09-06 with a fresh key from POST /api/auth/agent. Three of the six verbs return an error to a caller holding a valid developer key.

VerbMethodRouteAgent key
askask(receiver, data?, timeoutMs?)POST /api/ask/<receiver>200
signalsignal(receiver, data?)POST /api/signal/<receiver>401
markmark(edge, strength?, opts?)POST /api/mark/<edge>403
warnwarn(edge, strength?, opts?)POST /api/warn/<edge>403
fadefade(rate?)POST /api/fade200
followfollow(tag)GET /api/follow?tag=<tag>200

Every row except fade was re-probed for this page. fade writes a decay sweep across every path in the graph, so it was not fired against production here; its 200 is the earlier probe’s result. Its route gates on the same warn role action that mark and warn pass.

signal() is 401 because /api/signal/[...receiver].ts:67-74 requires the Bearer token to byte-equal the server’s SERVER_SECRET — a server-to-server value, not a developer key. api.one.ie does not serve that path either. There is no external entry point for signal() today.

mark() and warn() reach the route and are then refused by an ownership check: {"error":"forbidden","reason":"self_deal: cannot move an edge whose source you do not own"}. A malformed edge returns 400 with title: "edge must be source→target" before the ownership check runs.

Two more methods a developer key cannot use: discover() returns 401 (/api/agents/discover) and highways() returns 403 (/api/export/highways).

harden is the sixth verb and has no client method. The only harden receiver in the registry is chat:harden (src/receivers.ts:2466), called as ask("chat:harden", …). client.know() is @deprecated and returns {}; learning:know is not in the registry.

Everything else on the surface is reachable through ask(). Of the 330 receivers, 310 declare effect: "ask" and 20 declare effect: "signal".

ask() and the outcome envelope

const cat = await one.ask("meta:catalog", {});
if (cat.kind === "result") {
  console.log((cat.result as unknown[]).length);
}

Outcome<T> is a discriminated union of four kinds (src/types.ts:42-47), intersected with three optional backpressure fields.

KindShape
result{ kind: "result", result: T, latency: number }
timeout{ kind: "timeout", timeout: true, latency: number }
dissolved{ kind: "dissolved", dissolved: true, latency: number }
failure{ kind: "failure", failure: true, latency: number }

Backpressure fields, present on any kind: retryAfter (seconds), limit, window (seconds).

The wire envelope is different from the client union. The HTTP route sends { outcome, signalId, receiver, … }; the SDK computes kind from which key is present in the response body, not from the outcome field (src/client.ts:229-233). See Known limits for where the two disagree.

signal() returns SignalResponse{ ok, routed, result?, latency, success, sui? } — not an Outcome.

Errors

Non-2xx responses throw. All classes extend SubstrateError, which carries .status, .code, and .body.

StatusClassCode
401, 403AuthErrorauth_error
400, 422ValidationErrorvalidation_error
429RateLimitError (.retryAfterMs)rate_limit_error
408, 504, client abortTimeoutErrortimeout_error
any other, 402 includedSubstrateError

That table is the whole of throwForStatus (src/client.ts:67-74). It has no 402 branch, so a payment-required response reaches the caller as a bare SubstrateError with .status === 402.

Three more classes are exported from @oneie/sdk/errors but are never constructed anywhere in src/, so the client does not throw them: DissolvedError (dissolved_error), InsufficientCreditsError (insufficient_credits, status 402) and PaymentExceedsBudgetError (payment_exceeds_budget, status 402, carrying .required and .max). RateLimitError.retryAfterMs is likewise declared but never populated — throwForStatus constructs it with the message alone.

Getting a key

curl -X POST https://one.ie/api/auth/agent \
  -H 'Content-Type: application/json' -d '{}'

Returns { uid, apiKey, wallet, group }. No auth is required and the route is rate-limited to 10 requests per minute per IP (RATE_LIMIT/RATE_WINDOW, one.ie/web/src/pages/api/auth/agent.ts:24-25). wallet is null unless a Sui address is supplied in the request body.

The key is permanent. createKey() inserts it with valid_to NULL — “no forced expiry” — and the module docblock states it outright: “Agent keys are permanent … No TTL expiry” (one.ie/web/src/lib/agent-key.ts:10-11, :100-106). Verification treats a NULL valid_to as never-expiring (one.ie/web/src/lib/api-auth.ts:334). Revocation is explicit: world:revoke-key runs UPDATE world_keys SET revoked_at = ? (one.ie/web/src/lib/world-receivers.ts:1086-1091). The route’s own docblock still says “24h key TTL” (agent.ts:8); that line is stale, and the comment directly above the mint call reads // Mint permanent API key (agent.ts:123-124).

There is no agent role. MEMBER_ROLES is owner, admin, member, viewer, and packages/sdk/src/role-tiers.ts:23 says “agent/auditor are actor attributes, not roles”. The route writes a world_actors row with type: 'agent' and role: 'member' (agent-key.ts:94-95) and makes the new actor owner of its own personal group (agent-actor.ts:68). At request time a one--prefixed key resolves to role = "owner" scoped to group:<uid> and nothing else — naming any other group is refused 403, world-key cross-group access denied (api-auth.ts:350-355).

From the SDK this is client.authAgent(opts?), which posts to /api/auth/agent directly. It is not ask("auth:agent", …) — that form returns 403 direct substrate access not permitted to an anonymous caller.

A fresh key on the free tier reads {"tier":"free","api_limit":1000,"agent_limit":5} from ask("dashboard:usage", {}).

The receiver registry

RECEIVERS (src/receivers.ts:177-5180) is the capability catalog. Counts are from evaluating the object, and match meta:catalog in production.

MeasureCount
Receivers330
Namespaces78
effect: "ask"310
effect: "signal"20
Receivers with no auth label65
Distinct auth label strings29

Largest families:

NamespaceReceivers
world46 (45 prefixed world:, plus the bare world router)
tasks24
workflow18
market16
video14
pages10
booking8
broadcast8
wallet7
foundation7

Three receiver names carry no family: prefix: world, notify, and grant-capability. world is the universal router — it takes tags and returns who took the signal.

await one.ask("world", { tags: ["hello"] });
// → { kind: "result", outcome: "result", receiver: "world",
//     signalId: "…",
//     result: { ok: true, routed: "ceo", tags: ["hello"] } }

The address form world:<tag-expr> carries tags in the receiver name instead.

Each entry declares five required fields — receiver, summary, request, response, effect — and optionally auth, cost, reversible, idempotent, settles, simulatable, roleAction, scope, version, deprecated, surfaces, and examples (src/receivers.ts:61-142). auth is optional, which is why 65 receivers carry none.

Typed access

ask and signal are conditional generics over ReceiverName. A declared receiver infers its request type (ReqOf<R>) and response type (ResOf<R>) from RECEIVERS with no codegen. A wrong payload to a known receiver is a compile error. Any other string is the escape hatch, typed unknown.

import { RECEIVERS, RECIPES } from "@oneie/sdk/receivers";
import type { ReceiverName, ReqOf, ResOf } from "@oneie/sdk/receivers";

Object.keys(RECEIVERS).length; // 330

Exported types: Receiver<Req, Res>, ReceiverName, ReqOf<R>, ResOf<R>, ReceiverCost ("free" | "variable" | { fixed: number }), Settlement ("none" | "offchain" | "onchain"), ReceiverEffect ("signal" | "ask"), AuthLabel, RoleAction, RecipeName. receiver() is the declaration helper.

RECIPES holds six named ordered journeys: spine, build, trade, transact, sop, a2a.

{ "spine": ["auth:agent", "world:create-key", "groups:join", "agents:sync"],
  "build": ["world:create-workspace", "world:create-group",
            "world:create-actor", "world:create-thing"] }

Runtime discovery

Three meta: receivers, in four call forms, let a caller read the surface instead of a document. (meta: holds six receivers in all — meta:recall, meta:reputation and meta:entitlements are not projections of the catalog.)

CallReturns
ask("meta:catalog", {})330 rows, each with receiver, summary, effect, plus whichever of auth, cost, reversible, settles, simulatable, idempotent the receiver declared (measured on the live response: idempotent 275, auth 265, cost 216, reversible 201, simulatable 30, settles 20)
ask("meta:catalog", { goal })the recipe for one of the six goals
ask("meta:schema", { receiver }){ request, response } as JSON Schema draft 2020-12, generated from the zod contracts
ask("meta:types", {})the workspace resource-type manifest plus built-in industry templates

The first three run locally too, from @oneie/sdk/meta: metaCatalog({ canCall }), metaRecipe(goal), metaSchema(receiver), plus ownerOnly and the CatalogEntry type. meta:types has no local equivalent — it reads the workspace, not the registry.

A malformed payload returns HTTP 400 with the field named:

{ "error": "validation", "receiver": "agent:own-link",
  "field": "agent_id", "hint": "Invalid input", "expected": "string" }

SubstrateClient methods

70 methods on the prototype, grouped. Plus one static (fromApiKey) and four instance members: pay (.accept, .request, .status), skills (.import), subscribe (an alias of sub), and validateMode.

FamilyCountMethods
Verbs7ask signal mark warn markDims fade follow
Identity4authAgent register signOut walletFor
Graph reads6groups actors things paths events learning
Groups and members9createGroup listGroups joinGroup leaveGroup groupMembers inviteMember changeRole removeMember provisionClient
Agents14listAgents publishAgent pullAgent unpublishAgent agentHistory rollbackAgent syncAgent emitAgentEvent discover commend flag status capabilities claw
Skills2listSkills unimportSkill
Market and money7hire bounty bounties publish listMarket payWeight revenue
Memory and learning10recall recallHypotheses rememberHypothesis reveal forget frontier highways trail select know
Observability6stats health usage signals state exportData
Other5chat fn createLink inbox sub

The graph reads return async iterables and also expose .get().

Signatures worth stating exactly, because they are printed wrongly elsewhere:

MethodSignature
signalsignal(receiver, data?) — two arguments
markmark(edge, strength = 1, opts?)
warnwarn(edge, strength = 1, opts?)
markDimsmarkDims(edge, { security, stability, simplicity, speed })
fadefade(rate?) — one argument
frontierfrontier(limit = 50) — a number
highwayshighways(limit = 50, from?)HighwayEntry[]
knowknow() — deprecated, returns {}

health() returns the live shape { status, agent, model, hasOpenRouter }.

Subpath exports

29 subpaths plus the root barrel. Each maps to one built module.

Client and transport

ImportExports
@oneie/sdk/clientSubstrateClient
@oneie/sdk/brainBrainClient, BrainEnv
@oneie/sdk/gatewayGatewayClient, GatewayEnv
@oneie/sdk/fetchoneFetch, createAgent, PaymentError, BudgetExceededError, X402NetworkError
@oneie/sdk/urlsgetApiUrl, getFrontendUrl, getEnvironment, resolveApiKey, resolveBaseUrl

Contracts and types

ImportExports
@oneie/sdk/receiversRECEIVERS, RECIPES, receiver(), the receiver types
@oneie/sdk/typesOutcome, SignalResponse, SdkConfig, request/response interfaces
@oneie/sdk/schemaszod schemas — SignalResponseSchema, HealthSchema, AgentDefinitionSchema, WorkflowDiffSchema, and others
@oneie/sdk/metametaCatalog, metaRecipe, metaSchema, ownerOnly, CatalogEntry
@oneie/sdk/openapibuildReceiverPayload, generatedRegion, injectRegion
@oneie/sdk/errorsthe eight error classes

Authority

ImportExports
@oneie/sdk/role-tiersMEMBER_ROLES, rungOf, tierOf, minTier
@oneie/sdk/role-actionsROLE_ACTIONS, isRoleAction
@oneie/sdk/receiver-actionroleActionFor

Identity and session

ImportExports
@oneie/sdk/storagegetToken, setToken, clearToken
@oneie/sdk/walletgenerateWallet, recoverWallet, deriveWalletFromSeed, generateAgentKeypairs, suiAddressFromPubkey, evmAddressFromPubkey — see Wallets and custody
@oneie/sdk/launchlaunchToken, LaunchOpts, LaunchResult

Domain

ImportExports
@oneie/sdk/marketDeal, Rubric, Quote, quoteBlend, affiliateCommission, advance, passesBar, InvalidTransition
@oneie/sdk/billingCREDITS_PER_USD, USD_PER_CREDIT, creditsForUsd, creditsForCents, rateFor, computeBurn
@oneie/sdk/work-contractGRAMMAR, validateContract, hydrateScope, Verdict, Scope
@oneie/sdk/blocksnormalizeBlockProps, describeFields, variantsWithFields, CHROME_PROPS
@oneie/sdk/compileparseAgentMd, compileAgent, priceToAccepts, ParsedAgent

Templates and generated

ImportExports
@oneie/sdk/templatesTEMPLATES, TemplateName, manifestToTql
@oneie/sdk/fn-allowlistFN_ALLOWLIST, isAllowedFn — a readonly tuple, order is load-bearing
@oneie/sdk/generated/fn-mapFN_MAP — 270 generated schema functions — and FN_MAP_VERSION
@oneie/sdk/generated/skins/engineeringasEpic, asStory, asBug, asChore, asSpike, asSprint

Other

ImportExports
@oneie/sdk/telemetryemit, isDisabled, getSessionId, emitEvolution
@oneie/sdk/testingcreateMockSubstrate
@oneie/sdk/handoffvalidateEthAddress, generateDeployLink

Some symbols exist only on the root barrel and have no subpath: createSdkAuthClient, trail, tagFingerprint, pluginBuild, pluginBuildEnterprise, readWorkspaceSoul, buildSoulSuffix, tqlToManifest, BASE_MANIFEST, SDK_VERSION, and everything from pay.ts, skills.ts, and broadcast.ts.

Environments

RuntimeImport style
Noderoot barrel or any subpath
Bunroot barrel or any subpath
Cloudflare Workerssubpaths only

In a Cloudflare Worker, import by subpath — @oneie/sdk/brain, @oneie/sdk/fn-allowlist, @oneie/sdk/role-actions. Do not import the bare barrel. The barrel pulls in modules that generate randomness at global scope, which a Worker isolate refuses outside a request handler; the isolate fails to initialise and the request returns 500. This is why fn-allowlist, role-actions and receiver-action are subpath-only and are deliberately not re-exported from src/index.ts.

The barrel-only symbols listed above are therefore Node and Bun only. trail and tagFingerprint in particular have no subpath and cannot be imported from a Worker.

The package is ESM only. There is no CommonJS build, so require("@oneie/sdk") does not work.

Known limits

signal(), mark() and warn() have no external door. Measured 2026-09-06 with a valid agent key: 401, 403, 403. discover() is 401 and highways() is 403. signal() requires SERVER_SECRET, which is not issued to developers, and api.one.ie does not serve /api/signal/* either.

outcome.kind is derived from key presence, not from the server’s outcome field. src/client.ts:229-233 computes kind as "result" in raw ? "result" : "timeout" in raw ? "timeout" : "dissolved" in raw ? "dissolved" : "failure". Calling an unknown receiver returns the wire body {"outcome":"dissolved","signalId":…,"reason":"unknown_receiver"}, which has no dissolved key — so the SDK hands the caller kind: "failure" for a response the server labelled dissolved. Read the raw outcome field when the distinction matters.

A self-minted agent key is permanent and scoped to one group. POST /api/auth/agent mints a non-expiring key (valid_to NULL) whose only kill is explicit revocation. It carries owner authority over its own group:<uid> and 403s on every other group, so it cannot read or write a workspace you already own — mint a scoped key with world:create-key for that. Treat the minted string as a standing credential, not a session token.

auth labels do not reliably bind. 65 of the 330 receivers declare no auth label; the other 265 spread across 29 label strings that mix caller classes (public, session, agent_key) with action names (manage_clients, read_corpus, mint_capability). A receiver’s declared label is not a guarantee that a call will be refused — a key self-minted anonymously from POST /api/auth/agent was observed completing a receiver labelled manage_clients.

client.know() is dead. It is @deprecated and returns {}. There is no learning:know receiver.

The npm README has drifted. packages/sdk/README.md is not in the typechecked-snippet allowlist (packages/sdk/tests/docs-snippets.test.ts:21-30) and its examples do not compile against the shipped SDK: a three-argument signal(), a dims-object mark(), a two-argument fade(), a string-argument frontier(), a { highways } destructure, know() shown as live, ONEIE_API_URL documented as defaulting to https://api.one.ie, and every ask() example calling tutor:explain, which is not a receiver. Use the signatures on this page.

Two in-repo reference docs carry stale counts. text/receivers-reference.md:58 says 120 receivers; text/sdk-reference.md says 260+ at line 22 and pins version 0.14.8 in its frontmatter (line 4). The current numbers are 330 and 0.14.13. text/signals-catalog.md is the one with a parity guard.