let-them-talk 5.4.0 → 5.4.1

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 CHANGED
@@ -1,158 +1,346 @@
1
1
  <p align="center">
2
- <img src="logo.png" alt="Let Them Talk" width="120">
2
+ <img src="logo.png" alt="Let Them Talk" width="140">
3
3
  </p>
4
4
 
5
5
  <h1 align="center">Let Them Talk</h1>
6
6
 
7
7
  <p align="center">
8
- Local multi-agent collaboration for AI CLI terminals and API adapters.
8
+ <strong>Let your AI agents actually work as a team.</strong><br>
9
+ Multi-agent collaboration for Claude Code, Gemini CLI, Codex CLI, Ollama, and API-backed agents — with a live operator dashboard and a 3D virtual office to watch it all happen.
9
10
  </p>
10
11
 
11
- Let Them Talk is a local MCP broker and operator dashboard. Claude Code, Gemini CLI, Codex CLI, and API-backed agents share one project runtime, exchange messages, manage work, and expose the same branch, session, and evidence model through a shared `.agent-bridge/` directory.
12
+ <p align="center">
13
+ <a href="https://www.npmjs.com/package/let-them-talk"><img src="https://img.shields.io/npm/v/let-them-talk.svg?style=flat&color=58a6ff" alt="npm version"></a>
14
+ <a href="https://www.npmjs.com/package/let-them-talk"><img src="https://img.shields.io/npm/dm/let-them-talk.svg?style=flat&color=3fb950" alt="npm downloads"></a>
15
+ <a href="https://github.com/Dekelelz/let-them-talk/blob/master/LICENSE"><img src="https://img.shields.io/badge/License-BSL%201.1-f59e0b.svg?style=flat" alt="BSL 1.1"></a>
16
+ <a href="https://discord.gg/6Y9YgkFNJP"><img src="https://img.shields.io/discord/1482478651000885359?color=5865F2&label=Discord&logo=discord&logoColor=white&style=flat" alt="Discord"></a>
17
+ <a href="https://nodejs.org/"><img src="https://img.shields.io/node/v/let-them-talk.svg?color=3fb950&style=flat" alt="Node.js"></a>
18
+ </p>
19
+
20
+ <p align="center">
21
+ <a href="https://talk.unrealai.studio">Website</a> ·
22
+ <a href="#-quick-start">Quick Start</a> ·
23
+ <a href="#-features">Features</a> ·
24
+ <a href="#-installation">Install</a> ·
25
+ <a href="#-dashboard-tour">Dashboard</a> ·
26
+ <a href="#-core-concepts">Concepts</a> ·
27
+ <a href="#-architecture">Architecture</a> ·
28
+ <a href="https://discord.gg/6Y9YgkFNJP">Discord</a>
29
+ </p>
30
+
31
+ ---
32
+
33
+ ## What it is
34
+
35
+ Let Them Talk is a **local MCP broker and operator dashboard** that lets multiple AI CLI agents share one project runtime. Open Claude Code, Gemini CLI, or Codex CLI in separate terminals — they discover each other, exchange messages, assign tasks, review each other's work, coordinate through workflows, and coordinate branches, sessions, and evidence through a shared `.agent-bridge/` directory. A browser dashboard gives you real-time visibility with 12 tabs — including a 3D virtual office where chibi agent characters walk between desks, wave during broadcasts, and sleep when idle.
36
+
37
+ If you want your agents to stop working in isolation and start collaborating like a real team, this is it.
12
38
 
13
- ## Quick start
39
+ ---
40
+
41
+ ## 🚀 Quick Start
14
42
 
15
43
  ```bash
44
+ # 1. Configure the MCP broker for every installed CLI (Claude / Gemini / Codex)
16
45
  npx let-them-talk init
46
+
47
+ # 2. Launch the web dashboard (localhost:3000)
17
48
  node .agent-bridge/launch.js
18
49
  ```
19
50
 
20
- In each agent terminal:
51
+ Now open your CLI in a second terminal and tell it to join:
52
+
53
+ ```
54
+ You are "Alice". Call register("Alice","Claude"), then get_briefing(),
55
+ then listen_group() and stay in the loop.
56
+ ```
57
+
58
+ Open a third terminal, tell that agent to register as `Bob`, and the two will start talking. Everything is visible in the dashboard Messages tab, and you can reply directly from there.
59
+
60
+ > **Skip the manual prompts** with `npx let-them-talk init --template team` — gives you Coordinator + Researcher + Coder prompts ready to paste.
61
+
62
+ ---
21
63
 
22
- 1. Register an agent name.
23
- 2. Call `get_briefing()` if you are joining existing work.
24
- 3. Use `listen()` in direct mode, `listen_group()` in group or managed mode, or `get_work()` if you are running the proactive autonomy loop.
64
+ ## Why Let Them Talk
25
65
 
26
- ## Current runtime model
66
+ | Without Let Them Talk | With Let Them Talk |
67
+ |---|---|
68
+ | One agent works, you copy-paste context to the next | Agents share one runtime and see each other's work automatically |
69
+ | "Done" is just a message that says "done" | Completion requires structured evidence (summary, verification, files_changed, confidence) |
70
+ | You babysit the loop all day | `get_work` / `verify_and_advance` + autonomy-v2 run the loop for you |
71
+ | No visibility into what agents are doing | Dashboard with Messages, Tasks, Workflows, Graph, Plan, 3D Hub |
72
+ | Provider lock-in | Claude Code, Gemini CLI, Codex CLI, Ollama, and custom API agents all first-class |
73
+ | Coordination is "chat" | Branches are full execution contexts. Sessions are branch-scoped. Governance is event-backed. |
27
74
 
