Create your first session
Create a session with the SDK, wait for the turn to end, and read the model's answer
With the werft client from Install the SDK, create one session and follow it until the first turn ends. The examples assume the development server started with --fake-model. A GATE-SPEC {…} message is a script the fake model reads; on a server that runs the real Claude, send a plain sentence.
Pick a profile
A session runs on one of the profiles the server operator registered: the list you saw in Check the connection. The development server has claude-coding-local (a person answers permission requests) and claude-coding-auto (a classifier decides), which use a repository, and general, which runs without one. This page uses claude-coding-local.
Create a session
import { waitForTurn } from "@werft-ai/sdk";
import { werft } from "./werft.ts";
const created = await werft.sessions.create({
profile_id: "claude-coding-local",
repository_id: "sample-app",
message: 'GATE-SPEC {"id":"hello","steps":[],"final":"hello from Werft"}',
});
console.log(created);{
session_id: '…',
turn_id: '1',
receipt_id: '…',
receipt_status: 'accepted',
status: 'queued'
}repository_idis the repository the session clones. The development server's read-only Git server providessample-app.messageis the input of the first turn. This script calls no tool and ends withhello from Werft.- Creating a session only accepts it. Read the result after the turn ends.
- A request that creates a session needs an
Idempotency-Key. The SDK makes one per call and sends the same key when it retries that call.
Wait for the turn to end
The scheduler starts a worker, the worker clones the repository, and then it runs turn 1. The first time takes tens of seconds.
const turn = await waitForTurn(werft, created.session_id, created.turn_id, {
signal: AbortSignal.timeout(5 * 60_000),
});
console.log(`turn ${turn.turn_id}: ${turn.status}`);turn 1: completedwaitForTurn checks every 2 seconds until the turn's status is a final value. completed, failed, interrupted, cancelled and outcome_unknown are final. failed is a status value, not an error, so judge whether the work got done from the events.
Read the model's answer
What happens in a session arrives on the event stream. The stream stays open after the turn ends, so end it yourself once you have the events you need.
const stream = werft.sessions.events.stream(created.session_id);
for await (const event of stream) {
if (event.kind === "assistant") {
console.log((event.payload as { text?: string }).text);
}
if (event.kind === "result") break;
}
stream.close();hello from WerftThe text of an assistant event is the text the model sent. Put the three pieces together in first-session.ts, run it with WERFT_API_KEY=csp_… node first-session.ts, and the output above appears in order.
Doing it with the HTTP API
The same flow is POST /v1/sessions (needs an Idempotency-Key header), polling GET /v1/sessions/{id}/turns/{turn_id}, and GET /v1/sessions/{id}/events (SSE).
Next steps
- Permission requests and closing: answer a permission request, send another message, and close the session
- Receiving a stream: event types and reconnecting