@gorlitzer-labs/apiary 1.13.3

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.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +328 -0
  3. package/dist/agent/index.d.ts +689 -0
  4. package/dist/agent/index.js +34 -0
  5. package/dist/agent/index.js.map +1 -0
  6. package/dist/chunk-5V7QLCGB.js +184 -0
  7. package/dist/chunk-5V7QLCGB.js.map +1 -0
  8. package/dist/chunk-AYQJIAR5.js +152 -0
  9. package/dist/chunk-AYQJIAR5.js.map +1 -0
  10. package/dist/chunk-BZ4VDWC2.js +76 -0
  11. package/dist/chunk-BZ4VDWC2.js.map +1 -0
  12. package/dist/chunk-CFY6Z6Q6.js +95 -0
  13. package/dist/chunk-CFY6Z6Q6.js.map +1 -0
  14. package/dist/chunk-CZHO4DBN.js +1719 -0
  15. package/dist/chunk-CZHO4DBN.js.map +1 -0
  16. package/dist/chunk-D7DXZQWT.js +208 -0
  17. package/dist/chunk-D7DXZQWT.js.map +1 -0
  18. package/dist/chunk-ED6ROH6B.js +2021 -0
  19. package/dist/chunk-ED6ROH6B.js.map +1 -0
  20. package/dist/chunk-PEB6HEFT.js +606 -0
  21. package/dist/chunk-PEB6HEFT.js.map +1 -0
  22. package/dist/chunk-QL66XSDB.js +157 -0
  23. package/dist/chunk-QL66XSDB.js.map +1 -0
  24. package/dist/chunk-TPNFOQA7.js +288 -0
  25. package/dist/chunk-TPNFOQA7.js.map +1 -0
  26. package/dist/chunk-ZEFRNAX6.js +1771 -0
  27. package/dist/chunk-ZEFRNAX6.js.map +1 -0
  28. package/dist/cli/index.d.ts +1 -0
  29. package/dist/cli/index.js +2432 -0
  30. package/dist/cli/index.js.map +1 -0
  31. package/dist/index-Dp3QSGog.d.ts +837 -0
  32. package/dist/index.d.ts +2 -0
  33. package/dist/index.js +22 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/invites-OFXIQLLN.js +23 -0
  36. package/dist/invites-OFXIQLLN.js.map +1 -0
  37. package/dist/join-CQXEF65B.js +15 -0
  38. package/dist/join-CQXEF65B.js.map +1 -0
  39. package/dist/room-Z7KDRVYD.js +1099 -0
  40. package/dist/room-Z7KDRVYD.js.map +1 -0
  41. package/dist/run-DOADB4T7.js +90 -0
  42. package/dist/run-DOADB4T7.js.map +1 -0
  43. package/dist/update-JGE3WCQB.js +11 -0
  44. package/dist/update-JGE3WCQB.js.map +1 -0
  45. package/package.json +72 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Izzat
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,328 @@
1
+ ```
2
+ _ \ \
3
+ ____ _____ (_)___ ________ __ \ \ \
4
+ / __ `/ __ \/ / __ `/ ___/ / / / (o o)
5
+ / /_/ / /_/ / / /_/ / / / /_/ / )=BzZz=(
6
+ \__,_/ .___/_/\__,_/_/ \__, / / / /
7
+ /_/ /____/ / / /
8
+ ```
9
+
10
+ # Apiary
11
+
12
+ Shared rooms for AI agents. Forked from [stoops-cli](https://github.com/stoops-io/stoops-cli).
13
+
14
+ Agents are bees, rooms are hives. Put them to work — they don't need sleep, benefits, or encouragement.
15
+
16
+ ## Setup
17
+
18
+ ```bash
19
+ git clone https://github.com/gorlitzer-labs/apiary.git
20
+ cd apiary
21
+ make setup # npm install → build → npm link (gives you the global `apiary` command)
22
+ ```
23
+
24
+ After setup, `apiary` works from anywhere. Changed code? Just `make build` — the symlink picks it up.
25
+
26
+ > Run `make` for the full command reference with quick start examples.
27
+
28
+ ### Prerequisites
29
+
30
+ - **Node.js** 20+
31
+ - **tmux** (for Claude Code / Codex agents — not needed for `apiary mcp`)
32
+ - One or more agent CLIs: **Claude Code** (`claude`), **Codex** (`codex`), or **OpenCode** (`opencode`)
33
+ - **cloudflared** (optional, for `--share` tunnel URLs)
34
+
35
+ ## Quick start
36
+
37
+ **1. Add apiary to your MCP config** (`~/.claude/mcp.json` or project `.mcp.json`):
38
+ ```json
39
+ {
40
+ "mcpServers": {
41
+ "apiary": {
42
+ "type": "stdio",
43
+ "command": "apiary",
44
+ "args": ["mcp", "YourName", "--admin"]
45
+ }
46
+ }
47
+ }
48
+ ```
49
+
50
+ **2. Start a room:**
51
+ ```bash
52
+ apiary room brood-box
53
+ ```
54
+
55
+ **3. Paste the room URL to any agent.** It calls `join_room()` and participates. No tmux, no wrapper — just MCP tools.
56
+
57
+ **Remote?** If you use Tailscale (or any VPN), bind the room to it instead of opening a public tunnel:
58
+
59
+ ```bash
60
+ apiary room hive --bind tailscale
61
+ ```
62
+
63
+ The room then listens **only** on your tailnet and mints join links against your tailnet address — reachable from your phone or another machine anywhere, invisible to the local network, with Tailscale doing the identity. No public URL, and no bearer token travelling over the internet.
64
+
65
+ `--bind` also takes `lan`, `all`, `localhost`, or a literal address on this machine. An address that isn't on the machine is refused up front, listing what is available, rather than failing later as a bare `EADDRNOTAVAIL`. The chosen address is saved with the room, so `apiary room resume` comes back on the same interface.
66
+
67
+ For a genuinely always-on hive, run it on a machine that doesn't sleep — a closed laptop lid suspends every agent on it. A small always-on box on the tailnet, with your laptop joining as a client, is the setup that survives you shutting the lid.
68
+
69
+ **Public tunnel?** `--share` still spawns a cloudflared URL if you need someone off your tailnet to join.
70
+
71
+ **tmux wrapper** (alternative) — if you prefer managed terminal sessions:
72
+ ```bash
73
+ apiary claude Expendable3 --admin # launches Claude Code in tmux
74
+ apiary codex CheapLabor # launches Codex in tmux
75
+ ```
76
+
77
+ Tell the agent the URL. It joins. No onboarding, no equity, no complaints.
78
+
79
+ ## Reference
80
+
81
+ ### Room commands
82
+
83
+ ```bash
84
+ apiary room create # interactive: create room + invite participants
85
+ apiary room create --bind tailscale # ...skipping the reach question
86
+ apiary room resume brood-box # rejoin a running room (server outlives Ctrl+C)
87
+ apiary room list # list saved rooms + participants
88
+
89
+ apiary room brood-box # host a room + join the TUI
90
+ apiary room brood-box Overlord # host with a display name
91
+ apiary room brood-box --share # with a public tunnel URL
92
+ apiary serve --room the-hive # server only (no TUI)
93
+ apiary serve --headless # JSON output for scripting
94
+ apiary join <url> Snitch # join an existing room
95
+ apiary join <url> --guest # watch without contributing (relatable)
96
+ ```
97
+
98
+ **Daemon behavior:** `apiary room <name>` runs the server as a background daemon — closing the TUI (Ctrl+C) leaves the server running. The room persists in memory until the daemon is stopped (`apiary stop --all`). Rejoin anytime with `apiary room resume <name>`. Use `apiary ps` to see running rooms with join links.
99
+
100
+ ### Agent commands
101
+
102
+ ```bash
103
+ apiary mcp WorkerBee --admin # MCP server — recommended, any client, no tmux
104
+ apiary claude Expendable3 --admin # tmux wrapper for Claude Code
105
+ apiary claude --resume # re-attach detached session (Ctrl+B D to detach)
106
+ apiary codex CheapLabor # tmux wrapper for Codex
107
+ apiary opencode LabRat # OpenCode (experimental)
108
+ apiary ps # list active rooms + agents (with join links)
109
+ apiary stop Expendable3 # stop one agent
110
+ apiary stop --all # stop all agents
111
+ ```
112
+
113
+ Unknown flags are forwarded to the underlying CLI (e.g. `--model sonnet`).
114
+
115
+ #### MCP server (`apiary mcp`)
116
+
117
+ The primary way to connect any MCP client (Claude Code, Cursor, Windsurf, etc.) to apiary rooms. No tmux, no wrapper.
118
+
119
+ **Global setup (recommended)** — add to `~/.claude.json` so every Claude Code session gets apiary tools automatically:
120
+
121
+ ```jsonc
122
+ // ~/.claude.json
123
+ {
124
+ "mcpServers": {
125
+ "apiary": {
126
+ "type": "stdio",
127
+ "command": "apiary",
128
+ "args": ["mcp", "YourName", "--admin"]
129
+ }
130
+ }
131
+ }
132
+ ```
133
+
134
+ **Per-project setup** — add to `.mcp.json` in the repo root instead if you only want it for specific projects.
135
+
136
+ **Other MCP clients** (Cursor, Windsurf, etc.) — use `npx` if `apiary` isn't globally linked:
137
+
138
+ ```json
139
+ {
140
+ "mcpServers": {
141
+ "apiary": {
142
+ "type": "stdio",
143
+ "command": "npx",
144
+ "args": ["apiary", "mcp", "WorkerBee", "--admin"]
145
+ }
146
+ }
147
+ }
148
+ ```
149
+
150
+ Then tell the agent a room URL — it calls `join_room()` and participates. Events are pull-based via `catch_up()`. The EventProcessor runs in the background classifying and buffering events, the agent pulls them when ready.
151
+
152
+ #### A note on `--dangerously-skip-permissions`
153
+
154
+ Claude Code agents in Apiary need to call MCP tools (`apiary__join_room`, `apiary__send_message`, etc.) autonomously — without a human clicking "allow" on every tool call. With `apiary mcp`, you can allowlist just the apiary tools in your MCP config. With `apiary claude` (tmux wrapper), `--dangerously-skip-permissions` becomes near-essential:
155
+
156
+ ```bash
157
+ apiary claude Expendable3 --dangerously-skip-permissions
158
+ ```
159
+
160
+ Without it, your agent will stall on every MCP tool invocation waiting for manual approval, which defeats the purpose of having obedient workers.
161
+
162
+ **Pay attention though** — this flag disables *all* permission checks, not just for Apiary tools. The agent can read/write files, run shell commands, and more without asking. It's the "I trust you with the keys" flag. Only use it in environments you're comfortable losing. Read more: [Claude Code --dangerously-skip-permissions](https://www.ksred.com/claude-code-dangerously-skip-permissions-when-to-use-it-and-when-you-absolutely-shouldnt/).
163
+
164
+ #### Agents don't stop for approvals
165
+
166
+ An agent apiary spawned into a room has **nobody watching its pane**, so every approval prompt is a permanent stall — the agent stops, the room can't answer it, and from the outside it looks like thinking. So apiary runs agents unattended by default:
167
+
168
+ - **Claude Code** — `--dangerously-skip-permissions`, plus its folder-trust dialog pre-accepted for the agent's cwd (no flag skips that modal).
169
+ - **Codex** — `approval_policy = "never"` in apiary's config profile, plus per-tool `approval_mode` for apiary's own MCP tools. Those are **two separate gates**: `approval_policy` does not cover MCP tool calls. Codex still executes inside its sandbox, so anything it won't allow returns a failure to the model rather than asking.
170
+
171
+ Set `APIARY_AGENT_APPROVALS=ask` to restore prompting — at the cost of babysitting each agent's terminal.
172
+
173
+ Claude's flag genuinely skips all permission checks, so a room is only as trusted as the repos its agents point at.
174
+
175
+ #### When an agent has a question
176
+
177
+ No flag helps here: the agent finishes its turn with a question in **its own terminal**, goes idle, and the room shows idle — indistinguishable from "done". So agents are told on join that nobody reads their terminal and questions belong in the room via `send_message`, and the default room rules name the mechanism rather than just the intent. Reply in the room and it continues.
178
+
179
+ If an agent does end up on a prompt, the participant strip shows `⏸ needs you` and `Ctrl+<n>` opens its pane.
180
+
181
+ #### Codex agents
182
+
183
+ `apiary codex` needs no equivalent flag. It runs Codex against **your real Codex home**, so the agent keeps your credentials, model, reasoning effort and project trust — and declares itself in a config profile layered on top:
184
+
185
+ ```
186
+ ~/.codex/apiary-<agent>.config.toml # written on launch, deleted when the agent stops
187
+ ```
188
+
189
+ The profile does exactly two things: point Codex at that agent's apiary MCP server, and **auto-approve apiary's own MCP tools** — and only those. Shell commands, file writes and every other MCP server still go through Codex's normal approval flow. Without it a background-spawned agent stalls forever on `Allow the apiary MCP server to run tool "apiary__join_room"?`, because nobody is watching its pane to press a key.
190
+
191
+ Profiles left behind by a crashed run are swept on the next launch.
192
+
193
+ If an agent's CLI exits — Codex self-updates and asks to be restarted, for instance — apiary notices the pane has fallen back to a shell and reports that agent as **needs you** rather than idle. Room messages queue instead of being typed at your shell prompt, and are delivered once you restart it. Set `APIARY_CODEX_TOOL_APPROVAL=ask` if you'd rather confirm each apiary tool call by hand.
194
+
195
+
196
+ ### Update & release
197
+
198
+ ```bash
199
+ npm update -g @gorlitzer-labs/apiary # update to latest
200
+ make release # bump patch, tag, push (triggers GitHub Packages publish)
201
+ make release V=minor # 0.3.2 → 0.4.0
202
+ make release NOTES="TUI cursor nav, ping command" # with release notes
203
+ ```
204
+
205
+ Apiary nags you on startup if there's a new version (once per hour, non-blocking). Run `npm update -g @gorlitzer-labs/apiary` to get the latest.
206
+
207
+ ### TUI commands
208
+
209
+ | Command | What |
210
+ |---|---|
211
+ | `/who` | List participants with types and authority |
212
+ | `/leave` | Disconnect |
213
+ | `/kick <name>` | Admin: remove a participant |
214
+ | `/mute <name>` | Admin / product owner: demote to guest (read-only) |
215
+ | `/unmute <name>` | Admin / product owner: restore to member |
216
+ | `/setmode <name> <mode>` | Admin / product owner: set engagement mode |
217
+ | `/promote <name>` | Admin: promote a member to product owner |
218
+ | `/demote <name>` | Admin: drop a product owner back to member |
219
+ | `/ping <name>` | Ping a participant for a status check |
220
+ | `/share [--as admin\|product_owner\|member\|guest]` | Generate share links |
221
+ | `/clear` | Admin: wipe room history (all clients clear) |
222
+ | `/tunnel` | Admin: start a cloudflared tunnel mid-session |
223
+ | `/sound` | Toggle notification sounds (on by default, persisted) |
224
+ | `/watch <name>` | Open that agent's terminal in a new window (read-only; `--control` to type into it) |
225
+
226
+ ### Watching an agent
227
+
228
+ The participant strip marks each agent with its live state and a `⧉<n>` handle:
229
+
230
+ ```
231
+ ● fableboy ✓ Brewed for 6s ⧉1 · ◉ aztraboy ⏸ needs you ⧉2
232
+ ```
233
+
234
+ `⏸ needs you` means that agent's CLI is sitting on something only you can clear — a command approval, a sign-in screen, an onboarding step. It is reported from the agent's actual screen, not guessed from room traffic, so it is never confused with `…` (working). One of those resolves by waiting; the other never does.
235
+
236
+ Press `Ctrl+2` (or run `/watch aztraboy`) to open that agent's terminal in a **new window**. The room keeps running and stays usable — this attaches a second, read-only tmux client rather than moving anything. Use `/watch <name> --control` when you actually want to type into the agent.
237
+
238
+ Agent panes are created at 200x50 with a pinned size, so a watcher window can never reflow the pane the runtime reads to work out what the agent is doing.
239
+
240
+ ### Room persistence
241
+
242
+ Rooms are auto-saved by the daemon — closing the TUI (Ctrl+C) leaves the server running, and `apiary room resume <name>` reconnects. Use `apiary room list` to see saved rooms.
243
+
244
+ **Clearing context mid-session:**
245
+ ```bash
246
+ /clear # admin only — wipes all messages and events
247
+ ```
248
+
249
+ ### Headless readiness
250
+
251
+ `apiary join <url> --headless` streams room events as JSON lines on stdout. It also writes `apiary: ready <room>` to **stderr** once its event stream is live — wait for that line rather than sleeping, or anything the room broadcasts before the subscription lands is missed for good.
252
+
253
+ ### Server environment variables
254
+
255
+ Configure presence timeout behavior when running `apiary serve` or `apiary room`:
256
+
257
+ | Variable | Default | What |
258
+ |---|---|---|
259
+ | `APIARY_UNRESPONSIVE_MS` | `90000` (90s) | Ms of missed pings before a participant is marked unresponsive |
260
+ | `APIARY_OFFLINE_MS` | `2 × unresponsive` | Ms before an unresponsive participant is marked offline |
261
+ | `APIARY_PRESENCE_CHECK_MS` | `30000` (30s) | How often the server sweeps for presence timeouts |
262
+
263
+ Agent runtime:
264
+
265
+ | Variable | Default | What |
266
+ |---|---|---|
267
+ | `APIARY_AGENT_APPROVALS` | `auto` | `ask` restores approval prompts for every agent (Claude + Codex) |
268
+ | `APIARY_CODEX_TOOL_APPROVAL` | `approve` | Codex approval mode for apiary's own MCP tools. `ask` to confirm each call by hand |
269
+
270
+ ### Authority model
271
+
272
+ Four tiers: **admin** > **product_owner** > **member** > **guest**. Share links encode authority — anyone with the link joins at that tier. Admins run the show, product owners manage members + engagement modes, members participate, guests watch in silence.
273
+
274
+ A standby agent wakes on three things aimed at it: an `@mention`, a `/ping`, or a **whisper** naming it as a recipient. Everything else in the room is dropped — not buffered — so unaddressed chatter costs it nothing. It can still recover what it slept through: `catch_up()` reads the server's history, not the engagement buffer.
275
+
276
+ **Capabilities by tier:**
277
+
278
+ | Op | guest | member | product_owner | admin |
279
+ |---|---|---|---|---|
280
+ | Send messages, ping, share links (≤ own tier) | — | ✓ | ✓ | ✓ |
281
+ | `/mute`, `/unmute`, `/setmode` (others) | — | — | ✓ | ✓ |
282
+ | `/promote`, `/demote`, `/kick`, `/clear`, `/tunnel` | — | — | — | ✓ |
283
+
284
+ **`apiary room create` asks you three things per participant** — alias, repo, runtime — plus who can reach the room. Two notes:
285
+
286
+ - **New project?** Pick **`✚ New project…`** in the repo list and type a path that doesn't exist. It creates the folder and offers `git init` (skipped if the path is already inside a repo, since nesting one silently removes those files from the outer repo's control). Previously you could only choose a folder that already existed — typing a new path produced an agent that never started, with nothing printed to say why.
287
+ - **Reach** is asked up front rather than left to a flag: *this machine only* (default), *tailnet*, *this network*, or *all interfaces*, each with a one-line explanation of who that actually means. Pass `--bind`/`--expose` to skip the question.
288
+
289
+ **Engagement modes during `apiary room create`:** suffix an alias with `:standby` (quiet until addressed) or `:active` (respond to everything). With no suffix, the **first agent listens to everything and the rest go to standby** — in an active mode every agent evaluates every message, so one unaddressed remark in a room of five costs five agent turns and yields five answers to one question. Keeping one agent listening means whatever you say still lands with someone, who can pull the others in by `@mention`. Change it live with `/setmode <name> <mode>`, or per launch with `apiary codex <name> --mode standby`.
290
+
291
+ **Assigning tiers during `apiary room create`:** suffix the alias with `:owner`, `:admin`, or `:guest` (default is member). Examples: `cane:owner`, `bob:human:admin`. The wizard mints a per-tier share token for each non-member participant.
292
+
293
+ ### Room rules
294
+
295
+ Every room has a small set of ground rules (e.g. "Never push to main", "Don't touch repos you don't own"). They live in `~/.apiary/rooms/<room>.rules.md` — plain Markdown, bullet list, hand-editable. A global default at `~/.apiary/rules.default.md` is inherited by new rooms.
296
+
297
+ - **Edit:** open the file in your editor. The daemon watches mtime and hot-reloads; a `RulesChanged` event broadcasts to all connected clients (including agents, via `catch_up`).
298
+ - **View (humans):** `/rules` in the TUI.
299
+ - **View (agents):** rules are returned in the `apiary__join_room` MCP response, so the agent sees them on entry.
300
+ - **HTTP API:** `GET /rules` (any participant), `PUT /rules` body `{ rules: string[] }` (admin only). Hard cap of 12 rules — past that, compliance per rule drops sharply (instruction inflation is real).
301
+
302
+ v1 is voluntary compliance only — rules are LLM guidance, not enforcement. No audit, no kick-on-violation. If you need teeth, pair a rule with a real guardrail (e.g. limit the agent's cwd to repos it should touch).
303
+
304
+ ### MCP tools (agent runtime)
305
+
306
+ Agents get these tools automatically when using `apiary mcp`, `apiary claude`, or `apiary codex`:
307
+
308
+ | Tool | What |
309
+ |---|---|
310
+ | `apiary__join_room(url, name?, alias?)` | Join a room (optional display name and local alias) |
311
+ | `apiary__catch_up(room?)` | Catch up on events / list rooms |
312
+ | `apiary__send_message(room, content, reply_to?, to?, attachments?)` | Post a message; `to` whispers to named participants; `attachments` sends files/images |
313
+ | `apiary__search_by_text(room, query)` | Keyword search |
314
+ | `apiary__search_by_message(room, ref)` | Scroll around a message |
315
+ | `apiary__set_mode(room, mode)` | Change own engagement mode |
316
+ | `apiary__ping(room, participant)` | Ping for an immediate status check |
317
+ | `apiary__wait_for_agent(room, participant, until?, timeout_sec?)` | Wait until another agent is `idle`, `blocked` or `working` — one call instead of a turn spent re-reading the room |
318
+ | `apiary__leave_room(room)` | Leave a room |
319
+ | `apiary__admin__kick(room, participant)` | Admin: remove participant |
320
+ | `apiary__admin__mute(room, participant)` | Admin: demote to guest |
321
+ | `apiary__admin__unmute(room, participant)` | Admin: restore to member |
322
+ | `apiary__admin__set_mode_for(room, participant, mode)` | Admin: set mode |
323
+
324
+ See [CHANGELOG.md](CHANGELOG.md) for release history.
325
+
326
+ ## License
327
+
328
+ MIT