@saadnvd1/agent-os 0.3.539 → 0.3.542

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/README.md CHANGED
@@ -12,132 +12,30 @@ and check on all of it from your phone.
12
12
 
13
13
  ## What it does
14
14
 
15
- ### An orchestrator for each workspace
16
-
17
- Every workspace has one orchestrator, a chat pinned at the top of its list.
18
- It starts tasks, answers agents that are blocked, and reviews and merges
19
- pull requests through gates: CI green and settled, an independent review of
20
- the exact commit (big diffs are reviewed in parts), nothing blocked, and the
21
- diff in scope. Anything that is yours to
22
- decide (publishing, money, something irreversible, credentials) waits as an
23
- ask with Approve, Decline and Reply. Turn on **Require my approval** and
24
- sensitive or large PRs wait for you too. [More](#orchestrator)
25
-
26
- ![The Work orchestrator's chat, with two asks waiting: a merge gate and a public post](screenshots/orchestrator.png)
27
-
28
- ### Tasks that end in a pull request
29
-
30
- A task gets its own git worktree, branch and ports, opens as a chat, runs
31
- the project's code review before it opens its PR, and waits for your
32
- sign-off. A workspace's running task limit (Settings → Workspaces) caps how many run at once; the rest
33
- wait under **Queued** with their place in line and start on their own, and
34
- `aos task --after` holds one until another finishes. [More](#tasks)
35
-
36
- ### Each kind of work on the right model
37
-
38
- Planning, gate reviews and the orchestrator run on Opus, implementation and
39
- scope checks on Sonnet, titles and summaries on Haiku, each editable in
40
- Settings → Models and per workspace. A task plans on one model and
41
- implements on another in the same conversation, can be resumed on any
42
- model, and can run on another provider (DeepSeek, GLM, any
43
- Anthropic-compatible endpoint) whose key stays a reference.
44
- **Usage → Compare** shows Claude-only and routed tasks side by side.
45
- [More](#model-routing)
46
-
47
- ![A task's chat: the edit, the tests, the code review and the PR it opened](screenshots/task-chat.png)
48
-
49
- ![Two queued tasks in the sidebar, one in line and one waiting on another task, with its menu open](screenshots/queued.png)
50
-
51
- ### Nothing starts until you send
52
-
53
- ⌥N opens a draft in the project you're in. Project, machine, agent, worktree
54
- and base branch are chips on it, model and access sit under the composer, and
55
- **Open a PR when done** makes it a task. Unsent drafts wait in the sidebar.
56
- [More](#new-sessions)
57
-
58
- ![A new task draft with its project, machine, branch and PR chips](screenshots/draft.png)
59
-
60
- ### Other machines in the same list
61
-
62
- Link another machine that runs AgentOS and its sessions show up next to
63
- yours, with the same rows, menu and address. Their chats and terminals are
64
- relayed through this server. Pick the machine on a draft to start a session
65
- or task there, even for a project that only lives here (it finds or clones
66
- the repository), and move a running terminal task between machines.
67
- [More](#machines)
68
-
69
- ![A linked machine's sessions listed under its name in the sidebar](screenshots/machines.png)
70
-
71
- ### Built for your phone
72
-
73
- The whole app works on a phone, not a cut-down view. Every session has its
74
- own link (`/?session=<id>`) you can bookmark or share between devices, and
75
- pairing a new device is a QR code. Tailscale gives you an encrypted address
76
- that works from anywhere. [More](#mobile-access)
77
-
78
- ![AgentOS on a phone: a chat and the session list](screenshots/mobile.png)
79
-
80
- ### Agents that talk to each other
81
-
82
- Sessions find and message each other with `aos peers`, `aos send` and
83
- `aos inbox`, start tasks and sessions, and schedule check-ins. You see every
84
- conversation in **Messages** and can join in. [More](#agent-network)
85
-
86
- ![Messages between agent sessions, and one from you](screenshots/messages.png)
87
-
88
- ### And the rest
89
-
90
- - **Chat or terminal, same conversation.** Streaming replies, steps and
91
- diffs, plan mode, a queue you can steer, slash commands and skills,
92
- `@file`, undo, and inline charts and pages. ⌘F (Ctrl+F) finds text
93
- anywhere in the conversation, tool output and older pages included, and
94
- opens the step it's in. One click hands the conversation to the agent's
95
- own terminal. [More](#chat)
96
- - **Project config.** `agentos.json` (or an existing `.dispatch.json`) gives
97
- each session its own ports, environment, copied files, cloned
98
- dependencies, a private Postgres copy, and a "Running this project"
99
- section in the agent's brief. [More](#project-config-agentosjson)
100
- - **Schedules.** Start tasks, chats or orchestrator prompts on a timer, or
101
- check in on a session, with run history. [More](#schedules)
102
- - **Recipes.** Save a job that comes up again (a build, an audit, a report);
103
- each run is a fresh task or session that is told what the last run
104
- reported. [More](#recipes)
105
- - **Plans in pieces.** A plan splits into several PRs only for a real reason,
106
- checked by AgentOS; later pieces start by themselves. [More](#plans-in-pieces)
107
- - **Stacks.** Run a board's cards as stacked PRs that merge bottom-up.
108
- [More](#stacks)
109
- - **Machine load.** A gauge in the sidebar, each session's share of CPU and
110
- memory, and a note to agents before they start a full test suite or build
111
- on a busy machine. [More](#machine-load)
112
- - **Status from the screen and the agent.** Every session moves between
113
- Needs you, Working and Done as it changes, including programs that report
114
- their own state (OSC 7501). [More](#the-sidebar)
115
- - **Also:** a ⌘K palette for every session and action, code search, a file
116
- picker with uploads from a phone, a git panel (diffs, commits, PRs), dev
117
- servers (Node and Docker), up to four panes side by side, dictation in the
118
- terminal toolbar, and tmux sessions you started yourself listed under their
119
- project.
120
-
121
- ![The slash-command menu open in a chat](screenshots/commands.png)
122
-
123
- ![A session in terminal view, with the agent asking before it runs a command](screenshots/terminal.png)
124
-
125
- **Guides:** step-by-step how-tos are in [`docs/guides/`](docs/guides/), starting with [installing AgentOS](docs/guides/install.md) and [using it from your phone](docs/guides/phone.md).
15
+ - **An orchestrator for each workspace.** A chat that starts tasks, answers blocked agents, and merges pull requests only through gates. Anything that is yours to decide waits as an ask. [More](docs/reference/orchestrator.md)
16
+ - **Tasks that end in a pull request.** Each gets its own worktree, branch and ports, runs the project's code review, and waits for your sign-off. [More](docs/guides/tasks.md)
17
+ - **Each kind of work on the right model.** Planning, review, implementation and titles each run on their own model, set in Settings → Models. [More](docs/reference/model-routing.md)
18
+ - **Nothing starts until you send.** ⌥N opens a draft with project, machine, agent and branch as chips. [More](docs/guides/sessions.md)
19
+ - **Other machines in the same list.** Link another machine that runs AgentOS and start or move work there. [More](docs/reference/machines.md)
20
+ - **Built for your phone.** The whole app works on a phone; pair it with a QR code. [More](docs/guides/phone.md)
21
+ - **Agents that talk to each other.** Sessions message each other with `aos`, and you see every conversation in Messages. [More](docs/guides/agent-network.md)
22
+ - **Chat or terminal, same conversation.** Streaming replies, steps and diffs, plan mode, slash commands, `@file`, undo. [More](docs/guides/chat.md)
23
+ - **Project config.** `agentos.json` gives each session its own ports, environment, files and a private Postgres copy. [More](docs/reference/project-config.md)
24
+ - **Schedules and recipes.** Start work on a timer, or save a job that comes up again. [More](docs/guides/schedules.md)
25
+ - **Plans in pieces and stacks.** A plan splits into several PRs only for a real reason; a board can run as stacked PRs. [More](docs/guides/tasks.md#plans-in-pieces)
26
+ - **Machine load and status.** A load gauge, each session's share of CPU and memory, and Needs you, Working, In review and Done as it changes. [More](docs/guides/sessions.md)
27
+ - **Workspaces.** Group projects, finish work with Done, and get a log of every merged task. [More](docs/reference/workspaces.md)
28
+ - **LumifyHub (optional).** Boards, cards and docs for a workspace, if you want them. [More](docs/lumifyhub.md)
29
+ - **Also:** a ⌘K palette, code search, a file picker, a git panel, dev servers, up to four panes, and dictation.
30
+
31
+ ## Documentation
32
+
33
+ - [Guides](docs/guides/README.md): [install](docs/guides/install.md), [phone](docs/guides/phone.md), [sessions](docs/guides/sessions.md), [chat](docs/guides/chat.md), [tasks](docs/guides/tasks.md), [schedules](docs/guides/schedules.md) and the [agent network](docs/guides/agent-network.md).
34
+ - [Reference](docs/reference/README.md): how each part works in detail, from the orchestrator's gates to the development workflow.
126
35
 
127
36
  ## Install
128
37
 
129
- The [install guide](docs/guides/install.md) walks through this step by step.
130
-
131
- You need Node.js 20+, tmux, and at least one agent CLI:
132
- [Claude Code](https://github.com/anthropics/claude-code),
133
- [Codex](https://github.com/openai/codex),
134
- [OpenCode](https://github.com/anomalyco/opencode),
135
- Pi,
136
- [Kilo Code CLI](https://kilo.ai/docs/cli),
137
- [Gemini CLI](https://github.com/google-gemini/gemini-cli),
138
- [Aider](https://aider.chat/), [Cursor CLI](https://cursor.com/cli), Amp or
139
- [GitHub Copilot CLI](https://github.com/github/copilot-cli) or
140
- [Kiro CLI](https://kiro.dev/docs/cli/).
38
+ You need Node.js 20+, tmux, and at least one agent CLI (the installer offers to set up what's missing).
141
39
 
142
40
  ```bash
143
41
  npm install -g @saadnvd1/agent-os
@@ -152,1890 +50,23 @@ curl -fsSL https://raw.githubusercontent.com/saadnvd1/agent-os/main/scripts/inst
152
50
  agent-os start
153
51
  ```
154
52
 
155
- From source:
156
-
157
- ```bash
158
- git clone https://github.com/saadnvd1/agent-os
159
- cd agent-os
160
- npm install
161
- npm run dev # http://localhost:3011
162
- ```
163
-
164
- Then open AgentOS, add a project from ⌘K, and press ⌥N. To use it from your
165
- phone, see [Mobile access](#mobile-access).
166
-
167
- ### Windows (WSL2)
168
-
169
- AgentOS runs on Windows inside WSL 2, as a Linux install. WSL 1 isn't
170
- supported (`wsl --set-version <distro> 2`). In an Ubuntu or Debian distro,
171
- run the install script above: it installs Node.js, tmux, ripgrep, lsof, a
172
- compiler for the native modules, and `wslu`, then prints the WSL next steps.
173
- The installer and the server both detect WSL the same way (the kernel
174
- release names Microsoft, or `WSL_DISTRO_NAME` is set).
175
-
176
- - **Open it from Windows** at `http://localhost:3011`. WSL 2 forwards
177
- localhost to the distro by default, and the server's loopback address is
178
- what's forwarded. Use `localhost`, not `127.0.0.1`: passkeys only work on
179
- localhost or https. With `networkingMode=mirrored` in `.wslconfig`
180
- (Windows 11), Windows and the distro share localhost directly. From a
181
- phone or another machine, install Tailscale inside the distro and use
182
- [Mobile access](#mobile-access) as on Linux.
183
- - **Keep projects in the Linux filesystem** (`~/code/...`), not on the
184
- Windows drive (`/mnt/c/...`). Git, npm and file watching are many times
185
- slower there, and changes made from Windows aren't seen by file watchers
186
- (inotify doesn't cross the boundary), so the "/" menu only picks up new
187
- skills after its cache expires. The folder picker warns on `/mnt/<drive>`,
188
- and the server log lists projects that live there.
189
- - **Links** open in the Windows browser through `wslview` (from `wslu`), or
190
- `explorer.exe` when it isn't installed. The server never touches the
191
- clipboard; copy buttons use the browser's.
192
- - **Approvals with a passkey** use Windows Hello in the Windows browser,
193
- registered for `localhost` (a passkey made on the tailnet https address is
194
- a separate one).
195
- - **Start at login**: `agent-os enable` writes a systemd user service, which
196
- needs systemd in the distro. Add this to `/etc/wsl.conf`, then run
197
- `wsl --shutdown` from Windows and reopen the terminal:
198
-
199
- ```ini
200
- [boot]
201
- systemd=true
202
- ```
203
-
204
- WSL still stops an idle distro, service and all, a few seconds after its
205
- last terminal closes. To keep AgentOS up without a terminal open, add this
206
- to `%UserProfile%\.wslconfig` (Windows 11) and start the distro at Windows
207
- login, for example with a Task Scheduler task running
208
- `wsl.exe -d <distro> -- sleep infinity`:
209
-
210
- ```ini
211
- [general]
212
- instanceIdleTimeout=-1
213
- [wsl2]
214
- vmIdleTimeout=-1
215
- ```
216
-
217
- What's been verified: the WSL detection and the installer's WSL paths have
218
- unit tests that run on any OS, and the manual [WSL workflow](.github/workflows/wsl.yml)
219
- ran on a GitHub-hosted Windows runner (Windows Server 2025, Ubuntu 24.04
220
- under WSL 2): the installer detected WSL 2 and installed what was missing
221
- through apt, tmux, lsof and node-pty worked, the server started and logged
222
- its WSL note, and Windows reached it at both `localhost:3011` and
223
- `127.0.0.1:3011`. Untested: Windows Hello approvals, links opening through
224
- `wslview`/`explorer.exe`, mirrored networking, `agent-os enable` under
225
- systemd, the idle-timeout settings above, and Debian or other distros.
226
-
227
- ### First run
228
-
229
- On a fresh install (no sessions, no projects of your own) the web app opens a
230
- short setup at `/?welcome`: it shows each agent CLI as ready, needing a
231
- sign-in, or missing, installs or signs one in from an embedded terminal, adds
232
- a first project (a folder, a clone or an empty one), then opens a session in
233
- it. A devices step offers to pair a phone, link another machine and set up
234
- notifications. Every step after the first can be skipped. It is remembered on the server,
235
- so a phone you pair later doesn't see it, and an install that already has work
236
- never does. Reopen it from Settings → Setup (**Run setup again**) or at
237
- `/welcome`; `AGENTOS_SKIP_WELCOME=1` turns it off. Settings → Setup & health
238
- also lists what this machine needs (Node, git, tmux, ripgrep, lsof, an agent
239
- CLI) with the fix for anything missing (`/api/doctor`).
240
-
241
- ### Supported agents
242
-
243
- | Agent | Chat | Resume | Fork | Auto-approve |
244
- | -------------- | ---- | ------ | ---- | -------------------------------------------- |
245
- | Claude Code | ✅ | ✅ | ✅ | `--dangerously-skip-permissions` |
246
- | Codex | ✅ | ✅ | ✅ | `--dangerously-bypass-approvals-and-sandbox` |
247
- | OpenCode | ✅ | ✅ | ✅ | `--auto` |
248
- | Pi | ✅ | ✅ | ✅ | Never asks |
249
- | Kilo Code | ❌ | ✅ | ✅ | Config file |
250
- | Gemini CLI | ❌ | ❌ | ❌ | `--yolo` |
251
- | Aider | ❌ | ❌ | ❌ | `--yes` |
252
- | Cursor CLI | ❌ | ✅ | ❌ | `--force` |
253
- | Amp | ❌ | ✅ | ❌ | `--dangerously-allow-all` |
254
- | Oh My Pi | ❌ | ❌ | ❌ | N/A |
255
- | GitHub Copilot | ✅ | ✅ | ❌ | `--allow-all` |
256
- | Kiro CLI | ❌ | ❌ | ❌ | `--trust-all-tools` |
257
- | Amazon Q (old) | ❌ | ❌ | ❌ | `--trust-all-tools` |
258
-
259
- Agents without chat run in the terminal. The new-session picker says when an
260
- agent isn't installed or needs a sign-in first, and what to run.
261
-
262
- Kiro CLI (and the older Amazon Q CLI, `q`, shown only where it is installed)
263
- signs in on its own: a session first checks `whoami`, and if you're signed out
264
- runs `login --use-device-flow`. AgentOS reads the link and one-time code off
265
- the screen and shows them in a card above the terminal, with a push when it's
266
- waiting, so you can finish on your phone. No credential passes through
267
- AgentOS. Identity Center sign-in (including Microsoft or Okta federation) works
268
- this way; a login through an external identity provider doesn't support the
269
- device flow, so sign in once on the machine itself, or set `KIRO_API_KEY`.
270
-
271
- ### CLI
272
-
273
- ```bash
274
- agent-os run # start and open the browser
275
- agent-os start # start in the background
276
- agent-os stop # stop the server
277
- agent-os restart # stop, then start
278
- agent-os status # show its addresses
279
- agent-os pair # add a phone, tablet or laptop (prints a QR code)
280
- agent-os logs # tail the logs
281
- agent-os update # update to the latest version
282
- agent-os enable # start at login (disable turns it off)
283
- agent-os passkeys reset # when every passkey is lost (see Orchestrator)
284
- agent-os uninstall
285
- ```
286
-
287
- # Reference
288
-
289
- Everything below is how each part works, in detail.
290
-
291
- ## Chat
292
-
293
- Sessions open as a chat by default: streaming replies, tool calls folded into
294
- expandable steps, inline diffs for edits, a plan checklist, highlighted code
295
- and mermaid diagrams, subagent cards, image attachments (pick, paste or drag
296
- them in) and a Stop button, all readable on a phone. Chat drives the same
297
- agent as the terminal, with your own logins: Claude Code through the Agent
298
- SDK, Codex through `codex app-server`, OpenCode through its own `opencode
299
- serve` (loopback only, behind a per-conversation password) and Pi through its
300
- RPC mode. Pi never asks before a tool, so AgentOS loads a small Pi extension
301
- that asks the chat as the access setting says. GitHub Copilot runs through
302
- `copilot --acp` (the Agent Client Protocol): its permission prompts become
303
- approval cards under the same access setting, and a conversation resumes with
304
- `session/load` after a restart. It signs in with `copilot login` or a
305
- `COPILOT_GITHUB_TOKEN`, `GH_TOKEN` or `GITHUB_TOKEN`; it has no plan mode,
306
- undo or in-chat model list yet, so it runs on its own default model unless one
307
- is named. The **Chat /
308
- Terminal** switch in the tab bar hands the same conversation between the two:
309
- the terminal resumes it (`claude --resume`, `codex resume`, `opencode
310
- --session`, `pi --session`, `copilot --resume`), and switching back closes the
311
- terminal so only one side drives it. Each chat conversation runs in its own
312
- worker process (in tmux, like terminal sessions), so restarting or updating
313
- AgentOS never cuts off a turn: the server reconnects to running workers when
314
- it starts. A worker from an older build finishes its turn, and any
315
- background work (subagents, shells), then hands over at the next turn
316
- boundary: messages that arrive meanwhile wait in the queue, and a current
317
- worker resumes the same conversation with this build's tools and sends them.
318
- An orchestrator fed events mid-turn picks up new tools this way with nobody
319
- restarting it. A turn whose worker did go away mid-step is resumed
320
- once, with a note telling the agent to check what it was doing, and a task's
321
- orchestrator hears about it. History is kept in AgentOS.
322
-
323
- The composer formats markdown as you type: `code`, **bold**, _italic_, lists,
324
- `- [ ]` task lists, and ` ```ts ` fenced blocks with syntax highlighting.
325
- What it sends is the markdown you typed, character for character. Code pasted
326
- from an editor (or anything multi-line that reads like code) lands in a code
327
- block, prose stays prose, and a paste of 32 KB or more becomes an attachment
328
- sent as a fenced block. Cmd/Ctrl+Shift+V pastes as plain text, and the **T**
329
- button (Cmd/Ctrl+/) turns live formatting off for this browser. Enter sends on
330
- a keyboard and is a newline on a phone; Cmd/Ctrl+Enter always sends.
331
- Shift+Enter is always a newline, and three of them at the end of a code block
332
- leave it.
333
-
334
- Type `/` in the composer for every slash command and skill the agent knows,
335
- yours included, filtered as you type. A skill or command you add or edit
336
- (in `~/.claude/skills`, `~/.claude/commands` or the project's own) shows up
337
- on its own; the menu's refresh button reloads the list now. Commands such as `/compact`, `/usage`
338
- and `/context` run in chat and show their output inline; skills the agent
339
- invokes on its own appear as a chip. `/model` (or the picker under the
340
- composer) switches the model mid-conversation. `/mcp` lists the session's MCP
341
- servers with their status and tools, without spending a turn. Commands that
342
- only make sense in a terminal, such as `/vim`, are left out, and say so if
343
- typed anyway.
344
-
345
- Type `@` for files and folders, matched the way Claude Code matches them
346
- (ripgrep over the folder until the agent is running), and pick one to insert
347
- `@path`. After each turn but the first, the agent's guess at your next message
348
- shows in the empty composer: **Tab** or **→** takes it, typing or **Esc** sets
349
- it aside; on a phone it's a chip to tap. **↑** and **↓** in an empty composer
350
- walk back through what you've sent. Select text in a reply and **Quote** puts
351
- it in the composer as a blockquote.
352
-
353
- A message sent while the agent is working waits in a queue above the
354
- composer, kept on the server so a reload doesn't lose it, and goes when the
355
- turn ends. Queued messages can be edited, moved or removed, and **Send now**
356
- stops the turn (as Esc does) and sends that one with the stop, so it's the
357
- very next thing the agent reads, ahead of a background task's notice it had
358
- waiting. A message typed right after Esc goes the same way.
359
-
360
- **Plan mode** (the **Plan** toggle under the composer, or Shift+Tab) has the
361
- agent read and plan without changing anything; it's remembered per session.
362
- When the agent has a plan it shows up as a card: **Carry it out** leaves plan
363
- mode and starts it, **Keep planning** goes back to the composer.
364
-
365
- The ring in the tab bar (in the composer on a phone) is how full the
366
- conversation's context is, measured against the room before auto-compact:
367
- amber past 60%, red past 85%. Tap it for the breakdown and **Compact now**.
368
-
369
- Two thresholds (Settings → Workspaces → Compact; 0 turns one off). Mid-turn,
370
- the agent compacts itself at 300k by default: AgentOS launches Claude Code
371
- with `CLAUDE_CODE_AUTO_COMPACT_WINDOW` set to that size (its floor is 100k),
372
- high enough that a long job isn't cut in half. Between
373
- turns AgentOS catches what it didn't: a chat over its 150k threshold is compacted
374
- before the next message, and so is one idle past its prompt cache (5 minutes
375
- or an hour, read from the agent's own usage), whose next message would
376
- re-read the whole conversation at the cache-write price. A chip above the
377
- composer says "Idle 47m · 412k context · Compact first?": Send compacts and
378
- then sends, **Send as-is** skips it for that one message. Messages nobody is
379
- typing (the orchestrator's `send`, AgentOS events and wakes, `aos send`,
380
- schedules) compact first on their own, only between turns, and the chat
381
- shows one quiet line with the context before and after. An orchestrator
382
- isn't compacted (a summary would lose the fence around what it read from
383
- tasks and CI): it starts a fresh conversation from its brief and the current
384
- state at its fresh-start threshold, or earlier once idle past its cache.
385
- While a chat compacts (any trigger, Claude, Pi or Codex) it is shown as
386
- compacting, not just working: a pulsing blue dot and a "Compacting" chip in
387
- the sidebar, and "Compacting context… 182k tokens" above the composer. The
388
- status API (`/api/sessions/status`) keeps `status: "running"` and adds
389
- `compacting: { since, before? }`; the orchestrator's `sessions` tool says
390
- "compacting context". It clears when the compaction ends, errors, is
391
- stopped, or the worker goes away.
392
- What survives a compaction: the summary is asked to keep the task, scope
393
- changes, every edited file by path, what's done, in progress and next, and
394
- the decisions. Right after it, AgentOS hands back a note built from its own
395
- records (a task's brief and scope changes, the files it edited, its todos,
396
- the latest message and `git status`), which doesn't depend on what the
397
- summary kept, and tells the agent not to re-read or rewrite whole files.
398
- Terminal agents don't get the note yet.
399
- On a desktop browser the screen button attaches a screenshot of a screen or
400
- window you pick; on a phone, attach a screenshot as a photo.
401
-
402
- **Usage** (the sidebar's ⋯ menu, or the palette) shows the account's 5-hour
403
- and weekly windows, and what chats cost today, over 7 or 30 days, by day,
404
- workspace and session. Costs are the agent's own estimates, recorded as each
405
- turn ends. **Gate reviews** below it shows what the orchestrator's
406
- independent reviewer and scope check cost, by PR: they run as `claude -p`
407
- and leave no transcript, so each run's tokens, model and duration are read
408
- from its JSON result into `check_runs`, and the review's verdict says them
409
- too. Every compaction is kept in `chat_compactions` (who ran it, whether it
410
- fired `mid_turn` or `between_turns`, and the context before and after), so cost per task can be compared by date.
411
- Rows from before the column existed, and any written by a chat worker still
412
- running older code, have a NULL `phase`: read those as unknown
413
- (`COALESCE(phase, 'unknown')`), not as either kind.
414
-
415
- **Esc** stops a running turn, as it does in Claude Code's terminal, unless a
416
- menu, dialog or the command list is open (those close first). On a phone the
417
- Stop button does the same. A stopped turn keeps what it wrote.
418
-
419
- Stop ends the turn even while the model is still thinking, before any tool
420
- call: the turn is interrupted, and if it hasn't ended within a few seconds the
421
- agent process is ended and restarted for the next message (not if the chat is
422
- waiting on an approval or question, or if a new message has started a new
423
- turn meanwhile). The conversation and
424
- worktree are kept, and whatever is sent next (yours, another agent's, the
425
- orchestrator's) runs as the next turn, never queued behind the stopped one.
426
- The UI, the orchestrator's `stop` tool and `aos stop` all take this one path
427
- and report "stopped" or a real error.
428
-
429
- A turn that has produced nothing (no token, tool call or result) for 8 minutes
430
- shows as **Stalled** in the session list, and its workspace's orchestrator gets
431
- one event naming the session, how long it has been silent and its last action.
432
- It fires once per stall and starts over when the session does something. A
433
- foreground tool call gets four times as long, and a session waiting on a
434
- background command it started isn't flagged. Set the time (2 to 120 minutes, 0 for off)
435
- in Settings → Workspaces → Stall alerts.
436
-
437
- The access picker under the composer sets what the agent may do on its own:
438
- **Ask first** (an approval card in the chat for anything not already allowed),
439
- **Accept edits** (edits files, asks before other commands) or **Full access**
440
- (the default, like running with permissions skipped). Questions the agent asks
441
- you come up as cards to answer. **Undo** on a message puts back the files the
442
- agent edited since, rewinds the conversation to before it, and returns the
443
- message to the composer to edit and resend. Changes made by shell commands
444
- aren't tracked, so they stay.
445
-
446
- While a turn runs, a line above the composer says what the agent is doing
447
- and for how long (with Stop), and every step shows its time. Work the agent
448
- starts in the background (shells, subagents, monitors) sits behind a
449
- "running in background" chip: each task with its elapsed time, its live
450
- output, and its own Stop. The session list says the same thing, so a long
451
- wait never looks like nothing is happening.
452
-
453
- **Visuals.** Every chat agent (not an orchestrator, which reads other
454
- sessions' text and gets no browser) has two tools: `html_preview` renders a page in
455
- headless Chrome and hands back a screenshot plus the console, so it can check
456
- its own work, and `html_render` shows the finished page (a chart, a table, a
457
- mockup) inline as its own card, with full screen and "open in new tab". Pages
458
- are kept under `~/.agent-os/artifacts/<session>/` with a row in SQLite, so
459
- they survive reloads and restarts (`GET /api/sessions/<id>/artifacts` lists
460
- them). They're served behind the same device gate with a CSP sandbox and no
461
- same-origin access, so a page can't read AgentOS cookies or call its API; the
462
- preview browser gets an empty profile and a proxy that only reaches public
463
- addresses. An image or SVG file the agent writes shows inline when its reply
464
- links to it by absolute path. The tools read files and reach the web, so
465
- under **Ask first** they ask like any other tool. Previews need Chrome, Chromium, Brave or Edge
466
- installed (or `AGENTOS_CHROME` pointing at one).
467
-
468
- Chat runs on this machine, and on linked machines through their own AgentOS
469
- (see [Machines](#machines)); sessions on machines reached over ssh only use
470
- the terminal.
471
- Drivers for other agent CLIs plug into `lib/chat/drivers`; undo, `@file`
472
- suggestions and visuals are Claude-only for now, and plan mode is Claude and
473
- OpenCode.
474
-
475
- ## Tasks
476
-
477
- Hand off work and keep going. A task is a draft with **Open a PR when
478
- done** turned on (**New task** in ⌘K, the sidebar's New menu or the Tasks
479
- panel opens one). AgentOS creates a git worktree and branch, starts Claude there in tmux
480
- with a brief to finish by pushing and opening a pull request, and tracks it:
481
- Working, Needs input, Blocked, Ready for review, Checks failing or Agent
482
- exited. **Sign off & merge** merges the PR (refused while CI is failing
483
- or pending), then removes the session, worktree and branches. **Drop** closes
484
- the PR and removes everything. Agents never merge their own work.
485
-
486
- **Merging settings.** How a PR merges (sign-off, Done, Land and the
487
- orchestrator's external PRs alike) and what's cleaned up after it are set in
488
- **Settings → Merging** (or ⌘K → Merge settings) for every project,
489
- and overridden per project in its **Project Settings → Merging** or in its
490
- `agentos.json`:
491
-
492
- ```json
493
- {
494
- "merge": {
495
- "method": "rebase",
496
- "delete_remote_branch": true,
497
- "delete_worktree": false
498
- }
499
- }
500
- ```
501
-
502
- `method` is `squash` (the default), `merge` (a merge commit) or `rebase`.
503
- GitHub enforces the repository's allowed methods: if it refuses the one set,
504
- the merge fails with a message naming the method and the repository setting
505
- to turn on (Settings → General → Pull Requests), and AgentOS never falls back
506
- to another method. The project's settings show a method its repository has
507
- turned off. `delete_remote_branch` and `delete_worktree` (both on by default)
508
- delete the branch on origin and the local worktree with its branch after a
509
- merge. With either on, `main`, `master` and `HEAD` are never deleted, nor a
510
- branch a stacked task still targets, nor a worktree holding uncommitted work
511
- or commits the merge didn't include. The most specific setting wins: the
512
- project's, then `agentos.json`, then the global one.
513
-
514
- **Queued tasks.** A workspace can limit how many tasks run at once (none by
515
- default; set it in **Settings → Workspaces**, or `PATCH /api/workspaces/<id>` with `{"maxRunningTasks": 3}`, or
516
- `null` for no limit). A task started over the limit is queued, with no
517
- worktree or agent yet, and starts by itself in line order when one finishes
518
- (merged, dropped or done). `aos task --after <task|any>` (and the
519
- orchestrator's `start_task` with `after`) holds a task until a named task
520
- finishes, or until any task still working now does (a running task whose PR
521
- was closed or merged doesn't count; with none, it starts at once). The
522
- orchestrator's `drop` removes a queued task by its id. Pause stops automatic starts,
523
- and the orchestrator's brakes still apply when its queued tasks start. A task runs on Claude Code unless
524
- `POST /api/tasks` names another `agent` (`"copilot"`): that one runs as a chat on
525
- this machine, with no plan-first step or role models, and is never picked for
526
- you. The
527
- line is kept in the database across restarts (`GET /api/tasks/queue`; start
528
- now, move up or down, or remove with `/api/tasks/queue/<id>`). The sidebar
529
- shows them under **Queued** with their place in line or what they wait on,
530
- and the same actions in each row's menu; a row becomes the task's own row
531
- when it starts. Why it works
532
- this way: [docs/decisions/2026-10-10-queued-tasks.md](docs/decisions/2026-10-10-queued-tasks.md).
533
-
534
- A paired device's token can run the building loop through read-only routes:
535
- `GET /api/start-options?projectId=` (agents and models, the models a task can
536
- run on, machines, branches, whether a task plans first, in one request),
537
- `GET /api/tasks/<id>/diff` (the task's whole change, base to head: a file list,
538
- then `?file=<path>` for one file's patch; capped, with `truncated` when a cap
539
- is hit; read from the worktree, else the PR), and `GET /api/tasks/<id>/checks`
540
- (the PR head's checks, the tail of a failing job's log, and the review gate's
541
- verdict). A task's `plan` in `GET /api/tasks` carries `status` (`writing`,
542
- `ready` or `approved`), a title and capped text. Their shapes are in
543
- `lib/tasks/loop-types.ts`, which has no server imports so a client can share it.
544
-
545
- ## Model routing
546
-
547
- Each kind of work AgentOS launches an agent for runs on its own model, set in
548
- **Settings → Models** (⌘K → Model settings). A model is named
549
- `provider/model`:
550
-
551
- | Role | Default |
552
- | --------------------------------------------------- | ------------------------------------- |
553
- | Task planning (a task's plan step) | `anthropic/claude-opus-5-5` |
554
- | Gate review | `anthropic/claude-opus-5-5` |
555
- | Task implementation | `anthropic/claude-sonnet-5-5` |
556
- | Orchestrator | `anthropic/claude-opus-5-5` |
557
- | Scope check | `anthropic/claude-sonnet-5-5` |
558
- | Interactive sessions | `anthropic/claude-opus-5-5` |
559
- | Chat & summary helpers (titles, summaries, PR text) | `anthropic/claude-haiku-4-5-20251001` |
560
-
561
- The most specific setting wins: a task's own model, then its workspace's
562
- (**Settings → Workspaces → Models**), then Settings, then the default.
563
- `AGENTOS_REVIEW_MODEL` (gate review and scope check) and
564
- `AGENTOS_TITLE_MODEL` (helpers) in the server's environment still replace a
565
- role's default where Settings names none. A
566
- Claude session you start without a model runs on the interactive role's. One
567
- an orchestrator starts (its `start_session`, or `aos spawn` run from an
568
- orchestrator) is recorded as started by it (`started_by`) and runs on the
569
- implementation role instead, so delegated work doesn't use Opus by default;
570
- `start_session` takes a `model` (`"provider/model"`, checked like a task's:
571
- gate roles can't be set, other providers must be enabled). One you pick a
572
- model for keeps it.
573
-
574
- **Plan, then implement.** A chat task whose planning and implementation
575
- models differ starts with a plan step: its first turn runs on the planning
576
- model and writes the plan to `.agentos/plan.md` in its worktree (ignored by
577
- git), changing nothing else. When that turn ends, the same conversation
578
- switches to the implementation model (a live model switch, or a resume with
579
- `--model` when the provider changes) and is told to follow the plan. Turn it
580
- off in Settings, or per task with `plan: false`. Terminal tasks skip it. An
581
- orchestrator decides it for every task: `start_task` requires `plan` and a
582
- short `plan_reason`, stored on the task and shown on its card ("Planned:
583
- touches 6 files across gates and UI" / "No plan: one-line default change"),
584
- and **Usage → Compare** splits cost into planned and not. When the plan step
585
- finishes, the orchestrator gets one event with the plan file's path and a
586
- 3-5 line summary; the handoff to implementation stays automatic.
587
-
588
- **Plan only.** A task started with `plan_only` (`start_task`'s `plan_only`,
589
- `aos task --plan-only`, or `plan_only: true` on `POST /api/tasks`) writes its
590
- plan on the planning model and then stops: no model switch, no implement
591
- prompt, even when one model does every role. It sits in a **Plan ready**
592
- state (`plan_phase` `awaiting`, stored on the task, so it survives a restart)
593
- that isn't blocked, doesn't count as needing you, and holds no agent process
594
- (its worker is released; the conversation resumes on approval). The
595
- orchestrator gets one event with the plan's path, a summary and that the task
596
- is waiting. **Approve** on the task row (plan viewable there), `POST
597
- /api/tasks/<id>/approve-plan`, or the orchestrator's `approve_plan(task,
598
- message?)` continues it on the implementation model, once; a message amends
599
- the plan and is recorded on the task's brief as a scope change, so the review
600
- judges against it. Reject with **Drop**. A chat task on this machine only; it
601
- can't move until approved.
602
-
603
- **Per task.** The task draft has a **Model** chip ("Routed by role", or one
604
- model); `POST /api/tasks` and the orchestrator's `start_task` take `model`, as
605
- `"provider/model"` for the task's own roles or a map such as
606
- `{"implement": "zai/glm-5.3"}`, and `plan`. Its gate review and scope check
607
- never follow a task's model, only Settings and its workspace, so work can't
608
- pick its own reviewer. **Resume on model…** on a task's row
609
- (or `POST /api/tasks/<id>/model`, or the orchestrator's `set_task_model`)
610
- moves a paused task to another model: same conversation, same worktree, and
611
- it keeps that model from then on. Each turn records the model, provider and
612
- role it ran as.
613
-
614
- **Providers.** `anthropic` is your Claude login and needs no key. Others are
615
- Anthropic-compatible endpoints (OpenAI-compatible ones can be defined and
616
- tested, but Claude Code can't run on them): a base URL, where the key lives,
617
- the models, and Claude Code's opus/sonnet/haiku tiers mapped to them so
618
- subagents and background calls stay on that provider. DeepSeek
619
- (`https://api.deepseek.com/anthropic`) and Z.ai GLM
620
- (`https://api.z.ai/api/anthropic`) ship as presets, off until given a key.
621
- Claude stays the default: another provider runs only where a role or a task
622
- picks it. If a role's provider is turned off or its key can't be read,
623
- helper runs, reviews and the orchestrator fall back to the role's default
624
- rather than fail. **Test provider** sends one tiny request and says whether it
625
- answered. Changing models, providers or the test runs only from this machine
626
- or over Tailscale, never from a paired device: a provider's URL and key
627
- reference decide where a key is sent.
628
-
629
- The key is never stored by AgentOS. A provider names where to read it: a
630
- tokenvault entry (`tv get <project> <desc>`), a macOS Keychain item
631
- (`security find-generic-password -s <service> -w`) or an environment
632
- variable named `*_API_KEY` (not `ANTHROPIC_`, `CLAUDE_` or `AGENTOS_`). It's read when an agent launches and goes only into that agent's
633
- environment (`ANTHROPIC_BASE_URL` with `ANTHROPIC_AUTH_TOKEN` or
634
- `ANTHROPIC_API_KEY`), never its command line, the database, a prompt or a
635
- log; a terminal task's shell reads it from the reference itself. Errors that
636
- might echo a key are scrubbed of it.
637
-
638
- **Usage → Daily: the usage ledger and the ratchet.** Every Claude response
639
- an AgentOS chat makes (subagents and the orchestrator included) is written to
640
- `usage_calls` as it arrives, with its input, cache read, 5-minute and 1-hour
641
- cache write and output tokens, its model, its context size and the
642
- session, task, workspace and role it belongs to. Terminal sessions, which no
643
- worker watches, are read from Claude's transcripts, and gate reviews come
644
- from `check_runs`; the same message id is never counted twice. Tokens are
645
- _weighted_ by the API's price ratios (Opus input 1, 5-minute write 1.25,
646
- 1-hour write 2, cache read 0.1, output 5; Sonnet half, Haiku a quarter), an
647
- estimate of how much of the plan's limits a call uses.
648
-
649
- The 5-hour and weekly windows come from the `rate_limit_event`s Claude Code
650
- sends on each response (the `anthropic-ratelimit-unified-*` headers), stored
651
- with their time in `rate_limit_readings` with no extra calls. An event
652
- carries one window, so the weekly figure can go stale: when it is over 6
653
- hours old it is estimated from recorded usage and marked `~`.
654
-
655
- A rollup job inside the server (no model) writes one `usage_rollups` row per
656
- day: weighted total, cost per merged PR, cost per _clean_-merged PR (the
657
- headline: cost against quality), review cost per PR, the share of calls above
658
- 200k context, model mix, orchestrator share, the weekly %, and the quality
659
- readings from existing data: first-try clean-merge rate (the first reviewed
660
- head passed review and CI, no gate failures, no later head), fix rounds per
661
- PR, gate escalations, scope changes, and escapes (a revert or fix PR touching
662
- the same files within 3 days, from `gh`; unknown rather than zero if `gh`
663
- fails). Spans of days are ratios of sums. The baseline is the first week of
664
- rollups and only ever moves to a better value. One phone alert fires (and
665
- stays quiet until it clears) when the 3-day cost per merged PR is over
666
- baseline by 15%, or the clean-merge rate is under it by 10 points, naming the
667
- supporting metric that moved most. The margins, the days averaged and the
668
- minimum merges to judge are settings (`usage.alert_cost_pct`,
669
- `usage.alert_clean_points`, `usage.avg_days`, `usage.alert_min_merges`,
670
- `usage.baseline_days`, `usage.weekly_stale_hours`). A dev server doesn't run
671
- it unless `AGENTOS_USAGE_ROLLUP=on`; `AGENTOS_USAGE_ROLLUP=off` turns it off
672
- in production. `POST /api/usage/rollups` runs the nightly pass now. Task
673
- cards show each task's weighted cost so far.
674
-
675
- **Usage by model.** **Usage → By model** shows tokens and estimated cost per
676
- role and per model in the plan's 5-hour window and the last 24 hours, from
677
- the price table in Settings → Models (dollars per million input, cache
678
- write, cache read and output tokens, editable).
679
-
680
- **How to read the comparison.** **Usage → Compare** (or ⌘K → Model
681
- comparison, or the sidebar menu) puts Claude-only tasks (the baseline,
682
- including everything from before routing) beside routed ones, per provider,
683
- over 7, 30 or 90 days, with a total column. A task counts under the provider
684
- its own planning and implementation turns ran on; its reviews and checks add
685
- to its cost wherever they ran. For each column: tasks, turns, tokens,
686
- estimated dollars (list prices; for Claude, what the API would charge),
687
- Claude window points per task (how far each turn moved the plan's 5-hour
688
- window, an estimate), agent time, CI green on the first push, review passed
689
- on the first try, gate failures and rework commits per task (heads checked
690
- after the first review), and merged or dropped. Outcomes come from the
691
- orchestrator's checks, so tasks it didn't run have cost but no outcome. A
692
- column with fewer than 10 tasks is marked a small sample: a hint, not a
693
- result. Parity means the routed column's outcome rows match the baseline's
694
- while its window points per task drop. Why it works this way:
695
- [docs/decisions/2026-10-11-model-routing.md](docs/decisions/2026-10-11-model-routing.md).
696
-
697
- ## New sessions
698
-
699
- ⌥N (the **+** on a phone) opens a draft: a composer in the current project, or
700
- the one you used last. Nothing exists until you send. Then the session is
701
- made, and with a worktree its setup runs in the chat, stage by stage: fetch,
702
- worktree, env files, dependencies, the project's setup script, with a log
703
- tail. The first message waits in the queue until setup is done, so the agent
704
- never starts on half-installed dependencies, and a restart can't lose it. The
705
- worktree starts on a temporary branch, renamed from the first message once
706
- it has a title (it keeps the temporary name if there's nothing to name it
707
- from).
708
-
709
- ⌥N reuses the project's empty draft; a draft you've typed in stays in the
710
- sidebar's **Drafts** until you send or discard it. A new draft takes the
711
- agent, model and access you were using; a project's own agent and model win.
712
- Chats with no project run in `~/.agent-os/scratch`.
713
-
714
- A task or session started from a prompt gets a short name: the brief's first
715
- heading at once (when the prompt points at a readable `.md` brief), then a
716
- 2-6 word title from a quick Haiku call a few seconds later. A chat opened as
717
- "Session 4" is named after its first message. Anything named by hand, a card's
718
- title, a schedule's name or `--name` is kept as given.
719
-
720
- The agent starts once its worktree has its dependencies. On macOS the main
721
- checkout's `node_modules` (and workspace ones like `apps/web/node_modules`)
722
- are cloned with `cp -Rc` when the lockfile matches, and a spare clone waits in
723
- `~/.agent-os/spare` so the next task takes it by rename, in milliseconds.
724
- Otherwise, and on Linux, the lockfile's frozen install runs (`npm ci`,
725
- `pnpm/yarn/bun --frozen-lockfile`), then a plain install, always with
726
- devDependencies even though the server runs with `NODE_ENV=production`. A
727
- project's `agentos.json` can name exactly what to copy and clone, and its
728
- `setup` commands (without a `clone`) replace the install; see
729
- [Project config](#project-config-agentosjson).
730
- Starting a task returns at once and shows **Setting up** until the agent
731
- launches; a restart in the middle resumes it. A failed setup shows on the task
732
- and is in the agent's first prompt (redacted, as data).
733
-
734
- Tasks don't review their own PRs. The orchestrator's independent review of
735
- the PR's exact head commit is the one review: `sign_off` and a stack's
736
- **Land** refuse a PR without a passing one, and a PR body with AI
737
- attribution. A head AgentOS rebased itself is covered by the review of the
738
- head it rebased while the PR's own patch is unchanged. A task may still run
739
- `/do-code-review` (the project's `.claude/skills/do-code-review`, or Claude
740
- Code's `/code-review`) on a risky change before its PR; it's no longer
741
- required. The review agents are in [.claude/agents](.claude/agents) and the
742
- skill in [.claude/skills](.claude/skills/README.md).
743
-
744
- Requires the GitHub CLI (`gh`) signed in, and a project with a GitHub remote.
745
-
746
- ![Tasks in different states: needs input, working, merged](screenshots/tasks.png)
747
-
748
- Tracking PRs stays inside GitHub's GraphQL quota (5,000 points an hour).
749
- Only running tasks are asked about: a finished task's PR comes from the
750
- database. One `gh pr list --state open` per repository a minute covers every
751
- running task with an open PR, and a branch without one is asked about on its
752
- own at most every 5 minutes. A merge or sign-off always asks fresh. When gh
753
- reports a rate limit, every gh call backs off until the limit resets, and gh
754
- failures are logged as `[gh] ...`, at most once a minute for each kind.
755
-
756
- ### Project config (`agentos.json`)
757
-
758
- A project describes how its sessions run in `agentos.json` at the repository
759
- root. Every field is optional:
760
-
761
- ```json
762
- {
763
- "ports": { "RAILS_PORT": 3000, "VITE_PORT": 3100 },
764
- "env": { "STORAGE_PROVIDER": "disk" },
765
- "copy": [".env", "config/master.key"],
766
- "clone": ["node_modules"],
767
- "setup": ["bin/setup"],
768
- "dev": "bin/dev",
769
- "ready": { "url": "/up", "port": "RAILS_PORT" },
770
- "test": "bundle exec rspec",
771
- "browse": { "login": "/dev/login", "map": "docs/browsing.md" },
772
- "database": { "from": "app_development", "env": "DATABASE_NAME" },
773
- "notes": ["Kill your own server by port: lsof -ti tcp:$RAILS_PORT"],
774
- "merge": { "method": "squash" },
775
- "deploy": {
776
- "deployed": "~/.deploy/deployed",
777
- "health": "https://app.example.com/up"
778
- }
779
- }
780
- ```
781
-
782
- `merge` sets the project's merge method and branch clean-up (see
783
- [Merging settings](#tasks)).
784
-
785
- `deploy` is how [Away mode](#orchestrator) checks a merge went live: `deployed`
786
- is a file your deploy writes the deployed commit to, `failed` (optional) one it
787
- writes a commit whose deploy failed to, and `health` (optional) a URL that
788
- answers 2xx once the server is back (a path alone is this AgentOS server's own,
789
- as this repository's `agentos.json` uses with `scripts/autodeploy`'s state
790
- files). A merge counts as deployed once the `deployed` commit contains it and
791
- `health` answers; as failed when the `failed` commit contains it, the server
792
- doesn't come back within 3 minutes (or, when its health answer has a
793
- `startedAt`, hasn't restarted since the merge), or it isn't deployed `within_minutes`
794
- (30) after the merge. No `deployed` file on the machine means nothing deploys
795
- there, and nothing is checked.
796
-
797
- Every task and worktree session takes a **port slot**, and each named port is
798
- `base + slot` (a project with no `ports` still gets a `PORT` from 3100), so
799
- parallel sessions never share a dev server port. The slot is kept on the
800
- session and freed when it's done or deleted (an archived or merged one's once
801
- its agent has stopped). The ports and
802
- `env` are exported to the setup commands, the agent and its terminals; a port
803
- always wins over an `env` entry of the same name, and `env` can't set names a
804
- shell, runtime, git or the agent reads (`PATH`, `NODE_OPTIONS`, `TERM`,
805
- `GIT_*`, `ANTHROPIC_*`, `AGENTOS_*`…): a config that sets one, such as
806
- `NODE_OPTIONS` or `TERM`, is refused, and the error names the variable and why. The agent's brief gets a
807
- short **Running this project** section: its ports, the dev command, how to
808
- wait for `ready` in one backgrounded call, the test command, the login URL on
809
- its own port, the browsing map and the notes. Only declared fields are
810
- mentioned, and `env` values never are. Keep secrets out of the file: it is
811
- committed.
812
-
813
- With `database`, every task and worktree session gets its **own Postgres
814
- database**, a copy of `from` named `<from>_aos_<hash of the session>`, made
815
- before setup runs and exported as `env` (default `DATABASE_NAME`, plus
816
- `PGPORT`/`DATABASE_PORT` and `PGHOST`/`DATABASE_HOST` when `port`/`host` are
817
- set), so one session's migrations never reach another's. It's copied with
818
- `pg_dump` into a database created from `template0`, not `createdb -T <from>`,
819
- which refuses while the dev server is connected to `from`. Only a local server
820
- is used (`host` may be `localhost`, `127.0.0.1`, `::1` or one socket folder), and
821
- `from` must be a plain database name. A copy left by an earlier start of the
822
- same session is reused. When Postgres isn't answering or the copy fails, the
823
- session still starts, without one, and its brief says so. The copy is dropped
824
- when the session is done, merged, dropped, moved away or deleted, and only one AgentOS made
825
- for that session (its comment names the session): `from` and any other
826
- database are never touched.
827
-
828
- The file is validated against
829
- [agentos.schema.json](lib/project-config/agentos.schema.json); a broken one
830
- fails the setup with every bad field named, rather than being ignored. Without
831
- an `agentos.json`, a `.dispatch.json` is read with the same meanings, then the
832
- legacy `.agent-os/worktrees.json` and `.agent-os.json`. The config is always
833
- read from the main checkout, so an agent can't change its own environment by
834
- editing it, and the merge gates flag an edit to it as agent config. The full
835
- schema, including the fields later releases implement (MCP servers, apps,
836
- recipes), is in
837
- [docs/decisions/2026-10-10-agentos-json.md](docs/decisions/2026-10-10-agentos-json.md).
838
-
839
- ### iOS simulator for tasks
840
-
841
- On a Mac, a task on an iOS app can boot a simulator of its own, put a debug
842
- build of its worktree on it, tap through screens, read the accessibility tree
843
- and take screenshots, to check a UI fix before anyone installs a release
844
- build. A project opts in with a `simulator` block in `agentos.json`:
845
-
846
- ```json
847
- {
848
- "ports": { "METRO_PORT": 8100 },
849
- "simulator": {
850
- "start": "npm run sim",
851
- "app": "com.example.app",
852
- "device": "iPhone 17"
853
- }
854
- }
855
- ```
856
-
857
- `start` runs in the task's worktree with `SIMULATOR_UDID` (and the task's
858
- ports) in its environment. It builds if needed, installs the app on that
859
- device and exits 0 once the app is up; AgentOS builds nothing itself, because
860
- the project knows its native fingerprint and what to cache. `app` is the
861
- bundle id, and `device` the model (default `iPhone 17`).
862
-
863
- A project without the block gets nothing: no brief lines and no tools. A task
864
- declares nothing and chooses nothing; it runs:
865
-
866
- ```bash
867
- aos sim open [--no-wait] # make its simulator, run start; waits until it is up
868
- aos sim status | close
869
- aos sim snapshot -i # accessibility tree with @e1, @e2... refs
870
- aos sim click @e3 | fill @e5 "text" | scroll | swipe | back | home | find | wait
871
- aos sim screenshot [path] # prints a PNG path under ~/.agent-os/simulators/<task>/shots
872
- aos sim logs --last 2m # the app's recent log
873
- ```
874
-
875
- - **Driving** is [agent-device](https://github.com/callstack/agent-device) (MIT),
876
- pinned and installed on first use into `~/.agent-os/tools`, with its own
877
- state dir. Only the commands above are accepted; the device and session are
878
- filled in by the server, so a task can only reach its own simulator.
879
- - **One simulator per task**, cloned from a base device AgentOS makes once on
880
- the newest iOS runtime. At most two are booted at once across all tasks
881
- (`AGENTOS_SIMULATOR_MAX`); one idle for 15 minutes is shut down and boots
882
- again on its next command. The XCTest runner builds the first time per Xcode
883
- version (minutes), then is cached.
884
- - **Cleanup**: a task's simulator is deleted when it is done, signed off,
885
- dropped, deleted or moved away, and shut down when stopped. A sweep at start
886
- and every 5 minutes also removes those of tasks that ended or crashed.
887
- Devices are named with a per-database prefix and only those are ever
888
- touched, so a dev instance and the real one never reap each other's.
889
- - **Mac only.** On any other machine, including a linked one a task was moved
890
- to, the brief says the simulator is unavailable and `aos sim` says the same;
891
- nothing is forwarded between machines.
892
- - **Optional.** No merge, review or release check reads simulator state.
893
- Screenshots are written outside the worktree, and the brief tells the task
894
- not to put them in commits or PR bodies unless they belong there.
895
-
896
- ### Stacks
897
-
898
- A project whose board is linked to LumifyHub can run the whole board as
899
- **stacked** tasks: **Tasks → From the board → Run as stack** shows the plan
900
- first, then starts it. A card starts as soon as every card it's blocked by has
901
- a PR open (not merged), on top of the card it depends on most: its branch is
902
- cut from that card's pushed branch, and its PR targets it, so each PR shows
903
- only its own commits. At most three run at once without a PR (adjustable).
904
-
905
- Merging goes bottom-up. Signing off a card whose parent hasn't merged is
906
- refused; after a parent merges, every card stacked on it (grandchildren
907
- included) is rebased and its PR retargeted, and its agent is told. This works
908
- with every merge method: only the child's own commits are replayed onto the
909
- default branch, whether the parent was squashed, rebased or merged with a
910
- merge commit. **Land**
911
- merges every PR in order after checking all of them are open and green, and
912
- waits for each restacked PR's checks before merging it. A chat card's agent
913
- is stopped between turns before anything merges (Land waits up to 5 minutes
914
- for a running turn, and refuses, naming the card, if it doesn't end), and
915
- what it's sent during the land waits in its queue. A conflict stops on
916
- that card with the exact command to fix it.
917
-
918
- ### Recipes
919
-
920
- A recipe is a saved brief: a project, a kind (a **task**, which ends in a PR
921
- and goes through the merge gates, or a **session**, which has no PR), and a
922
- short brief that says what to run and how to judge it. The steps belong in a
923
- script in the repo; the recipe says "run this, judge the result". Every run
924
- is a fresh task or session, so nothing piles up in one long conversation.
925
-
926
- Open **Settings → Recipes** (the sidebar's **⋯** menu, the workspace menu, or
927
- ⌘K → Recipes or "Run recipe: …"). **Run** takes an optional one-off note and
928
- shows exactly what will be sent. **Save as recipe** on a session's menu or a
929
- finished task prefills the form from what it did, with a suggested brief to
930
- use or ignore.
931
-
932
- - **Carried between runs.** A run ends with one line,
933
- `RESULT: ok|fail key=value … | one sentence`. The next run's brief gets a
934
- short block (at most 600 characters) with the last run's outcome and
935
- those values, such as a build number; after a failure it also carries the
936
- last good run. With no line, a cheap model summarises the run, and with
937
- that unavailable the state alone is recorded. **Start the next run fresh**
938
- drops the block.
939
- - **One run at a time.** A run while another is going is refused, and a
940
- double tap starts one run.
941
- - **Timers.** A recipe can run hourly, daily, on weekdays, weekly or on a
942
- cron expression, never more than once an hour; a timer that fires while a
943
- run is going is skipped. Only you set timers: the orchestrator can't.
944
- - **Orchestrator.** `recipes`, `run_recipe`, `recipe_save` and `recipe_update`
945
- tools, and the workspace's recipes in its brief and digest. A run goes
946
- through the same brakes, Pause and task queue as a task it started
947
- itself, and a recipe is never an approval: it can't pass a gate. The
948
- orchestrator gets an event when a run it started finishes, and for any
949
- failure.
950
- - **History.** Each recipe lists its runs: when, how triggered and by whom,
951
- outcome, the reported values, cost, duration, and links to the session and
952
- PR, with totals.
953
-
954
- ### Plans in pieces
955
-
956
- A plan ends with a `## Pieces` block, one piece by default. AgentOS accepts
957
- more only for one of four reasons, written on the piece: (a) it spans
958
- repositories, (b) one part must be live (merged and deployed) before the
959
- other can merge, (c) one part needs you mid-way, (d) one part must be
960
- revertible on its own (a migration that rewrites rows, or an auth change
961
- mixed with other work). Diff size is never a reason. A piece without a
962
- standing reason is folded into the one before it, and a repository with no
963
- deploy check can't claim (b); this is a deterministic check, not the model's
964
- word.
965
-
966
- A one-piece plan behaves as always. With several, piece 1 continues in the
967
- planning task with only its slice, and the rest wait as rows (no worktree,
968
- port or queue slot) until what they wait on has merged or deployed, then start
969
- as tasks through the usual brakes and queue. A plan waiting for approval
970
- shows its pieces: **Merge into ①** or **Drop** a piece (undoable until you
971
- approve), **Approve with note…**, or **Reject**. Each piece's review judges
972
- its slice; the last also checks the whole plan was built. **Tasks** shows
973
- the feature's pieces and what each waits on, with **Release anyway** for one
974
- held by a dropped or failed predecessor. A plan-only task that reaches
975
- approval sends a "Plan ready: name, N pieces" push, and a finished feature
976
- sends one "Feature merged" push naming it.
977
-
978
- ### Schedules
979
-
980
- A schedule starts agent work at set times without you opening AgentOS:
981
- **Schedules** in the workspace menu, the sidebar's **⋯** menu, or ⌘K. Each has a
982
- name, a time (presets for hourly, daily, weekdays and weekly, or any
983
- five-field cron expression, in America/Chicago unless you pick another zone),
984
- a project and a prompt, and starts one of:
985
-
986
- - **Task** and **Session**: now recipes (Settings > Recipes) with a timer.
987
- Migration 81 turned each existing recurring task or session schedule into a
988
- recipe, with its run history; the Schedules form no longer offers them. A
989
- one-off that still has one of these kinds is left as it was. To undo the
990
- move, stop AgentOS and run
991
- `npx tsx scripts/revert-schedules-move.ts --db <path to agent-os.db>`.
992
- - **Orchestrator**: the prompt, posted to the workspace's orchestrator as a
993
- message from "Schedule <name>", marked as a scheduled prompt so it never
994
- counts as an approval.
995
- - **Message**: the prompt, sent to a session you pick the way `aos send`
996
- does, marked the same way. A chat whose agent has exited (idle chats stop
997
- after 30 minutes) is started again to take it. The run records `delivered`,
998
- `queued` or why it failed. **Schedule check-ins** in a session's **⋯** menu
999
- fills one in. The session is stored by id, so renaming it changes nothing.
1000
- An archived session fails the run until it's back. When the session is
1001
- deleted or a finished task, the schedule
1002
- turns itself off on the first run that finds it gone and says so once, in
1003
- the orchestrator's chat and on your phone; point it at another session or
1004
- delete it. The orchestrator isn't a target (it has its own kind):
1005
- `aos schedule add --session <the orchestrator>` makes an orchestrator
1006
- schedule, so it follows whichever session is the workspace's orchestrator.
1007
- A schedule an agent made with `aos schedule add` stays in that agent's
1008
- workspace and reaches its target labelled as that agent's request, not
1009
- yours.
1010
-
1011
- The server checks once a minute and claims each run in SQLite before starting
1012
- it, so a time never runs twice. If AgentOS was off when runs were due, it
1013
- runs only the most recent one when it comes back, marked **caught up**. A run
1014
- is **skipped** while the schedule's previous task or session is still working,
1015
- and while the workspace's orchestrator is paused. A run that fails to start is
1016
- recorded with why, noted in the orchestrator's chat and sent to your phone
1017
- (see below), once per failing streak: not again until a run starts. Every run stays in the
1018
- schedule's history with a link to what it started. **Run now** runs one
1019
- immediately, even while the last run is still working (Pause still holds it).
1020
- Task and session runs go through the orchestrator's brakes, like its own
1021
- starts: a braked run is skipped with the brake's reason and tried again on the
1022
- next minute until the brake lifts or a newer run is due (Run now obeys them
1023
- too, once). A schedule whose project has moved to another workspace fails
1024
- until it's edited. Removing a schedule keeps its history.
1025
-
1026
- **One-off schedules.** Pick **Once** in the form (a date and time in the
1027
- schedule's zone), or `aos schedule add --at "tomorrow 10am" ...` (an ISO time,
1028
- `in 2h`, a weekday; America/Chicago unless `--tz`). It works with every kind,
1029
- runs once and then turns itself off; the run stays in its history, marked
1030
- done, and the schedule moves to the **Done** group. Upcoming one-offs are
1031
- listed first with their run time, how far off it is and who made it (you or an
1032
- orchestrator), each with Run now, Edit and Cancel; the count shows in the
1033
- sidebar menu and the orchestrator's header. The same claim-in-SQLite rule
1034
- applies, so it never runs twice, and one AgentOS missed while off runs when it
1035
- returns, marked **caught up**. Pause holds a one-off until you resume rather
1036
- than skipping it, and the brakes apply as for any run. A past time is refused.
1037
- Run now uses up its only run; edit it to a new time to run it again. An
1038
- orchestrator makes its own with `remind_me`: at least ten minutes ahead, 20
1039
- pending at most, in its own workspace, and it arrives as a scheduled prompt,
1040
- never an approval.
1041
-
1042
- Task and session schedules run at most hourly, message schedules at most
1043
- every 10 minutes and skip a run (`still working`) while their session is
1044
- still busy, mid-turn or holding a queued message. A task schedule waits
1045
- while any task it started is unfinished (working, waiting on you, in review
1046
- or failing checks), so it can't stack up pull requests. Only one server
1047
- process runs schedules (it holds a lease in the database); a dev server runs
1048
- none unless `AGENTOS_SCHEDULES=on`, and `AGENTOS_SCHEDULES=off` stops them in
1049
- production.
1050
-
1051
- ### Machine load
1052
-
1053
- The dot in the sidebar header is the machine's load: green, amber (load
1054
- over 1.5 per core, or memory pressure warning) or red (over 3 per core, or
1055
- critical pressure), with some slack before it drops back. Tap it for the
1056
- numbers and the sessions using the most CPU; a busy session's row shows its
1057
- own share ("3.1 cores · 4.2 GB"), summed over its terminal's process tree
1058
- from one `ps` every 30 seconds.
1059
-
1060
- Nothing is ever stopped, paused or queued. Instead, before an agent starts a
1061
- whole test suite, type check, build, repo-wide lint, `xcodebuild` or
1062
- `pytest`, the Claude hook AgentOS installs tells it what heavy commands are
1063
- already running and how loaded the machine is, so it can narrow the run or
1064
- wait. Targeted runs (`vitest run lib/x.test.ts`) are left alone. `aos heavy
1065
- -- <cmd>` does the same for anything else. When the load stays red for two
1066
- minutes, one message goes to your phone and to each workspace orchestrator,
1067
- naming the top sessions and their heavy commands; the next one waits until
1068
- it has been green for ten minutes. `AGENTOS_LOAD=off` turns it all off.
1069
-
1070
- ### Tmux cleanup
1071
-
1072
- Deleting, finishing, dropping or marking a session done ends its tmux session
1073
- and every process its panes started, on the machine it runs on. At start,
1074
- AgentOS also ends tmux sessions it created (its `<agent>-<uuid>` and
1075
- `aos-chat-<uuid>` names, or the `AGENTOS_SESSION_ID` it sets at launch) whose
1076
- session no longer exists, and logs each as `[tmux-sweep]`. Sessions it didn't
1077
- create are never touched. The sweep runs only in production mode (a dev or test instance shares the tmux server but not the database); `AGENTOS_TMUX_SWEEP=off` skips it.
1078
-
1079
- ### Phone notifications
1080
-
1081
- Two things reach your phone: a schedule run that failed, and whatever an
1082
- agent sends on purpose with `aos notify "<text>"` (the orchestrator's morning
1083
- report, a real milestone). Status changes don't; that's the in-app Needs-you
1084
- list. Each source sends at most one a minute: anything more inside the minute
1085
- waits and goes out as one message (kept in the database, so a restart
1086
- doesn't lose it; past 20 waiting, more are dropped), and the same text twice
1087
- goes once.
1088
-
1089
- Set it up in **Settings → Notifications** (⌘K → Phone notifications, or the
1090
- line at the bottom of Schedules), one of:
1091
-
1092
- - **Command**: `AGENTOS_NOTIFY_CMD` in the server's environment, a shell
1093
- command that gets the message on stdin. It wins when set. For example, a
1094
- Telegram sender on another machine:
1095
- `AGENTOS_NOTIFY_CMD='ssh -o BatchMode=yes me@box "NOTIFY_SOURCE=agentos ~/bin/notify"'`.
1096
- - **Telegram**: a bot token and your chat id. The token is kept in the
1097
- database and never shown again, returned by the API or logged.
1098
-
1099
- #### Push to the phone app
1100
-
1101
- A machine linked to Connect sends to the paired phones that have registered
1102
- for push, instead of Telegram. A push is generic: the title "AgentOS", a
1103
- category word and a link to open, with no session or task text (a plan's or
1104
- feature's name is the one exception, scrubbed to a single line) (the payload is a
1105
- versioned envelope, so an encrypted body can replace it later). It goes
1106
- through the Connect relay, signed with the machine key; AgentOS keeps a
1107
- `push_outbox` that retries with backoff, forgets tokens the relay reports as
1108
- dead, and caps alerting pushes at 10 an hour per device (one summary after).
1109
-
1110
- - **What pushes**: an ask raised, a session waiting on you for a minute,
1111
- a task ready for review, CI or a review failing, a plan ready to approve,
1112
- a feature merged, and the Away digest. Merged is off by default. Each device picks its
1113
- categories (`PATCH /api/devices/me/push`). A task mirrored from another
1114
- machine never pushes from here.
1115
- - **Quiet rules**: waiting, review, CI and merged don't push while you're at
1116
- this Mac (keyboard or mouse used in the last 3 minutes). While Away is on,
1117
- everything except asks folds into the 10-minute digest.
1118
- - **Fallback**: agent messages, the Away digest and machine alerts (load,
1119
- schedules) go to Telegram when push isn't configured or fails. The newer
1120
- events are push-only. If Connect says push isn't set up yet, AgentOS
1121
- stops asking for 10 minutes and uses Telegram meanwhile.
1122
- - **Check it**: `aos push test` sends a real push to each registered phone
1123
- and prints what came back; Settings → Devices shows each device's push
1124
- state, categories, last error and a Send test button.
1125
-
1126
- ## Agent network
1127
-
1128
- Sessions started by AgentOS can find and talk to each other without you,
1129
- through the `aos` command on their PATH (any agent CLI can use it; Claude is
1130
- also briefed on it):
1131
-
1132
- In a chat, a message from another session shows as theirs, with the
1133
- sender's name, rather than as one you typed.
1134
-
1135
- ```bash
1136
- aos peers # sessions, their project, what each is doing
1137
- aos send <session> "message" # wakes the other session with the message
1138
- aos inbox # read messages sent to you
1139
- aos history <session> # your conversation with a session
1140
- aos spawn <project> "prompt" # start a new agent session in a project
1141
- aos task <project> "prompt" # start a background task that ends in a PR
1142
- # (both take --name "..." before the prompt;
1143
- # task takes --after <task|any> to queue it;
1144
- # a task opens as a chat, --terminal for tmux)
1145
- aos move <session> <machine> # carry a task on there ("here" brings it back)
1146
- aos stack <project> [--plan] # run the project's board as stacked tasks
1147
- aos stacks # every stack and where each card is
1148
- aos schedules # every schedule, its next run and last outcome
1149
- aos schedule run <name> # run a schedule now
1150
- aos schedule add --session <s> --every 30m "prompt" # check in on a session
1151
- aos notify "text" # push a message to your phone
1152
- aos push test # a real test push to the paired phones, and the result
1153
- aos heavy -- npm test # run it now; says first what else heavy is running
1154
- aos stop <session> # stop its turn now; the next message runs as a new turn
1155
- aos done <session> # finished: merge through the gates, archive
1156
- aos done --all-idle # the same for every idle session around you
1157
- aos docs [query] # LumifyHub pages, when the workspace is linked
1158
- ```
1159
-
1160
- Messages are delivered by typing them into the recipient's terminal, labelled
1161
- as coming from another agent, and a rate limit stops two agents looping.
1162
- Delivery is checked against the pane: the text has to reach the input and
1163
- leave it on Enter (retried once as a bracketed paste), and a menu on screen is
1164
- never typed into. `aos send` says `delivered`, `queued` (the agent was busy and
1165
- will see it after its turn) or `FAILED: <why>` with exit code 2; a chat session
1166
- counts as delivered once its worker records the message. Either way the
1167
- message waits in the recipient's `aos inbox`.
1168
-
1169
- Sessions are addressed by name, `project/name`, id or a unique id prefix, and
1170
- renaming one keeps its old names: a message to "Session 3" still reaches the
1171
- session now called "orchestrator", and `aos peers` shows
1172
- `orchestrator (was Session 3)`. If another session has since taken the old
1173
- name, the current owner wins and `aos send` says so. A name that matches more
1174
- than one session is refused with the candidates listed. The
1175
- **Messages** panel shows every conversation and lets you message any session.
1176
- Sessions on other machines can receive messages but not yet send them.
1177
-
1178
- ## The sidebar
1179
-
1180
- One flat list of every session in the current workspace, each row naming its
1181
- project underneath. The workspace's orchestrator comes first, as a compact row
1182
- with its state and how many of its asks wait on you; it starts pinned there,
1183
- and unpinning it from its ⋯ menu (remembered per workspace) drops it among the
1184
- other sessions. Sessions sit on shelves: **Pinned** (pin from a row's ⋯
1185
- menu), **Needs you** (an approval, a question, a terminal waiting for input, a
1186
- message typed and never sent, a failed task, or the orchestrator's open asks,
1187
- each with a badge), **Working**,
1188
- and **Done**. Done is folded to one row, "3 done today · 12 earlier", until you
1189
- tap it (open or folded is remembered per device); open, it lists newest first,
1190
- ten at a time. The orchestrator's row carries small chips for the work it
1191
- started: running, in review, blocked and queued, each left out at zero. Tap
1192
- them to show only that orchestrator's work on the same shelves; the "Showing
1193
- … work ×" chip at the top clears it (it resets on reload). A session an
1194
- orchestrator started has a small orchestrator icon on its row. A purple dot marks a session that
1195
- finished or changed since you last opened it. Search matches
1196
- titles and project names, and the project filter narrows the list to one
1197
- project and holds that project's own actions: new session, terminal, dev
1198
- server, settings, board, workspace.
1199
-
1200
- Every session has its own address, `/?session=<id>`: open it in a new tab,
1201
- on a phone or from a bookmark and that session opens; **Copy link** in a row's
1202
- ⋯ menu or the pane's menu copies it. The address bar follows the focused
1203
- pane's session, each switch is a history entry so back and forward move
1204
- between sessions, and an address for an archived or unknown session says so
1205
- and opens the usual home. A device that isn't paired is sent through pairing
1206
- and comes back to the same session; the address grants nothing by itself.
1207
-
1208
- **Settings** (the sidebar's ⋯ menu, or ⌘K → Settings) holds every setting in
1209
- one place: **Merging** (the approval switch, merge method and branch
1210
- clean-up, with the projects that override them), **Workspaces** (each one's
1211
- running task limit), **Devices & access** (pairing, passkeys, network),
1212
- **Notifications** (this browser's sound and alerts, and your phone) and
1213
- **Schedules**. Each section has its own address, `/?settings=<section>`
1214
- (`merging`, `workspaces`, `devices`, `notifications`, `schedules`), beside
1215
- `?session=`; on a phone the sections are a list, then the one you open.
1216
-
1217
- Rows move the moment a session changes state: the server pushes every change
1218
- over `/ws/status` (behind the same device gate as the terminal). The same
1219
- stream says when anything else on screen changed: database triggers mark the
1220
- tables written (sessions, stacks, schedules, asks, bus messages and more,
1221
- whoever wrote them), and the git panel's folders are polled once on the
1222
- server for every viewer. The browser refetches only what moved, so an idle tab
1223
- makes about one request a minute instead of forty. Messages are numbered: a
1224
- reconnecting phone picks up what it missed, or takes a fresh snapshot when
1225
- it's been away too long. While the socket is down, the old polling carries on.
1226
- API JSON is gzipped and the sockets use permessage-deflate.
1227
-
1228
- **AgentOS reads OSC 7501**, the [Program Status
1229
- Protocol](https://www.superlogical.com/rex/docs/build/program-status): a
1230
- program in a terminal session can say it's `working`, `blocked` (on a
1231
- permission, a question or a sign-in), `done`, or failed, and that wins over
1232
- reading the screen. Blocked lands on Needs you with Approve, Answer or Sign in
1233
- and the program's message (plain text, capped); done gets the unread dot.
1234
-
1235
- ```sh
1236
- printf '\e]7501;state=blocked:kind=permission:app=me:msg=%s\e\\' "$(printf 'Apply 3 changes?' | base64)"
1237
- ```
1238
-
1239
- tmux drops sequences it doesn't know, so AgentOS watches each local terminal
1240
- session through tmux control mode: one long-lived, read-only `tmux -C`
1241
- client per session (tmux 3.2 or newer) pushes the pane's raw output, which
1242
- carries the reports, and keeps a copy of its screen for reading status, so
1243
- nothing polls `capture-pane` or taps panes with `pipe-pane`. A screen is kept
1244
- only while its pane prints, and it's checked against tmux again whenever
1245
- output settles. A session's terminal views share one `tmux attach` (it runs at
1246
- the smallest view's size), and a view that can't keep up is held back and sent
1247
- the current screen once it catches up. On older tmux, or with
1248
- `AGENTOS_TMUX_CONTROL=off`, AgentOS falls back to copying each session's
1249
- output to itself (`tmux pipe-pane`, through a unix socket only you can reach;
1250
- needs `nc`) and reading screens with `capture-pane`. Claude Code sessions AgentOS starts on this
1251
- machine report through hooks it installs (`~/.agent-os/claude-status-hooks.json`,
1252
- passed with `--settings`). Not covered yet: sessions on other machines (their
1253
- output never passes through this one), Codex and the other agents (Codex only
1254
- notifies when a turn ends, with nothing for "working" or "blocked"; they keep
1255
- reading the screen), and the terminfo
1256
- `Pst` capability (the pane's terminal is tmux's).
1257
-
1258
- The screen covers what no report says. A selection menu at the bottom of a
1259
- terminal (Claude Code's "Enter to select · ↑/↓ to navigate", a Codex "› 1."
1260
- list) lands on Needs you with **Answer** and its question, for sessions
1261
- without the hooks. Text typed into a Claude Code or Codex input box and left
1262
- unchanged for a minute while the agent sits idle lands there with **Unsent**
1263
- and the text, so a message that never got sent doesn't wait for hours. The
1264
- dim suggested prompt in the same box doesn't count. Claude Code fires no hook
1265
- when a question is dismissed with Esc, so a question report clears once its
1266
- input box is back on screen.
1267
-
1268
- ## Workspaces
1269
-
1270
- Group projects into workspaces (e.g. Work, Personal) from the workspace
1271
- switcher at the top of the sidebar, which also picks the workspace the list
1272
- shows and holds the current one's orchestrator, clean-up, Archived and
1273
- LumifyHub link. Move a project in from the project filter's menu. Deleting a
1274
- workspace keeps its projects.
1275
-
1276
- ### Done
1277
-
1278
- **Done** (a session's ⋯ menu; `aos
1279
- done`; or the orchestrator's `done` tool) is for finished work, where
1280
- **Stop** keeps everything and **Drop** rejects it. A task with an open PR
1281
- merges first, only through the orchestrator's gates at the judged commit; a
1282
- failing gate refuses with its name and nothing merges. A task already
1283
- merged, or a session with no PR, just cleans up. If GitHub can't be read, or
1284
- a task that had a PR has none now, done refuses rather than guess.
1285
-
1286
- Cleanup stops the agent and archives the session. The worktree goes only if
1287
- nothing in it would be lost: never with uncommitted changes; after a merge,
1288
- only when every commit on it is in the merged PR or on a remote; otherwise
1289
- only when its branch has no commits of its own. Anything else is kept and the
1290
- reply says why, naming the uncommitted files. Files setup copied in (env
1291
- files, agentos.json's `copy`) don't count while they still hold exactly what
1292
- was copied; setup records them, hashed from the main checkout, in the
1293
- worktree's git directory. Cloned dependencies are gitignored, so never count. A sign-off from Tasks or the orchestrator follows the same
1294
- rule. A branch merged on GitHub is deleted on origin when origin's tip is the
1295
- commit that merged.
1296
-
1297
- Archived sessions leave the sidebar, the needs-you count, session statuses
1298
- and the orchestrator's view, but are never deleted; the **Archived** view
1299
- (the workspace switcher for one workspace, or ⋯ in the sidebar header for
1300
- all of them) lists
1301
- them with Unarchive, which only puts the entry back.
1302
-
1303
- **Clean up idle sessions** (the workspace switcher) first shows what will happen
1304
- to each idle or stopped session, and `aos done --all-idle` does the same
1305
- sweep. A clean-up never merges: open PRs are listed for their own done.
1306
- `aos done` reaches only sessions in the caller's workspace (or project).
1307
-
1308
- ### Session logs
1309
-
1310
- When a task merges, AgentOS writes a log of it. It costs no model tokens: the
1311
- log is a fixed template filled from records AgentOS already holds, and nothing
1312
- that makes it can call a model (a test holds it to that). Dropped tasks get
1313
- none.
1314
-
1315
- A log holds:
1316
-
1317
- - **Header:** task name and id, workspace, project, branch, PR number and
1318
- link, merge commit, start, merge time and duration.
1319
- - **Brief:** the task's prompt and every scope change recorded on it, in
1320
- order.
1321
- - **Plan:** `.agentos/plan.md`, read at the merge before cleanup removes the
1322
- worktree. A task with no plan says so.
1323
- - **Timeline:** PR opened, gate failures per commit (CI with the failing
1324
- check's name, review, scope), each review and scope verdict per commit with
1325
- its text trimmed, escalations to you and your answers, and the merge.
1326
- - **Usage:** tokens, estimated cost and model per role, from the usage ledger.
1327
- - **Outcome:** the task agent's last message, verbatim.
1328
- - **Links:** the PR and the session.
1329
-
1330
- Text from tasks, CI and reviewers is untrusted. It is written inside fences
1331
- or code spans, so it can't add headings or links to the document, and
1332
- credential-shaped strings are redacted.
1333
-
1334
- The database is the record: `session_logs`, one row per task, never deleted.
1335
- Each log is also written to a file, `YYYY-MM-DD-<task>.md`, in the first of:
1336
-
1337
- 1. the project's **Session log folder** (project settings; an absolute or `~`
1338
- path),
1339
- 2. the workspace's **HQ folder** (workspace settings):
1340
- `<hq>/docs/sessions/<project>/`,
1341
- 3. `~/.agent-os/session-logs/<workspace>/<project>/`.
1342
-
1343
- A folder inside the project's repository is refused, because repositories can
1344
- be public, and the files are never written into one.
1345
-
1346
- The HQ folder is a git repo. Saving it checks that it is a repository, that it
1347
- isn't inside or equal to any of the workspace's project repos, and (with one
1348
- `gh repo view --json visibility`) that its GitHub remote isn't public; the
1349
- result is stored. When a log lands in the HQ it is committed there as
1350
- `session log: <task name>`, only that file, whatever else is changed in the
1351
- tree, and pushed to the current branch's upstream only if the repo is
1352
- private. A failed commit or push is logged and never reaches the merge; the
1353
- next push carries the earlier commit. Commits to one HQ run one at a time.
1354
- The database row is the record either way.
1355
-
1356
- The same dialog lists the project's logs, newest first, and a merged task's
1357
- view has a **Log** tab. The orchestrator reads them with its `logs` tool: the
1358
- latest headers of a workspace or project, or one log in full. It only reads.
1359
-
1360
- The log is made once per task, in the background, from wherever the merge
1361
- happens: a sign-off, Done, a stack landing, or a merge seen on GitHub. A
1362
- failure is logged and never reaches the merge. For tasks that merged before
1363
- this existed:
1364
-
1365
- ```bash
1366
- npx tsx scripts/backfill-session-logs.ts --db <path to agent-os.db> [--no-gh] [--dry] [--reexport]
1367
- ```
1368
-
1369
- Their plan files are gone, so those logs say "plan not kept". Files go to the
1370
- same destinations as above; into an HQ the backfill commits once at the end.
1371
- `--reexport` writes no new logs: it rewrites the files of logs already in the
1372
- database to where they'd go now, from the stored markdown (no rebuild, no
1373
- model), leaves the old files in place, and does nothing on a second run.
1374
-
1375
- ### Orchestrator
1376
-
1377
- Each workspace has one standing orchestrator, pinned at the top of its
1378
- section: a chat that runs the work across the workspace's projects. It's made
1379
- the first time you open it, works from a scratch folder in
1380
- `~/.agent-os/orchestrators/<workspace>`, and is never swept with idle sessions.
1381
- Its brief lists the workspace's projects (path, board, default branch), what
1382
- it may do on its own, and the lines that always come back to you as asks.
1383
-
1384
- - **Tools:** `sessions` (every session's status, activity, task, PR, CI and
1385
- stack position), `read` (the end of a terminal or chat) and `cards` (the
1386
- linked boards' cards), plus acting tools: `send`, `start_task`,
1387
- `start_session`, `stack`, `stack_status`, `land`, `drop`, `stop`, `done`, `move`,
1388
- `add_project` (a git repository on the machine becomes a project of the
1389
- workspace, or the project already at that path moves in from no workspace;
1390
- folders that hold secrets and projects of another workspace are refused),
1391
- `note`,
1392
- `rule_add`, `rule_remove`, `review`, `sign_off`, `arm`, `disarm`, `remind_me`, `reminders`, `cancel_reminder`, `ask_saad`, `question` and `resolve_question`. All are served in-process to its chat, refuse
1393
- any target outside its workspace, and validate their arguments. The one
1394
- exception is other orchestrators: `orchestrators` lists every workspace and
1395
- whether it has one, and `message_orchestrator` messages another workspace's
1396
- current orchestrator by workspace name (never any other session there). It
1397
- arrives marked as from that orchestrator and fenced as untrusted, so it can't
1398
- approve, answer an ask or pass a gate. The route
1399
- they call answers only the orchestrator's worker, by a per-orchestrator
1400
- secret.
1401
- - **Shell:** it runs anything without asking, so an orchestrator can read and
1402
- investigate on its own: `gh pr list`, `gh run view --log-failed`, `gh api`
1403
- GETs, `curl`, `sqlite3 -readonly`, git in any repository, a skill's scripts,
1404
- pipes and chains. Its chat worker refuses a deny list before a command runs,
1405
- naming the tool to use instead: merging, closing or retargeting a PR
1406
- (`gh pr merge`, `gh pr close`, `gh pr edit --base`, and `gh api` or `curl`
1407
- calls that merge a pull request or PATCH or PUT one; use `sign_off`, `arm`,
1408
- `land` or `drop`), `aos move`, `aos done` and `aos stop` (use `move`, `done` and
1409
- `stop`, which are scoped to the workspace and held by Pause), `git push` (`quick_pr` pushes), writing in a project
1410
- repository or task worktree other than its own open quick changes (git
1411
- commit, reset, checkout, rebase, merge, stash, clean or rm there, and `rm`,
1412
- `mv`, `cp`, `tee` or a redirect into one), writing AgentOS's state (`sqlite3`
1413
- on its database without `-readonly` or with INSERT, UPDATE, DELETE, DROP,
1414
- ALTER or ATTACH; files under `~/.agent-os` outside its folder), stopping
1415
- AgentOS or its tmux (`pkill`/`kill` aimed at it, `tmux kill-*`, a
1416
- `launchctl` or `serviceman` restart), and reading secret files (the same
1417
- list as the write guard; tokenvault is allowed, through `tv` and its folders). It reads each
1418
- command line the way a shell would, so these are caught inside pipes,
1419
- chains and `$( )`, behind `bash -c`, `sh -c`, `env`, `sudo`, `xargs`,
1420
- `find -exec` or an absolute path, and after a `cd` or `git -C`. **The deny
1421
- list catches honest mistakes, not a determined bypass:** a script or
1422
- `python -c` can do any of these where no parser sees it, and an
1423
- orchestrator reads other sessions' text, which can carry planted
1424
- instructions. The trade-off was chosen on 2026-10-11, for an orchestrator
1425
- that does its own investigating instead of handing it to him.
1426
- - **Triage:** its brief has it decide each job: small and clear is a task with
1427
- `plan: false` and the steps written into the brief; big, unclear or
1428
- cross-cutting is `plan: true`; work outside a repository is a
1429
- `start_session` (Sonnet) with the steps in the prompt. It puts
1430
- implementation on Opus only when the work needs deep reasoning, and says why.
1431
- - **Files:** it reads anywhere and writes (Write, Edit, NotebookEdit) anywhere
1432
- except a project repository, a task worktree (`~/.agent-os/worktrees`),
1433
- AgentOS's own install and state (all of `~/.agent-os` but its own folder),
1434
- secret files (`.env`, keys, `~/.ssh`, `~/.aws`, `gh`'s token, tokenvault and
1435
- the like; the list the merge gates use for secrets handling,
1436
- `lib/secret-paths.ts`), and files that make something run: dotfiles and
1437
- dot-folders at the top of its home (shell, git, Claude and tool config, the
1438
- usage brake's `limits.json`), `~/Library`, `/Library/LaunchAgents` and
1439
- `LaunchDaemons`, git's `core.hooksPath` folders (yours and each project's),
1440
- the folders on `PATH`, and any `.git`, `.claude`, `.mcp.json`, `CLAUDE.md`
1441
- or `AGENTS.md`, since writing one would give it a shell or run code in
1442
- AgentOS's own git; and the temporary checkouts a review or rebase runs in.
1443
- Code changes to a project go through a task, so its PR still passes CI,
1444
- review and scope. It is a list of exceptions, not of allowed places: a
1445
- script a hook or scheduled job runs from an ordinary folder can still be
1446
- written, so an orchestrator misled by text it read could run code that way.
1447
- That's accepted: task agents can already write anywhere, so an allowlist
1448
- on the orchestrator alone would buy little.
1449
- - **MCP servers.** An orchestrator runs without prompts, so an MCP server's
1450
- tools are refused unless its workspace allows the server. Settings →
1451
- Workspaces lists the servers configured on the machine (names only: user
1452
- servers, connectors and plugin servers; never their env, headers or tokens)
1453
- as toggles, and `linear` is allowed by default. A ticked server adds a bare
1454
- `mcp__<server>` rule to the orchestrator's allowed tools, covering all its
1455
- tools. Its worker ends at its next turn boundary when the list changes, and
1456
- the next one starts with the new permissions. Sending a message, email or
1457
- post through a server stays a hard line the brief sends to `ask_saad`.
1458
- Its chat worker checks every write in a PreToolUse hook before it runs, on
1459
- the path with symlinks and `..` resolved as the system will, and refuses
1460
- with the reason; the repositories are read from the database on each write,
1461
- so a project added since counts. A worker from before an update picks the
1462
- new permissions up at its handover to the new build.
1463
- - **Brakes:** every start is refused, with the reason, while 4 sessions run in
1464
- the workspace, after 6 starts in an hour (`orch_max_running` and
1465
- `orch_max_starts_per_hour` on `workspaces`), or when the account's 5-hour
1466
- usage window would run out before it resets (read from the statusline's
1467
- `~/.claude/.context-cost/limits.json`, as dispatch does;
1468
- `AGENTOS_LIMITS_FILE` overrides). A missing file, or one not sampled for 15
1469
- minutes, refuses too. Each card of a stack it starts is braked as its own
1470
- start. A brake writes one note and pauses only new starts.
1471
- - **Review and sign-off:** `review` runs a fresh `claude -p` on a
1472
- symlink-free detached checkout of the PR's exact head commit. It loads no
1473
- settings or MCP servers from anywhere (so nothing the PR ships runs), gets
1474
- an allowlisted environment, can only Read/Grep/Glob inside the checkout,
1475
- and follows the repo's review agents' rules (`.claude/agents/review-*.md`), or its review skill, as the base branch has them. The verdict
1476
- is stored against that sha. A diff over 80k characters is reviewed in up
1477
- to 6 parts of whole files, each against the task, and fails if any part
1478
- does; a single file over 80k, or more than 6 parts, goes to you. A task from a card also gets a scope check against the card.
1479
- When you change a running task's scope, the orchestrator tells it with
1480
- `send` and `scope_change`, which records the message on the task's brief
1481
- (`brief_amendments`, logged in its chat): the review and the card's scope
1482
- check judge the PR against the brief as amended, the amendments winning,
1483
- and a "Scope change" note in the PR body counts only where one backs it.
1484
- `sign_off` merges only that commit (with the project's merge method) when CI is green and settled on
1485
- it (2 minutes with no new check), its review passed, nothing is
1486
- `BLOCKED:` or waiting, the diff stays in scope (no secrets, not only
1487
- lockfiles, nothing outside the repo, within the card) and its stack parent
1488
- has merged, and the PR body carries no AI attribution. `land` judges each item again at its own head right before
1489
- merging it. A gate failing again on a different commit, or a repo with no
1490
- CI, goes to you as an ask, and the orchestrator stops merging that task.
1491
- A failure counts once per task, gate and head commit, however many times
1492
- and from wherever that commit is judged (the armed watcher, CI finishing,
1493
- `sign_off`, `done`, `land`); a pass in between doesn't reset it. A review
1494
- that blocks counts when its verdict arrives, whether or not `sign_off`
1495
- ever reads it.
1496
- - **Arm to merge:** `arm` (or **Arm merge** on a task's row) makes AgentOS
1497
- merge the task's PR itself the moment every `sign_off` gate passes at its
1498
- head, starting the review once CI is green, so nothing polls `sign_off`.
1499
- The orchestrator hears one event: merged, or the failure (counted once per
1500
- head; the task stays armed for the fix, and one that goes to you disarms
1501
- it). The flag is in the database, so it survives a restart; `disarm`
1502
- takes it back.
1503
- - **Automatic rebase:** when the base moves and GitHub says a task's PR now
1504
- conflicts (read in the PR poll AgentOS already makes), `git merge-tree`
1505
- checks it against the base. Clean, and with the task's agent idle and
1506
- nothing uncommitted, AgentOS rebases it in the task's worktree and pushes
1507
- only its branch with `--force-with-lease`, and the orchestrator's review
1508
- carries over when the PR's own patch is
1509
- unchanged (same `git patch-id`; a fresh review starts otherwise). Your
1510
- merge approval carries over a rebase the same way (any rebase, the task's
1511
- own included): when the PR's patch is unchanged it follows the new head,
1512
- else you're asked again, naming the new head and what changed, and an open
1513
- merge ask follows its PR's head. Not
1514
- clean: the task is asked once to rebase. Either way, one event. Main and
1515
- other tasks' branches are never written.
1516
- - **Tasks woken on CI failures and reviews:** a check failing on a task's
1517
- PR head messages the task's own agent once per head, with the check, the
1518
- failing step and about 60 lines of `gh run view --log-failed` around the
1519
- error, telling it to fix the root cause and push. A review or comment from a collaborator (not the account gh runs
1520
- as, which is the task's own) wakes it once per review or comment; one
1521
- GraphQL query per repository a minute fingerprints the open task PRs, and
1522
- only a PR whose fingerprint moved has its reviews read. Comment-only wakes
1523
- stop at 10 a task; changes requested always wake. A task mid-turn gets it
1524
- queued, the orchestrator hears one line per wake, and merged, closed,
1525
- dropped or done tasks aren't watched. On by default; **Settings →
1526
- Workspaces** turns it off per workspace.
1527
- - **External PRs and sessions:** `review` and `sign_off` also take an open
1528
- PR no AgentOS task owns (dispatch, a person, dependabot) by `#N`,
1529
- `owner/repo#N` or URL, as long as its repository is one of the workspace's
1530
- projects; anything else is refused. The same gates apply, except that a
1531
- draft waits and a "blocked", "do not merge" or "wip" label holds it (there's
1532
- no session to read). `sessions` also lists tmux
1533
- sessions AgentOS didn't start that work in a workspace repository or a
1534
- worktree of it, here or on another machine, with their branch's PR; `read`
1535
- reads them, and nothing else acts on them.
1536
- - **Merge approvals** (Settings → Merging, off by default): on, any change to
1537
- CI config, build and hook scripts, agent config, deploy scripts, secrets
1538
- handling or AgentOS's security code, and any diff over 80k characters, goes
1539
- to you as an ask whatever the gates say, and merges once on your passkey.
1540
- Off, those merge through the gates like any other PR. Switching it off
1541
- again needs your passkey.
1542
- - **Decision log:** `note` and the brakes and escalations write to
1543
- `orchestrator_notes`, and each line shows in its chat.
1544
- - **Standing rules:** what it must keep knowing ("never merge #111", "briefs
1545
- must not name third-party products") it keeps with `rule_add` and drops with
1546
- `rule_remove`, in `orchestrator_rules`. You see, add, edit and remove them in
1547
- Settings → Workspaces, each change with your passkey (any process on the
1548
- machine reaches the route, and a rule of yours is your word to it). A rule restricts or informs; it never approves an
1549
- ask, passes a gate or clears a hard line. Yours are marked as from you and
1550
- only you remove them; the ones it kept, like its decision-log lines, come
1551
- back to it fenced as its own notes, so text it read can't pass for your
1552
- word. Rule text is redacted when stored, and removed rules stay on record.
1553
- - **Where things stand:** every start appends a digest read straight from
1554
- the database, no model involved: the standing rules, open asks, running
1555
- tasks with their PR, armed-to-merge and gate state, recently gated external
1556
- PRs, the queue, schedules and the newest decision-log lines, capped at about
1557
- 4k tokens. The brief tells it this is authoritative over what it remembers.
1558
- - **Fresh starts:** fed events nonstop, an orchestrator never idles and can't
1559
- compact itself. Once its context passes a threshold (200k tokens by
1560
- default, Settings → Workspaces → Fresh starts), its worker ends the
1561
- conversation at the next turn boundary and the next one starts a new
1562
- conversation with the brief and digest, telling the agent in one line why.
1563
- Nothing is lost, because its state lives in the database; its chat goes on,
1564
- with a line where it started over. The same can be switched on for chat
1565
- tasks (off by default: a task keeps only its brief and its branch).
1566
- **Start fresh by hand:** after a deploy that changes its permissions or
1567
- brief, use **New conversation (keep brief)** in the orchestrator's row menu or type `/fresh`
1568
- in its chat (task chats have both too). It takes the threshold's path: an
1569
- idle agent starts over at once; a running turn finishes first, with a
1570
- "Starts fresh after this turn" line. The next conversation launches with
1571
- the brief, permissions and workspace state the server has then.
1572
- - **Events:** the server sends it one short line per event (a PR opened, CI
1573
- failed, or green once it has settled so `sign_off`'s ci gate passes, a `BLOCKED:` line, a merge, a session needing input, a
1574
- stack step, a task idle 30 minutes with no PR, a review's verdict). Events
1575
- wait while its turn runs, duplicates fold, and at most one batched message
1576
- goes out per 30 seconds. What it has been told is kept in
1577
- `orchestrator_events`, so a restart resends nothing. Set
1578
- `AGENTOS_ORCHESTRATOR=off` to stop events.
1579
- - **Asks:** what's yours to decide sits on its asks list
1580
- (`orchestrator_asks`): what it raises with `ask_saad` (a decision, or
1581
- something crossing a hard line: public or outbound, money, irreversible,
1582
- credentials, a product call), and every escalated gate and brake. There's
1583
- one open ask per subject (a task, the brakes, a title), so an escalation
1584
- that repeats updates its ask. Each shows as a card under its row and at the
1585
- top of its chat, with Approve, Decline and Reply. Open asks are its
1586
- needs-you: the amber dot, one count each in "N need you", and the
1587
- notifications. Your answer reaches it as an event (`ask "<title>":
1588
- approved`). An approval covers that one item only: a held task's approval
1589
- lets `sign_off` merge it once, at the commit you approved (a new commit
1590
- asks again), and a brake's lets one start through, for that brake only.
1591
- The orchestrator can ask you itself whether to merge a PR the gates won't
1592
- pass, by giving `ask_saad` the task and its head sha: the ask is pinned to
1593
- that commit, opens with what AgentOS knows about it (files changed,
1594
- sensitive files, the review's verdict) and links the PR, and your approval
1595
- lets `sign_off` merge it once, at that commit. It never rewrites an ask the
1596
- gates raised. An approved merge (either kind, and an armed task's) needs no
1597
- review or other gate of that commit: only an AI-attributed PR body, failing
1598
- CI (running CI waits), a head that moved off the commit, and on the
1599
- orchestrator's own ask a stack parent not merged yet, still stop it.
1600
- An ask closes itself when its task is merged or dropped, or the brakes
1601
- lift. At most 10 are open per workspace, titles that say the same thing
1602
- fold into one, a declined subject isn't asked again for 6 hours, and a
1603
- "decision" that reads as money, outbound, irreversible or credentials is
1604
- filed as that hard line.
1605
- - **Readable when busy:** in the orchestrator's chat, anything AgentOS
1606
- sent it (a PR opened, CI green, a task woken, a schedule, a task's message)
1607
- and the orchestrator's reply fold into one line: an icon, the task, how the
1608
- reply starts, the time. Tap to read the whole reply; runs of them group as
1609
- "5 updates". What you typed, and the replies to it, stay whole, and so do
1610
- your own decisions and any turn waiting on an approval or showing a plan or
1611
- an error. Where a message came from is recorded when it is delivered;
1612
- older messages are told apart by their opening text only.
1613
- A **Needs you** strip above the composer lists everything waiting on you
1614
- until it is resolved: open asks (escalated gates and brakes too), questions
1615
- the orchestrator put to you in chat, its chat waiting on an approval, and
1616
- tasks that need you. Each is one line that jumps to the ask, the message or
1617
- the session, with a count when collapsed. The orchestrator marks a chat
1618
- question with `question` (the same words while open are the same
1619
- question) and clears it with `resolve_question`; the strip's Reply quotes
1620
- it into the composer and resolves it when you send. Dismissing an item
1621
- hides it on all your devices and resolves nothing: an ask stays open on
1622
- its list and in the counts. Questions about a task clear when it is merged
1623
- or dropped.
1624
- - **Proof it's you:** only this machine, the tailnet, or a paired device you
1625
- switched to "Can approve" in Devices may answer asks or pause. Approving a
1626
- hard line, a gate, a brake or a new passkey, Resume, changing the
1627
- orchestrator's standing rules, and switching merge approvals off, also
1628
- need a
1629
- passkey (Touch ID or Face ID, user verification required) on a challenge
1630
- bound to that one ask at its current commit or brake: single use, two
1631
- minutes. Agents on this machine reach every route but can't make your
1632
- authenticator sign, and neither `aos` nor the orchestrator's tools can
1633
- answer or resume. Passkeys belong to the host they were made on
1634
- (localhost or the tailnet's https name), so add one on
1635
- each in Devices. The first one on an install is trusted on first use,
1636
- once: every later one needs a code from a device that has one, even after
1637
- every passkey is revoked. Revoking always needs a passkey, the last one
1638
- included, and every add or revoke becomes an ask (declining a new one
1639
- revokes it, with your passkey). If none is left, run `agent-os passkeys
1640
- reset` yourself in a terminal on the machine: it refuses inside an
1641
- AgentOS session or an agent's shell, asks you to type a confirmation, and
1642
- makes the next passkey first-use again. Browsers offer passkeys only over
1643
- https or on localhost.
1644
- - **Header line and Pause:** its row reads like "Orchestrator · 3 running ·
1645
- 1 in review · 1 ask" from live data, and tapping it opens the chat, where
1646
- the same line carries Pause/Resume. While paused it acts on nothing:
1647
- events queue, acting tools refuse, and its stack starts and lands hold.
1648
- It can still read, note and ask. Resume delivers what queued, folded.
1649
- - **Away mode:** turn it on when you step away, from the coffee cup in the
1650
- sidebar header or ⌘K ("Away for 4 hours"), for 1 hour, 4 hours, until
1651
- morning (8 AM) or until you're back. It's kept in `away_periods` (who set
1652
- it, when, when it ends), the cup turns amber while it's on (with an amber dot on the phone's menu button), and it
1653
- ends on its own at its time. It works only through orchestrators that
1654
- had a real turn (yours or theirs, not an AgentOS event or a status poll)
1655
- in the last hour, set in Settings → Workspaces → Away mode; the rest
1656
- aren't told or woken. Each active orchestrator gets an event, and a line
1657
- leading its digest, saying you're away and to follow work through rather
1658
- than only react. Every 10 minutes a sweep, written as code with no model
1659
- scanning, runs a review again when a PR is green and settled but its
1660
- review never started or was lost (once seen on two sweeps, so the
1661
- orchestrator had its turn), checks after each merge whether the project's
1662
- `deploy` went live and the server came back, and sends the orchestrator
1663
- one digest of what's new: tasks quiet 30 minutes with no PR (or failing
1664
- CI), idle tasks with uncommitted work and no PR, and your own sessions
1665
- idle with uncommitted work. Only sessions with a real turn inside the
1666
- window are listed, never stopped, finished or archived ones, and nothing
1667
- goes out when nothing changed. The sweep messages no session itself: the
1668
- orchestrator decides what needs work, and asks one of your sessions at
1669
- most once to wrap up. Away's own messages don't count as activity. Paused
1670
- workspaces aren't swept. Hard lines still become asks, and while you're
1671
- away the asks raised, failed deploys and any `aos notify` an orchestrator
1672
- sends reach your phone as one message per sweep. Turning it off (or its running out) builds "While you were
1673
- away" from the database, for the workspaces Away reached: what merged and
1674
- deployed with PR links, what the sweep flagged that's still in flight and
1675
- which gate or blocker holds it, what failed, was dropped
1676
- or was escalated, and what waits on you (an explicit "none"). It opens on
1677
- whichever device is open until you dismiss it, a short summary goes to
1678
- your phone, and the report stays in Settings → Audits (`away/`).
1679
-
1680
- ## LumifyHub (optional)
1681
-
1682
- AgentOS works fully without a LumifyHub account. Connecting one, from a
1683
- workspace's menu, gives its docs and boards a home you can open anywhere and
1684
- share with anyone:
1685
-
1686
- - A workspace links to a LumifyHub workspace, and a project to a board in it.
1687
- Tasks get a card on the project's board that moves as the task runs, and a
1688
- card in To Do can be started as a task.
1689
- - **Docs** lists the linked workspace's pages and reads them; editing happens
1690
- in LumifyHub.
1691
- - A markdown file open in the file explorer can be published as a page marked
1692
- as coming from the repo. Publishing again updates the same page, and so does
1693
- merging a task that changed the file. It goes one way: edits made in
1694
- LumifyHub are overwritten.
1695
- - Agents can list, read and create those pages with `aos docs`, `aos doc <id>`
1696
- and `aos doc new "<title>" --file <path>`. The token stays in AgentOS.
1697
-
1698
- What maps to what, and the API it uses: [docs/lumifyhub.md](docs/lumifyhub.md).
1699
-
1700
- ## Machines
1701
-
1702
- Open the sidebar menu (⋯) → **Machines** and add one with a name and an ssh
1703
- target (`user@host` or an alias from `~/.ssh/config`). Requirements: key-based
1704
- ssh from the machine running AgentOS (no password prompts), and tmux on the
1705
- remote machine. **Test connection** checks both.
1706
-
1707
- New projects can then pick a machine. Their sessions run in tmux there and
1708
- attach over one reused ssh connection per machine. Folders match across
1709
- machines relative to `~`, so `~/dev/app` on your laptop and on a server are
1710
- the same project.
1711
-
1712
- On other machines, files, git, worktrees, dev servers and summarize are not
1713
- available yet; the terminal, status, rename and send-keys are.
1714
-
1715
- ### Sessions on a linked machine
1716
-
1717
- Once a machine is linked (below), this AgentOS talks to the AgentOS running
1718
- there instead of running tmux over ssh. That machine owns its sessions: their
1719
- processes, chats and state. This one is a client of it, over HTTP and
1720
- WebSockets with the link's device token, and only ever connects out to it.
1721
-
1722
- - The sessions its AgentOS runs are sessions here: each is mirrored (same id)
1723
- as soon as it's listed, with the same row, menu and address as a local one.
1724
- One whose folder is in a project you have for that machine sits with that
1725
- project's sessions; the rest are listed under the machine's name. Its
1726
- orchestrator and its tasks stay with it. **Elsewhere** is only for tmux
1727
- sessions no AgentOS started.
1728
- - From the menu, rename, done (and its undo) and delete run on that machine.
1729
- Fork, fresh start, move to project and check-ins are shown disabled with
1730
- the reason. A new session started here on that machine is started by its
1731
- AgentOS and opens in chat, like a local one.
1732
- - A session for a project here can start on a linked machine too: pick it in
1733
- the draft's Machine chip. That machine finds the project by its repository
1734
- or folder, or clones it, as for tasks. A machine that can't (no remote, a
1735
- folder there that isn't a repository, no clone access, unreachable) is
1736
- greyed out in the chip with the reason. The session sits with the project
1737
- here.
1738
- - Starts are safe to retry: the draft's id is the start's key and the
1739
- session's id, so a resend, or this machine retrying a start whose answer
1740
- was lost, gets the session the first one made instead of a second.
1741
- - Terminals attach through its `/ws/terminal`, relayed by this server; one
1742
- connection per session however many views show it, with flow control
1743
- carried through. A dropped connection retries for two minutes, then says so.
1744
- - Chats open in the chat view through its `/ws/chat`, retried the same way
1745
- while the chat stays open. Messages from agents
1746
- (`aos send`) and schedules aren't relayed to another machine's chats: they'd
1747
- arrive there as yours.
1748
- - The orchestrator asks that machine for a linked task's screen before
1749
- clearing it; a screen it can't get counts as possibly blocked.
1750
- - ssh stays for machines that aren't linked. A row that can't be opened
1751
- (the machine unreachable, a name tmux can't attach) is greyed out and says why.
1752
-
1753
- ### Tasks on another machine
1754
-
1755
- A machine that runs its own AgentOS can take tasks. Run AgentOS there (any
1756
- port behind your own front door, or plain 3011 on loopback plus a proxy), then
1757
- press **Link** (the chain icon) next to it in Machines. Linking asks that
1758
- AgentOS for a pairing code over ssh, where its loopback is trusted, and keeps
1759
- the device token it gets back. The token goes straight into this machine's
1760
- database and is never shown.
1761
-
1762
- Once linked:
1763
-
1764
- - **New task → Run on** picks the machine (`aos task --on devbox <project> ...`
1765
- does the same). That machine creates the worktree, runs the agent and opens
1766
- the PR on its own. This one lists the task in the sidebar and Tasks with its
1767
- live state, opens its chat (or terminal) through that machine's AgentOS,
1768
- and sends sign-off and drop to it (pinned to the reviewed commit). Opened
1769
- while it still sets up, it shows that machine's setup steps and joins the
1770
- agent once it starts. Tasks open as chats unless Terminal is picked.
1771
- - **Move** carries a running task between this machine and a linked one,
1772
- either way. The source stops the agent, commits anything uncommitted as
1773
- `wip: moving to <machine>`, pushes the branch and hands over Claude's
1774
- conversation. The target finds the project by its git remote, then by its
1775
- folder relative to `~`, and clones it when it has neither. It checks the
1776
- branch out (reusing a worktree still on it), rewrites the conversation's
1777
- paths and resumes it with `--resume`. The source keeps its row, marked moved.
1778
- If the target refuses, the agent resumes where it was. If the source can't
1779
- tell whether it arrived (a timeout, a restart), the task stays **Moving**:
1780
- press Move again to finish it, or **Resume here**, which first asks the
1781
- other machine whether it arrived. Tasks waiting on you (an escalated gate or
1782
- an open ask), card tasks and stacked tasks don't move yet.
1783
- - **An orchestrator's task moves too**, by the orchestrator's `move` tool (`task`,
1784
- `machine`; `here` brings it back) or the Move button. Its state is re-keyed to
1785
- the task's new session id in the same step it lands: brief and scope changes,
1786
- plan file and phase, gate checks and failure counts, asks, wakes, queue
1787
- order, arm, model and provider. Both machines need an AgentOS that can do
1788
- it, and the arriving one must have the task's provider. The machine it lands
1789
- on holds it for the orchestrator's machine alone: only that device can
1790
- merge, arm, message, stop, done or read it, and the arriving machine's own
1791
- orchestrator, armed merges and bulk done skip it. The orchestrator keeps
1792
- judging the PR at its head, reads BLOCKED lines and open approvals from the
1793
- task's chat there, and gets PR, CI, idle and plan events by polling that
1794
- machine. Its messages arrive marked as from the orchestrator, never as
1795
- yours. The task can `aos send` its orchestrator back: the machine it runs
1796
- on only stores the message, and the orchestrator's machine pulls it and
1797
- delivers it as that task's own. Moving it back stops its agent there and
1798
- removes its worktree when nothing in it would be lost. Guards (write guard, shell deny list, attribution settings) run in
1799
- the task's worker on either machine, and the task can't merge or push to
1800
- the default branch. Moving counts toward the brakes and Pause refuses the
1801
- tool.
1802
- - **A chat task moves the same way**, between turns: a running turn is let
1803
- finish (up to 3 minutes, else the move is refused and it carries on here),
1804
- and one waiting on your answer isn't moved. What's sent to it while its
1805
- turn finishes waits in its queue and goes with it; once the move has packed
1806
- the queue, sends are refused until it arrives. Its chat history, queue,
1807
- access and plan settings go
1808
- with it, and on arrival a chat worker resumes the same Claude conversation.
1809
- Both machines need an AgentOS that can move chat tasks.
1810
-
1811
- Works for any project. Requests to the other machine carry its device token,
1812
- so it can sit behind a proxy that never trusts loopback. Linking needs this
1813
- machine or the tailnet, and only pairs with the ssh target's own host name.
1814
- The orchestrator starts tasks on its own machine and moves them afterwards.
53
+ Then open AgentOS, add a project from ⌘K, and press ⌥N. The [install guide](docs/guides/install.md) covers Windows (WSL2), the supported agents, first run and the `agent-os` commands. To use it from your phone, see the [phone guide](docs/guides/phone.md).
1815
54
 
1816
55
  ## Security
1817
56
 
1818
- AgentOS gives whoever uses it a terminal as you, so it decides who that is:
1819
-
1820
- - **This machine** (localhost) is always trusted.
1821
- - **Your tailnet** is trusted by default. Turn on "Require pairing on Tailscale
1822
- too" in Devices if other people share it.
1823
- - **Everything else** needs a paired device. That covers Wi-Fi, `AGENTOS_BIND`,
1824
- and any reverse proxy, including `tailscale serve`. A request that arrives
1825
- from localhost with proxy headers (`X-Forwarded-*`, `Forwarded`, `Via`,
1826
- `X-Real-IP`, `CF-*`, `Tailscale-*` and similar) counts as coming from the
1827
- proxy's client, not from this machine. A proxy that sends none of these
1828
- looks like this machine itself, so put such a proxy behind
1829
- `AGENTOS_AUTH=off` only if it does its own login.
1830
- - A request from localhost must also be addressed to `localhost` or
1831
- `127.0.0.1`. This stops a web page that has rebound its own domain to
1832
- 127.0.0.1 from counting as this machine.
1833
-
1834
- Each paired device holds its own token. Only a hash of it is stored, and
1835
- removing the device in Devices cuts its open terminals at once. A paired
1836
- device can use AgentOS but can't add devices or change access; only this
1837
- machine and the tailnet can.
1838
-
1839
- AgentOS also refuses requests addressed to any other host name (DNS rebinding),
1840
- and API calls or terminal connections made by another website's page. That
1841
- Origin check holds whatever `AGENTOS_BIND` says: a page may write to the API
1842
- or open a terminal, chat or status socket only from this machine's own
1843
- addresses (loopback, the addresses it listens on, its tailnet name, its own
1844
- Connect address and `AGENTOS_ALLOWED_HOSTS`). Another Connect machine's page
1845
- is always refused. With `AGENTOS_BIND=0.0.0.0`, reaching it by a DNS name
1846
- other than these needs that name in `AGENTOS_ALLOWED_HOSTS`.
1847
-
1848
- | Variable | Effect |
1849
- | -------------------------------------- | ------------------------------------------------------------------------------------------------------ |
1850
- | `AGENTOS_NETWORK=lan` | Listen on Wi-Fi too. Same as the switch in Devices. |
1851
- | `AGENTOS_REQUIRE_PAIRING_ON_TAILNET=1` | Pairing on the tailnet too. |
1852
- | `AGENTOS_BIND` | Listen on these addresses instead (e.g. `0.0.0.0`). Pairing still applies. |
1853
- | `AGENTOS_ALLOWED_HOSTS` | Extra host names to answer to. |
1854
- | `AGENTOS_TOKEN` | A device token for `aos` and the MCP server when they reach AgentOS over a network that needs pairing. |
1855
- | `AGENTOS_AUTH=off` | No pairing, for when your own proxy does the login. Anyone who reaches the port gets a shell. |
1856
-
1857
- ### Connect
1858
-
1859
- Connect (in development) reaches this machine from anywhere at
1860
- `https://m-<16 hex>.runagentos.com`. `agent-os connect` links the machine with
1861
- a code from runagentos.com: it makes an Ed25519 key in `~/.agent-os/connect`
1862
- that never leaves the machine, and the Connect service makes the machine a
1863
- Cloudflare tunnel. Running it again on a linked machine links the same tunnel
1864
- again, keeping its address. The first-run setup's Devices step can link too: paste
1865
- the code into the field (same code path, `POST /api/devices/connect`, local or
1866
- tailnet callers only). `agent-os disconnect` (or the switch in Devices)
1867
- turns it off.
1868
-
1869
- While Connect is on, the production server:
1870
-
1871
- - downloads cloudflared 2026.10.0 into `~/.agent-os/connect/bin` (never one
1872
- from `PATH`) and checks its SHA-256 before making it executable or running it;
1873
- - asks the Connect service for a fresh connector token on every start and hands
1874
- it to `cloudflared tunnel run` in `TUNNEL_TOKEN` only, never in argv, a file
1875
- or a log;
1876
- - starts cloudflared only once AgentOS holds the tunnel port and has seen a
1877
- connection to it arrive on its own listener, and stops it if the listener
1878
- goes, so it never publishes something else on that port;
1879
- - runs cloudflared in a process group of its own under a small watchdog that
1880
- kills it the moment AgentOS exits, however it exits, and kills one a crash
1881
- left behind (from `cloudflared.pid`) before starting another;
1882
- - restarts cloudflared with backoff if it exits, and stops it when Connect is
1883
- turned off. Devices shows its state.
1884
-
1885
- Cloudflare's edge ends TLS and cloudflared delivers requests to a listener of
1886
- their own on `127.0.0.1:<port + 433>`. That listener never trusts anything as
1887
- this machine, the tailnet or `AGENTOS_AUTH=off`: every request needs a paired
1888
- device. It answers only the machine's own host name and drops
1889
- `X-Forwarded-Host`, `Forwarded` and `X-Original-Host` before anything reads
1890
- them.
1891
-
1892
- | Variable | Effect |
1893
- | ---------------------- | ------------------------------------------------------------------- |
1894
- | `AGENTOS_CONNECT=0` | Never start Connect in this process. |
1895
- | `AGENTOS_CONNECT_PORT` | The tunnel's loopback port (default AgentOS's port + 433). |
1896
- | `AGENTOS_CONNECT_DIR` | Where the key and cloudflared live (default `~/.agent-os/connect`). |
1897
-
1898
- ### Demo mode
1899
-
1900
- `AGENTOS_DEMO=1` runs a server that is safe to show to strangers, over fake
1901
- data. Every request is refused unless it is on a read allowlist
1902
- (`lib/security/demo.ts`): no terminals, no exec or send-keys, no git, tmux or
1903
- file writes, nothing that starts a session, task, dev server or other process.
1904
- Reads of sessions, chats, diffs and PRs work, as does pairing a device from
1905
- this machine. A few writes stay database-only: pinning a session, Done
1906
- (archives, with no merge or clean-up), answering an ask, and removing your own
1907
- device. A chat message gets a short canned reply instead of an agent, and the
1908
- device list and network settings show no addresses. Visitors share one demo,
1909
- so what they type (a chat message, an answer to an ask) is kept and shown as
1910
- fixed text, and the database goes back to its seed every 10 minutes, in
1911
- place, while it keeps serving.
1912
- File reads stay inside the demo's home, and the server refuses to start in
1913
- demo mode unless `HOME` and `DB_PATH` both sit under `AGENTOS_DEMO_ROOT`, so
1914
- it can never serve a real machine's sessions.
1915
-
1916
- ```bash
1917
- npm run demo # seed fake data, serve it on 127.0.0.1:3340
1918
- npm run build && npm run demo -- --prod
1919
- AGENTOS_BIND=0.0.0.0 AGENTOS_ALLOWED_HOSTS=demo.example.com AGENTOS_AUTH=off npm run demo -- --prod
1920
- ```
1921
-
1922
- The seed (`scripts/screenshots/seed.ts`) needs git and tmux, and works on macOS
1923
- and Linux. `AGENTOS_DEMO_ROOT` (default `/tmp/agentos-demo`) and
1924
- `AGENTOS_DEMO_PORT` move it; keep the root short, as tmux socket paths are
1925
- limited to about 100 characters.
57
+ AgentOS gives whoever uses it a terminal as you, so it decides who that is. This machine (localhost) is always trusted. Your tailnet is trusted by default. Everything else, including Wi-Fi and any reverse proxy, needs a paired device. `AGENTOS_AUTH=off` removes pairing and gives anyone who reaches the port a shell, so use it only behind a proxy that does its own login. The full model, Connect and demo mode are in [docs/reference/security.md](docs/reference/security.md).
1926
58
 
1927
59
  ## Development
1928
60
 
1929
61
  ```bash
1930
- npm run screenshots # regenerate screenshots/ from a demo instance with fake data
1931
62
  npm run dev # http://localhost:3011
1932
63
  npm test # vitest
1933
64
  npm run lint # eslint
1934
65
  npm run check # typecheck, lint, format and tests: what CI runs
1935
- scripts/redeploy # pull, install, build; restarts via $AGENTOS_RESTART only if all of it worked
1936
- scripts/redeploy --rollback # put the previous build back and restart
66
+ npm run screenshots # regenerate screenshots/ from a demo instance with fake data
1937
67
  ```
1938
68
 
1939
- One Node process serves every terminal, chat stream and request, so a route
1940
- handler in `app/api/` may not call a `*Sync` child_process or fs function:
1941
- ESLint refuses it. Use the async form with a timeout.
1942
-
1943
- Every git process starts in `lib/git-exec.ts`: `git()`, `gitResult()`,
1944
- `gitOk()` and named operations (`revParse`, `worktreeAdd`, `gitPush`, …). It
1945
- sets one timeout, kills a hung git, never lets git prompt, keeps the server's
1946
- tmux out of hooks and rejects with a `GitError` carrying the exit code and
1947
- stderr. ESLint refuses git spawned anywhere else in `lib/`, `app/` or
1948
- `server.ts`.
1949
-
1950
- `scripts/redeploy` (and `scripts/autodeploy`, which calls it) builds into
1951
- `.next-build` while the live server keeps serving `.next`. The build is swapped
1952
- in by rename only once it finished with a `BUILD_ID`, right before the restart.
1953
- The build it replaced is kept in `.next-prev` for one rollback, and a failed
1954
- build leaves `.next` as it was.
1955
-
1956
- `scripts/autodeploy` waits for a merge to be 2 minutes old
1957
- (`AGENTOS_SETTLE`), so a burst of merges is one build and one restart. Before
1958
- it pulls, `scripts/wait-quiet` waits for the reviews and task setups the
1959
- server runs (`GET /api/busy`, loopback or tailnet only) to finish, for up to
1960
- 10 minutes (`AGENTOS_QUIET_WAIT`), then deploys anyway. A review a restart
1961
- cuts off anyway runs again when the server starts, and its verdict arrives
1962
- as usual.
1963
-
1964
- `scripts/perf/loadtest.mjs` starts a throwaway AgentOS (its own HOME,
1965
- database, port and tmux socket) with N idle sessions and reports RSS, file
1966
- descriptors, child processes and spawns per minute; `scripts/perf/execs.mjs
1967
- --pid <pid>` counts what any server spawns, grouped by command. Both count
1968
- spawns with eslogger (macOS) or strace (Linux) and need passwordless sudo for
1969
- that one number. Run them on a machine with room to spare.
1970
-
1971
- A pre-commit hook (`.husky/pre-commit`, installed by `npm install`) checks
1972
- only what is staged, in well under two seconds: `prettier --check`, failing
1973
- with the `npx prettier --write …` command that fixes it, and a scan of the
1974
- added lines for token-shaped secrets with the merge gate's own rule
1975
- (`scripts/hooks/staged-secrets.ts` reads `secretsIn` from
1976
- `lib/orchestrator/diff.ts`), naming the file and line. Build a test's fake
1977
- token at runtime (`"gh" + "p_" + "a".repeat(36)`) rather than writing it
1978
- whole. It also refuses words that must not land in this public repo
1979
- (`scripts/hooks/banned-terms.ts`): a short built-in list, plus, when it
1980
- exists, a private list of regexes kept outside the repo in
1981
- `~/.config/agent-os/banned-names` (`AGENTOS_BANNED_NAMES` overrides the
1982
- path), checked against added lines and file names; `scripts/check` runs the
1983
- same check over every tracked file. It runs in the worktrees AgentOS makes too, which have no `.husky/_`
1984
- until `npm install` runs in them. Typecheck, lint and tests are left to CI.
1985
- In an emergency, `git commit --no-verify` skips it. CI runs `scripts/check --build` on every pull request and push to main,
1986
- which also holds the app's first-load JavaScript to a budget
1987
- (`scripts/check-bundle.mjs`; `npx next experimental-analyze` shows what's in
1988
- it).
1989
-
1990
- ### Session audits
1991
-
1992
- `/session-audit`, a Claude Code skill kept locally (gitignored, not in this
1993
- repo), audits the sessions AgentOS started (tasks, chats, orchestrators and their review
1994
- agents) for token waste and repeated manual work. Its extractor,
1995
- `scripts/session-audit/audit.ts`, streams the sessions' Claude transcripts and
1996
- AgentOS's own records (checks, notes, asks, messages) into a compact summary
1997
- in a couple of seconds: context read per turn, peak context, the biggest tool
1998
- outputs, repeated commands and errors, files re-read, polling loops, rebases,
1999
- hand-stripped trailers and dev-instance clean-ups. The skill reads only that
2000
- summary, ranks a plan by impact and effort, compares it with the last audit,
2001
- and offers to start the fixes you pick as tasks.
2002
-
2003
- ### Code health audits
2004
-
2005
- `/code-health-audit`, also a local skill, audits this codebase for
2006
- performance, security and duplication. A script does the measuring first:
2007
- `scripts/code-health/prepass.ts` collects `npm audit` and outdated
2008
- packages, first-load bundle sizes from the last build, the largest files and
2009
- functions, copied blocks, ESLint by rule, API routes that are public or
2010
- change state without a `lib/security` guard, commands a shell parses and SQL
2011
- built from strings, secret shapes and machine details (redacted), and slow
2012
- tests from a vitest JSON, into one compact summary, and compares its numbers
2013
- with the last audit's. The skill reads that summary and the lines it points
2014
- at, writes a ranked plan (calling out work a script could do instead of a
2015
- model), and starts the fixes you pick as tasks.
2016
-
2017
- Audits quote session content and name weak spots, so they stay on your
2018
- machine in `~/.agent-os/audits/<kind>/` (session audits in `sessions/`,
2019
- code health in `code-health/`;
2020
- `AGENTOS_AUDITS_DIR` moves the root) and never in a repo. Settings → Audits
2021
- (or ⌘K, "Session audits") lists every kind's markdown reports, newest first,
2022
- and renders them.
2023
-
2024
- ## Mobile access
2025
-
2026
- **At home:** open **Settings → Devices & access** from the menu, turn on "Allow devices on this Wi-Fi",
2027
- tap "Add a device", and scan the QR code with your phone. Laptops open the link
2028
- and type the code. Each code works once, for 10 minutes.
2029
-
2030
- **Anywhere:** install [Tailscale](https://tailscale.com) on this machine and
2031
- your phone and sign in to the same account. Devices then shows a Tailscale
2032
- link, which works from anywhere and is encrypted. If your tailnet has HTTPS
2033
- certificates turned on, AgentOS also serves `https://<machine>.ts.net:3443`
2034
- with Tailscale's own certificate (renewed daily). Passkeys, the clipboard
2035
- and notifications need that secure address. Plain HTTP on 3011 keeps
2036
- working. `AGENTOS_TAILNET_HTTPS=0` turns it off, and
2037
- `AGENTOS_TAILNET_HTTPS_PORT` moves it. Use Wi-Fi access only on
2038
- networks you trust, because traffic on Wi-Fi is not encrypted.
69
+ A pre-commit hook checks formatting, secrets and banned terms on what is staged. Route handlers may not call `*Sync` functions, and git runs only through `lib/git-exec.ts`. More in [docs/reference/development.md](docs/reference/development.md).
2039
70
 
2040
71
  ## License
2041
72