> ## Documentation Index
> Fetch the complete documentation index at: https://usefused.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# harnest.channels

> Public Python signatures, fields, and methods.

[All Python modules](https://usefused.com/docs/harnest/reference/api/overview.md) · [Import and compatibility guidance](https://usefused.com/docs/harnest/build/python-imports.md)

## Exports

| Name | Kind |
| - | - |
| [`ChannelAdapter`](#channeladapter) | Class |
| [`ChannelAdapterConflictError`](#channeladapterconflicterror) | Class |
| [`ChannelAdapterFactory`](#channeladapterfactory) | Value or type alias |
| [`ChannelAdapterNotFoundError`](#channeladapternotfounderror) | Class |
| [`ChannelBinding`](#channelbinding) | Class |
| [`ChannelError`](#channelerror) | Class |
| [`ChannelEvent`](#channelevent) | Class |
| [`ChannelHTTPInvoker`](#channelhttpinvoker) | Class |
| [`ChannelReply`](#channelreply) | Class |
| [`ChannelStore`](#channelstore) | Class |
| [`ChannelStoreConflictError`](#channelstoreconflicterror) | Class |
| [`ChannelWorker`](#channelworker) | Class |
| [`MemoryChannelStore`](#memorychannelstore) | Class |
| [`create_channel_adapter`](#create_channel_adapter) | Function |
| [`discover_channel_bindings`](#discover_channel_bindings) | Function |
| [`register_channel_adapter`](#register_channel_adapter) | Function |
| [`registered_channel_adapters`](#registered_channel_adapters) | Function |

## ChannelAdapter

Platform-specific transport that normalizes events and sends replies.

Extensions implement this contract without exposing raw provider drivers.
Normalization is synchronous and offline so fixtures can be tested without
live credentials; sending is the only network-owned operation.

```python theme={null}
ChannelAdapter()
```

Fields (`—` means no declared default):

| Field | Type | Default |
| - | - | - |
| `platform` | `str` | `—` |

> [accordion] Example
>
> ```python theme={null}
> from harnest.channels import ChannelAdapter
>
> class MyChannelAdapter(ChannelAdapter):
>     ...
> ```

### ChannelAdapter.start

```python theme={null}
async ChannelAdapter.start() -> None
```

Initialize provider-owned clients before accepting invocations.

> [accordion] Example
>
> ```python theme={null}
> from harnest.channels import ChannelAdapter
>
> adapter: ChannelAdapter
> await adapter.start()
> ```

### ChannelAdapter.normalize\_event

```python theme={null}
ChannelAdapter.normalize_event(raw: Mapping[str, Any]) -> ChannelEvent
```

Parse one provider payload into a ChannelEvent without any I/O.

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `raw` | `Mapping[str, Any]` | Required |
>
> ```python theme={null}
> from harnest.channels import ChannelAdapter
>
> adapter: ChannelAdapter
> event = adapter.normalize_event(raw=...)
> ```

### ChannelAdapter.send\_reply

```python theme={null}
async ChannelAdapter.send_reply(reply: ChannelReply) -> Mapping[str, Any]
```

Send content through the transport and return an opaque receipt.

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `reply` | `ChannelReply` | Required |
>
> ```python theme={null}
> from harnest.channels import ChannelAdapter
>
> adapter: ChannelAdapter
> result = await adapter.send_reply(reply=...)
> ```

### ChannelAdapter.close

```python theme={null}
async ChannelAdapter.close() -> None
```

Release provider-owned clients after invocations have drained.

> [accordion] Example
>
> ```python theme={null}
> from harnest.channels import ChannelAdapter
>
> adapter: ChannelAdapter
> await adapter.close()
> ```

## ChannelAdapterConflictError

Two extensions registered a channel adapter under the same name.

> [accordion] Example
>
> ```python theme={null}
> from harnest.channels import ChannelAdapterConflictError
>
> try:
>     ...
> except ChannelAdapterConflictError as error:
>     ...
> ```

## ChannelAdapterFactory

```python theme={null}
ChannelAdapterFactory = Callable[[Mapping[str, Any]], harnest.channels.ChannelAdapter]
```

> [accordion] Example
>
> ```python theme={null}
> from harnest.channels import ChannelAdapterFactory
> ```

## ChannelAdapterNotFoundError

No extension registered a channel adapter under the requested name.

> [accordion] Example
>
> ```python theme={null}
> from harnest.channels import ChannelAdapterNotFoundError
>
> try:
>     ...
> except ChannelAdapterNotFoundError as error:
>     ...
> ```

## ChannelBinding

Local policy connecting one platform conversation scope to this agent.

`extension` names the registered ChannelAdapter factory that owns the
platform transport (for example a Fused-backed Slack extension, or a
direct-API extension); the binding itself never depends on how that
extension talks to the platform. Empty allow-lists mean nothing is
authorized yet, not that everything is; an adapter must fail closed.

```python theme={null}
ChannelBinding(
    platform: str,
    extension: str,
    allowed_installations: tuple[str, ...] = (),
    allowed_conversations: tuple[str, ...] = (),
    config: Mapping[str, Any] = ...,
) -> None
```

Fields (`—` means no declared default):

| Field | Type | Default |
| - | - | - |
| `platform` | `str` | `—` |
| `extension` | `str` | `—` |
| `allowed_installations` | `tuple[str, ...]` | `()` |
| `allowed_conversations` | `tuple[str, ...]` | `()` |
| `config` | `Mapping[str, Any]` | `dict()` |

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `platform` | `str` | Required |
> | `extension` | `str` | Required |
> | `allowed_installations` | `tuple[str, ...]` | `()` |
> | `allowed_conversations` | `tuple[str, ...]` | `()` |
> | `config` | `Mapping[str, Any]` | `...` |
>
> ```python theme={null}
> from harnest.channels import ChannelBinding
>
> binding = ChannelBinding(platform=..., extension=...)
> ```

## ChannelError

Base class for channel configuration and adapter failures.

> [accordion] Example
>
> ```python theme={null}
> from harnest.channels import ChannelError
>
> try:
>     ...
> except ChannelError as error:
>     ...
> ```

## ChannelEvent

One inbound platform message, normalized by a ChannelAdapter.

`delivery_id` identifies this specific transport delivery and may repeat
across retries; `provider_event_id` is the platform's stable identity for
deduplication. `reply_to` is an opaque, adapter-owned address a later
reply must target and is never interpreted by the store.

```python theme={null}
ChannelEvent(
    platform: str,
    installation_id: str,
    provider_event_id: str,
    kind: str,
    sender_id: str,
    conversation_id: str,
    message_id: str,
    occurred_at: float,
    delivery_id: str = '',
    thread_id: str | None = None,
    content: str = '',
    reply_to: Mapping[str, Any] = ...,
) -> None
```

Fields (`—` means no declared default):

| Field | Type | Default |
| - | - | - |
| `platform` | `str` | `—` |
| `installation_id` | `str` | `—` |
| `provider_event_id` | `str` | `—` |
| `kind` | `str` | `—` |
| `sender_id` | `str` | `—` |
| `conversation_id` | `str` | `—` |
| `message_id` | `str` | `—` |
| `occurred_at` | `float` | `—` |
| `delivery_id` | `str` | `''` |
| `thread_id` | `str \| None` | `None` |
| `content` | `str` | `''` |
| `reply_to` | `Mapping[str, Any]` | `dict()` |

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `platform` | `str` | Required |
> | `installation_id` | `str` | Required |
> | `provider_event_id` | `str` | Required |
> | `kind` | `str` | Required |
> | `sender_id` | `str` | Required |
> | `conversation_id` | `str` | Required |
> | `message_id` | `str` | Required |
> | `occurred_at` | `float` | Required |
> | `delivery_id` | `str` | `''` |
> | `thread_id` | `str \| None` | `None` |
> | `content` | `str` | `''` |
> | `reply_to` | `Mapping[str, Any]` | `...` |
>
> ```python theme={null}
> from harnest.channels import ChannelEvent
>
> event = ChannelEvent(
>     platform=...,
>     installation_id=...,
>     provider_event_id=...,
>     kind=...,
>     sender_id=...,
>     conversation_id=...,
>     message_id=...,
>     occurred_at=...,
> )
> ```

## ChannelHTTPInvoker

Use caller-owned HTTP transport and explicit per-actor authentication headers.

The server's authenticator must validate the service credential and map the
supplied actor identity to its principal. Metadata never establishes identity.

```python theme={null}
ChannelHTTPInvoker(client: Any, headers_for_actor: Any) -> None
```

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `client` | `Any` | Required |
> | `headers_for_actor` | `Any` | Required |
>
> ```python theme={null}
> from harnest.channels import ChannelHTTPInvoker
>
> invoker = ChannelHTTPInvoker(client=..., headers_for_actor=...)
> ```

### ChannelHTTPInvoker.**call**

```python theme={null}
async ChannelHTTPInvoker.__call__(event: ChannelEvent, session_id: str, actor_id: str) -> str
```

Create/reuse the scoped session and refuse approval or incomplete responses.

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `event` | `ChannelEvent` | Required |
> | `session_id` | `str` | Required |
> | `actor_id` | `str` | Required |
>
> ```python theme={null}
> from harnest.channels import ChannelHTTPInvoker
>
> invoker: ChannelHTTPInvoker
> result = await invoker(event=..., session_id=..., actor_id=...)
> ```

## ChannelReply

One outbound answer queued for durable, at-least-once delivery.

`status` is pending, sent, failed, or delivery\_unknown (an ambiguous
send that must be reconciled before replay, never blindly retried).

```python theme={null}
ChannelReply(
    reply_id: str,
    platform: str,
    installation_id: str,
    conversation_id: str,
    reply_to: Mapping[str, Any],
    content: str,
    status: str = 'pending',
    receipt: Mapping[str, Any] | None = None,
    created_at: float = 0.0,
    updated_at: float = 0.0,
) -> None
```

Fields (`—` means no declared default):

| Field | Type | Default |
| - | - | - |
| `reply_id` | `str` | `—` |
| `platform` | `str` | `—` |
| `installation_id` | `str` | `—` |
| `conversation_id` | `str` | `—` |
| `reply_to` | `Mapping[str, Any]` | `—` |
| `content` | `str` | `—` |
| `status` | `str` | `'pending'` |
| `receipt` | `Mapping[str, Any] \| None` | `None` |
| `created_at` | `float` | `0.0` |
| `updated_at` | `float` | `0.0` |

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `reply_id` | `str` | Required |
> | `platform` | `str` | Required |
> | `installation_id` | `str` | Required |
> | `conversation_id` | `str` | Required |
> | `reply_to` | `Mapping[str, Any]` | Required |
> | `content` | `str` | Required |
> | `status` | `str` | `'pending'` |
> | `receipt` | `Mapping[str, Any] \| None` | `None` |
> | `created_at` | `float` | `0.0` |
> | `updated_at` | `float` | `0.0` |
>
> ```python theme={null}
> from harnest.channels import ChannelReply
>
> reply = ChannelReply(
>     reply_id=...,
>     platform=...,
>     installation_id=...,
>     conversation_id=...,
>     reply_to=...,
>     content=...,
> )
> ```

## ChannelStore

Atomic operations required for durable, deduplicated channel messaging.

All identity, scope, and ordering predicates execute inside the datastore.
A provider must durably commit before returning success.

```python theme={null}
ChannelStore(*args, **kwargs)
```

> [accordion] Example
>
> ```python theme={null}
> from harnest.channels import ChannelStore
>
> class MyChannelStore(ChannelStore):
>     ...
> ```

### ChannelStore.start

```python theme={null}
async ChannelStore.start() -> None
```

Open owned resources and initialize the provider's durable schema.

> [accordion] Example
>
> ```python theme={null}
> from harnest.channels import ChannelStore
>
> store: ChannelStore
> await store.start()
> ```

### ChannelStore.close

```python theme={null}
async ChannelStore.close() -> None
```

Release owned resources after receivers and senders have stopped.

> [accordion] Example
>
> ```python theme={null}
> from harnest.channels import ChannelStore
>
> store: ChannelStore
> await store.close()
> ```

### ChannelStore.admit\_event

```python theme={null}
async ChannelStore.admit_event(event: ChannelEvent) -> tuple[ChannelEvent, bool]
```

Atomically persist a new event or return an identical prior admission.

Deduplication is scoped by platform, installation, and provider event
ID. A conflicting definition under the same identity raises
ChannelStoreConflictError. The second return value is True only for a
newly admitted event.

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `event` | `ChannelEvent` | Required |
>
> ```python theme={null}
> from harnest.channels import ChannelStore
>
> store: ChannelStore
> result = await store.admit_event(event=...)
> ```

### ChannelStore.get\_event

```python theme={null}
async ChannelStore.get_event(*, platform: str, installation_id: str, provider_event_id: str) -> ChannelEvent | None
```

Read one admitted event by its deduplication identity.

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `platform` | `str` | Required |
> | `installation_id` | `str` | Required |
> | `provider_event_id` | `str` | Required |
>
> ```python theme={null}
> from harnest.channels import ChannelStore
>
> store: ChannelStore
> event = await store.get_event(platform=..., installation_id=..., provider_event_id=...)
> ```

### ChannelStore.bind\_session

```python theme={null}
async ChannelStore.bind_session(
    *,
    platform: str,
    installation_id: str,
    conversation_id: str,
    thread_id: str | None,
    session_id: str,
) -> None
```

Idempotently record which Harnest session owns a conversation scope.

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `platform` | `str` | Required |
> | `installation_id` | `str` | Required |
> | `conversation_id` | `str` | Required |
> | `thread_id` | `str \| None` | Required |
> | `session_id` | `str` | Required |
>
> ```python theme={null}
> from harnest.channels import ChannelStore
>
> store: ChannelStore
> await store.bind_session(
>     platform=...,
>     installation_id=...,
>     conversation_id=...,
>     thread_id=...,
>     session_id=...,
> )
> ```

### ChannelStore.get\_session\_binding

```python theme={null}
async ChannelStore.get_session_binding(
    *,
    platform: str,
    installation_id: str,
    conversation_id: str,
    thread_id: str | None,
) -> str | None
```

Read the session bound to a conversation scope, if any.

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `platform` | `str` | Required |
> | `installation_id` | `str` | Required |
> | `conversation_id` | `str` | Required |
> | `thread_id` | `str \| None` | Required |
>
> ```python theme={null}
> from harnest.channels import ChannelStore
>
> store: ChannelStore
> result = await store.get_session_binding(
>     platform=...,
>     installation_id=...,
>     conversation_id=...,
>     thread_id=...,
> )
> ```

### ChannelStore.enqueue\_reply

```python theme={null}
async ChannelStore.enqueue_reply(reply: ChannelReply) -> ChannelReply
```

Durably queue one reply before the adapter sends it.

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `reply` | `ChannelReply` | Required |
>
> ```python theme={null}
> from harnest.channels import ChannelStore
>
> store: ChannelStore
> reply = await store.enqueue_reply(reply=...)
> ```

### ChannelStore.claim\_replies

```python theme={null}
async ChannelStore.claim_replies(*, platform: str, installation_id: str, limit: int = 1) -> tuple[ChannelReply, ...]
```

Claim a bounded batch of pending replies for one sender to send.

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `platform` | `str` | Required |
> | `installation_id` | `str` | Required |
> | `limit` | `int` | `1` |
>
> ```python theme={null}
> from harnest.channels import ChannelStore
>
> store: ChannelStore
> result = await store.claim_replies(platform=..., installation_id=...)
> ```

### ChannelStore.finish\_reply

```python theme={null}
async ChannelStore.finish_reply(*, reply_id: str, status: str, receipt: Mapping[str, Any] | None = None) -> bool
```

Record a claimed reply's terminal outcome; unknown IDs return false.

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `reply_id` | `str` | Required |
> | `status` | `str` | Required |
> | `receipt` | `Mapping[str, Any] \| None` | `None` |
>
> ```python theme={null}
> from harnest.channels import ChannelStore
>
> store: ChannelStore
> result = await store.finish_reply(reply_id=..., status=...)
> ```

## ChannelStoreConflictError

An admitted event or reply has a different definition than the request.

> [accordion] Example
>
> ```python theme={null}
> from harnest.channels import ChannelStoreConflictError
>
> try:
>     ...
> except ChannelStoreConflictError as error:
>     ...
> ```

## ChannelWorker

Admit before ACK, fence work, and persist replies before any provider send.

The caller owns the started task store and authenticated invoke/send callbacks.
Jobs never automatically retry an ambiguous model execution or provider send.
Pending jobs survive restart; interrupted claimed jobs require reconciliation.

```python theme={null}
ChannelWorker(
    *,
    application_id: str,
    binding_id: str,
    binding: ChannelBinding,
    store: TaskStore,
    invoke: Any,
    send: Any,
    allowed_senders: tuple[str, ...],
    allowed_kinds: tuple[str, ...] = ('app_mention',),
    timeout: float = 120,
    not_before: float = 0,
) -> None
```

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `application_id` | `str` | Required |
> | `binding_id` | `str` | Required |
> | `binding` | `ChannelBinding` | Required |
> | `store` | `TaskStore` | Required |
> | `invoke` | `Any` | Required |
> | `send` | `Any` | Required |
> | `allowed_senders` | `tuple[str, ...]` | Required |
> | `allowed_kinds` | `tuple[str, ...]` | `('app_mention',)` |
> | `timeout` | `float` | `120` |
> | `not_before` | `float` | `0` |
>
> ```python theme={null}
> from harnest.channels import ChannelWorker
>
> worker = ChannelWorker(
>     application_id=...,
>     binding_id=...,
>     binding=...,
>     store=...,
>     invoke=...,
>     send=...,
>     allowed_senders=...,
> )
> ```

### ChannelWorker.accepts

```python theme={null}
ChannelWorker.accepts(event: ChannelEvent) -> bool
```

Recheck policy at intake and execution, including work retained before changes.

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `event` | `ChannelEvent` | Required |
>
> ```python theme={null}
> from harnest.channels import ChannelWorker
>
> worker: ChannelWorker
> result = worker.accepts(event=...)
> ```

### ChannelWorker.admit

```python theme={null}
async ChannelWorker.admit(event: ChannelEvent) -> str | None
```

Commit input and dispatch intent in one atomic, idempotent task admission.

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `event` | `ChannelEvent` | Required |
>
> ```python theme={null}
> from harnest.channels import ChannelWorker
>
> worker: ChannelWorker
> result = await worker.admit(event=...)
> ```

### ChannelWorker.step

```python theme={null}
async ChannelWorker.step() -> int
```

Process bounded disjoint claims, prioritizing replies already durably queued.

> [accordion] Example
>
> ```python theme={null}
> from harnest.channels import ChannelWorker
>
> worker: ChannelWorker
> result = await worker.step()
> ```

### ChannelWorker.run

```python theme={null}
async ChannelWorker.run(stop: asyncio.Event) -> None
```

Drain bounded work until shutdown; the receiver must stop before this worker.

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `stop` | `asyncio.Event` | Required |
>
> ```python theme={null}
> from harnest.channels import ChannelWorker
>
> worker: ChannelWorker
> await worker.run(stop=...)
> ```

## MemoryChannelStore

Implement the atomic channel contract in one process; nothing survives restart.

```python theme={null}
MemoryChannelStore() -> None
```

> [accordion] Example
>
> ```python theme={null}
> from harnest.channels import MemoryChannelStore
>
> store = MemoryChannelStore()
> ```

### MemoryChannelStore.start

```python theme={null}
async MemoryChannelStore.start() -> None
```

Satisfy lifecycle ownership without opening external resources.

> [accordion] Example
>
> ```python theme={null}
> from harnest.channels import MemoryChannelStore
>
> store: MemoryChannelStore
> await store.start()
> ```

### MemoryChannelStore.close

```python theme={null}
async MemoryChannelStore.close() -> None
```

Release no resources; in-memory data lives only with this instance.

> [accordion] Example
>
> ```python theme={null}
> from harnest.channels import MemoryChannelStore
>
> store: MemoryChannelStore
> await store.close()
> ```

### MemoryChannelStore.admit\_event

```python theme={null}
async MemoryChannelStore.admit_event(event: ChannelEvent) -> tuple[ChannelEvent, bool]
```

Commit an isolated event snapshot keyed by its deduplication identity.

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `event` | `ChannelEvent` | Required |
>
> ```python theme={null}
> from harnest.channels import MemoryChannelStore
>
> store: MemoryChannelStore
> result = await store.admit_event(event=...)
> ```

### MemoryChannelStore.get\_event

```python theme={null}
async MemoryChannelStore.get_event(*, platform: str, installation_id: str, provider_event_id: str) -> ChannelEvent | None
```

Read one detached event snapshot by its deduplication identity.

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `platform` | `str` | Required |
> | `installation_id` | `str` | Required |
> | `provider_event_id` | `str` | Required |
>
> ```python theme={null}
> from harnest.channels import MemoryChannelStore
>
> store: MemoryChannelStore
> event = await store.get_event(platform=..., installation_id=..., provider_event_id=...)
> ```

### MemoryChannelStore.bind\_session

```python theme={null}
async MemoryChannelStore.bind_session(
    *,
    platform: str,
    installation_id: str,
    conversation_id: str,
    thread_id: str | None,
    session_id: str,
) -> None
```

Record the session owning a conversation scope without overwriting it.

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `platform` | `str` | Required |
> | `installation_id` | `str` | Required |
> | `conversation_id` | `str` | Required |
> | `thread_id` | `str \| None` | Required |
> | `session_id` | `str` | Required |
>
> ```python theme={null}
> from harnest.channels import MemoryChannelStore
>
> store: MemoryChannelStore
> await store.bind_session(
>     platform=...,
>     installation_id=...,
>     conversation_id=...,
>     thread_id=...,
>     session_id=...,
> )
> ```

### MemoryChannelStore.get\_session\_binding

```python theme={null}
async MemoryChannelStore.get_session_binding(
    *,
    platform: str,
    installation_id: str,
    conversation_id: str,
    thread_id: str | None,
) -> str | None
```

Read the session bound to a conversation scope, if any.

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `platform` | `str` | Required |
> | `installation_id` | `str` | Required |
> | `conversation_id` | `str` | Required |
> | `thread_id` | `str \| None` | Required |
>
> ```python theme={null}
> from harnest.channels import MemoryChannelStore
>
> store: MemoryChannelStore
> result = await store.get_session_binding(
>     platform=...,
>     installation_id=...,
>     conversation_id=...,
>     thread_id=...,
> )
> ```

### MemoryChannelStore.enqueue\_reply

```python theme={null}
async MemoryChannelStore.enqueue_reply(reply: ChannelReply) -> ChannelReply
```

Queue one detached reply snapshot for later claim and send.

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `reply` | `ChannelReply` | Required |
>
> ```python theme={null}
> from harnest.channels import MemoryChannelStore
>
> store: MemoryChannelStore
> reply = await store.enqueue_reply(reply=...)
> ```

### MemoryChannelStore.claim\_replies

```python theme={null}
async MemoryChannelStore.claim_replies(*, platform: str, installation_id: str, limit: int = 1) -> tuple[ChannelReply, ...]
```

Return a bounded scoped batch of pending replies, oldest first.

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `platform` | `str` | Required |
> | `installation_id` | `str` | Required |
> | `limit` | `int` | `1` |
>
> ```python theme={null}
> from harnest.channels import MemoryChannelStore
>
> store: MemoryChannelStore
> result = await store.claim_replies(platform=..., installation_id=...)
> ```

### MemoryChannelStore.finish\_reply

```python theme={null}
async MemoryChannelStore.finish_reply(
    *,
    reply_id: str,
    status: str,
    receipt: Mapping[str, Any] | None = None,
) -> bool
```

Record a terminal outcome for one previously enqueued reply.

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `reply_id` | `str` | Required |
> | `status` | `str` | Required |
> | `receipt` | `Mapping[str, Any] \| None` | `None` |
>
> ```python theme={null}
> from harnest.channels import MemoryChannelStore
>
> store: MemoryChannelStore
> result = await store.finish_reply(reply_id=..., status=...)
> ```

## create\_channel\_adapter

Build the adapter a binding names, raising if its extension is absent.

```python theme={null}
create_channel_adapter(extension: str, config: Mapping[str, Any]) -> ChannelAdapter
```

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `extension` | `str` | Required |
> | `config` | `Mapping[str, Any]` | Required |
>
> ```python theme={null}
> from harnest.channels import create_channel_adapter
>
> adapter = create_channel_adapter(extension=..., config=...)
> ```

## discover\_channel\_bindings

Load every ChannelBinding exported by a project's channels/ directory.

Mirrors the discovery convention used for tools and MCP clients: one file
per binding, named after the platform, exporting a callable `binding()`.

```python theme={null}
discover_channel_bindings(directory: Path) -> tuple[ChannelBinding, ...]
```

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `directory` | `Path` | Required |
>
> ```python theme={null}
> from harnest.channels import discover_channel_bindings
>
> result = discover_channel_bindings(directory=...)
> ```

## register\_channel\_adapter

Register one packaged extension's adapter factory under its unique name.

```python theme={null}
register_channel_adapter(extension: str, factory: ChannelAdapterFactory) -> None
```

> [accordion] Parameters and example
>
> | Parameter | Type | Default |
> | - | - | - |
> | `extension` | `str` | Required |
> | `factory` | `ChannelAdapterFactory` | Required |
>
> ```python theme={null}
> from harnest.channels import register_channel_adapter
>
> register_channel_adapter(extension=..., factory=...)
> ```

## registered\_channel\_adapters

List currently registered extension names for inspection and errors.

```python theme={null}
registered_channel_adapters() -> tuple[str, ...]
```

> [accordion] Example
>
> ```python theme={null}
> from harnest.channels import registered_channel_adapters
>
> result = registered_channel_adapters()
> ```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.