Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ curl -fsSL https://raw.githubusercontent.com/AgentSystemLabs/agent-office/main/i

## What it is

- **A floor per project.** Ride the elevator, pick one of your GitHub repos, and the office clones it (showing how far along it is) and opens a floor for it. Every worker, board and queue on that floor works in that checkout.
- **A floor per project.** Ride the elevator, pick one of your GitHub repos, and the office clones it (showing how far along it is) and opens a floor for it. Pick the branch too, if the floor shouldn't start on the repository's default one. Every worker, board and queue on that floor works in that checkout.
- **Workers at desks.** Walk up to an empty desk, press **E**, and pick Claude Code, Codex, OpenCode, Grok, Muse, DeepSeek Harness, Pi or Cursor, each with its model and reasoning effort. The agent's live terminal shows on its laptop, and anyone can open it and type.
- **Talk instead of typing.** Hold **Ctrl+Space** (or the **🎤**) in a worker's terminal or a prompt box and say what you want: it's typed in for you to send. Your browser does the listening, so there's nothing to install.
- **You can't miss who needs you.** A worker that stops to ask you something lights a red beacon over its desk, puts a banner on your screen saying who and what for, and sounds an alarm. One that has finished jumps up and down and dings. Press **N** to go straight to whoever is waiting.
Expand Down
2 changes: 1 addition & 1 deletion docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Everything in the office, room by room. Back to the [README](../README.md).

