SDK Guide

The Raison SDK is a small TypeScript/JavaScript library that connects your application to the Raison platform and delivers prompts in real-time.

Use this pre-built prompt to get started faster.

Installation

npm install raison

SDK Architecture

Internally, the SDK is built on two components:

  • In-memory database — A local memgoose store that holds all prompts currently deployed to your environment. Indexed on id and [agentId, name] for fast lookups.
  • WebSocket connection — A Socket.IO client connected to the /sdk namespace on api.raison.ist. Handles authentication, initial sync, and real-time updates.

These two pieces together mean every SDK method reads from local memory — there are no HTTP requests per prompt lookup. Latency is microseconds, not milliseconds.

Connection Lifecycle

new Raison({ apiKey })

    ├─ Validates API key format (must start with rsn_)
    ├─ Creates isolated in-memory database
    ├─ Opens WebSocket to api.raison.ist/sdk
    └─ Creates readyPromise (pending)

Server authenticates the API key

    └─ Emits 'sync' event with all deployed prompts

SDK receives 'sync'

    ├─ Upserts all prompts into in-memory DB
    ├─ Removes any stale prompts not in the sync payload
    └─ Resolves readyPromise → SDK is now ready

Dashboard: prompt deployed

    └─ Server emits 'prompt:deployed' to environment room

           └─ SDK upserts the updated prompt in memory

Waiting for Initial Sync

All SDK methods (render, find, findOne) internally await the readyPromise before executing. This means:

  • You never need to check if the SDK is "ready" — every method handles this automatically.
  • If you call render before the sync completes, it will simply wait until sync is done, then return the result.
  • There is no race condition between construction and first use.
// This is safe — render waits for sync if needed
const raison = new Raison({ apiKey: process.env.RAISON_API_KEY })
const prompt = await raison.render('PROMPT_ID', { name: 'Alice' })

Rendering Prompts

render looks up the prompt by ID, compiles the Handlebars template, and returns the rendered string.

const message = await raison.render('YOUR_PROMPT_ID', {
  userName: 'Alice',
  context: 'billing inquiry',
})

Edge cases:

  • Prompt not found → returns "" (empty string)
  • No variables passed → returns raw content (template is not compiled)
  • Template compilation fails → returns raw content as a safe fallback
  • Prompt has empty content → returns "" (empty string)

Handlebars is compiled with noEscape: true — HTML special characters in variable values are not escaped. This is intentional, since prompts are plain text, not HTML.

Querying Prompts

find and findOne query the in-memory database directly.

// All prompts deployed to this environment
const all = await raison.find()

// Filter by agent
const agentPrompts = await raison.find({ agentId: 'YOUR_AGENT_ID' })

// Filter by name
const byName = await raison.find({ name: 'system-prompt' })

// Find a single prompt
const systemPrompt = await raison.findOne({ name: 'system-prompt' })

// Find by ID
const specific = await raison.findOne({ id: 'YOUR_PROMPT_ID' })

// Find by agent + name (uses the composite index — most efficient)
const precise = await raison.findOne({
  agentId: 'YOUR_AGENT_ID',
  name: 'system-prompt',
})

// Find by version
const v3 = await raison.findOne({ name: 'system-prompt', version: 3 })

find always returns an array (never null — returns [] if nothing matches). findOne returns the prompt object or null.

Error Handling

The SDK is designed to be safe by default:

  • If a prompt does not exist, render returns "" — not an error. Guard with a non-empty check if needed.
  • If a template is malformed, render returns the raw content — your application keeps working.
  • If the WebSocket disconnects, Socket.IO reconnects automatically with exponential backoff.
  • The in-memory database is preserved across reconnects — prompts are not lost during a brief disconnect.
const message = await raison.render('PROMPT_ID', variables)
if (!message) {
  // Prompt not found or has no content — use a fallback
  return DEFAULT_SYSTEM_PROMPT
}

Custom Handlebars Helpers

Register helpers before using them. Helpers are global — they apply to all Raison instances.

Raison.registerHelper('uppercase', (str: string) => str.toUpperCase())
Raison.registerHelper('json', (obj: unknown) => JSON.stringify(obj, null, 2))

Register helpers at application startup (before creating Raison instances) to ensure they are available when prompts are first rendered. See Templating for more helper patterns.

Multiple Environments

Each Raison instance is fully isolated — separate in-memory database, separate WebSocket connection:

const dev = new Raison({ apiKey: process.env.RAISON_DEV_KEY })
const staging = new Raison({ apiKey: process.env.RAISON_STAGING_KEY })
const prod = new Raison({ apiKey: process.env.RAISON_PROD_KEY })

This is useful for environments that need to serve traffic from multiple deployment targets simultaneously, or for testing environment promotion logic locally.

Disconnect and Cleanup

Call disconnect() to close the WebSocket connection cleanly. Do this when your process is shutting down:

process.on('SIGTERM', () => {
  raison.disconnect()
  process.exit(0)
})

After disconnect(), the in-memory database is still accessible (reads will still work), but real-time updates will stop and the readyPromise will not resolve for any pending calls.

Self-Hosting

If you are running a self-hosted Raison instance, pass your API base URL:

const raison = new Raison({
  apiKey: 'rsn_development_xxx',
  baseUrl: 'https://api.your-domain.com',
})

Trailing slashes in baseUrl are stripped automatically.