agent-office-studio 0.3.0 → 0.4.0

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/dist/index.html CHANGED
@@ -24,9 +24,9 @@
24
24
  } catch (e) {}
25
25
  })();
26
26
  </script>
27
- <title>Agent Office</title>
28
- <script type="module" crossorigin src="/assets/index-DgXF8Kqx.js"></script>
29
- <link rel="stylesheet" crossorigin href="/assets/index-D5IzEWKU.css">
27
+ <title>Office</title>
28
+ <script type="module" crossorigin src="/assets/index-S_6NhxZ0.js"></script>
29
+ <link rel="stylesheet" crossorigin href="/assets/index-CiEWLydu.css">
30
30
  </head>
31
31
  <body>
32
32
  <div class="app" id="app" data-m="office">
@@ -34,9 +34,12 @@
34
34
  <div class="side-grip" id="side-grip" role="separator" aria-orientation="vertical" aria-label="Resize the side panel" tabindex="0"></div>
35
35
  <header class="brand">
36
36
  <div class="title">
37
- <h1>Agent Office</h1>
37
+ <span class="title-start">
38
+ <span class="lv" role="img" id="lv" aria-label="Level 1"><svg viewBox="0 0 36 36" aria-hidden="true"><circle class="trk" cx="18" cy="18" r="15"/><circle class="arc" cx="18" cy="18" r="15" pathLength="100"/></svg><b id="lvNum">1</b></span>
39
+ <h1 id="officeName">Your Office</h1>
40
+ <button type="button" class="fold" id="fold" aria-label="Show usage" aria-expanded="false" aria-controls="gaugesBox" title="Show usage"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg></button>
41
+ </span>
38
42
  <span class="title-end">
39
- <span class="lv" id="lv">Lv 1</span>
40
43
  <button type="button" class="theme-btn" id="lbBtn" aria-label="Leaderboard" aria-haspopup="true" aria-expanded="false" title="Leaderboard">
41
44
  <svg viewBox="0 0 24 24"><path d="M8 4h8v5a4 4 0 0 1-8 0z"/><path d="M8 6H5v1a3 3 0 0 0 3 3"/><path d="M16 6h3v1a3 3 0 0 1-3 3"/><path d="M12 13v4"/><path d="M8.5 20h7"/></svg>
42
45
  </button>
@@ -46,6 +49,9 @@
46
49
  <button type="button" class="theme-btn" id="acctBtn" aria-label="Claude access" aria-haspopup="true" aria-expanded="false" title="Claude access">
47
50
  <svg viewBox="0 0 24 24"><circle cx="8" cy="15" r="4"/><path d="M10.8 12.2 20 3"/><path d="m17 6 3 3"/><path d="m14.5 8.5 2 2"/></svg>
48
51
  </button>
52
+ <button type="button" class="theme-btn" id="setBtn" aria-label="Settings" aria-haspopup="dialog" aria-expanded="false" title="Settings">
53
+ <svg viewBox="0 0 24 24"><path d="M4 7h9M17 7h3M4 17h3M11 17h9"/><circle cx="15" cy="7" r="2"/><circle cx="9" cy="17" r="2"/></svg>
54
+ </button>
49
55
  <button type="button" class="theme-btn" id="themeBtn" aria-label="Appearance" aria-haspopup="true" aria-expanded="false" title="Appearance">
50
56
  <svg viewBox="0 0 24 24"><path d="M12 3a9 9 0 1 0 0 18c1.4 0 2-.9 2-1.8 0-.9-.6-1.3-.6-2.2 0-1 .8-1.6 1.8-1.6H17a4 4 0 0 0 4-4C21 6.7 17 3 12 3z"/><circle cx="7.5" cy="11" r="1"/><circle cx="10" cy="7" r="1"/><circle cx="15" cy="7.5" r="1"/></svg>
51
57
  </button>
@@ -59,17 +65,18 @@
59
65
  <div class="xpbar"><i id="xpbar"></i></div>
60
66
  <span class="xp" id="xptext">0 / 100 XP</span>
61
67
  </div>
68
+ <div class="gauges" id="gaugesBox" hidden>
62
69
  <div class="usage" id="usage" aria-label="Plan usage">
63
70
  <div class="meter" id="useSession">
64
71
  <span class="k">Session</span>
65
72
  <span class="v"></span>
