Appearance
How it works
This page is for technical readers. It describes the beta as built.
The pieces
| Piece | What it is | What it owns |
|---|---|---|
| Relay (the daemon) | A Node process bundled inside the app. Vistara starts it at launch, checks its build, and replaces a stale copy. It listens on 127.0.0.1:47321 and requires a bearer token stored in ~/.vistara-relay/local-token. | The append-only event log (SQLite, ~/.vistara-relay/relay.db), held approvals and questions, the per-session and per-project Workstate, the local policy, and repo verification. |
| Menu-bar app | An Electron app with no Dock icon. | Cards near the cursor, the ⌘⇧Space overlay, the session inventory, reply delivery, Send work, the MCP server, the Points page, diagnostics. |
| Hooks | Entries Vistara adds to Claude Code's ~/.claude/settings.json (HTTP hooks to Relay) and Codex's ~/.codex/hooks.json (a command hook that runs Relay's codex-hook). | Telling Relay what each session does, and carrying your answer back to a held request. |
| Inbox sockets | Claude Code's own per-session message socket. | Delivering a reply to a live Claude session in any tab, busy or idle. |
| Transcripts | Files your agents already write: ~/.claude/projects/…, ~/.codex/sessions/…, Cursor's transcripts and its chat database. | The inventory of sessions and the live conversation view. Read only. |
| Work graph | A local index of terminals, browser tabs and apps, refreshed every 60 seconds. | Search in the overlay. Browser tabs and Warp are added only if you turn them on. |
The app reads the session inventory every 10 seconds. Hooks are faster: Relay pushes a held request to the app as soon as the agent asks.
Data flow
Hooks
When you connect your agents, Vistara adds these entries. It never touches your own hooks, and every file is backed up before it is changed.
Claude Code (~/.claude/settings.json, HTTP hooks to Relay with a bearer token):
| Hook | Relay endpoint | Timeout | Purpose |
|---|---|---|---|
PermissionRequest | /v1/hooks/claude/permission | 600 s | An approval Claude would ask you for. Held for a card. |
PreToolUse on AskUserQuestion | /v1/hooks/claude/question | 600 s | A question with options. Held for a card. |
Stop | /v1/hooks/claude/stop | 120 s | A turn whose last paragraph ends with a question to you. Held so a typed reply can continue the turn. |
SessionStart, UserPromptSubmit, PostToolUse, PostToolUseFailure, Notification | /v1/hooks/claude | 5 s | Evidence for the Workstate. |
Codex (~/.codex/hooks.json, a command hook): PermissionRequest (600 s), plus SessionStart, UserPromptSubmit, PostToolUse and Stop (10 s each).
Hook timeouts are longer than Relay's hold, so Relay always answers first. If Relay is not running, Claude Code treats the failed HTTP hook as a non-blocking error and shows its normal prompt. Installing hooks cannot wedge an agent.
How Attention holds work
When an agent asks for something, Relay decides in this order:
- Policy. Relay checks the request against your local policy. If the policy allows or denies it, Relay answers at once and no card appears. See The local policy.
- Is anyone watching? Relay holds a request only while the Vistara app is connected. If the app is closed, the request passes straight through to the agent's own prompt.
- Hold. Relay opens an attention item and keeps the hook's HTTP request open. The app shows a card near your cursor. The agent waits; its terminal shows a spinner rather than the question.
- Resolve. One of four things ends the hold:
| What happens | Result for the agent |
|---|---|
| You click an option or type an answer | The hook returns your decision. Claude or Codex continues with it. |
| You press Esc on the card | Relay releases the request at once. The agent shows its own prompt in the terminal. |
| 60 seconds pass | The item expires. The agent shows its own prompt. |
| The agent hangs up (you answered in the terminal, or it quit) | The item closes as abandoned. |
The hold is 60 seconds for Claude permissions and questions, for Codex permissions, and for Claude Stop replies. Repeated identical requests from the same session collapse into one card. When Relay shuts down, it releases every held request so agents fall back to their own prompts.
Codex has one extra case: after the hold ends, Codex asks in its own terminal. The card then says so honestly, rather than offering a button that can no longer reach Codex.
The local policy
The policy lives in ~/.vistara-relay/policy.json. If the file is missing, defaults apply. If it cannot be read, Relay asks you about everything; a broken policy never widens what agents may do.
By default, auto-approve is on. It allows:
- read-only and routine commands inside the session's working folder, such as
ls,git status,git diff,git commit, and test, lint, typecheck and build commands; - reads and edits of files inside the working folder;
- Codex patches that add or update files inside the working folder.
It always sends these to you, whatever your allow list says: commands such as sudo, rm -rf, git push --force, git reset --hard; anything outside the working folder; secret-bearing files; writes inside .git; changes to Vistara's or the agents' own settings; shell constructs it cannot read reliably (substitution, redirects, piped interpreters); deleting files through a patch; and web fetches to hosts not on your allow list.
You can set "autoApprove": false to see every request, and add askCommands, denyCommands, allowCommands and allowDomains. Vistara never auto-denies anything unless you wrote a deny rule. There is no settings screen for the policy yet.
Toward the mandate
This policy is a first, local step toward the mandate in the whitepaper. It is not signed and has no budgets, network rules or sandbox. Those are Planned.
Workstate v0
Workstate v0 is where a project or session stands right now. Relay computes it only from the event log and open attention items. The same events always give the same state, in any order. No model decides it.
Agents. One row per session. A session is working if its last event is less than 3 minutes old and is not the end of a turn; otherwise it is waiting. Sessions seen in the last 30 minutes are listed.
Checks. Relay looks at shell commands the agents ran (from PostToolUse hook events) and classifies them:
- tests:
vitest,jest,pytest,mocha,cargo test,go test,npm test,pnpm test,make test, and similar; - build:
tsc,npm run build,pnpm typecheck,cargo build,go build,next build,xcodebuild, and similar.
A run passes or fails by its exit code when the agent reports one, otherwise by the runner's output (for example "3 failed" or "error TS2345"). The summary shown is short, such as "84 passed", never raw output. A check result becomes unknown as soon as a file is edited after it, so a pass never outlives the code it tested.
Status. The first rule that matches wins:
| Order | Status | When |
|---|---|---|
| 1 | needs_user | One of this project's sessions has an open, held approval, question or reply. Next: "Answer: …". |
| 2 | running | The latest agent event is under 3 minutes old and is not the end of a turn. |
| 3 | blocked | The same check failed twice in a row. Next: look at the failure with the agent. |
| 4 | failed | The latest tests or build failed. Next: ask the agent to fix it. |
| 5 | done | The latest tests or build passed. Next: review and ship. |
| 6 | waiting | None of the above. Next: reply to the agent. |
Last change. The latest check result ("Tests: 84 passed") or, if files changed after it, the files edited ("Edited api.ts, routes.ts").
Repo verification
When a Claude Code or Codex session stops in a git repo whose working tree changed since the last check, Relay waits a few seconds and then:
- snapshots the working tree, untracked files included, into a commit using a temporary index (your index and files are not touched);
- checks that snapshot out into a separate
git worktree; - runs the repo's own checks there (
typecheck,lintandtestscripts frompackage.json,pytestwhen the repo has a pytest config,cargo test,go test,make test, or a.vistara/verify.jsontaken from the base commit); - compares base to snapshot for test-integrity problems, such as removed or weakened tests;
- removes the worktree.
A check script that the agent changed in this work is not run automatically, and the card says so. Results are recorded as evidence. Only a failure interrupts you: if the agent changed files and the checks or the integrity check fail, a review card appears. Passing results stay in the Workstate. You can turn this off with "verify": false in the policy file.
Toward V0–V3 verification
This is a narrow form of the whitepaper's V1 (acceptance) and V2 (integrity) checks, run against the repo's existing checks rather than against a goal written in advance. Goals with acceptance criteria and the full V0–V3 levels are Planned.
How replies are routed
A reply comes from a card, from the overlay's reply box, or from an option button. Vistara sends it only when you click or press Enter, and tries the most exact route first:
| Order | Route | When it is used |
|---|---|---|
| 1 | Hook | The agent is holding a request for this answer: a Claude approval, question or Stop reply, or a Codex approval. The answer goes back as the hook's response. Nothing is typed. |
| 2 | Inbox socket | The session is a live Claude Code session. Vistara finds its process from ~/.claude/sessions/ and writes one message to its inbox socket. This works in any tab or window, whether the session is busy or idle. The message reads "The user replied from Vistara…". |
| 3 | Terminal typing (opt-in) | The agent has no hook path, Terminal typing is on, and a Warp window's title exactly matches the session's own title. Vistara raises that window, checks it is in front with that title, pastes your reply and presses Enter, then restores your clipboard. A title shared by two sessions is treated as ambiguous. If the agent is showing a menu, free text is copied instead, and option buttons send a single keystroke. |
| 4 | Clipboard | None of the above applies. Vistara copies your reply and says so on the card before you click. |
Vistara confirms a typed reply by watching the agent's history for your text rather than assuming it arrived.
Replies cannot approve permissions. A permission is granted only by the hook response, which comes from your click on an approval card or from your local policy. A message delivered through the inbox socket or a Stop-hook reply is presented to the agent as text from you; it does not answer a permission prompt.
The overlay
⌘⇧Space opens a translucent panel from any app. Esc closes it and returns focus to the window you came from. Opening it never types, switches tabs or opens sessions.
- Today: asks handled and median answer time, what is waiting on you, what finished, and one row per project with its agents, status and checks. If you were away, a While you were away section lists what finished, asked or was verified.
- Needs you: only sessions that are actually waiting on a decision.
- A session: its status, checks, last change, what you asked it, the live conversation streamed from its transcript, a reply box and Send work…. ⌘C copies its resume command.
- Search: type in the box at the top for one ranked list across agents, terminals and (if enabled) browser tabs. Enter acts: focuses a reply, brings a browser tab forward, activates an app, or copies a path or a resume command.
- Points: your node. See Points and Vistara Node.
What the beta does not do
- It does not run agents for you or start work on its own. It works with sessions you start.
- It does not sandbox agents, enforce budgets or restrict network access.
- It does not read your screen or keystrokes.
- It does not use a remote model. If you have Ollama installed, the app can use it locally to add one line of context to a card; the card works without it.