Metadata-Version: 2.4
Name: yothere
Version: 1.5.3
Summary: yothere — an ambient-agent cockpit: a voice loop + fleet board that drives any agent brain over the Brain Protocol and tells a human when to look.
Project-URL: Homepage, https://github.com/phios-ai/yothere
Project-URL: Repository, https://github.com/phios-ai/yothere
Author: Phil Wenger, Oscar
License: MIT
License-File: LICENSE
Keywords: agents,ambient-agent,claude-code,cockpit,fleet,voice
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Requires-Python: >=3.11
Requires-Dist: pywebpush>=1.14
Requires-Dist: pyyaml>=6
Requires-Dist: websockets>=12
Provides-Extra: dev
Requires-Dist: pyflakes>=3; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Provides-Extra: llm
Requires-Dist: litellm>=1.89; extra == 'llm'
Provides-Extra: mcp
Requires-Dist: mcp>=1.2; extra == 'mcp'
Provides-Extra: postgres
Requires-Dist: psycopg[binary]>=3.1; extra == 'postgres'
Provides-Extra: voice
Requires-Dist: deepgram-sdk>=3.7; extra == 'voice'
Requires-Dist: fastapi>=0.115; extra == 'voice'
Requires-Dist: google-genai>=1.75; extra == 'voice'
Requires-Dist: pipecat-ai-small-webrtc-prebuilt>=2.5; extra == 'voice'
Requires-Dist: pipecat-ai[deepgram,google,silero,webrtc]>=1.4; extra == 'voice'
Requires-Dist: python-multipart>=0.0.9; extra == 'voice'
Requires-Dist: twilio>=9.0; extra == 'voice'
Requires-Dist: uvicorn[standard]>=0.30; extra == 'voice'
Requires-Dist: wsproto>=1.2; extra == 'voice'
Provides-Extra: web
Requires-Dist: fastapi>=0.115; extra == 'web'
Requires-Dist: python-multipart>=0.0.9; extra == 'web'
Requires-Dist: uvicorn[standard]>=0.30; extra == 'web'
Requires-Dist: wsproto>=1.2; extra == 'web'
Description-Content-Type: text/markdown

# yothere

**An ambient-agent cockpit.** yothere is the *interface* for long-running agents: a
fleet board, a voice loop, and a headless runner that advances work and tells a
human *when to look*. The agent that actually does the work, the **brain**, is
anything you point yothere at, over one published wire contract:
[`docs/brain-protocol-v1.md`](docs/brain-protocol-v1.md) (WebSocket + JSON-RPC 2.0).

yothere is harness-agnostic by design. The same cockpit drives:

- **Claude Code** running locally (`claude -p` per thread),
- **ubob** or any model-agnostic harness over its WebSocket daemon,
- a **remote brain** over the internet (a hosted sprite, a teammate's stack, a
  work platform) — anything that speaks the Brain Protocol.

It runs the same whether the brain is on this machine or behind a `wss://`
endpoint, so you can start a thread at your desk and watch it from your phone.

> **New here?** Start with [`docs/ONBOARDING.md`](docs/ONBOARDING.md): a 20-minute
> walkthrough from install to a real task advancing, plus how to send feedback.

## Why it exists