66
- <div class="bar"><i></i></div>
73
+ <svg class="bar" viewBox="0 0 36 36" aria-hidden="true"><circle class="trk" cx="18" cy="18" r="15"/><circle class="arc" cx="18" cy="18" r="15" pathLength="100"/><g class="ico"><path d="M18 13v5l3 2"/></g></svg>
67
74
  <span class="r"></span>
68
75
  </div>
69
76
  <div class="meter" id="useWeek">
70
77
  <span class="k">Week</span>
71
78
  <span class="v"></span>
72
- <div class="bar"><i></i></div>
79
+ <svg class="bar" viewBox="0 0 36 36" aria-hidden="true"><circle class="trk" cx="18" cy="18" r="15"/><circle class="arc" cx="18" cy="18" r="15" pathLength="100"/><g class="ico"><rect x="13" y="14" width="10" height="9" rx="1.5"/><path d="M13 17.5h10M16 12.5v2.5M20 12.5v2.5"/></g></svg>
73
80
  <span class="r"></span>
74
81
  </div>
75
82
  <p class="u-err" id="useErr" hidden></p>
@@ -78,16 +85,17 @@
78
85
  <div class="meter" id="loadCpu">
79
86
  <span class="k">CPU</span>
80
87
  <span class="v"></span>
81
- <div class="bar"><i></i></div>
88
+ <svg class="bar" viewBox="0 0 36 36" aria-hidden="true"><circle class="trk" cx="18" cy="18" r="15"/><circle class="arc" cx="18" cy="18" r="15" pathLength="100"/><g class="ico"><rect x="14" y="14" width="8" height="8" rx="1.5"/><path d="M16.5 12v2M19.5 12v2M16.5 22v2M19.5 22v2M12 16.5h2M12 19.5h2M22 16.5h2M22 19.5h2"/></g></svg>
82
89
  <span class="r"></span>
83
90
  </div>
84
91
  <div class="meter" id="loadMem">
85
92
  <span class="k">Memory</span>
86
93
  <span class="v"></span>
87
- <div class="bar"><i></i></div>
94
+ <svg class="bar" viewBox="0 0 36 36" aria-hidden="true"><circle class="trk" cx="18" cy="18" r="15"/><circle class="arc" cx="18" cy="18" r="15" pathLength="100"/><g class="ico"><rect x="12.5" y="14.5" width="11" height="7" rx="1"/><path d="M15.5 21.5v1.5M18 21.5v1.5M20.5 21.5v1.5M15.5 17h1M19.5 17h1"/></g></svg>
88
95
  <span class="r"></span>
89
96
  </div>
90
97
  </div>
98
+ </div>
91
99
  </header>
92
100
  <nav class="tabs">
93
101
  <button type="button" data-tab="chat" class="on">Chat</button>
@@ -241,5 +249,6 @@
241
249
  </button>
242
250
  </nav>
243
251
  </div>
252
+ <dialog class="settings" id="settings" aria-label="Settings"></dialog>
244
253
  </body>
245
254
  </html>
@@ -5,8 +5,8 @@ The key button beside Appearance chooses how the office signs in to Claude:
5
5
  - **Claude Code login** — the login Claude Code keeps on this machine, so jobs
6
6
  run on your Claude plan and the plan meters show how much of it is used.
7
7
  - **API key** — an Anthropic API key, billed to that API account. Paste it
8
- once; it's checked with Anthropic, kept in `data/auth.json` (readable only by
9
- you) and never sent back to the browser. A key already in
8
+ once; it's checked with Anthropic, kept in `auth.json` in the data folder
9
+ (readable only by you) and never sent back to the browser. A key already in
10
10
  `ANTHROPIC_API_KEY` is used until you paste another. The plan meters hide,
11
11
  because there's no plan.
12
12
 
@@ -4,6 +4,8 @@ Everything is set with environment variables when the server starts, e.g.
4
4
  `PORT=4400 CHIEF_MODEL=haiku npm start`. In-app choices — Claude access, the
5
5
  voice toggle, team profiles, theme — are made in the office and remembered.
6
6
 
7
+ **Settings page.** Open the sliders icon in the office header to change the owner, token limit, compaction point, chief model, standup time and weekends, sharing of job titles, and the break-room talk without restarting. A value saved there wins over the environment variable below, which becomes the default; "Use the default" puts it back. Everything else here is environment-only.
8
+
7
9
  ## The office
8
10
 
9
11
  | Env | Default | |
