Metadata-Version: 2.5
Name: statewire
Version: 0.20.0
Summary: Replicate one JSON object over an SSE op stream + a command endpoint
Project-URL: Repository, https://github.com/assistant-ui/harness-sdk
License-Expression: MIT
Requires-Python: <4.0,>=3.12
Requires-Dist: fastapi>=0.115
Requires-Dist: httpx>=0.27
Requires-Dist: pinned<0.17,>=0.16.0
Requires-Dist: statepatch<0.4,>=0.3.0
Provides-Extra: langgraph
Requires-Dist: langchain-core>=0.3; extra == 'langgraph'
Provides-Extra: orjson
Requires-Dist: orjson>=3.9; extra == 'orjson'
Description-Content-Type: text/markdown

# statewire

The Statewire protocol for Python: a `Statewire` host owns one JSON state dict, streams every change to attached clients as ops, and dispatches typed commands back. Part of [harness-sdk](https://github.com/assistant-ui/harness-sdk), with `harness-sdk` and `pinned`.

## Install

```sh
uv add statewire
```

Extras: `uv add "statewire[langgraph]"`, `uv add "statewire[orjson]"`.

## Use

```python
from fastapi import FastAPI
from pinned import PinnedHost, PinnedWorker
from statewire import Statewire, StatewireReject, command

class Counter(Statewire):
    async def lifespan(self):
        self.state = {"count": 0}
        yield

    @command
    async def increment(self):
        if self.state["count"] >= 10:
            raise StatewireReject("the counter is full (max 10)")
        self.state["count"] += 1

worker = PinnedWorker()
app = FastAPI()
app.include_router(worker)
app.include_router(PinnedHost(Counter, worker=worker, namespace="/threads"))
```

## Protocols and documents

Connections negotiate date ranges through `Statewire-Version` and `Statewire-Protocol`. Protocols are additive and required by default. The server selects versions in `syn`; WebSockets use `statewire.v1`.

Each protocol owns its commands and its documents, and mints statement seqs in its own lane. Ephemeral subprotocols (`Statewire.Subprotocol("interest", record="ephemeral")`) restart their lane on every attach and carry per-attach documents mounted from handlers via `ctx.attach`. Python hosts support chained compatibility adapters.

See the [protocol registration and migration guide](https://github.com/assistant-ui/harness-sdk/blob/main/apps/docs/app/statewire/docs/spec/statewire-protocol/protocols/page.mdx).

## Docs

- Get started: https://github.com/assistant-ui/harness-sdk/blob/main/apps/docs/app/statewire/docs/get-started/statewire/page.mdx
- Guide: https://github.com/assistant-ui/harness-sdk/blob/main/apps/docs/app/statewire/docs/guides/statewire/host/page.mdx
- Reference: https://github.com/assistant-ui/harness-sdk/blob/main/apps/docs/app/statewire/docs/reference/statewire-python/page.mdx
- Spec: https://github.com/assistant-ui/harness-sdk/blob/main/apps/docs/app/statewire/docs/spec/statewire-protocol/page.mdx

## Lease context

```python
client = StatewireClient.sse(url, context={"acme-chat": {"locale": "en"}})
client.set_context("acme-chat", {"locale": "de"})
```

Context is a full object per protocol and connection lease. The client restores its latest values on every new attachment, including a fresh hello on the same socket. Hosts validate candidates through `validate_context` and react through `context_changed`. Commands read their admission snapshot through `ctx.context`; later replacements do not alter queued commands. Context supports document datetime metadata, has a 64 KiB limit per entry, and consumes no command sequence numbers.
