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.
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
idand[agentId, name]for fast lookups. - WebSocket connection — A Socket.IO client connected to the
/sdknamespace onapi.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
renderbefore 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,
renderreturns""— not an error. Guard with a non-empty check if needed. - If a template is malformed,
renderreturns 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.