@@ -23,6 +25,7 @@ voice toggle, team profiles, theme — are made in the office and remembered.
23
25
  | `CLAUDE_CODE_OAUTH_TOKEN` | none | a Claude Code login token, for the login mode and the plan meters |
24
26
  | `CHIEF_MODEL` | `sonnet` | the chief of staff, and the standup write-up |
25
27
  | `AGENT_COMPACT_PCT` | `60` | how full an agent's context gets before Claude Code compacts it |
28
+ | `AGENT_CLEAR_TOKENS` | `150000` | context size past which an agent's next message nudges it to `clear_context` and start fresh; `0` turns the nudge off; the limit set in the office (Claude access menu) overrides it |
26
29
 
27
30
  ## Standup and the break room
28
31
 
@@ -68,6 +68,22 @@ so you can check what a job was started with without spending tokens.
68
68
  When you stop a test server, kill it by PID, not with `pkill -f`, which can't
69
69
  tell it from the live one.
70
70
 
71
+ ## Releasing
72
+
73
+ 1. Move the changelog's *Unreleased* entries under a new version heading,
74
+ `## 0.2.0 — <date>`.
75
+ 2. Set the same version in `package.json` (`npm version 0.2.0 --no-git-tag-version`).
76
+ 3. Commit, then tag and push: `git tag v0.2.0 && git push origin master v0.2.0`.
77
+
78
+ The *Release* workflow checks the tag matches `package.json`, runs the build,
79
+ the smoke test and `scripts/pack-smoke.sh` (which installs the packed package
80
+ the way a user would), publishes to npm with provenance, and creates the
81
+ GitHub release from that changelog section. It needs an npm access token in
82
+ the repository secret `NPM_TOKEN`.
83
+
84
+ To try the package locally without publishing: `sh scripts/pack-smoke.sh`, or
85
+ `npm pack` and `npm install -g ./agent-office-studio-*.tgz`.
86
+
71
87
  ## The launch video
72
88
 
73
89
  `launch/` holds the tooling that recorded the launch video: `setup.sh` resets a
@@ -1,36 +1,42 @@
1
1
  # Updating
2
2
 
3
- Your office's state — jobs, chat, channels, XP, team profiles, Claude access —
4
- lives in `data/`, which updates never touch.
3
+ Your office — jobs, chat, channels, XP, team profiles, Claude access — lives
4
+ in the data folder (`~/.agent-office`), which updates never touch.
5
5
 
6
- ## From a git clone
6
+ ## The installed command
7
7
 
8
8
  ```bash
9
- cd agent-office
10
- git pull
11
- npm install
12
- npm run build
9
+ npm install -g agent-office-studio@latest
13
10
  ```
14
11
 
15
- Then stop the office (Ctrl-C in its terminal) and start it again with
16
- `npm start`. Running jobs are stopped cleanly and resume when it comes back.
12
+ Then stop the office (Ctrl-C) and start it again. Running jobs stop cleanly
13
+ and resume when it comes back.
14
+
15
+ Read the [changelog](../../CHANGELOG.md) for what changed and anything you
16
+ need to do. `agent-office --version` says what you're on.
17
17
 
18
- Read [CHANGELOG.md](../../CHANGELOG.md) for what changed, and anything you
19
- need to do.
18
+ ### A particular version
20
19
 
21
- ## Pinning a version
20
+ ```bash
21
+ npm install -g agent-office-studio@0.2.0
22
+ ```
22
23
 
23
- To stay on a release rather than the latest code:
24
+ ## A clone
24
25
 
25
26
  ```bash
26
- git fetch --tags
27
- git checkout v0.1.0
28
- npm install && npm run build
27
+ cd agent-office
28
+ git pull
29
+ npm install
30
+ npm run build
29
31
  ```
30
32
 
33
+ Then restart it with `npm start`. To stay on a release, check out its tag
34
+ (`git checkout v0.2.0`) instead of pulling. A clone's data is in `data/`.
35
+
31
36
  ## If something breaks
32
37
 
