npm package: @ff-terminal/sdk
Description: Embeddable TypeScript SDK for FF Terminal daemon turn streaming
Latest version: 0.1.0-beta.0

# @ff-terminal/sdk

Embeddable Node.js SDK for interacting with FF Terminal through the daemon WebSocket protocol.

- Node.js: `>=20`
- Package: `@ff-terminal/sdk`
- MVP surface: `createClient`, `listTools`, `runTurn` (streaming), `cancelTurn`, `close`

## Documentation Suite

Canonical SDK docs for architecture, operations, and release process live in:

- `docs/sdk/README.md`

High-value pages:

- `docs/sdk/03-client-api-reference.md`
- `docs/sdk/05-daemon-lifecycle-managed-vs-external.md`
- `docs/sdk/06-providers-models-profiles.md`
- `docs/sdk/07-tool-policy-security.md`
- `docs/sdk/10-testing-and-runtime-truth.md`

## Install

```bash
npm install @ff-terminal/sdk@beta
```

Managed mode runtime note:

- `@ff-terminal/sdk` depends on `@ff-terminal/runtime`.
- daemon endpoint is still required (managed launch or external daemon URL).

## Quickstart

```ts
import { createClient } from "@ff-terminal/sdk";

const client = createClient(); // managed daemon by default

const tools = await client.listTools();
console.log(tools);

for await (const event of client.runTurn("Summarize this repo")) {
  if (event.type === "content") process.stdout.write(event.delta);
  if (event.type === "turn_finished") console.log("\nDone", event.ok);
}

await client.close();
```

## Local CLI Agent Test

From this repository:

```bash
npm run build
npm run sdk:agent
```

Example:

```text
sdk-agent> /tools
sdk-agent> Hello
sdk-agent> /session
sdk-agent> /session reset
sdk-agent> /exit
```

Commands:

- `/tools` list available tools (policy-filtered)
- `/session` show current session ID
- `/session reset` clear persisted session state
- `/exit` close and quit

## Lifecycle Modes

### Managed daemon (default)

The SDK starts and manages a local daemon sidecar.

```ts
const client = createClient({
  daemon: {
    mode: "managed"
  }
});
```

Optional overrides:

```ts
const client = createClient({
  daemon: {
    mode: "managed",
    command: process.execPath,
    args: ["/absolute/path/to/dist/bin/ff-terminal.js", "daemon"],
    startupTimeoutMs: 15000
  }
});
```

Managed mode resolution order when `command` is not provided:

1. `FF_TERMINAL_DAEMON_JS` (absolute path to `ff-terminal.js`)
2. Local `dist/bin/ff-terminal.js` discovered from `cwd` / repo ancestry
3. `@ff-terminal/runtime` daemon launcher from dependency graph
4. `ff-terminal` from `PATH`

### External daemon

Connect to an existing daemon process.

```ts
const client = createClient({
  daemon: {
    mode: "external",
    url: "ws://127.0.0.1:28888"
  }
});
```

## Security Defaults and Tool Policy

Default policy is `safe-default`, which blocks high-risk tools unless explicitly allowed.

```ts
const client = createClient({
  toolPolicy: "safe-default" // default
});
```

Other policy modes:

```ts
// full: no restrictions (SDK prints a startup warning)
createClient({ toolPolicy: "full" });

// custom: explicit allow/deny
createClient({
  toolPolicy: {
    mode: "custom",
    allowTools: ["glob", "read_file"],
    denyTools: ["run_command"] // deny always wins
  }
});
```

## API

### `createClient(options)`

Creates an SDK client using managed or external daemon mode.

### `listTools(): Promise<string[]>`

Returns daemon tool names filtered by the configured tool policy.

### `runTurn(input, { sessionId?, signal? }): AsyncIterable<SDKEvent>`

Starts a turn and streams events. Pass `AbortSignal` to cancel.

### `cancelTurn(turnId): Promise<void>`

Explicitly cancel an in-flight turn.

### `close(): Promise<void>`

Closes websocket resources and stops the managed daemon if SDK started it.

## Compatibility and Deprecation

- Versioning: semantic versioning.
- Node support: Node.js 20+ only.
- Runtime protocol: backward-compatible additive changes for minor releases.
- Deprecation window: deprecated APIs remain for at least one minor release before removal in a major release.

## Provider and Profile Boundary

- SDK does not currently accept `provider`, `model`, or `profile` as first-class client options.
- Provider/model/profile are selected by daemon runtime env/config.
- See `docs/sdk/06-providers-models-profiles.md` for operational recipes.

## Migration Notes

- Existing daemon clients without `toolPolicy` remain supported.
- SDK clients send `toolPolicy` on `start_turn` to enforce client-side security defaults.
- `safe-default` may hide tools that were previously visible in unrestricted clients.