Skip to content
Closed
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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ and jump into any of them together. Every GitHub repo is a floor of the building
[![Platform](https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-lightgrey?style=flat-square)](#run-locally)
[![Built with TypeScript](https://img.shields.io/badge/built%20with-TypeScript-3178c6?style=flat-square)](https://www.typescriptlang.org)

[**Run locally**](#run-locally) · [**Deploy to AWS**](#deploy-to-aws-ec2) · [**Azure**](#deploy-to-azure) · [**Railway**](#deploy-to-railway) · [**Fly.io**](#deploy-to-flyio) · [**Dokploy**](#deploy-to-dokploy) · [**Coolify**](#deploy-to-coolify) · [**Any server**](#deploy-to-any-ubuntu-or-debian-server) · [**Add users**](#add-users) · [**Controls**](#controls) · [**Features**](docs/features.md) · [**How it works**](docs/how-it-works.md)
[**Run locally**](#run-locally) · [**Deploy to AWS**](#deploy-to-aws-ec2) · [**Azure**](#deploy-to-azure) · [**Railway**](#deploy-to-railway) · [**Fly.io**](#deploy-to-flyio) · [**Dokploy**](#deploy-to-dokploy) · [**Coolify**](#deploy-to-coolify) · [**Any server**](#deploy-to-any-ubuntu-or-debian-server) · [**Add users**](#add-users) · [**Controls**](#controls) · [**Features**](docs/features.md) · [**System overview**](docs/system-overview.md) · [**How it works**](docs/how-it-works.md)

```sh
curl -fsSL https://raw.githubusercontent.com/AgentSystemLabs/agent-office/main/install.sh | bash
Expand All @@ -43,7 +43,7 @@ curl -fsSL https://raw.githubusercontent.com/AgentSystemLabs/agent-office/main/i

- **Other maps.** Turn the whole building into a castle: sit on a throne of iron blades while your workers line up before you when they're done, send new ones off through the Hand of the King, and watch their beards grow long and grey as they toil. Send one home and the Kingsguard runs up from the dungeon, marches it down the stairs and throws it in a cell, where it starves, dies and rots down to a skeleton. Or into a space station in orbit, the Earth turning outside its windows: you run it from the captain's chair on the bridge, and a worker sent home is marched to the airlock and blown out into space, to drift off past the observation windows with everyone who went before it. Or make a map of your own, with its own way of seeing workers off in JSON ([docs/maps.md](docs/maps.md)).

There's a lot more (a rooftop bar, an office dog, an arcade, supercars in the garage to drive round a scenic loop past a farm, pines, mountains and a beach): see [docs/features.md](docs/features.md).
There's a lot more (a rooftop bar, an office dog, an arcade, supercars in the garage to drive round a scenic loop past a farm, pines, mountains and a beach): see [docs/features.md](docs/features.md). Open **☰ → 📚 Docs** from anywhere to read the current project's docs without walking to the bookshelf. The bookshelf renders Mermaid diagrams in Markdown; the [system overview](docs/system-overview.md) is the quick flow map for this project.

## Requirements

Expand Down
4 changes: 2 additions & 2 deletions docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,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.
- **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.
- **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. **☰ → 📚 Docs** opens the current project's Markdown docs from anywhere, including the office map, without walking to the bookshelf. The bookshelf renders Mermaid diagrams; see the [system overview](system-overview.md) for this project's system flow map. Turn each panel on or off there, or hide it 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.
- **Boss office.** Stairs along the back wall climb to a glass-walled office on the loft in the corner. From up there you can look down over every desk and watch your workers go.
- **Ladder and fire poles.** The floors are stacked like a real building, with a ceiling over each. A ladder up the west wall goes through trapdoors in the ceiling and the floor: press **E** to grab it, **W** / **S** to climb, and **E** (or **Space**) to get off. Climb past the ceiling and you come up through the floor of the floor above. To go down in a hurry, walk into the hole round the fire pole (or press **E** at it). You slide down it spinning and come out of the ceiling below. The pole runs the whole way down the building, so a slide takes you one floor down and swings you off beside its hole there, ready to go again. On the bottom floor you land on a mat and a firehouse bell rings, and pressing **E** at the pole there gives you a twirl.
Expand Down Expand Up @@ -58,7 +58,7 @@ Everything in the office, room by room. Back to the [README](../README.md).
- **Services board.** When a worker starts a web server (`npm run dev`, a preview build, `python -m http.server`), it appears within a few seconds on the **🌐 Services** board, which hangs on the wall by the lounge and is also in the **☰** menu. Each entry shows the worker, its branch and the page's title. Click a row to copy one command that opens that server on your own computer. Or run `agent-office tunnel` on your computer once and leave it running: every server a worker starts opens there on the same port, by itself, and closes when the worker stops it ([Workers' servers on your own computer](tunnel.md)). Hire a worker with its own worktree, ask it to run the dev server, and your designer can review the branch in their own browser.
- **Pictures on the walls.** Press **F** (or **🖼️ Hang a picture** in the **☰** menu) and paste a link to any image online: a team photo, a diagram, a meme. Pick one of six frames, then aim at a wall and click to hang it. Scroll to size it first. Where it can't go, over a window or a board, the preview turns red. Everyone sees it right away, and it stays up across restarts. Look at a picture and press **E** for a closer look, or to move, edit or take it down.
- **A whiteboard to draw on together.** A whiteboard on wheels stands out on the floor between the desks and the lounge. Press **E** at it (or **📝 Whiteboard** in the **☰** menu) and [Excalidraw](https://excalidraw.com) opens, with shapes, arrows, freehand, text and pasted pictures. Everyone on the floor who opens it draws on the same board at once: you see their strokes as they draw, their cursors with their names, and what they have selected. The top of the window shows who's drawing, and so does the hint at the board. Whatever is drawn shows on the whiteboard in the office for everyone walking past, and stays there across restarts. Each floor has its own. Press Esc once to finish what you're doing and again to close it.
- **A bookshelf of the project's docs.** A bookshelf stands against the south wall, between the balcony doors and the window. Press **E** at it to read every Markdown file in the project: the README, the docs folder, each package's notes. Type in the filter box to narrow the list down. The letters only need to be in order, so `gs` finds `getting-started.md`, and each extra word narrows it again. Use **↑ ↓** and **Enter** to open one, and **Page Up/Down** to read on without leaving the box. Docs look the way GitHub shows them, with tables, code, callouts, task lists and the project's own pictures. A link to another doc opens it right there, **☰ Contents** jumps to any heading, and the shelf reopens on the doc you last read. While you read, your character holds an open book, turning a page now and then. Everyone else sees it, along with what you're reading under your name tag. A page turns with a soft swish when you open a doc or scroll a screenful. Turn the swish off with the 🔈 at the top of the bookshelf, or under **⚙️ → Sound & voice**.
- **A bookshelf of the project's docs.** A bookshelf stands against the south wall, between the balcony doors and the window. Press **E** at it to read every Markdown file in the project: the README, the docs folder, each package's notes. Type in the filter box to narrow the list down. The letters only need to be in order, so `gs` finds `getting-started.md`, and each extra word narrows it again. Use **↑ ↓** and **Enter** to open one, and **Page Up/Down** to read on without leaving the box. Docs look the way GitHub shows them, with tables, code, callouts, task lists, the project's own pictures, and rendered Mermaid diagrams. Mermaid stays optional and is loaded only for a document that contains a Mermaid code block; invalid diagrams keep their source visible. A link to another doc opens it right there, **☰ Contents** jumps to any heading, and the shelf reopens on the doc you last read. While you read, your character holds an open book, turning a page now and then. Everyone else sees it, along with what you're reading under your name tag. A page turns with a soft swish when you open a doc or scroll a screenful. Turn the swish off with the 🔈 at the top of the bookshelf, or under **⚙️ → Sound & voice**.
- **An office dog.** Every floor has a dog. It naps under the desks of workers who are busy, trots after people for a while, sniffs around and hangs out on the lounge rug. When a worker needs input, it drops everything, runs to that desk and barks until someone opens that worker's terminal, so you can see from across the room who's waiting. It stays there until the worker is answered. Walk up and press **E** to pet it, and everyone sees it wag. Name it under **⚙️** → *Office dog*, and pick its breed (a pup, a corgi, a dachshund, a pug, a shiba or a pomeranian) and its coat there too: they're for everyone on that floor. Until someone picks them, each floor's dog is a breed and coat of its own.
- **Sent home with a box.** A worker you send home (**X** at its desk) doesn't just vanish. Its light goes out, its face falls, and its things go into a cardboard box: a plant, a framed photo, its mug and a rubber duck. Its laptop snaps shut, and it hops off its chair and trudges out with the box in its arms, out the exit door, down the steps and off along the sidewalk. Floors above the bottom one have no exit door, so there it walks out onto the balcony instead, climbs up on the railing and jumps: its parachute pops open and it circles down onto the lot out front, box and all, then walks off along the sidewalk. The desk is free straight away, so you can hire someone new while the last one is still on the way out. In the castle it goes to the dungeon instead and on the space station out of the airlock, and a map of your own can script its own way of seeing workers off ([Sending workers home](maps.md#sending-workers-home)).
- **Voice.** Browser-to-browser WebRTC voice. Volume depends on how close you stand, but people are never fully silent. **V** joins, and once you're in, **V** is push to talk: hold it to talk, and you're muted when you let go. **M** mutes and unmutes. Pick **Push to talk** under **⚙️** to join muted, or keep an open mic. Leave voice from the **☰** menu.
Expand Down
51 changes: 51 additions & 0 deletions docs/system-overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# System overview

Back to the [README](../README.md). This is the quick map of how a person, a project floor and its workers fit together. For implementation detail, see [How it works](how-it-works.md) and [Code layout](code-layout.md).

```mermaid
flowchart LR
person[Teammate] -->|browser: HTTPS + WebSocket| client[Client<br/>HUD, 3D world, windows]
client <-->|messages and state| office[Agent Office server<br/>Node.js]

office --> floors[Floor manager]
floors -->|one floor per project| project[Project checkout<br/>boards, queue, docs, settings]
project -->|GitHub CLI| github[GitHub<br/>issues, pull requests, branches]

office --> manager[Worker manager]
manager -->|PTY or ACP session| agent[Agent CLI<br/>Claude, Codex, OpenCode, etc.]
agent -->|reads and changes files| project
agent -->|hooks / worker tools| hooks[Loopback hook server<br/>status, tasks, worker actions]
hooks --> manager

office --> storage[Office data<br/>accounts, floors, chat, settings]
manager --> workerdata[Project data<br/>sessions, queue, worktrees]
workerdata --> project

client -->|live presence, chat, voice signaling| peers[Other teammates]
office -->|WebRTC signaling| peers
```

## Typical task flow

```mermaid
sequenceDiagram
actor Teammate
participant Browser as Browser client
participant Office as Agent Office server
participant Floor as Project floor
participant Worker as Agent worker
participant GitHub

Teammate->>Browser: Choose a project and assign work
Browser->>Office: Send task over WebSocket
Office->>Floor: Create worker and optional worktree
Floor->>Worker: Start agent CLI in project directory
Worker->>Floor: Read and edit project files
Worker-->>Office: Report status through hooks or ACP
Office-->>Browser: Stream status and terminal updates
Worker->>GitHub: Push branch and open pull request
GitHub-->>Floor: Pull request data is refreshed
Floor-->>Browser: Show the PR on the board and worker desk
```

The project agent should keep this page aligned with the actual system when architecture changes. Mermaid source stays ordinary Markdown, so it can also be reviewed and edited in GitHub.
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"concurrently": "^10.0.5",
"dompurify": "^3.4.16",
"marked": "^18.0.14",
"mermaid": "^11.17.2",
"playwright-core": "^1.63.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
Expand Down
3 changes: 2 additions & 1 deletion src/client/features/bookshelf/ui.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import './ui.css';
import { isDocPath, resolveDocLink, type DocFile, type DocList, type DocText } from '../../../shared/docs';
import { clip, h, openModal, setDoing, timeAgo, toast } from '../../ui/dom';
import { markdownFile } from '../../ui/markdown';
import { markdownFile, renderMermaidDiagrams } from '../../ui/markdown';

// The bookshelf: every Markdown file in the floor's project, to read without leaving the office.
// The filter box over the list picks docs out as you type (the letters in order, not necessarily
Expand Down Expand Up @@ -322,6 +322,7 @@ export function openBookshelf(deps: ShelfDeps) {
const body = doc.text.trim() ? markdownFile(doc.text) : h('div.md', {}, h('p.none', {}, 'This file is empty.'));
wire(body, path);
page.replaceChildren(body);
void renderMermaidDiagrams(body);
const dir = path.slice(0, path.length - nameOf(path).length);
crumbs.replaceChildren(dir ? h('span.dir', {}, dir) : '', nameOf(path));
crumbs.title = path;
Expand Down
4 changes: 2 additions & 2 deletions src/client/features/hud/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ export function installHud(ctx: Ctx, core: CoreState, parts: HudParts) {
run: () => parts.meeting.showMeeting(),
},
{ id: 'search', icon: '🔎', label: 'Search', section: 'Open', key: '/', title: () => 'Search the chat and every terminal', run: waiting.showSearch },
// The office has its bookshelf for them; a map of its own may not.
{ id: 'docs', icon: '📚', label: 'Docs', section: 'Open', shown: () => !inOffice(), title: () => 'Read the project’s docs', run: parts.bookshelf.showBookshelf },
// Keep project docs one click away from the office map too; the bookshelf reads the current floor.
{ id: 'docs', icon: '📚', label: 'Docs', section: 'Open', title: () => 'Read the current project’s docs', run: parts.bookshelf.showBookshelf },
{ id: 'elevator', icon: '🛗', label: () => (inOffice() ? 'Elevator' : 'Floors'), section: 'Open', count: () => store.floors.reduce((n, f) => n + (f.id === store.floor ? 0 : f.waiting), 0), title: () => (inOffice() ? 'Ride to another project' : 'Go to another project, or add one'), run: travel.showElevator },
{ id: 'roof', icon: '🍸', label: 'Rooftop bar', section: 'Open', shown: () => !core.upTop && inOffice() && builtFloors().length > 0, title: () => 'Ride the elevator up to the roof: a DJ, drinks and the city', run: () => travel.ride(ROOF) },
// In voice, V is push to talk, so leaving is only from here.
Expand Down
Loading