33
- - `npm install` failing on `node-pty` is harmless: it's optional, and only
34
- the terminal needs it. See [Troubleshooting](troubleshooting.md#the-terminal-wont-open).
35
- - To keep a way back, copy `data/` before updating. Going back is then: stop
36
- the office, check out the previous tag, restore `data/`, build and start.
38
+ - **Keep a way back:** copy the data folder before updating. Going back is
39
+ then: stop the office, install the previous version, restore the folder,
40
+ start.
41
+ - **The terminal stops working after an update:** node-pty needs rebuilding;
42
+ see [Troubleshooting](troubleshooting.md#the-terminal-wont-open).
package/docs/jobs.md CHANGED
@@ -33,6 +33,27 @@ never moves on its own.
33
33
  The drawer shows each job's model and how much context its last turn carried,
34
34
  so a session that has grown expensive is visible rather than guessed at.
35
35
 
36
+ An agent can also clear its own context. Its `clear_context` tool takes notes
37
+ to itself (what is done, what is left, what it learned); when it ends its
38
+ turn the office closes the session and starts the job again fresh, carrying the
39
+ brief, those notes and any message that arrived meanwhile. The history is what
40
+ costs tokens on every turn, so this is the way to shed it at a natural break.
41
+ Once a session's context passes `AGENT_CLEAR_TOKENS` (150,000 by default, `0` to
42
+ turn it off), the next message the agent receives carries a one-time nudge to do
43
+ this. Clearing is still the agent's call. The log records each clear, and it is
44
+ capped at five per job.
45
+
46
+ The boss can also just say "clear context" in chat, for everyone or for named
47
+ agents. The chief of staff does it directly: a working agent restarts fresh when
48
+ its current turn ends (carrying its last reply as notes), and a finished job
49
+ forgets its session so the next reply starts clean.
50
+
51
+ Neither kind of clear loses track of the work. The office keeps a short note on
52
+ the job (`lastClear`: the agent's last report, or the brief if it had not
53
+ reported) and shows it in the job's log. A reply to a cleared job carries the
54
+ note and the brief into the fresh session, and any new job the agent takes
55
+ mentions what they were last on, so "what were you doing?" still has an answer.
56
+
36
57
  ## What changed
37
58
 
38
59
  When a job starts, the office snapshots the project's working tree; when it
package/docs/phone.md CHANGED
@@ -16,7 +16,7 @@ The supported way is [Tailscale](https://tailscale.com): put the office behind
16
16
 
17
17
  ```bash
18
18
  tailscale serve --bg 4317
19
- OFFICE_ALLOWED_HOSTS=my-mac.tail1234.ts.net npm start
19
+ OFFICE_ALLOWED_HOSTS=my-mac.tail1234.ts.net agent-office
20
20
  ```
21
21
 
22
22
  `OFFICE_ALLOWED_HOSTS` takes exact hostnames, comma-separated. Every other
@@ -27,6 +27,6 @@ On the phone, open the tailnet address once with the office key on the end,
27
27
  printed, or `agentoffice --link`). The phone keeps it after that.
28
28
 
29
29
  **Read this first.** Whoever can open that address can run Claude in your
30
- projects with full autonomy, and — if `OFFICE_TERMINAL=1` — get a shell on
30
+ projects with full autonomy, and — if started with `--terminal` — get a shell on
31
31
  this machine. Only expose it on a tailnet that is just you. Never put it on
32
32
  the open internet. See [Security](security.md).
package/docs/security.md CHANGED
@@ -35,10 +35,10 @@ command you could.
35
35
  `claude` it starts reads them. The plan meters read the login's access token
36
36
  to ask for usage, and nothing else.
37
37
  - With an **API key**, the key is checked with Anthropic, stored in
38
- `data/auth.json` with mode `0600`, passed only to the `claude` processes the
38
+ `auth.json` in the data folder with mode `0600`, passed only to the `claude` processes the
39
39
  office starts, and never sent to the browser, which sees the last four
40
40
  characters.
41
- - `data/` is git-ignored.
41
+ - The data folder is outside the package (`~/.agent-office`), or git-ignored `data/` in a clone.
42
42
 
43
43
  ## The leaderboard
44
44
 
@@ -75,6 +75,6 @@ people you would trust with those projects. Details in
75
75
 
76
76
  ## The terminal
77
77
 
78
- Off unless `OFFICE_TERMINAL=1`. A session needs a single-use ticket from the
78
+ Off unless started with `--terminal` (`OFFICE_TERMINAL=1`). A session needs a single-use ticket from the
79
79
  origin-checked API, no agent can open one, and keystrokes are never logged. It
80
80
  is not a sandbox. Details in [The terminal](terminal.md).
package/docs/terminal.md CHANGED
@@ -10,7 +10,7 @@ the way they do in a terminal app.
10
10
  It is off until you ask for it:
11
11
 
12
12
  ```bash
13
- OFFICE_TERMINAL=1 npm start
13
+ agent-office --terminal # or, in a clone: OFFICE_TERMINAL=1 npm start
14
14
  ```
15
15
 
16
16
  That switch exists because shell access is the one door in the building that
@@ -26,8 +26,8 @@ So:
26
26
  - **Not for the staff.** No agent can open one. There's no office tool and no
27
27
  `/api/agent` route that reaches it, and a shell never inherits the job
28
28
  credentials the office gives its own children.
29
- - **Nothing is kept.** Not in `data/state.json`, not in the chat, not on the
30
- main socket. Scrollback lives in the tab and dies with it. `data/terminal.log`
29
+ - **Nothing is kept.** Not in `state.json`, not in the chat, not on the
30
+ main socket. Scrollback lives in the tab and dies with it. `terminal.log` in the data folder
31
31
  records when sessions opened and closed and in which folder — never
32
32
  keystrokes, because a log of what you typed into a shell is a file full of
33
33
  passwords.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-office-studio",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "A 3D office where the staff are Claude Code agents.",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -49,17 +49,17 @@
49
49
  "prepack": "vite build"
50
50
  },
