# Debug, audit, and replay

Read OrchaJS JSONL session events with .events() for debugging, audit, and replay.

Source: https://orcha.sh/docs/sessions/events
Markdown: https://orcha.sh/docs/sessions/events.mdx

Use `.events()` when you need the exact durable record for auditing,
debugging, or replay:

```ts
const page = await orcha.supportAgent.events(sessionId, {
  page: 1,
  pageSize: 100,
});

for (const event of page.events) {
  console.log(event.sequence, event.type, event.data);
}
```

These are the pure events stored by the default Node runtime at:

```text
.orcha/sessions/<agentName>/<sessionId>.jsonl
```

This append-only event stream is not just a debug log. Orcha derives the
agent's functioning session state, history, pending client actions, usage,
and resumable context from it.

Use `.history()` for normal conversation UI. Use `.events()` when the exact
internal timeline matters.

## Example response

```ts
{
  events: [
    {
      sequence: 1,                         // Position in this session.
      type: "session.created",             // What happened.
      timestamp: "2026-09-28T12:00:00Z",   // ISO timestamp.
      data: {
        schemaVersion: 1,
        sessionId: "ses_01K...",
        agent: "supportAgent",
        status: "active",
        metadata: {},
        variables: {},
      },
    },
    {
      sequence: 2,
      type: "run.started",
      timestamp: "2026-09-28T12:00:01Z",
      run: 1,                              // Numbered run in the session.
      data: {
        status: "running",
        agent: "supportAgent",
        provider: "anthropic",
        model: "claude-sonnet-4-6",
        region: "global",
        outputType: "text",
        clientCapabilities: [],
      },
    },
  ],
  throughSequence: 12, // Stable upper boundary for pagination.
  page: 1,
  pageSize: 100,
  total: 12,
  hasMore: false,

  // The current SessionSnapshot is included too.
  sessionId: "ses_01K...",
  agent: "supportAgent",
  status: "active",
  metadata: {},
  createdAt: "2026-09-28T12:00:00Z",
  updatedAt: "2026-09-28T12:00:08Z",
  runStatus: "completed",
  pendingClientActions: [],
}
```

## Paginate against a stable session

Sessions can receive new events while you read older pages. Keep the
`throughSequence` returned by the first request and send it with later pages:

```ts
const latest = await orcha.supportAgent.events(sessionId, {
  page: 1,
  pageSize: 100,
});

const older = await orcha.supportAgent.events(sessionId, {
  page: 2,
  pageSize: 100,
  throughSequence: latest.throughSequence,
});
```

This keeps every page within the same event boundary. Page 1 is the newest
page; higher page numbers move backward.

Most product interfaces should use [`history()`](/docs/sessions/history)
instead. Do not read `.orcha` storage files directly.

## API reference

```ts
events(
  sessionId: string,
  options?: {
    page?: number;
    pageSize?: number;
    throughSequence?: number;
  },
): Promise<SessionEvents>

type SessionEvents = SessionSnapshot & {
  events: SessionEvent[];
  throughSequence: number;
  page: number;
  pageSize: number;
  total: number;
  hasMore: boolean;
};
```

- `page` defaults to `1`.
- `pageSize` defaults to `50` and accepts `1` through `100`.
- `throughSequence` fixes the newest event included across paginated calls.
- `total` counts events inside that sequence boundary.
- Snapshot fields describe the current session.

### Event envelope

```ts
type SessionEvent = {
  sequence: number;
  type: SessionEventType;
  timestamp: string;
  run?: number;
  data: Record<string, unknown>;
};
```

- `sequence` is unique and strictly ordered within one session.
- `type` identifies the event and the shape of `data`.
- `timestamp` is an ISO timestamp.
- `run` identifies the numbered run. Session-level events omit it.
- `data` is the typed payload for that event.

### Event types

Session lifecycle:

```ts
"session.created"
"session.updated"
"session.paused"
"session.resumed"
```

Run lifecycle:

```ts
"run.started"
"run.paused"
"run.completed"
"run.failed"
```

Messages and actions:

```ts
"message.created"
"action.requested"
"action.completed"
"action.failed"
"client_action.requested"
"client_action.resolved"
```

Skills, evaluations, and subagents:

```ts
"skill.requested"
"skill.loaded"
"skill.failed"
"evaluation.requested"
"evaluation.completed"
"evaluation.failed"
"subagent.initiated"
"subagent.resumed"
"subagent.completed"
"subagent.paused"
"subagent.failed"
```

Tests can additionally write `test.warning` and `test.completed`.

### Important payloads

```ts
// message.created
{
  role: "user" | "assistant" | "tool";
  content: MessageContent[] | ToolResult[];
  // Assistant messages can also include provider, model, usage,
  // durationMs, stopReason, responseId, status, and parsedOutput.
}

// client_action.requested
{
  status: "waiting";
  calls: Array<{
    callId: string;
    name: string;
    arguments: Record<string, unknown>;
  }>;
  localResults: ToolResult[];
  toolCallOrder: string[];
}

// client_action.resolved
{
  status: "completed";
  results: ToolResult[];
}

// run.paused
{
  status: "waiting_for_client_action" | "paused";
  clientToolCalls?: ClientToolCall[];
  output?: AgentOutput;
  usage?: Usage;
  durationMs?: number;
}

// run.failed
{
  status: "failed";
  durationMs: number;
  usage?: Usage;
  error: {
    code: string;
    message: string;
    retryable?: boolean;
  };
}
```

Treat the event log as append-only. Consume events by `sequence`; never edit
or infer storage filenames.
