Skip to Content
DocumentationReferenceTypeScript SDK (@loopstack/client)

TypeScript SDK

@loopstack/client is the headless SDK for Loopstack: the same REST + SSE API that Studio and the CLI use, as a typed, framework-free client. It runs in bare Node and in the browser, has no framework dependencies, and every request and response type comes from @loopstack/contracts — the same zod contracts the server validates against.

npm install @loopstack/client

Start a run and stream it — in under 20 lines

Against a local backend with auth disabled, no token or login needed:

import { createClient } from '@loopstack/client'; const client = createClient({ url: 'http://localhost:3000' }); const { data: workspaces } = await client.workspaces.list({ limit: 1 }); const workspace = workspaces[0] ?? (await client.workspaces.create({ appName: 'hello_app', title: 'SDK' })); const events = client.stream.events(); // subscribe before starting — no event is missed const run = await client.processor.start({ workflowName: 'hello', workspaceId: workspace.id, args: { name: 'SDK' } }); for await (const event of events) { if (!('workflowId' in event) || event.workflowId !== run.workflowId) continue; if (event.type === 'llm.response.text_delta') process.stdout.write(event.delta); if (event.type === 'workflow.updated' && ['completed', 'failed', 'canceled'].includes(event.status)) break; } client.stream.close(); const { result } = await client.workflows.get(run.workflowId); console.log(result); // → { greeting: 'Hello, SDK! 👋' }

Resources

ResourceWhat it covers
client.workflowsRuns: get, status, list (filter/sort/search/pagination), create, update, delete, batchDelete, checkpoints, toolCalls (recorded tool calls of a traced run)
client.documentsDocuments produced by runs: get, list
client.processorExecution: start a workflow, run a transition — answering human-in-the-loop prompts is a transition with a payload
client.workspacesWorkspaces: CRUD, favourites, batch delete
client.configWhat the backend serves: apps (workflows, documents, UI config per @StudioApp), tools, tool, workflowConfig, workflowSource, availableEnvironments
client.dashboardstats — recent runs and recent errors
client.authme, workerHealth, hubLogin, refresh, logout
client.httpThe typed fetch layer (get/post/put/patch/delete) — the escape hatch for endpoints without a resource yet

Live events

client.stream is the backend’s server-sent-events stream, shared by all subscribers of the client. It is lazy — no connection opens until the first subscriber attaches:

// Typed per-event-type handler; returns an unsubscribe function client.stream.on('workflow.updated', (event) => console.log(event.workflowId, event.status)); // Every event const off = client.stream.onAny((event) => console.log(event.type)); // Async-iterator form — ideal for following one run for await (const event of client.stream.events()) { /* … */ } client.stream.close();

Event types include workflow.updated (place and status changes), document.*, and llm.response.* (token deltas while an LLM generates).

Authentication

const client = createClient({ url: 'https://my-backend.example.com', token: process.env.LOOPSTACK_TOKEN, // personal access token (lsk_…) or JWT });
  • Token — pass a personal access token (created via POST /api/v1/auth/tokens or Studio) or a JWT; it is sent as a bearer credential on every request and on the event stream.
  • Cookies — omit token in the browser; credentials defaults to 'include'.
  • Local development — a backend with auth disabled needs neither.

fetch can be injected for testing or instrumentation.

Query descriptors

Every read is also available as a { queryKey, queryFn } descriptor under client.queries.*, with keys scoped by the client’s envKey (defaults to the URL) so two environments never share cache entries. Plug them into any TanStack-Query-compatible cache — or use @loopstack/react for ready-made hooks with live invalidation.

Last updated on