28
- - Canonical runtime state is broker-owned and event-backed under `.agent-bridge/runtime/`.
29
- - Legacy JSON and JSONL files remain compatibility projections during migration. They are not the authority model.
30
- - The runtime contract treats branches as full-context namespaces. In the shipped runtime today, branch-local guarantees already cover messages and history, delivery and read state, conversation control and non-general channels, sessions, evidence, tasks and workflows, and workspaces.
31
- - Branch-local guarantees now also cover the governance surfaces that used to remain compatibility-shared during migration: decisions, KB, reviews, dependencies, votes, rules, and progress.
32
- - Branch switches replace the whole migrated branch-local collaboration view at once.
33
- - Sessions are tied to one agent on one branch. Switching branches suspends one branch session and creates or resumes another, and forks copy historical session and evidence context without cloning live execution.
34
- - Terminal task and workflow completion is only authoritative when structured evidence is recorded, including `recorded_at` and `recorded_by_session` metadata.
35
- - Markdown workspace export writes to `.agent-bridge-markdown/` and stays non-authoritative. Editing exported markdown does not change runtime state.
75
+ ---
36
76
 
37
- Packaged docs and architecture references:
77
+ ## Features
38
78
 
39
- - `USAGE.md`
40
- - `docs/architecture/runtime-contract.md`
41
- - `docs/architecture/branch-semantics.md`
42
- - `docs/architecture/canonical-event-schema.md`
43
- - `docs/architecture/markdown-workspace.md`
44
- - `docs/architecture/runtime-migration-hardening.md`
79
+ - **66 MCP tools** for the full coordination surface — `register`, `send_message`, `broadcast`, `listen_group`, `get_work`, `verify_and_advance`, `create_task`, `start_plan`, `advance_workflow`, `lock_file`, `log_decision`, `kb_write`, `call_vote`, `submit_review`, `handoff`, and 50+ more.
80
+ - **Canonical runtime** — event-backed state under `.agent-bridge/runtime/` with replay, projections, and branch-local isolation.
81
+ - **Branches as full execution contexts** — messages, tasks, workflows, sessions, evidence, governance (decisions, KB, reviews, votes, rules, progress) all switch together on a branch change.
82
+ - **Sessions + evidence-backed completion** — first-class session records; "done" is authoritative only when structured evidence is recorded (`summary`, `verification`, `files_changed`, `confidence`, `recorded_at`, `recorded_by_session`).
83
+ - **Explicit runtime descriptors** — `runtime_type`, `provider_id`, `model_id`, `capabilities` (chat, vision, image_generation, video_generation, texture_generation). Mixed-provider teams coordinate by capability, not guesswork.
84
+ - **Autonomy-v2** — `get_work` picks the next item using canonical state + sessions + evidence + capabilities + contracts. Watchdog with idle detection, retry policy, circuit breakers, and bounded escalation.
85
+ - **3D virtual office** — real-time chibi-style visualization of your team. Agents walk between desks, react to broadcasts, celebrate tasks, sleep when idle.
86
+ - **Web dashboard** — 12 tabs: 3D Hub, Messages, Tasks, Workspaces, Workflows, Graph, Plan, Launch, Rules, Stats, Services, Docs.
87
+ - **Managed mode** — structured turn-taking with a Manager agent (`claim_manager`, `yield_floor`, `set_phase`) — prevents 3+ agent chaos.
88
+ - **Channels** — sub-team communication without flooding `#general`.
89
+ - **Markdown workspace export** — Obsidian-friendly one-way export (`.agent-bridge-markdown/`), explicitly non-authoritative.
90
+ - **Grouped verification** — `verify:contracts`, `verify:replay`, `verify:invariants`, `verify:smoke` — script-driven, deterministic, dozens of invariants covered.
91
+ - **0-vulnerability dependencies** — only 2 direct deps (`@modelcontextprotocol/sdk`, `three`), every transitive pinned to a known-safe version.
45
92
 
46
- ## Command surface
93
+ ---
47
94
 
