Skip to main content

Install

npm install @samvad-protocol/sdk zod
Requires Node.js 20+. The SDK is ESM-only.

Build an agent

Create hello-agent.ts:
import { Agent } from '@samvad-protocol/sdk'
import { z } from 'zod'

const agent = new Agent({
  name: 'Hello Agent',
  description: 'A simple greeting agent',
  url: 'http://localhost:3002',
  specializations: ['greetings'],
})

agent.skill('greet', {
  name: 'Greet',
  description: 'Returns a personalised greeting',
  input: z.object({
    name: z.string().max(100),
    language: z.enum(['en', 'es', 'fr']).optional(),
  }),
  output: z.object({ greeting: z.string() }),
  modes: ['sync', 'stream'],
  trust: 'public',
  handler: async (input) => {
    const { name, language } = input as { name: string; language?: 'en' | 'es' | 'fr' }
    const greetings = { en: 'Hello', es: 'Hola', fr: 'Bonjour' }
    return { greeting: `${greetings[language ?? 'en']}, ${name}!` }
  },
})

agent.serve({ port: 3002 })
Run it:
npx tsx hello-agent.ts
On first run the SDK generates an Ed25519 keypair in .samvad/keys/ and starts serving automatically. That directory is gitignored — never commit it.
Your agent is now live at http://localhost:3002 with these endpoints:
EndpointPurpose
GET /.well-known/agent.jsonMachine-readable agent card
GET /agent/introHuman-readable introduction
GET /agent/healthLiveness check
POST /agent/messageSynchronous calls
POST /agent/taskAsync tasks
GET /agent/task/:taskIdTask status polling
POST /agent/streamSSE streaming

Call the agent

Create call-agent.ts:
import { AgentClient } from '@samvad-protocol/sdk'

const client = await AgentClient.from('http://localhost:3002')
const result = await client.call('greet', { name: 'Ada', language: 'en' })
console.log(result) // { greeting: 'Hello, Ada!' }
Run both in separate terminals. That’s it — a signed, rate-limited, schema-validated, streaming-capable agent with one call.

What just happened

  1. AgentClient.from() fetched the remote agent card (/.well-known/agent.json) and loaded the public key.
  2. client.call() built a signed message envelope — nonce, timestamp, Ed25519 signature over canonical JSON of all fields.
  3. The agent verified the signature, checked the nonce window, validated the input schema, and ran your handler.
  4. The result came back in a signed response envelope.
All of that is automatic.

Next steps

Building Agents

Rate limits, trust tiers, async mode, and more.

Calling Agents

Async tasks, polling, SSE streaming, delegation.