docs GitHub

Using VyreDraft

How Vyre runs your sessions

Every session Vyre starts, from Chat, the Lumen on your Mac, your phone, an agent, the planner or a learning job, is a real session that Vyre runs and keeps on your own server. It carries on after you close a window, and every surface you use sees the same conversation. A claude you start yourself in a terminal stays yours: Vyre follows it through the plugin and never takes it over. The two kinds write the same transcripts, so either can pick up the other. The decision behind this is ADR 0030.

Four providers, your own accounts

A session runs on one provider at a time, and each provider runs from an account of yours.

ProviderHow it runsAccount you bring
ClaudeClaude Code, on the Claude Agent SDKA Claude sign-in or setup token, or an Anthropic API key
CodexCodex, over the Agent Client ProtocolA ChatGPT sign-in, or an OpenAI API key
GrokGrok Build, over the Agent Client ProtocolA Grok sign-in, or an xAI API key
OpenRouterChat over HTTPAn OpenRouter API key

OpenRouter answers in words only. It has no tools, so it never asks a permission question and cannot touch a file or run a command; it is there so a conversation can carry on when everything else is out of usage. Codex and Grok cannot be steered mid-turn or rewound, and the effort levels are Claude's only.

You connect Claude when you set up Vyre, or later in Settings, with the provider's own sign-in: you open its page, enter the code it shows, and the token goes into that account's own private folder, which Vyre never reads. An account can also hold an API key from the Vault. Store the key, let sessions read it, and add the account:

vyre vault put openrouter-key --kind api-key
vyre vault grant openrouter-key threads
vyre call sessions.accounts.add '{"provider":"openrouter","label":"work","kind":"api-key","vault_item":"openrouter-key"}'

A provider can have several accounts. An account can be limited to some projects or agents, and sessions.accounts.list shows each one with its plan and, for a sign-in, who it is signed in as. On a server, each account runs as its own user, so one account's sign-in cannot be read from another's. An account that an agent started stays pending until you finish it on your own device.

Your own sign-in on a team's server

When you join a team's server, you sign in your own AI there: Settings, Accounts, sign in with Claude, Codex or Grok. The provider shows you its page and a code, you approve it, and the sign-in lives in a folder that belongs to that account alone. Your turns in a shared chat run on it, and no one else's do: not the owner's, not another member's. The owner cannot list it, use it or read it. You can have one sign-in account on the server; to change it, remove it first. An API key is not offered to members yet, because a key sits in the server's Vault, which is the owner's. Members' own Vaults come in 0.3.4.

What a vendor sees

A sign-in session (Claude, Codex or Grok on your own subscription) talks to its own vendor with your own sign-in. Vyre keeps the session: the transcript, memory, tools and the Gate that holds a send for your yes are Vyre's, and what you type is checked for keys before the vendor hears it; what the model prints is checked for keys before it reaches the transcript. Vyre does not check a sealed customer value you typed into the chat against the session's record of what it has used: the vendor is your choice, and the Gate still holds anything that leaves your Space. A session on an API key (OpenRouter, an OpenAI-compatible address, or a Codex or Grok account that holds a key) goes through Vyre's model door instead. Vyre checks each piece of text as it arrives, so a key that a model prints split across two streamed pieces is caught only in the whole message that follows; the half-finished text on your screen while it streams can briefly show part of it.

One picker per session

Chat has one chip above the message box that says who answers, the model and the effort, for example "Codex · GPT-5 high", with the provider's logo. Press it to open Answer with: each signed-in account, the models under it, and (for Claude) the effort levels. The choice applies from the next turn.

  • Picking another account moves the same session, folder and files to that provider between turns. The new provider is given a short brief of what was said so far, and the session says so in the thread, for example "Switched to Codex. It has this session's memory and files.", with a line on anything the new provider cannot do. Switching while a turn runs is refused until you stop it or it finishes.

  • Switching back to a provider that ran this session before returns to its own memory of the session: "Back on Claude. It has this session's memory and files, and what Codex said this turn."

  • Every reply carries the logo of the provider that wrote it, and a reply keeps its logo after you switch.

  • When a provider's usage runs out and you have set a fallback order, the session moves to the next one by itself and says "Claude's limit was reached. Switched to Codex." The order is per project, per agent or for the whole machine, for example Claude, then Codex, then Grok:

    vyre call sessions.routes.set '{"scope":"default","entries":[{"provider":"claude"},{"provider":"codex"}]}'
    

    Two entries on one provider (two accounts of one vendor) can break that vendor's terms, so Vyre saves them only with "acknowledge": true, after you have read the warning.

One message on another provider

