Metadata-Version: 2.4
Name: terminull-bridge
Version: 0.5.10
Summary: Headless bridge for Terminull — connects the mobile client to local coding agents (Claude Code, Codex, Cursor, Gemini, and more) over an end-to-end-encrypted relay.
Author: Lungo
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: ai-agent,bridge,claude,codex,coding-agent,e2ee,remote
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: AsyncIO
Classifier: Intended Audience :: Developers
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development
Requires-Python: >=3.12
Requires-Dist: anthropic>=0.40.0
Requires-Dist: cryptography>=42.0
Requires-Dist: httpx>=0.27.0
Requires-Dist: keyring>=25.0
Requires-Dist: orjson>=3.10
Requires-Dist: pdfplumber>=0.11.0
Requires-Dist: pydantic>=2.0
Requires-Dist: python-dotenv>=1.0
Requires-Dist: qrcode[pil]>=7.4
Requires-Dist: websockets>=13.0
Requires-Dist: zeroconf>=0.132.0
Provides-Extra: llm-mac
Requires-Dist: mlx-lm>=0.19.0; extra == 'llm-mac'
Requires-Dist: transformers<5.13,>=5.0.0; extra == 'llm-mac'
Provides-Extra: stt-linux
Requires-Dist: faster-whisper>=1.0; extra == 'stt-linux'
Requires-Dist: numpy>=1.26; extra == 'stt-linux'
Requires-Dist: onnxruntime>=1.16; extra == 'stt-linux'
Provides-Extra: stt-mac
Requires-Dist: mlx-whisper>=0.4.0; extra == 'stt-mac'
Requires-Dist: numpy>=1.26; extra == 'stt-mac'
Requires-Dist: onnxruntime>=1.16; extra == 'stt-mac'
Provides-Extra: telemetry
Requires-Dist: sentry-sdk>=2.0; extra == 'telemetry'
Provides-Extra: test
Requires-Dist: pytest-asyncio>=0.23; extra == 'test'
Requires-Dist: pytest>=8.0; extra == 'test'
Provides-Extra: vision-mac
Requires-Dist: pyobjc-framework-libdispatch>=10.0; extra == 'vision-mac'
Requires-Dist: pyobjc-framework-network>=10.0; extra == 'vision-mac'
Requires-Dist: pyobjc-framework-vision>=10.0; extra == 'vision-mac'
Provides-Extra: webrtc
Requires-Dist: aiortc>=1.6.0; extra == 'webrtc'
Description-Content-Type: text/markdown

# terminull-bridge

The headless bridge that powers [Terminull](https://terminull.dev) — it runs on your Mac or
Linux box, holds your local coding agents, and streams them to the Terminull mobile client
over an **end-to-end-encrypted** relay (or directly over your LAN). The bridge never sees
your account credentials, and the relay only ever sees ciphertext.

```
mobile client  ⇄  relay (splice, opaque)  ⇄  terminull-bridge  ⇄  local agent (Claude Code, Codex, …)
                        └──────────── LAN direct / WebRTC P2P ────────────┘
```

## What it does

- **Adapters** for a range of local coding agents — Claude Code, Codex, Cursor, Gemini,
  Kilo, OpenCode, Pi, Droid, Goose, Copilot, and more — normalized into one **block
  protocol** (a unified JSON stream the client renders identically regardless of agent).
- **End-to-end encryption** — X25519 ECDH + HKDF per-session keys, AES-GCM per block.
  The relay is a blind splice; it only ever forwards ciphertext.
- **Transport** — WebSocket over TCP, LAN-direct or relay-spliced, with an optional
  WebRTC P2P data channel for direct device↔bridge delivery.
- **Reliable delivery** — per-device replay buffer, resume tokens, message dedup + ack,
  so a dropped connection resumes exactly where it left off.
- **Voice** — on-device / bridge-side speech-to-text with optional LLM post-correction.

## Install

**Linux / VPS** — one-liner (installs a `systemd --user` service, pairs via QR):

```bash
curl -fsSL https://raw.githubusercontent.com/lungohq/terminull-bridge/main/install.sh | bash
```

**Any platform** — from PyPI:

```bash
pip install terminull-bridge
```

Optional extras (install what your platform needs):

| Extra | Adds |
|-------|------|
| `stt-mac` / `stt-linux` | Speech-to-text (Whisper) |
| `vision-mac` | On-device OCR for image attachments (macOS) |
| `webrtc` | WebRTC P2P data channel (`aiortc`) |
| `telemetry` | Crash reporting (`sentry-sdk`) |

```bash
pip install 'terminull-bridge[stt-linux,webrtc]'
```

## Run

```bash
terminull          # start the headless bridge (pairs via QR on first run)
terminull-admin    # admin/diagnostics CLI
```

## Configuration

The bridge reads two files under `~/.config/terminull/`:

- **`.env`** — secrets + machine/deploy overrides (hand-edited; restart to apply). On
  systemd, the unit's `EnvironmentFile` points at this same file. Defaults target the
  hosted relay/API (`wss://relay.terminull.dev` / `https://api.terminull.dev`); override
  with `TERMINULL_RELAY_URL` / `TERMINULL_API_URL`.
- **`config.toml`** — feature flags the app can toggle live (bridge-written): STT, vision,
  summaries, relay on/off, LAN-only mode, assist-tier providers. See
  [`config.example.toml`](config.example.toml).

Data (replay buffer, keyring) lives under `~/.local/share/terminull/`.

## Writing an adapter

Adapters subclass `BaseAdapter` (`terminull_bridge/adapters/base.py`) and implement
`start` / `send` / `stream` / `stop`, declaring their capabilities via `cap_*` class
attributes. Every concrete adapter must also set `agent_id`, `display_name`, and both
`provides_models`/`provides_usage` (`True`/`False`) — the last two are enforced at import
by `BaseAdapter.__init_subclass__`, so leaving them unset is a load-time error.

You can drop external adapters into `~/.terminull/ext_adapters/*.py` without forking the
package — see the fully-worked, copy-pasteable reference in
[`examples/ext_adapter_example.py`](examples/ext_adapter_example.py) (it also documents the
spawn-time wiring the bridge offers your `__init__`, incl. `on_session_id` for
resume-after-restart). A bad drop-in is logged and skipped, never fatal.

## Layout

```
terminull_bridge/
├── adapters/     agent adapters (one per coding agent) + BaseAdapter
├── blocks.py     the unified block protocol
├── headless.py   the headless entry point (terminull)
├── relay_client.py / local_server.py   transports (relay WS / LAN WS)
├── frame.py      transport-v2 binary framing
├── replay_buffer.py   per-device reliable delivery
└── …
```

## License

Licensed under the [Apache License 2.0](LICENSE).
