---
title: "@treeship/sdk"
description: TypeScript SDK for Treeship. Wraps the CLI binary for signing, verification, and hub connections.
---

import { Callout } from 'fumadocs-ui/components/callout';
import { Card, Cards } from 'fumadocs-ui/components/card';

## Install

```bash
npm install @treeship/sdk
```

<Callout type="info">
The SDK shells out to the `treeship` CLI binary. The CLI must be installed and initialized (`treeship init`) before using the SDK. WASM-based signing is planned for a future version.
</Callout>

## Quick start

```ts
import { ship } from '@treeship/sdk';

const s = ship();

// Attest an action
const { artifactId } = await s.attest.action({
  actor: 'agent://my-agent',
  action: 'tool.call',
});

// Verify it
const result = await s.verify.verify(artifactId);
console.log(result.outcome); // "pass"

// Push to Hub
const { hubUrl } = await s.hub.push(artifactId);
console.log(hubUrl); // https://treeship.dev/verify/art_xxx
```

## Ship class

### `Ship.checkCli()`

Static method that checks whether the `treeship` CLI binary is installed and available on PATH. Returns the version string (e.g. `"0.4.1"`). Throws a descriptive error if the binary is not found.

```ts
import { Ship } from '@treeship/sdk';

const version = await Ship.checkCli();
console.log(`Treeship CLI version: ${version}`);
```

Call this early in your startup sequence to fail fast if the CLI is missing, rather than getting a confusing error on the first attestation call.

### Instance properties

| Property | Type | Description |
|----------|------|-------------|
| `attest` | `AttestModule` | Attestation methods (action, decision, approval, handoff) |
| `verify` | `VerifyModule` | Verification methods |
| `hub` | `HubModule` | Hub push/pull and connection status |

## Attest module

All attestation methods live under `s.attest`.

### `s.attest.action(params)`

Record that an actor performed an action.

```ts
const { artifactId } = await s.attest.action({
  actor: 'agent://my-agent',
  action: 'tool.call',
  meta: { model: 'gpt-4o', tokens: 1247 },
});
```

**Params: `ActionParams`**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `actor` | `string` | Yes | Actor URI, e.g. `agent://my-agent` |
| `action` | `string` | Yes | Label for the action performed |
| `parentId` | `string` | No | Parent artifact ID for chain linking |
| `approvalNonce` | `string` | No | Nonce from an existing approval |
| `meta` | `Record<string, unknown>` | No | Arbitrary metadata attached to the artifact |

**Returns: `ActionResult`** -- `{ artifactId: string }`

### `s.attest.decision(params)`

Record an LLM inference decision with token usage and confidence scoring.

```ts
await s.attest.decision({
  actor: 'agent://analyst',
  model: 'claude-opus-4',
  tokensIn: 8432,
  tokensOut: 1247,
  summary: 'Contract looks standard.',
  confidence: 0.91,
});
```

**Params: `DecisionParams`**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `actor` | `string` | Yes | Actor URI |
| `model` | `string` | No | Model identifier |
| `tokensIn` | `number` | No | Input token count |
| `tokensOut` | `number` | No | Output token count |
| `promptDigest` | `string` | No | SHA-256 digest of the prompt |
| `summary` | `string` | No | Plain-text summary of the decision |
| `confidence` | `number` | No | Confidence score between 0 and 1 |
| `parentId` | `string` | No | Parent artifact ID for chain linking |

Note: The `modelVersion` field exists in the TypeScript type but is not currently forwarded to the CLI. Use the `model` field to identify the model and version together (e.g., `"claude-opus-4-20260301"`).

**Returns: `ActionResult`** -- `{ artifactId: string }`

### `s.attest.approval(params)`

Record that an approver authorized an intent. Returns a nonce that can be echoed back when attesting the approved action.

```ts
const { artifactId, nonce } = await s.attest.approval({
  approver: 'human://alice',
  description: 'approve payment max $500',
});
```

**Params: `ApprovalParams`**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `approver` | `string` | Yes | Approver identity URI |
| `description` | `string` | Yes | Plain-text description of what is authorized |
| `expires` | `string` | No | ISO-8601 timestamp when the approval expires, e.g. `"2026-12-31T00:00:00Z"` |
| `subject` | `string` | No | Artifact ID being approved -- maps to the CLI `--subject` flag |

**Returns: `ApprovalResult`** -- `{ artifactId: string, nonce: string }`

### `s.attest.handoff(params)`

Record a transfer of work between actors.

```ts
await s.attest.handoff({
  from: 'agent://researcher',
  to: 'agent://executor',
  artifacts: ['art_abc123'],
});
```

