> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kairn.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# SDK Reference

> Full API reference for the @kairnsh/sdk Node.js SDK.

## Installation

```bash npm theme={null}
npm install @kairnsh/sdk
```

```bash pnpm theme={null}
pnpm add @kairnsh/sdk
```

## Initialisation

```ts theme={null}
import Kairn from '@kairnsh/sdk'

const kairn = new Kairn({
  apiKey: 'kn_live_...',           // required
  baseUrl: 'https://api.kairn.sh', // optional — override for self-hosted
})
```

***

## `kairn.invoke()`

Run an agent for a user. Waits for the full response.

```ts theme={null}
const result = await kairn.invoke({
  agent: 'assistant',   // soul name
  userId: 'user_123',   // your user's ID
  input: 'Help me update my billing address.',
  role: 'default',      // optional
  sessionId: 'chat_1',  // optional — enables multi-turn history
})
```

**Returns `InvokeResult`:**

**output** `string`

The agent's final text response.

**invocationId** `string`

Unique ID for this invocation — use for audit log lookup.

**memoryDelta** `Record\<string, string\>`

Memory keys written during this turn.

**toolCalls** `ToolCall[]`

All tool calls the agent made during this turn.

**status** `"completed" | "failed"`

Final status of the invocation.

**tokensInput** `number`

Input tokens consumed.

**tokensOutput** `number`

Output tokens generated.

**durationMs** `number`

Wall-clock time for the full invocation.

***

## `kairn.stream()`

Stream an agent invocation as typed events. Same params as `invoke`.

```ts theme={null}
for await (const event of kairn.stream({
  agent: 'assistant',
  userId: 'user_123',
  input: 'Summarise my last 5 actions.',
})) {
  switch (event.type) {
    case 'token':
      process.stdout.write(event.text)
      break
    case 'tool_start':
      console.log(`Using tool: ${event.name}`)
      break
    case 'memory_delta':
      console.log('Memory written:', event.delta)
      break
    case 'done':
      console.log('Final output:', event.output)
      break
    case 'error':
      console.error('Agent error:', event.error)
      break
  }
}
```

**Event types:**

| Type | Fields |
| - | - |
| `token` | `text: string` |
| `tool_start` | `name: string`, `input: Record<string, unknown>` |
| `tool_end` | `name: string`, `resultSummary?: string` |
| `memory_delta` | `delta: Record<string, string>` |
| `done` | `output`, `status`, `memoryDelta`, `toolCalls`, `tokensInput`, `tokensOutput`, `durationMs`, `sessionId` |
| `error` | `error: string`, `errorType?: string` |

### Next.js App Router streaming

```ts theme={null}
// app/api/chat/route.ts
import Kairn from '@kairnsh/sdk'

const kairn = new Kairn({ apiKey: process.env.KAIRN_API_KEY! })

export async function POST(req: Request) {
  const { userId, input, sessionId } = await req.json()

  const encoder = new TextEncoder()
  const stream = new ReadableStream({
    async start(controller) {
      for await (const event of kairn.stream({ agent: 'assistant', userId, input, sessionId })) {
        if (event.type === 'token') {
          controller.enqueue(encoder.encode(event.text))
        }
        if (event.type === 'done' || event.type === 'error') {
          controller.close()
        }
      }
    },
  })

  return new Response(stream, {
    headers: { 'Content-Type': 'text/plain; charset=utf-8' },
  })
}
```

***

## `kairn.invokeAsync()`

Queue an agent invocation as a background job. Returns a `JobHandle` immediately — no connection held open, no timeout risk. Best for long-running tasks, automations, and workflow triggers.

```ts theme={null}
const job = await kairn.invokeAsync({
  agent: 'advisor',
  userId: 'user_123',
  input: 'Research our top 5 competitors and summarise findings.',
  callbackUrl: 'https://yourapp.com/webhooks/kairn', // optional
})
```

**Params** — same as `invoke()`, plus:

**callbackUrl** `string`

Optional URL to POST the result to when the job completes. Useful when you don't want to poll — Kairn pushes the result to you.

**Returns `JobHandle`:**

### `job.jobId`

The unique job ID. Store this if you need to look up the result from a different process.

### `job.poll()` → `AsyncJob`

Check the current status once.

```ts theme={null}
const status = await job.poll()
// { jobId, status: 'running', ... }
```

