# yothere

**Your agent fleet, hands-free.** yothere is the hands-free cockpit for your AI coding
agents (Claude Code, Codex, and OpenClaw): the fleet runs unattended on your own machine, yothere
routes only the decisions that need a human, and you answer by voice or one tap,
wherever you are.

The hosted cockpit lives at **[app.yothere.ai](https://app.yothere.ai)** (open beta,
first 7 days free with no credit card, then the Founding plan at $20/mo). 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. Sign up at https://app.yothere.ai/signup (7 days free, no card; then $20/mo) 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
#    A headless or SSH-only box pairs the same way: open the printed link in a browser
#    on any device. Unattended provisioning only: an operator mints a single-use token
#    on the control plane (yothere admin pair-token <email>) and you pass it with --token.

# 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/).

## 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), `openclaw` (OpenClaw CLI, local, observe/workspace tiers), 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 open signup behind
the Founding paywall 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, repo)`**: spawn thread(s) from a natural-language
  task; `repo` binds them to a registered workspace (fail-closed — an unknown repo
  spawns nothing and asks).
- **`board()`**: the fleet at a glance, needs-eyes first.
- **`reply(thread_id, text)`**: approve, edit or reject a blocked thread.
- **`list_workspaces()`**: the registered repos, so a coding agent can match its own
  working directory and delegate a separable chunk of its task to the fleet
  ([delegate from your editor](https://yothere.ai/docs/delegate-from-your-editor)).

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

**Open 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` (open signup, 7-day free
trial, then the Founding plan), 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.

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).
