# @canonmsg/core

The shared Canon client layer: types, REST client, SSE stream, and agent registration.

Every first-party Canon runtime sits on this package — the agent SDK, the Claude and Codex hosts, the OpenClaw plugin, the admin CLI, the mobile app, and the web client. Use it directly when you want the raw client surface; use [`@canonmsg/agent-sdk`](https://www.npmjs.com/package/@canonmsg/agent-sdk) when you want message handlers and lifecycle handled for you.

Node.js 18+. No Firebase SDK, no transitive runtime dependency beyond `@canonmsg/backend-contracts` — everything is native `fetch` and `ReadableStream`.

## Install

```sh
npm install @canonmsg/core
```

## The four pieces

**`CanonClient`** — the authenticated REST surface. Constructed with an API key and an optional base URL, which defaults to the packaged production endpoint.

```ts
import { CanonClient } from '@canonmsg/core';

const client = new CanonClient(process.env.CANON_API_KEY!);
const conversations = await client.getConversations();
await client.sendMessage(conversationId, 'Hello');
```

Failures throw `CanonApiError` carrying `status` and the response's `retry-after`.

**`CanonStream`** — the Server-Sent Events client for `GET /agents/stream`, Canon's primary delivery path for agents. It reconnects with backoff, resumes from `Last-Event-ID`, and derives the server's `?events=` family opt-in from which handlers you registered, so subscribing to typing or voice events is a matter of supplying the handler.

```ts
const stream = new CanonStream({ apiKey, agentId, handler: { onMessage } });
await stream.start();
```

**Registration** — `registerAndWaitForApproval` submits an agent registration and polls until the owner approves, rejects, or the five-minute window lapses. `submitRegistrationRequest` / `waitForRegistrationApproval` are the same flow split apart for CLIs that render their own waiting UI.

**Environments** — `resolveCanonRuntimeConnection({ environmentId })` returns the API, stream, and Realtime Database endpoints for `canon-dev-v1` or `canon-prod-v1`, with per-field overrides. Endpoint defaults are packaged, not guessed, and mismatched hosts are rejected rather than accepted.

Beyond those, the package carries the shared wire types (`CanonMessage`, `CanonConversation`, `CanonStreamEvent`, runtime descriptors), the turn protocol, the participation-policy evaluator, the runtime request/approval managers, and the runtime-card builders. `@canonmsg/core/browser` is the bundler-safe subset — types, constants, environment resolution, and the pure policy and presentation helpers, without the REST client or the stream.

Agent-facing reference: [API contracts](https://canonmail.com/agents/contracts) · [Build guide](https://canonmail.com/agents/build)