Start a message with @codex or @grok (or @claude, @openrouter) to send that one message to that provider. The session keeps its own provider. The other provider gets the session's memory and files, its reply carries its logo, and the session is told what was said while it was away. When a provider has several accounts, the word is the name with the account's label, such as @codex-work, and the message box shows "This turn runs on" the account that will answer. Only the first word of the message counts. If that account is signed out or out of usage, Vyre says so in plain words and sends nothing; it never falls back to another one.

What runs them

Vyre runs Claude sessions on the Claude Agent SDK, which runs Claude Code itself. The SDK is installed on first use into ~/.vyre/sessions-sdk (on a box, the home's volume), and sessions run directly on the claude command until it is ready. To install it now and wait:

vyre sessions setup

vyre sessions status says which driver is in use, which sign-in, which Claude Code, and whether the SDK is installed.

Setting (sessions in config.json)Box defaultMac defaultWhat it does
driversdksdksdk runs sessions on the Agent SDK; cli on the claude command. Until the SDK is installed, sessions run on claude either way.
authsetup-tokenloginThe Claude sign-in sessions use when no account is named. setup-token is the token you gave during setup, kept in the vault; login is Claude Code's own sign-in on that machine; api-key is the API key in the vault.
claudebundledinstalledWhich Claude Code: the one the SDK ships, the claude you installed, or a path.
idle_minutes1010A session nobody is using closes after this long, and comes back on your next message. 0 keeps them open.
max_live60 (none)At most this many sessions running at once. The one idle longest closes to make room; when all are busy, a new one is refused until one finishes.

When your Claude subscription's limit is reached and an Anthropic API key is in the vault, a session carries on under the key and says so in the thread. With a fallback order set (above), it moves to the next provider instead.

Which model

This is the model for a Claude session before you pick one in the chip. Real work runs on Opus: Chat, agents, teammates and project sessions. Quick answers and background jobs (Lumen quick asks, memory, the planner, learning, any one-shot job) run on a faster, cheaper model, haiku by default. An agent's own model wins, and you can change any of it:

vyre call sessions.models.get
vyre call sessions.models.set '{"scope":"purpose:capsule","model":"sonnet"}'
vyre call sessions.models.set '{"scope":"project:northwind-bakery","model":"opus"}'

sessions.models in config.json sets the defaults per purpose (chat, agent, project, teammate, capsule for Lumen, job, memory, planner, learn, helper); vyre sessions models takes the first eight and the others are set with sessions.models.set. A thread shows its model on its chip.

Effort, as /effort in Claude Code: low, medium, high, xhigh or max (the model's own limits apply). The picker offers it for Claude sessions. An agent's saved Effort is used for its sessions. Change a running session's at once, and it stays with the session when it comes back:

vyre call threads.effort '{"thread":"<id>","effort":"high"}'

A send can switch both first: threads.send {thread, text, model: "opus", effort: "max"}. In Lumen, Command-Return inside an answer's own thread asks the deeper model (sonnet) and turns thinking on.

Your existing sessions

Every session is in one list, whether a terminal, Vyre, your Mac or your box started it. Send one a message from Chat and Vyre resumes it where it ran, on the machine that has it; from then on it works like any session Vyre started. If it is open in a terminal right now, your message waits and is handed over when that terminal's turn ends, or you can fork it: threads.fork carries on the conversation as a copy, and the terminal's session is never touched.

Permission modes

threads.mode puts a running session in default (asks), acceptEdits (edits without asking) or plan (reads and plans only), as Shift+Tab does in Claude Code, or "Doesn't ask" (below). Only you can change a mode; a session or an agent never can, and no answer to a question ever does.

Doesn't ask

"Doesn't ask" (Claude Code's bypassPermissions) runs a session without permission questions. You turn it on yourself, with no Touch ID: for one session, as Shift+Tab does, or as a project's default for new sessions there.

vyre call threads.mode '{"thread":"<id>","mode":"bypassPermissions"}'
vyre call sessions.mode.set '{"project":"northwind-bakery","mode":"bypassPermissions"}'
vyre call sessions.mode.set '{"project":"northwind-bakery"}'    # back to asking

What still holds: Vyre's safety checks run before every tool call (writes to your settings or Vyre's state, secrets, and the rest of its rules are refused), and the Gate still holds outbound actions. Only a person sets it: no answer to a question, no model and no agent can, and a session's own tools cannot. A session started without Vyre's plugin (a quick answer) refuses it. The mode carries over when an idle session comes back.

Closed when idle, back on the next message

An idle session holds memory on the machine. So a session with no turn running, no question waiting, nobody at its keyboard and no watch on it is closed after idle_minutes. Its thread shows "paused", and your next message resumes it where it was: the same conversation, the same transcript. Nothing is lost.

Messages while it works

A message you send while a Claude session is working joins the running turn at Claude's next step, as in Claude Code (steering). Send with mode: "queue" to wait for the turn to end instead; a queued message can be edited, taken back or sent now until then. Pasted images go with either. Steered words that a stop or a restart cut off before Claude took them in are kept, and run first when the session comes back.

Near your plan's limit

Claude Code reports how much of your plan's window is used. When a Claude sign-in is near its limit (a warning, 80 percent used, or refused), Vyre stops starting new subagents and teammates on it until the window resets; sessions already running carry on. To go on anyway, or to turn the pause off:

vyre call sessions.usage.get
vyre call sessions.usage.resume '{"auth":"subscription"}'

"pause_at_warning": false under sessions in config.json turns it off.

Stop a turn

threads.interrupt (vyre threads interrupt <thread>) stops the turn a session is running, as Escape does in Claude Code. The session stays and takes your next message. Any question that turn was waiting on is cancelled.

The system prompt

What every Claude session is told can be edited at three levels:

LevelScopeApplies to
The assistantassistantYour assistant's sessions and every session no agent runs
An agentagent:<name>That agent's sessions
A projectproject:<slug>Every session in that project

By default your text is added after Claude Code's own system prompt, which keeps its tool use, safety and coding behaviour. More specific levels come after more general ones.

vyre call sessions.prompt.set '{"scope":"assistant","text":"Answer alex in short paragraphs."}'
vyre call sessions.prompt.set '{"scope":"project:northwind-bakery","text":"Prices are in dollars with two decimals."}'
vyre call sessions.prompt.preview '{"project":"northwind-bakery"}'

An edit applies from the next session, never to one in the middle of a conversation.

Every edit is a version. A bad edit is undone by going back to an older version, and going back is itself a version, so it can be undone too:

vyre call sessions.prompt.history '{"scope":"assistant"}'
vyre call sessions.prompt.revert '{"scope":"assistant","version":1}'

Replace, for experts. "mode":"replace" makes your text the whole system prompt. This drops Claude Code's own instructions (tool use, safety and coding behaviour), and the reply to the edit says so. Vyre's own rules for the session (who it works for, that you answer its permission questions) are still added after your text.

Only you can edit a system prompt. No agent, model or tool call from inside a session can, its own least of all.

Lumen's quick answer (Vyre Memory)

A question you ask in Lumen runs as a small session on the fast model with its own prompt: it is Vyre Memory, it answers only from the facts Lumen showed you for the same words, cites them by number ([1]), and says "I don't know yet." in one line when none of them answers. It never talks about its access or tools, answers in one to three sentences, and fixes your typos without saying so. Thinking is off, so the same words get the same answer. The prompt is versioned (capsule@2, or capsule@own-<n> once you add your own), and the version is on the thread's start.

To add a line of your own, or replace it, use scope capsule, versioned and undoable like the others:

vyre call sessions.prompt.set '{"scope":"capsule","text":"Call me alex."}'
vyre call sessions.prompt.preview '{"purpose":"capsule"}'

npm run eval:iq asks the model eleven fixed questions twice each with your own Claude sign-in and says which answers break a rule or change between runs.

Each session's own line to Vyre

On a server that runs sessions as their own user, a session cannot open Vyre's own socket. Vyre opens one for each session instead and hands it over as VYRE_SOCKET: the session's Vyre tools, its hooks and any vyre command it runs go through it, as that session, whatever they claim to be, and your own tools (answering, approving, modes) are never reachable from it. It closes when the session stops. sessions.thread_socket (auto, on, off) controls it; auto opens one only where sessions run as their own user.

Vyre from the shell, inside a session

A session that runs in the sandbox has vyre on its path, for models that work through the shell. It is the same vyre you use, in session mode, with three forms:

  • vyre tools find "send an email" lists the tools that fit those words, each with a ready call.
  • vyre tools describe mail.send says what a tool does and what input it takes.
  • vyre call mail.send '{"to":"[email protected]","subject":"Hello","body":"Hi"}' runs it.

It acts as the session, over the session's own socket: the same registry, the same one-yes rule, the same Gate. A send is held for your approval and the output says nothing ran. Your own tools and the vault are not there, and every command that works on the computer itself (update, up, down, setup, vault, keys, config) is refused with a line that points at vyre tools find, and the shell still cannot read Vyre's home or data folders. The floor lets these three forms through without a question; a longer shell line that merely mentions vyre is judged like any other. A session that is not in the sandbox does not get it.

Open in terminal

vyre resume <thread> opens any thread in claude in your terminal, where it ran. A session Vyre is running is handed over first: if it is idle Vyre closes it, and your terminal takes it. If it is in the middle of a turn or waiting on a question, it is left alone and the command says so. A message from the Vyre app or Lumen after you exit brings it back to Vyre.