SDK
The @wular/coder SDK, every CLI command as a typed function.
The SDK is the CLI as a library: the same commands, names and options. coder --help is the reference for both.
Rules
- Names. A command group is a namespace and a subcommand a function:
coder task steeristask.steer,coder model aliasismodel.alias. Top-level commands are functions:setupHost,upgrade,docs. Exceptions:task watchistask.stream, an async iterable of progress events.connection rmisconnection.remove.reviewisreview.run.server rotate-keyisserver.rotateKey.agent run --taskisagent.runTask, for runners, not application code.
- Arguments. Positional arguments come first, in CLI order. Flags become one options object in camelCase:
--max-tasksismaxTasks,--output-schemaisoutputSchema. - Models.
modeltakes the same spec as--model:sol,sol/low,claude/opusorcodex/gpt-6.1-sol/high. - Server. Every command that takes
--serveraccepts{ server: true | url, organization?, token?, yes? }:serverfalls back toCODER_SERVER, then the hosted service.organizationis the workspace slug and overrides the saved one.- Authentication comes from
auth.login()ortoken. yes: trueaccepts a new server origin in non-interactive code.
- Results. Functions never print and never call
process.exit. Results are typed values.task.listreturns one page,{ items, next? }; passnextback ascursor. - Errors. Failures throw
CoderError, whosecodesays what went wrong:'chain-exhausted': every engine failed to start. It carries the fallback payload andfallback.instructions, and is the CLI's exit code 3.'approval-pending': carries the approval to answer.'login-failed'.'server': carries the HTTPstatus.- The option errors the CLI reports.
- Hosting.
server.handler(env)serves Coder on serverless hosts; see Self-host.
Examples
A task with a JSON answer, then its result:
import coder from '@wular/coder';
const { taskId } = await coder.task.run('List the API routes', {
model: 'claude/opus',
outputSchema: { type: 'object', properties: { routes: { type: 'array' } } },
});
const res = await coder.task.result(taskId, { wait: true });
The schema goes to the engine natively and never into the stored prompt. A continuation keeps it unless given a new one.
A wave of read-only tasks:
import { task } from '@wular/coder';
const ids = await Promise.all(areas.map(a => task.run(`Audit ${a}`, { access: 'read-only' })));
const results = await Promise.all(ids.map(({ taskId }) => task.result(taskId, { wait: true })));
Following a task live. Each event has a kind, such as assistant, tool, usage or error:
for await (const event of task.stream(taskId)) {
if (event.kind === 'assistant') console.log(event.message);
}
A task on the Coder server:
await task.steer(id, 'Also cover the retry path', { server: true });
A flow:
import { flow } from '@wular/coder';
const run = await flow.run('fix-tests', { args: { files } });
For gates, journaling and resume, write a flow instead of looping over task.*. Runners are in Runners.