Metadata-Version: 2.4
Name: yothere
Version: 1.25.0
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: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Requires-Python: <3.14,>=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: e2e
Requires-Dist: playwright>=1.48; extra == 'e2e'
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-pool>=3.2; extra == 'postgres'
Requires-Dist: psycopg[binary]>=3.1; extra == 'postgres'
Provides-Extra: voice
Requires-Dist: aioice>=0.10.2; extra == 'voice'
Requires-Dist: aiortc==1.14.0; extra == 'voice'
Requires-Dist: av==16.1.0; extra == 'voice'
Requires-Dist: cryptography>=49.0.0; 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: onnxruntime>=1.24.4; extra == 'voice'
Requires-Dist: opencv-python==4.13.0.92; extra == 'voice'
Requires-Dist: pipecat-ai-small-webrtc-prebuilt==2.5.0; extra == 'voice'
Requires-Dist: pipecat-ai[deepgram,google,silero,webrtc]==1.4.0; extra == 'voice'
Requires-Dist: pylibsrtp>=1.0.0; 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: voice-billing
Requires-Dist: google-genai>=1.75; extra == 'voice-billing'
Provides-Extra: voice-worker
Requires-Dist: cryptography>=49.0.0; extra == 'voice-worker'
Requires-Dist: deepgram-sdk>=3.7; extra == 'voice-worker'
Requires-Dist: fastapi>=0.115; extra == 'voice-worker'
Requires-Dist: google-genai>=1.75; extra == 'voice-worker'
Requires-Dist: onnxruntime>=1.24.4; extra == 'voice-worker'
Requires-Dist: pipecat-ai[daily,deepgram,google,silero]==1.4.0; extra == 'voice-worker'
Requires-Dist: python-multipart>=0.0.9; extra == 'voice-worker'
Requires-Dist: uvicorn[standard]>=0.30; extra == 'voice-worker'
Requires-Dist: wsproto>=1.2; extra == 'voice-worker'
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

**Run five agents. Watch none of them.** yothere advances up to five agent turns at
once on the Claude or ChatGPT subscription you already pay for, and gives you one
inbox instead of five terminal tabs.

The hosted cockpit lives at **[app.yothere.ai](https://app.yothere.ai)** (invite-only
beta). It holds your account, your threads, and the UI. **The agents run on your own
machine**, on your own Claude Code or Codex CLI login. yothere never holds your model
credentials and never bills you for inference.

