# zidane/channels

> Slack and GitHub channels for zidane hosts, with the config types, providers, presenters and the runner. Experimental.

Import: `import { … } from 'zidane/channels'`. Source: [src/channels/index.ts](https://github.com/Tahul/zidane/blob/main/src/channels/index.ts).

Use `zidane/channels` to type a channels config with `defineChannels`, or to build your own provider or presenter. zidane-server and `zidane-daemon` load it only when their data dir holds a channels config. The entry point is experimental: its API can change in any release. [Channels](https://zidane.si/docs/channels.md) covers the setup, the access levels and the commands.

```ts
import { defineChannels } from 'zidane/channels'

export default defineChannels({
  channels: {
    me: {
      provider: 'slack',
      team: 'T0123ABCD',
      botToken: { env: 'SLACK_BOT_TOKEN' },
      appToken: { env: 'SLACK_APP_TOKEN' },
      owners: ['U0123ABCD'],
      bindings: [{ match: { dm: true }, folder: '/home/me/code/app' }],
    },
  },
})
```

## Functions

### `accessLayers`

Function.

The channels config: types, `defineChannels`, validation, access
resolution, loading, `channels check` and the file watcher.

```ts
function accessLayers(
  config: ChannelsConfig,
  channel: string,
  binding: Binding<SlackMatch | GithubMatch> | undefined,
  role: ChannelRole,
): Access[]
```

**Parameters**

- `config` (`ChannelsConfig`): The validated config.
- `channel` (`string`): The channel's name.
- `binding` (`Binding<SlackMatch | GithubMatch> | undefined`): The binding (absent: defaults and channel only).
- `role` (`ChannelRole`): Whose access.

**Returns** `Access[]`

Source: [src/channels/config/access.ts:102](https://github.com/Tahul/zidane/blob/main/src/channels/config/access.ts#L102)

### `appJwt`

Function.

The App JWT: RS256 over `{ iat: now - 60, exp: now + 540, iss: appId }`
(seconds; `iat` backdated against clock drift, `exp` under GitHub's 10-minute cap).

```ts
function appJwt(input: { appId: number; key: KeyObject; now: number }): string
```

**Parameters**

- `input` (`{ appId: number; key: KeyObject; now: number }`): The App id, its key and the clock.

**Returns** `string`

Source: [src/channels/providers/github/auth.ts:51](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/auth.ts#L51)

### `channelsDisabled`

Function.

The kill switch is set.

```ts
function channelsDisabled(env?: Env): boolean
```

**Parameters**

- `env?` (`Env`, default `process.env`): Default `process.env`.

**Returns** `boolean`

Source: [src/channels/config/load.ts:73](https://github.com/Tahul/zidane/blob/main/src/channels/config/load.ts#L73)

### `channelWarnings`

Function.

The risky combinations in a validated config: members who may read the
host's secrets, members whose tool calls nobody approves, members whose
approvals never time out. Access set by a function is not inspected.

```ts
function channelWarnings(config: ChannelsConfig): ChannelsWarning[]
```

**Parameters**

- `config` (`ChannelsConfig`): A validated config.

**Returns** `ChannelsWarning[]`

Source: [src/channels/config/warnings.ts:25](https://github.com/Tahul/zidane/blob/main/src/channels/config/warnings.ts#L25)

### `checkChannels`

Function.

Check the channels config in `dataDir` without starting anything.

```ts
function checkChannels(dataDir: string, opts?: LoadOptions): Promise<ChannelsCheck>
```

**Parameters**

- `dataDir` (`string`): The host's storage dir.
- `opts?` (`LoadOptions`, default `{}`): Environment and workspace roots, as for loading.

**Returns** `Promise<ChannelsCheck>`

Source: [src/channels/config/check.ts:128](https://github.com/Tahul/zidane/blob/main/src/channels/config/check.ts#L128)

### `conversationId`

Function.

A conversation's stable id: `ch-` + 24 hex of sha256(channel NUL key).

```ts
function conversationId(channel: string, key: string): string
```

**Parameters**

- `channel` (`string`): The channel's name.
- `key` (`string`): The conversation's key.

**Returns** `string`

Source: [src/channels/runner/ids.ts:21](https://github.com/Tahul/zidane/blob/main/src/channels/runner/ids.ts#L21)

### `createBranchPublisher`

Function.

A branch publisher for one channel.

```ts
function createBranchPublisher(options: BranchPublisherOptions): BranchPublisher
```

**Parameters**

- `options` (`BranchPublisherOptions`): The client, channel, config and seams.

**Returns** `BranchPublisher`

Source: [src/channels/providers/github/pr.ts:213](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/pr.ts#L213)

### `createGithubClient`

Function.

A GitHub client for one channel.

```ts
function createGithubClient(options: GithubClientOptions): GithubClient
```

**Parameters**

- `options` (`GithubClientOptions`): The App, its key and test seams.

**Returns** `GithubClient`

Source: [src/channels/providers/github/api.ts:167](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/api.ts#L167)

### `createGithubPresenter`

Function.

The built-in presenter for one channel.

```ts
function createGithubPresenter(
  client: GithubChannelClient,
  options: { log: ChannelLogger; timers: RunnerTimers },
): Presenter<GithubRef>
```

**Parameters**

- `client` (`GithubChannelClient`): The channel's GitHub client (with its branch publisher).
- `options` (`{ log: ChannelLogger; timers: RunnerTimers }`): Timers (tests drive them) and the log.

**Returns** `Presenter<GithubRef>`

Source: [src/channels/providers/github/presenter.ts:61](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/presenter.ts#L61)

### `createGithubProvider`

Function.

A GitHub provider.

```ts
function createGithubProvider(
  options?: GithubProviderOptions,
): ChannelProvider<GithubChannel, GithubRef, GithubChannelClient>
```

**Parameters**

- `options?` (`GithubProviderOptions`, default `{}`): Test seams; default the real GitHub.

**Returns** `ChannelProvider<GithubChannel, GithubRef, GithubChannelClient>`

Source: [src/channels/providers/github/index.ts:69](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/index.ts#L69)

### `createPresenter`

Function.

A provider's or a module's presenter, built for one channel.

```ts
function createPresenter<Ref, Client>(
  value: PresenterDefinition<Ref, Client> | Presenter<Ref>,
  ctx: PresenterContext<Client>,
): Presenter<Ref>
```

**Type parameters**

- `Ref`
- `Client`

**Parameters**

- `value` (`PresenterDefinition<Ref, Client> | Presenter<Ref>`): A [`PresenterDefinition`](https://zidane.si/docs/reference/channels.md#PresenterDefinition) or plain hooks.
- `ctx` (`PresenterContext<Client>`): The channel and its provider client.

**Returns** `Presenter<Ref>`

Source: [src/channels/presenter.ts:245](https://github.com/Tahul/zidane/blob/main/src/channels/presenter.ts#L245)

### `createSlackClient`

Function.

A Slack client for one channel.

```ts
function createSlackClient(options: SlackClientOptions): SlackClient
```

**Parameters**

- `options` (`SlackClientOptions`): Tokens, team and test seams.

**Returns** `SlackClient`

Source: [src/channels/providers/slack/api.ts:233](https://github.com/Tahul/zidane/blob/main/src/channels/providers/slack/api.ts#L233)

### `createSlackPresenter`

Function.

The built-in presenter for one channel.

```ts
function createSlackPresenter(
  client: SlackClient,
  options: { log: ChannelLogger; store?: PresenterStore; timers: RunnerTimers },
): Presenter<SlackRef>
```

**Parameters**

- `client` (`SlackClient`): The channel's Slack client.
- `options` (`{ log: ChannelLogger; store?: PresenterStore; timers: RunnerTimers }`): Timers (tests drive them), the log and the channel's store.

**Returns** `Presenter<SlackRef>`

Source: [src/channels/providers/slack/presenter.ts:60](https://github.com/Tahul/zidane/blob/main/src/channels/providers/slack/presenter.ts#L60)

### `createSlackProvider`

Function.

A Slack provider.

```ts
function createSlackProvider(
  options?: SlackProviderOptions,
): ChannelProvider<SlackChannel, SlackRef, SlackClient>
```

**Parameters**

- `options?` (`SlackProviderOptions`, default `{}`): Test seams; default the real Slack.

**Returns** `ChannelProvider<SlackChannel, SlackRef, SlackClient>`

Source: [src/channels/providers/slack/index.ts:68](https://github.com/Tahul/zidane/blob/main/src/channels/providers/slack/index.ts#L68)

### `daemonRefusals`

Function.

Why the laptop daemon refuses `config` (design: owners only, no
webhooks), each naming its key path. Empty when it may run it.

```ts
function daemonRefusals(config: ChannelsConfig): string[]
```

**Parameters**

- `config` (`ChannelsConfig`): A validated config.

**Returns** `string[]`

Source: [src/channels/host.ts:143](https://github.com/Tahul/zidane/blob/main/src/channels/host.ts#L143)

### `defineChannelProvider`

Function.

Returns `provider` unchanged: a typed anchor for provider modules.

```ts
function defineChannelProvider<C extends ChannelConfig, Ref = JsonValue, Client = unknown>(
  provider: ChannelProvider<C, Ref, Client>,
): ChannelProvider<C, Ref, Client>
```

**Type parameters**

- `C` (`extends ChannelConfig`)
- `Ref` (default `JsonValue`)
- `Client` (default `unknown`)

**Parameters**

- `provider` (`ChannelProvider<C, Ref, Client>`): The provider.

**Returns** `ChannelProvider<C, Ref, Client>`

Source: [src/channels/provider.ts:203](https://github.com/Tahul/zidane/blob/main/src/channels/provider.ts#L203)

### `defineChannels`

Function.

Returns `config` unchanged: a typed anchor for `channels.config.ts`.
Validation happens in the loader.

```ts
function defineChannels(config: ChannelsConfig): ChannelsConfig
```

**Parameters**

- `config` (`ChannelsConfig`): The channels and their defaults.

**Returns** `ChannelsConfig`

**Example**

```ts
import { defineChannels } from 'zidane/channels'

export default defineChannels({
  channels: {
    ops: {
      provider: 'slack',
      team: 'T0123',
      botToken: { env: 'SLACK_BOT_TOKEN' },
      appToken: { env: 'SLACK_APP_TOKEN' },
      owners: ['U0123'],
      bindings: [{ match: { channel: 'C0123' }, folder: '/work/app' }],
    },
  },
})
```

Source: [src/channels/config/types.ts:185](https://github.com/Tahul/zidane/blob/main/src/channels/config/types.ts#L185)

### `definePresenter`

Function.

A presenter for a provider or a channel's `presenter` module (its default export).

```ts
function definePresenter<Ref = JsonValue, Client = unknown>(
  presenter: Presenter<Ref> | ((ctx: PresenterContext<Client>) => Presenter<Ref>),
): PresenterDefinition<Ref, Client>
```

**Type parameters**

- `Ref` (default `JsonValue`)
- `Client` (default `unknown`)

**Parameters**

- `presenter` (`Presenter<Ref> | ((ctx: PresenterContext<Client>) => Presenter<Ref>)`): The hooks, or a function building them from the provider's client.

**Returns** `PresenterDefinition<Ref, Client>`

**Example**

```ts
import { definePresenter } from 'zidane/channels'

export default definePresenter(({ client }) => ({
  async run(ref, event) {
    if (event.kind === 'ended')
      await client.post(ref, `done: ${event.status}`)
  },
}))
```

Source: [src/channels/presenter.ts:235](https://github.com/Tahul/zidane/blob/main/src/channels/presenter.ts#L235)

### `effectiveAccess`

Function.

The channels config: types, `defineChannels`, validation, access
resolution, loading, `channels check` and the file watcher.

```ts
function effectiveAccess(
  layers: Access[],
  role: ChannelRole,
  ctx?: AccessContext,
): EffectiveAccess | 'dynamic' | undefined
```

**Parameters**

- `layers` (`Access[]`): From [`accessLayers`](https://zidane.si/docs/reference/channels.md#accessLayers).
- `role` (`ChannelRole`): Whose access (owners start from 'full').
- `ctx?` (`AccessContext`): The sender, to call function layers with.

**Returns** `EffectiveAccess | 'dynamic' | undefined`

Source: [src/channels/config/access.ts:116](https://github.com/Tahul/zidane/blob/main/src/channels/config/access.ts#L116)

### `expandLevel`

Function.

The channels config: types, `defineChannels`, validation, access
resolution, loading, `channels check` and the file watcher.

```ts
function expandLevel(level: AccessLevel): EffectiveAccess
```

**Parameters**

- `level` (`AccessLevel`): The level to expand.

**Returns** `EffectiveAccess`

Source: [src/channels/config/access.ts:57](https://github.com/Tahul/zidane/blob/main/src/channels/config/access.ts#L57)

### `findChannelsConfig`

Function.

The config file in `dataDir`, or `null` when there is none.

```ts
function findChannelsConfig(dataDir: string): ChannelsConfigFile | null
```

**Parameters**

- `dataDir` (`string`): The host's storage dir.

**Returns** `ChannelsConfigFile | null`

Source: [src/channels/config/load.ts:83](https://github.com/Tahul/zidane/blob/main/src/channels/config/load.ts#L83)

### `githubPresenter`

Function.

The built-in presenter as a definition (the provider's default).

```ts
function githubPresenter(
  options?: { timers?: RunnerTimers },
): PresenterDefinition<GithubRef, GithubChannelClient>
```

**Parameters**

- `options?` (`{ timers?: RunnerTimers }`, default `{}`): Timers; default real time.

**Returns** `PresenterDefinition<GithubRef, GithubChannelClient>`

Source: [src/channels/providers/github/presenter.ts:194](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/presenter.ts#L194)

### `githubSignature`

Function.

The `sha256=<hex>` signature of a body.

```ts
function githubSignature(
  secret: string,
  body: string | Uint8Array<ArrayBufferLike>,
): Promise<string>
```

**Parameters**

- `secret` (`string`): The App's webhook secret.
- `body` (`string | Uint8Array<ArrayBufferLike>`): The raw body.

**Returns** `Promise<string>`

Source: [src/channels/providers/github/signature.ts:32](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/signature.ts#L32)

### `hostChannels`

Function.

Host the channels configured in `options.dataDir`. Never throws into the
host: a config that does not load is logged with its key paths and
reported by `status()`; channels then stay off until a reload succeeds.

```ts
function hostChannels(options: HostChannelsOptions): Promise<ChannelsHost>
```

**Parameters**

- `options` (`HostChannelsOptions`): Flavor, client, data dir, environment snapshot, log.

**Returns** `Promise<ChannelsHost>`

Source: [src/channels/host.ts:191](https://github.com/Tahul/zidane/blob/main/src/channels/host.ts#L191)

### `intakePath`

Function.

Where the intake file lives.

```ts
function intakePath(dataDir: string): string
```

**Parameters**

- `dataDir` (`string`): The host's data dir: the file is `<dataDir>/channels/intake.db`.

**Returns** `string`

Source: [src/channels/runner/intake.ts:104](https://github.com/Tahul/zidane/blob/main/src/channels/runner/intake.ts#L104)

### `isPresenterDefinition`

Function.

Whether `value` came from [`definePresenter`](https://zidane.si/docs/reference/channels.md#definePresenter).

```ts
function isPresenterDefinition(
  value: unknown,
): value is PresenterDefinition<never, never>
```

**Parameters**

- `value` (`unknown`): Anything (a module's export).

**Returns** `value is PresenterDefinition<never, never>`

Source: [src/channels/presenter.ts:254](https://github.com/Tahul/zidane/blob/main/src/channels/presenter.ts#L254)

### `jsonErrorPosition`

Function.

The first error in `text`, or `null` when it is valid JSON.

```ts
function jsonErrorPosition(text: string): JsonErrorPosition | null
```

**Parameters**

- `text` (`string`): The file's content.

**Returns** `JsonErrorPosition | null`

Source: [src/channels/config/json-position.ts:138](https://github.com/Tahul/zidane/blob/main/src/channels/config/json-position.ts#L138)

### `limitsOf`

Function.

The channels config: types, `defineChannels`, validation, access
resolution, loading, `channels check` and the file watcher.

```ts
function limitsOf(config: ChannelsConfig, channel: string): Required<Limits>
```

**Parameters**

- `config` (`ChannelsConfig`): The validated config.
- `channel` (`string`): The channel's name.

**Returns** `Required<Limits>`

Source: [src/channels/config/access.ts:196](https://github.com/Tahul/zidane/blob/main/src/channels/config/access.ts#L196)

### `loadChannelsConfig`

Function.

The host's channels config: `null` when channels are off (no file, or the
kill switch).

```ts
function loadChannelsConfig(
  dataDir: string,
  opts?: LoadOptions,
): Promise<LoadedChannels | null>
```

**Parameters**

- `dataDir` (`string`): The host's storage dir.
- `opts?` (`LoadOptions`, default `{}`): Environment and workspace roots.

**Returns** `Promise<LoadedChannels | null>`

Source: [src/channels/config/load.ts:182](https://github.com/Tahul/zidane/blob/main/src/channels/config/load.ts#L182)

### `mentionsBot`

Function.

Whether `text` mentions the bot: `@<login without [bot]>` or `@<login>`.

```ts
function mentionsBot(text: string, botLogin: string): boolean
```

**Parameters**

- `text` (`string`): The comment body.
- `botLogin` (`string`): The bot's login (`name[bot]`).

**Returns** `boolean`

Source: [src/channels/providers/github/inbound.ts:62](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/inbound.ts#L62)

### `normalizeWebhook`

Function.

One webhook delivery as an inbound message, or `null` when it is not for
the runner (another event or action, a bot, a comment that does not
address the bot).

```ts
function normalizeWebhook(
  deps: GithubInboundDeps,
  event: string,
  payload: unknown,
): InboundMessage | null
```

**Parameters**

- `deps` (`GithubInboundDeps`): The channel, its config and the bot's login.
- `event` (`string`): `X-GitHub-Event`.
- `payload` (`unknown`): The parsed body.

**Returns** `InboundMessage | null`

Source: [src/channels/providers/github/inbound.ts:93](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/inbound.ts#L93)

### `parsePrivateKey`

Function.

The App's private key, parsed.

```ts
function parsePrivateKey(pem: string): KeyObject
```

**Parameters**

- `pem` (`string`): PEM text: `BEGIN RSA PRIVATE KEY` (PKCS#1) or `BEGIN PRIVATE KEY` (PKCS#8).

**Returns** `KeyObject`

Source: [src/channels/providers/github/auth.ts:29](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/auth.ts#L29)

### `readChannelsConfig`

Function.

Read and validate one config file, secrets included.

```ts
function readChannelsConfig(
  file: ChannelsConfigFile,
  opts?: LoadOptions,
): Promise<LoadedChannels>
```

**Parameters**

- `file` (`ChannelsConfigFile`): From [`findChannelsConfig`](https://zidane.si/docs/reference/channels.md#findChannelsConfig).
- `opts?` (`LoadOptions`, default `{}`): Environment and workspace roots.

**Returns** `Promise<LoadedChannels>`

Source: [src/channels/config/load.ts:156](https://github.com/Tahul/zidane/blob/main/src/channels/config/load.ts#L156)

### `resolveAccess`

Function.

The channels config: types, `defineChannels`, validation, access
resolution, loading, `channels check` and the file watcher.

```ts
function resolveAccess(
  config: ChannelsConfig,
  target: { binding: Binding; channel: string; userId: string },
): ResolvedAccess | null
```

**Parameters**

- `config` (`ChannelsConfig`): The validated config.
- `target` (`{ binding: Binding; channel: string; userId: string }`): The channel's name, the binding and the sender's provider id.

**Returns** `ResolvedAccess | null`

Source: [src/channels/config/access.ts:210](https://github.com/Tahul/zidane/blob/main/src/channels/config/access.ts#L210)

### `resolveSecrets`

Function.

Read every `{ env }` secret of a validated config.

```ts
function resolveSecrets(
  config: ChannelsConfig,
  env?: Record<string, string | undefined>,
): ResolvedSecrets
```

**Parameters**

- `config` (`ChannelsConfig`): A validated config (not modified).
- `env?` (`Record<string, string | undefined>`, default `process.env`): Where variables are read. Default `process.env`.

**Returns** `ResolvedSecrets`

Source: [src/channels/config/secrets.ts:34](https://github.com/Tahul/zidane/blob/main/src/channels/config/secrets.ts#L34)

### `roleOf`

Function.

The channels config: types, `defineChannels`, validation, access
resolution, loading, `channels check` and the file watcher.

```ts
function roleOf(
  channel: ChannelConfig,
  binding: Binding<SlackMatch | GithubMatch> | undefined,
  userId: string,
): ChannelRole | null
```

**Parameters**

- `channel` (`ChannelConfig`): The channel.
- `binding` (`Binding<SlackMatch | GithubMatch> | undefined`): The binding the message arrived through.
- `userId` (`string`): The sender's provider id.

**Returns** `ChannelRole | null`

Source: [src/channels/config/access.ts:183](https://github.com/Tahul/zidane/blob/main/src/channels/config/access.ts#L183)

### `runChannels`

Function.

Start the channels of `config` against the host `client` talks to.
Never throws into the host: a channel that cannot start shows 'failed'
on its integration, and an intake store that cannot open fails them all.

```ts
function runChannels(options: RunChannelsOptions): Promise<ChannelsRunner>
```

**Parameters**

- `options` (`RunChannelsOptions`): Client, config, data dir, log, providers.

**Returns** `Promise<ChannelsRunner>`

Source: [src/channels/runner/index.ts:115](https://github.com/Tahul/zidane/blob/main/src/channels/runner/index.ts#L115)

### `secretValue`

Function.

A resolved secret's value.

```ts
function secretValue(secret: Secret): string
```

**Parameters**

- `secret` (`Secret`): A secret from a config [`resolveSecrets`](https://zidane.si/docs/reference/channels.md#resolveSecrets) returned.

**Returns** `string`

Source: [src/channels/config/secrets.ts:94](https://github.com/Tahul/zidane/blob/main/src/channels/config/secrets.ts#L94)

### `slackPresenter`

Function.

The built-in presenter as a definition (the provider's default).

```ts
function slackPresenter(
  options?: { timers?: RunnerTimers },
): PresenterDefinition<SlackRef, SlackClient>
```

**Parameters**

- `options?` (`{ timers?: RunnerTimers }`, default `{}`): Timers; default real time.

**Returns** `PresenterDefinition<SlackRef, SlackClient>`

Source: [src/channels/providers/slack/presenter.ts:189](https://github.com/Tahul/zidane/blob/main/src/channels/providers/slack/presenter.ts#L189)

### `slackSignature`

Function.

The `v0=<hex>` signature of a request.

```ts
function slackSignature(
  secret: string,
  timestamp: string,
  body: string,
): Promise<string>
```

**Parameters**

- `secret` (`string`): The app's signing secret.
- `timestamp` (`string`): `X-Slack-Request-Timestamp`.
- `body` (`string`): The raw body.

**Returns** `Promise<string>`

Source: [src/channels/providers/slack/signature.ts:36](https://github.com/Tahul/zidane/blob/main/src/channels/providers/slack/signature.ts#L36)

### `toSessionPolicy`

Function.

The channels config: types, `defineChannels`, validation, access
resolution, loading, `channels check` and the file watcher.

```ts
function toSessionPolicy(access: EffectiveAccess): SessionPolicy
```

**Parameters**

- `access` (`EffectiveAccess`): The folded rules.

**Returns** `SessionPolicy`

Source: [src/channels/config/access.ts:142](https://github.com/Tahul/zidane/blob/main/src/channels/config/access.ts#L142)

### `validateChannelsConfig`

Function.

Check a channels config read from JSON or exported by a TS file.

```ts
function validateChannelsConfig(
  value: unknown,
  opts?: ValidateOptions,
): ValidationResult
```

**Parameters**

- `value` (`unknown`): The parsed file (untrusted).
- `opts?` (`ValidateOptions`, default `{}`): Whether function access rules are allowed, and the workspace roots folders must sit in.

**Returns** `ValidationResult`: The typed config, or every problem with its key path.

Source: [src/channels/config/validate.ts:348](https://github.com/Tahul/zidane/blob/main/src/channels/config/validate.ts#L348)

### `verifyGithubSignature`

Function.

Check a delivery's signature.

```ts
function verifyGithubSignature(
  input: { body: string | Uint8Array<ArrayBufferLike>; secret: string; signature: string | null },
): Promise<GithubSignatureCheck>
```

**Parameters**

- `input` (`{ body: string | Uint8Array<ArrayBufferLike>; secret: string; signature: string | null }`): The secret, the header and the raw body.

**Returns** `Promise<GithubSignatureCheck>`

Source: [src/channels/providers/github/signature.ts:46](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/signature.ts#L46)

### `verifySlackSignature`

Function.

Check a request's signature.

```ts
function verifySlackSignature(
  input: { body: string; now: number; secret: string; signature: string | null; timestamp: string | null },
): Promise<SlackSignatureCheck>
```

**Parameters**

- `input` (`{ body: string; now: number; secret: string; signature: string | null; timestamp: string | null }`): The secret, the two headers, the raw body and the clock.

**Returns** `Promise<SlackSignatureCheck>`

Source: [src/channels/providers/slack/signature.ts:51](https://github.com/Tahul/zidane/blob/main/src/channels/providers/slack/signature.ts#L51)

### `watchChannelsConfig`

Function.

Watch `dataDir` for changes to its channels config. A missing dir watches
nothing (a config created later is picked up at the next start).

```ts
function watchChannelsConfig(
  dataDir: string,
  onChange: (change: ChannelsConfigChange) => void,
  opts?: WatchOptions,
): ChannelsConfigWatcher
```

**Parameters**

- `dataDir` (`string`): The host's storage dir.
- `onChange` (`(change: ChannelsConfigChange) => void`): Called once per burst of changes to one file.
- `opts?` (`WatchOptions`, default `{}`): Debounce.

**Returns** `ChannelsConfigWatcher`

Source: [src/channels/config/watch.ts:79](https://github.com/Tahul/zidane/blob/main/src/channels/config/watch.ts#L79)

### `worktreeBranch`

Function.

The worktree branch of a conversation's session: `zidane/<provider>-<first 8 hex>`.

```ts
function worktreeBranch(provider: string, localId: string): string
```

**Parameters**

- `provider` (`string`): The channel's provider.
- `localId` (`string`): From [`conversationId`](https://zidane.si/docs/reference/channels.md#conversationId).

**Returns** `string`

Source: [src/channels/runner/ids.ts:42](https://github.com/Tahul/zidane/blob/main/src/channels/runner/ids.ts#L42)

## Classes

### `ChannelProviderError`

Class.

An error a provider throws (from `start`, or reports with `ctx.fail`) to
say whether retrying can help. Any other error counts as 'transient'.

```ts
class ChannelProviderError extends Error
```

**Constructor**

```ts
new ChannelProviderError(kind: ChannelFailureKind, message: string)
```

**Parameters**

- `kind` (`ChannelFailureKind`): 'auth' / 'config': stop the channel. 'transient': retry.
- `message` (`string`): Why, shown as the integration's detail.

**Returns** `ChannelProviderError`

**Properties**

- `kind` (`ChannelFailureKind`, readonly): 'auth' / 'config': the channel stops. 'transient': it retries with backoff.

Source: [src/channels/provider.ts:124](https://github.com/Tahul/zidane/blob/main/src/channels/provider.ts#L124)

### `ChannelsConfigError`

Class.

A config that does not load: every problem, each naming its key path.

```ts
class ChannelsConfigError extends Error
```

**Constructor**

```ts
new ChannelsConfigError(errors: string[])
```

**Parameters**

- `errors` (`string[]`): Every problem, each naming its key path. The message joins them with newlines.

**Returns** `ChannelsConfigError`

**Properties**

- `errors` (`string[]`, readonly): Every problem, each naming its key path.

Source: [src/channels/config/types.ts:190](https://github.com/Tahul/zidane/blob/main/src/channels/config/types.ts#L190)

### `GithubApiError`

Class.

A REST call that failed.

```ts
class GithubApiError extends ChannelProviderError
```

**Constructor**

```ts
new GithubApiError(
  path: string,
  status: number,
  message: string,
  kind?: ChannelFailureKind,
)
```

**Parameters**

- `path` (`string`): The REST path called.
- `status` (`number`): HTTP status, 0 for a transport failure.
- `message` (`string`): What went wrong. The error's message is `github <path>: <message>`.
- `kind?` (`ChannelFailureKind`, default `'transient'`): Whether retrying can help. Default 'transient'.

**Returns** `GithubApiError`

**Properties**

- `kind` (`ChannelFailureKind`, readonly, from `ChannelProviderError`): 'auth' / 'config': the channel stops. 'transient': it retries with backoff.
- `path` (`string`, readonly): The REST path called (`/app`, `/repos/<owner>/<repo>/…`).
- `status` (`number`, readonly): HTTP status, 0 for a transport failure.

Source: [src/channels/providers/github/api.ts:38](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/api.ts#L38)

### `SlackApiError`

Class.

A Web API call that failed: Slack's error code, and whether retrying can help.

```ts
class SlackApiError extends ChannelProviderError
```

**Constructor**

```ts
new SlackApiError(method: string, error: string, kind?: ChannelFailureKind)
```

**Parameters**

- `method` (`string`): The Web API method called.
- `error` (`string`): Slack's error code, or a transport failure. The error's message is `slack <method>: <error>`.
- `kind?` (`ChannelFailureKind`, default `'transient'`): Whether retrying can help. Default 'transient'.

**Returns** `SlackApiError`

**Properties**

- `error` (`string`, readonly): Slack's error code (`channel_not_found`), or a transport failure.
- `kind` (`ChannelFailureKind`, readonly, from `ChannelProviderError`): 'auth' / 'config': the channel stops. 'transient': it retries with backoff.
- `method` (`string`, readonly): The Web API method called (`chat.postMessage`), or `files` for a download.

Source: [src/channels/providers/slack/api.ts:45](https://github.com/Tahul/zidane/blob/main/src/channels/providers/slack/api.ts#L45)

## Constants

### `BUILTIN_CHANNEL_PROVIDERS`

Constant.

Built-in providers by name (`slack`, `github`).

```ts
const BUILTIN_CHANNEL_PROVIDERS: Readonly<Record<string, ChannelProvider<any, any, any>>>
```

Source: [src/channels/providers/index.ts:16](https://github.com/Tahul/zidane/blob/main/src/channels/providers/index.ts#L16)

### `CHANNEL_SECRET_KEYS`

Constant.

The config keys that hold secrets, per provider.

```ts
const CHANNEL_SECRET_KEYS: Readonly<Record<ChannelConfig['provider'], readonly string[]>>
```

Source: [src/channels/config/secrets.ts:23](https://github.com/Tahul/zidane/blob/main/src/channels/config/secrets.ts#L23)

### `CHANNELS_JSON`

Constant.

The JSON config's file name in the data dir.

```ts
const CHANNELS_JSON = 'channels.json'
```

Source: [src/channels/config/load.ts:28](https://github.com/Tahul/zidane/blob/main/src/channels/config/load.ts#L28)

### `CHANNELS_KILL_SWITCH`

Constant.

Set to 1, true, yes or on: channels stay off whatever the config says.

```ts
const CHANNELS_KILL_SWITCH = 'ZIDANE_NO_CHANNELS'
```

Source: [src/channels/config/load.ts:32](https://github.com/Tahul/zidane/blob/main/src/channels/config/load.ts#L32)

### `CHANNELS_ROUTE_PREFIX`

Constant.

Where webhook routes are mounted: `/channels/<channel name><route path>`.

```ts
const CHANNELS_ROUTE_PREFIX = '/channels/'
```

Source: [src/channels/host.ts:25](https://github.com/Tahul/zidane/blob/main/src/channels/host.ts#L25)

### `CHANNELS_TS`

Constant.

The TS config's file name in the data dir.

```ts
const CHANNELS_TS = 'channels.config.ts'
```

Source: [src/channels/config/load.ts:30](https://github.com/Tahul/zidane/blob/main/src/channels/config/load.ts#L30)

### `DEFAULT_LIMITS`

Constant.

Default throttles (owners are never throttled).

```ts
const DEFAULT_LIMITS: Required<Limits>
```

Source: [src/channels/config/access.ts:47](https://github.com/Tahul/zidane/blob/main/src/channels/config/access.ts#L47)

### `GITHUB_API_BASE`

Constant.

Where the REST API lives. Tests point it at a fake (`createGithubProvider({ apiBase })`).

```ts
const GITHUB_API_BASE = 'https://api.github.com'
```

Source: [src/channels/providers/github/api.ts:25](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/api.ts#L25)

### `githubProvider`

Constant.

The GitHub provider the hosts register.

```ts
const githubProvider: ChannelProvider<GithubChannel, GithubRef, GithubChannelClient>
```

Source: [src/channels/providers/github/index.ts:124](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/index.ts#L124)

### `READONLY_AGENT`

Constant.

The read-only level's agent profile.

```ts
const READONLY_AGENT = 'plan'
```

Source: [src/channels/config/access.ts:50](https://github.com/Tahul/zidane/blob/main/src/channels/config/access.ts#L50)

### `slackProvider`

Constant.

The Slack provider the hosts register.

```ts
const slackProvider: ChannelProvider<SlackChannel, SlackRef, SlackClient>
```

Source: [src/channels/providers/slack/index.ts:146](https://github.com/Tahul/zidane/blob/main/src/channels/providers/slack/index.ts#L146)

## Interfaces

### `AccessContext`

Interface.

What a function access rule is called with (`channels.config.ts` only).

```ts
interface AccessContext
```

**Properties**

- `binding` (`Binding`): The binding the message arrived through.
- `channel` (`string`): The channel's name (its key in `channels`).
- `provider` (`ChannelProvider`): The channel's provider.
- `role` (`ChannelRole`): The sender's role in this binding.
- `userId` (`string`): The sender's provider id (Slack user id, GitHub login).

Source: [src/channels/config/types.ts:39](https://github.com/Tahul/zidane/blob/main/src/channels/config/types.ts#L39)

### `AccessPolicy`

Interface.

A level with some of its rules changed.

```ts
interface AccessPolicy
```

**Properties**

- `agent?` (`string`): Agent profile id the session runs (overrides the binding's).
- `approvals?` (`ChannelApprovals`): How tool calls are approved: 'ask' (the channel's owners answer), 'decide' (a model decides), 'off' (never asked). Absent: the host's approval mode.
- `approvalTimeout?` (`number | 'never'`): Minutes a pending approval waits before it is denied; 'never' waits until answered.
- `budget?` (`{ minutes?: number; usd?: number }`): Per-run ceilings: cost in US dollars, wall time in minutes.
- `extends?` (`AccessLevel`): The level this policy starts from. Absent: the level the outer layers gave (an owner with none starts from 'full'; a member must have one).
- `readDeny?` (`false | 'host-secrets'`): 'host-secrets': read tools refuse the host's secret paths. `false` lifts it.
- `toolset?` (`'host' | 'profile-only'`): 'profile-only': the agent gets only its profile's tools and MCP servers, none the host or the folder adds (session policy `toolset`). 'host' lifts it. Absent: what the outer layers gave; no level sets it.

Source: [src/channels/config/types.ts:21](https://github.com/Tahul/zidane/blob/main/src/channels/config/types.ts#L21)

### `ApprovalView`

Interface.

A tool call waiting for an owner's decision.

```ts
interface ApprovalView
```

**Properties**

- `cwd` (`string`): The session's folder.
- `input` (`Record<string, unknown>`): The tool call's input.
- `owners` (`string[]`): Provider ids allowed to decide (the channel's owners), e.g. to DM them.
- `requestId` (`string`): The approval's id.
- `tool` (`string`): The tool's name.

Source: [src/channels/presenter.ts:81](https://github.com/Tahul/zidane/blob/main/src/channels/presenter.ts#L81)

### `BackoffOptions`

Interface.

Retry delays of a channel whose provider failed: doubling from `baseMs`, capped at `maxMs`.

```ts
interface BackoffOptions
```

**Properties**

- `baseMs` (`number`): The first delay, in milliseconds.
- `maxMs` (`number`): The longest delay, in milliseconds.

Source: [src/channels/runner/state.ts:38](https://github.com/Tahul/zidane/blob/main/src/channels/runner/state.ts#L38)

### `Binding`

Interface.

Where a channel's conversations go: the folder, agent and environment of their sessions.

```ts
interface Binding<M = SlackMatch | GithubMatch>
```

**Type parameters**

- `M` (default `SlackMatch | GithubMatch`)

**Properties**

- `access?` (`RoleAccess`): Access for this binding, over the channel's.
- `agent?` (`string`): Agent profile id. Default: the host's default agent.
- `environment?` (`'worktree' | 'local'`): 'worktree' (default): each conversation gets its own git worktree. 'local': the folder itself.
- `folder` (`string`): The sessions' working folder: absolute, inside the host's workspace roots.
- `match` (`M`): The conversations this binding takes.
- `members?` (`string[]`): More members, for this binding only (provider user ids).

Source: [src/channels/config/types.ts:84](https://github.com/Tahul/zidane/blob/main/src/channels/config/types.ts#L84)

### `BindingSummary`

Interface.

One binding, as `channels check` shows it.

```ts
interface BindingSummary
```

**Properties**

- `agent?` (`string`): The binding's agent profile, when it sets one.
- `environment` (`'worktree' | 'local'`): Where its sessions run. Default 'worktree'.
- `folder` (`string`): The folder its sessions run in.
- `match` (`string`): The conversations it takes: `#C0123`, `DMs`, `owner/repo`.
- `roles` (`Partial<Record<ChannelRole, string>>`): Each role's access, described (`full`, `contained: approvals ask, budget $2 / 15 min, …`).

Source: [src/channels/config/check.ts:16](https://github.com/Tahul/zidane/blob/main/src/channels/config/check.ts#L16)

### `BranchPublisher`

Interface.

Pushes a conversation's branch and opens its pull request.

```ts
interface BranchPublisher
```

**Properties**

- `publish` (`(ref: GithubRef, summary: string) => Promise<PublishResult>`): Push and open or update the pull request when the branch has new commits. Never throws.

Source: [src/channels/providers/github/pr.ts:72](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/pr.ts#L72)

### `ChannelAuditEvent`

Interface.

One audit record: who did what through a channel. Carries provider ids,
never message text.

```ts
interface ChannelAuditEvent
```

**Properties**

- `action` (`string`): What happened (`stranger.ignored`, `approval.refused`, `channel.failed`…).
- `channel` (`string`): The channel's name.
- `detail?` (`Record<string, JsonValue>`): Anything else worth keeping (no message text).
- `sessionId?` (`string`): The session involved.
- `userId?` (`string`): Provider user id, when a person is involved.

Source: [src/channels/provider.ts:94](https://github.com/Tahul/zidane/blob/main/src/channels/provider.ts#L94)

### `ChannelCommon`

Interface.

Fields every channel has.

```ts
interface ChannelCommon<M>
```

**Type parameters**

- `M`

**Properties**

- `access?` (`RoleAccess`): Access for this channel, over the defaults.
- `bindings` (`Binding<M>[]`): The conversations this channel serves.
- `enabled?` (`boolean`): `false` keeps the channel configured but off. Default true.
- `limits?` (`Limits`): Throttles, over the defaults.
- `members?` (`string[]`): Provider user ids who may talk to the agent with member access.
- `owners` (`string[]`): Provider user ids (Slack U…, GitHub logins) with owner rights: approvals, commands, steering.
- `presenter?` (`string`): Module path (relative to the config file) exporting `definePresenter(...)`. Default: the provider's built-in presenter.
- `provider` (`ChannelProvider`): Which provider this channel connects to.

Source: [src/channels/config/types.ts:100](https://github.com/Tahul/zidane/blob/main/src/channels/config/types.ts#L100)

### `ChannelLogger`

Interface.

Where a channel writes what it does. Never given message text from strangers.

```ts
interface ChannelLogger
```

**Properties**

- `debug` (`(message: string, data?: Record<string, unknown>) => void`): Writes a debug line.
- `error` (`(message: string, data?: Record<string, unknown>) => void`): Writes an error.
- `info` (`(message: string, data?: Record<string, unknown>) => void`): Writes an info line.
- `warn` (`(message: string, data?: Record<string, unknown>) => void`): Writes a warning.

Source: [src/channels/provider.ts:77](https://github.com/Tahul/zidane/blob/main/src/channels/provider.ts#L77)

### `ChannelProvider`

Interface.

A channel provider.

```ts
interface ChannelProvider<C extends ChannelConfig = ChannelConfig, Ref = JsonValue, Client = unknown>
```

**Type parameters**

- `C` (`extends ChannelConfig`, default `ChannelConfig`)
- `Ref` (default `JsonValue`)
- `Client` (default `unknown`)

**Properties**

- `name` (`'github' | 'slack'`): The provider name channels configure (`provider: 'slack'`).
- `parse` (`(config: ChannelConfig) => C`): Narrow the channel's config section, already validated by
  `src/channels/config`. Throw a [`ChannelProviderError`](https://zidane.si/docs/reference/channels.md#ChannelProviderError) ('config') to refuse it.
- `presenter` (`PresenterDefinition<Ref, Client> | Presenter<Ref>`): The presenter used when the channel names none.
- `start` (`(ctx: ProviderContext<C>) => Promise<ProviderInstance<Client>>`): Open the transports. Throw a [`ChannelProviderError`](https://zidane.si/docs/reference/channels.md#ChannelProviderError) to classify a failure.

Source: [src/channels/provider.ts:183](https://github.com/Tahul/zidane/blob/main/src/channels/provider.ts#L183)

### `ChannelRoute`

Interface.

An HTTP route a provider serves (a webhook). The host mounts it at
`/channels/<channelName><path>`.

```ts
interface ChannelRoute
```

**Properties**

- `handler` (`(request: Request) => Promise<Response>`): A fetch handler: the raw request in, the response out.
- `method` (`string`): HTTP method, upper case (`POST`).
- `path` (`` `/${string}` ``): Suffix under the channel's prefix, starting with `/` (`/events`).

Source: [src/channels/provider.ts:20](https://github.com/Tahul/zidane/blob/main/src/channels/provider.ts#L20)

### `ChannelsCheck`

Interface.

The outcome of [`checkChannels`](https://zidane.si/docs/reference/channels.md#checkChannels).

```ts
interface ChannelsCheck
```

**Properties**

- `errors` (`string[]`): Why the config does not load, each naming its key path.
- `file?` (`ChannelsConfigFile`): The config file, when one is there.
- `ok` (`boolean`): `false` when the config does not load.
- `state` (`'off' | 'absent' | 'on'`): 'absent': no config file. 'off': the kill switch is set. 'on': a config file is there (`ok` says whether it loads).
- `summary` (`ChannelSummary[]`): The channels the config sets up, when it loads.
- `warnings` (`ChannelsWarning[]`): Risky but legal combinations, and a file others can read that holds inline secrets.

Source: [src/channels/config/check.ts:46](https://github.com/Tahul/zidane/blob/main/src/channels/config/check.ts#L46)

### `ChannelsConfig`

Interface.

The whole file.

```ts
interface ChannelsConfig
```

**Properties**

- `channels` (`Record<string, ChannelConfig>`): Channels by name (letters, digits, '-' and '\_'; used in webhook URLs and default session titles).
- `defaults?` (`{ access?: RoleAccess; limits?: Limits }`): The outermost layer: access and limits every channel starts from.

Source: [src/channels/config/types.ts:155](https://github.com/Tahul/zidane/blob/main/src/channels/config/types.ts#L155)

### `ChannelsConfigChange`

Interface.

A changed (written, created or deleted) config file.

```ts
interface ChannelsConfigChange
```

**Properties**

- `kind` (`'json' | 'ts'`): Which config file changed.
- `path` (`string`): The file's full path.
- `reload` (`'manual' | 'live'`): 'live': reload it now. 'manual': tell the user to reload.

Source: [src/channels/config/watch.ts:13](https://github.com/Tahul/zidane/blob/main/src/channels/config/watch.ts#L13)

### `ChannelsConfigFile`

Interface.

The config file in use.

```ts
interface ChannelsConfigFile
```

**Properties**

- `kind` (`'json' | 'ts'`): `channels.json` or `channels.config.ts`.
- `path` (`string`): The file's full path.

Source: [src/channels/config/load.ts:37](https://github.com/Tahul/zidane/blob/main/src/channels/config/load.ts#L37)

### `ChannelsConfigWatcher`

Interface.

Stops watching.

```ts
interface ChannelsConfigWatcher
```

**Properties**

- `close` (`() => void`): Stops watching and drops pending reports.

Source: [src/channels/config/watch.ts:23](https://github.com/Tahul/zidane/blob/main/src/channels/config/watch.ts#L23)

### `ChannelsHost`

Interface.

Channels hosted by a zidane-server or the laptop daemon.

```ts
interface ChannelsHost
```

**Properties**

- `close` (`() => Promise<void>`): Stop watching, close the runner, then its client. Idempotent.
- `ready` (`() => Promise<void>`): Resolves once every channel of the config in use made its first
  connection attempt (connected, or failed and retrying): the host resumes
  the runs a dead process left after it, so their events reach their
  conversations. At once when no config loaded. Never rejects.
- `reload` (`() => Promise<ChannelsReloadResult>`): Read the config again (JSON or TS) and apply it.
- `route` (`(request: Request) => Promise<Response> | undefined`): A provider's answer to a request under [`CHANNELS_ROUTE_PREFIX`](https://zidane.si/docs/reference/channels.md#CHANNELS_ROUTE_PREFIX), or `undefined` when no route takes it. Never rejects.
- `status` (`() => ChannelsHostStatus`): What the host knows about its channels now.

Source: [src/channels/host.ts:118](https://github.com/Tahul/zidane/blob/main/src/channels/host.ts#L118)

### `ChannelsHostStatus`

Interface.

What the host knows about its channels.

```ts
interface ChannelsHostStatus
```

**Properties**

- `channels` (`ChannelStatus[]`): Each channel's state.
- `errors` (`string[]`): The last (re)load's problems; with 'running', the config still in use is the previous one.
- `file?` (`string`): The config file's path, when one loaded.
- `state` (`'error' | 'off' | 'running'`): 'running': a config loaded and its channels run. 'error': none loaded yet (`errors` says why). 'off': the config file went away.

Source: [src/channels/host.ts:102](https://github.com/Tahul/zidane/blob/main/src/channels/host.ts#L102)

### `ChannelsReloadResult`

Interface.

The outcome of a (re)load.

```ts
interface ChannelsReloadResult
```

**Properties**

- `channels` (`string[]`): The configured channels, when it loaded.
- `errors` (`string[]`): Every problem, each naming its key path. A failed reload keeps what ran before.
- `file?` (`string`): The config file in use, when one loaded.
- `ok` (`boolean`): The config loaded and applies now.
- `trigger` (`ChannelsReloadTrigger`): What started the (re)load.

Source: [src/channels/host.ts:47](https://github.com/Tahul/zidane/blob/main/src/channels/host.ts#L47)

### `ChannelsRunner`

Interface.

A running channels runner.

```ts
interface ChannelsRunner
```

**Properties**

- `close` (`() => Promise<void>`): Stop every channel and close the intake store, waiting at most `CLOSE_WAIT_MS` for presenter calls. Idempotent.
- `ready` (`() => Promise<void>`): Resolves once each channel of the first config made its first start attempt (connected, or failed). Never rejects.
- `reload` (`(config: LoadedChannels) => Promise<void>`): Apply a new config: access and bindings for new messages; channels added, removed, disabled or changed start, stop or restart.
- `routes` (`() => Record<string, ChannelRoute[]>`): The webhook routes of each started channel, to mount at `/channels/<name><path>`.
- `status` (`() => ChannelStatus[]`): Each channel's state now.

Source: [src/channels/runner/index.ts:94](https://github.com/Tahul/zidane/blob/main/src/channels/runner/index.ts#L94)

### `ChannelStatus`

Interface.

One channel's state.

```ts
interface ChannelStatus
```

**Properties**

- `activeRuns` (`number`): Runs of its sessions now.
- `detail?` (`string`): Why it is in that state (an error, a reconnect), when known.
- `held` (`number`): Messages it holds back (limits).
- `name` (`string`): The channel's name.
- `provider` (`string`): The channel's provider.
- `since` (`number`): When it entered that state, in milliseconds since the epoch.
- `state` (`'connected' | 'failed' | 'stopped' | 'starting' | 'degraded'`): Its integration state.

Source: [src/channels/runner/index.ts:72](https://github.com/Tahul/zidane/blob/main/src/channels/runner/index.ts#L72)

### `ChannelSummary`

Interface.

One channel, as `channels check` shows it.

```ts
interface ChannelSummary
```

**Properties**

- `bindings` (`BindingSummary[]`): Its bindings, in config order.
- `enabled` (`boolean`): `false` when the config sets `enabled: false`.
- `members` (`number`): Channel-wide members (bindings may add their own).
- `name` (`string`): The channel's name.
- `owners` (`number`): How many owners it has.
- `provider` (`'github' | 'slack'`): The channel's provider.

Source: [src/channels/config/check.ts:30](https://github.com/Tahul/zidane/blob/main/src/channels/config/check.ts#L30)

### `ChannelsWarning`

Interface.

One finding, at a key path.

```ts
interface ChannelsWarning
```

**Properties**

- `level` (`'info' | 'warning'`): 'warning': worth fixing. 'info': worth knowing.
- `message` (`string`): What is risky, and how to fix it.
- `path` (`string`): The key path it is about (`channels.<name>.bindings[0]`).

Source: [src/channels/config/warnings.ts:9](https://github.com/Tahul/zidane/blob/main/src/channels/config/warnings.ts#L9)

### `DeliveryView`

Interface.

What became of one message. 'queued' also covers a message the runner
holds back (a limit); 'context' a message kept as context only.

```ts
interface DeliveryView
```

**Properties**

- `deliveryId` (`string`): The provider's delivery id of the message.
- `heldFor?` (`'busy' | 'concurrency' | 'hourly'`): Why it waits, when the runner holds it: 'concurrency', 'hourly', or 'busy' (a live run while queueing is off).
- `messageRef?` (`JsonValue`): The provider's data about the message (`InboundMessage.messageRef`).
- `state` (`'context' | DeliveryState`): The message's delivery state, or 'context' when it is kept as context only.

Source: [src/channels/presenter.ts:27](https://github.com/Tahul/zidane/blob/main/src/channels/presenter.ts#L27)

### `EffectiveAccess`

Interface.

A level with every rule spelled out.

```ts
interface EffectiveAccess
```

**Properties**

- `agent?` (`string`): The agent profile. Absent: the host's default.
- `approvals?` (`ChannelApprovals`): Absent: the host's approval mode.
- `approvalTimeout?` (`number | 'never'`): Minutes; absent or 'never': wait until answered.
- `budget?` (`{ minutes?: number; usd?: number }`): Each run's limits: cost in US dollars, time in minutes.
- `level` (`AccessLevel`): The level the rules start from.
- `readDeny` (`false | 'host-secrets'`): 'host-secrets': the host's secret files are hidden from the agent. `false`: readable.
- `toolset?` (`'host' | 'profile-only'`): Absent or 'host': the host's tools.

Source: [src/channels/config/access.ts:17](https://github.com/Tahul/zidane/blob/main/src/channels/config/access.ts#L17)

### `GithubChannel`

Interface.

A GitHub App (server only).

```ts
interface GithubChannel extends ChannelCommon<GithubMatch>
```

**Properties**

- `access?` (`RoleAccess`, from `ChannelCommon`): Access for this channel, over the defaults.
- `appId` (`number`): The App's numeric id.
- `bindings` (`Binding<GithubMatch>[]`, from `ChannelCommon`): The conversations this channel serves.
- `botLogin?` (`string`): The App's bot login (`name[bot]`), used to spot mentions and its own comments.
- `enabled?` (`boolean`, from `ChannelCommon`): `false` keeps the channel configured but off. Default true.
- `installationId?` (`number`): The installation to act as. Default: the one each webhook delivery names.
- `limits?` (`Limits`, from `ChannelCommon`): Throttles, over the defaults.
- `members?` (`string[]`, from `ChannelCommon`): Provider user ids who may talk to the agent with member access.
- `owners` (`string[]`, from `ChannelCommon`): Provider user ids (Slack U…, GitHub logins) with owner rights: approvals, commands, steering.
- `presenter?` (`string`, from `ChannelCommon`): Module path (relative to the config file) exporting `definePresenter(...)`. Default: the provider's built-in presenter.
- `privateKey` (`Secret`): The App's private key (PEM).
- `provider` (`'github'`): Which provider this channel connects to.
- `webhookSecret` (`Secret`): Verifies webhook deliveries (X-Hub-Signature-256).

Source: [src/channels/config/types.ts:137](https://github.com/Tahul/zidane/blob/main/src/channels/config/types.ts#L137)

### `GithubClient`

Interface.

The GitHub client a channel's presenter gets (`PresenterContext.client`).

```ts
interface GithubClient
```

**Properties**

- `addReaction` (`(ref: GithubRef, comment: GithubMessageRef, content: GithubReaction) => Promise<void>`): Adds a reaction to an issue or review comment.
- `appSlug` (`string | undefined`, readonly): The App's slug, known once the channel started (`GET /app`).
- `botLogin` (`string | undefined`, readonly): The bot's login (`<slug>[bot]`, or the config's `botLogin`).
- `createComment` (`(ref: GithubRef, body: string) => Promise<{ htmlUrl?: string; id: number }>`): Posts a comment on the issue or pull request. Resolves its id and page URL.
- `installationFor` (`(ref: GithubRef) => number`): The installation to act as for a conversation.
- `installationToken` (`(installationId: number) => Promise<string>`): An installation token (cached). For git over HTTPS; never hand it to the agent.
- `loadApp` (`() => Promise<{ botLogin: string; slug: string }>`): `GET /app`: checks the key and learns the slug and bot login.
- `openOrUpdatePull` (`(ref: GithubRef, args: { base: string; body: string; head: string; title: string }) => Promise<GithubPull>`): Opens a pull request from `head`, or updates the body of the open one.
- `request` (`<T = unknown>(method: string, path: string, options: { auth: GithubAuth; body?: unknown }) => Promise<T>`): Any REST call. Resolves the JSON answer (`undefined` for 204).
- `updateComment` (`(ref: GithubRef, commentId: number, body: string) => Promise<void>`): Replaces the body of a comment.

Source: [src/channels/providers/github/api.ts:78](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/api.ts#L78)

### `GithubClientOptions`

Interface.

Options of [`createGithubClient`](https://zidane.si/docs/reference/channels.md#createGithubClient).

```ts
interface GithubClientOptions
```

**Properties**

- `apiBase?` (`string`): Default [`GITHUB_API_BASE`](https://zidane.si/docs/reference/channels.md#GITHUB_API_BASE).
- `appId` (`number`): The App's id, the issuer of its JWTs.
- `botLogin?` (`string`): The config's bot login; else learned from `GET /app`.
- `fetch?` (`typeof fetch`): The `fetch` used for every call. Default the global `fetch`.
- `installationId?` (`number`): The config's installation; else each conversation's.
- `log?` (`ChannelLogger`): Where rate-limit waits are logged.
- `maxRetries?` (`number`): Retries of a rate-limited call. Default 3.
- `privateKey` (`string`): PEM text (PKCS#1 or PKCS#8).
- `requestTimeoutMs?` (`number`): A call's deadline. Default 30 s.
- `signal?` (`AbortSignal`): The channel's stop signal: requests and rate-limit waits end when it aborts.
- `timers?` (`RunnerTimers`): Clock and timers of rate-limit waits and token expiry. Default: real time.

Source: [src/channels/providers/github/api.ts:106](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/api.ts#L106)

### `GithubMatch`

Interface.

A GitHub repository, as `owner/name`.

```ts
interface GithubMatch
```

**Properties**

- `repo` (`string`): `owner/name`.

Source: [src/channels/config/types.ts:78](https://github.com/Tahul/zidane/blob/main/src/channels/config/types.ts#L78)

### `GithubMessageRef`

Interface.

One comment: what reactions go on.

```ts
interface GithubMessageRef
```

**Properties**

- `association?` (`string`): GitHub's `author_association` of the commenter (OWNER, MEMBER, CONTRIBUTOR, NONE…), for custom presenters; roles come from the config only.
- `commentId` (`number`): The comment's id.
- `kind` (`'issue' | 'review'`): 'issue': an issue or PR conversation comment. 'review': a PR review (diff) comment.

Source: [src/channels/providers/github/types.ts:25](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/types.ts#L25)

### `GithubProviderOptions`

Interface.

Test seams of [`createGithubProvider`](https://zidane.si/docs/reference/channels.md#createGithubProvider). Not user config: a channel
always talks to GitHub itself.

```ts
interface GithubProviderOptions
```

**Properties**

- `allowProtocols?` (`readonly string[]`): Transports git may push over besides HTTPS (tests: `['file']` for a local bare remote).
- `apiBase?` (`string`): REST API base. Default `https://api.github.com`.
- `fetch?` (`typeof fetch`): The `fetch` the REST client uses. Default the global `fetch`.
- `maxRetries?` (`number`): Rate-limit retries per call. Default 3.
- `remoteUrl?` (`(owner: string, repo: string) => string`): Where branches are pushed. Default `https://github.com/<owner>/<repo>.git`.
- `spawn?` (`SpawnLike`): Runs git (`node:child_process` spawn).
- `timers?` (`RunnerTimers`): Clock and timers of retries, token expiry and the edit throttle.

Source: [src/channels/providers/github/index.ts:39](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/index.ts#L39)

### `GithubPull`

Interface.

A pull request opened or updated.

```ts
interface GithubPull
```

**Properties**

- `created` (`boolean`): `true` when the call opened it, `false` when it updated the open one.
- `htmlUrl` (`string`): The pull request's page on GitHub.
- `number` (`number`): The pull request number.

Source: [src/channels/providers/github/api.ts:61](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/api.ts#L61)

### `GithubRef`

Interface.

Where a conversation lives: the issue or pull request the presenter answers on.

```ts
interface GithubRef
```

**Properties**

- `defaultBranch` (`string`): The repository's default branch: the base of the pull request a run opens.
- `installationId?` (`number`): The App installation to act as: the config's, else the delivery's.
- `isPullRequest` (`boolean`): The conversation is a pull request, not an issue.
- `number` (`number`): The issue or pull request number.
- `owner` (`string`): The repository's owner login.
- `repo` (`string`): The repository's name.
- `title` (`string`): The issue or pull request title.

Source: [src/channels/providers/github/types.ts:7](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/types.ts#L7)

### `HostChannelsOptions`

Interface.

Options of [`hostChannels`](https://zidane.si/docs/reference/channels.md#hostChannels).

```ts
interface HostChannelsOptions
```

**Properties**

- `audit?` (`ChannelAuditSink`): The runner's audit records. Default: the log.
- `backoff?` (`BackoffOptions`): The runner's retry delays (tests).
- `connect` (`() => Promise<IpcClient>`): Opens the runner's client (scope `approve`). Called once, when a config first loads.
- `dataDir` (`string`): The host's storage dir, where the config lives.
- `env` (`Record<string, string | undefined>`): The environment as it was before channels started: `{ env }` secrets
  are read from it on every load (each load unsets them from
  `process.env` as soon as the file parses, so a reload could not read
  them there).
- `flavor` (`ChannelsHostFlavor`): Which host runs the channels. The daemon refuses webhooks and members.
- `log` (`ChannelLogger`): Where the host and the runner write what they do.
- `onReload?` (`(result: ChannelsReloadResult) => void`): Called after every (re)load, failed or not.
- `providers?` (`Record<string, ChannelProvider<any, any, any>>`): Providers by name. Default [`BUILTIN_CHANNEL_PROVIDERS`](https://zidane.si/docs/reference/channels.md#BUILTIN_CHANNEL_PROVIDERS).
- `timers?` (`RunnerTimers`): The runner's clock and timers (tests).
- `watch?` (`boolean | { debounceMs?: number }`): Watch the data dir for config changes. Default on (200 ms debounce).
- `workspaceRoots?` (`string[]`): Binding folders must be inside one of these.

Source: [src/channels/host.ts:65](https://github.com/Tahul/zidane/blob/main/src/channels/host.ts#L65)

### `InboundMessage`

Interface.

One message a provider received.

```ts
interface InboundMessage
```

**Properties**

- `channel` (`string`): The channel's name (its key in the config): the provider's `ctx.name`.
- `conversation` (`{ key: string; ref: JsonValue; title?: string }`): The conversation (thread, issue) the message belongs to: one session per conversation.
- `deliveryId` (`string`): The provider's id for this delivery, the same on a redelivery (Slack event id, X-GitHub-Delivery). Edits and deletes carry the original message's.
- `files?` (`PromptAttachment[]`): Files attached to the message, as prompt attachments.
- `fromThreadStarter` (`boolean`): The sender started the conversation (the thread's first message, the issue's author).
- `kind?` (`'stop' | 'edit' | 'delete' | 'message'`): 'edit' / 'delete': a change to the message `deliveryId` names. 'stop': a stop button click (text `/zidane stop`), honored from an owner only. Default 'message'.
- `match` (`{ channel?: string; dm?: boolean; repo?: string }`): What bindings match on: a Slack channel id or the DMs, a GitHub repo.
- `mentionsBot` (`boolean`): The message addresses the bot (a mention, a DM).
- `messageRef?` (`JsonValue`): Provider data about this one message (its ts, comment id), handed back with its delivery states.
- `sender` (`{ bot?: boolean; id: string; name?: string }`): Who sent it.
- `text` (`string`): The message text, mentions already turned into names.

Source: [src/channels/provider.ts:34](https://github.com/Tahul/zidane/blob/main/src/channels/provider.ts#L34)

### `InteractionView`

Interface.

A question or plan waiting for an answer.

```ts
interface InteractionView
```

**Properties**

- `allowed` (`string[]`): Provider ids allowed to answer: the owners and the conversation's starter.
- `request` (`InteractionRequest`): What the agent asks.
- `requestId` (`string`): The question's or plan's id.

Source: [src/channels/presenter.ts:99](https://github.com/Tahul/zidane/blob/main/src/channels/presenter.ts#L99)

### `JsonErrorPosition`

Interface.

A 1-based line and column, and what was wrong there.

```ts
interface JsonErrorPosition
```

**Properties**

- `column` (`number`): The column, from 1.
- `line` (`number`): The line, from 1.
- `message` (`string`): What was wrong (`unexpected end of file`).

Source: [src/channels/config/json-position.ts:8](https://github.com/Tahul/zidane/blob/main/src/channels/config/json-position.ts#L8)

### `Limits`

Interface.

Throttles per channel. Owners are never throttled.

```ts
interface Limits
```

**Properties**

- `concurrentRuns?` (`number`): Runs of this channel's sessions at once. Default 2.
- `runsPerMemberPerHour?` (`number`): Runs one member may start per hour. Default 10.

Source: [src/channels/config/types.ts:64](https://github.com/Tahul/zidane/blob/main/src/channels/config/types.ts#L64)

### `LoadedChannels`

Interface.

A loaded config.

```ts
interface LoadedChannels
```

**Properties**

- `config` (`ChannelsConfig`): Validated, its secrets read.
- `envNames` (`string[]`): Environment variables secrets were read from (the runner unsets them).
- `file` (`ChannelsConfigFile`): The file it loaded from.
- `inlineSecrets` (`boolean`): Some secret is written in the file itself.
- `warnings` (`ChannelsWarning[]`): Risky combinations (`./warnings`).

Source: [src/channels/config/load.ts:45](https://github.com/Tahul/zidane/blob/main/src/channels/config/load.ts#L45)

### `LoadOptions`

Interface.

Options of [`loadChannelsConfig`](https://zidane.si/docs/reference/channels.md#loadChannelsConfig).

```ts
interface LoadOptions
```

**Properties**

- `env?` (`Env`): Variables for the kill switch and `{ env }` secrets. Default `process.env`.
- `onSecretEnv?` (`(names: string[]) => void`): Called with the `{ env }` names of the secrets as soon as the file parses, before validation (the host unsets them whatever happens next).
- `workspaceRoots?` (`string[]`): When given, binding folders must be inside one of these.

Source: [src/channels/config/load.ts:59](https://github.com/Tahul/zidane/blob/main/src/channels/config/load.ts#L59)

### `NoticeView`

Interface.

Something the runner tells the conversation (a command's result, a refusal).

```ts
interface NoticeView
```

**Properties**

- `level` (`'error' | 'info' | 'warn'`): How serious it is.
- `text` (`string`): The text to show.

Source: [src/channels/presenter.ts:126](https://github.com/Tahul/zidane/blob/main/src/channels/presenter.ts#L126)

### `Presenter`

Interface.

Hooks that map host activity to provider calls. `Ref` is the
conversation's `ref` from the provider's inbound messages.

```ts
interface Presenter<Ref = JsonValue>
```

**Type parameters**

- `Ref` (default `JsonValue`)

**Properties**

- `approval?` (`(ref: Ref, view: ApprovalView, respond: (decision: ApprovalDecision, by: string) => Promise<RespondResult>) => Promise<void>`): `respond(decision, clickerId)`: honored only from an owner.
- `delivery?` (`(ref: Ref, view: DeliveryView) => Promise<void>`): A message's delivery state changed.
- `dispose?` (`() => void | Promise<void>`): The channel stopped (removed, disabled, restarted, reloaded with new
  provider settings, or the runner closed): clear timers and stop using
  the provider client. A presenter built by [`definePresenter`](https://zidane.si/docs/reference/channels.md#definePresenter) from a
  function is built again on the next start; a plain hooks object is reused.
- `interaction?` (`(ref: Ref, view: InteractionView, respond: (response: InteractionResponse, by: string) => Promise<RespondResult>) => Promise<void>`): `respond(response, clickerId)`: honored only from an owner or the conversation's starter.
- `notice?` (`(ref: Ref, view: NoticeView) => Promise<void>`): A notice from the runner.
- `run?` (`(ref: Ref, event: RunView) => Promise<void>`): One step of a run in the conversation.
- `settled?` (`(ref: Ref, view: SettledView) => Promise<void>`): A request shown by `approval` / `interaction` no longer waits: drop its buttons and handlers.

Source: [src/channels/presenter.ts:151](https://github.com/Tahul/zidane/blob/main/src/channels/presenter.ts#L151)

### `PresenterContext`

Interface.

What a presenter is built with when its channel starts.

```ts
interface PresenterContext<Client = unknown>
```

**Type parameters**

- `Client` (default `unknown`)

**Properties**

- `channel` (`string`): The channel's name.
- `client` (`Client`): The provider's API client (`ProviderInstance.client`).
- `log` (`ChannelLogger`): Where the presenter writes what it does.
- `store?` (`PresenterStore`): Values kept across restarts of the host, per channel (the runner's
  intake store), such as the message a run is shown in, so a resumed run
  keeps editing it. A value not set for 7 days is forgotten. Absent when
  the presenter is built outside a runner.

Source: [src/channels/presenter.ts:178](https://github.com/Tahul/zidane/blob/main/src/channels/presenter.ts#L178)

### `PresenterDefinition`

Interface.

Builds a channel's presenter once its provider has started.

```ts
interface PresenterDefinition<Ref = JsonValue, Client = unknown>
```

**Type parameters**

- `Ref` (default `JsonValue`)
- `Client` (default `unknown`)

**Properties**

- `create` (`(ctx: PresenterContext<Client>) => Presenter<Ref>`): Builds the hooks for one channel.
- `kind` (`'presenter'`, readonly): Always 'presenter': marks a value from [`definePresenter`](https://zidane.si/docs/reference/channels.md#definePresenter).

Source: [src/channels/presenter.ts:211](https://github.com/Tahul/zidane/blob/main/src/channels/presenter.ts#L211)

### `PresenterStore`

Interface.

A channel presenter's persistent values (`PresenterContext.store`).

```ts
interface PresenterStore
```

**Properties**

- `get` (`(key: string) => JsonValue | undefined`): The value stored under `key`, or `undefined`.
- `set` (`(key: string, value: JsonValue | undefined) => void`): `undefined` forgets the key.

Source: [src/channels/presenter.ts:199](https://github.com/Tahul/zidane/blob/main/src/channels/presenter.ts#L199)

### `ProviderContext`

Interface.

What a provider gets when its channel starts.

```ts
interface ProviderContext<C extends ChannelConfig = ChannelConfig>
```

**Type parameters**

- `C` (`extends ChannelConfig`, default `ChannelConfig`)

**Properties**

- `audit` (`ChannelAuditSink`): Receives the channel's audit records.
- `config` (`C`): The channel's config section, parsed by the provider's `parse`, secrets resolved.
- `emit` (`(inbound: InboundMessage) => Promise<void>`): Hand a received message to the runner. Resolves once it is recorded (deduped); never rejects.
- `fail` (`(error: unknown) => void`): Report a failure after start: the runner stops the channel and, unless it is 'auth' / 'config', starts it again with backoff.
- `log` (`ChannelLogger`): Where the channel writes what it does.
- `name` (`string`): The channel's name (its key in the config).
- `secrets` (`Readonly<Record<string, string>>`): The channel's secrets by config key (`botToken`, `webhookSecret`…), read from the file or the environment.
- `signal` (`AbortSignal`): Aborted when the channel stops: close sockets, stop polling.
- `status` (`(state: 'connected' | 'degraded', detail?: string) => void`): Report the transport's health after start: 'degraded' while reconnecting, 'connected' once back.

Source: [src/channels/provider.ts:143](https://github.com/Tahul/zidane/blob/main/src/channels/provider.ts#L143)

### `ProviderInstance`

Interface.

A started channel.

```ts
interface ProviderInstance<Client = unknown>
```

**Type parameters**

- `Client` (default `unknown`)

**Properties**

- `client?` (`Client`): The provider's API client, handed to presenters so custom ones can call the provider.
- `routes?` (`ChannelRoute[]`): Webhook routes to mount (`/channels/<name><path>`).
- `stop` (`() => void | Promise<void>`): Close the transports. Called once, when the channel stops or restarts.

Source: [src/channels/provider.ts:169](https://github.com/Tahul/zidane/blob/main/src/channels/provider.ts#L169)

### `ResolvedAccess`

Interface.

What a sender's message runs under.

```ts
interface ResolvedAccess
```

**Properties**

- `level` (`AccessLevel`): The level the sender's messages run under.
- `policy` (`SessionPolicy`): The session's policy (`sessions.create` / `sessions.setPolicy`).
- `role` (`ChannelRole`): The sender's role in the channel.
- `session` (`{ agent?: string; environment: 'worktree' | 'local' }`): Session options: the agent profile (absent: the host's default) and the environment.

Source: [src/channels/config/access.ts:35](https://github.com/Tahul/zidane/blob/main/src/channels/config/access.ts#L35)

### `ResolvedSecrets`

Interface.

The config with every secret read, and what it took.

```ts
interface ResolvedSecrets
```

**Properties**

- `config` (`ChannelsConfig`): A copy of the config whose secrets are all strings.
- `envNames` (`string[]`): Environment variables secrets were read from.
- `errors` (`string[]`): Unset variables, each naming its key path.
- `inlineSecrets` (`boolean`): Some secret is written in the file itself.

Source: [src/channels/config/secrets.ts:11](https://github.com/Tahul/zidane/blob/main/src/channels/config/secrets.ts#L11)

### `RespondResult`

Interface.

The outcome of a click: `ok: false` when the clicker may not answer, or the request is gone.

```ts
interface RespondResult
```

**Properties**

- `ok` (`boolean`): The answer was taken.
- `reason?` (`string`): Why it was not, when `ok` is false.

Source: [src/channels/presenter.ts:138](https://github.com/Tahul/zidane/blob/main/src/channels/presenter.ts#L138)

### `RoleAccess`

Interface.

Access per role at one layer (defaults, channel or binding).

```ts
interface RoleAccess
```

**Properties**

- `member?` (`Access`): Access for its members. Required at some layer once a channel or binding has members.
- `owner?` (`Access`): Access for the channel's owners. Default 'full'.

Source: [src/channels/config/types.ts:56](https://github.com/Tahul/zidane/blob/main/src/channels/config/types.ts#L56)

### `RunChannelsOptions`

Interface.

Options of [`runChannels`](https://zidane.si/docs/reference/channels.md#runChannels).

```ts
interface RunChannelsOptions
```

**Properties**

- `audit?` (`ChannelAuditSink`): Where audit records go. Default: the log.
- `backoff?` (`BackoffOptions`): Retry delays of failing providers. Default 1 s doubling to 60 s.
- `client` (`IpcClient`): A connected client, scoped `approve` (it answers approvals for owners).
- `config` (`LoadedChannels`): The loaded config (`loadChannelsConfig`).
- `dataDir` (`string`): The host's data dir: the intake store lives in `<dataDir>/channels/`.
- `log` (`ChannelLogger`): Where the runner writes what it does.
- `providers` (`Record<string, ChannelProvider<any, any, any>>`): Providers by name (`slack`, `github`).
- `timers?` (`RunnerTimers`): Clock and timers (tests drive them). Default: real time.

Source: [src/channels/runner/index.ts:48](https://github.com/Tahul/zidane/blob/main/src/channels/runner/index.ts#L48)

### `RunnerTimers`

Interface.

The clock and timers the runner uses (backoff, hourly limits).

```ts
interface RunnerTimers
```

**Properties**

- `clearTimeout` (`(handle: unknown) => void`): Cancels a timer `setTimeout` started.
- `now` (`() => number`): The time, in milliseconds since the epoch.
- `setTimeout` (`(fn: () => void, ms: number) => unknown`): Calls `fn` after `ms`. Returns a handle for `clearTimeout`.

Source: [src/channels/runner/state.ts:16](https://github.com/Tahul/zidane/blob/main/src/channels/runner/state.ts#L16)

### `RunSummary`

Interface.

What a run cost, when known.

```ts
interface RunSummary
```

**Properties**

- `costUsd?` (`number`): What the run cost, in US dollars.
- `durationMs?` (`number`): How long the run took, in milliseconds.
- `model?` (`string`): The model's id.
- `tokensIn?` (`number`): Input tokens.
- `tokensOut?` (`number`): Output tokens.

Source: [src/channels/presenter.ts:43](https://github.com/Tahul/zidane/blob/main/src/channels/presenter.ts#L43)

### `SettledView`

Interface.

An approval or question that stopped waiting without this presenter's
`respond` (answered in another window, timed out, its run ended).

```ts
interface SettledView
```

**Properties**

- `kind` (`'interaction' | 'approval'`): Which hook showed it.
- `requestId` (`string`): The id the request had in `approval` / `interaction`.

Source: [src/channels/presenter.ts:114](https://github.com/Tahul/zidane/blob/main/src/channels/presenter.ts#L114)

### `SlackChannel`

Interface.

A Slack workspace app.

```ts
interface SlackChannel extends ChannelCommon<SlackMatch>
```

**Properties**

- `access?` (`RoleAccess`, from `ChannelCommon`): Access for this channel, over the defaults.
- `appToken?` (`Secret`): The app-level token (xapp-…) Socket Mode connects with.
- `bindings` (`Binding<SlackMatch>[]`, from `ChannelCommon`): The conversations this channel serves.
- `botToken` (`Secret`): The bot token (xoxb-…).
- `dm?` (`boolean`): Answer direct messages (bindings with `match: { dm: true }`). Default true.
- `enabled?` (`boolean`, from `ChannelCommon`): `false` keeps the channel configured but off. Default true.
- `limits?` (`Limits`, from `ChannelCommon`): Throttles, over the defaults.
- `members?` (`string[]`, from `ChannelCommon`): Provider user ids who may talk to the agent with member access.
- `owners` (`string[]`, from `ChannelCommon`): Provider user ids (Slack U…, GitHub logins) with owner rights: approvals, commands, steering.
- `presenter?` (`string`, from `ChannelCommon`): Module path (relative to the config file) exporting `definePresenter(...)`. Default: the provider's built-in presenter.
- `provider` (`'slack'`): Which provider this channel connects to.
- `signingSecret?` (`Secret`): Verifies Events API requests.
- `team` (`string`): The workspace id (T…); events from any other team are refused.
- `transport?` (`'events' | 'socket'`): 'socket' (default): Socket Mode, needs `appToken`. 'events': the Events API webhook, needs `signingSecret`.

Source: [src/channels/config/types.ts:120](https://github.com/Tahul/zidane/blob/main/src/channels/config/types.ts#L120)

### `SlackClient`

Interface.

The Slack client a channel's presenter gets (`PresenterContext.client`),
so a custom presenter can post, react and stream like the built-in one.

```ts
interface SlackClient
```

**Properties**

- `addReaction` (`(channel: string, ts: string, name: string) => Promise<void>`): Adds a reaction; one already there counts as done.
- `appendStream` (`(args: { channel: string; chunks?: SlackChunk[]; markdownText?: string; ts: string }) => Promise<void>`): `chat.appendStream`: adds text or chunks to a streamed reply.
- `authTest` (`() => Promise<{ botId?: string; teamId: string; userId: string }>`): `auth.test`: checks the token and learns the bot's user id.
- `botUserId` (`string | undefined`, readonly): The bot's own user id, known once the channel started (`auth.test`).
- `call` (`<T = Record<string, unknown>>(method: string, args?: Record<string, unknown>, options?: { okErrors?: readonly string[]; token?: string }) => Promise<T & { error?: string; ok: boolean }>`): Any Web API method. Throws [`SlackApiError`](https://zidane.si/docs/reference/channels.md#SlackApiError) unless `ok` (or the error is in `okErrors`).
- `downloadFile` (`(url: string, maxBytes?: number) => Promise<Uint8Array<ArrayBufferLike> | null>`): A `url_private` file's bytes, or `null` when it is larger than `maxBytes`.
- `interactive` (`SlackInteractiveRouter`, readonly): Clicks and modal submissions, routed to the prompt that posted them.
- `openDm` (`(user: string) => Promise<string>`): The DM channel with `user` (cached).
- `openView` (`(triggerId: string, view: Record<string, unknown>) => Promise<void>`): `views.open`: opens a modal for a click's `trigger_id`.
- `postEphemeral` (`(args: { channel: string; text: string; threadTs?: string; user: string }) => Promise<void>`): `chat.postEphemeral`: posts a message only `user` sees.
- `postMessage` (`(args: { blocks?: SlackBlock[]; channel: string; text: string; threadTs?: string }) => Promise<SlackPosted>`): `chat.postMessage`: posts a message, in a thread when `threadTs` is set.
- `removeReaction` (`(channel: string, ts: string, name: string) => Promise<void>`): Removes a reaction; one already gone counts as done.
- `renameSession` (`(args: { channel: string; threadTs: string; title: string }) => Promise<void>`): `agents.sessions.rename`: renames the thread's agent session (title cut to 200 characters).
- `setSessionStatus` (`(args: { channel: string; status: SlackSessionStatus; threadTs: string }) => Promise<void>`): `agents.sessions.setStatus`: sets the status of the thread's agent session.
- `startStream` (`(args: { channel: string; markdownText?: string; recipientTeamId?: string; recipientUserId?: string; threadTs: string }) => Promise<SlackPosted>`): Starts a streamed reply in a thread. In a channel (not a DM) Slack needs the recipient.
- `stopStream` (`(args: { channel: string; markdownText?: string; sessionStatus?: SlackSessionStatus; ts: string }) => Promise<void>`): `chat.stopStream`: ends a streamed reply, with optional last text and session status.
- `team` (`string`, readonly): The workspace id the channel serves.
- `update` (`(args: { blocks?: SlackBlock[]; channel: string; text: string; ts: string }) => Promise<void>`): `chat.update`: replaces a message's text and blocks.
- `userName` (`(user: string) => Promise<string>`): A user's display name (cached); the id when unknown.

Source: [src/channels/providers/slack/api.ts:87](https://github.com/Tahul/zidane/blob/main/src/channels/providers/slack/api.ts#L87)

### `SlackClientOptions`

Interface.

Options of [`createSlackClient`](https://zidane.si/docs/reference/channels.md#createSlackClient).

```ts
interface SlackClientOptions
```

**Properties**

- `apiBase?` (`string`): Default `SLACK_API_BASE`.
- `botToken` (`string`): The bot token (`xoxb-…`) every call and file download uses.
- `fetch?` (`typeof fetch`): The `fetch` used for every call. Default the global `fetch`.
- `fileHosts?` (`readonly string[]`): Hosts files may be downloaded from with the bot token. Default `SLACK_FILE_HOSTS`.
- `log?` (`ChannelLogger`): Where failed clicks are logged.
- `maxRetries?` (`number`): Retries of a rate-limited call. Default 3.
- `requestTimeoutMs?` (`number`): A Web API call's deadline. Default 30 s.
- `signal?` (`AbortSignal`): The channel's stop signal: requests and rate-limit waits end when it aborts.
- `team` (`string`): The workspace id the channel serves (`SlackClient.team`).
- `timers?` (`RunnerTimers`): Clock and timers of rate-limit waits. Default: real time.
- `transferTimeoutMs?` (`number`): A file download's deadline. Default 120 s.

Source: [src/channels/providers/slack/api.ts:133](https://github.com/Tahul/zidane/blob/main/src/channels/providers/slack/api.ts#L133)

### `SlackMessageRef`

Interface.

One Slack message: what reactions go on.

```ts
interface SlackMessageRef
```

**Properties**

- `channel` (`string`): The channel or DM id.
- `ts` (`string`): The message's ts.
- `user?` (`string`): Its author.

Source: [src/channels/providers/slack/types.ts:21](https://github.com/Tahul/zidane/blob/main/src/channels/providers/slack/types.ts#L21)

### `SlackProviderOptions`

Interface.

Test seams of [`createSlackProvider`](https://zidane.si/docs/reference/channels.md#createSlackProvider). Not user config: a channel
always talks to Slack itself.

```ts
interface SlackProviderOptions
```

**Properties**

- `apiBase?` (`string`): Web API base. Default `https://slack.com/api`.
- `backoff?` (`BackoffOptions`): Socket Mode reconnect delays.
- `fetch?` (`typeof fetch`): The `fetch` the Web API client uses. Default the global `fetch`.
- `fileHosts?` (`readonly string[]`): Hosts `url_private` files may come from. Default `files.slack.com`.
- `maxFileBytes?` (`number`): Files larger than this are skipped. Default 10 MB.
- `maxRetries?` (`number`): Rate-limit retries per call. Default 3.
- `socket?` (`{ helloTimeoutMs?: number; idleTimeoutMs?: number }`): Socket Mode: how soon a connection must say hello, and how long it may stay silent.
- `timers?` (`RunnerTimers`): Clock and timers of retries, reconnects, batching and reactions.
- `WebSocket?` (`(url: string | URL, protocols?: string | string[]) => WebSocket`): The Socket Mode `WebSocket` class. Default the global `WebSocket`.

Source: [src/channels/providers/slack/index.ts:34](https://github.com/Tahul/zidane/blob/main/src/channels/providers/slack/index.ts#L34)

### `SlackRef`

Interface.

Where a conversation lives: what the presenter answers into.

```ts
interface SlackRef
```

**Properties**

- `channel` (`string`): The channel or DM id (C…, G…, D…).
- `team` (`string`): The workspace id (T…).
- `threadTs` (`string`): The thread's root message ts.
- `title?` (`string`): The root message's first line, for the session title and approval details.
- `user?` (`string`): Who wrote the thread's root message.

Source: [src/channels/providers/slack/types.ts:7](https://github.com/Tahul/zidane/blob/main/src/channels/providers/slack/types.ts#L7)

### `ValidateOptions`

Interface.

Options of [`validateChannelsConfig`](https://zidane.si/docs/reference/channels.md#validateChannelsConfig).

```ts
interface ValidateOptions
```

**Properties**

- `functions?` (`boolean`): Function access rules are allowed (a `channels.config.ts`). Default false.
- `workspaceRoots?` (`string[]`): When given, every binding folder must be inside one of these.

Source: [src/channels/config/validate.ts:12](https://github.com/Tahul/zidane/blob/main/src/channels/config/validate.ts#L12)

### `WatchOptions`

Interface.

Options of [`watchChannelsConfig`](https://zidane.si/docs/reference/channels.md#watchChannelsConfig).

```ts
interface WatchOptions
```

**Properties**

- `debounceMs?` (`number`): Quiet time after the last event of a burst before it is reported. Default 200 ms.

Source: [src/channels/config/watch.ts:29](https://github.com/Tahul/zidane/blob/main/src/channels/config/watch.ts#L29)

## Types

### `Access`

Type.

A level, a policy, or (TS config only) a function of the sender picking one.

```ts
type Access =
  | AccessLevel
  | AccessPolicy
  | ((ctx: AccessContext) => AccessLevel | AccessPolicy)
```

Source: [src/channels/config/types.ts:53](https://github.com/Tahul/zidane/blob/main/src/channels/config/types.ts#L53)

### `AccessLevel`

Type.

Named access presets; each expands to a session policy and session options (`./access`).

```ts
type AccessLevel = 'full' | 'contained' | 'readonly'
```

Source: [src/channels/config/types.ts:15](https://github.com/Tahul/zidane/blob/main/src/channels/config/types.ts#L15)

### `ChannelApprovals`

Type.

Approval modes a channel session may run under.

```ts
type ChannelApprovals = 'ask' | 'decide' | 'off'
```

Source: [src/channels/config/types.ts:18](https://github.com/Tahul/zidane/blob/main/src/channels/config/types.ts#L18)

### `ChannelAuditSink`

Type.

Receives audit records.

```ts
type ChannelAuditSink = (event: ChannelAuditEvent) => void
```

Source: [src/channels/provider.ts:108](https://github.com/Tahul/zidane/blob/main/src/channels/provider.ts#L108)

### `ChannelConfig`

Type.

One configured channel.

```ts
type ChannelConfig = SlackChannel | GithubChannel
```

Source: [src/channels/config/types.ts:152](https://github.com/Tahul/zidane/blob/main/src/channels/config/types.ts#L152)

### `ChannelFailureKind`

Type.

How a provider classifies a failure: 'auth' and 'config' stop the channel
(its integration shows 'failed'), anything else is retried with backoff.

```ts
type ChannelFailureKind = 'auth' | 'config' | 'transient'
```

Source: [src/channels/provider.ts:116](https://github.com/Tahul/zidane/blob/main/src/channels/provider.ts#L116)

### `ChannelRole`

Type.

Who a provider user is to a channel. Anyone else is a stranger and is ignored.

```ts
type ChannelRole = 'owner' | 'member'
```

Source: [src/channels/config/types.ts:12](https://github.com/Tahul/zidane/blob/main/src/channels/config/types.ts#L12)

### `ChannelsHostFlavor`

Type.

Which host runs the channels. The laptop daemon has no public port and
serves its user only: socket transports, owners only.

```ts
type ChannelsHostFlavor = 'server' | 'daemon'
```

Source: [src/channels/host.ts:33](https://github.com/Tahul/zidane/blob/main/src/channels/host.ts#L33)

### `ChannelsReloadTrigger`

Type.

What started a (re)load.

```ts
type ChannelsReloadTrigger = 'start' | 'watch' | 'manual'
```

Source: [src/channels/host.ts:40](https://github.com/Tahul/zidane/blob/main/src/channels/host.ts#L40)

### `GithubAuth`

Type.

How a call authenticates: as the App (JWT) or as an installation.

```ts
type GithubAuth = { app: true } | { installationId: number }
```

Source: [src/channels/providers/github/api.ts:71](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/api.ts#L71)

### `GithubChannelClient`

Type.

The client a GitHub channel's presenter gets: the REST client and, for
the built-in presenter, the branch publisher.

```ts
type GithubChannelClient = GithubClient & { readonly branches?: BranchPublisher }
```

Source: [src/channels/providers/github/presenter.ts:28](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/presenter.ts#L28)

### `GithubReaction`

Type.

A reaction GitHub accepts.

```ts
type GithubReaction =
  | '+1'
  | '-1'
  | 'laugh'
  | 'confused'
  | 'heart'
  | 'hooray'
  | 'rocket'
  | 'eyes'
```

Source: [src/channels/providers/github/api.ts:58](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/api.ts#L58)

### `PublishResult`

Type.

What publishing did.

```ts
type PublishResult =
  | { kind: 'none' }
  | { created: boolean; kind: 'pull'; url: string }
  | { kind: 'failed'; reason: string }
```

Source: [src/channels/providers/github/pr.ts:62](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/pr.ts#L62)

### `RunView`

Type.

One step of a run.

```ts
type RunView =
  | { kind: 'started'; runId: string }
  | { delta: string; kind: 'text'; runId: string }
  | { callId: string; input?: Record<string, unknown>; kind: 'tool-start'; runId: string; tool: string }
  | { callId: string; kind: 'tool-end'; ok: boolean; runId: string; tool: string }
  | { inProgress: TodoItem | null; kind: 'todos'; runId: string; todos: TodoItem[] }
  | { error?: string; kind: 'ended'; runId: string; status: 'ok' | 'failed' | 'interrupted'; summary: RunSummary }
  | { kind: 'handed-off'; runId: string }
```

Source: [src/channels/presenter.ts:61](https://github.com/Tahul/zidane/blob/main/src/channels/presenter.ts#L61)

### `Secret`

Type.

A secret: inline, or the name of an environment variable holding it.

```ts
type Secret = string | { env: string }
```

Source: [src/channels/config/types.ts:9](https://github.com/Tahul/zidane/blob/main/src/channels/config/types.ts#L9)

### `SlackMatch`

Type.

A Slack conversation: a channel (C…, or G… for private ones) or the bot's DMs.

```ts
type SlackMatch = { channel: string } | { dm: true }
```

Source: [src/channels/config/types.ts:75](https://github.com/Tahul/zidane/blob/main/src/channels/config/types.ts#L75)

### `SpawnLike`

Type.

`node:child_process` `spawn`, or a spy around it (tests).

```ts
type SpawnLike = (command: string, args: readonly string[], options: SpawnOptions) => ChildProcess
```

Source: [src/channels/providers/github/pr.ts:42](https://github.com/Tahul/zidane/blob/main/src/channels/providers/github/pr.ts#L42)

### `ValidationResult`

Type.

The outcome: a typed config, or every problem found.

```ts
type ValidationResult =
  | { config: ChannelsConfig; ok: true }
  | { errors: string[]; ok: false }
```

Source: [src/channels/config/validate.ts:20](https://github.com/Tahul/zidane/blob/main/src/channels/config/validate.ts#L20)