**Params: `HandoffParams`**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `from` | `string` | Yes | Source actor URI |
| `to` | `string` | Yes | Destination actor URI |
| `artifacts` | `string[]` | Yes | Artifact IDs being transferred |
| `approvals` | `string[]` | No | Approval IDs the receiver inherits |
| `obligations` | `string[]` | No | Obligations the receiver must satisfy |

**Returns: `ActionResult`** -- `{ artifactId: string }`

## Verify module

### `s.verify.verify(artifactId)`

Verify an artifact and walk its chain.

```ts
const result = await s.verify.verify('art_abc123');
// { outcome: 'pass', chain: 3, target: 'art_abc123' }
```

**Returns: `VerifyResult`**

| Field | Type | Description |
|-------|------|-------------|
| `outcome` | `'pass' \| 'fail' \| 'error'` | Verification result |
| `chain` | `number` | Number of artifacts in the chain |
| `target` | `string` | The artifact ID that was verified |

## Hub module

### `s.hub.push(artifactId)`

Push an artifact to the Treeship Hub.

```ts
const { hubUrl } = await s.hub.push('art_abc123');
// https://treeship.dev/verify/art_abc123
```

**Returns: `PushResult`**

| Field | Type | Description |
|-------|------|-------------|
| `hubUrl` | `string` | Public URL for the artifact on the Hub |
| `rekorIndex` | `number \| undefined` | Rekor transparency log index, if available |

### `s.hub.pull(id)`

Pull an artifact from the Treeship Hub to the local store.

```ts
await s.hub.pull('art_abc123');
```

Returns `void`. Throws if the artifact is not found or the network request fails.

### `s.hub.status()`

Check the current hub connection status.

```ts
const status = await s.hub.status();
if (status.attached) {
  console.log(`Connected to ${status.endpoint}`);
}
```

**Returns:**

| Field | Type | Description |
|-------|------|-------------|
| `attached` | `boolean` | Whether the hub connection is currently active |
| `endpoint` | `string \| undefined` | Hub endpoint URL, if connected |
| `hubId` | `string \| undefined` | Hub connection identifier, if connected |

If the status check fails for any reason (CLI not installed, no config), returns `{ attached: false }` instead of throwing.

## Exported types

All types are re-exported from the top-level `@treeship/sdk` import.

### `ActionParams`

```ts
interface ActionParams {
  actor: string;
  action: string;
  parentId?: string;
  approvalNonce?: string;
  meta?: Record<string, unknown>;
}
```

### `ApprovalParams`

```ts
interface ApprovalParams {
  approver: string;
  description: string;
  expires?: string;   // ISO-8601 timestamp
  subject?: string;   // artifact ID being approved
}
```

### `HandoffParams`

```ts
interface HandoffParams {
  from: string;
  to: string;
  artifacts: string[];
  approvals?: string[];
  obligations?: string[];
}
```

### `DecisionParams`

```ts
interface DecisionParams {
  actor: string;
  model?: string;
  modelVersion?: string;
  tokensIn?: number;
  tokensOut?: number;
  promptDigest?: string;
  summary?: string;
  confidence?: number;
  parentId?: string;
}
```

### `ActionResult`

```ts
interface ActionResult {
  artifactId: string;
}
```

### `ApprovalResult`

```ts
interface ApprovalResult {
  artifactId: string;
  nonce: string;
}
```

### `VerifyResult`

```ts
interface VerifyResult {
  outcome: "pass" | "fail" | "error";
  chain: number;
  target: string;
}
```

### `PushResult`

```ts
interface PushResult {
  hubUrl: string;
  rekorIndex?: number;
}
```

## Error handling

The SDK throws `TreeshipError` when the CLI exits with a non-zero code.

### `TreeshipError`

```ts
class TreeshipError extends Error {
  readonly args: string[];  // the CLI arguments that were passed
  readonly name: "TreeshipError";
}
```

`TreeshipError` extends the standard `Error` class. The `args` property contains the exact CLI arguments that were passed, which is useful for debugging. The `message` property contains the stderr output from the CLI.

```ts
import { TreeshipError } from '@treeship/sdk';

try {
  await s.attest.action({ actor: 'agent://x', action: 'test' });
} catch (e) {
  if (e instanceof TreeshipError) {
    console.error('CLI failed:', e.message);
    console.error('Args:', e.args);
  }
}
```

## Design rules

<Cards>
<Card title="CLI-backed" description="Shells out to the treeship binary. No native crypto in the SDK yet." />
<Card title="Never stores sensitive content" description="Hash payloads, not content." />
<Card title="Explicit errors" description="CLI failures throw TreeshipError. Verify returns a typed VerifyResult with an outcome field instead of throwing." />
</Cards>
