
# SDK events

Subscriptions report changes after they happen. Fetch an initial snapshot first, then apply updates to it.

Every `subscribe()` method returns a local unsubscribe function. It removes your callback; it does not stop or archive the underlying resource.

## Follow one agent's status

The daemon sends agent-directory updates only after the connection opens an agent-list subscription:

```ts
await client.agents.list({
  filter: { includeArchived: false },
  subscribe: { subscriptionId: "issue-board-agents" },
});

const agent = client.agents.ref(agentId);
await agent.refresh();

const unsubscribe = agent.subscribe((update) => {
  if (update.kind === "upsert") {
    console.log(update.agent.status);
  } else {
    console.log("Agent removed from the active directory");
  }
});
```

The handle updates its properties and `current()` value before it calls your handler.

## Follow timeline events

```ts
const unsubscribe = agent.timeline.subscribe(({ event, timestamp }) => {
  if (event.type === "timeline" && event.item.type === "assistant_message") {
    process.stdout.write(event.item.text);
  }

  if (event.type === "turn_completed") {
    console.log(`\nCompleted at ${timestamp}`);
  }
});
```

Assistant messages can arrive in pieces. Concatenate their text when you need a complete message, or use `run()` and read `lastMessage` when you only need the final reply.

Turn completion comes from `turn_completed`, `turn_failed`, or `turn_canceled`. Do not infer turn completion from an `agent_update` transition to `idle`.

## Fetch timeline history

```ts
const page = await agent.timeline.refetch({
  direction: "before",
  limit: 100,
  projection: "projected",
});

for (const entry of page.entries) {
  console.log(entry.seq, entry.event.type);
}
```

Use `startCursor`, `endCursor`, `hasOlder`, and `hasNewer` from the result to page without inventing offsets.

## Follow workspace updates

Workspace updates also require a directory subscription:

```ts
await client.workspaces.list({
  subscribe: { subscriptionId: "issue-board-workspaces" },
});

const workspace = client.workspaces.ref(workspaceId);
const unsubscribe = workspace.subscribe((update) => {
  if (update.kind === "upsert") {
    console.log(update.workspace.status);
  }
});
```

## Follow provider catalog changes

```ts
const unsubscribe = client.providers.subscribe((update) => {
  const ready = update.entries.filter((entry) => entry.status === "ready");
  console.log(
    "Ready providers:",
    ready.map((entry) => entry.provider),
  );
});
```

Always call the returned unsubscribe functions before discarding the owning object. Call `client.close()` when the application no longer needs the daemon connection.
