TypeScript SDK

Start sessions, stream records, and invoke automations from TypeScript.

Install

Shell
npm install @ellipsis-dev/sdk

Start a session

TypeScript
import { Ellipsis } from '@ellipsis-dev/sdk';

const client = new Ellipsis({
  apiKey: process.env.ELLIPSIS_API_TOKEN!,
});
const handle = await client.sessions.run({
  harness: { type: 'claude_code' },
  environment: 'api-environment',
  prompt: 'Run the tests and report failures.',
  interactive: false,
  budget: 3,
});
const session = await handle.wait({ timeoutMs: 900_000 });
console.log(session.status, session.exit_status);

run returns a handle while work continues. wait polls until the session settles. A timeout leaves the session running.

Use await client.sessions.handle(sessionId) to attach to an existing session.

Continue a conversation

Leave interactive enabled to accept messages:

TypeScript
const conversation = await client.sessions.run({
  harness: { type: 'claude_code' },
  environment: 'api-environment',
  prompt: 'Investigate the failing validation test.',
  budget: 5,
});
await conversation.wait();
await conversation.send('Add a regression test.', {
  idempotencyKey: 'add-test',
});
await conversation.wait();
await conversation.stop();

The same message key is accepted once per session. A message during an active turn waits for the next turn.

Invoke an automation

TypeScript
const { session } = await client.automations.run('test-repair', {
  prompt: 'Investigate the request validation tests.',
});
const run = await client.sessions.handle(session.id);
await run.wait();

For an automation with an input schema, pass input instead:

TypeScript
await client.automations.run('classify-change', {
  input: { description: 'Reject expired reset tokens' },
});

Stream a session

See Session events for every modeled event and complete JSON examples.

In Node.js, install ws and connect it to the stream adapter:

TypeScript
import WebSocket from 'ws';
import { streamSession, type OpenSocket } from '@ellipsis-dev/sdk/stream';

const token = process.env.ELLIPSIS_API_TOKEN!;
const openSocket: OpenSocket = ({ sessionId, query }) => {
  const path = '/v1/sessions/' + encodeURIComponent(sessionId) + '/stream';
  const ws = new WebSocket('wss://api.ellipsis.dev' + path + '?' + query, {
    headers: { authorization: 'Bearer ' + token },
  });
  return {
    onOpen: (cb) => ws.on('open', cb),
    onMessage: (cb) => ws.on('message', (raw) => cb(raw.toString())),
    onClose: (cb) => ws.on('close', (code) => cb(code)),
    onError: (cb) => ws.on('error', (error) => cb(error)),
    close: () => ws.close(),
  };
};

const outcome = await streamSession({
  sessionId: handle.id,
  openSocket,
  onFrame: (frame) => console.log(frame.type),
});
console.log(outcome.type);

Pass the adapter's query unchanged. The SDK handles reconnects and resume cursors. Complete records persist; partial text deltas are live-only.

Read records

TypeScript
for await (const record of await client.sessions.records(handle.id)) {
  if (record.kind === 'platform') {
    console.log(record.record_type, record.payload);
  } else if (record.kind === 'claude_code') {
    console.log(record.payload);
  } else if (record.kind === 'codex' || record.kind === 'unknown') {
    console.log(record.record_format, record.payload);
  }
}

Native records preserve their original payloads. Handle unknown variants so new event types do not break your consumer.

Pagination and errors

TypeScript
import { APIError } from '@ellipsis-dev/sdk';

try {
  for await (const session of await client.sessions.list({ days: 7 })) {
    console.log(session.id, session.exit_status);
  }
} catch (error) {
  if (!(error instanceof APIError)) throw error;
  console.error(error.status, error.code);
}

Manual pagination exposes items, hasMore, and nextCursor. API fields retain their wire names; SDK options use camelCase.

The client defaults to a 60-second request timeout and two retries for transport errors, 429, 502, 503, and 504. Configure timeoutMs and maxRetries when creating it.

On this page

Schedule a demo