aibroker 0.61.1 → 0.61.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.
- package/README.md +38 -433
- package/dist/adapters/iterm/core.d.ts +34 -4
- package/dist/adapters/iterm/core.d.ts.map +1 -1
- package/dist/adapters/iterm/core.js +139 -104
- package/dist/adapters/iterm/core.js.map +1 -1
- package/dist/adapters/iterm/iterm2-api.d.ts.map +1 -1
- package/dist/adapters/iterm/iterm2-api.js +4 -2
- package/dist/adapters/iterm/iterm2-api.js.map +1 -1
- package/dist/adapters/iterm/sessions.d.ts.map +1 -1
- package/dist/adapters/iterm/sessions.js +47 -114
- package/dist/adapters/iterm/sessions.js.map +1 -1
- package/dist/adapters/pailot/gateway.d.ts.map +1 -1
- package/dist/adapters/pailot/gateway.js +6 -52
- package/dist/adapters/pailot/gateway.js.map +1 -1
- package/dist/daemon/commands.d.ts.map +1 -1
- package/dist/daemon/commands.js +4 -29
- package/dist/daemon/commands.js.map +1 -1
- package/dist/daemon/core-handlers.js +1 -1
- package/dist/daemon/core-handlers.js.map +1 -1
- package/dist/daemon/manage.d.ts +0 -18
- package/dist/daemon/manage.d.ts.map +1 -1
- package/dist/daemon/manage.js +8 -38
- package/dist/daemon/manage.js.map +1 -1
- package/dist/daemon/screenshot.d.ts.map +1 -1
- package/dist/daemon/screenshot.js +6 -42
- package/dist/daemon/screenshot.js.map +1 -1
- package/dist/daemon/session-content.d.ts +1 -1
- package/dist/daemon/session-content.d.ts.map +1 -1
- package/dist/daemon/session-content.js +10 -25
- package/dist/daemon/session-content.js.map +1 -1
- package/dist/daemon/sessions.d.ts.map +1 -1
- package/dist/daemon/sessions.js +7 -13
- package/dist/daemon/sessions.js.map +1 -1
- package/dist/daemon/setup.d.ts.map +1 -1
- package/dist/daemon/setup.js +5 -2
- package/dist/daemon/setup.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.js +7 -13
- package/dist/mcp/index.js.map +1 -1
- package/dist/transport/iterm.d.ts.map +1 -1
- package/dist/transport/iterm.js +12 -20
- package/dist/transport/iterm.js.map +1 -1
- package/hooks/manage-hook.mjs +4 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,63 +4,13 @@ Claude Code is locked inside your terminal. You can only talk to it by typing. A
|
|
|
4
4
|
|
|
5
5
|
Install AIBroker and your Claude Code sessions become reachable from anywhere. Ask Claude to check on your build while you're away from the desk. Send a screenshot request from WhatsApp. Switch between Claude sessions from your phone. It all routes through one daemon that owns the plumbing — TTS, transcription, image generation, screenshots, session management — so the adapters stay thin and the experience stays consistent.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
### Talk to Claude from Your Phone
|
|
12
|
-
|
|
13
|
-
- **WhatsApp** — Send a text or voice note. Claude gets it, processes it, replies back. Voice in → voice out.
|
|
14
|
-
- **Telegram** — Same experience, different app. Text and voice both work.
|
|
15
|
-
- **PAILot** (iOS app) — Native companion app with session switching, voice messages, typing indicators, and message history.
|
|
16
|
-
|
|
17
|
-
### Delegate Work from Todoist
|
|
18
|
-
|
|
19
|
-
File a task in Todoist — from your phone, your watch, or the web — and the AI
|
|
20
|
-
session that owns that project picks it up, does the work, and answers in the
|
|
21
|
-
comments. Reply from the comments and it goes back to the same session.
|
|
22
|
-
|
|
23
|
-
No new app, no new habit: you delegate to it the way you delegate to a
|
|
24
|
-
colleague, and because the work happens on a task you can see what it is doing,
|
|
25
|
-
what it decided, and say no before anything happens.
|
|
26
|
-
|
|
27
|
-
[What it feels like](docs/task-manager-as-interface.md) · [Setup and security model](docs/todoist.md)
|
|
28
|
-
|
|
29
|
-
### Manage Sessions Remotely
|
|
30
|
-
|
|
31
|
-
- "Show me all sessions" — see every running Claude Code session
|
|
32
|
-
- "Switch to session 2" — route your messages to a different session
|
|
33
|
-
- "Start a new session for ~/projects/api" — launch a fresh Claude session from your phone
|
|
34
|
-
- "Screenshot" — capture what Claude is showing in iTerm right now
|
|
35
|
-
- "What's the status?" — see which sessions are busy, idle, or waiting
|
|
36
|
-
|
|
37
|
-
### Voice and Media
|
|
38
|
-
|
|
39
|
-
- **Voice notes** — Send a voice note from WhatsApp or Telegram. Whisper transcribes it, Claude processes it, Kokoro speaks the reply back as a voice note.
|
|
40
|
-
- **Image generation** — "Send me an image of a sunset over mountains" — Flux generates it, delivers it to your chat.
|
|
41
|
-
- **Screenshots** — Capture any iTerm session and receive the image on your phone.
|
|
42
|
-
- **Video analysis** — Send a video, Gemini analyzes it, Claude discusses the results.
|
|
43
|
-
|
|
44
|
-
### Slash Commands from Anywhere
|
|
45
|
-
|
|
46
|
-
Type these in any channel — WhatsApp, Telegram, PAILot, or terminal:
|
|
47
|
-
|
|
48
|
-
| Command | What it does |
|
|
49
|
-
|---------|-------------|
|
|
50
|
-
| `/s` | List all sessions |
|
|
51
|
-
| `/n ~/project` | Start a new visual session |
|
|
52
|
-
| `/ss` | Screenshot the active session |
|
|
53
|
-
| `/status` | Show all session statuses |
|
|
54
|
-
| `/image a cat in space` | Generate and deliver an image |
|
|
55
|
-
| `/e 3` | End session 3 |
|
|
56
|
-
| `/aibp` | AIBP protocol status — plugins, channels, commands |
|
|
57
|
-
| `/aibp plugins` | Detailed plugin list with capabilities |
|
|
58
|
-
| `/aibp commands` | All registered commands by owner |
|
|
59
|
-
| `/aibp help` | List all `/aibp` subcommands |
|
|
7
|
+
- Talk to Claude from WhatsApp, Telegram or the PAILot app, by text or voice
|
|
8
|
+
- Delegate work from Todoist and manage sessions remotely
|
|
9
|
+
- Generate images, transcribe voice notes, screenshot a session
|
|
60
10
|
|
|
61
11
|
---
|
|
62
12
|
|
|
63
|
-
##
|
|
13
|
+
## Install
|
|
64
14
|
|
|
65
15
|
```bash
|
|
66
16
|
npm install -g aibroker
|
|
@@ -68,432 +18,89 @@ aibroker setup # service + MCP registration + Claude Code hooks + ~/.aibrok
|
|
|
68
18
|
aibroker doctor # every check green, or it says exactly what to fix
|
|
69
19
|
```
|
|
70
20
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
The hub owns the IPC socket at `/tmp/aibroker.sock` and the PAILot WebSocket gateway on port 8765.
|
|
74
|
-
|
|
75
|
-
| | macOS | Linux |
|
|
76
|
-
|---|---|---|
|
|
77
|
-
| Service | LaunchAgent `com.aibroker.daemon` (an existing plist is left alone unless `--force`) | `systemd --user` unit `aibroker.service`; run `sudo loginctl enable-linger $USER` once so it survives logout |
|
|
78
|
-
| Session host | iTerm2 (tmux optional) | tmux |
|
|
79
|
-
| Prerequisites | Node.js 22+, iTerm2, ffmpeg | Node.js 22+, tmux, ffmpeg |
|
|
80
|
-
| Guide | [docs/macos.md](docs/macos.md) | [docs/linux.md](docs/linux.md) — no macOS needed anywhere |
|
|
81
|
-
|
|
82
|
-
From a source checkout instead: `git clone https://github.com/mnott/AIBroker && cd AIBroker && npm install && npm run build && node dist/daemon/cli.js setup`.
|
|
83
|
-
|
|
84
|
-
### 4. Session backup across reboots (optional)
|
|
85
|
-
|
|
86
|
-
```bash
|
|
87
|
-
aibroker sessions install
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
Installs a LaunchAgent (`com.aibroker.sessions-snapshot`, macOS) that records your open Claude sessions (name + directory) every 5 minutes. Around a reboot:
|
|
91
|
-
|
|
92
|
-
```bash
|
|
93
|
-
aibroker sessions checkpoint # before: tells each open session to persist its state
|
|
94
|
-
# reboot
|
|
95
|
-
aibroker sessions restore # after: reopens every session in its own iTerm2 tab
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
`checkpoint` waits for each session to actually finish saving and prints a per-session result, so a session that never reacted is reported instead of silently skipped. Retry just those with `--only NAME`; raise `--timeout SECONDS` for slow ones.
|
|
99
|
-
|
|
100
|
-
`restore` relaunches a fresh named session per entry (which `go`s to pick up that project's saved state) — it does not rely on `claude --resume`.
|
|
101
|
-
|
|
102
|
-
The manifest (`~/.aibroker/session-restore.json`) is a **registry, not a mirror**: snapshots merge into it, so closing a session — or shutting everything down before a reboot — never removes anything. Entries leave only via `aibroker sessions forget NAME` or `aibroker sessions prune --older-than DAYS`, and every write keeps a `.bak`. See `aibroker sessions help` for the rest.
|
|
103
|
-
|
|
104
|
-
### 5. Dispatch work to a project's session
|
|
105
|
-
|
|
106
|
-
```bash
|
|
107
|
-
aibroker dispatch <project> --stdin --json [--no-spawn]
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
Resolves a project to its running Claude session and delivers a message, launching the session if none is running. One atomic call: a caller doing list → launch → send itself races, because a session can start or die between the check and the send.
|
|
111
|
-
|
|
112
|
-
The body comes in over **stdin** — task bodies are multi-line and carry quotes and backticks, which argv mangles. Messages arrive prefixed `[Task]`, meaning *act on it, do not reply* (unlike `[Session:NAME]`, there is no sender left to reply to).
|
|
113
|
-
|
|
114
|
-
Outcomes are results, not errors — all exit 0, so a batch keeps going:
|
|
115
|
-
|
|
116
|
-
| outcome | meaning |
|
|
117
|
-
|---|---|
|
|
118
|
-
| `delivered` | a live session accepted it |
|
|
119
|
-
| `spawned` | none was running; one was launched and accepted it |
|
|
120
|
-
| `unlaunchable` | no curated alias — run `pai project name <identifier> <shortname>` |
|
|
121
|
-
| `unreachable` | tab opened but the session never accepted input |
|
|
122
|
-
| `skipped` | no live session and `--no-spawn` was set |
|
|
123
|
-
|
|
124
|
-
Resolution uses the **curated** alias list only, never `pai project names --all`: the full set has no aliases and real ambiguity (several registry rows share a display name at different paths), so widening it dispatches work to the wrong directory silently. Bus participation is opt-in by design.
|
|
125
|
-
|
|
126
|
-
`spawned` means *confirmed submitted*, not *tab opened* — delivery is verified by watching the message leave the input box and land in the transcript, which works whether the session is idle or busy.
|
|
127
|
-
|
|
128
|
-
`--timeout SECONDS` is a **total budget for the whole dispatch**, not a per-stage cap: the readiness wait and the delivery share it, retries included. Callers that wrap this in their own kill timer should set it below theirs — then AIBroker always times out first and returns a reason, instead of being killed and surfacing as the caller's own timeout with the cause lost.
|
|
129
|
-
|
|
130
|
-
The logic lives in the daemon (`dispatch` IPC), so MCP, PAILot and adapters can route work without shelling out; the CLI is a thin, versioned wrapper for shell callers.
|
|
131
|
-
|
|
132
|
-
### 6. Ask a session whether it is still alive
|
|
133
|
-
|
|
134
|
-
```bash
|
|
135
|
-
aibroker ask <project> --stdin --timeout 60 --json
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
For callers with no session and no mailbox — a launchd poller checking whether the session it handed work to is still going. **Never spawns**: a probe that creates the thing it is probing turns a dead session into a fresh one and reports health.
|
|
139
|
-
|
|
140
|
-
| state | meaning |
|
|
141
|
-
|---|---|
|
|
142
|
-
| `replied` | it answered; `reply` holds its words |
|
|
143
|
-
| `busy` | mid-turn and still producing output. **Alive** — nothing was sent |
|
|
144
|
-
| `silent` | idle, took the question, never answered. Genuinely suspicious |
|
|
145
|
-
| `absent` | no live session for that project |
|
|
146
|
-
|
|
147
|
-
**`busy` is positive evidence of life and must not count toward a stuck threshold.** Claude Code queues typed input while mid-turn and only reads it when the turn ends, so a session busy doing exactly the work it was given cannot answer — and a short timeout would report it as silent. Since a scheduler probes precisely when a task has overrun, that false positive would fire constantly. Liveness is therefore decided *before* any question is sent, which also means a working session pays no token cost for being probed.
|
|
148
|
-
|
|
149
|
-
Every probe of an idle session does inject a message that stays in that session's context, so keep the text short and probe rarely.
|
|
150
|
-
|
|
151
|
-
### 7. File work from your phone or watch (optional)
|
|
152
|
-
|
|
153
|
-
```bash
|
|
154
|
-
tailscale funnel --bg --https=443 --set-path=/todoist http://127.0.0.1:8766/todoist
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
> **Port 443, and no port in the callback URL.** Todoist *silently* refuses any
|
|
158
|
-
> webhook URL carrying a port: the form accepts it, activation appears to do
|
|
159
|
-
> nothing, and the status stays *Not configured* forever with no error anywhere.
|
|
160
|
-
> `--https=8443` will look like it worked and never deliver a single event.
|
|
161
|
-
|
|
162
|
-
Add a task in Todoist and it reaches the session that owns it — no polling, because Todoist pushes. Set a **reminder** rather than a due date to schedule work: `reminder:fired` is a webhook event, a task merely becoming due is not.
|
|
163
|
-
|
|
164
|
-
This is an execution ingress, so it is narrow by construction: every request must carry a valid HMAC signature, only explicitly allowlisted projects can reach a session, and an empty allowlist accepts nothing rather than everything. Todoist's Inbox cannot be shared, which is what makes quick capture from a watch safe.
|
|
165
|
-
|
|
166
|
-
What it feels like to use: **[docs/task-manager-as-interface.md](docs/task-manager-as-interface.md)**.
|
|
167
|
-
Full setup, routing rules and the security model: **[docs/todoist.md](docs/todoist.md)**.
|
|
168
|
-
|
|
169
|
-
### 8. Audit what one session did to another
|
|
170
|
-
|
|
171
|
-
```bash
|
|
172
|
-
aibroker audit # recent cross-session activity
|
|
173
|
-
aibroker audit --session Youdrill # everything touching one session
|
|
174
|
-
aibroker audit --trace <id> # follow one causation chain
|
|
175
|
-
aibroker audit --bodies # full message bodies
|
|
176
|
-
aibroker audit --json # raw JSONL, for piping
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
Every daemon-mediated cross-session action — `send`, `dispatch`, `ask`, `launch`, and refusals — is appended to `~/.aibroker/audit.jsonl`, one JSON object per line, **before and independently of whatever the acting agent later reports**.
|
|
180
|
-
|
|
181
|
-
That distinction is the point. Sessions can now message each other, dispatch work, spawn new sessions and probe for liveness, and chains form that nobody designed: an observation in one project reaching a second session which relays it to a third. Without a record, the only account of any of it is each participant's own — a session that acts and does not mention it leaves no trace, and a session that ends takes its side of the story with it.
|
|
182
|
-
|
|
183
|
-
Bodies are stored in full, because a summary of a message is exactly the self-report this replaces. Refusals are stored too: "the hub declined to type this into a shell" is part of the history.
|
|
184
|
-
|
|
185
|
-
`--trace` walks a chain in both directions — what led to an event, and what it led to. Causation is inferred from the last message an actor received, which reconstructs `A→B→C` correctly in the ordinary case but is a heuristic, not proof: an agent may act for reasons of its own.
|
|
186
|
-
|
|
187
|
-
The format is deliberately plain JSONL: greppable with the tools already on the machine, appendable by any other tool that wants to contribute events, and a torn final line costs one record rather than the file. Set `AIBROKER_AUDIT_FILE` to relocate it.
|
|
188
|
-
|
|
189
|
-
### 9. Connect an adapter
|
|
190
|
-
|
|
191
|
-
```bash
|
|
192
|
-
# WhatsApp
|
|
193
|
-
npm install -g whazaa
|
|
194
|
-
whazaa setup # pair the phone (QR code), once
|
|
195
|
-
whazaa service start # run the watcher as a service (LaunchAgent on macOS, systemd user unit on Linux)
|
|
196
|
-
|
|
197
|
-
# Telegram
|
|
198
|
-
npm install -g @tekmidian/telex
|
|
199
|
-
telex setup # log in to Telegram, once
|
|
200
|
-
telex service start
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
`<bin> service start|stop|status|unit` manages the background service; see [macos.md](docs/macos.md) and [linux.md](docs/linux.md). Once connected, messages from your phone route to Claude and replies come back automatically.
|
|
21
|
+
Then connect an adapter: `npm install -g whazaa && whazaa setup` (WhatsApp) or `npm install -g @tekmidian/telex && telex setup` (Telegram). Platform guides: [macOS](docs/macos.md), [Linux](docs/linux.md). Flags, source checkout and the adapter service commands: [docs/install.md](docs/install.md).
|
|
204
22
|
|
|
205
23
|
---
|
|
206
24
|
|
|
207
|
-
##
|
|
25
|
+
## What You Can Do
|
|
208
26
|
|
|
209
|
-
|
|
210
|
-
Your Phone AIBroker Daemon Claude Code
|
|
211
|
-
────────── ─────────────── ──────────
|
|
212
|
-
WhatsApp ───► Whazaa ──┐ ┌──► Session 1 (iTerm)
|
|
213
|
-
Telegram ───► Telex ──┤ Hub (IPC + AIBP routing) ├──► Session 2 (iTerm)
|
|
214
|
-
PAILot ───► WS:8765 ──┤ TTS · STT · Screenshots ├──► Session 3 (iTerm)
|
|
215
|
-
Your App ───► Adapter ──┘ Image Gen · Session Mgmt └──► Headless (API)
|
|
216
|
-
```
|
|
27
|
+
Text and voice from WhatsApp, Telegram and PAILot; delegating from Todoist; listing, switching, launching and screenshotting sessions; voice notes, image generation, video analysis; slash commands such as `/s`, `/n`, `/ss`, `/status`, `/image` from any channel.
|
|
217
28
|
|
|
218
|
-
|
|
29
|
+
→ [docs/what-you-can-do.md](docs/what-you-can-do.md)
|
|
219
30
|
|
|
220
|
-
|
|
31
|
+
## Session Backup and Dispatch
|
|
221
32
|
|
|
222
|
-
|
|
33
|
+
`aibroker sessions` records your open sessions and restores them after a reboot. `aibroker dispatch` delivers a message to a project's session, launching it if needed; `aibroker ask` probes whether a session is still alive without ever spawning one.
|
|
223
34
|
|
|
224
|
-
|
|
225
|
-
Plugin A ──message──► #session:abc ──fan-out──► Plugin B, Plugin C, Plugin D
|
|
226
|
-
```
|
|
35
|
+
→ [docs/session-backup.md](docs/session-backup.md) · [docs/dispatch.md](docs/dispatch.md)
|
|
227
36
|
|
|
228
|
-
|
|
37
|
+
## Todoist
|
|
229
38
|
|
|
230
|
-
|
|
231
|
-
|------------|----------|-------------|
|
|
232
|
-
| `transport` | Whazaa, Telex | TEXT, VOICE, IMAGE, FILE |
|
|
233
|
-
| `terminal` | iTerm2 | TEXT, COMMAND |
|
|
234
|
-
| `mobile` | PAILot | TEXT, VOICE, IMAGE, TYPING, STATUS |
|
|
235
|
-
| `mcp` | Claude Code sessions | TEXT, VOICE, IMAGE, COMMAND |
|
|
236
|
-
| `bridge` | Remote hubs | TEXT, VOICE, IMAGE, COMMAND, FILE |
|
|
39
|
+
File a task from your phone or watch and the session that owns that project picks it up. Todoist pushes, so there is no polling; the ingress is narrow by construction (HMAC, allowlisted projects).
|
|
237
40
|
|
|
238
|
-
|
|
41
|
+
→ [docs/todoist.md](docs/todoist.md) · [docs/task-manager-as-interface.md](docs/task-manager-as-interface.md)
|
|
239
42
|
|
|
240
|
-
|
|
43
|
+
## Audit
|
|
241
44
|
|
|
242
|
-
|
|
45
|
+
Every daemon-mediated cross-session action, refusals included, is appended to `~/.aibroker/audit.jsonl` before and independently of what the acting agent reports. `aibroker audit` reads it.
|
|
243
46
|
|
|
244
|
-
|
|
245
|
-
/aibp → combined overview (sessions, plugins, channels, peers)
|
|
246
|
-
/aibp plugins → registered plugins with type, status, capabilities
|
|
247
|
-
/aibp channels → active channels with members and activity
|
|
248
|
-
/aibp commands → all commands grouped by owning plugin
|
|
249
|
-
/aibp peers → mesh network peers
|
|
250
|
-
```
|
|
47
|
+
→ [docs/audit.md](docs/audit.md)
|
|
251
48
|
|
|
252
|
-
|
|
49
|
+
## Architecture and AIBP Protocol
|
|
253
50
|
|
|
254
|
-
|
|
51
|
+
The hub is the runtime; adapters are thin transport plugins. Internally every message flows through AIBP, an IRC-inspired routing layer with explicit source and destination addresses, typed channels and plugin registration. `/aibp` inspects the live state.
|
|
255
52
|
|
|
256
|
-
|
|
53
|
+
→ [docs/architecture.md](docs/architecture.md) · [docs/protocol.md](docs/protocol.md)
|
|
257
54
|
|
|
258
55
|
## MCP Tools
|
|
259
56
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
### Message Routing
|
|
57
|
+
One unified MCP server exposes 42 tools (`whatsapp_*`, `telegram_*`, `pailot_*`, `aibroker_*`). Message prefixes such as `[Whazaa:voice]` tell Claude which channel to reply through.
|
|
263
58
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
| Prefix | Source | Claude replies with |
|
|
267
|
-
|--------|--------|-------------------|
|
|
268
|
-
| `[Whazaa]` | WhatsApp text | `whatsapp_send` |
|
|
269
|
-
| `[Whazaa:voice]` | WhatsApp voice note | `whatsapp_tts` |
|
|
270
|
-
| `[Telex]` | Telegram text | `telegram_send` |
|
|
271
|
-
| `[Telex:voice]` | Telegram voice note | `telegram_tts` |
|
|
272
|
-
| `[PAILot]` | PAILot app text | `pailot_send` |
|
|
273
|
-
| `[PAILot:voice]` | PAILot app voice | `pailot_tts` |
|
|
274
|
-
| _(no prefix)_ | Terminal keyboard | Terminal only |
|
|
275
|
-
|
|
276
|
-
### Tool Categories
|
|
277
|
-
|
|
278
|
-
| Category | Tools | What they do |
|
|
279
|
-
|----------|-------|-------------|
|
|
280
|
-
| `whatsapp_*` | send, tts, contacts, chats, history, login, status | WhatsApp messaging and management |
|
|
281
|
-
| `telegram_*` | send, tts, contacts, chats, history, login, status | Telegram messaging and management |
|
|
282
|
-
| `pailot_*` | send, tts, receive | PAILot app communication |
|
|
283
|
-
| `aibroker_*` | status, sessions, switch, discover, speak, dictate, generate_image, ... | Hub-level operations |
|
|
284
|
-
|
|
285
|
-
For the complete reference, see [docs/mcp-tools.md](docs/mcp-tools.md).
|
|
286
|
-
|
|
287
|
-
---
|
|
59
|
+
→ [docs/mcp-tools.md](docs/mcp-tools.md)
|
|
288
60
|
|
|
289
61
|
## Bring Your Own Messenger
|
|
290
62
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
```bash
|
|
294
|
-
aibroker create-adapter my-signal
|
|
295
|
-
cd my-signal
|
|
296
|
-
npm install
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
Full guide: [docs/adapters.md](docs/adapters.md)
|
|
63
|
+
Adapters are standalone npm packages. `aibroker create-adapter my-signal` scaffolds the IPC wiring, MCP registration and hub integration; you implement how to connect and how to send.
|
|
300
64
|
|
|
301
|
-
|
|
65
|
+
→ [docs/adapters.md](docs/adapters.md)
|
|
302
66
|
|
|
303
67
|
## Media Pipelines
|
|
304
68
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
| Pipeline | Technology | What happens |
|
|
308
|
-
|----------|-----------|-------------|
|
|
309
|
-
| **Text-to-Speech** | Kokoro (local) | Text → WAV → OGG Opus → delivered as voice note |
|
|
310
|
-
| **Speech-to-Text** | Whisper (local) | Voice note → transcription → delivered as text to Claude |
|
|
311
|
-
| **Image Generation** | Pluggable (see below) | Prompt → image → delivered to chat |
|
|
312
|
-
| **Image Analysis** | Claude Vision | Image → description → text response (no extra API cost on Max plan) |
|
|
313
|
-
| **Video Analysis** | Gemini 2.0 Flash | Video → analysis → text response (free tier: 15 RPM) |
|
|
314
|
-
| **Screenshots** | iTerm2 AppleScript | Capture terminal → PNG → delivered to chat |
|
|
315
|
-
|
|
316
|
-
### Image Generation — Works Out of the Box
|
|
317
|
-
|
|
318
|
-
Image generation uses [Pollinations.ai](https://pollinations.ai) by default — free, unlimited, no API key, no signup. Just ask Claude to generate an image and it works.
|
|
319
|
-
|
|
320
|
-
Want faster results? Upgrade to a paid provider by setting a single environment variable in `~/.aibroker/env`:
|
|
321
|
-
|
|
322
|
-
| Provider | Setup | Speed | Cost |
|
|
323
|
-
|----------|-------|-------|------|
|
|
324
|
-
| **Pollinations** _(default)_ | Nothing — works immediately | ~20s | Free |
|
|
325
|
-
| **Replicate** | `REPLICATE_API_TOKEN=r8_...` | 2-4s | ~$0.003/image |
|
|
326
|
-
| **Cloudflare Workers AI** | `CLOUDFLARE_AI_TOKEN=...` + `CLOUDFLARE_ACCOUNT_ID=...` | 3-5s | Free (~100/day) |
|
|
327
|
-
| **Hugging Face** | `HF_API_TOKEN=hf_...` | 5-15s | Free (rate-limited) |
|
|
328
|
-
|
|
329
|
-
AIBroker auto-detects which token is set and uses that provider. No config file needed.
|
|
330
|
-
|
|
331
|
-
**Pin a specific provider** with `~/.aibroker/image-gen.json`:
|
|
332
|
-
|
|
333
|
-
```json
|
|
334
|
-
{
|
|
335
|
-
"provider": "replicate"
|
|
336
|
-
}
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
**Bring your own provider** — point to any Node.js module that implements the `ImageProvider` interface:
|
|
340
|
-
|
|
341
|
-
```json
|
|
342
|
-
{
|
|
343
|
-
"provider": "custom",
|
|
344
|
-
"modulePath": "/path/to/my-provider.js",
|
|
345
|
-
"options": { "apiKey": "...", "endpoint": "https://my-api.com" }
|
|
346
|
-
}
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
Your module exports one function:
|
|
350
|
-
|
|
351
|
-
```typescript
|
|
352
|
-
import type { ImageProvider, ImageProviderConfig } from "aibroker";
|
|
353
|
-
|
|
354
|
-
export function createProvider(config: ImageProviderConfig): ImageProvider {
|
|
355
|
-
return {
|
|
356
|
-
name: "my-provider",
|
|
357
|
-
async generate(opts) {
|
|
358
|
-
const res = await fetch(config.options.endpoint, { /* ... */ });
|
|
359
|
-
return {
|
|
360
|
-
images: [Buffer.from(await res.arrayBuffer())],
|
|
361
|
-
model: "my-model",
|
|
362
|
-
durationMs: 0,
|
|
363
|
-
};
|
|
364
|
-
},
|
|
365
|
-
};
|
|
366
|
-
}
|
|
367
|
-
```
|
|
368
|
-
|
|
369
|
-
All built-in providers use FLUX.1 Schnell by default. Override with `"model": "your-model-id"` in the config.
|
|
370
|
-
|
|
371
|
-
### Iterative Refinement
|
|
69
|
+
TTS (Kokoro), STT (Whisper), image generation (Pollinations by default, Replicate, Cloudflare, Hugging Face or your own provider), image and video analysis, screenshots. Image generation is conversational and refines on follow-ups.
|
|
372
70
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
```
|
|
376
|
-
You: "Send me an image of a fish sitting on a chair"
|
|
377
|
-
Claude: [image]
|
|
378
|
-
You: "Put a tie on it"
|
|
379
|
-
Claude: [refined image — fish on chair, now wearing a tie]
|
|
380
|
-
You: "Make it watercolor style"
|
|
381
|
-
Claude: [refined image — watercolor fish with tie on chair]
|
|
382
|
-
```
|
|
383
|
-
|
|
384
|
-
AIBroker detects refinement intent from modification verbs ("put", "add", "make"), image references ("it", "the image"), style keywords ("watercolor", "cartoon"), and prepositional modifiers ("with a hat", "without the chair"). Messages that don't reference the image pass through to Claude normally — no manual "stop" needed.
|
|
385
|
-
|
|
386
|
-
Image context is scoped per source, recipient, and session, so multiple users or devices never interfere. Context expires after 30 minutes of inactivity. Say "new image" or "start over" to reset explicitly.
|
|
387
|
-
|
|
388
|
-
---
|
|
71
|
+
→ [docs/media.md](docs/media.md)
|
|
389
72
|
|
|
390
73
|
## PAILot Companion App
|
|
391
74
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
- **Session management** — switch between Claude sessions, start new ones, end old ones
|
|
395
|
-
- **Voice messages** — record and send, receive voice replies with chain playback
|
|
396
|
-
- **Typing indicators** — see when Claude is processing
|
|
397
|
-
- **Message history** — persistent chat with text and voice
|
|
398
|
-
- **Offline queuing** — messages buffer on the server when you're disconnected, drain on reconnect
|
|
399
|
-
- **Session isolation** — the gateway tracks which session each client is viewing and only delivers matching messages, preventing cross-session content bleed
|
|
400
|
-
|
|
401
|
-
PAILot connects to `ws://your-mac:8765`. See [docs/pailot.md](docs/pailot.md).
|
|
75
|
+
A native iOS app that connects to AIBroker over WebSocket: session management, voice messages, typing indicators, message history, offline queuing and session isolation.
|
|
402
76
|
|
|
403
|
-
|
|
77
|
+
→ [docs/pailot.md](docs/pailot.md)
|
|
404
78
|
|
|
405
79
|
## Pair Programming, for Agents
|
|
406
80
|
|
|
407
|
-
Two Claude sessions
|
|
408
|
-
|
|
409
|
-
```
|
|
410
|
-
you ──► manager session ──┬──► worker A (owns Sources/, drives the screen)
|
|
411
|
-
(asleep) └──► worker B (owns tools/, its own git worktree)
|
|
412
|
-
```
|
|
413
|
-
|
|
414
|
-
The manager is an ordinary Claude session with the `manage` CLI. It does four things the workers cannot do for themselves.
|
|
415
|
-
|
|
416
|
-
**It holds the objective.** `manage <session> set "<objective>"` stores a standing goal; the manager re-types it into the pane whenever the session stops. A session that finishes a task and would otherwise idle gets pointed at the next one. `manage <session> add` appends a rule to every future arming, so a correction made once survives every restart.
|
|
417
|
-
|
|
418
|
-
**It refuses to let a session stand down.** Workers ask to be released when they judge themselves done. The manager declines and re-arms — the objective says who ends it, and it is not the worker.
|
|
419
|
-
|
|
420
|
-
**It watches the context wall.** At 82% it asks for a handover into a named file; the session writes what a compaction would destroy and carries on working. Sessions routinely reached 99% and compacted with the record already on disk.
|
|
421
|
-
|
|
422
|
-
**It arbitrates the split.** Each worker owns a set of directories and a separate git worktree, and anything across the line is asked for by name. This is not tidiness: two sessions in one tree destroyed each other's uncommitted work twice in one night, once through a directory-wide `git add` and once through `git checkout --`.
|
|
81
|
+
Two Claude sessions work the same repository overnight while a manager session keeps both pointed at the work: it holds the objective, refuses to let a session stand down, watches the context wall and arbitrates the split.
|
|
423
82
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
```bash
|
|
427
|
-
aibroker manage worker-a "objective, in one line" # store it
|
|
428
|
-
aibroker manage worker-a hands on for 8 hours # grant the screen, expires by itself
|
|
429
|
-
aibroker manage worker-a now # arm it immediately
|
|
430
|
-
aibroker manage worker-a handover Notes/handover.md # where it writes before compacting
|
|
431
|
-
aibroker manage worker-a status # what it is doing, and what the manager has done
|
|
432
|
-
```
|
|
433
|
-
|
|
434
|
-
What makes this work is not autonomy but **refusal**. The instructive failures were all instruments reporting success while measuring nothing: a guard that exempted the case it existed to stop, a mutation test whose mutation never applied, a screenshot of the previous build, a message delivered to the wrong session, a session timestamping eight hours of work from a clock it carried in context rather than one it read. Every one of them looked like progress. The manager's job is to be a second reader who asks what was actually measured.
|
|
435
|
-
|
|
436
|
-
See [docs/managed-sessions.md](docs/managed-sessions.md) and [docs/session-watchdog.md](docs/session-watchdog.md).
|
|
437
|
-
|
|
438
|
-
---
|
|
83
|
+
→ [docs/pair-programming.md](docs/pair-programming.md) · [docs/managed-sessions.md](docs/managed-sessions.md) · [docs/session-watchdog.md](docs/session-watchdog.md)
|
|
439
84
|
|
|
440
85
|
## Mesh Networking
|
|
441
86
|
|
|
442
|
-
Two AIBroker instances on different machines
|
|
87
|
+
Two AIBroker instances on different machines exchange messages through AIBP bridge plugins; `hub:machine-b/session:abc` routes through the bridge to the remote hub.
|
|
443
88
|
|
|
444
|
-
|
|
445
|
-
Machine A Machine B
|
|
446
|
-
───────── ─────────
|
|
447
|
-
PAILot ──► Hub A ──bridge──► Hub B ──► Claude Session
|
|
448
|
-
```
|
|
449
|
-
|
|
450
|
-
Addressing is explicit: `hub:machine-b/session:abc` routes through the bridge to the remote hub. See [docs/mesh.md](docs/mesh.md).
|
|
451
|
-
|
|
452
|
-
---
|
|
89
|
+
→ [docs/mesh.md](docs/mesh.md)
|
|
453
90
|
|
|
454
91
|
## Documentation
|
|
455
92
|
|
|
456
|
-
|
|
457
|
-
|----------|---------------|
|
|
458
|
-
| [architecture.md](docs/architecture.md) | System design, component interactions, data flow |
|
|
459
|
-
| [protocol.md](docs/protocol.md) | AIBP protocol specification |
|
|
460
|
-
| [plugins.md](docs/plugins.md) | Plugin types, registration, capabilities |
|
|
461
|
-
| [routing.md](docs/routing.md) | Message routing logic and channel system |
|
|
462
|
-
| [macos.md](docs/macos.md) | macOS: LaunchAgent, iTerm2 + tmux, permissions, troubleshooting |
|
|
463
|
-
| [linux.md](docs/linux.md) | Linux: install to daily use with tmux and systemd, PAI (SQLite or Postgres in Docker), messengers, Tailscale, testing, what stays macOS-only |
|
|
464
|
-
| [sessions.md](docs/sessions.md) | Session management and lifecycle |
|
|
465
|
-
| [commands.md](docs/commands.md) | Slash command reference |
|
|
466
|
-
| [agentish.md](docs/agentish.md) | AG2: the wire format sessions use to talk to each other |
|
|
467
|
-
| [a2a-agentish-extension.md](docs/a2a-agentish-extension.md) | AG2 declared as an A2A protocol extension (definition + helpers, no transport) |
|
|
468
|
-
| [a2a.md](docs/a2a.md) | A2A v0.3.0 transport: expose sessions as skills for outside agents to task, and task outside agents from a session |
|
|
469
|
-
| [mcp-tools.md](docs/mcp-tools.md) | All 42 MCP tools with parameters |
|
|
470
|
-
| [adapters.md](docs/adapters.md) | Adapter development guide |
|
|
471
|
-
| [pailot.md](docs/pailot.md) | PAILot iOS app integration |
|
|
472
|
-
| [task-manager-as-interface.md](docs/task-manager-as-interface.md) | Todoist as the front door to AI: what it feels like, what it will not do |
|
|
473
|
-
| [todoist.md](docs/todoist.md) | Todoist inbound channel: webhook setup, routing, security model, the comment mirror |
|
|
474
|
-
| [channels.md](docs/channels.md) | The model every inbound path shares — read first for anything inbound |
|
|
475
|
-
| [inbound.md](docs/inbound.md) | Generic `POST /hook/<route>` endpoint, and subscribing a session to a repository's issues |
|
|
476
|
-
| [outbound.md](docs/outbound.md) | Acting in external systems through a platform's own actions |
|
|
477
|
-
| [mailbox.md](docs/mailbox.md) | Durable per-session queue and confirmed delivery |
|
|
478
|
-
| [session-watchdog.md](docs/session-watchdog.md) | Keeping a long autonomous session running: one goal at a time, context rollover, and the failures that shaped it |
|
|
479
|
-
| [audit.md](docs/audit.md) | What is recorded, and how to read it |
|
|
480
|
-
| [mesh.md](docs/mesh.md) | Multi-machine mesh networking |
|
|
481
|
-
| [ipc.md](docs/ipc.md) | IPC protocol and message format |
|
|
482
|
-
| [tts-stt.md](docs/tts-stt.md) | Voice pipeline details |
|
|
483
|
-
| [use-cases.md](docs/use-cases.md) | End-to-end message flow diagrams |
|
|
484
|
-
| [protocol-landscape.md](docs/protocol-landscape.md) | How AIBP relates to A2A, MCP, and other standards |
|
|
485
|
-
| [configuration.md](docs/configuration.md) | Configuration reference |
|
|
486
|
-
| [development.md](docs/development.md) | Development setup and testing |
|
|
93
|
+
The full page index, including configuration, IPC, voice pipeline, use cases and development.
|
|
487
94
|
|
|
488
|
-
|
|
95
|
+
→ [docs/README.md](docs/README.md)
|
|
489
96
|
|
|
490
|
-
|
|
97
|
+
---
|
|
491
98
|
|
|
492
|
-
|
|
99
|
+
## Credits
|
|
493
100
|
|
|
494
|
-
|
|
101
|
+
AIBroker never imports `@whiskeysockets/baileys`, `telegram`/`gramjs`, `better-sqlite3`, `qrcode`, or any transport-specific SDK. Platform-specific dependencies belong in the adapter packages ([docs/development.md](docs/development.md)).
|
|
495
102
|
|
|
496
|
-
|
|
103
|
+
Companion projects:
|
|
497
104
|
|
|
498
105
|
| Package | What it does | Repo |
|
|
499
106
|
|---------|-------------|------|
|
|
@@ -503,8 +110,6 @@ AIBroker never imports `@whiskeysockets/baileys`, `telegram`/`gramjs`, `better-s
|
|
|
503
110
|
| **[Coogle](https://github.com/mnott/Coogle)** | Google Workspace MCP — Gmail, Calendar, Drive multiplexing | [github.com/mnott/Coogle](https://github.com/mnott/Coogle) |
|
|
504
111
|
| **[DEVONthink MCP](https://github.com/mnott/devonthink-mcp)** | DEVONthink integration — document search and archival | [github.com/mnott/devonthink-mcp](https://github.com/mnott/devonthink-mcp) |
|
|
505
112
|
|
|
506
|
-
---
|
|
507
|
-
|
|
508
113
|
## License
|
|
509
114
|
|
|
510
115
|
MIT — Matthias Nott
|
|
@@ -4,7 +4,31 @@
|
|
|
4
4
|
* Foundation of all iTerm2 communication. Wraps `osascript` and `spawnSync`
|
|
5
5
|
* with zero transport-specific imports.
|
|
6
6
|
*/
|
|
7
|
+
/**
|
|
8
|
+
* Environment for any child that can touch AppKit. iTerm exports
|
|
9
|
+
* __CFBundleIdentifier into its shells; a child that inherits it registers with
|
|
10
|
+
* LaunchServices AS iTerm2 (an "impostor") for as long as it runs.
|
|
11
|
+
*/
|
|
12
|
+
export declare function cleanChildEnv(env?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
7
13
|
export declare function runAppleScript(script: string, timeoutMs?: number): string | null;
|
|
14
|
+
export declare const REAL_ITERM_SUFFIX = "/iTerm.app/Contents/MacOS/iTerm2";
|
|
15
|
+
/**
|
|
16
|
+
* Parser half of itermPid(), split out for testing. Input is `ps -Ao pid=,comm=`;
|
|
17
|
+
* only a process whose executable is iTerm's own is accepted, so a bundle-id
|
|
18
|
+
* impostor (osascript/helper that inherited __CFBundleIdentifier) is never picked.
|
|
19
|
+
*/
|
|
20
|
+
export declare function parseItermPid(psOutput: string): number | null;
|
|
21
|
+
/** Pid of the real iTerm (cached, re-resolved once that pid is gone); null when it is not running. */
|
|
22
|
+
export declare function itermPid(): number | null;
|
|
23
|
+
/** The JXA program run for a body: `app` is bound to the real iTerm process, the body returns a string. */
|
|
24
|
+
export declare function buildItermJxa(pid: number, body: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Run JXA against iTerm, addressed by PROCESS ID — never by name, bundle id or
|
|
27
|
+
* path, all of which LaunchServices resolves through the bundle-id registry
|
|
28
|
+
* that an impostor process poisons (-600 / -1708). The body sees `app` and
|
|
29
|
+
* must `return` a string. Same failure value as runAppleScript: null.
|
|
30
|
+
*/
|
|
31
|
+
export declare function runItermJxa(body: string, timeoutMs?: number): string | null;
|
|
8
32
|
/**
|
|
9
33
|
* Plain-object indirection so tests can replace the osascript call without
|
|
10
34
|
* mocking node:child_process — a builtin's named export is a fixed snapshot
|
|
@@ -13,9 +37,15 @@ export declare function runAppleScript(script: string, timeoutMs?: number): stri
|
|
|
13
37
|
*/
|
|
14
38
|
export declare const _internal: {
|
|
15
39
|
runAppleScript: typeof runAppleScript;
|
|
40
|
+
runItermJxa: typeof runItermJxa;
|
|
16
41
|
};
|
|
17
42
|
export declare function stripItermPrefix(id: string | undefined): string | undefined;
|
|
18
|
-
|
|
43
|
+
/**
|
|
44
|
+
* JXA body that finds the session with this id and runs `body` on it.
|
|
45
|
+
* `body` sees `app`, `aWindow`, `aTab`, `aSession` and must `return` a string;
|
|
46
|
+
* `fallback` is a JS expression returned when no session matches.
|
|
47
|
+
*/
|
|
48
|
+
export declare function withSessionJxa(sessionId: string, body: string, fallback?: string): string;
|
|
19
49
|
export declare function sendKeystrokeToSession(sessionId: string, asciiCode: number): boolean;
|
|
20
50
|
export declare function sendEscapeSequenceToSession(sessionId: string, dirChar: string): boolean;
|
|
21
51
|
export declare function typeIntoSession(sessionId: string, text: string): boolean;
|
|
@@ -82,9 +112,9 @@ export declare function parseLsappinfoImpostors(text: string): ItermBundleIdImpo
|
|
|
82
112
|
/**
|
|
83
113
|
* Processes registered with LaunchServices under iTerm2's bundle id but NOT
|
|
84
114
|
* running iTerm's own executable — e.g. an osascript/helper child that
|
|
85
|
-
* inherited iTerm's __CFBundleIdentifier env var. While registered,
|
|
86
|
-
*
|
|
87
|
-
* with -600/-1708
|
|
115
|
+
* inherited iTerm's __CFBundleIdentifier env var. While registered, anything
|
|
116
|
+
* addressing iTerm by name or bundle id is routed to the impostor, which answers
|
|
117
|
+
* with -600/-1708 (iTerm itself is addressed by pid, so it is immune). Diagnostic only: never kills
|
|
88
118
|
* anything, never throws — on any error this is "found nothing" to a caller
|
|
89
119
|
* that already treats [] as the safe default.
|
|
90
120
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../../src/adapters/iterm/core.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../../src/adapters/iterm/core.ts"],"names":[],"mappings":"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"}
|