# Features The full tour. Agent 007 grows with how much you hand off: web terminals for your coding agents, many of them in one window, a job board they pick work from, and Billion, one agent that runs the board from a goal. The [README](../README.md) has the short version. - **Billion, the one agent you talk to** -- The server starts an always-on Claude Code agent called Billion. You give it a mission, narrow ("ship the Windows build") or broad ("grow the company"), and it runs the work: it plans, posts job cards, reviews what comes back, merges pull requests, and comes to you only for money, access, anything irreversible, making a private repo public, payments or security, and real forks in direction. It runs without permission prompts (`--dangerously-skip-permissions`), so those rules are its brakes. On its first start it introduces itself in the Billion tab's chat, shows you what it will always ask you about, and asks for your mission and where new project repos should go (you answer there; your messages reach it during the introduction, everything else waits for it); after that the server wakes it for each operating cycle, paced by Billion with `set_next_wake`, and a server restart resumes its last conversation (`claude --continue`, or its Codex session by id). Its memory is a git repo of its own in `~/.agent-007/billion`: your rules in `CLAUDE.md`, the mission and what it learns in `COMPANY.md`, its current plan in `STATE.md`, every change a commit. Its instructions (`CHARTER.md`) are Agent 007's and are rewritten on every start, so a new release reaches it without touching your rules. It sits pinned at the top of the left panel and alone at the top of the office, and its terminal runs from the start, its tab hidden until you click Billion in the office (or its row); closing that tab hides it again and never stops Billion. Nothing restarts it on its own: a stopped Billion shows a Start button. If Claude Code is not installed, the Billion chat says so, with where to get it and a Start button; install it and press Start, or set `BILLION=0`. If it is installed but not logged in, the chat says Billion is waiting at its sign-in, with a button that opens its terminal to sign in there. Every agent can message Billion, whoever owns it, and messages and board notices wait until Billion says it is ready, so nothing lands mid-introduction. A card Billion posted tells it the moment it reaches Review, with the pull request or summary, and again once CI on that pull request finishes on its latest commit (all passed, or which checks failed), so Billion merges on that instead of watching CI itself; before each merge it runs `merge_check`, which reads the repo's workflows as the merge leaves them (including any the PR itself adds or edits) and says whether the merge sets off a deploy (a workflow on push to the base that deploys, publishes or releases), and when it does Billion asks you first, unless your rule in its CLAUDE.md says never ask or ask only for production; only Billion can edit its cards, and it can accept one that has no pull request or send it back to To do with a note for the next worker. It can also add a new project's repo to the board, and read the last lines of a worker's terminal on one of its own cards (`read_agent_screen`) to see why it stalled; agents you start by hand stay off-limits. A worker on one of Billion's cards, Claude Code or Codex, asks Billion before it asks you: Billion allows, denies with a reason the worker reads, or leaves it to you, and anything it does not answer within two minutes comes to you as the usual dialog. A request it could not see in full, a question or plan approval, or text that tries to steer its answer always reaches you instead, and a server that is down or slow never approves anything. A Codex worker gets its hook as two `-c` flags for that run, the hook and its trusted hash, so nothing is written to `~/.codex/config.toml`; the server asks Codex for that hash when it starts (`codex app-server`, `hooks/list`), and if `codex` is missing or does not answer, Codex workers ask you as before. If you have a `PermissionRequest` hook of your own in `~/.codex/hooks.json`, both run: a deny from either wins, then an allow from either, and only when neither decides do you see the dialog. Workers on either CLI call `send_message` and `finish_job`, the two board tools every worker on Billion's card is told to use, without a dialog (for Codex, `-c mcp_servers.agent-007-board.tools..approval_mode="approve"` for that run only); any other board tool still asks. It runs on Claude Code, or on Codex with `BILLION_AGENT=codex`; the button next to its name switches between them, handing the end of the conversation over in `HANDOVER.md`; the server does the same by itself when the one it runs on hits its usage limit, and never switches back on a timer (`BILLION_AUTO_SWITCH=0` turns that off); and on both the server wakes it for each operating cycle ([BILLION.md](BILLION.md#claude-code-or-codex)). `BILLION=0` turns it off and `BILLION_DIR` moves its folder (it must be new or empty). It stays off while user accounts are enabled, since it would belong to everyone. One thing to know: a worker that read untrusted text can pass it on to Billion, which has full access; messages arrive labelled as coming from an agent and its charter treats them as information, not instructions, but that is not a sandbox. The design, step by step, is in [BILLION.md](BILLION.md). - **Billion comes to you twice a day** -- Billion's questions come in two rounds a day, 08:30 and 15:30 your time (`rounds`, `roundMaxPerProject` and `roundsTimeZone` in `~/.agent-007/config.json`; `rounds: []` turns it off). `notify_owner` queues a question under its project; at each round the server shows you at most two per project, the most important first (blocking, normal, low, then Billion's `rank`, then newest), with Billion's brief on top, and sends one Telegram message for the whole round. Whatever the previous round left unanswered is consolidated: kept in *Earlier*, off your list, and Billion is told so it re-asks only what is still in a project's top two. Only a blocking question (or `telegram: true`) reaches you between rounds. Until the first round comes due a new install's questions show at once, so its introduction and first cycle never wait for 08:30. Once a round has been released the Billion tab opens on **This round** (before that, on **Chat**, unless you picked one) (one section per project, tap choices and a reply box on each card, answered cards folding in place, "3 of 7 done"); the chat moved to a **Chat** view beside it. A status line on top says what Billion is doing ("Working: reviewing PR #120 · 3 workers running · next round 3:30 pm"; Billion's `set_status`, and "Billion is working on your message…" until it replies). Every item in a round has a number: tap *Done* or type `1d` (`1d 3d` for several) and Billion reads `[Owner via app] item 1 done`. *Start the round now* (or typing "start the round now") releases the next round early. What you type is never held for a round: each pending message has its own progress box of concise `set_status` summaries, with only the oldest unanswered message receiving updates. When its reply arrives, those summaries fold into closed **Work details** beneath the answer; tap to expand them. Progress never reads terminal output, and reply bindings and summaries survive reconnects and server restarts. On the first start with rounds, open questions other than blocking ones are consolidated. See [BILLION.md](BILLION.md#briefings). - **Talk to Billion in the Billion tab** -- The Billion tab's **Chat** view is a chat thread with Billion; the tab is the one a page opens on (it cannot be closed). It is the web twin of its Telegram channel, so the conversation is not buried under the board notices and worker messages in its terminal (which stays the work log). Type in the box at the bottom (Enter sends) and it reaches Billion as `[Owner via app] ...`; a message starting with `/` (`/model opus`) runs as a slash command in Billion's terminal instead, with its screen shown back in the thread (`//` sends a literal `/`; [details](BILLION.md#telegram)); Billion's `tell_owner` replies and questions show as bubbles on the left, your messages on the right, Telegram ones included (voice notes as their transcript, marked *(voice)*). Typing is always a plain message: to answer a question by typing, tap *Reply* under it and the box says "Answers Q3". *Undo* takes an answer back for a minute after, and Billion can reopen a question with `reopen_question`. While Billion is busy, a message of yours still waiting in its queue reads *queued* with a **× Cancel** link (tap twice): a cancelled message never reaches Billion and stays in the thread struck through, and once typing into Billion's terminal has started it is sent and Cancel goes away ([details](BILLION.md#briefings)). Open questions also pin to a strip at the top ("3 open questions ▾"); tap it, or the tab's badge, for the **Open questions** panel: one section per project (Billion passes `project` to `notify_owner`, or the server reads it off a GitHub URL or repo name in the question, else `general`), or, with the *by project | by type* switch, one per type (engineering, marketing, outreach, finance, product, admin, other; Billion passes `type`, or the server reads it off the text). Sections start closed, their header showing the count and "!" when a blocking question is inside; the grouping and which sections are open are kept per browser. Each row is answered in place with its choices or *Reply*, and its text jumping to the bubble. × or Esc closes it; on a phone it fills the screen. The thread, the panel and the Jobs tab's columns update in place when something changes, so a refresh never moves you: where you have scrolled to stays put, and the thread only follows new messages while you are already at the bottom (otherwise *New messages ↓* appears). The last 500 messages are kept in `~/.agent-007/chat.json`, with open questions and unanswered owner requests retained beyond that cap until answered. - **Show Billion a screenshot or a file** -- In the Billion tab, paste an image (Cmd/Ctrl+V), drop files anywhere on the tab, or pick them with the paperclip beside the mic. They show as chips above the box (a thumbnail for an image, name and size otherwise, × to remove) and go with the next Send; files alone, with no text, send too. They are saved owner-only in `~/.agent-007/chat-files//`, and the turn Billion gets ends with their absolute paths, `[Owner via app] (attached: /path/a.png, /path/b.pdf)` (an answer the same way, `[Owner via app] Q3: ...`), so it reads them with its file tools. The limits are the job form's: 10MB a file, 20 files and 50MB a message. Your bubble keeps them as thumbnails that open full size and download links, served only from that folder and only while user accounts are off (the chat is the owner's alone); they go when the message leaves chat history; unanswered owner requests stay past the 500-message cap. Treat a file from outside like pasted instructions: Billion acts on what it reads. - **Read aloud and dictate in the Billion tab** -- A speaker button on every message from Billion reads it aloud with the browser's own voices (free, nothing leaves the browser): markdown dropped, links read as "link", Q51 as "question 51", a question's choices at the end, long messages spoken sentence by sentence; tap again to stop, and pick the voice in Settings (the gear, under *Read aloud*). Tap *Read aloud* (the speaker) in the bar at the top of the tab to turn on reading new messages aloud, and each new message is spoken as it arrives while the tab is showing (tap it while it reads to stop and turn it off; after a reload, one tap on *Resume reading*). The mic beside the text box dictates a reply into the box, greyed while it is heard, and never sends it for you; in "Answers Q3" mode it answers Q3 like typed text. Locked-screen playback on a phone is not reliable in mobile browsers; Telegram voice notes cover that. See [BILLION.md](BILLION.md#read-aloud-and-dictation-in-the-tab). - **Talk to Billion** -- A hands-free voice conversation with the same Billion in the Billion tab's Chat view: tap *Talk to Billion*, allow the mic, and speak. Speech is detected in the browser (Silero VAD, served by the app) and transcribed on your machine by whisper.cpp; the turn ends only after a real pause (about 1.2 s after a finished sentence, 1.5 s usually, 2.6 s after an unfinished phrase like "...and the"), and words added before Billion answers join the same turn. The turn is sent once as a voice turn, a short acknowledgment ("Got it, one sec.") plays at once, and Billion's reply to that turn is spoken as soon as it comes, then it listens again. With `ELEVENLABS_API_KEY` set, replies are spoken by ElevenLabs (voice Eric, the Flash model; `ELEVENLABS_VOICE` and `ELEVENLABS_MODEL` change them), streamed as they are made, and only the reply's text goes to ElevenLabs; without it, by the same macOS `say` voice as Telegram. Talk over it to interrupt (it ducks at once, then stops); Listening, Thinking, Speaking, Muted and Disconnected states with Mute and End; the chat thread is the transcript. Replies to typed or Telegram messages are never spoken as a voice turn's answer. Your audio never leaves the machine; without whisper.cpp, or without ElevenLabs and `say`, it falls back to the browser's speech and says so. See [BILLION.md](BILLION.md#talk-to-billion). - **Billion asks you on your phone** -- When Billion needs you, its `notify_owner` tool puts the question, numbered (Q3), in the **Billion** tab next to Jobs (a chat bubble and "Billion", with a badge counting open questions; the same in a phone's bottom bar) and, with `TELEGRAM_BOT_TOKEN` and `TELEGRAM_CHAT_ID` set, sends it to you through a Telegram bot when it is **blocking** (or Billion passes `telegram: true` for a super urgent one); normal and low questions wait in the tab. A question can carry 2 to 5 `choices` with one `recommended`: tap one under the question in the tab or its Telegram button, or type an answer in the tab's text box or as a Telegram reply to the question. It reaches Billion as `[Owner via app] Q3: ...` or `[Owner via Telegram] Q3: ...`, and the question is marked answered in both places (the Telegram message is edited to show the answer). Each question carries an `urgency`: open ones list **blocking** first (marked `! Q3`: a worker or merge is waiting, and the Telegram message starts with `! `), then normal, then **low** (number dimmed: optional), oldest first within each. Answered ones stay in the thread with "you answered: ..."; *Dismiss* closes one; everything survives restarts. Anything else you send the bot is typed into Billion's terminal as `[Owner via Telegram] ...`. Telegram buzzes for blocking questions only, and Billion's `tell_owner` replies reach it only while you are talking on the phone: after a message from the tab they stay in the tab ([details](BILLION.md#telegram)). The bot is Billion's own, so its messages carry no name: `Q3: ...`, `! Q3: ...`, or a reply's text alone. Only your chat is accepted. Setup in three steps is in [BILLION.md](BILLION.md#telegram). **Voice both ways, all local**: on macOS with ffmpeg, Billion's messages can arrive as voice notes (spoken by `say`, with the text as caption), and your voice notes are transcribed on your machine by whisper.cpp and reach Billion as `[Owner via Telegram, voice] ...`. By default Billion answers in the mode you last used (`TELEGRAM_VOICE`); see [Voice](BILLION.md#voice). - **Claude account rotation** -- In **Settings → Accounts**, every logged-in Claude and Codex login the scan finds (at start and on **Refresh**) joins the switch list, unselected while switching is on; add a folder the scan misses under **Add an account folder manually**, picking Claude or Codex next to it. Claude and Codex accounts share one list, each row tagged with its CLI, under one **Auto-switch accounts at usage limits** switch and one **Save settings**. Automatic rotation turns on by default once two accounts (of either CLI) have been added. Choose the included accounts and their order, then save changes: each CLI cycles through its selected accounts in list order (starting again from the top) and keeps its own active account, and each account's place in the list is saved as its `rank` in its CLI's registry. Settings saved before the one list show Claude accounts first, then Codex, each in its saved order. A saved off setting stays off when accounts are added or rediscovered; recovery also keeps rotation off. A hard limit on Billion or a managed Claude worker selects the next eligible login. Only authentication and account-specific metadata change: the current Claude config directory retains all settings, history, plugins, skills, MCP servers and trust settings. The app blocks new Claude spawns, stops its Claude sessions and tool processes, saves the outgoing account's latest refresh token, activates the next login, and resumes each exact conversation with its startup options. Unsupported custom startup flags prevent the switch instead of silently losing options. The scan refuses a switch while it detects another Claude process outside the app; do not launch another during a switch or use the source login folders concurrently. Saved credentials live in owner-only `account-logins/` files under the app config directory (POSIX 0600 files, 0700 directory; Windows uses the user's filesystem ACLs). Account order, active identity, limits and a recovery journal persist in `account-rotation.json`; secrets never reach the browser or logs. Discovery does not overwrite maintained credentials with a stale source copy. Failed activation restores the previous login; an interrupted or failed rollback blocks further switches and offers **Restore previous login**, which turns automatic rotation off. Explicit relative or ISO reset times are respected; ambiguous local clock labels use a 30-minute retry delay. Exhausted workers wait. Settings saved before the one list keep each CLI's own on/off until the next Save. When every selected Claude account is unavailable, Billion hands over to Codex only if the list has a selected Codex account (and the reverse), subject to `BILLION_AUTO_SWITCH` and the existing CLI-switch cooldown; there is no separate fallback switch. Codex-to-Claude first selects an eligible login too. Cross-CLI handovers export up to 80 recent dialogue/tool entries, about 96,000 characters total and 8,000 per entry, with explicit truncation notes and a pointer to the original transcript. Private reasoning is excluded. Billion's own Git directory remains the source of persistent state and pending work. Account rotation itself needs no handover. This replaces the permanent-move UI; old backups remain recoverable. Controls remain owner-only, hidden when app user accounts are enabled or Billion is off. - **Codex account rotation** -- Codex accounts sit in the same list under **Settings → Accounts**, on the same machinery (server/account-rotation.js with a Codex adapter, server/codex-login.js) and the same account lock. Discovery finds `~/.codex` (or `CODEX_HOME`) and `~/.codex-*` folders that hold an `auth.json` and pass `codex login status`; each is saved as a snapshot of that `auth.json` under `account-logins/` (0600), keyed by the ChatGPT account and user ids in its token, with order, limits and the recovery journal in `codex-account-rotation.json`. An API-key login has no token and is not offered. Activating writes the snapshot over the default home's `auth.json` (tmp then rename, 0600, through a symlink if it is one) and checks it with `codex login status`; the config, sessions, skills and history stay put. Every switch first saves the outgoing account's refreshed `auth.json`, and discovery never overwrites a maintained login with a source folder's stale copy. At a hard Codex limit on Billion or a Codex worker, the app blocks new Codex spawns, stops its Codex sessions, stops Codex's shared background server (`codex app-server daemon stop`, then checked gone, else no account is switched; it holds the login in memory, and the next `codex` starts it again on the new one), activates the next eligible login and resumes each session on `codex resume ` with its startup options. It refuses before stopping anything when a session's conversation id is unknown (it is the newest Codex recorded in the session's folder since it started, else the id in its own `codex resume ` command; two app Codex sessions in one folder have none), a startup option cannot be carried over, or a `codex` process outside the app is running (the background server itself is not counted). A limited account comes back at the reset Codex prints (`try again at Oct 25th, 2026 3:15 PM`, `at 3:15 PM`, `in 2 days 3 hours`; local time), else after 30 minutes. Only when every selected Codex account is unavailable does Billion hand over to Claude Code (when the list has a selected Claude account and `BILLION_AUTO_SWITCH` is not `0`), and a Claude-to-Codex handover picks an eligible Codex login first; Codex workers rotate the same way instead of waiting. Anything else that reads `~/.codex/auth.json` (another tool symlinked to it, the IDE extension) follows the switch, as it would if you switched accounts yourself. - **Pixel office** -- Canvas-rendered workstations that show each agent's state at a glance (working, waiting, needs attention, idle, disconnected). Desks are grouped into per-repo pods, each on its own labeled rug, in a front-facing grid (up to four desks across, wrapping into rows with an aisle between); a sparse office shows a row of empty spare desks below the real one, a conference table with cushioned chairs sits in the open floor below them, and the bottom of the floor fills with ambient decor (a sofas-and-coffee-table chat area in each corner, the two plants stacked between them as a divider) that yields as the office gets crowded; low bookshelves run under the windows. Pixel-art characters (six sprite variants) face the screen when working, turn to face you when waiting, and wander off to sit down when they are at rest -- at the conference table when the window is tall enough for one, and otherwise on the corner sofas, which are there at any size. A newly spawned agent walks in from the entrance to its desk, a departing one walks out before its desk disappears, and when the job board dispatches a job a small paper flies from that job's whiteboard column to the new agent's desk (all motion respects `prefers-reduced-motion`). The three whiteboards mirror the job board live: one pinned paper per job in each column, with a "+N" note when more are queued than fit -- click one to open the Jobs tab. - **Git worktree isolation** -- Each agent gets its own worktree and branch automatically. No merge conflicts between agents working on the same repo. Branches are named with cocktail names (`bill/vesper`, `bill/martini`, ...). - **Multi-repo support** -- Add any number of repos. Spawn agents on different repos and manage them all from one place. - **Live file explorer** -- Real-time file tree with git status indicators, inline diff viewer, and a changes/all toggle to filter what you see. Repo sections collapse from their header (click, or Enter/Space when focused); a collapsed header keeps the agent count and a dot for the most urgent agent state, so folded sections still show when something needs you. - **Terminal multiplexer** -- Full xterm.js terminals with clickable URLs, clipboard image paste (Cmd+V a screenshot), and draggable tabs for reordering. Double-click an agent's tab (or press the pencil button in the terminal header) to rename it; the new name shows up in every panel and in every connected browser, and survives a server restart. Only the label changes -- the agent's worktree directory and branch keep their original codename, so nothing moves under a running session. Open the same terminal in several windows (a laptop and a phone, or you and a teammate watching) and it takes the size of the smallest of its owner's windows showing it, as tmux does: every window draws it at that size, so a bigger one shows some empty space instead of scrambled lines. - **Job board** -- Queue work instead of babysitting it. A job has a title, details, and a repo, plus any screenshots or files you attach (paste an image into Details, or **Attach files**); they are stored outside the repo and the agent is told where to read them (it reads whatever you attach, so treat a file from outside the way you would treat pasted instructions). The board runs from a fresh install (**Stop** in its toolbar stops it, and the choice is saved); while it is stopped, To do says so with a Start button beside any waiting card. While the board is running, a queued job whose repo is under its agent cap gets a fresh agent on its own worktree and a branch named after the job within a couple of seconds: posting a card, moving one back to To do, or a worker's slot freeing up (its card to Review or Done, or its agent gone) each start a dispatch pass. A card that comes back to To do (moved there by hand, or sent back by Billion) is held for a minute first, showing "held · dispatching in Ns", so it can be edited before a new worker picks it up; editing does not lift the hold, **Dispatch now** on the card does. The board also scans every 5 minutes as a fallback, which is when it finds pull requests and files merged cards; **Run now** does that scan on demand. When the agent is done it reports back to the board with the pull request it opened (the board also spots the PR on its own if the agent forgets). A card that needs a pull request, in a repo with no GitHub remote or on a CLI with no ship skill (gstack's `/ship`, or `$ship` in Codex), says so as soon as it is posted or dispatched; it still runs, but it can't open the pull request until you add the remote or install the skill. Set **Pull request: Not required** on a card for work that is not a code change, such as research or a chore: its agent is not told to ship, reports a summary instead, and the summary shows on the card in Review. Agents dispatch in `auto` mode, where Claude Code's classifier reviews each action and escalates the rest to you -- worth having, because a job agent's prompt is your card text plus whatever it reads out of the repo. `CLAUDE_PERMISSION_MODE` / `CODEX_PERMISSION_MODE` in `.env` set another default per CLI, which the toolbar shows as ".env: …" until a mode is picked there; a picked mode overrides both. Set **permissions** in the board toolbar to change that for every job, or **Permissions** on a card to change it for one; a card left on "Board default" follows the board setting, including if you change it later. **Model** on a card picks the model its CLI runs (`--model` for Claude Code, `-m` for Codex), shown on the card; left on "CLI default" the CLI chooses. The list is discovered, never typed in: Claude Code's aliases for its newest models (`fable`, `opus`, `sonnet`, `haiku`) when `claude` is installed, and the models Codex lists in its picker (from `codex debug models`, or `$CODEX_HOME/models_cache.json` if that command fails, which the board only reads; hidden internal ones such as `codex-auto-review` are left out) when `codex` is. It is found at startup, again every hour and when the card form opens on a list over 10 minutes old; a value not on the list is refused, and a worker re-spawned after a restart keeps its card's model. Agents choose one with `post_job` / `edit_job`, whose description lists what is available. **Agent** on a card picks the CLI it runs on, Claude Code or Codex; Codex has no permission modes of its own, so a Codex card offers board default, `auto` (Codex's own default: it writes in the worktree and asks before risky commands) and `bypassPermissions` (`--dangerously-bypass-approvals-and-sandbox`). A board set to another mode maps onto Codex's nearest flag, so a strict board binds a Codex card too: `plan` runs it read-only, `manual` keeps it read-only and turns every write into a question, `dontAsk` never asks and fails instead, and `acceptEdits` is Codex's default. Auto mode needs a classifier that isn't available everywhere (an unsupported model on Bedrock or Vertex, or a machine with `permissions.disableAutoMode` set), and where it's missing Claude Code quietly starts the agent in manual instead -- so every job runs until it needs your permission and then waits there, showing orange on the card. That is what the board setting is for. In `bypassPermissions` a job agent edits files and runs Bash unprompted as you, and nothing inside the app bounds it, so only queue jobs against repos whose contents you trust ([DESIGN.md](../DESIGN.md) has the reasoning). Jobs move To do -> In progress -> Review on their own. A card in Review keeps its agent running, so you can click it to open that terminal and ask about the work; the agent and its worktree are released when the card reaches Done or goes back to To do, and agents waiting in Review do not count toward the cap. Once the pull request merges or is closed without merging (marked as such in Finished jobs), or you mark the card done, it leaves the board for **View finished jobs** -- so the Review column keeps meaning "needs your review". A finished card stays finished: it is the record of what shipped, and follow-up work is a new job. An agent that stops to ask you something turns its card orange and puts a count on the Jobs tab; click it to land in that terminal, answer, and it carries on. A worker whose turn died on a passing API error (a 429, a 5xx, "Overloaded", a dropped connection) is told `continue` a minute later instead of waiting for you all night: at most twice per card, both given back by a turn that ends cleanly, each one logged on the card (`autoContinues` in `read_job`) and in server.log. A usage limit or a login prompt is left to account rotation, and agents you start by hand are never touched. Claude Code asks "do you trust this folder?" the first time it runs anywhere, and every worker gets a brand-new worktree, so the board accepts that for its Claude Code workers: before the spawn it adds the worktree's path to `~/.claude.json` (or `$CLAUDE_CONFIG_DIR/.claude.json`) as trusted. That is one entry, written to a temp file and renamed over it, only when the file already exists and parses, and abandoned if Claude Code writes the file meanwhile. If the dialog shows anyway, it picks "Yes" on the screen: it never presses Enter while "No, exit" is highlighted, and never sends Escape, which exits. The trade-off: a trusted folder loads the repo's own `.claude/settings.json`, so its hooks run as you the moment the job starts, and its `permissions.allow` rules can pre-approve commands that a strict board or card mode (`plan`, `manual`) would otherwise ask about. That is the trust you give a repo by queueing work on it; for a repo whose contents you have not read, set `TRUST_BOARD_WORKTREES=0` in `.env` to keep the dialog. Hand-started agents keep it too, with one exception: codenames are reused, so an agent that later lands on a worktree path a board worker once had finds it already trusted. Claude Code 2.1.282 also counts a repo's main checkout as covering its worktrees, so a repo you have trusted there never shows the dialog either way. Codex asks the same ("Do you trust the contents of this directory?"), and a Codex worker is started with `-c projects={""={trust_level="trusted"}}`, which trusts that one worktree for that run and writes nothing to `~/.codex/config.toml`; a trusted folder lets the repo's Codex project config, hooks and exec policies load, the same trade-off. `TRUST_BOARD_WORKTREES=0` keeps the dialog for both CLIs. An orphan re-spawned onto a card still In progress or in Review (its saved card, or the card on its branch) is that card's board worker again and gets the same trust; one with no card is not, so it asks again. - **One GitHub account per repo** -- With several gh accounts signed in, each board worker in a github.com repo gets `GH_TOKEN` for the account that can see that repo (the one named like its owner, else the first that can read it), and `git push` uses it too, so no agent ever runs `gh auth switch` and flips the account under everyone else. Claude Code workers are denied `gh auth switch`, `login` and `logout` outright. Details in [BILLION.md](BILLION.md#github-accounts). - **Job types** -- The + Job form's Type is **Now** (a one-time card that goes straight into the queue), **Scheduled** (a one-time card that waits in To do until a date and time you pick in your local time zone, up to a year ahead, then goes through the board like any card) or **Recurring** (a cron schedule). - **Scheduled jobs** -- A card can also be a schedule, fired by cron (`0 9 * * 1-5`, or `@daily`) in the server's local time. The schedule itself stays in To do; each time it comes due it posts a run card that goes through the board like any job: its agent reports back with `finish_job`, the result waits in Review, and the agent is released at Done. Runs report a summary by default; set **Pull request: Required** on the schedule for runs that should open a PR. A schedule never piles up work: it holds off while its last run is still going or while that run's PR is open (merging or closing the PR files the run away and lets the schedule run again), and a newer summary-only run replaces the last unread one in Review (the older one moves to Finished jobs with its summary, and the newest says how many it replaced). Finished jobs keeps a schedule's newest 50 runs. Its card says its schedule in words ("Mondays at 9:00 AM", with the cron in its tooltip) under a *recurring* chip. **Pause** holds further runs of a recurring schedule without deleting it; **Resume** sets the next run from that moment, so a schedule paused for a week doesn't fire the instant it comes back. Work for one date (a follow-up on 24 September) is not a schedule but a **Scheduled** card: an ordinary one-time card with a start time. Agents post it with `run_at` (an ISO date-time, at most a year ahead; a schedule plus `once: true` still works and means the same). While it waits in To do the card shows a *scheduled* chip and its date ("Sat Oct 3, 9:00 AM · in 2 days"), with **Edit**, **Run now**, **Archive** and **Delete** (no Pause); the dispatcher leaves it until that time, then dispatches that same card, which moves through In progress, Review and Done like any other and drops the chip once started. Editing it moves its time; switching it to Now clears the time; switching it to Recurring makes it a schedule. A server start converts each once schedule left from earlier versions that has not fired yet into such a card (same id, title, detail, repo, agent, model and attachments, starting at its due time) and logs each one; once schedules that already fired stay archived. A server start also archives every one-date schedule (`0 10 24 9 *`: fixed minute, hour, day and month, any weekday) that has already run, and logs each one. **Archive** on any To do card files it to Finished jobs without running it, after a confirm, with a note saying who archived it and why; unlike Delete, the card and its history are kept. Billion does the same for its own cards with `close_job`. On the **Jobs** tab, each schedule shows whether it is waiting for its next firing, overdue for run posting, or held by an earlier queued, active, or PR-review run. A gone, stalled, or needs-input worker is called out separately; **Inspect blocker** opens the existing run. Expand **Firing evidence** for the last saved due time actually examined by a scan, when the scan observed it and whether it posted, held, or failed, plus the last posted run, available worker start/finish timestamps, next saved due time, server timezone, configured scan interval, and snapshot time. The overdue grace is that configured interval, not a deadline guarantee: slow scans can take longer, and a posted run waiting behind the agent cap is not a missed firing. Only the latest observation is retained across restarts; older installations show “not recorded” until a scan observes a firing, and delayed or skipped ticks are never filled in as fictional runs. Status refreshes through existing board scans and updates, with no new alerts or polling. It reports evidence only: it does not replay work, recover workers, or clear an old hold because a separate recovery job finished. Paused and archived schedules expect no new runs; a completed one-time schedule stays archived. - **Worker limit and memory back-pressure** -- The board runs at most **max total** workers at once across every repo (`jobBoard.maxWorkers` in `~/.agent-007/config.json`, 5 unless set), on top of **max/repo**. Billion itself never counts against it. When the board is full, queued cards go out in order: Billion's urgent cards (`post_job` with `urgent: true`) and the runs of a schedule first, then oldest first. Before starting a worker the board reads how full the machine is: swap (`vm.swapusage` on macOS, `/proc/meminfo` on Linux), macOS's memory pressure level, free disk where your home folder is, and, when present and under 15 minutes old, the mac-mini-guard watchdog's `~/.local/share/mac-mini-guard/current.json` (its disk figure wins, since it counts the space macOS can purge). Under pressure (swap over 75% full, under 15 GB of disk free, macOS warning, or the guard saying `pressure`) the board runs two workers fewer, never below one; when critical (swap over 90%, under 8 GB of disk free, macOS critical, or the guard saying `critical`) it starts none, and running ones carry on. To do then says why ("Waiting: Mac memory is low (…)"), a card held back shows "delayed by memory", a schedule's run keeps its place and goes out first when memory recovers, and the board looks again every minute rather than waiting for the next scan. The toolbar shows running against the limit ("2/3 workers (memory)"), and `agent007 doctor` shows the readings, the limit and the reason. `MEMORY_BACK_PRESSURE=0` in `.env` turns the readings off. - **Ask an agent to post a job** -- Say "add that to the job board" to an agent you are already working with and it posts the card itself, so noticing work does not mean stopping to type it into the form. The board appears in every Claude Code and Codex agent as an MCP tool, so the agent can see it without being told it exists; under the default permission mode Claude Code still asks you to approve the call, so a card is never filed behind your back. A card an agent files always inherits the board's permission mode -- an agent cannot pick the mode the board will spawn with. It runs on the same CLI as the agent that filed it unless the agent names another; a card a person files runs on Claude Code unless they pick Codex. The card lands in To do showing "via ", and runs in that terminal's repo unless the agent names another. The same agent can read the board back to you and change a card you have not started yet -- "what is queued?", "what does that card say?", "add the repro steps to it". A card that has left To do is closed to edits, for you and for it alike, because its agent already has the text; an agent cannot touch a card someone else queued; and an edit that does land is announced and shown on the card, so a rewritten card never reads as the work of whoever queued it. - **Agents message each other** -- Say "ask Viper what it changed in jobs.js" and the agent sends the question itself, whether Viper runs on Claude Code or Codex. Every agent has two MCP tools for this, `list_agents` and `send_message`, on the same server as the job board. Claude Code's own messaging only reaches other Claude Code sessions. A message is typed into the other agent's terminal as a new turn, headed with who sent it, so you see it arrive and the agent answers it like anything else you typed. It is typed in only while that agent rests at its prompt: never while it is working, never into a permission or trust dialog the app recognises (the Enter would answer it), and not within 30 seconds of you typing in that terminal. "Rests at its prompt" means no recognised dialog is on screen, so a dialog a new CLI release words differently could still be answered by the Enter. Until then it waits in a queue of up to 20, and the sender gets a message id: while the message is still queued it can take it back with `withdraw_message`, or rewrite it in place with `send_message`'s `replaces`, so a note overtaken by events (a PR since merged) is never acted on. Only the sender can do either, and board notices and approval requests are out of reach. The reply comes back the same way. An agent reaches only agents with the same owner, never a plain shell tab, and one agent can send another at most 10 messages in 10 minutes, so two agents cannot keep answering each other for ever. An agent that never asks before acting (`bypassPermissions`, `--dangerously-skip-permissions`, or on Codex `--yolo`, `danger-full-access`, `--ask-for-approval never`, `--full-auto`, or any `-c`/`--profile` override) only takes messages from another agent that never asks: otherwise any agent could borrow its permissions just by asking it to do something. `AGENT_MESSAGING=open` in `.env` lifts this rule for all your agents; it changes nothing when every agent runs in the same kind of mode, and an agent the rule refuses is told why. This is read off the command line the agent was started with, so a bare `claude` or `codex` whose own config file turns the questions off is not caught by it. Billion is the one exception to both rules: every agent can reach it. A message is a prompt, and it runs with the recipient's permissions, not the sender's: an agent in `bypassPermissions` acts on what it is sent as it would on what you type. The header says the message came from an agent, and the body is quoted line by line so it cannot pass itself off as you. That helps, but it is not a sandbox. - **Works on a phone** -- Below 700px the three panels become one screen at a time, switched from a Files / Office / Terminal bar at the bottom. Tapping a desk or whiteboard in the office lands you in that terminal or the job board, and opening a file diff lands you in the office panel, the same as on a desktop. - **Dark/light themes** -- Gold-accented dark theme and a warm low-glare paper light theme tuned for long sessions (see [DESIGN.md](../DESIGN.md)). Toggles instantly, terminal colors and office canvas included. - **Accounts** -- The gear next to the theme toggle opens Settings, whose **Accounts** section is one list of every login on this machine, each row tagged with its CLI (Claude, Codex, Gemini) and showing its email (or folder, when it has none), plan and one status: Active, Available, Limited · until … or Logged out for a Claude/Codex switch row, Logged in or Logged out for the others, plus Default for the CLI's default folder when that login is not the Active one. Folders logged in as the same email under one CLI are one row. Claude and Codex rows come first, in switch order, with their switch status, checkbox, Move up/down and Switch now (see account rotation above); the others are read-only. While app user accounts are on, or Billion is off, the whole list is read-only. Below it, one line per agent CLI found on the PATH (Claude Code, Codex, Gemini CLI, opencode, aider and others) with its version, path and, for Claude Code and Codex, **Update to …** when npm has a newer one. Scanned once at start; **Refresh** rescans. It only runs each CLI's local status check and reads the email from its login file, and never returns or logs a token. - **Run as a service** -- `agent007 install` (macOS and Linux) registers a per-user service, a LaunchAgent (`~/Library/LaunchAgents/com.bill10.agent-007.plist`) or a systemd `--user` unit (`~/.config/systemd/user/agent-007.service`, with linger turned on so it outlives a logout), that starts Agent 007 at login and restarts it when it exits. It runs the copy it was installed from (a clone's `bin/agent-007.js`, or the global npm install) with an absolute `node` and the `PATH` of a fresh login shell, and `PORT`/`HOST` only when they were set; settings files are read at each start as usual. It refuses while a server already holds the port in a terminal, and `--dry-run` prints the file. An npx copy cannot be installed (it is temporary); Windows prints how to run it in a terminal. `agent007 uninstall` removes the service and nothing in `~/.agent-007`. `agent007 status` reads `~/.agent-007/server.json`, which a running server writes (pid, port, version, a random token, mode 0600), and asks it over an authenticated local call: how it runs, pid, version, port, uptime, board workers mid-step, and its remote access (`PUBLIC_URL` and what the proxy last forwarded, see [REMOTE.md](REMOTE.md#behind-a-reverse-proxy-public_url)). `agent007 restart` waits for those workers to go idle (`--now` skips the wait), then asks the server to exit with code 75: a service brings it back, and in a terminal `bin/agent-007.js` starts it again in the same terminal. `agent007 logs [-f] [-n N]` tails `~/.agent-007/logs/server.log`, which the service caps at 5 MB plus one older copy. `agent007 update` pulls a clone (`git pull --ff-only`, refusing local changes or a diverged branch, `npm install` only when `package-lock.json` changed) or runs `npm install -g @bill10/agent-007@latest`, prints old → new version and restarts as above; under npx it says npx already runs the latest. `agent007` is the command's name from this version; `agent-007` still works. - **One skill store** -- **Settings → One skill store** (off by default; turning it on shows a dry run first) keeps every skill once in `~/.agents/skills`, which Codex reads, with a link in `~/.claude/skills` for Claude Code. Real folders in `~/.claude/skills` and `~/.codex/skills` (`CLAUDE_CONFIG_DIR`, `CODEX_HOME`) move into the store, each kept in `~/.agent-007/skill-backup/