- **A floor per project.** The first time the office starts in a terminal it walks you through picking your first project (see [Run locally](../README.md#run-locally)). Otherwise you start inside the elevator, and it asks for one: pick one of the repositories your `gh` login can see (or type `owner/name`) and the office clones it into the workspace folder, `~/agent-office/<owner>/<repo>` unless you pick another (**📁 Change folder** right there, for admins). While it clones, its floor on the panel says how far along it is (*Downloading 64% · 231 MiB · 1.5 MiB/s*), and you can close the panel and carry on: everyone hears when the floor opens. Whoever added it, or an admin, can stop it with the **⏹️** beside it. A clone that hears nothing from GitHub for 3 minutes is stopped as stalled, one that would have to ask something (an ssh host key, a password) fails straight away and says what to run on the office's machine, and restarting the office doesn't stop one. To add another project, or go to one, walk into the elevator on the north wall and press **E**. Or click the project name in the top-left corner for the list of floors: pick one and you're there in a blink, standing on the same spot in the office. From outside it (the balcony, the street, the garage) it takes you in, and you step out of that floor's elevator. Each floor has its own desks, workers, issues and PR boards, task queue, services and pictures, and its own wall and floor colors, so you always know where you are. You only see and hear the people on your floor. The elevator panel shows how many workers are busy or waiting on someone on each floor, and you get a heads-up when a worker on another floor starts waiting. An admin can take a project off the building with the **🗑** beside its floor in the elevator: its workers stop, and everyone on it rides the elevator to another floor. Nothing is deleted. The checkout stays on disk with its workers, queue and pictures, and adding the same repository again moves back into it (as long as the workspace folder hasn't moved since). That goes for the project the office was started in (`agent-office <dir>`) too: it stays off after a restart, and the office keeps its own data in that folder as before.
- **A floor per project.** The first time the office starts in a terminal it walks you through picking your first project (see [Run locally](../README.md#run-locally)). Otherwise you start inside the elevator, and it asks for one: pick one of the repositories your `gh` login can see (or type `owner/name`) and the office clones it into the workspace folder, `~/agent-office/<owner>/<repo>` unless you pick another (**📁 Change folder** right there, for admins). Under the list is the **Branch** the floor starts on: *Default branch* unless you pick another of the repository's, which the office asks GitHub for as soon as you pick the repository. The whole repository comes down either way, so the floor still has every branch to work from — only its checkout starts where you picked, and its workers branch off that. A checkout that was already there (a floor taken off the building, or cloned by hand) is moved onto the branch you picked, and says so if it can't. While it clones, its floor on the panel says how far along it is (*Downloading 64% · 231 MiB · 1.5 MiB/s*), and you can close the panel and carry on: everyone hears when the floor opens. Whoever added it, or an admin, can stop it with the **⏹️** beside it. A clone that hears nothing from GitHub for 3 minutes is stopped as stalled, one that would have to ask something (an ssh host key, a password) fails straight away and says what to run on the office's machine, and restarting the office doesn't stop one. To add another project, or go to one, walk into the elevator on the north wall and press **E**. Or click the project name in the top-left corner for the list of floors: pick one and you're there in a blink, standing on the same spot in the office. From outside it (the balcony, the street, the garage) it takes you in, and you step out of that floor's elevator. Each floor has its own desks, workers, issues and PR boards, task queue, services and pictures, and its own wall and floor colors, so you always know where you are. You only see and hear the people on your floor. The elevator panel shows how many workers are busy or waiting on someone on each floor, and you get a heads-up when a worker on another floor starts waiting. An admin can take a project off the building with the **🗑** beside its floor in the elevator: its workers stop, and everyone on it rides the elevator to another floor. Nothing is deleted. The checkout stays on disk with its workers, queue and pictures, and adding the same repository again moves back into it (as long as the workspace folder hasn't moved since). That goes for the project the office was started in (`agent-office <dir>`) too: it stays off after a restart, and the office keeps its own data in that folder as before.
- **Walk around.** Use WASD, Space to jump, and drag the mouse to orbit the camera. Everyone in the office sees everyone else move in real time.
- **A quiet screen.** The office stays in view: the top bar holds just the floor you're on, **🤖 Workers** and the **☰** menu (or **Tab**). The menu opens every window (issues, PRs, the queue, services, the whiteboard, search, voice, screen sharing, settings) and lists what can show on screen: the workers, who's in the office, spend, Claude limits, the chat and the floor details. Turn each one on or off there, or hide a panel with its **✕**. Pin anything you use a lot to the top bar. The choices are kept in your browser. Chat lines fade after a few seconds; hover the chat or press **T** to read back. What needs you shows up on the top bar by itself: the workers waiting on someone (click to go to them, like **N**), the mute button while you're in voice, **Sharing** while you share your screen, and **⬆️ Update** when there's a new version.
- **Coffee.** Press **E** at the coffee machine in the kitchen for a mug and a minute of quicker walking and higher jumps. A little meter under the project name shows how much buzz is left. Drink a third cup before the last one wears off and you get the jitters for a few seconds.
Expand Down
2 changes: 1 addition & 1 deletion docs/how-it-works.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ browser ──HTTPS/WSS──▶ agent-office (Node)
- **The gong.** Each time the office fetches the PR list, a PR that was open last time and is merged now rings the gong. A merge from the PR window rings as soon as `gh pr merge` returns, and isn't rung again when the list catches up. Anything else shows up at the next fetch: about every 90 seconds while someone is on the floor, and right after a queue task finishes. The gong is synthesized like the other sounds, so the volume and mute under **⚙️** apply to it.
- **Golf.** A shot is three numbers, its heading, loft and power, sent to everyone on the floor. Each browser works out the flight from those the same way, a fixed 240 steps a second: gravity and a little drag, the balcony's railing and wall, the neighbours' walls and roofs, the balconies further down, then bounces and a roll that depend on what it lands on (green, fringe, fairway, rough, sand or road), and the cup. So everyone sees the same ball land in the same place without it being streamed. The hitter's browser adds a little mishit to the numbers before sending them, so no two swings are exactly alike.
- **Jukebox.** Each floor's `jukebox.json` says only what's on and when it started, so it keeps playing through a restart. Every browser plays it for itself: a tune is decided note by note by its bar and step, so starting from the same moment is enough for everyone to hear the same thing. To agree on that moment, each page pings the office a few times on arriving and keeps the quickest answer to line its clock up with the office's. A tune is drums, bass, an FM electric piano and a melody picked from the chord tones, with record crackle and tape wobble, in 32-bar rounds. It's scheduled a second ahead on a timer rather than each frame, which lets it carry on in a background tab. It goes through a panner at the jukebox and a filter that muffles it with distance. Most streams can't be routed through Web Audio without CORS, so a stream plays in a plain `<audio>` element, turned down by hand on the same distance curve. An audio file seeks to where everyone else is.
- **Floors.** `floors.json` in the office's `.agent-office/` lists the floors: each one's checkout and colors. Adding one runs `gh repo view` (does this login see it, and what's its exact name), then `gh repo clone` into the projects folder; a checkout that's already there from the same repository is used as it is (one whose clone was cut off, with nothing checked out, isn't). The clone runs in a session of its own with no terminal, so nothing can stop to ask a question nobody sees, and git's progress goes to a log in `.agent-office/clones/`, which the office reads every second for the elevator panel. A log that stops growing for 3 minutes means the clone is stuck, and it's stopped. The clones under way are kept in `cloning.json`: an office restarted mid-clone (tsx watch, systemd) picks them up and carries on, while Ctrl+C stops them. Each floor runs its own workers, GitHub boards, queue and changes watcher in its checkout. A floor nobody is on, with nothing running, asks GitHub about its boards every 10 minutes instead of every 90 seconds. People get only the moves, worker updates and terminal frames of the floor they're on; the chat, voice connections and the budget are the building's.
- **Floors.** `floors.json` in the office's `.agent-office/` lists the floors: each one's checkout and colors. Adding one runs `gh repo view` (does this login see it, and what's its exact name), then `gh repo clone` into the projects folder; a checkout that's already there from the same repository is used as it is (one whose clone was cut off, with nothing checked out, isn't). The floor starts on the repository's default branch unless another was picked, which is git's own `--branch` after the `--`: the whole repository comes down, so the floor has every branch to work from, and only the checkout starts where they picked. The picker's list is `gh api repos/<owner>/<name>/branches`, asked for once someone picks the repository. A checkout already on disk is put on the picked branch with `git checkout` (which makes it from origin if it isn't there yet, and refuses rather than losing work on a dirty one). The clone runs in a session of its own with no terminal, so nothing can stop to ask a question nobody sees, and git's progress goes to a log in `.agent-office/clones/`, which the office reads every second for the elevator panel. A log that stops growing for 3 minutes means the clone is stuck, and it's stopped. The clones under way are kept in `cloning.json`: an office restarted mid-clone (tsx watch, systemd) picks them up and carries on, while Ctrl+C stops them. Each floor runs its own workers, GitHub boards, queue and changes watcher in its checkout. A floor nobody is on, with nothing running, asks GitHub about its boards every 10 minutes instead of every 90 seconds. People get only the moves, worker updates and terminal frames of the floor they're on; the chat, voice connections and the budget are the building's.
- **The rooftop.** Nobody works up there, so the roof isn't a floor: it's a place (`@roof`, which no floor id can be) that people are on, with none of a floor's workers, boards or queue. The DJ's set is endless and needs no state: its tracks, their keys, grooves and basslines, and where each one is follow from the office's clock, like the jukebox's tunes, so everyone up there hears the same bar, and the lights flash on the same kicks and snares even for someone with the music off. Drum and bass at 172 BPM, synthesized in the browser: a two-step break, a reese bass through a filter that opens and closes on the eighths, a sub, pads, an arpeggio, risers into each drop and an air horn when one lands. Being drunk is just your own browser's: while you are, the frame is drawn into a texture and onto the screen through a shader that doubles, smears and ripples it. With reduced motion on, nothing sways or strobes.
- **State.** The office's `.agent-office/` (in `~/agent-office`, or in the project you started it in) holds the password, the signing secret, the accounts and open invites (`accounts.json`), each account's own Claude, GitHub and git sign-ins (`homes/<account>/`), the floors (`floors.json`) and the clones on their way (`cloning.json`), the chat, the spend and whether workers go home once their PR merges (`leave-on-merge.json`). Each floor's checkout has its own `.agent-office/` with the hook settings, the saved workers and their scrollback, the task queue, the pictures on the walls (`decor.json`), the dog's name (`dog.json`), the jukebox (`jukebox.json`), the whiteboard (`whiteboard/`) and the meetings (`meetings.json`, and each meeting's notes in `meetings/`) and, for DeepSeek Harness workers, the profile patch (`dsh-patch.yml`) with their session logs under `dsh-sessions/`. It is added to `.git/info/exclude` automatically, so it never shows up in `git status`. The one thing the office writes outside it is a Cursor worker's hooks, which the Cursor CLI only reads from `.cursor/hooks.json` in the folder it runs in: they're there while the worker runs, and excluded from git the same way (see [Choosing an agent](agents.md)).

Expand Down
6 changes: 6 additions & 0 deletions src/client/ui/elevator.css
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@
.elevator .repo .when { font-size: 11px; color: var(--muted); white-space: nowrap; }
.elevator .note { margin: 8px 0 0; font-size: 12px; font-weight: 700; color: var(--muted); overflow-wrap: anywhere; }
.elevator .note.busy { color: var(--ink); }
/* The branch the new floor is cloned on, under the repository list. */
.elevator .branch-row { display: flex; gap: 8px; align-items: center; margin-top: 8px; font-size: 13px; font-weight: 800; }
.elevator .branch-row .lbl { color: var(--muted); }
.elevator .branch-row select { flex: 0 1 auto; min-width: 0; padding: 4px 8px; font: inherit; font-weight: 800; color: var(--ink); background: #fff; border: 3px solid var(--ink); border-radius: 12px; }
.elevator .branch-row select:disabled { color: var(--muted); }
.elevator .branch-note { flex: 1; min-width: 0; font-size: 12px; font-weight: 700; color: var(--bad); overflow-wrap: anywhere; }
/* The folder's Change button: styles/base.css, after the button rules it restyles. */
.elevator .dir-pick { margin-top: 8px; }
.elevator .err { margin: 8px 0 0; font-size: 13px; font-weight: 800; color: var(--bad); overflow-wrap: anywhere; }
Loading