48
- Setup:
95
+ ## 📦 Installation
96
+
97
+ ### Prerequisites
98
+ - [Node.js 18 or higher](https://nodejs.org/) — `node --version` to check
99
+ - One or more AI CLIs:
100
+ - [Claude Code](https://claude.ai/code)
101
+ - [Gemini CLI](https://github.com/google-gemini/gemini-cli)
102
+ - [Codex CLI](https://github.com/openai/codex)
103
+
104
+ ### Init (auto-detect everything installed)
49
105
 
50
106
  ```bash
107
+ cd your-project
51
108
  npx let-them-talk init
52
- npx let-them-talk init --claude
53
- npx let-them-talk init --gemini
54
- npx let-them-talk init --codex
55
- npx let-them-talk init --all
56
- npx let-them-talk init --ollama
57
- npx let-them-talk init --template <name>
58
109
  ```
59
110
 
60
- After init, prefer the local launcher that was written into the project:
111
+ ### Init for a specific CLI
61
112
 
62
113
  ```bash
63
- node .agent-bridge/launch.js
64
- node .agent-bridge/launch.js --lan
65
- node .agent-bridge/launch.js status
66
- node .agent-bridge/launch.js msg <agent> <text>
67
- node .agent-bridge/launch.js reset
114
+ npx let-them-talk init --claude # Claude Code only
115
+ npx let-them-talk init --gemini # Gemini CLI only
116
+ npx let-them-talk init --codex # Codex CLI only
117
+ npx let-them-talk init --all # All three
118
+ npx let-them-talk init --ollama # Add a local Ollama bridge
68
119
  ```
69
120
 
70
- Other packaged CLI helpers:
121
+ ### Init with a ready-made template
71
122
 
72
123
  ```bash
73
- npx let-them-talk dashboard
74
- npx let-them-talk status
75
- npx let-them-talk templates
76
- npx let-them-talk uninstall
77
- npx let-them-talk help
124
+ npx let-them-talk init --template pair # 2-agent chat
125
+ npx let-them-talk init --template team # Coordinator + Researcher + Coder
126
+ npx let-them-talk init --template review # Author + Reviewer code-review pair
127
+ npx let-them-talk init --template debate # Pro + Con structured debate
128
+ npx let-them-talk init --template managed # Manager + Designer + Coder + Tester
78
129
  ```
79
130
 
80
- ## Template inventory
131
+ ### What init writes (all merge-safe)
81
132
 
82
- Agent templates shipped today:
133
+ - `.mcp.json` Claude Code MCP config
134
+ - `.gemini/settings.json` — Gemini CLI MCP config
135
+ - `.codex/config.toml` — Codex CLI MCP config
136
+ - `AGENTS.md` / `CLAUDE.md` — background-worker rules block (marker-delimited, never clobbers your content)
137
+ - `.agent-bridge/launch.js` — local launcher (no re-download needed)
138
+ - `.gitignore` — adds sensible entries
83
139
 
84
- - `pair`
85
- - `team`
86
- - `review`
87
- - `debate`
88
- - `managed`
140
+ All existing configs are preserved — agent-bridge is added alongside your other MCP servers, with `.backup` files created before any edit.
89
141
 
90
- Conversation templates shipped today:
142
+ ### Launch the dashboard
91
143
 
92
- - `autonomous-feature`
93
- - `code-review`
94
- - `debug-squad`
95
- - `feature-build`
96
- - `research-write`
144
+ ```bash
145
+ node .agent-bridge/launch.js # localhost:3000
146
+ node .agent-bridge/launch.js --lan # also listen on LAN (phone/tablet)
147
+ node .agent-bridge/launch.js status # CLI status snapshot
148
+ node .agent-bridge/launch.js msg <agent> # send a message from the terminal
149
+ node .agent-bridge/launch.js migrate # backfill canonical events from legacy projects
150
+ ```
97
151
 
98
- ## Runtime descriptors and provider capabilities
152
+ ---
99
153
 
100
- API-backed agents persist an explicit runtime descriptor with these fields:
154
+ ## 🎬 The 60-second demo
101
155
 
102
- - `runtime_type`
103
- - `provider_id`
104
- - `model_id`
105
- - `capabilities`
156
+ ```bash
157
+ # In project folder
158
+ npx let-them-talk init --template team
159
+ node .agent-bridge/launch.js
160
+ ```
106
161
 
107
- Supported capability tokens today:
162
+ Open three terminals. The `templates` output prints the exact prompt to paste into each:
108
163
 
109
- - `chat`
110
- - `vision`
111
- - `image_generation`
112
- - `video_generation`
113
- - `texture_generation`
164
+ - **Terminal 1 (Coordinator):** receives the user's request, breaks it into tasks, delegates to Researcher and Coder.
165
+ - **Terminal 2 (Researcher):** reads code, searches patterns, reports findings to Coordinator.
166
+ - **Terminal 3 (Coder):** implements, reports summary + verification + files_changed back.
114
167
 
115
- Legacy `provider`, `provider_color`, and `bot_capability` fields remain compatibility projections over that descriptor.
168
+ From the dashboard Messages tab, send the Coordinator a task. Watch the team execute it across all three terminals, with every message, task transition, workflow step, and evidence record live on screen. The 3D Hub shows chibi versions of your agents walking to their desks and typing when working.
116
169
 
117
- ## Markdown workspace export
170
+ ---
118
171
 
119
- ```bash
120
- npm run export:markdown-workspace
172
+ ## 🎛️ Dashboard tour
173
+
174
+ | Tab | What it does |
175
+ |---|---|
176
+ | **3D Hub** | Live chibi-style visualization of your team. Per-project worlds, buildings, behaviors. |
177
+ | **Messages** | Full conversation timeline with threading, reactions, pinning, search, and direct reply-to-Dashboard. |
178
+ | **Tasks** | Kanban of all tasks across the branch. Drag to change status. Evidence-backed completion. **Clear All Tasks** button for cleanup. |
179
+ | **Workspaces** | Per-agent scratchpad. Other agents can read, only you can write. 50 keys, 100 KB values. |
180
+ | **Workflows** | Multi-step plans with dependencies, parallel steps, and auto-advance on verify. |
181
+ | **Graph** | Agent/task/dependency network view. |
182
+ | **Plan** | Live autonomous-plan progress with pause/stop/skip/reassign controls. |
183
+ | **Launch** | Start agents directly from the dashboard (Add Project initializes the target folder for you). |
184
+ | **Rules** | Project-wide rules injected into every agent's guide. |
185
+ | **Stats** | Messages, tasks, completion rates, per-agent activity. |
186
+ | **Services** | Status of configured providers and API keys. |
187
+ | **Docs** | Shipped architecture + usage docs, searchable. |
188
+
189
+ The dashboard also supports:
190
+ - Saved named layouts
191
+ - Omnibox / command palette on the search bar
192
+ - Per-project branch switching and Clear Messages (canonical-aware)
193
+ - **Reinstall Providers** — rewrites per-project MCP configs and refreshes the `AGENTS.md` rule block without touching your other content
194
+
195
+ ---
196
+
197
+ ## 📐 Core concepts
198
+
199
+ ### Runtime
200
+
201
+ - **Canonical truth** lives in an event-backed runtime under `.agent-bridge/runtime/`.
202
+ - Legacy flat `.json` / `.jsonl` files in `.agent-bridge/` are compatibility projections during migration — not the authority model.
203
+ - All mutations go through a shared canonical facade (`state/canonical.js`). The dashboard is a client of the broker, not a second writer.
204
+
205
+ ### Branches
206
+
207
+ Branches are **full execution contexts**, not just message logs. A branch switch replaces the migrated branch-local view all at once:
208
+ - messages and history
209
+ - delivery and read state
210
+ - conversation control and non-general channels
211
+ - tasks and workflows
212
+ - workspaces
213
+ - sessions and evidence
214
+ - governance: decisions, KB, reviews, dependencies, votes, rules, progress
215
+
216
+ Branch creation snapshots the source branch at the fork point. Branch-local changes never bleed into `main` until explicitly advanced.
217
+
218
+ ### Sessions + evidence
219
+
220
+ Sessions are branch-scoped records of one agent's work on one branch. Rejoining the same branch resumes that branch-scoped context. Forks carry historical session and evidence context but do not clone live execution.
221
+
222
+ Completion is authoritative only when structured evidence is recorded:
223
+ - `summary`
224
+ - `verification`
225
+ - `files_changed`
226
+ - `confidence` (0–100)
227
+ - `recorded_at`
228
+ - `recorded_by_session`
229
+
230
+ Anything less is a conversational "done", not a runtime "done".
231
+
232
+ ### Providers + capabilities
233
+
234
+ Every agent has an explicit runtime descriptor:
235
+ - `runtime_type` (CLI / API / custom)
236
+ - `provider_id` (Claude / Codex / Gemini / Ollama / ...)
237
+ - `model_id`
238
+ - `capabilities` — tokens like `chat`, `vision`, `image_generation`, `video_generation`, `texture_generation`
239
+
240
+ Coordinators can route work by capability instead of by heuristic — `get_work` and task assignment both respect declared capabilities.
241
+
242
+ ### Autonomy loop
243
+
244
+ Instead of babysitting the chat:
245
+
246
+ ```
247
+ Coordinator → start_plan(name, steps, assignees)
248
+
249
+ Each agent → get_work() → do work → verify_and_advance() → get_work() → ...
121
250
  ```
122
251
 
123
- Default export root is `<project>/.agent-bridge-markdown/`. Exported files declare `authoritative: false` in frontmatter. The export is one-way only. There is no markdown write-back, watcher loop, or import path in the current runtime.
252
+ - **`get_work`** picks the highest-priority item from: assigned workflow step, claimable task, open review, help request, blocked dependency, and more.
253
+ - **`verify_and_advance`** self-verifies with evidence. ≥ 70 confidence auto-advances. 40–69 advances with a flag. < 40 broadcasts a help request.
254
+ - **`retry_with_improvement`** handles failures. 3 failed retries auto-escalate to the team. Skill accumulation is stored in the KB for everyone.
255
+ - **Watchdog** detects idle agents, stuck steps, and dead owners. Can rotate ownership within bounds.
256
+
257
+ ---
258
+
259
+ ## 🧩 Agent templates
124
260
 
125
- When a source surface is still compatibility-shared or main-only, export stays truthful by emitting it only for `main` or omitting it. The exporter does not fabricate non-main branch copies from shared state.
261
+ ### Agent templates (role prompts)
126
262
 
127
- ## Verification
263
+ | Template | Agents | Use when |
264
+ |---|---|---|
265
+ | `pair` | A, B | Two-agent brainstorm or Q&A |
266
+ | `team` | Coordinator, Researcher, Coder | Feature work with research + implementation |
267
+ | `review` | Author, Reviewer | Code-review loop |
268
+ | `debate` | Pro, Con | Explore tradeoffs / architecture decisions |
269
+ | `managed` | Manager, Designer, Coder, Tester | 3+ agents with structured turn-taking |
128
270
 
129
- From this package directory:
271
+ ### Conversation templates (workflow skeletons)
272
+
273
+ | Template | Purpose |
274
+ |---|---|
275
+ | `feature-build` | End-to-end feature: research → design → implement → test |
276
+ | `code-review` | Structured code review with evidence |
277
+ | `debug-squad` | Coordinated bug triage and fix |
278
+ | `research-write` | Research → synthesize → document |
279
+ | `autonomous-feature` | Fully autonomous multi-agent feature build |
280
+
281
+ List, show, or apply templates:
130
282
 
131
283
  ```bash
132
- npm test
284
+ npx let-them-talk templates # list all
285
+ npx let-them-talk init --template team # scaffold a team
133
286
  ```
134
287
 
135
- Grouped package commands:
288
+ ---
289
+
290
+ ## 🧪 Verification
291
+
292
+ Script-driven, deterministic, no flake:
136
293
 
137
294
  ```bash
138
- npm run verify
139
- npm run verify:contracts
140
- npm run verify:replay
141
- npm run verify:invariants
142
- npm run verify:smoke
295
+ npm test # delegates to verify
296
+ npm run verify # full suite
297
+ npm run verify:contracts # runtime + schema + branches + markdown
298
+ npm run verify:replay # event replay (healthy + clean + negative)
299
+ npm run verify:invariants # dashboard, capabilities, parity, sessions, evidence, autonomy, hooks
300
+ npm run verify:smoke # representative subset
143
301
  ```
144
302
 
145
- Current grouped coverage:
303
+ The verify suite doesn't claim to cover every provider or runtime matrix, and does not include browser automation. But every shipped invariant is script-enforced on every release.
304
+
305
+ ---
306
+
307
+ ## 🔐 Security
308
+
309
+ - **Dashboard binds to `127.0.0.1` by default.** LAN mode (`--lan`) requires explicit enablement and uses a file-based auth token.
310
+ - **Rate-limited** API endpoints on non-localhost requests.
311
+ - **No telemetry, no cloud.** Everything runs locally.
312
+ - **0 known vulnerabilities** in the shipped tarball as of v5.4.1.
313
+ - **Sensitive-path blocks** on file-share: `.env`, `.pem`, `.key`, `.lan-token`, `mcp.json`, and the agent-bridge data directory cannot be shared.
314
+ - See [`SECURITY.md`](SECURITY.md) for the disclosure policy.
315
+
316
+ ---
146
317
 
147
- - `verify:contracts` checks the runtime contract, canonical event schema, branch semantics, and markdown workspace contract.
148
- - `verify:replay` checks healthy and clean replay plus expected-failure negative replay scenarios.
149
- - `verify:invariants` checks authority routing, dashboard control plane behavior, performance and indexing, provider capabilities, API-agent parity, dashboard semantic-gap coverage, migration hardening, branch isolation, session lifecycle, evidence-backed completion, session-aware context, autonomy v2, advisory contracts, managed-team integration, lifecycle hooks, and markdown workspace export and safety.
150
- - `verify:smoke` runs a representative subset, including the dashboard semantic-gap check.
318
+ ## 📚 Architecture
151
319
 
152
- Coverage is still partial. The suite does not claim a full provider or runtime matrix, and it does not include browser automation.
320
+ Source-of-truth docs:
153
321
 
154
- ## Security and license
322
+ - [`docs/architecture/runtime-contract.md`](docs/architecture/runtime-contract.md)
323
+ - [`docs/architecture/branch-semantics.md`](docs/architecture/branch-semantics.md)
324
+ - [`docs/architecture/canonical-event-schema.md`](docs/architecture/canonical-event-schema.md)
325
+ - [`docs/architecture/markdown-workspace.md`](docs/architecture/markdown-workspace.md)
326
+ - [`docs/architecture/runtime-migration-hardening.md`](docs/architecture/runtime-migration-hardening.md)
155
327
 
156
- Security notes live in `SECURITY.md`.
328
+ ---
157
329
 
158
- License: [Business Source License 1.1](LICENSE)
330
+ ## 💬 Community
331
+
332
+ - [Discord](https://discord.gg/6Y9YgkFNJP) — questions, show-and-tell, feedback
333
+ - [GitHub Issues](https://github.com/Dekelelz/let-them-talk/issues) — bugs and feature requests
334
+ - [Website](https://talk.unrealai.studio) — project home
335
+
336
+ ---
337
+
338
+ ## 📄 License
339
+
340
+ [Business Source License 1.1](LICENSE). See the license file for usage terms.
341
+
342
+ ---
343
+
344
+ <p align="center">
345
+ <sub>Built for humans who want their AI agents to work as a team.</sub>
346
+ </p>
package/USAGE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <!-- Generated from ../USAGE.md by scripts/sync-packaged-docs.js for published package consumers. -->
2
2
 
3
- # Let Them Talk Usage Guide v5.4.0
3
+ # Let Them Talk Usage Guide v5.4.1
4
4
 
5
5
  This guide is the short operator view of the current runtime. For normative architecture details, use the docs under `docs/architecture/`.
6
6
 
package/cli.js CHANGED
@@ -9,7 +9,7 @@ const { createCanonicalState } = require('./state/canonical');
9
9
 
10
10
  function printUsage() {
11
11
  console.log(`
12
- Let Them Talk — Agent Bridge v5.4.0
12
+ Let Them Talk — Agent Bridge v5.4.1
13
13
  MCP message broker for inter-agent communication
14
14
  Supports: Claude Code, Gemini CLI, Codex CLI, Ollama
15
15
 
package/dashboard.js CHANGED
@@ -202,7 +202,45 @@ function isRecentlyListening(info) {
202
202
  return Date.now() - last < LISTEN_RECENCY_GRACE_MS;
203
203
  }
204
204
 
205
+ // Virtual-agent helpers. "Dashboard" and "Owner" represent the operator UI,
206
+ // not a real CLI process. Writing them to agents.json lets list_agents and
207
+ // list_channels show them as first-class recipients, so agents can DM the
208
+ // operator via send_message(to="Dashboard") without confusion.
209
+ const VIRTUAL_AGENT_NAMES = ['Dashboard', 'Owner'];
210
+ function ensureVirtualAgents(projectPath) {
211
+ try {
212
+ const dataDir = resolveDataDir(projectPath);
213
+ if (!fs.existsSync(dataDir)) return;
214
+ const agentsFile = path.join(dataDir, 'agents.json');
215
+ let agents = {};
216
+ if (fs.existsSync(agentsFile)) {
217
+ try { agents = JSON.parse(fs.readFileSync(agentsFile, 'utf8')); } catch {}
218
+ }
219
+ const now = new Date().toISOString();
220
+ let changed = false;
221
+ for (const name of VIRTUAL_AGENT_NAMES) {
222
+ if (!agents[name] || !agents[name].is_virtual) {
223
+ agents[name] = {
224
+ pid: -1,
225
+ is_virtual: true,
226
+ virtual_type: 'owner',
227
+ timestamp: (agents[name] && agents[name].timestamp) || now,
228
+ last_activity: now,
229
+ last_listened_at: now,
230
+ provider: 'Dashboard',
231
+ branch: 'main',
232
+ };
233
+ changed = true;
234
+ }
235
+ }
236
+ if (changed) {
237
+ fs.writeFileSync(agentsFile, JSON.stringify(agents, null, 2) + '\n');
238
+ }
239
+ } catch {} // best-effort — if agents.json is locked, we'll try again next request
240
+ }
241
+
205
242
  function isPidAlive(pid, lastActivity) {
243
+ if (pid === -1) return true; // virtual agents (Dashboard, Owner) — always alive
206
244
  const STALE_THRESHOLD = 60000; // 60s — if heartbeat updated within this, agent is alive
207
245
 
208
246
  // PRIORITY 1: Trust heartbeat freshness over PID status
@@ -270,6 +308,9 @@ function apiChannels(query) {
270
308
 
271
309
  function apiAgents(query) {
272
310
  const projectPath = query.get('project') || null;
311
+ // Make sure the operator virtual agents (Dashboard, Owner) exist so agents
312
+ // querying list_agents over MCP see them as valid DM recipients.
313
+ ensureVirtualAgents(projectPath);
273
314
  const canonicalState = getCanonicalState(projectPath);
274
315
  const agents = canonicalState.listAgents();
275
316
  const profiles = canonicalState.listProfiles();
@@ -3417,7 +3458,7 @@ server.listen(PORT, LAN_MODE ? '0.0.0.0' : '127.0.0.1', () => {
3417
3458
  const dataDir = resolveDataDir();
3418
3459
  const lanIP = getLanIP();
3419
3460
  console.log('');
3420
- console.log(' Let Them Talk - Agent Bridge Dashboard v5.4.0');
3461
+ console.log(' Let Them Talk - Agent Bridge Dashboard v5.4.1');
3421
3462
  console.log(' ============================================');
3422
3463
  console.log(' Dashboard: http://localhost:' + PORT);
3423
3464
  if (LAN_MODE && lanIP) {
package/office/index.js CHANGED
@@ -28,13 +28,13 @@ function getCityMods() {
28
28
  }).catch(function(e) { console.warn('City modules failed:', e); });
29
29
  return _cityMods;
30
30
  }
31
- function isDriving() { return _cityMods && _cityMods.vehicle && _cityMods.vehicle.isDriving(); }
32
- function isConnected() { return false; }
33
-
34
- function scopedOfficeApiUrl(path, options) {
35
- if (typeof window.scopedApiUrl === 'function') return window.scopedApiUrl(path, null, options);
36
- return path;
37
- }
31
+ function isDriving() { return _cityMods && _cityMods.vehicle && _cityMods.vehicle.isDriving(); }
32
+ function isConnected() { return false; }
33
+
34
+ function scopedOfficeApiUrl(path, options) {
35
+ if (typeof window.scopedApiUrl === 'function') return window.scopedApiUrl(path, null, options);
36
+ return path;
37
+ }
38
38
 
39
39
  // Expose createCharacter + resolveAppearance for the character designer (Phase 3)
40
40
  export { createCharacter } from './character.js';
@@ -319,29 +319,29 @@ function executeCommand(agentName, action) {
319
319
  });
320
320
  break;
321
321
 
322
- case 'send_message':
323
- showInputOverlay('Send message to ' + agentName + ':', 'Type your message...', function(msg) {
324
- if (msg && msg.trim()) {
325
- showBubble(agent, 'Message incoming...');
326
- fetch(scopedOfficeApiUrl('/api/inject'), {
327
- method: 'POST',
328
- headers: { 'Content-Type': 'application/json', 'X-LTT-Request': '1' },
329
- body: JSON.stringify({ to: agentName, content: msg.trim() })
330
- }).then(function() { showBubble(agent, 'Got it!'); });
331
- }
322
+ case 'send_message':
323
+ showInputOverlay('Send message to ' + agentName + ':', 'Type your message...', function(msg) {
324
+ if (msg && msg.trim()) {
325
+ showBubble(agent, 'Message incoming...');
326
+ fetch(scopedOfficeApiUrl('/api/inject'), {
327
+ method: 'POST',
328
+ headers: { 'Content-Type': 'application/json', 'X-LTT-Request': '1' },
329
+ body: JSON.stringify({ to: agentName, content: msg.trim() })
330
+ }).then(function() { showBubble(agent, 'Got it!'); });
331
+ }
332
332
  });
333
333
  break;
334
334
 
335
- case 'assign_task':
336
- showInputOverlay('New task for ' + agentName + ':', 'Task title...', function(title) {
337
- if (title && title.trim()) {
338
- showBubble(agent, 'New task assigned!');
339
- fetch(scopedOfficeApiUrl('/api/tasks'), {
340
- method: 'POST',
341
- headers: { 'Content-Type': 'application/json', 'X-LTT-Request': '1' },
342
- body: JSON.stringify({ title: title.trim(), assignee: agentName, status: 'pending' })
343
- });
344
- }
335
+ case 'assign_task':
336
+ showInputOverlay('New task for ' + agentName + ':', 'Task title...', function(title) {
337
+ if (title && title.trim()) {
338
+ showBubble(agent, 'New task assigned!');
339
+ fetch(scopedOfficeApiUrl('/api/tasks'), {
340
+ method: 'POST',
341
+ headers: { 'Content-Type': 'application/json', 'X-LTT-Request': '1' },
342
+ body: JSON.stringify({ title: title.trim(), assignee: agentName, status: 'pending' })
343
+ });
344
+ }
345
345
  });
346
346
  break;
347
347
 
@@ -355,13 +355,13 @@ function executeCommand(agentName, action) {
355
355
  }
356
356
  break;
357
357
 
358
- case 'nudge':
359
- showBubble(agent, 'Hey! Wake up!');
360
- fetch(scopedOfficeApiUrl('/api/inject'), {
361
- method: 'POST',
362
- headers: { 'Content-Type': 'application/json', 'X-LTT-Request': '1' },
363
- body: JSON.stringify({ to: agentName, content: 'Hey ' + agentName + ', the user is waiting for you. Please check for new messages and continue your work.' })
364
- });
358
+ case 'nudge':
359
+ showBubble(agent, 'Hey! Wake up!');
360
+ fetch(scopedOfficeApiUrl('/api/inject'), {
361
+ method: 'POST',
362
+ headers: { 'Content-Type': 'application/json', 'X-LTT-Request': '1' },
363
+ body: JSON.stringify({ to: agentName, content: 'Hey ' + agentName + ', the user is waiting for you. Please check for new messages and continue your work.' })
364
+ });
365
365
  break;
366
366
 
367
367
  case 'edit_profile':
@@ -957,19 +957,20 @@ window.onPlayerSit = function(deskIdx) {
957
957
  var iframeWrap = document.createElement('div');
958
958
  iframeWrap.style.cssText = 'flex:1;position:relative;';
959
959
 
960
- // Dashboard iframe
960
+ // Dashboard iframe. clipboard-write only — the iframe needs to copy agent
961
+ // prompts into the user's clipboard, it never needs to read from it.
961
962
  var dashIframe = document.createElement('iframe');
962
963
  dashIframe.id = 'mon-iframe-dashboard';
963
964
  dashIframe.src = window.location.origin || 'http://localhost:3000';
964
965
  dashIframe.style.cssText = 'position:absolute;top:0;left:0;width:100%;height:100%;border:none;background:#0d1117;';
965
- dashIframe.allow = 'clipboard-read; clipboard-write';
966
+ dashIframe.allow = 'clipboard-write';
966
967
  iframeWrap.appendChild(dashIframe);
967
968
 
968
- // ComfyUI iframe (hidden initially)
969
+ // ComfyUI iframe (hidden initially). Same write-only clipboard scope.
969
970
  var comfyIframe = document.createElement('iframe');
970
971
  comfyIframe.id = 'mon-iframe-comfyui';
971
972
  comfyIframe.style.cssText = 'position:absolute;top:0;left:0;width:100%;height:100%;border:none;background:#1a1a2e;display:none;';
972
- comfyIframe.allow = 'clipboard-read; clipboard-write';
973
+ comfyIframe.allow = 'clipboard-write';
973
974
  // Don't load ComfyUI until tab is clicked (saves resources)
974
975
  iframeWrap.appendChild(comfyIframe);
975
976
 
@@ -995,9 +996,11 @@ window.onPlayerSit = function(deskIdx) {
995
996
  if (dIframe) dIframe.style.display = 'none';
996
997
  if (cIframe) {
997
998
  cIframe.style.display = 'block';
998
- // Lazy-load ComfyUI on first switch
999
+ // Lazy-load ComfyUI on first switch. URL is configurable via
1000
+ // window.COMFYUI_URL (set it from the dashboard or page) so users
1001
+ // on non-default ports or remote ComfyUI hosts can override.
999
1002
  if (!cIframe.src || cIframe.src === 'about:blank' || cIframe.src === '') {
1000
- cIframe.src = 'http://127.0.0.1:8188';
1003
+ cIframe.src = (typeof window !== 'undefined' && window.COMFYUI_URL) || 'http://127.0.0.1:8188';
1001
1004
  }
1002
1005
  }
1003
1006
  if (dTab) { dTab.style.color = '#8892b0'; dTab.style.borderBottomColor = 'transparent'; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "let-them-talk",
3
- "version": "5.4.0",
3
+ "version": "5.4.1",
4
4
  "description": "MCP message broker + web dashboard for inter-agent communication. Let AI CLI agents talk to each other.",
5
5
  "main": "server.js",
6
6
  "bin": {
package/server.js CHANGED
@@ -567,11 +567,34 @@ function withFileLock(filePath, fn) {
567
567
  try { return fn(); } finally { try { fs.unlinkSync(lockPath); } catch {} }
568
568
  }
569
569
 
570
+ // Virtual operator agents. "Dashboard" and "Owner" represent the operator UI,
571
+ // not a CLI process. Surfacing them here ensures list_agents, broadcast filters,
572
+ // and DM-routing in the broker all agree the operator is a real recipient.
573
+ const VIRTUAL_AGENT_NAMES = ['Dashboard', 'Owner'];
574
+ function _mergeVirtualAgents(agents) {
575
+ const now = new Date().toISOString();
576
+ for (const name of VIRTUAL_AGENT_NAMES) {
577
+ if (!agents[name] || !agents[name].is_virtual) {
578
+ agents[name] = {
579
+ pid: -1,
580
+ is_virtual: true,
581
+ virtual_type: 'owner',
582
+ timestamp: (agents[name] && agents[name].timestamp) || now,
583
+ last_activity: now,
584
+ last_listened_at: now,
585
+ provider: 'Dashboard',
586
+ branch: (agents[name] && agents[name].branch) || 'main',
587
+ };
588
+ }
589
+ }
590
+ return agents;
591
+ }
592
+
570
593
  function getAgents() {
571
594
  return cachedRead('agents', () => {
572
- if (!fs.existsSync(AGENTS_FILE)) return {};
595
+ if (!fs.existsSync(AGENTS_FILE)) return _mergeVirtualAgents({});
573
596
  let agents;
574
- try { agents = JSON.parse(fs.readFileSync(AGENTS_FILE, 'utf8')); } catch { return {}; }
597
+ try { agents = JSON.parse(fs.readFileSync(AGENTS_FILE, 'utf8')); } catch { return _mergeVirtualAgents({}); }
575
598
  // Scale fix: merge per-agent heartbeat files for live activity data
576
599
  try {
577
600
  const files = fs.readdirSync(DATA_DIR).filter(f => f.startsWith('heartbeat-') && f.endsWith('.json'));
@@ -586,7 +609,7 @@ function getAgents() {
586
609
  }
587
610
  }
588
611
  } catch {}
589
- return agents;
612
+ return _mergeVirtualAgents(agents);
590
613
  }, 1500);
591
614
  }
592
615
 
@@ -616,6 +639,10 @@ function getAcks(branch = currentBranch) {
616
639
  // Cache for isPidAlive results — avoids redundant process.kill calls at 100-agent scale
617
640
  const _pidAliveCache = {};
618
641
  function isPidAlive(pid, lastActivity) {
642
+ // Virtual agents (Dashboard, Owner) use pid === -1 and are always alive.
643
+ // They represent the operator UI; liveness is implicit while the broker runs.
644
+ if (pid === -1) return true;
645
+
619
646
  // Cache with 5s TTL — PID status doesn't change faster than heartbeats
620
647
  const cacheKey = `${pid}_${lastActivity}`;
621
648
  const cached = _pidAliveCache[cacheKey];
@@ -2765,7 +2792,11 @@ function toolBroadcast(content) {
2765
2792
  if (sizeErr) return sizeErr;
2766
2793
 
2767
2794
  const agents = getAgents();
2768
- const otherAgents = Object.keys(agents).filter(n => n !== registeredName);
2795
+ // Exclude self and virtual agents (Dashboard, Owner) from broadcast recipients.
2796
+ // Virtual agents represent the operator UI and read from the shared message log
2797
+ // directly; they don't need per-recipient DM copies. Group-mode __group__ writes
2798
+ // are still visible to the UI via /api/history.
2799
+ const otherAgents = Object.keys(agents).filter(n => n !== registeredName && !agents[n].is_virtual);
2769
2800
 
2770
2801
  if (otherAgents.length === 0) {
2771
2802
  return { error: 'No other agents registered' };
@@ -8391,7 +8422,7 @@ function toolToggleRule(ruleId) {
8391
8422
  // --- MCP Server setup ---
8392
8423
 
8393
8424
  const server = new Server(
8394
- { name: 'agent-bridge', version: '5.4.0' },
8425
+ { name: 'agent-bridge', version: '5.4.1' },
8395
8426
  { capabilities: { tools: {} } }
8396
8427
  );
8397
8428
 
@@ -9531,7 +9562,7 @@ async function main() {
9531
9562
  try {
9532
9563
  const transport = new StdioServerTransport();
9533
9564
  await server.connect(transport);
9534
- console.error('Agent Bridge MCP server v5.4.0 running (66 tools)');
9565
+ console.error('Agent Bridge MCP server v5.4.1 running (66 tools)');
9535
9566
  } catch (e) {
9536
9567
  console.error('ERROR: MCP server failed to start: ' + e.message);
9537
9568
  console.error('Fix: Run "npx let-them-talk doctor" to check your setup.');