Metadata-Version: 2.4
Name: anna-app-runtime-local
Version: 0.2.0a6
Summary: Local-dev in-memory runtime for Anna Apps. Wraps anna-app-core's dispatcher with an InMemoryWindowStore + WebSocket bridge.
Author: Talent AI
License: Proprietary
Keywords: anna,anna-app,dev,executa,harness
Requires-Python: >=3.10
Requires-Dist: anna-app-core<0.7,>=0.6.0
Description-Content-Type: text/markdown

# anna-app-runtime-local

Local-dev in-memory runtime for Anna Apps. Reuses the production
[`anna_app_rpc_dispatcher`](../../src/services/anna_app_rpc_dispatcher.py)
through `WindowStoreProtocol` so harness behaviour is byte-identical to
nexus production.

## How it shares code with production

This package does not vendor a copy of the dispatcher. Instead it:

1. Imports `dispatch`, `WindowStoreProtocol`, `HostRpcError` from
   `src.services.anna_app_rpc_dispatcher` (matrix-nexus source).
2. Provides `InMemoryWindowStore` — a `WindowStoreProtocol` impl that
   keeps state in dictionaries and queues SSE events in memory.
3. Wires the production `dispatch(store, …)` against in-memory state.

Because the wheel imports `src.services.…` directly, the bridge process
must be launched from a Python environment that has matrix-nexus on
`PYTHONPATH` (typically: `cd matrix-nexus && uv run python -m
anna_app_runtime_local.bridge`).

## Public surface

```python
from anna_app_runtime_local import LocalDispatcherSession, mint_dev_token

session = LocalDispatcherSession.create(
    user_id=1,
    app_slug="focus-flow",
    manifest_dict={...},  # parsed manifest.json
    view="main",
    entry_payload={"topic": "ECM"},
)
result = await session.call("storage", "set", {"key": "x", "value": 42})
events = session.drain_events()  # list[dict] for SSE relay
```

## stdio bridge

```bash
python -m anna_app_runtime_local.bridge
```

Speaks JSON-RPC 2.0 over stdin/stdout (one envelope per line). Methods:

- `session.create` → `{ session_id, window_uuid, token, view, view_meta }`
- `session.call`   → forwards to `dispatch()`; returns `{ ok, result | error }`
- `session.drain_events` → flushes queued SSE events
- `session.close`  → drops the session
- `session.refresh_token` → re-mints a dev token for an active session
- `executas.register` → registers `{tool_id, project_dir, command?}` for
  `tools.invoke`; first call lazy-spawns `uv run --project <dir> <tool_id>`
  and reuses the warm subprocess.

The Node-side harness (`anna-app-cli/src/harness/bridge.ts`) speaks this
protocol over `python-shell`.

## Local HMAC tokens

`mint_dev_token / verify_dev_token` use a per-user key at
`~/.anna-app/dev.key` (mode 600, generated on first use). TTL defaults
to 30 s — shorter than production's 120 s — to surface SDK refresh bugs
early.

These tokens are **not interoperable** with the production JWT path;
production's `_is_tool_allowed` already rejects `tool-dev-…` prefixes.