### `job.wait(options?)` → `InvokeResult`

Auto-polls until the job reaches a terminal state, then returns the full result. Throws `KairnError` on failure or timeout.

```ts theme={null}
// Simple: fire and wait
const result = await job.wait()
console.log(result.output)

// With custom poll interval and timeout
const result = await job.wait({ intervalMs: 3000, timeoutMs: 60000 })
```

| Option | Type | Default | Description |
| - | - | - | - |
| `intervalMs` | `number` | `2000` | Milliseconds between polls |
| `timeoutMs` | `number` | `120000` | Max total wait time before throwing |

### Common patterns

**Fire and store for later:**

```ts theme={null}
// In your API handler
const job = await kairn.invokeAsync({ agent: 'advisor', userId, input })
await db.jobs.insert({ id: job.jobId, userId })
return res.status(202).json({ jobId: job.jobId })

// In a separate polling endpoint
const status = await kairn.jobs.get(savedJobId)
if (status.status === 'completed') {
  return res.json({ output: status.output })
}
```

**With webhook — no polling needed:**

```ts theme={null}
await kairn.invokeAsync({
  agent: 'advisor',
  userId,
  input: 'Run the weekly review.',
  callbackUrl: 'https://yourapp.com/webhooks/kairn',
})
// Kairn POSTs { job_id, status, output, memory_delta, ... } to your URL when done
```

***

## `kairn.jobs`

Look up any async job by ID. Useful when you stored the `job_id` and need to check it from a different process or request.

### `.get(jobId)` → `AsyncJob`

```ts theme={null}
const job = await kairn.jobs.get('2e4edc0c-8597-4e04-bf0a-c16349c6d35e')
```

**`AsyncJob` fields:**

**jobId** `string`

Unique job ID.

**status** `"pending" | "running" | "completed" | "failed"`

Current state. Poll until `completed` or `failed`.

**output** `string | undefined`

The agent's response. Only present when `status === 'completed'`.

**error** `string | undefined`

Error message. Only present when `status === 'failed'`.

**memoryDelta** `Record\<string, string\> | undefined`

Memory keys written during the run. Only present when `completed`.

**tokensInput** `number | undefined`

**tokensOutput** `number | undefined`

**durationMs** `number | undefined`

***

## `kairn.memory`

### `.get(userId, role)` → `MemoryMap`

```ts theme={null}
const memory = await kairn.memory.get('user_123', 'default')
// { plan: 'pro', name: 'Alex' }
```

### `.get(userId)` → `MemorySummary`

```ts theme={null}
const all = await kairn.memory.get('user_123')
// { default: { plan: 'pro' }, manager: { team_size: '12' } }
```

### `.set(userId, role, delta)`

Write keys to memory. Set a key to `null` to delete it.

```ts theme={null}
await kairn.memory.set('user_123', 'default', {
  plan: 'pro',
  onboarding_done: 'true',
  temp_flag: null, // deletes this key
})
```

### `.delete(userId)`

Wipes all memory for a user across all roles. Use on account deletion.

```ts theme={null}
await kairn.memory.delete('user_123')
```

***

## `kairn.souls`

### `.list()` → `Soul[]`

```ts theme={null}
const souls = await kairn.souls.list()
```

### `.create(params)` → `Soul`

**name** `string` *required*

Internal name — used in invoke calls as `agent`.

**label** `string`

Human-readable label shown in the dashboard.

**soulMd** `string`

The soul's identity, personality, and instructions (markdown). This becomes the agent's system prompt.

**defaultModel** `string`

Model identifier e.g. `anthropic/claude-sonnet-4-6`, `openai/gpt-4o`.

**allowedSkills** `string[]`

Tools this soul may use. Options: `bash`, `read`, `write`, `edit`, `web_search`.

```ts theme={null}
await kairn.souls.create({
  name: 'advisor',
  label: 'Growth Advisor',
  soulMd: 'You are a seasoned growth advisor...',
  defaultModel: 'anthropic/claude-sonnet-4-6',
  allowedSkills: ['web_search'],
})
```

### `.update(name, params)` → `Soul`

```ts theme={null}
await kairn.souls.update('advisor', {
  soulMd: 'Updated identity...',
})
```

***

## `kairn.skills`