A fleet of agents working in the background is only useful if a human knows which
one needs them *now*. yothere is an **attention router for the human**, not a work
router for the agents: pull-on-glance by default, one rate-limited nudge ("N
threads need your eyes"), never a firehose, never interrupting your focus thread.

## Install

```bash
pip install yothere          # core: fleet runner + board + remote-brain client
pip install 'yothere[voice]' # + the Gemini-Live voice surface (WebRTC/Twilio)
pip install 'yothere[llm]'   # + optional LLM tiebreak for routing (deterministic otherwise)
```

yothere keeps all of its state under `~/.yothere` (override with `YOTHERE_HOME`,
or the legacy `RELAY_HOME`; an existing `~/.relay` is used as a fallback); see
[`docs/configuration.md`](docs/configuration.md) for every env seam (each `RELAY_*`
name also accepts its `YOTHERE_*` sibling).

## Quickstart — drive the bundled reference brain

```bash
# 1. Start the conformance brain (the smallest valid Brain Protocol implementation).
python -m yothere.voicecall.echo_brain --port 9999 &

# 2. Point yothere at it and spawn a thread.
export RELAY_REMOTE_BRAIN_URL=ws://127.0.0.1:9999
export RELAY_THREAD_HARNESS=remote
yothere spawn "research agentic commerce"

# 3. Advance the fleet one tick, then glance at the board.
python -m yothere.runner once   # or: python -m yothere.runner loop  (always-on engine)
yothere board --open
```

Swap `RELAY_REMOTE_BRAIN_URL` for your real endpoint and yothere drives your brain.
To run threads with a local Claude Code instead, set `RELAY_THREAD_HARNESS=claude`.

## The contract

A brain implements [`docs/brain-protocol-v1.md`](docs/brain-protocol-v1.md):
`hello` / `streamSubscribe` / `prompt` / `cancel` / `close`, streaming back
`delta` (text), and optionally `progress`, `status` (drives the attention
router), and `cost`. The reference is
[`src/yothere/voicecall/echo_brain.py`](src/yothere/voicecall/echo_brain.py), ~60
lines. Two load-bearing caveats live in [`SECURITY.md`](SECURITY.md): a remote
brain's cost cap is advisory, and **the brain owns its own safety/permissions**.

## Architecture

```
            yothere (cockpit + voice + runner)            YOUR BRAIN
  ┌───────────────────────────────────────────┐   ┌──────────────────┐
  cli  ──► spawn ──► store (dir-per-thread) ◄── runner ─┐            │
   │         │            │                       │     │  Brain     │
  board ◄─ fleet_state ◄──┘                  brain_advance ──ws──►  Protocol  │
   │     (attention router: rank · focus)          │     │  v1        │
  voice ──► session_manager ──────────────────────┘     └──────────────────┘
```

- **store / thread_model** — the dir-per-thread state machine (atomic
  `status.json`, session-id resume, the worker contract).
- **attention** — deterministic ranking + the human-facing guardrails.
- **runner / worker** — the headless advance engine (cost caps, stale sweep,
  429 usage-cap hold, coalesced nudges).
- **brain/** — the harness clients: local Claude, ubob daemon, any remote brain.
- **board / card** — the glance UI (server-rendered, XSS-safe).

## Hosted mode (multi-tenant cockpit)

The `/overview` cockpit runs in one of two modes, selected by `RELAY_AUTH_MODE`:

- **`off` (default) — local, single-user.** No login. The page, its SSE stream
  (`/live`), and the plan-review reply are reachable over loopback/tailnet
  (`_PUBLIC_PATHS`); the dangerous surface (WebRTC offer, `/harness`, `/start`,
  `/client`) stays behind the `RELAY_VOICECALL_BEARER` gate with a loopback
  exemption. This is byte-identical to the pre-auth cockpit — zero config.
- **`hosted` — multi-tenant.** A login is required: the tailnet carve-out is gone,
  every route except `/healthz` + `/login` needs a session cookie, and each account
  is scoped to its **own** `~/.relay-<tenant>` home (separate threads/data/state),
  so two logins see two isolated fleets with no cross-tenant read. Auth is
  Python-native and stdlib-only (`yothere.voicecall.auth`): scrypt password hashing,
  an opaque session token in SQLite (`RELAY_AUTH_DB`, WAL, separate from fleet
  state), login lockout, and a `Secure` cookie tied to the mode (not the request
  URL, so a TLS-terminating proxy can't drop it). Tenant homes live under
  `RELAY_TENANTS_ROOT` (default: beside `~/.relay`).

Hosted env: `RELAY_AUTH_MODE=hosted`, `RELAY_AUTH_DB=<path>`,
`RELAY_TENANTS_ROOT=<dir>`. Seed users via `yothere.voicecall.auth.AuthStore.create_user`
(public signup + hosted deployment are the next increment). The headless runner is
still single-tenant in this increment: a non-default tenant's threads are created and
isolated, but advancing them needs per-tenant runner orchestration (next increment).

## MCP surface

Drive a yothere fleet from any MCP client (Claude Desktop, etc.) — an orthogonal channel
that exposes the same front doors as the CLI and cockpit over stdio MCP:

- **`spawn_thread(task, mode, focus)`** — spawn fleet thread(s) from a natural-language
  task (read/draft-only, blocks for your approval before any outward action).
- **`board()`** — the fleet at a glance, needs-eyes first.
- **`reply(thread_id, text)`** — approve / edit / reject a blocked thread.

Single-user / local (drives this machine's `~/.relay` fleet). `mcp` is an optional
extra; install + register:

```bash
pip install 'yothere[mcp]'
```

```jsonc
// Claude Desktop: claude_desktop_config.json
{ "mcpServers": { "yothere": { "command": "yothere-mcp" } } }
```

The tool logic lives in SDK-free `_*_impl` helpers (`yothere.mcp_server`), so it imports
and tests without the `mcp` dependency installed.

## Status

v1.0.0. Fleet runner, board, voice surface, and the remote-brain path are tested
(`python tests/relay_test.py`). The hosted web cockpit and brain-side token
lifecycle are out of v1 (see [`CHANGELOG.md`](CHANGELOG.md)).

## Contributing

Two people build yothere and neither should break `main` alone. Every change goes
through a PR that the other founder approves before it merges — see
[`CONTRIBUTING.md`](CONTRIBUTING.md).

## License

MIT — see [`LICENSE`](LICENSE).
