yothere splits cleanly into two halves that never blur: a hosted cockpit that decides when you should look, and your own machine that does the actual work. This page walks that split from the browser down to the files on disk and the wire protocol between them.
The split, in one line
The hosted control plane (app.yothere.ai, on Fly with Postgres) runs the cockpit, the inbox, the job queue, the cost ledger, and hosted voice. It runs zero agent compute. Its own entrypoint is explicit: the Fly machine is the control plane only, and each tenant’s own machine leases a thread and runs the turn.
Your machine runs every agent turn. It runs Claude Code or the Codex CLI, on the subscription you already pay for. It reads your files, runs your tools, drafts your messages. yothere never receives your agent login and never receives your model credentials, and your files stay on your machine.
What does reach the control plane is the thread: the task you dispatched and the result your agent hands back, so you can see your fleet from a phone. A result is the agent’s own words, and it can quote whatever the agent read, so treat it as content. Privacy lists exactly what is stored.
A stolen control-plane record still cannot spend your subscription, because your subscription never touches the control plane.
The core loop
You hail a task. yothere creates a thread. Your machine leases the thread and runs the turn (the brain works). If the brain blocks on a decision, yothere pings you; your reply resumes the thread. Otherwise it finishes. Repeat until done.
Text version of the diagram: Hail, then Spawn thread, then your Machine leases and runs the turn while the brain works. If the thread is Blocked, yothere Pings you, You reply, and the thread Resumes. When nothing blocks, the thread reaches Done.
Threads are files
Everything about a thread lives in a directory on disk. Its live state is a status.json written atomically, so a reader never sees a torn file. Its session id lets a brain resume its own context turn after turn. There is no message bus in the hot path; the thread store is the source of truth.
This matters because of the ways yothere runs the same work. There are three execution substrates:
- Leased. How the hosted plane advances a thread. The control plane picks the next thread and offers it; your paired machine long-polls for a job, takes a lease, runs the turn locally, and pushes the result back. The lease is the cross-machine lock: exactly one machine holds a given thread at a time, and the database decides the winner of a racing claim. This is the product path.
- Headless. The runner loop running as a background service on one box, advancing threads on its own and enforcing the cost caps. This is the local development path.
- In-session. A governed agent tool running inside a host application. It can spawn threads, read the board, and reply, but it draws a hard line at outward actions and blocks for your approval.
The contract between them is the thread store, not the process. All three write through the same thread status and the same cost ledger, so they operate on one fleet without a shared process or socket.
Brains and the Brain Protocol
A brain is what does the work. Three ship today: Claude Code, the Codex CLI, and OpenClaw, all running on your machine, on your login. Those three are local CLIs, and yothere drives them as subprocesses (claude -p, codex exec, openclaw agent --local) behind a backend seam (harness/base.py).
Brain Protocol v1 is the other seam: the one a brain that is not a local CLI speaks. The transport is a WebSocket carrying JSON-RPC 2.0 text frames (one JSON object per frame). yothere opens a fresh connection per turn and closes it when the turn ends, which makes barge-in structurally clean: closing the socket aborts the turn. Nothing we plan to build requires you to implement it; it exists so a third-party or remote brain can be plugged in.
The methods yothere calls on such a brain:
hello. A handshake. yothere learns the brain’s name, protocol version, and capability flags, and gates on the version.streamSubscribe. Opens a streaming channel for the next prompt and returns a subscription id.turn(also accepted asprompt). Runs one turn. The key parameter isconversation_id, the join key for context continuity: the brain owns context server-side keyed by this id, so the same id across turns and reconnects means the same conversation.sessionStatus(optional). Reads a conversation’s state without running a turn, so a client with no local thread files (a phone, a web cockpit) can render the fleet.cancelandclose. Abort an in-flight turn, and tear down a conversation. Both are best-effort; yothere also just closes the socket.
During a turn the brain streams back JSON-RPC notification frames (method: "stream"):
delta(required). Token text appended to the running answer.progress(optional). Tool activity, so the cockpit shows what the turn is doing right now instead of a stalled card.status(optional). The thread state (working,blocked,needs_input,done). This is what drives the attention router.cost(optional). A spend report.
The turn ends on the first done: true stream frame or the id-bearing result answering the turn request. Full details and a minimal implementation are in Agent onboarding.
hello gate warns on mismatch.The runner and the attention router
The runner is the headless advance engine, one tick roughly every 30 seconds. Each tick it reaps finished workers, sweeps stale threads to stuck, checks the cost caps, asks the attention router which threads to advance (bounded by max concurrency and a per-thread cooldown), and spawns one worker subprocess per chosen thread.
Up to five work turns advance at once. Typed replies draw from a separate pool on top of that (two on a paired machine), so a question you type never queues behind the work.
The attention router is the deterministic core the runner leans on. It is offline-first (no model call, no online learning), so it is fully unit-testable and never stalls on a network hop. It scores the fleet, recommends one focus thread, and gives a thread you pin a large score bonus, which lifts it over the ordinary fleet without overriding it (an urgent thread still scores higher). The hosted planner reuses the exact same ranking to decide which of your threads to offer your machine next. Its full behavior and the cost-cap numbers are in Core concepts.
The send-gate
A worker turn is genuinely unattended: it runs with bypassPermissions, in the directory you point it at (YOTHERE_WORK_DIR is the turn’s cwd, not a sandbox boundary). The send-gate is a PreToolUse hook, injected by yothere into every worker turn, that denies outward actions until a human approves them. An agent that decides to email someone stops at you: the worker writes a blocked status and asks. Your approval mints a single-use, thread-scoped grant that opens exactly that one send.
git push, gh api and the mutating gh subcommands are on a never-grant list. No approval can open them for a worker turn, so an agent can never publish. You can: press Ship it on the diff and yothere pushes the branch and opens the PR as you, host-side, outside the turn, as plain git with no model in the loop. It is the strongest rule in the gate, not a sandbox guarantee.
The code lane
A thread can be bound to a git repo you already have on this machine (yothere workspace add <name> <path>, then yothere spawn --repo <name> "fix the layout shift on the pricing page"). yothere never clones and holds no git credential.
A bound thread does not run in the one shared work directory, and it does not run in your checkout. Its turns run in a git worktree of that repo, under ~/.yothere/worktrees/, on a branch of its own (yothere/<thread-id>-<slug>). Three code threads are three worktrees and three HEADs, so they cannot collide with each other or with what you are editing, and each branch is a clean diff by construction. The agent commits there and reports the sha.
Be precise about what the worktree buys: parallel safety and a clean diff, not containment. A worker turn runs with permissions bypassed and can write outside its cwd, so the worktree is isolation between threads, not a jail. What keeps the work on your machine is the never-grant list: the branch is where the agent stops and you take over.
Where it runs
Two run modes exist, selected by configuration:
- Hosted (the product). A login is required, and each account is scoped to its own isolated home, so two logins see two separate fleets with no cross-tenant read. Access is open during the beta: sign up, the first 7 days are free (no credit card), then the Founding plan is $20/mo. The cockpit, the queue, and voice run on the control plane; every agent turn runs on your machine.
- Local single-user (a development path). No login, and the cockpit and its live stream are served on
127.0.0.1:8767. Useful for hacking on yothere or on a brain, not the supported way to run the product.
Local state lives under ~/.yothere (YOTHERE_HOME), and the device credential at ~/.yothere/credentials.json (mode 0600) carries no compute keys. The knobs for both modes live in Configuration.