Manage custom skills: instruction-only (prompt injection) or webhook tools. Souls reference skills via `allowed_skills`.

### `.list()` → `Skill[]`

```ts theme={null}
const skills = await kairn.skills.list()
```

### `.create(params)` → `Skill`

**name** `string` *required*

Internal name — lowercase letters, digits, underscores. Used in soul `allowed_skills`.

**label** `string` *required*

Human-readable label.

**instructionsMd** `string`

Behavioral guide injected into the system prompt. At least one of `instructionsMd` or `webhookUrl` required.

**descriptionMd** `string`

Short tool description (used when `webhookUrl` is set).

**webhookUrl** `string`

When set, the skill is a callable webhook tool.

**httpMethod** `string`

HTTP method for webhook calls. Default `POST`. One of: `GET`, `POST`, `PUT`, `PATCH`, `DELETE`.

**parameters** `object`

Parameters/schema for the webhook. Default `{}`.

**headers** `object`

Headers sent with webhook requests. Default `{}`.

```ts theme={null}
await kairn.skills.create({
  name: 'my_skill',
  label: 'My Skill',
  instructionsMd: 'How to use this skill.',
  webhookUrl: 'https://example.com/webhook',
  httpMethod: 'POST',
})
```

### `.get(skillName)` / `.update(skillName, params)` / `.delete(skillName)`

```ts theme={null}
const skill = await kairn.skills.get('my_skill')
await kairn.skills.update('my_skill', { label: 'Updated Label', instructionsMd: 'New instructions.' })
await kairn.skills.delete('my_skill')
```

***

## `kairn.mandates`

### `.create(params)` → `Mandate`

**userId** `string` *required*

The user this mandate runs for.

**soul** `string` *required*

Soul name to run.

**label** `string` *required*

Human-readable label.

**taskPrompt** `string` *required*

The task the agent will execute each time the mandate fires.

**trigger** `object` *required*

`{ type: 'cron', cron: '0 9 * * 1' }` — standard cron expression (UTC).

```ts theme={null}
await kairn.mandates.create({
  userId: 'user_123',
  soul: 'advisor',
  label: 'Weekly check-in',
  taskPrompt: 'Review goals and write a weekly summary to memory.',
  trigger: { type: 'cron', cron: '0 9 * * 1' },
})
```

### `.list()` / `.get(id)` / `.pause(id)` / `.cancel(id)`

```ts theme={null}
const mandates = await kairn.mandates.list()
const mandate  = await kairn.mandates.get(mandate.id)
await kairn.mandates.pause(mandate.id)
await kairn.mandates.cancel(mandate.id)
```

***

## `kairn.invocations`

### `.list(params)` → `InvocationListResult`

```ts theme={null}
const { invocations, nextCursor } = await kairn.invocations.list({
  userId: 'user_123',
  status: 'completed',
  limit: 20,
})

// Paginate
const next = await kairn.invocations.list({ cursor: nextCursor })
```

### `.get(invocationId)` → `Invocation`

```ts theme={null}
const inv = await kairn.invocations.get('inv_abc123')
```

***

## Error handling

```ts theme={null}
import Kairn, { KairnError } from '@kairnsh/sdk'

try {
  await kairn.invoke({ agent: 'advisor', userId, input })
} catch (err) {
  if (err instanceof KairnError) {
    console.error(err.message)    // human-readable
    console.error(err.status)     // HTTP status code
    console.error(err.errorType)  // machine-readable type

    if (err.status === 429 && err.errorType === 'quota_exceeded') {
      // Monthly plan limit hit
    }
    if (err.status === 429 && err.errorType === 'rate_limit_exceeded') {
      // Too many requests per minute
    }
    if (err.status === 404 && err.errorType === 'soul_not_found') {
      // Soul name doesn't exist for this tenant
    }
  }
}
```

***

## TypeScript

The SDK ships full type definitions. All types are exported:

```ts theme={null}
import type {
  InvokeParams,
  InvokeResult,
  AsyncInvokeParams,
  AsyncJob,
  StreamEvent,
  MemoryMap,
  MemoryDelta,
  Soul,
  SoulCreateParams,
  Skill,
  SkillCreateParams,
  Mandate,
  MandateCreateParams,
  Invocation,
  KairnOptions,
} from '@kairnsh/sdk'
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.