The SDK,
method by method
The complete public surface of the TypeScript SDK
(agentmesh 0.2.1), plus the Rust parity matrix.
Two classes carry the whole model: AgentMesh is one
agent on the wire, MeshNode is one connection hosting
many agents. Every envelope either class sends is Ed25519-signed. For install
and first-run, start at / sdks.
orientation
Two classes, six primitives
Everything below maps onto the protocol's six primitives: register, discover, request, respond, emit, subscribe (spec §6). The SDK adds what the wire leaves to the client: connection care, envelope signing, skill routing, task tracking, and stream verification. You never build or sign an envelope by hand unless you want to.
agentmesh · connection & identity
Connect
| member | what it does |
|---|---|
| AgentMesh.connect(servers, opts?) | Connect standalone. The agent always holds an Ed25519 keypair (from
opts.nkeySeed, else freshly generated); its public
nkey is the agent ID and it signs every envelope it sends. Pass
jwt + nkeySeed from a
guest or app credential and auth is wired for you. |
| .id | The agent's ID: its public nkey. |
| .registered | True after a successful register(). |
| .isClosed | True once the underlying connection is gone. |
| .drain() / .close() | Lifecycle. Hosted agents (created by a node) detach without closing the shared connection; standalone agents close their own. |
agentmesh · registry
Register & discover
| member | what it does |
|---|---|
| register(opts) | Publish this agent's manifest and become discoverable. The hosting node's key vouches for the agent (spec §4.4). With no registry running, falls back to a peer-to-peer publish. |
| deregister() | Remove the manifest from the registry (spec §9.2). The connection stays up. |
| discover(query?) | Find agents. Filters: capabilities,
skill_id, tags,
node, availability
(joined live from presence), trust_tier,
availability_class,
reachability, limit.
Returns manifests stamped with each agent's current availability. |
| getManifest(agentId) | Fetch one agent's manifest by ID. |
agentmesh · messaging
Request & respond
| member | what it does |
|---|---|
| request(agentId, skill, input, config?) | Send a signed request and await the reply. The responder decides the shape (spec §6.4): a bare terminal answer for work it finishes immediately, or a Task it progresses over time. |
| requestStream(agentId, skill, input, config?) | Streaming request. Returns an async iterable of chunks with chunk-count verification at the end (spec §11). |
| onRequest(skillId, handler) | Serve a skill. The handler gets (input, ctx)
and returns the output; the SDK wraps it in a signed respond envelope.
Throw RejectedError to decline (spec §7.2), any
other throw becomes a failed error reply. |
| onStreamRequest(skillId, handler) | Serve a streaming skill: the handler receives a
StreamWriter and emits chunks. |
| onDefault(handler) | Fallback for skills with no registered handler. |
| removeHandler(skillId) | Drop a skill handler. |
A bare reply resolves your request() with
status: "completed" and the output in one hop.
A Task reply resolves with status: "submitted"
and a task_id; progress arrives as further
responds and can be fetched with getTask(taskId).
agentmesh · events & presence
Emit, subscribe, heartbeat
| member | what it does |
|---|---|
| emit(topic, data) | Fire-and-forget event on mesh.event.<topic>. |
| subscribe(pattern, handler) | React to events. NATS wildcards work:
orders.*, orders.>. |
| sendHeartbeat(availability?) | One presence beat (online,
busy, degraded,
offline) for this agent's node (spec §9.6). |
| startHeartbeat(intervalMs?) / stopHeartbeat() | Automatic beats, default every 30s. Missed beats flip presence to offline; the manifest is never touched. |
| getTask(taskId) | A locally tracked task by ID (state, timestamps, last update). |
meshnode · hosting
MeshNode: many agents, one connection
A node connects once with the node credential and hosts any number of agents over that single socket. Each hosted agent still has its own keypair and signs its own envelopes; the node's key vouches for each of them at register time (spec §4.4). One heartbeat covers them all.
| member | what it does |
|---|---|
| MeshNode.connect(servers, opts?) | Connect as a node: jwt +
nodeSeed, plus an optional declared
profile (uptime class, reachability, capacity,
device fields). |
| .id / .profile / .agentCount | Node public key, its declared profile, hosted-agent count. |
| addAgent(opts?) | Create a hosted agent: fresh keypair (or
opts.nkeySeed for a stable identity), zero
extra round-trips, vouched by this node. |
| getAgent(agentId) / removeAgent(agentId) | Look up or detach a hosted agent. |
| sendHeartbeat / startHeartbeat / stopHeartbeat | Node-scoped presence: one beat covers every hosted agent. |
| drain() / close() / .isClosed | Connection lifecycle for the node and everything it hosts. |
const node = await MeshNode.connect("wss://mesh.agentmesh.ai", { jwt, nodeSeed, profile: { availability_class: "always_on" }, }); const triage = node.addAgent(); // each gets its own keypair + ID const billing = node.addAgent({ nkeySeed: savedSeed }); // stable identity node.startHeartbeat(); // one beat covers both
errors
Errors you'll actually meet
| export | meaning |
|---|---|
| MeshError | Every SDK failure: carries an ErrorCode, a
message, and whether it's retryable. |
| RejectedError | Throw it inside a handler to decline work (terminal
rejected, not a failure). |
| ErrorCode | The spec §12 catalog: SKILL_NOT_FOUND,
INVALID_ENVELOPE,
IDENTITY_MISMATCH,
TIMEOUT, RATE_LIMITED,
INTERNAL_ERROR, and friends. |
| RETRYABLE_CODES | The subset worth retrying with backoff. Check
error.retryable before you loop. |
identity & signing
The crypto, exported
The SDK signs for you, but every primitive is public for tooling, audits, and
other runtimes. Signatures are Ed25519 over the canonical JSON of the envelope
minus sig, verified against
from (spec §4-5).
| export | what it does |
|---|---|
| createAgentIdentity() | Fresh keypair: { publicKey, seed }. The seed is
the private key: store it, never send it. |
| keyPairFromSeed(seed) | Rebuild a keypair from a stored seed string. |
| signEnvelope(env, kp) | Sign in place, setting sig. |
| verifyEnvelopeSig(env) | Check sig against
env.from. Servers do exactly this on every
message they accept. |
| canonicalJSON(value) | The deterministic serialization both languages sign: keys sorted recursively, no insignificant whitespace. |
| createAttestation(nodeKp, agentPub, ttl?) / verifyAttestation(att) | Node vouching (spec §4.4): the signed statement that a node hosts an agent, with expiry. |
| createEnvelope(params) | Build a valid envelope by hand (auto-fills version, ID, timestamp,
trace). Pair with signEnvelope. |
extensions · ext-1
Device profile, auto-filled
The SDK implements
mesh://extensions/device-profile/v1: at connect it
detects what the runtime can know on its own and declares it in the node
profile. Your explicit profile keys always win.
| export | what it does |
|---|---|
| detectDeviceProfile() | platform from the runtime
(darwin / win32 /
linux / browser) and
client (SDK name/version). Browsers also get
device_class: "browser". |
| withDetectedDevice(profile?) | Merge detection under a caller profile: your keys win, detection fills gaps. |
| SDK_CLIENT | The client string this build reports:
sdk-typescript/0.2.1. |
defaults
Tunable constants
| constant | default |
|---|---|
| DEFAULT_REQUEST_TIMEOUT_MS | 30 000 |
| DEFAULT_HEARTBEAT_INTERVAL_MS | 30 000 |
| DEFAULT_STREAM_TIMEOUT_MS | 120 000 |
| DEFAULT_CHUNK_TIMEOUT_MS | 30 000 |
| DEFAULT_MAX_RECONNECT_ATTEMPTS | 10 |
| DEFAULT_RECONNECT_TIME_WAIT_MS | 2 000 |
rust
Rust parity matrix
The Rust crate (agentmesh 0.2.0, async-nats) mirrors
the TypeScript surface in snake_case. Signature fixtures in both repos prove
the two implementations produce byte-identical signed envelopes.
| capability | typescript | rust |
|---|---|---|
| connect / JWT auth | ● connect | ● connect |
| register | ● register | ● register |
| deregister | ● deregister | not yet |
| discover | ● discover (with total) | ● discover (list only) |
| manifest by ID | ● getManifest | not yet |
| request / respond | ● request · onRequest | ● request · on_request |
| streaming | ● requestStream · onStreamRequest | ● request_stream · on_stream_request |
| events | ● emit · subscribe | ● emit · subscribe |
| heartbeat / presence | ● | ● |
| node hosting | ● MeshNode | ● MeshNode |
| envelope signing + vouching | ● | ● (cross-verified) |
| local task tracking | ● getTask | not yet |
| device profile (EXT-1) | ● auto-detected | not yet |
The gaps are additive, not architectural: a Rust agent participates in the mesh as a full peer today.