51
51
  "dependencies": {
52
- "@fontsource-variable/inter": "5.1.0",
53
- "@fontsource/jetbrains-mono": "5.1.1",
54
- "@xterm/addon-fit": "0.10.0",
55
- "@xterm/xterm": "5.5.0",
56
- "marked": "^14.1.3",
57
- "three": "0.169.0",
58
- "ws": "8.18.0"
52
+ "ws": "8.22.0"
59
53
  },
60
54
  "devDependencies": {
61
- "concurrently": "9.0.1",
62
- "vite": "5.4.10"
55
+ "@fontsource-variable/inter": "5.3.0",
56
+ "@fontsource/jetbrains-mono": "5.3.0",
57
+ "@xterm/addon-fit": "0.11.0",
58
+ "@xterm/xterm": "6.0.0",
59
+ "concurrently": "10.0.6",
60
+ "marked": "^18.1.0",
61
+ "three": "0.186.1",
62
+ "vite": "6.4.3"
63
63
  },
64
64
  "optionalDependencies": {
65
65
  "node-pty": "1.0.0"
package/server/chief.js CHANGED
@@ -24,7 +24,7 @@ export function canSee(files) {
24
24
  const SCHEMA = {
25
25
  type: 'object',
26
26
  properties: {
27
- action: { type: 'string', enum: ['followup', 'new', 'dismiss', 'recall', 'standup', 'ask', 'chat'] },
27
+ action: { type: 'string', enum: ['followup', 'new', 'dismiss', 'recall', 'clear', 'standup', 'ask', 'chat'] },
28
28
  jobId: { type: 'string' },
29
29
  agentId: { type: 'string' },
30
30
  agentIds: { type: 'array', items: { type: 'string' } },
@@ -45,6 +45,7 @@ Actions:
45
45
  - "new": a new piece of work. Give "repo" (exactly one name from Projects), "brief" (the task in the boss's own words, plus any context from recent chat that the agent needs; never add requirements), "agentId" (the tagged agent's id; otherwise a free agent whose role in Staff clearly fits the work; otherwise "" for whoever is free), and "model" (see Sizing the work). Never pick a busy or dismissed agent unless the boss tagged them.
46
46
  - "dismiss": the boss wants agents sent home (dismissed, let go for now, off the floor). Give "agentIds": the ids of exactly who they mean, worked out from Staff (e.g. "everyone who's free except Mira" means every free agent but Mira). Only free agents can go; leave out anyone working.
47
47
  - "recall": the boss wants dismissed agents back in. Give "agentIds" (every dismissed agent if they say "everyone").
48
+ - "clear": the boss wants agents to clear their context (start fresh, forget the conversation so far). Do it yourself; never hand it out as a job. Give "agentIds" for the agents they name, or leave it empty when they mean everyone.
48
49
  - "standup": the boss wants the team to hold a standup now (e.g. "standup time", "let's do standup", "gather everyone for a status update").
49
50
  - "ask": you can't tell which project new work belongs to, or the request is too unclear to start. Ask one short question.
50
51
  - "chat": greetings, thanks, or questions about the office itself (who is doing what). Answer from the context given. If your answer is about one particular job, give its jobId too, so the boss gets a link to where that job's updates are collecting.