Product docs (canonical, kept in step with what ships):
**[yothere.ai/docs](https://yothere.ai/docs/)**. This README is the repo front door.

## What you need

- **A Mac or a Linux box you can leave open.** Those are the only two platforms the
  service installer supports; on Windows, run it inside WSL2.
- **Python 3.11, 3.12 or 3.13.** 3.14 is not supported and `yothere doctor` fails it.
- **`pipx`** (`brew install pipx` on macOS).
- **Your own coding agent, logged in**: Claude Code (the `claude` CLI on PATH) or the
  Codex CLI on a ChatGPT subscription.

**And you leave the laptop open.** This is the consequence of BYO compute, so it is
worth saying plainly: while your paired machine is asleep or offline, nothing advances.
Dispatched tasks queue and drain the moment it reconnects. Nothing is lost. Nothing
moves either.

## Hosted beta, end to end

The full walkthrough is [`docs/BETA-GUIDE.md`](docs/BETA-GUIDE.md). The short version:

```bash
# 0. Redeem your invite code at https://app.yothere.ai and open the cockpit.
pipx install yothere                                        # Python 3.11-3.13

# 1. Pair this machine. `yothere login` prints a short pairing code (XXXX-XXXX) plus a
#    link to https://app.yothere.ai/activate. Open it in the browser where you are already
#    logged in, confirm which machine is asking, pick its permission tier (the full tier
#    ticks a bypass-consent checkbox), and the CLI saves the per-device credential. No token
#    is pasted, and your coding agent never handles a secret.
yothere login
#    Legacy fallback, for a headless or SSH-only box with no browser: mint a single-use
#    token in the cockpit's "Pair a machine" panel and paste it:
#    yothere login --url https://app.yothere.ai --token <paste>

# 2. Start the leaser in the FOREGROUND once. It prints the unattended-tool-use
#    consent and refuses to start until you acknowledge it. Read it before you ack.
cd <the project you want the agent to work in>
yothere service

# 3. Once you have acknowledged it, make it always-on (survives logout and reboot).
yothere service install
yothere service status      # expect: running

# Anytime:
yothere devices list        # paired machines (yothere devices revoke <id> to kill one)
yothere doctor              # diagnose the install (--bundle writes a redacted tarball)
```

Then dispatch from the cockpit. For voice, click **Connect** in the cockpit: voice is
hosted, so there is no phone number, no Twilio, and no API key of your own.

### Read this before `yothere service install`

Worker turns run your agent with permissions bypassed: `claude -p --permission-mode
bypassPermissions`, or `codex exec -s danger-full-access`. Inside a turn the agent
reads, writes and runs commands in `YOTHERE_WORK_DIR` **without asking you per action**.

- `yothere service` (foreground) gates on that: it prints the consent text and blocks
  until you set `YOTHERE_BYPASS_PERMISSIONS_ACK=1`.
- `yothere service install` does **not** print it. The installed unit runs
  `python -m yothere.cloud.agent` directly. Run the foreground path once first, so the
  ack is recorded in `~/.yothere/yothere.env` before the always-on unit ever starts.
- Point `YOTHERE_WORK_DIR` at a scratch or project directory, never at something you
  would mind an agent editing.
- Want the unattended bypass off entirely: set
  `YOTHERE_WORKER_PERMISSION_MODE=acceptEdits` in `~/.yothere/yothere.env`.

What yothere *does* contain is **outward actions**. A send-gate on your machine denies
sends, posts and pushes in an unattended turn: the thread stops at `blocked` and waits
for your approval. `git push` and `gh` are in a never-grant list, so **no approval can
ever unlock them for a worker turn**: an agent can never publish. You still can, and yothere
carries it out: press **Ship it** on a diff and it pushes the branch and opens the PR as you
(`publish.py`, host-side, outside the turn, plain git with no model in the loop). Cost caps run
per thread and per day.

The gate is a guardrail, not a sandbox. It inspects shell and MCP tool calls, so what an
agent **reads**, and its outbound **GET** requests, are not contained. See
[`SECURITY.md`](SECURITY.md).

## Install

```bash
pipx install yothere                  # macOS: pip is usually not on PATH, and PEP 668
                                      # blocks a global install. pipx is the path.
pipx install 'yothere[mcp]'           # + the MCP surface (drive a fleet from any MCP client)
```

State roots at `~/.yothere` (override with `YOTHERE_HOME`; an existing `~/.relay` is
used as a fallback). `YOTHERE_*` is the canonical env namespace; legacy `RELAY_*` names
still resolve as deprecated aliases. Every seam:
[`docs/configuration.md`](docs/configuration.md).

## Commands

```bash
yothere spawn "<task>"        # create a thread (or: yothere preset <key> <arg>)
yothere workspace add <name> <path/to/repo>   # register a repo you already have
yothere spawn --repo <name> "<task>"          # a code thread, in its own git worktree
yothere list                  # live threads + state
yothere show <id>             # status, plan, transcript
yothere reply <id> "<text>"   # answer a blocked thread -> it re-advances
yothere focus <id>            # pin the focus thread (yothere unfocus clears it)
yothere board --open          # the glance board
yothere note "<text>"         # capture a reminder (no thread)
yothere park <id>             # pause a thread (yothere kill <id> removes it)
yothere tasks                 # brain-discovered task source (discover|refresh|show)
yothere feedback "<text>"     # send feedback to the team (paired) or save it locally
yothere doctor                # pass/warn/fail per check, with the fix
```

Full reference: [yothere.ai/docs/cli](https://yothere.ai/docs/cli/).

## The code lane

Register a repo you **already have** on the machine. yothere never clones, and never
holds a git credential of yours:

```bash
yothere workspace add site ~/code/site        # also: workspace list, workspace rm <name>
yothere spawn --repo site "fix the layout shift on the pricing page"
```

The thread's turns run in **their own git worktree** (under `~/.yothere/worktrees/`, not
in your checkout), on their own branch. So a code thread cannot tread on what you have
open, or on another thread. It commits, and hands the branch back for you to read.

**No approval opens a push, a PR or a merge.** `git push` and `gh` are in the never-grant
list, so no approval unlocks them, not yours and not ours. You publish, or nobody does.
That is a rule in the gate, not a sandbox: `YOTHERE_WORKER_SEND_POLICY=open` turns the gate
off wholesale, and a GitHub MCP server you install yourself can carry a publish tool the
gate does not read as a send.

The worktree is isolation from other **threads**, not a sandbox: a bypassed turn can
still write elsewhere on the box. See [`SECURITY.md`](SECURITY.md).

## Coming soon

One item, marked here so nobody plans around it:

- **Recurring tasks.** There is no scheduler. A hail runs **once, immediately**. "Every
  morning at 7, scan the news" spawns one thread that starts now.

Answered in the FAQ: [yothere.ai/docs/faq](https://yothere.ai/docs/faq/). The whole
picture: [yothere.ai/roadmap](https://yothere.ai/roadmap/).

## Self-host, and your own brain

Everything above is the hosted product. The repo also runs standalone.

A **brain** is whatever actually does the work. yothere talks to it over one published
wire contract, [`docs/brain-protocol-v1.md`](docs/brain-protocol-v1.md) (WebSocket +
JSON-RPC 2.0): `hello` / `streamSubscribe` / `prompt` / `cancel` / `close`, streaming
back `delta`, and optionally `progress`, `status` and `cost`. The reference
implementation is [`src/yothere/voicecall/echo_brain.py`](src/yothere/voicecall/echo_brain.py),
about 60 lines, and it is the conformance fixture.

The harnesses that run today: `claude` (Claude Code, local), `codex` (Codex CLI, local,
on a ChatGPT subscription), and `remote` (anything speaking the Brain Protocol).

```bash
# Drive the bundled reference brain, no keys, no account.
python -m yothere.voicecall.echo_brain --port 9999 &
export YOTHERE_REMOTE_BRAIN_URL=ws://127.0.0.1:9999
export YOTHERE_THREAD_HARNESS=remote
yothere spawn "research agentic commerce"
python -m yothere.runner once     # advance one tick (or: python -m yothere.runner loop)
yothere board --open
```

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 and permissions**. Local walkthrough:
[`docs/ONBOARDING.md`](docs/ONBOARDING.md) and [`QUICKSTART.md`](QUICKSTART.md).

## 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).
- **runner / worker**. The headless advance engine. Up to 5 work turns in parallel
  (`YOTHERE_MAX_CONCURRENCY`), plus a **separate** pool for typed questions
  (`YOTHERE_CHAT_CONCURRENCY`), so your reply never queues behind the work. Cost caps,
  stale sweep, 429 usage-cap hold.
- **attention**. Deterministic ranking of what needs a human.
- **brain/**. The harness clients: local Claude, local Codex, any remote brain.
- **cloud/**. The hosted control plane (auth, jobs queue, voice worker) and the
  BYO-compute leaser that long-polls it.
- **board / card**. The glance UI (server-rendered, XSS-safe).

## Hosted mode (multi-tenant)

`YOTHERE_AUTH_MODE` selects the cockpit's mode:

- **`off` (default), local, single-user, gated.** Every route except the liveness probe,
  the PWA statics and `/login` requires loopback, the opt-in trusted tailnet identity, the
  `YOTHERE_VOICECALL_BEARER` bearer, or a signed local-session cookie.
- **`hosted`, multi-tenant.** Login required, no tailnet carve-out, and each account is
  scoped to its own `~/.yothere-<tenant>` home, so two logins see two isolated fleets.
  Auth is stdlib-only (`yothere.voicecall.auth`): scrypt hashing, opaque session tokens,
  login lockout, `Secure` cookie tied to the mode.

This is what runs at `app.yothere.ai` (Fly + managed Postgres), with invite-gated signup
and **zero agent compute on the control plane**: each tenant pairs their own machine,
which long-polls a device-token job queue and runs the turns locally. Every paired machine
carries a **permission tier** (read-only by default, up to full), chosen in the pairing
ladder and editable in Settings → Machines; the control plane refuses to lease work to a
restricted machine whose wheel cannot enforce its tier. Deploy notes:
[`docs/DEPLOY-fly.md`](docs/DEPLOY-fly.md).

## MCP surface

Drive a fleet from any MCP client over stdio:

- **`spawn_thread(task, mode, focus)`**: spawn thread(s) from a natural-language task.
- **`board()`**: the fleet at a glance, needs-eyes first.
- **`reply(thread_id, text)`**: approve, edit or reject a blocked thread.

```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

**Invite-only beta.** The installed version is whatever `pipx install yothere` resolves
to; `yothere --version` prints it, and the current release is on
[PyPI](https://pypi.org/project/yothere/) and in
[GitHub Releases](https://github.com/phios-ai/yothere/releases). What changed in each one:
[`CHANGELOG.md`](CHANGELOG.md). Beta walkthrough: [`docs/BETA-GUIDE.md`](docs/BETA-GUIDE.md).

Live today: the hosted cockpit and inbox at `app.yothere.ai` (invite-gated signup), up to
five parallel turns per paired machine, the code lane (a thread bound to a repo you already
have, working in its own git worktree), hosted voice with a daily cost cap, web push to a
phone, the send-gate and cost caps, and the BYO-compute leaser. Not live: scheduling (see
**Coming soon**).

Hosted voice runs a dedicated voice-worker app. The per-tenant `voice_media` flag still
defaults to `laptop`, so a new account is flipped to the hosted plane by hand until the
default moves.

Invites and support: [hey@yothere.ai](mailto:hey@yothere.ai).

## Contributing

Two people build yothere and neither should break `main` alone. Every change goes through
a PR, and the gate is green CI rather than the other founder: either of us merges our own
PR once the checks pass. See [`CONTRIBUTING.md`](CONTRIBUTING.md).

## License

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