@oar-sh/oar 0.9.5 → 0.9.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/extensions/web-relay/polling/polling-loop.mjs +12 -32
- package/.github/extensions/web-relay/skills/question-bridge.mjs +14 -39
- package/CHANGELOG.md +340 -0
- package/README.md +196 -26
- package/package.json +2 -1
- package/server/README.md +174 -7
- package/server/claude-cloud-worker/claude-cloud-event-normalizer.mjs +340 -0
- package/server/claude-cloud-worker/claude-cloud-session-process.mjs +1325 -0
- package/server/claude-cloud-worker/claude-cloud-session-worker.mjs +155 -0
- package/server/claude-worker/claude-remote-relay-tool.mjs +2 -0
- package/server/claude-worker/claude-sdk-adapter.mjs +18 -2
- package/server/claude-worker/claude-session-process.mjs +151 -1
- package/server/claude-worker/claude-session-worker.mjs +6 -0
- package/server/claude-worker/claude-turn-failure.mjs +92 -0
- package/server/claude-worker/claude-turn-publisher.mjs +52 -3
- package/server/claude-worker/sdk-message-normalizer.mjs +13 -1
- package/server/copilot-worker/copilot-model-switch.mjs +29 -3
- package/server/copilot-worker/copilot-question-bridge.mjs +2 -4
- package/server/copilot-worker/copilot-runtime-tree.mjs +91 -0
- package/server/copilot-worker/copilot-sdk-adapter.mjs +48 -8
- package/server/copilot-worker/copilot-sdk-session-process.mjs +897 -166
- package/server/cursor-worker/cursor-sdk-adapter.mjs +80 -13
- package/server/cursor-worker/cursor-turn-runner.mjs +5 -2
- package/server/db-schema.mjs +24 -0
- package/server/grok-worker/acp-client.mjs +68 -12
- package/server/grok-worker/grok-sdk-adapter.mjs +4 -0
- package/server/grok-worker/grok-turn-runner.mjs +6 -2
- package/server/migrations/0006-workspace-root-settings.mjs +67 -0
- package/server/migrations/0007-claude-cloud.mjs +82 -0
- package/server/public/app/agent-sessions-settings-ui.js +197 -0
- package/server/public/app/agent-sessions-settings.mjs +134 -0
- package/server/public/app/api-client.js +160 -6
- package/server/public/app/attachments-view.js +20 -1
- package/server/public/app/attribution-control.mjs +46 -0
- package/server/public/app/bootstrap.js +347 -31
- package/server/public/app/claude-cloud-conversation-ui.js +110 -0
- package/server/public/app/claude-cloud-settings-ui.js +374 -0
- package/server/public/app/claude-cloud-ui.mjs +611 -0
- package/server/public/app/composer-control-state.mjs +15 -3
- package/server/public/app/context-menu.mjs +140 -0
- package/server/public/app/context-tier-options.mjs +4 -0
- package/server/public/app/conversation-origin-ui.js +27 -0
- package/server/public/app/conversation-provider-indicator.mjs +22 -4
- package/server/public/app/conversation-view.js +178 -8
- package/server/public/app/cwd-picker.js +12 -0
- package/server/public/app/journal-view.js +704 -28
- package/server/public/app/markdown-strikethrough.mjs +31 -0
- package/server/public/app/math-dollars.mjs +89 -0
- package/server/public/app/model-selector-options.mjs +1 -1
- package/server/public/app/plan-usage-view.mjs +36 -8
- package/server/public/app/relay-board-inline.mjs +70 -0
- package/server/public/app/relay-board-view.js +157 -61
- package/server/public/app/relay-error-ctas.mjs +28 -5
- package/server/public/app/remote-relay-origin-view.mjs +120 -4
- package/server/public/app/router.js +49 -12
- package/server/public/app/settings-modal.js +33 -2
- package/server/public/app/settings-tabs.js +1 -1
- package/server/public/app/socket-handlers.js +60 -0
- package/server/public/app/store.js +4 -1
- package/server/public/app/subagent-fold.mjs +61 -0
- package/server/public/app/usage-limit-ui.js +225 -0
- package/server/public/index.html +471 -8
- package/server/relay-tools.md +13 -1
- package/server/repositories/message-repository.mjs +10 -1
- package/server/repositories/question-repository.mjs +1 -0
- package/server/repositories/remote-relay-repository.mjs +72 -1
- package/server/repositories/session-repository.mjs +47 -1
- package/server/routes/claude-cloud-routes.mjs +140 -0
- package/server/routes/git-routes.mjs +37 -0
- package/server/routes/messages-routes.mjs +202 -26
- package/server/routes/relay-board-routes.mjs +56 -2
- package/server/routes/remote-relay-routes.mjs +15 -1
- package/server/routes/sessions-routes.mjs +538 -72
- package/server/server-runtime.mjs +291 -27
- package/server/services/claude-account-usage-service.mjs +176 -0
- package/server/services/claude-cloud-repo-service.mjs +408 -0
- package/server/services/claude-cloud-session-service.mjs +326 -0
- package/server/services/claude-cloud-settings-service.mjs +269 -0
- package/server/services/git-remote-service.mjs +115 -0
- package/server/services/plan-usage-claude-cloud.mjs +211 -0
- package/server/services/plan-usage-claude.mjs +202 -40
- package/server/services/plan-usage-contract.mjs +39 -3
- package/server/services/plan-usage-service.mjs +82 -2
- package/server/services/preview-proxy-server.mjs +64 -36
- package/server/services/process-list-service.mjs +122 -0
- package/server/services/provider-reasoning-effort.mjs +3 -0
- package/server/services/relay-console-log.mjs +199 -0
- package/server/services/remote-relay-caller-context.mjs +78 -19
- package/server/services/remote-relay-client.mjs +9 -0
- package/server/services/remote-relay-dispatcher.mjs +451 -39
- package/server/services/remote-relay-inbound.mjs +83 -1
- package/server/services/remote-relay-loopback.mjs +245 -0
- package/server/services/remote-relay-registry-service.mjs +52 -0
- package/server/services/session-worker-launch-service.mjs +100 -15
- package/server/services/session-worker-process-service.mjs +410 -138
- package/server/services/session-worker-registry-service.mjs +1 -1
- package/server/services/session-worker-stop-service.mjs +24 -13
- package/server/services/session-worker-supervisor-service.mjs +89 -2
- package/server/services/usage-limit-pause-service.mjs +443 -0
- package/server/services/worker-launch-note-service.mjs +151 -0
- package/shared/ask-user-bridge.mjs +14 -39
- package/shared/claude-attribution.mjs +117 -0
- package/shared/claude-cloud/api-client.mjs +809 -0
- package/shared/claude-cloud/base-url.mjs +47 -0
- package/shared/claude-cloud/credentials.mjs +221 -0
- package/shared/claude-cloud/repo-url.mjs +111 -0
- package/shared/claude-usage-limit.mjs +257 -0
- package/shared/control-poller.mjs +69 -20
- package/shared/failure-note-text.mjs +38 -0
- package/shared/provider-routing.mjs +4 -2
- package/shared/question-wait.mjs +108 -0
- package/shared/remote-relay-contract.mjs +167 -22
- package/shared/remote-relay-tool-core.mjs +11 -8
- package/shared/steer-settle-failure.mjs +17 -0
- package/shared/steer-settle-markers.mjs +8 -0
- package/shared/worker-runtime/process-tree.mjs +483 -0
- package/shared/worker-runtime/relay-errors.mjs +31 -0
- package/shared/worker-runtime/send-and-wait-errors.mjs +4 -4
- package/shared/worker-runtime/turn-liveness.mjs +249 -0
package/README.md
CHANGED
|
@@ -8,13 +8,14 @@ curl -fsSL oar.sh/install | sh
|
|
|
8
8
|
|
|
9
9
|
On Windows, run `irm oar.sh/install.ps1 | iex` in PowerShell. Landing page: [oar.sh](https://oar.sh). npm and git-checkout installs are covered under [Install](#install).
|
|
10
10
|
|
|
11
|
-
OAR relays
|
|
11
|
+
OAR relays seven runtimes: **GitHub Copilot**, **OpenAI (BYOK)**, **OpenAI Image (BYOK)**, **Claude (Agent SDK)**, **Claude Cloud**, **Cursor (Agent SDK)**, and **Grok (CLI ACP)**. You pick one per conversation, and all of them share the same chat UI, queue, history, file browser, and question cards.
|
|
12
12
|
|
|
13
13
|
```text
|
|
14
14
|
┌── Copilot SDK worker, or Copilot CLI + extension
|
|
15
15
|
├── OpenAI Copilot runtime, your API key
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
├── OpenAI Image Images API, called by the relay
|
|
17
|
+
[Browser] <--WebSocket--> [OAR relay :3333] ┼── Claude Agent SDK worker, host's Claude login
|
|
18
|
+
├── Claude Cloud sandbox at Anthropic, host's Claude login
|
|
18
19
|
├── Cursor Agent SDK worker, your Cursor API key
|
|
19
20
|
└── Grok Grok CLI over ACP, host's Grok login
|
|
20
21
|
```
|
|
@@ -65,6 +66,7 @@ You need Node.js plus whatever the runtimes you actually use need. Nothing else
|
|
|
65
66
|
| GitHub CLI (`gh`), signed in | the `oar` launcher command; Extension-engine sessions on Windows; the Copilot card in **Check Usage** | `gh copilot` is built into current GitHub CLI releases, so there is no extension to install. The usage card also accepts a token in `GH_TOKEN` or `GITHUB_TOKEN` |
|
|
66
67
|
| OpenAI API key | OpenAI and OpenAI Image chats | Entered in **⚙️ Settings**, stored in the relay database |
|
|
67
68
|
| A Claude login on the relay host | Claude chats | Log in from **⚙️ Settings → Providers → Claude → Relogin** (the panel can install the Claude Code CLI first), or run `claude` once on the host. The relay stores no Claude key |
|
|
69
|
+
| The same Claude login, from a claude.ai account with GitHub connected | Claude Cloud chats | The Claude GitHub app must be allowed on each repository a cloud chat works on (see [Claude Cloud](#claude-cloud)) |
|
|
68
70
|
| Cursor API key | Cursor chats | Entered in **⚙️ Settings**, stored in the relay database |
|
|
69
71
|
| Grok CLI, signed in | Grok chats | Install it and sign in from **⚙️ Settings → Providers → Grok**, or set `XAI_API_KEY` in the relay's environment |
|
|
70
72
|
| tmux (optional) | Linux and macOS | Session workers run in detached tmux sessions you can watch from the browser (**🖥️ Inspect tmux console**). Without tmux they run as plain background processes |
|
|
@@ -78,7 +80,7 @@ curl -fsSL oar.sh/install | sh
|
|
|
78
80
|
The script checks for Node.js 22.13 or newer, runs `npm install -g @oar-sh/oar`, and then hands off to `oar setup` (with `--defaults` when there is no terminal to ask questions in). It refuses to run as root, because OAR installs per user. `OAR_VERSION=x.y.z` pins a version, `OAR_CHANNEL=beta` follows the beta channel, and `OAR_DRY_RUN=1` only prints what it would do:
|
|
79
81
|
|
|
80
82
|
```bash
|
|
81
|
-
curl -fsSL oar.sh/install | OAR_VERSION=0.9.
|
|
83
|
+
curl -fsSL oar.sh/install | OAR_VERSION=0.9.6 sh
|
|
82
84
|
```
|
|
83
85
|
|
|
84
86
|
Read it before you run it: [oar.sh/install](https://oar.sh/install).
|
|
@@ -89,7 +91,7 @@ Read it before you run it: [oar.sh/install](https://oar.sh/install).
|
|
|
89
91
|
irm oar.sh/install.ps1 | iex
|
|
90
92
|
```
|
|
91
93
|
|
|
92
|
-
The PowerShell installer (PowerShell 5 or newer) does the same: it checks Node.js, runs `npm install -g @oar-sh/oar`, then `oar setup`. It reads the same `OAR_VERSION`, `OAR_CHANNEL`, and `OAR_DRY_RUN` variables, for example `$env:OAR_VERSION = '0.9.
|
|
94
|
+
The PowerShell installer (PowerShell 5 or newer) does the same: it checks Node.js, runs `npm install -g @oar-sh/oar`, then `oar setup`. It reads the same `OAR_VERSION`, `OAR_CHANNEL`, and `OAR_DRY_RUN` variables, for example `$env:OAR_VERSION = '0.9.6'` before the command.
|
|
93
95
|
|
|
94
96
|
### npm
|
|
95
97
|
|
|
@@ -172,9 +174,9 @@ A global install keeps its state in `~/.oar` (`%APPDATA%\oar` on Windows; `OAR_S
|
|
|
172
174
|
|
|
173
175
|
## Runtimes
|
|
174
176
|
|
|
175
|
-
The runtime (called the *provider* in the UI) is chosen in **New Chat** and then fixed for that conversation: once a conversation has sent its first message it keeps that provider, and its composer is locked to that provider's models. The composer states this above the input — `🔒 Session locked to GitHub Copilot / OpenAI / OpenAI Image / Claude SDK / Cursor SDK / Grok models.`, colour-coded per provider. OpenAI sessions also pin one exact model, which the note names in parentheses and the model dropdown shows as a disabled `🔒` entry.
|
|
177
|
+
The runtime (called the *provider* in the UI) is chosen in **New Chat** and then fixed for that conversation: once a conversation has sent its first message it keeps that provider, and its composer is locked to that provider's models. The composer states this above the input — `🔒 Session locked to GitHub Copilot / OpenAI / OpenAI Image / Claude SDK / ☁ Claude Cloud / Cursor SDK / Grok models.`, colour-coded per provider. OpenAI sessions also pin one exact model, which the note names in parentheses and the model dropdown shows as a disabled `🔒` entry.
|
|
176
178
|
|
|
177
|
-
Turning a provider **off** (or removing the OpenAI key) rebinds conversations that have not sent a message yet back to Copilot, so you are never left with a conversation pointing at a runtime that can no longer start. Conversations already in flight, and conversations belonging to a different provider, are left alone.
|
|
179
|
+
Turning a provider **off** (or removing the OpenAI key) rebinds conversations that have not sent a message yet back to Copilot, so you are never left with a conversation pointing at a runtime that can no longer start. Conversations already in flight, and conversations belonging to a different provider, are left alone. Claude Cloud is the exception: switching it off only takes it out of **New Chat**, and its conversations stay as they are.
|
|
178
180
|
|
|
179
181
|
| Runtime | Enable via | Auth | Notes |
|
|
180
182
|
| ------- | ---------- | ---- | ----- |
|
|
@@ -182,6 +184,7 @@ Turning a provider **off** (or removing the OpenAI key) rebinds conversations th
|
|
|
182
184
|
| **OpenAI (BYOK)** | ⚙️ Settings → Providers → OpenAI | your API key, stored in the relay database | Runs the Copilot runtime, on either engine, against an OpenAI-compatible endpoint |
|
|
183
185
|
| **OpenAI Image (BYOK)** | ⚙️ Settings → Providers → OpenAI | the same key | The relay calls the OpenAI Images API itself; a chat whose replies are images |
|
|
184
186
|
| **Claude (Agent SDK)** | ⚙️ Settings → Providers → Claude | the relay host's Claude login, **switchable from the panel** | A dedicated Node worker per conversation. The Claude Code CLI can be installed and updated from the panel |
|
|
187
|
+
| **Claude Cloud** | ⚙️ Settings → Providers → Claude Cloud (off by default) | the relay host's Claude login (a claude.ai account), read from the Claude CLI | Claude Code in a sandbox at Anthropic, on a clone of a GitHub repository. Results come back as pushed branches; billed to that Claude account. Uses API endpoints that are not a documented public API (see [Claude Cloud](#claude-cloud)) |
|
|
185
188
|
| **Cursor (Agent SDK)** | ⚙️ Settings → Providers → Cursor | your Cursor API key, stored in the relay database | A dedicated Node worker per conversation through the Cursor Agent SDK |
|
|
186
189
|
| **Grok (CLI ACP)** | ⚙️ Settings → Providers → Grok | the relay host's Grok CLI login, **sign in and out from the panel** | Drives the Grok CLI's `grok agent stdio` over ACP. The CLI can be installed and updated from the panel |
|
|
187
190
|
|
|
@@ -214,6 +217,8 @@ Save your key in **⚙️ Settings → Providers → OpenAI**, together with the
|
|
|
214
217
|
|
|
215
218
|
Turn on **⚙️ Settings → Providers → Claude → Enable Claude for New Chat model selection**. The relay authenticates through the Claude credentials on the host machine (`~/.claude`), so there is no key to enter.
|
|
216
219
|
|
|
220
|
+
**Commit attribution.** Commits an agent makes in a Claude session end with `Co-authored-by: Open Agent Relay (<model>) <no-reply@oar.sh>` — the model's name in the parentheses, e.g. `Claude Fable 5.1` — and pull request bodies with `🤖 Generated with [Open Agent Relay](https://oar.sh)`. The same tab has the choice: **OAR** (default), **vanilla** (Claude Code's own `Co-Authored-By: Claude …` lines) or **off** (no attribution). A repo folder can override it for all of its Claude sessions from the **🧠** context modal. A change reaches a running session with its next message (a switch back to vanilla restarts the session's CLI between turns). [Claude Cloud](#claude-cloud) chats follow the same setting. Other providers are not affected: their tools have no such setting.
|
|
221
|
+
|
|
217
222
|
The same panel manages the account itself. The row at the top names the signed-in account and plan, and:
|
|
218
223
|
|
|
219
224
|
- **Relogin** runs the Claude CLI's login on the relay host and brings the flow to the browser: the authorize link appears inline with a **Copy link** button — open it on any device, authorize on claude.ai, then paste the returned code back into the field. The relay holds no Claude secret; the CLI rewrites the host credentials, and a fresh model discovery runs straight after, so switching accounts needs no relay restart. The flow is pushed over the socket, so you can start it on one device and finish it on another, and closing the modal does not lose it.
|
|
@@ -240,6 +245,69 @@ Differences from Copilot conversations:
|
|
|
240
245
|
- Claude turns are not included in the Copilot usage line, and no usage line is attached to their replies (Claude's own plan limits appear in **Check Usage**)
|
|
241
246
|
- The browsable **Session** root points at the Agent SDK's project directory rather than a Copilot session-state folder
|
|
242
247
|
|
|
248
|
+
### Claude Cloud
|
|
249
|
+
|
|
250
|
+
**Experimental**, and off by default.
|
|
251
|
+
|
|
252
|
+
A Claude Cloud chat runs Claude Code in a sandbox at Anthropic instead of on the relay host. The sandbox works on its own clone of a GitHub repository: it sees what is pushed to GitHub and nothing on the host, and its results come back as branches the agent pushes. The chat is billed to the Claude account the relay host's Claude CLI is logged in to. In OAR it is a conversation like the others: the reply streams in, questions arrive as cards, and it works from the phone.
|
|
253
|
+
|
|
254
|
+
**What it needs.**
|
|
255
|
+
|
|
256
|
+
- The Claude CLI on the relay host, logged in with a claude.ai account (**⚙️ Settings → Providers → Claude → Relogin**, or `claude` on the host). The same login serves Claude chats.
|
|
257
|
+
- GitHub connected to that Claude account: [claude.ai/connect-github](https://claude.ai/connect-github).
|
|
258
|
+
- The Claude GitHub app allowed on every repository a cloud chat should work on (GitHub → Settings → Applications → Claude → Configure).
|
|
259
|
+
|
|
260
|
+
**Enabling.** Turn on **⚙️ Settings → Providers → Claude Cloud → Enable Claude Cloud for New Chat**. It is off by default, and it is refused while the host has no Claude login. The tab then shows:
|
|
261
|
+
|
|
262
|
+
- the account the chats are billed to, and where the relay reads the login from and until when it is valid. The login itself is changed on the Claude tab (**Claude login** jumps there);
|
|
263
|
+
- **Cloud environment**: the environments of the account. With none saved, the relay takes the first active one and saves it. An account without any gets its default one when you open [claude.ai/code](https://claude.ai/code) once;
|
|
264
|
+
- **Default model** for new cloud chats (`claude-sonnet-5-5` until you change it). The list is the Claude provider's models without their `[1m]` variants, plus the default.
|
|
265
|
+
|
|
266
|
+
Switching Claude Cloud off takes it out of **New Chat**. Cloud conversations that already exist keep working.
|
|
267
|
+
|
|
268
|
+
**Starting a chat.** Choose **+ New Chat → Provider → Claude Cloud**. The folder picker stays, but here it only fills in two fields, which you can also pick from a list or type yourself:
|
|
269
|
+
|
|
270
|
+
- **Repository**: read from the folder's `origin` remote (or the remote of its upstream branch). With the field focused, OAR lists the repositories the Claude GitHub app can reach for the account (read from Anthropic, kept for a minute; **↻** next to the label reads it again), the ones used in earlier cloud chats on this relay first and marked "used here"; typing filters the list by `owner/name`, arrow keys and Enter pick, Escape closes. `owner/repo` or a GitHub URL, https or ssh, can still be typed or pasted; only GitHub repositories are accepted.
|
|
271
|
+
- **Branch**: the folder's current branch; a repository picked from the list brings its default branch. With the field focused, OAR offers the repository's branches as the relay host's git sees them (`git ls-remote`, with the host's own GitHub login; the host's `OAR_CLAUDE_CLOUD_BRANCH_LOOKUP=off` turns this off). When the host cannot read them the field is a plain text field. Leave it empty for the repository's default branch.
|
|
272
|
+
|
|
273
|
+
Under the fields OAR warns about what the cloud clone will not have: commits that are not pushed, a branch without an upstream, uncommitted changes. It also says when the folder is no git repository or has no GitHub remote, when the Claude GitHub app has no access to the repository in the field (the cloud would refuse the first message), and when no cloud environment is set. There is no reasoning effort to choose. The cloud session itself is created by the first message.
|
|
274
|
+
|
|
275
|
+
**What works.**
|
|
276
|
+
|
|
277
|
+
- The reply streams in as the agent writes it, with thoughts, tool activity, subagent bubbles and the steps of the sandbox starting up
|
|
278
|
+
- Questions from the agent (`AskUserQuestion`) as question cards, multi-select included; a tool that asks for permission gets an **Allow** / **Deny** card. A card answered on claude.ai closes in OAR
|
|
279
|
+
- **Stop** interrupts the cloud turn. If the cloud does not confirm within 30 seconds, the turn ends in OAR with a note that the agent may still be working there
|
|
280
|
+
- Image attachments (JPEG, PNG, GIF or WebP, up to 5 MB each), sent inline
|
|
281
|
+
- Follow-up messages go into the same cloud session, also after it has been idle for a long time
|
|
282
|
+
- A restart of the worker or the relay in the middle of a turn does not send your message twice: the new worker finds the turn in the session's event log and follows it, and a turn that finished in the meantime is answered from the log. A dropped connection to the session is reopened where it broke off
|
|
283
|
+
- The **cloud line** above the composer: the repository, the branch, a link to the session on claude.ai, one **⇡ branch** link per branch the agent pushed (it opens GitHub's comparison with the branch the chat started from) and what the session has cost so far. The `⋯` menu has **☁️ Open on claude.ai**
|
|
284
|
+
- [Commit attribution](#claude-agent-sdk): commits and pull requests the agent makes in the sandbox end with what the Claude tab's setting says (**OAR**, **vanilla** or **off**), from the first message on, and a change reaches the sandbox with the next message. In OAR mode the `Claude-Session` link to claude.ai is left out too. A chat started from a folder follows that folder's override, and its **🧠** modal has the select. The commit's author is still the sandbox's git identity (`Claude`); the setting covers the lines at the end
|
|
285
|
+
- A turn the session starts by itself — the agent's closing turn when its background work outlived the hold, or a message you sent on claude.ai — appears in the chat as a continuation reply, with a line saying where it came from; the worker keeps the session's event stream open for that
|
|
286
|
+
- A turn the cloud refuses at the Claude usage limit is paused like a local Claude turn (a note with the reset time, the banner, and the work carries on by itself after the reset); the limit warning before it appears in the tool activity
|
|
287
|
+
- Deleting or archiving the conversation archives the cloud session at Anthropic; nothing is deleted there
|
|
288
|
+
- A **Claude Cloud** card in **Check Usage** with the account's cloud credit and the cost Anthropic reports for this relay's cloud sessions, and the **🧠** button for the session's context use (see [Usage and context](#usage-and-context))
|
|
289
|
+
- A failure the relay can name says what to do: log in again, connect GitHub, give the Claude GitHub app access to the repository, choose an environment
|
|
290
|
+
|
|
291
|
+
**What does not.**
|
|
292
|
+
|
|
293
|
+
- No relay modes, no reasoning effort and no context size: the three selectors are hidden. The model is chosen in **New Chat** and can be changed between turns in the composer like a local Claude chat's (the sandbox switches before the next message)
|
|
294
|
+
- No mid-turn steering: a message sent during a turn waits for the turn to end
|
|
295
|
+
- Nothing from the relay host reaches the sandbox: attachments other than images are refused, there is no working directory to change and no **Session** folder to browse
|
|
296
|
+
- No relay tools inside the sandbox: no `preview`, no `remote_relay`, no media embedded by host path
|
|
297
|
+
- No background task panel
|
|
298
|
+
|
|
299
|
+
**Started by an agent.** An agent in another session can start a cloud chat with the `remote_relay` tool, naming the repository and, if it wants one, the branch (`repo` and `branch`): an agent on a [paired relay](#remote-relays), under the rules for starting any session from there, or an agent on this relay once [agent sessions](#agent-sessions) are switched on. The same checks apply as in **New Chat** (the provider is on, an environment is set, the repository is on GitHub), and a chat without a requested model starts with the tab's default model. It can also read, prompt, wait for and stop a cloud chat you created.
|
|
300
|
+
|
|
301
|
+
**What OAR does with the Claude login.** Claude Cloud uses the login the Claude CLI keeps on the relay host (`.credentials.json` in `~/.claude`, or in `CLAUDE_CONFIG_DIR`) to call the Anthropic API endpoints the Claude CLI itself uses for cloud sessions and account usage. **These endpoints are not a documented public API.** Anthropic can change them without notice; cloud chats and the live usage figures then fail with a note until OAR is updated. If you are not comfortable with a program other than the CLI using its login this way, leave the provider off.
|
|
302
|
+
|
|
303
|
+
- The relay and its cloud workers only **read** the access token. It is sent as the bearer token to `https://api.anthropic.com` and to no other host. (OAR's own tests point the client at a fake API on the same machine; that setting accepts a loopback address and nothing else.)
|
|
304
|
+
- It is held in memory only. It is never written to the database or to a log, never sent to the browser and never put into an error message. Each cloud worker reads the credentials file itself, so nothing is passed along at launch.
|
|
305
|
+
- It is never refreshed by OAR, and the refresh token is never used. The CLI keeps its own login fresh; when the token has run out, the relay — and a cloud chat's worker, through the relay — reads the file again and at most once in five minutes has the CLI check its own login (`claude auth status`, which refreshes a login whose refresh token is still good), then retries. A login that is still expired ends the turn with a note to log in again.
|
|
306
|
+
- While the switch is off, the relay asks Anthropic for nothing with this login: it lists no environments and reads no account usage. Only a cloud conversation from before still talks to its session, when you write to it, delete it or archive it.
|
|
307
|
+
- The provider is off by default. Switching it on is the consent for all of the above.
|
|
308
|
+
|
|
309
|
+
`CLAUDE_CODE_OAUTH_TOKEN` in the relay's environment is used instead of the credentials file when it is set. That is the one case in which the relay passes the login on: a cloud worker started under tmux gets the variable through a file only the relay's user can read, which the worker's shell reads once and deletes; workers of other providers are not given it that way (see [Environment variables](#environment-variables)).
|
|
310
|
+
|
|
243
311
|
### Cursor (Agent SDK)
|
|
244
312
|
|
|
245
313
|
Turn on **⚙️ Settings → Providers → Cursor**, paste your Cursor API key, and enable it for New Chat model selection. Saving the key runs model discovery and also discovers each model's supported reasoning-effort tiers; use **🤗 Select Models → Cursor SDK** to choose which models appear in the composer (the configured default model, `composer-2.5` unless you change it, always stays enabled).
|
|
@@ -319,13 +387,32 @@ The composer's model picker is the union of every enabled provider's catalog, fi
|
|
|
319
387
|
- **Copilot** models are discovered from the installed Copilot CLI runtime a few seconds after the relay starts, and refreshed by the sessions that run on it. Each model shows the reasoning efforts and context window the runtime reports. The list starts with `auto`, then groups models by vendor (OpenAI, Anthropic, Google, xAI, Microsoft, Azure OpenAI, Moonshot AI, then any others alphabetically), newest version first. Before the first discovery, a fresh relay offers a curated set: `gpt-5.4`, `gpt-5.4-mini` (the default), `gpt-5.3-codex`, `claude-sonnet-4.6`, and `claude-haiku-4.5`.
|
|
320
388
|
- **OpenAI (BYOK)** models are discovered from `/v1/models` when the key is saved or re-enabled.
|
|
321
389
|
- **Claude** models are discovered from the Agent SDK when the provider is enabled. Bracketed `[1m]` long-context variants (such as `claude-opus-5[1m]`) do not appear as separate entries; they surface as a 1M option in the composer's context-size dropdown for the base model.
|
|
390
|
+
- **Claude Cloud** has no discovery of its own: its picker offers the Claude provider's models under their plain ids, plus the tab's default model.
|
|
322
391
|
- **Cursor** models (and their per-model reasoning-effort tiers) are discovered when the API key is saved or the provider is re-enabled.
|
|
323
392
|
- **Grok** models are discovered from the Grok CLI over ACP when the provider is enabled, after a sign-in, and after a CLI install from the panel.
|
|
324
393
|
|
|
325
|
-
Use **🤗 Select Models** to choose which variants show up in the composer, then **💾 Save enabled models**; **Refresh** reruns discovery for every enabled runtime. The modal has one tab per runtime — **Copilot**, **OpenAI**, **Claude SDK**, **Cursor SDK**, **Grok** — and each tab lists only the models that runtime serves; there is no cross-runtime switching inside a conversation.
|
|
394
|
+
Use **🤗 Select Models** to choose which variants show up in the composer, then **💾 Save enabled models**; **Refresh** reruns discovery for every enabled runtime. The modal has one tab per runtime — **Copilot**, **OpenAI**, **Claude SDK**, **Cursor SDK**, **Grok** — and each tab lists only the models that runtime serves; there is no cross-runtime switching inside a conversation. Claude Cloud has no tab there.
|
|
326
395
|
|
|
327
396
|
## Highlights
|
|
328
397
|
|
|
398
|
+
### New in 0.9.7
|
|
399
|
+
|
|
400
|
+
- **Claude Cloud (experimental, off by default)**: a chat that runs Claude Code in a sandbox at Anthropic, on its own clone of a GitHub repository. Pick the repository and branch from a list, follow the turn live, answer its questions, stop it, change the model between turns; the results come back as pushed branches. See [Claude Cloud](#claude-cloud) for what it needs and what it does with the Claude login.
|
|
401
|
+
- **Archive, and a menu on every conversation**: archive a conversation instead of deleting it (🗄 shows the archived ones), and right-click a row, or long-press it on a phone, to open, rename, stop, kill, archive or delete it.
|
|
402
|
+
- **Agent sessions**: an agent can start other sessions on the relay it runs on, wait for them and read their results, once you switch it on under Settings → Relays.
|
|
403
|
+
- **Commits say Open Agent Relay**: commits and pull requests of Claude sessions carry `Co-authored-by: Open Agent Relay (<model>)`; choose OAR, Claude Code's own lines or none, per relay and per folder.
|
|
404
|
+
- **Check Usage opens at once**: the last reading shows immediately and only the open tab is read live.
|
|
405
|
+
- **Fixes**: two prices in one paragraph are no longer shown as a formula, a reply that names an error code is no longer stored as a failed turn, and on Windows the relay no longer stalls or fails to start workers while it reads the process list.
|
|
406
|
+
|
|
407
|
+
### New in 0.9.6
|
|
408
|
+
|
|
409
|
+
- **Claude pauses at the usage limit**: a turn that runs into the subscription's usage limit is paused instead of failed. A banner above the composer says when it carries on, with **Resume now** and **Cancel**; after the reset the relay sends a message of its own that quotes what was refused. The pause survives a relay restart, and a reset more than six hours away waits for you. A second banner warns when the usage passes 90 % of a limit.
|
|
410
|
+
- **A quiet command no longer fails its turn** (Copilot, Cursor, Grok): how long a turn may stay silent depends on what the agent is doing: 2 minutes with nothing in flight, 5 minutes during a model request, 30 minutes while a tool runs.
|
|
411
|
+
- **Copilot turns that fail, fail well**: the failure shows at once, what the agent had written stays above the note, Stop works on a stuck turn, a finished reply survives a relay restart, and the commands of a runtime that died are stopped. A message you send while a command runs waits for the command instead of cutting it short.
|
|
412
|
+
- **Agents on paired relays can answer each other**: a relay you mentioned stays in reach for the whole session, and an agent that was asked from another relay can answer, ask back or report later. See [Remote relays](#remote-relays).
|
|
413
|
+
- **Less scrolling in a running turn**: subagents are folded to a one-line header that says what they are doing, and a plan board sits inside the reply it belongs to; its choice also sets the session's mode.
|
|
414
|
+
- **Failure notes that help**: no more advice to restart the relay, and a Claude account problem (billing, sign-in, access) says what to check. The relay keeps its console in `relay-console.log`.
|
|
415
|
+
|
|
329
416
|
### New in 0.9.5
|
|
330
417
|
|
|
331
418
|
- **A misplaced Claude reply no longer blocks the conversation**: when a reply is published as a *background continuation* instead of under your message, the message closes after about 45 seconds of silence with a small note naming that reply, and the next message runs normally. It used to hold every later message for up to 5 minutes.
|
|
@@ -351,10 +438,10 @@ Use **🤗 Select Models** to choose which variants show up in the composer, the
|
|
|
351
438
|
- Nested **subagent bubbles**: each subagent gets its own live bubble with its own thoughts, activity, and streamed text, kept as collapsible sections after the turn finishes
|
|
352
439
|
- **Background task panel** with live per-task state, model, and token use; Claude workflow tasks fold out into a progress tree of phases and agents, and leave a *Finished background task* card in the transcript when they complete
|
|
353
440
|
- Question cards for clarification: one-click choices, multi-select checkmarks, free text, and multi-field structured forms validated against their JSON schema
|
|
354
|
-
- Mathematical and scientific notation rendering for TeX/LaTeX equations and chemical formulas
|
|
441
|
+
- Mathematical and scientific notation rendering for TeX/LaTeX equations and chemical formulas, written as `$…$`, `\(…\)`, `$$…$$` or `\[…\]`. A single `$` opens a formula only when a non-space character follows it directly and the next `$` has a non-space character directly before it and no digit directly after it (a digit is allowed after something that looks like TeX, as in `$x^2$3`), so prices such as `$5 and $9` stay text
|
|
355
442
|
- **Context usage** modal with a per-category token breakdown of the model's context window, plus a per-conversation **auto-compact window** slider for Claude sessions
|
|
356
443
|
- **Transcript breaks**: day separators, a marker where a Claude session auto-compacted its context, and matching dots beside the scrollbar
|
|
357
|
-
- **Plan usage** modal with subscription credits, rate-limit windows, and reset countdowns for Copilot, Claude, Cursor, and Grok
|
|
444
|
+
- **Plan usage** modal with subscription credits, rate-limit windows, and reset countdowns for Copilot, Claude, Claude Cloud, Cursor, and Grok
|
|
358
445
|
- **Image conversations** (OpenAI Image): generate images in chat and iterate on a generated image with **Edit this image**
|
|
359
446
|
- Agents can embed **images, video, and audio** in a reply by their absolute path, on every runtime; clicking an embedded image opens the file viewer with zoom, download, and copy
|
|
360
447
|
- **Screenshot annotations**: mark up an uploaded screenshot with highlighter strokes before or after sending; the original upload is never modified
|
|
@@ -371,7 +458,7 @@ Use **🤗 Select Models** to choose which variants show up in the composer, the
|
|
|
371
458
|
|
|
372
459
|
### Starting a conversation
|
|
373
460
|
|
|
374
|
-
- Start a chat with **+ New Chat**, which asks for the **Working directory**, **Provider**, **Model**, and **Reasoning effort** (or **Quality** and **Size**, for image chats; **Context window** where a model offers several) before the conversation exists. The working-directory list offers the known directories (current session, relay workspace, browser folder, recent roots), a **Custom path…** entry, and a 📁 folder picker; it defaults to the directory you picked last, and the chosen directory is applied before the session worker first launches. With Copilot as the only provider the provider row is hidden.
|
|
461
|
+
- Start a chat with **+ New Chat**, which asks for the **Working directory**, **Provider**, **Model**, and **Reasoning effort** (or **Quality** and **Size**, for image chats; **Context window** where a model offers several) before the conversation exists. The working-directory list offers the known directories (current session, relay workspace, browser folder, recent roots), a **Custom path…** entry, and a 📁 folder picker; it defaults to the directory you picked last, and the chosen directory is applied before the session worker first launches. With Copilot as the only provider the provider row is hidden. For **Claude Cloud** the modal asks for a **Repository** and a **Branch** instead of a reasoning effort, filled in from the chosen folder (see [Claude Cloud](#claude-cloud)).
|
|
375
462
|
- Choose the **mode** and **model** per message in the composer.
|
|
376
463
|
- The composer knows two slash commands, with autocomplete: **`/compact`** branches to a fresh conversation seeded with summary context, and **`/preview`** publishes a local dev server or directory on the public preview host without involving the agent (`/preview 5173 [label]`, `/preview ./dist [label]`, `/preview list`, `/preview close`). Agents can do the same through the `preview` tool (Claude and Cursor) or the documented API (see [docs/preview-servers.md](docs/preview-servers.md)). Any other single-line text starting with `/` is held back once with an *Unknown command* notice; press send again to send it as text.
|
|
377
464
|
|
|
@@ -393,7 +480,7 @@ Use **🤗 Select Models** to choose which variants show up in the composer, the
|
|
|
393
480
|
|
|
394
481
|
### Question cards
|
|
395
482
|
|
|
396
|
-
- Agents ask clarifying questions through question cards: `ask_user` on Copilot and Cursor, `AskUserQuestion` on Claude. A choice answers with one click; a question that allows several answers shows checkmarks and one **Reply with selection** button, whose reply lists every ticked choice plus anything you typed. Structured requests render as multi-field forms.
|
|
483
|
+
- Agents ask clarifying questions through question cards: `ask_user` on Copilot and Cursor, `AskUserQuestion` on Claude and Claude Cloud. A choice answers with one click; a question that allows several answers shows checkmarks and one **Reply with selection** button, whose reply lists every ticked choice plus anything you typed. Structured requests render as multi-field forms.
|
|
397
484
|
- On Copilot's SDK engine, the model gets OAR's own `ask_user` tool, which can mark a question as multi-select; a question worded "select all that apply" counts too, and every Copilot choice card that accepts free text has a **Select several** switch.
|
|
398
485
|
- A card waits 8 hours for an answer (2 hours on Copilot's Extension engine). After that the agent is told nobody answered and continues according to the conversation's mode. A turn that is waiting on a card is never treated as stuck.
|
|
399
486
|
- Grok has no question cards: ACP has no ask-user surface.
|
|
@@ -414,13 +501,15 @@ The composer draft, attachments included, is saved per conversation on the relay
|
|
|
414
501
|
- **Filter conversations…** above the list matches titles, ignoring case. It clears with **×** or Escape, and while it is active it loads older pages, so it searches every conversation, not just the loaded ones.
|
|
415
502
|
- **🔍** in the conversation header searches message text across all conversations.
|
|
416
503
|
- On startup, the relay imports the Copilot sessions stored on the host (through the installed Copilot runtime) into its database, so they appear in the list with their history. If the runtime is unavailable, the import is reported as failed rather than guessed from the filesystem.
|
|
417
|
-
-
|
|
504
|
+
- **Archive** (🗄 on the row, or **Archive conversation** in the `⋯` menu) takes a conversation out of the list without deleting anything: its session worker is stopped, and a Claude Cloud chat's session at Anthropic is archived with it. The 🗄 toggle above the list shows the archived conversations; **Unarchive** (📂) brings one back, cloud session included. An archived chat that is opened cannot be sent to until it is unarchived; a message that reaches it anyway (an agent's through a paired relay, say) unarchives it. A conversation that is still working is not archived — stop it first.
|
|
505
|
+
- A **right-click on a row** (a long press on a phone) opens a menu with Open, Edit title, Stop turn, Kill session, Archive or Unarchive, and Delete, so a session can be stopped or killed without opening it.
|
|
506
|
+
- Deleting a conversation stops its session worker and removes its CLI session too (Copilot through the runtime, Claude by deleting that session's transcript). A Claude Cloud conversation's session at Anthropic is archived, not deleted. An imported Copilot session the relay never ran is only hidden: its CLI session stays, and nothing is stopped for it. A conversation that is still working — a running turn, one waiting on a question card or approval, or live background tasks — is not deleted, and the sidebar says why so you can stop it first.
|
|
418
507
|
|
|
419
508
|
### Files, git, and previews
|
|
420
509
|
|
|
421
510
|
- Use **📁 Browse files** to inspect the workspace (💼), drives (📀), or the session's own folder (🕵️), and to open previews. The **Hidden** and **Heavy** toolbar filters are remembered per browser, and a refresh re-opens the folders you had expanded.
|
|
422
511
|
- Click the file and folder copy controls to insert `@file:...` / `@folder:...` tokens.
|
|
423
|
-
- Workspace browsing follows the selected session's effective working directory. Running sessions keep their learned runtime directory, **🗂️ Change CWD** in the `⋯` menu changes the directory for the next launch, and `cd ...` typed in chat does not retarget the browser.
|
|
512
|
+
- Workspace browsing follows the selected session's effective working directory. Running sessions keep their learned runtime directory, **🗂️ Change CWD** in the `⋯` menu changes the directory for the next launch, and `cd ...` typed in chat does not retarget the browser. A Claude Cloud chat has no **Change CWD**: it works on a clone at Anthropic.
|
|
424
513
|
- Use **🌿 Git changes** in the conversation `⋯` menu to review the workspace repository: the header shows the branch with ahead/behind counts and a **⬇ Pull** button, and the list shows every staged, unstaged, and untracked file (deleted files struck through). Clicking a file opens a diff viewer with **Changes** and **Full file** modes; closing it returns to the still-open list.
|
|
425
514
|
- Agents can embed images, video, and audio in a reply by absolute path; they render inline.
|
|
426
515
|
- Tap an image attachment in the composer (it carries a 🖍️ badge), or use **🖍️ Annotate** in the file viewer, to mark it up with highlighter strokes. The annotated copy is uploaded; the original stays untouched.
|
|
@@ -428,13 +517,14 @@ The composer draft, attachments included, is saved per conversation on the relay
|
|
|
428
517
|
|
|
429
518
|
### Usage and context
|
|
430
519
|
|
|
431
|
-
- Use **📊 Check Usage** in the conversation `⋯` menu for plan usage across every configured provider: remaining credits, rate-limit windows, reset countdowns, and collapsible cost/token detail. Each provider gets its own tab, opening on the conversation's own provider, and the card names the signed-in account (email and plan) beneath its title. Sources differ per provider:
|
|
520
|
+
- Use **📊 Check Usage** in the conversation `⋯` menu for plan usage across every configured provider: remaining credits, rate-limit windows, reset countdowns, and collapsible cost/token detail. Each provider gets its own tab, opening on the conversation's own provider, and the card names the signed-in account (email and plan) beneath its title. The modal opens on the reading it showed last time and reads only the open tab's provider live (its card says "updating…" until the answer is in); a tab you switch to is read live when its reading is older than a minute, **Refresh** reads the open tab, and the relay keeps the last live answer of every provider so the other cards are never empty. Sources differ per provider:
|
|
432
521
|
- **Copilot** — live quota (AI credits or premium requests, chat, plan), plus per-model/product billed cost when your GitHub token can read personal billing. Conversations on the SDK engine add a **Last SDK worker turn** section (AI credits actually spent, tokens, model calls, overage) with the model and how long ago it was captured; it is one turn's numbers rather than a running total, and it stops being shown once it is more than seven days old.
|
|
433
|
-
- **Claude** — subscription limit windows (5-hour, weekly, per-model), extra-usage credits, session cost, and local usage attribution. Read from the live session at the end of a turn; the relay never starts a hidden turn to refresh it, so the newest reading is from your last Claude turn.
|
|
522
|
+
- **Claude** — subscription limit windows (5-hour, weekly, per-model), extra-usage credits, session cost, and local usage attribution. Read from the live session at the end of a turn; the relay never starts a hidden turn to refresh it, so the newest reading is from your last Claude turn. With **Claude Cloud** switched on, the limits are read live from the account each time the modal opens (kept for a minute), with no turn involved: the card then carries a **Live** badge, a limit that is getting close carries Anthropic's own warning word, and it adds **This week by product** (Claude Code, chats and the other products as shares of the week) and the organisation's **Prepaid credits** when there are any. Limit resets (full and 5-hour) are shown on claude.ai only; the card links there. When the live read fails, the card falls back to the last turn's reading and says why.
|
|
523
|
+
- **Claude Cloud** — shown while the provider is on. A meter per dollar credit the account holds, with what is used, what is left and when it expires; **Cloud spend (OAR sessions)**, the cost Anthropic reports per cloud session, summed over the cloud conversations this relay still has, with this conversation's own cost when the modal was opened from a cloud chat; and the latest cloud session report (its cost, and cost and tokens by model). These figures are Anthropic's reported cost, not a billing statement, and sessions started elsewhere are not counted. A credit that is offered but not yet claimed is mentioned with a link to claude.ai. Cloud turns spend the cloud credit first; without a credit they count against the Claude limits above.
|
|
434
524
|
- **Cursor** — spend from the Cursor SDK measured against the monthly allowances you enter in Settings, split into the Cursor Models and Other Models pools; these figures are estimates, and Cursor's Spending dashboard remains authoritative. With a dashboard session token, the card adds live *Included in plan* bars.
|
|
435
525
|
- **Grok** — the live weekly subscription quota, read with the host's Grok CLI login, plus per-turn tokens and estimated cost from the agent's prompt result. An optional monthly USD allowance in Settings adds an estimated remaining meter; the card is hidden when Grok is disabled. Billing: [console.x.ai](https://console.x.ai).
|
|
436
|
-
- Per-reply usage lines are recorded only for Copilot turns — OpenAI, Claude, Cursor, and Grok turns do not consume Copilot premium requests, and no usage line is attached to them.
|
|
437
|
-
- Use the **🧠** context button for a per-category breakdown of the conversation's context window: a usage bar, a token/percentage table, and free space. Claude sessions report exact SDK categories; Copilot sessions show the coarser system/tools + messages + buffer split, labelled as a lower-bound estimate when the runtime no longer emits full buckets.
|
|
526
|
+
- Per-reply usage lines are recorded only for Copilot turns — OpenAI, Claude, Claude Cloud, Cursor, and Grok turns do not consume Copilot premium requests, and no usage line is attached to them.
|
|
527
|
+
- Use the **🧠** context button for a per-category breakdown of the conversation's context window (Claude sessions also show the auto-compact window, the thinking controls and the folder's commit attribution there): a usage bar, a token/percentage table, and free space. Claude sessions report exact SDK categories; Copilot sessions show the coarser system/tools + messages + buffer split, labelled as a lower-bound estimate when the runtime no longer emits full buckets. A Claude Cloud session reports how much of its window is used after each turn, without categories.
|
|
438
528
|
- Claude conversations additionally get an **auto-compact window** slider in that modal. Claude Code compacts a session once it approaches a model-tuned window (around 967k tokens on a 1M-context model), which is why long conversations rarely compact at all; setting a smaller window makes it happen sooner and keeps turns cheaper. *Auto* hands the choice back to the CLI. The smallest window is 100k, because the CLI silently ignores anything below that and falls back to its own default. The line beneath the slider reports the window actually in force and where it came from — your setting, the model default, or the `CLAUDE_CODE_AUTO_COMPACT_WINDOW` environment override — and fills in once the conversation's first turn completes. The change reaches a running session on its next message.
|
|
439
529
|
- The transcript marks day boundaries, and marks the point where a Claude session compacted its context with the tokens before and after. Both appear as dots beside the scrollbar for the messages currently loaded.
|
|
440
530
|
|
|
@@ -449,7 +539,7 @@ Use **➡️ Share conversation** in the `⋯` menu to publish a read-only link.
|
|
|
449
539
|
|
|
450
540
|
### The conversation menu
|
|
451
541
|
|
|
452
|
-
Besides the entries above, the `⋯` menu holds **✍️ Edit conversation title**, **🖥️ Inspect tmux console** (a read-only view of the session's tmux pane), **🤗 Select Models**, **⚙️ Settings**, **🌄 Restart web relay** (queued until the current turn is idle), **💤 Suspend host** (Windows; see below), and **☠️ Kill session** (stops the conversation's worker; an active turn then needs a retry or a new message). Its header shows the queue counts with **🚮 Empty queue**.
|
|
542
|
+
Besides the entries above, the `⋯` menu holds **✍️ Edit conversation title**, **🗄 Archive conversation** (**📂 Unarchive** on an archived chat), **🖥️ Inspect tmux console** (a read-only view of the session's tmux pane), **🤗 Select Models**, **☁️ Open on claude.ai** (Claude Cloud chats, once their session exists), **⚙️ Settings**, **🌄 Restart web relay** (queued until the current turn is idle), **💤 Suspend host** (Windows; see below), and **☠️ Kill session** (stops the conversation's worker; an active turn then needs a retry or a new message). Its header shows the queue counts with **🚮 Empty queue**.
|
|
453
543
|
|
|
454
544
|
**💤 Suspend host** puts the machine the relay runs on to sleep, once the work is done. The confirmation lists what is still active. The relay then queues the suspend and fires it after 2 minutes with nothing active: no queued, running or parked turn, no background task of a live worker, and no open GitHub Actions run in the repository of a conversation that was busy since the request (read through `gh`; a repository whose state cannot be read blocks for 15 minutes, then is ignored). With nothing running when you confirm, it fires after a 30-second countdown. While a suspend is queued, every device shows a banner with the blockers or the countdown and a **Cancel** button, and a push notification reports the suspend. A relay restart drops a queued suspend and says so. **Show Suspend host action** in Settings hides the entry per browser.
|
|
455
545
|
|
|
@@ -457,7 +547,7 @@ Besides the entries above, the `⋯` menu holds **✍️ Edit conversation title
|
|
|
457
547
|
|
|
458
548
|
### Settings (⚙️ in the web UI)
|
|
459
549
|
|
|
460
|
-
The modal is organised into six tabs — **General**, **Providers** (with a **Copilot**, **OpenAI**, **Claude**, **Grok**, and **Cursor** sub-tab), **Relays**, **Previews**, **Notifications**, and **Features** — and reopens on the tab you used last. Unless noted as per browser, these settings live in the relay database rather than the config file, and apply to every browser that connects:
|
|
550
|
+
The modal is organised into six tabs — **General**, **Providers** (with a **Copilot**, **OpenAI**, **Claude**, **Claude Cloud**, **Grok**, and **Cursor** sub-tab), **Relays**, **Previews**, **Notifications**, and **Features** — and reopens on the tab you used last. Unless noted as per browser, these settings live in the relay database rather than the config file, and apply to every browser that connects:
|
|
461
551
|
|
|
462
552
|
| Tab | Setting | Default | What it does |
|
|
463
553
|
| --- | ------- | ------- | ------------ |
|
|
@@ -473,9 +563,13 @@ The modal is organised into six tabs — **General**, **Providers** (with a **Co
|
|
|
473
563
|
| Providers | OpenAI API key / model / base URL | — / `gpt-4o` / `https://api.openai.com/v1` | Enables the OpenAI and OpenAI Image providers |
|
|
474
564
|
| Providers | Claude (Agent SDK) | off | Enables Claude as a New Chat provider and runs model discovery; default model `claude-sonnet-5` |
|
|
475
565
|
| Providers | Claude account (Relogin / Logout) | host login | Switches the Claude account the relay host's CLI uses, from the browser (see [Claude (Agent SDK)](#claude-agent-sdk)) |
|
|
566
|
+
| Providers | Claude Cloud | off | Enables Claude Cloud as a New Chat provider, and the live account figures in **Check Usage**; the switch is the consent to use the Claude CLI's login (see [Claude Cloud](#claude-cloud)) |
|
|
567
|
+
| Providers | Claude Cloud environment / default model | first active environment of the account / `claude-sonnet-5-5` | The cloud environment new cloud sessions run in, and the model a new cloud chat starts with |
|
|
476
568
|
| Providers | Cursor API key / model | — / `composer-2.5` | Enables Cursor; plus monthly plan allowances and the optional dashboard session token |
|
|
477
569
|
| Providers | Grok | off | Enables Grok; default model `grok-4.5`; **Sign in** / **Sign out**; optional monthly allowance |
|
|
478
570
|
| Relays | Public address, Accept prompts from other relays' agents | browser address / on | How paired relays reach this one, and whether their agents may prompt sessions here (see [Remote relays](#remote-relays)) |
|
|
571
|
+
| Relays | Agent sessions: Agents may start and use sessions on this relay | off | Lets agents on this relay start and use other sessions here with the `remote_relay` tool; the first session an agent starts in a conversation asks for your approval (see [Agent sessions](#agent-sessions)) |
|
|
572
|
+
| Relays | Agent sessions: Longest wait per tool call | `10 min` | How long one `remote_relay` call may wait for a reply (2 to 60 minutes), on this relay and on paired ones; adjustable whether or not the switch above is on |
|
|
479
573
|
| Relays | Remote relays | — | Pair a relay by pasting its web address; per relay **Agents may** read only, read and prompt, or do everything |
|
|
480
574
|
| Previews | Live previews | — | Lists the published previews, each of which you can close |
|
|
481
575
|
| Notifications | Push notifications | off | Per device: which events notify, and whether titles and message previews are included |
|
|
@@ -555,7 +649,8 @@ The config file is `server/config.json` in a git checkout and `~/.oar/config.jso
|
|
|
555
649
|
| `GH_TOKEN`, `GITHUB_TOKEN` | GitHub token for the Copilot usage card, instead of `gh auth token` |
|
|
556
650
|
| `XAI_API_KEY` | Grok authentication instead of the Grok CLI login |
|
|
557
651
|
| `CURSOR_SESSION_TOKEN` | Cursor dashboard session token for live plan bars |
|
|
558
|
-
| `CLAUDE_CONFIG_DIR` | Claude configuration directory, instead of `~/.claude` |
|
|
652
|
+
| `CLAUDE_CONFIG_DIR` | Claude configuration directory, instead of `~/.claude`; Claude Cloud reads the CLI's login (`.credentials.json`) from it |
|
|
653
|
+
| `CLAUDE_CODE_OAUTH_TOKEN` | A Claude login token for Claude Cloud, used instead of the CLI's credentials file, by the relay (settings tab, **Check Usage**, archiving) and by its cloud workers. Under tmux the relay hands it to cloud workers only, through an owner-only file; a worker started without tmux inherits the relay's environment as it is |
|
|
559
654
|
| `CLAUDE_CODE_AUTO_COMPACT_WINDOW` | Overrides the Claude auto-compact window |
|
|
560
655
|
| `COPILOT_CLOUDFLARED_MODE`, `COPILOT_CLOUDFLARED_TOKEN`, `COPILOT_CLOUDFLARED_BINARY` | Override `cloudflaredTunnel.mode`, `.token`, and `.binary` |
|
|
561
656
|
| `COPILOT_WORKSPACE_ROOT_ALLOW_LIST` | Same as `workspaceRootAllowList` |
|
|
@@ -677,16 +772,33 @@ locked in a conversation until you mention it in one of your messages: type `@`
|
|
|
677
772
|
from the list, or write its name or its host name. An IP address or `localhost` never counts as a
|
|
678
773
|
host name; a relay whose name is itself an address is unlocked only with a leading `@`. The
|
|
679
774
|
mention unlocks that relay for the rest of
|
|
680
|
-
the conversation
|
|
681
|
-
|
|
775
|
+
the conversation, whatever prompts arrive in it later.
|
|
776
|
+
|
|
777
|
+
**Agents can answer each other.** When an agent on a paired relay writes to a conversation, that
|
|
778
|
+
relay is open to the conversation from then on, within what **Agents may** allows, so the agent
|
|
779
|
+
that was asked can answer, ask back or report later. A prompt from an agent never unlocks any
|
|
780
|
+
other relay. A prompt that already crossed two relays is not passed on to a third one unless you
|
|
781
|
+
unlocked that relay yourself; reading and waiting are never limited. When the agent of a
|
|
782
|
+
conversation has sent 30 prompts to agents on other relays without a message from you, the next
|
|
783
|
+
one asks you first with a question card; **Allow** starts the count again.
|
|
682
784
|
|
|
683
785
|
**What agents can do.** Every provider gets the same `remote_relay` tool (Claude, Cursor and
|
|
684
|
-
Copilot directly; Grok and the Copilot extension engine through OAR's MCP server).
|
|
786
|
+
Copilot directly; Grok and the Copilot extension engine through OAR's MCP server). Sessions get it
|
|
787
|
+
while at least one relay is paired or [agent sessions](#agent-sessions) are switched on. Per paired
|
|
685
788
|
relay, **Agents may** limits it to *read only*, *read and prompt* (existing sessions) or *full*
|
|
686
789
|
(also create sessions, answer questions, stop turns, archive). In the *ask* and *plan* relay
|
|
687
790
|
modes, every write action first asks you with a question card. For a session it starts, an agent
|
|
688
791
|
can set the provider, model, relay mode and reasoning effort; what it leaves out follows the
|
|
689
|
-
session it works in, as far as the other relay offers it.
|
|
792
|
+
session it works in, as far as the other relay offers it. A [Claude Cloud](#claude-cloud) session
|
|
793
|
+
is started with `provider: "claude-cloud"`, a `repo` (a GitHub URL or `owner/repo`, for example
|
|
794
|
+
`example-org/sample-repo`) and an optional `branch` instead of a folder; without a model it gets
|
|
795
|
+
the default model of the other relay's Claude Cloud tab. Claude Cloud must be switched on there.
|
|
796
|
+
A cloud session that exists can be read, prompted, waited for and stopped like any other.
|
|
797
|
+
|
|
798
|
+
A `send`, `create_session` or `wait` call waits for the reply for as long as the agent asks, up to
|
|
799
|
+
**Longest wait per tool call** of the relay the agent runs on (10 minutes unless you changed it,
|
|
800
|
+
see [Agent sessions](#agent-sessions)). When the time is up the agent gets what there is so far
|
|
801
|
+
and can call `wait` again.
|
|
690
802
|
|
|
691
803
|
When an agent prompts a session on another relay, that relay shows a **↗ from …** badge with the
|
|
692
804
|
sending relay, session and model on the message, and marks sessions an agent created in the
|
|
@@ -699,6 +811,58 @@ The calls go through your own relay, which holds the other relay's token: agents
|
|
|
699
811
|
token. Remote addresses must use `https://`; plain `http://` is accepted only for loopback (an
|
|
700
812
|
SSH port forward, for example) and private network ranges.
|
|
701
813
|
|
|
814
|
+
### Agent sessions
|
|
815
|
+
|
|
816
|
+
The same `remote_relay` tool can also work on the relay the agent itself runs on. An agent can
|
|
817
|
+
then hand parts of its task to other sessions: it starts them, waits for them and reads their
|
|
818
|
+
replies. Every session it starts is an ordinary conversation in your list. No relay has to be
|
|
819
|
+
paired for this.
|
|
820
|
+
|
|
821
|
+
**Switching it on.** It is off by default. Turn on **Settings → Relays → Agent sessions →
|
|
822
|
+
Agents may start and use sessions on this relay**. From then on this relay is the first entry of
|
|
823
|
+
the relay list an agent sees, marked as its own; the agent names it by its **Relay name** or as
|
|
824
|
+
`this`. It needs no mention, and **Agents may** and **Accept prompts from other relays' agents**
|
|
825
|
+
do not apply to it. On this relay an agent can do what *full* allows on a paired one: list and
|
|
826
|
+
read every session here, prompt one, start one, wait for it, answer its question, stop its turn
|
|
827
|
+
and archive it. Switching the setting off closes this relay to the tool again.
|
|
828
|
+
|
|
829
|
+
**The rules.**
|
|
830
|
+
|
|
831
|
+
- **Approval once per conversation.** The first time the agent of a conversation wants to start
|
|
832
|
+
a session here, a question card (**Agent sessions**) shows the provider, the folder or
|
|
833
|
+
repository and the prompt. **Allow** covers every session that conversation's agent starts
|
|
834
|
+
later, also after a relay restart; **Deny** refuses that one call. In the *ask* and *plan*
|
|
835
|
+
relay modes, every other write action still asks, as it does for a paired relay.
|
|
836
|
+
- **At most 4 at work.** Of the sessions one conversation's agent started, 4 may have a turn
|
|
837
|
+
queued or running at the same time. A fifth is refused until one of them has finished.
|
|
838
|
+
- **One level only.** A session that an agent created, here or from a paired relay, cannot start
|
|
839
|
+
sessions on this relay.
|
|
840
|
+
- **Not on itself.** An agent cannot prompt, stop, archive, wait for or answer the conversation
|
|
841
|
+
it runs in.
|
|
842
|
+
- The count of 30 prompts without a message from you (see above) includes prompts to sessions
|
|
843
|
+
on this relay.
|
|
844
|
+
|
|
845
|
+
**What it can start.** A session with any provider that is enabled on this relay (Copilot,
|
|
846
|
+
OpenAI, Claude, Cursor, Grok or Claude Cloud; not an OpenAI Image chat): in a folder
|
|
847
|
+
(the relay's default folder when the agent names none), or a [Claude Cloud](#claude-cloud) chat
|
|
848
|
+
with `provider: "claude-cloud"`, `repo` and an optional `branch`. A new session knows nothing of
|
|
849
|
+
the conversation it was started from. Sessions an agent starts use this relay's accounts and
|
|
850
|
+
count against their usage.
|
|
851
|
+
|
|
852
|
+
**In the conversation list.** A session an agent on this relay started carries **via agent ·
|
|
853
|
+
“title”** in the sidebar and under the title in the header, with the title of the conversation
|
|
854
|
+
the agent runs in; clicking it opens that conversation while it is still in the list. The
|
|
855
|
+
agent's prompts carry the same marker, with its model, as a badge on the message. The relay never
|
|
856
|
+
archives these sessions by itself: they stay in the list until you archive or delete them, or the
|
|
857
|
+
agent archives one with the tool.
|
|
858
|
+
|
|
859
|
+
**Longest wait per tool call.** The slider under the switch sets how long one `send`,
|
|
860
|
+
`create_session` or `wait` call may wait for a reply: 10 minutes by default, from 2 to 60 minutes
|
|
861
|
+
in steps of one minute. The agent can call `wait` again to keep waiting. The limit also applies
|
|
862
|
+
to this relay's agents when they wait for a session on a paired relay, so the slider can be moved
|
|
863
|
+
whether or not the switch above it is on. A turn that waits is still subject to **Max turn duration**
|
|
864
|
+
under **General** (60 minutes by default), which does not know about the wait.
|
|
865
|
+
|
|
702
866
|
## Security notes
|
|
703
867
|
|
|
704
868
|
- The auth token guards the API and the Socket.IO channel. A browser signs in once, with the token or with a URL carrying `?token=` (such as the one `oar setup` prints and puts in its QR code), and then holds an HttpOnly cookie for 30 days, marked `Secure` when the relay is reached over HTTPS. Treat the token, and that URL, like a password.
|
|
@@ -708,6 +872,7 @@ SSH port forward, for example) and private network ranges.
|
|
|
708
872
|
- Shared conversation links and preview links are public by design: anyone with the URL can read the shared transcript or reach the previewed app, without signing in.
|
|
709
873
|
- A [paired relay](#remote-relays) holds a token that opens the other relay completely. The per-relay "Agents may" limit and the "Accept prompts from other relays' agents" switch are honoured by OAR's own traffic, but anyone holding the token can still use the full API: the token is the real boundary. A token entered for a paired relay is stored like the API keys below and never sent to browsers or agents.
|
|
710
874
|
- API keys you enter (OpenAI, Cursor) are stored in the relay database on the host and never sent to browsers. Claude and Grok credentials stay with their CLIs on the host.
|
|
875
|
+
- Claude Cloud, when you switch it on, reads the Claude CLI's login and uses it against Anthropic API endpoints that are not a documented public API. The token is only read and held in memory, and goes to `api.anthropic.com` only (see [Claude Cloud](#claude-cloud)). A cloud agent works in Anthropic's sandbox, not on your host.
|
|
711
876
|
- OAR has no telemetry. Its only request to oar.sh is the update check, which is off until you enable it.
|
|
712
877
|
|
|
713
878
|
## Troubleshooting
|
|
@@ -723,6 +888,9 @@ SSH port forward, for example) and private network ranges.
|
|
|
723
888
|
| File links fail | Verify auth token/cookie and that paths are inside allowed workspace/drive roots |
|
|
724
889
|
| Claude missing from New Chat | Enable it in **⚙️ Settings → Providers → Claude**; the toggle is off by default |
|
|
725
890
|
| Claude reply says it cannot authenticate | Press **Claude settings** on the failed reply, then **Relogin** (or run `claude` on the relay host), and retry the turn |
|
|
891
|
+
| Claude Cloud missing from New Chat | Enable it in **⚙️ Settings → Providers → Claude Cloud**; it is off by default and needs a Claude login on the relay host |
|
|
892
|
+
| Claude Cloud reply says GitHub is not connected, or the Claude GitHub app has no access | Connect GitHub to the Claude account at [claude.ai/connect-github](https://claude.ai/connect-github), or add the repository to the Claude GitHub app's repository access on GitHub; then send the message again |
|
|
893
|
+
| New Chat says *No cloud environment is set* | Choose one in **⚙️ Settings → Providers → Claude Cloud**; an account without any gets its default one when you open claude.ai/code once |
|
|
726
894
|
| Grok reply says the CLI was not found | Press **Install Grok CLI** on the failed reply, or install it from **⚙️ Settings → Providers → Grok**; no relay restart is needed afterwards |
|
|
727
895
|
| Grok reply says authentication failed | Press **Sign in to Grok** on the failed reply and confirm the device code in a browser |
|
|
728
896
|
| Long turn requeued unexpectedly | Raise or clear **Max turn duration** in Settings (0 = no limit) |
|
|
@@ -731,7 +899,7 @@ SSH port forward, for example) and private network ranges.
|
|
|
731
899
|
| A conversation seems wedged | **☠️ Kill session** in the `⋯` menu stops its worker; retry the turn or send a new message |
|
|
732
900
|
| **🌄 Restart web relay** fails with *localhost-only* | The restart endpoint accepts loopback connections only: use it on the relay host or through a tunnel, not over a direct LAN connection |
|
|
733
901
|
| `npm install -g @oar-sh/oar` fails with node-gyp or prebuild errors | `better-sqlite3` has no prebuilt binary for your platform; install a C/C++ build toolchain and Python, then retry |
|
|
734
|
-
| No usage line under a reply | Expected for OpenAI, Claude, Cursor, and Grok turns; only Copilot turns record plan usage |
|
|
902
|
+
| No usage line under a reply | Expected for OpenAI, Claude, Claude Cloud, Cursor, and Grok turns; only Copilot turns record plan usage |
|
|
735
903
|
|
|
736
904
|
## Repository layout
|
|
737
905
|
|
|
@@ -741,6 +909,7 @@ oar/
|
|
|
741
909
|
├── bin/ # The `oar` command (oar.js) and a Windows cmd shim for checkouts (bat/oar.bat)
|
|
742
910
|
├── docs/ # Preview-server guide, Copilot BYOK notes, SDK feature tracker
|
|
743
911
|
├── server/
|
|
912
|
+
│ ├── claude-cloud-worker/ # Claude Cloud session worker (follows a cloud session's event stream; runs no agent itself)
|
|
744
913
|
│ ├── claude-worker/ # Claude Agent SDK session worker (turn runner, ask-user bridge, attachments)
|
|
745
914
|
│ ├── copilot-worker/ # Copilot SDK engine session worker (steering, background tasks, questions)
|
|
746
915
|
│ ├── cursor-worker/ # Cursor Agent SDK session worker (turn runner, mode nudges, auth retry)
|
|
@@ -754,6 +923,7 @@ oar/
|
|
|
754
923
|
│ ├── server.js # Entry point: supervisor plus relay runtime
|
|
755
924
|
│ └── server-runtime.mjs # Express + Socket.IO relay server
|
|
756
925
|
├── shared/ # Code shared by the server, the extension, and the workers
|
|
926
|
+
│ ├── claude-cloud/ # Claude Cloud API client, credentials reader, repository and branch rules
|
|
757
927
|
│ └── worker-runtime/ # Common worker plumbing (relay API client, heartbeat, worker link)
|
|
758
928
|
├── tests/ # Playwright end-to-end suite and its isolated relay harness
|
|
759
929
|
├── CHANGELOG.md
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oar-sh/oar",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "OAR — Open Agent Relay: drive your local coding agents from any browser",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"server/uploads/image_input.md",
|
|
31
31
|
"shared/",
|
|
32
32
|
"!shared/**/*.test.mjs",
|
|
33
|
+
"!shared/**/*-test-harness.mjs",
|
|
33
34
|
"!shared/**/fixtures/",
|
|
34
35
|
".github/extensions/web-relay/",
|
|
35
36
|
"!.github/extensions/web-relay/**/*.test.mjs",
|