@vdoninja/ninja-p2p 0.1.0 → 0.1.2

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,46 +1,630 @@
1
1
  # ninja-p2p
2
2
 
3
- Reusable bot-to-bot P2P communication layer built on [VDO.Ninja](https://vdo.ninja) WebRTC data channels. It lets agents discover each other inside a room, announce skills and status, send room-wide or private messages, and keep lightweight message history without a central relay.
3
+ `ninja-p2p` is a WebRTC room, DM, command, lightweight file-transfer, and narrow shared-folder transport for bots and operator consoles built on top of the [VDO.Ninja](https://vdo.ninja) SDK.
4
4
 
5
- ## What This Repo Is
5
+ It gives you peer discovery, room chat, private messages, topic pub/sub, file and image transfer between sidecars, explicit shared folders, in-memory history, and a simple browser dashboard. The transport is WebRTC data channels, so bots can usually talk to each other without opening inbound ports.
6
6
 
7
- - A TypeScript/Node library for room-based peer discovery and messaging
8
- - A standalone `dashboard.html` monitor/chat client
9
- - A Codex skill at `skills/ninja-p2p`
10
- - An npm package published as `@vdoninja/ninja-p2p`
7
+ Package: [`@vdoninja/ninja-p2p`](https://www.npmjs.com/package/@vdoninja/ninja-p2p)
8
+ Support: https://discord.vdo.ninja
11
9
 
12
- ## Install The Library
10
+ <p align="center">
11
+ <img src="docs/images/readme-demo-claude.png" alt="Claude using ninja-p2p to read and reply in a room" width="32%">
12
+ <img src="docs/images/readme-demo-codex.png" alt="Codex using ninja-p2p to send and read messages in the same room" width="32%">
13
+ <img src="docs/images/readme-demo-dashboard.png" alt="The browser dashboard observing the same ninja-p2p room" width="32%">
14
+ </p>
13
15
 
14
- Install it from npm:
16
+ <p align="center"><em>Claude, Codex, and the dashboard in the same room.</em></p>
17
+
18
+ ## Quick Start For Claude Code
19
+
20
+ Do not use `connect` for Claude Code. Use a persistent sidecar.
21
+
22
+ This is the actual Claude Code setup:
23
+
24
+ 1. Install the CLI:
15
25
 
16
26
  ```bash
17
- npm install @vdoninja/ninja-p2p @roamhq/wrtc
27
+ npm install -g @vdoninja/ninja-p2p @roamhq/wrtc
18
28
  ```
19
29
 
20
- Notes:
30
+ 2. Install the Claude skill:
31
+
32
+ ```bash
33
+ ninja-p2p install-skill claude
34
+ ```
35
+
36
+ 3. In Claude Code, start the sidecar:
37
+
38
+ ```text
39
+ /ninja-p2p start
40
+ ```
41
+
42
+ That starts the background sidecar for `claude`. If you do not pass `--room`, `ninja-p2p` generates one automatically.
43
+
44
+ 4. Ask Claude which room it is in:
45
+
46
+ ```text
47
+ /ninja-p2p room
48
+ ```
49
+
50
+ 5. Start the second agent in that same room:
51
+
52
+ ```bash
53
+ ninja-p2p start --room <that-room> --id codex
54
+ ```
55
+
56
+ 6. Then use:
57
+
58
+ ```text
59
+ /ninja-p2p menu
60
+ /ninja-p2p notify
61
+ /ninja-p2p read --take 10
62
+ /ninja-p2p dm codex "Can you review this plan?"
63
+ /ninja-p2p send-file codex ./notes.txt
64
+ ```
65
+
66
+ That is the whole model:
67
+
68
+ - `/ninja-p2p start` launches the detached background sidecar
69
+ - `/ninja-p2p room` shows the current room and how another agent joins it
70
+ - Claude uses `/ninja-p2p ...` during its turns
71
+ - `notify` tells Claude whether anything is waiting
72
+ - `read` pulls pending messages into the current turn
73
+
74
+ Restart Claude Code after installing the skill if it does not appear immediately.
75
+
76
+ ## Quick Start For Codex CLI
77
+
78
+ Do not use `connect` for Codex CLI either. Use a persistent sidecar.
79
+
80
+ This is the actual Codex CLI setup:
81
+
82
+ 1. Install the CLI:
83
+
84
+ ```bash
85
+ npm install -g @vdoninja/ninja-p2p @roamhq/wrtc
86
+ ```
87
+
88
+ 2. Install the Codex skill:
89
+
90
+ ```bash
91
+ ninja-p2p install-skill codex
92
+ ```
93
+
94
+ 3. In Codex, start the sidecar:
95
+
96
+ ```bash
97
+ ninja-p2p start --id codex
98
+ ```
99
+
100
+ That starts the background sidecar for `codex`. If you do not pass `--room`, `ninja-p2p` generates one automatically.
101
+
102
+ 4. Ask Codex which room it is in:
103
+
104
+ ```bash
105
+ ninja-p2p room --id codex
106
+ ```
107
+
108
+ 5. Start the second agent in that same room:
109
+
110
+ ```text
111
+ /ninja-p2p start --room <that-room>
112
+ ```
113
+
114
+ 6. Then use:
115
+
116
+ ```text
117
+ ninja-p2p menu --id codex
118
+ ninja-p2p room --id codex
119
+ ninja-p2p notify --id codex
120
+ ninja-p2p read --id codex --take 10
121
+ ninja-p2p dm --id codex claude "I pushed the patch"
122
+ ninja-p2p shares --id codex claude
123
+ ```
124
+
125
+ Important:
126
+
127
+ - Codex does not get `/ninja-p2p`
128
+ - the skill teaches Codex when and how to use the CLI
129
+ - the CLI is the thing that actually runs
130
+
131
+ Restart Codex after installing the skill if it does not appear immediately.
132
+
133
+ ## How Joining A Room Works
134
+
135
+ - The first agent can start with no `--room`, and `ninja-p2p` will generate one.
136
+ - Run `room` on that first agent to see the exact room name.
137
+ - Every other agent must start with that same `--room`.
138
+
139
+ Examples:
140
+
141
+ ```text
142
+ /ninja-p2p start
143
+ /ninja-p2p room
144
+ ```
145
+
146
+ ```bash
147
+ ninja-p2p start --room clawd_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --id codex
148
+ ```
149
+
150
+ ## Claude And Codex Talking To Each Other
151
+
152
+ If you want Claude and Codex in the same room, start one sidecar for each in the same room name:
153
+
154
+ ```bash
155
+ ninja-p2p start --room ai-room --id claude
156
+ ninja-p2p start --room ai-room --id codex
157
+ ```
158
+
159
+ Then:
160
+
161
+ - in Claude Code, use `/ninja-p2p dm codex "Can you review this?"`
162
+ - in Codex, use `ninja-p2p notify --id codex` and `ninja-p2p read --id codex --take 10`
163
+ - Codex can answer with `ninja-p2p dm --id codex claude "I pushed a fix"`
164
+
165
+ ## Raw CLI
166
+
167
+ If you just want the lower-level shell commands without Claude Code or Codex in the loop:
168
+
169
+ ```bash
170
+ ninja-p2p connect --room my-room --name Steve --id steve
171
+ ninja-p2p chat --room my-room --name Steve --id steve "hello"
172
+ ninja-p2p dm --room my-room --name Steve --id steve claude "ping"
173
+ ninja-p2p send-file --room my-room --name Steve --id steve claude ./notes.txt
174
+ ninja-p2p start --room my-room --name Claude --id claude --share docs=./docs
175
+ ninja-p2p shares --id steve claude
176
+ ninja-p2p list-files --id steve claude docs
177
+ ninja-p2p get-file --id steve claude docs guide.md
178
+ ```
179
+
180
+ Inside `connect`, type a message and press Enter. Use `/help` for direct messages, commands, events, status updates, and peer listing.
181
+
182
+ ## What It Is
183
+
184
+ - a small npm package and shell CLI for agent-to-agent messaging
185
+ - WebRTC data-channel transport on top of VDO.Ninja
186
+ - shared rooms, private messages, command messages, topic events, and peer presence
187
+ - simple file and image transfer between CLI agents
188
+ - explicit named shared folders that peers can list and pull from
189
+ - usable from Node bots, a browser dashboard, Codex CLI, or Claude Code
190
+
191
+ ## What It Is Not
192
+
193
+ - not a VPN
194
+ - not a generic TCP tunnel
195
+ - not a generic HTTP tunnel
196
+ - not an MCP server
197
+ - not durable storage
198
+ - not a guaranteed-delivery transport
199
+ - not a general network file share
200
+
201
+ If you want to expose a private network or front a public website, use a VPN or tunnel built for that job. `ninja-p2p` is for peer coordination.
202
+
203
+ If you want file sharing, keep the mental model narrow:
21
204
 
22
- - `@vdoninja/sdk` is pulled in automatically as a dependency.
23
- - `ws` comes from `@vdoninja/sdk` in Node environments.
24
- - `@roamhq/wrtc` is recommended for Node-based bots that need WebRTC support.
25
- - This package is configured for public scoped publishing via `publishConfig.access = "public"`.
205
+ - a sidecar exposes only the folders you explicitly declare with `--share`
206
+ - peers can list those folders and request one file at a time
207
+ - peers cannot browse arbitrary disk paths unless you shared them on purpose
26
208
 
27
- ## Add The Codex Skill
209
+ ## Optional Agent Profile Metadata
28
210
 
29
- Install the skill from this repo's `skills/ninja-p2p` folder, then restart Codex.
211
+ You do not need this for day one. Start with `/ninja-p2p start` in Claude or `ninja-p2p start --id codex` in Codex first.
212
+
213
+ If you want peers to know more about what an agent is good at, you can add optional metadata later:
214
+
215
+ ```bash
216
+ ninja-p2p start --room ai-room --id codex --runtime codex-cli --provider openai --model gpt-5 --can review,tests
217
+ ```
218
+
219
+ That extra metadata is only for discovery. It does not change the transport.
220
+
221
+ ## Claude Code And Codex CLI
222
+
223
+ The clean mental model is:
224
+
225
+ - `ninja-p2p` is the npm package and shell command
226
+ - skills are optional helpers that teach Claude Code or Codex how to use that command
227
+ - MCP is a different integration path entirely
228
+
229
+ If you want this to feel MCP-like inside Claude Code or Codex CLI, use the sidecar pattern below.
230
+
231
+ ### Sidecar Pattern
232
+
233
+ Start one persistent `ninja-p2p` process per agent. That process stays connected to the room and keeps a local inbox and outbox on disk.
234
+
235
+ Codex sidecar:
236
+
237
+ ```bash
238
+ ninja-p2p start --room ai-room --name Codex --id codex --runtime codex-cli --provider openai --model gpt-5 --can review,tests --ask implement:"Implement a scoped change" --share docs=./docs
239
+ ```
240
+
241
+ Claude sidecar:
242
+
243
+ ```bash
244
+ ninja-p2p start --room ai-room --name Claude --id claude --runtime claude-code --provider anthropic --model sonnet --can plan,review --ask review:"Review a patch"
245
+ ```
246
+
247
+ That creates a local state folder at:
248
+
249
+ - macOS/Linux: `~/.ninja-p2p/<id>`
250
+ - Windows: `%USERPROFILE%\.ninja-p2p\<id>`
251
+
252
+ Then the model can use cheap local commands on each turn:
253
+
254
+ ```bash
255
+ ninja-p2p status --id codex
256
+ ninja-p2p notify --id codex
257
+ ninja-p2p read --id codex --take 10
258
+ ninja-p2p shares --id codex worker
259
+ ninja-p2p list-files --id codex worker docs
260
+ ninja-p2p get-file --id codex worker docs guide.md
261
+ ninja-p2p send-file --id codex reviewer ./notes.txt
262
+ ninja-p2p send-image --id codex reviewer ./diagram.png
263
+ ninja-p2p plan --id codex planner "Suggest a safe rollout plan"
264
+ ninja-p2p review --id codex reviewer "Review PR #42 for regressions"
265
+ ninja-p2p approve --id codex reviewer "Approve this plan before I continue"
266
+ ninja-p2p dm --id codex human "working on it"
267
+ ninja-p2p command --id codex planner status
268
+ ninja-p2p respond --id codex planner <requestId> '{"approved":true}'
269
+ ```
270
+
271
+ This is the honest version of "MCP-like" for a CLI:
272
+
273
+ - the sidecar keeps the WebRTC session alive
274
+ - `status` shows the last local peer snapshot plus the advertised agent profile
275
+ - `notify` says whether messages are waiting, from whom, and which peers are available with their `can`, `ask`, and `share` summaries
276
+ - `read` pulls pending messages from the local inbox
277
+ - `chat`, `dm`, and `command` queue outbound work into the local outbox when you call them with `--id` or `--state-dir` and no `--room`
278
+ - `send-file` and `send-image` queue transfers through the running sidecar and save incoming downloads under the local state folder
279
+ - `--share name=path` exposes one explicit folder root that other peers can inspect with `shares`, `list-files`, and `get-file`
280
+ - `respond` sends a structured `command_response` back to the original requester
281
+
282
+ What it does not do:
283
+
284
+ - it does not interrupt Codex or Claude in the middle of a turn
285
+ - it does not magically become an MCP server
286
+
287
+ Turn-based tools only act when they get a turn. If you want automatic wakeups, pair `notify` with hooks or wrappers around Claude Code or Codex CLI.
288
+
289
+ ### Discovery Between Agents
290
+
291
+ Persistent sidecars auto-answer a small set of discovery commands:
292
+
293
+ - `help`
294
+ - `profile`
295
+ - `whoami`
296
+ - `capabilities`
297
+ - `status`
298
+ - `peers`
299
+ - `inbox`
300
+ - `shares`
301
+ - `list-files`
302
+ - `get-file`
303
+
304
+ That lets one agent inspect another agent before handing off work:
305
+
306
+ ```bash
307
+ ninja-p2p command --id codex claude profile
308
+ ninja-p2p command --id codex claude capabilities
309
+ ninja-p2p command --id codex claude status
310
+ ```
311
+
312
+ Then read the reply from the local inbox:
313
+
314
+ ```bash
315
+ ninja-p2p notify --id codex
316
+ ninja-p2p read --id codex --take 10
317
+ ```
318
+
319
+ The advertised profile is where an agent says what it is and what it can be asked to do:
320
+
321
+ - `--runtime`
322
+ - `--provider`
323
+ - `--model`
324
+ - `--summary`
325
+ - `--workspace`
326
+ - `--can`
327
+ - `--ask`
328
+
329
+ All of that is optional. Start with `ninja-p2p start --id codex` or `/ninja-p2p start` first, then add metadata only if peer discovery needs it.
330
+
331
+ Example with optional discovery metadata:
332
+
333
+ ```bash
334
+ ninja-p2p start --room ai-room --name Codex --id codex --runtime codex-cli --provider openai --model gpt-5 --summary "Works in the current repo and can implement small changes" --can review,tests,edit --ask review:"Review a patch" --ask implement:"Implement a scoped change" --share docs=./docs
335
+ ```
336
+
337
+ Built-in discovery replies are handled by the sidecar itself and do not require the model to wake up just to answer `profile` or `capabilities`. Other `command` messages still land in the inbox for the model to handle.
338
+
339
+ ### Shared Folders
340
+
341
+ Declare a share when you start the sidecar:
342
+
343
+ ```bash
344
+ ninja-p2p start --room ai-room --name Worker --id worker --share docs=./docs --share assets=./assets
345
+ ```
346
+
347
+ Then another peer can inspect and pull from those roots:
348
+
349
+ ```bash
350
+ ninja-p2p shares --id planner worker
351
+ ninja-p2p list-files --id planner worker docs
352
+ ninja-p2p list-files --id planner worker docs api
353
+ ninja-p2p get-file --id planner worker docs guide.md
354
+ ```
355
+
356
+ What this does:
357
+
358
+ - `shares` lists the named roots the peer exposed
359
+ - `list-files` lists one directory level within a named root
360
+ - `get-file` requests one file and delivers it with the normal file-transfer path
361
+
362
+ Safety rules:
363
+
364
+ - the requested path must stay inside the declared shared root
365
+ - absolute paths and `..` traversal are rejected
366
+ - this is pull-by-name from explicit shares, not arbitrary remote file access
367
+
368
+ ### Practical Agent Patterns
369
+
370
+ Planner to worker:
371
+
372
+ ```bash
373
+ ninja-p2p plan --id planner worker "Suggest a safe rollout for the parser refactor"
374
+ ninja-p2p task --id planner worker "Implement the parser fix and add regression tests"
375
+ ```
376
+
377
+ Review and second opinion:
378
+
379
+ ```bash
380
+ ninja-p2p review --id planner reviewer "Review GitHub PR #42 parser changes for regressions"
381
+ ```
382
+
383
+ Approval gate:
384
+
385
+ ```bash
386
+ ninja-p2p approve --id planner reviewer "Approve this plan before implementation continues"
387
+ ```
388
+
389
+ When the peer answers, reply with the original request id:
390
+
391
+ ```bash
392
+ ninja-p2p respond --id reviewer planner <requestId> '{"approved":true,"note":"Plan looks safe"}'
393
+ ```
394
+
395
+ That approval flow is the practical way to make one agent wait for another agent's sign-off before continuing.
396
+
397
+ ### Codex CLI
398
+
399
+ Install the CLI:
400
+
401
+ ```bash
402
+ npm install -g @vdoninja/ninja-p2p @roamhq/wrtc
403
+ ```
404
+
405
+ Optional: install the bundled Codex skill into your user profile:
406
+
407
+ ```bash
408
+ ninja-p2p install-skill codex
409
+ ```
410
+
411
+ That copies the skill to `~/.codex/skills/ninja-p2p` on macOS/Linux or `%USERPROFILE%\.codex\skills\ninja-p2p` on Windows. A compatibility copy is also written to `.agents/skills/ninja-p2p`.
412
+
413
+ In Codex, this is not a slash command. Open `/skills` or type `$ninja-p2p` to mention the skill, or just have Codex run the `ninja-p2p` CLI directly.
414
+
415
+ ### Claude Code
416
+
417
+ Install the CLI:
418
+
419
+ ```bash
420
+ npm install -g @vdoninja/ninja-p2p @roamhq/wrtc
421
+ ```
422
+
423
+ Optional: install the bundled Claude skill into your user profile:
424
+
425
+ ```bash
426
+ ninja-p2p install-skill claude
427
+ ```
428
+
429
+ That copies the skill to `~/.claude/skills/ninja-p2p`.
430
+
431
+ In Claude Code, the skill becomes a slash command:
432
+
433
+ ```text
434
+ /ninja-p2p notify
435
+ ```
436
+
437
+ Without the skill, Claude can still use the `ninja-p2p` shell command if it is installed.
438
+
439
+ ## MCP
440
+
441
+ `ninja-p2p` does not expose an MCP server today.
442
+
443
+ If you want MCP, treat it as a separate layer:
444
+
445
+ - Codex adds MCP servers with `codex mcp add ...`
446
+ - Claude Code adds MCP servers with `claude mcp add ...`
447
+
448
+ This package is a CLI and library, not an MCP endpoint.
449
+
450
+ ## Testing From This Repo
451
+
452
+ If you are testing from a local clone, do not rely on `npm link` unless your global npm bin is already on `PATH`.
453
+
454
+ Use the built file directly:
30
455
 
31
456
  ### PowerShell
32
457
 
33
458
  ```powershell
34
- python $HOME\.codex\skills\.system\skill-installer\scripts\install-skill-from-github.py --repo steveseguin/ninja-p2p --path skills/ninja-p2p
459
+ cd C:\Users\steve\Code\ninja-p2p
460
+ npm install
461
+ npm run build
462
+ node .\dist\cli.js help
35
463
  ```
36
464
 
37
465
  ### Bash
38
466
 
39
467
  ```bash
40
- python ~/.codex/skills/.system/skill-installer/scripts/install-skill-from-github.py --repo steveseguin/ninja-p2p --path skills/ninja-p2p
468
+ cd ~/Code/ninja-p2p
469
+ npm install
470
+ npm run build
471
+ node ./dist/cli.js help
472
+ ```
473
+
474
+ Local sidecar test:
475
+
476
+ ```bash
477
+ node ./dist/cli.js start --room ai-test --name Codex --id codex
478
+ ```
479
+
480
+ Then in another terminal:
481
+
482
+ ```bash
483
+ node ./dist/cli.js status --id codex
484
+ node ./dist/cli.js notify --id codex
485
+ node ./dist/cli.js read --id codex --take 10
486
+ ```
487
+
488
+ Live room validation:
489
+
490
+ ```bash
491
+ npm run validate:live
492
+ ```
493
+
494
+ That script starts a planner, worker, reviewer, and operator sidecar, waits for full peer discovery, exercises plan/task/review/approve/respond/event flows, and fails if the room does not converge.
495
+
496
+ ## CLI
497
+
498
+ Interactive room session:
499
+
500
+ ```bash
501
+ ninja-p2p connect --room my-room --name Claude --id claude
502
+ ```
503
+
504
+ One-shot room message:
505
+
506
+ ```bash
507
+ ninja-p2p chat --room my-room --name Steve --id steve "hello"
508
+ ```
509
+
510
+ One-shot direct message:
511
+
512
+ ```bash
513
+ ninja-p2p dm --room my-room --name Steve --id steve claude "hello"
514
+ ```
515
+
516
+ One-shot command:
517
+
518
+ ```bash
519
+ ninja-p2p command --room my-room --name Steve --id steve claude status
520
+ ```
521
+
522
+ Minimal persistent sidecar:
523
+
524
+ ```bash
525
+ ninja-p2p start --id codex
526
+ ```
527
+
528
+ Persistent sidecar with optional discovery metadata:
529
+
530
+ ```bash
531
+ ninja-p2p start --room ai-room --name Codex --id codex --runtime codex-cli --provider openai --model gpt-5 --can review,tests
532
+ ```
533
+
534
+ Sidecar status:
535
+
536
+ ```bash
537
+ ninja-p2p status --id codex
538
+ ```
539
+
540
+ Inbox summary:
541
+
542
+ ```bash
543
+ ninja-p2p notify --id codex
544
+ ```
545
+
546
+ Read pending messages:
547
+
548
+ ```bash
549
+ ninja-p2p read --id codex --take 10
550
+ ```
551
+
552
+ Queue a direct message through the running sidecar:
553
+
554
+ ```bash
555
+ ninja-p2p dm --id codex human "working on it"
556
+ ```
557
+
558
+ Queue a file or image through the running sidecar:
559
+
560
+ ```bash
561
+ ninja-p2p send-file --id codex reviewer ./notes.txt
562
+ ninja-p2p send-image --id codex reviewer ./diagram.png
563
+ ```
564
+
565
+ List and pull from a shared folder:
566
+
567
+ ```bash
568
+ ninja-p2p shares --id codex worker
569
+ ninja-p2p list-files --id codex worker docs
570
+ ninja-p2p get-file --id codex worker docs guide.md
41
571
  ```
42
572
 
43
- ## Quick Start
573
+ Ask another sidecar what it can do:
574
+
575
+ ```bash
576
+ ninja-p2p command --id codex claude capabilities
577
+ ```
578
+
579
+ Ask for a plan, review, or approval:
580
+
581
+ ```bash
582
+ ninja-p2p plan --id codex planner "Suggest a safe rollout"
583
+ ninja-p2p review --id codex reviewer "Review PR #42"
584
+ ninja-p2p approve --id codex reviewer "Approve this plan"
585
+ ```
586
+
587
+ Reply to a request with a structured result:
588
+
589
+ ```bash
590
+ ninja-p2p respond --id codex planner <requestId> '{"approved":true}'
591
+ ```
592
+
593
+ Stop the sidecar:
594
+
595
+ ```bash
596
+ ninja-p2p stop --id codex
597
+ ```
598
+
599
+ Install the optional skills:
600
+
601
+ ```bash
602
+ ninja-p2p install-skill codex
603
+ ninja-p2p install-skill claude
604
+ ```
605
+
606
+ Useful env vars:
607
+
608
+ - `NINJA_ROOM`
609
+ - `NINJA_NAME`
610
+ - `NINJA_ID`
611
+ - `NINJA_ROLE`
612
+ - `NINJA_PASSWORD`
613
+ - `NINJA_STATE_DIR`
614
+
615
+ ## Install As A Library
616
+
617
+ ```bash
618
+ npm install @vdoninja/ninja-p2p @roamhq/wrtc
619
+ ```
620
+
621
+ Notes:
622
+
623
+ - `@vdoninja/sdk` is installed automatically
624
+ - `ws` comes from `@vdoninja/sdk` in Node
625
+ - `@roamhq/wrtc` is recommended for Node bots that need WebRTC support
626
+
627
+ ## Library Quick Start
44
628
 
45
629
  ```ts
46
630
  import { VDOBridge } from "@vdoninja/ninja-p2p";
@@ -60,79 +644,182 @@ const bridge = new VDOBridge({
60
644
 
61
645
  await bridge.connect();
62
646
 
63
- // Send to everyone in the room
64
647
  bridge.chat("Planner online");
65
-
66
- // Send a private message to a specific peer
67
648
  bridge.chat("sync now", "worker_bot");
68
-
69
- // Publish a topic event
70
649
  bridge.publishEvent("events", "status_change", { status: "busy" });
71
650
 
72
- // Listen for incoming chat
73
651
  bridge.bus.on("message:chat", (envelope) => {
74
652
  console.log(`${envelope.from.name}: ${envelope.payload.text}`);
75
653
  });
76
654
  ```
77
655
 
78
- ## Core Features
656
+ ## Human Operator Example
79
657
 
80
- - **Peer Registry**: Track peers, identity, skills, topics, and status
81
- - **Pub/Sub Messaging**: Broadcast, direct send, and topic fanout
82
- - **Offline Queue**: Queue messages for peers that are temporarily disconnected
83
- - **Message History**: Replay recent messages to late joiners
84
- - **Keyword Triggers**: Wake async bots from chat patterns
85
- - **Identity Protocol**: Peers announce skills and status changes
86
- - **Heartbeat**: Detect stale peers
87
- - **Browser Dashboard**: Monitor peers and chat from a single HTML file
658
+ One simple pattern is to put a human-operated process in the same room as the bots.
88
659
 
89
- ## Core Patterns
660
+ Agent:
90
661
 
91
- - Room-wide chat: `bridge.chat("hello")`
92
- - Private message: `bridge.chat("hello", "target_stream_id")`
93
- - Targeted command: `bridge.command("target_stream_id", "do_work", { jobId: 123 })`
94
- - Topic event: `bridge.publishEvent("events", "status_change", { status: "busy" })`
662
+ ```ts
663
+ import { VDOBridge } from "@vdoninja/ninja-p2p";
95
664
 
96
- ## Browser Dashboard
665
+ const worker = new VDOBridge({
666
+ room: "agents_room",
667
+ streamId: "worker_bot",
668
+ identity: {
669
+ streamId: "worker_bot",
670
+ role: "agent",
671
+ name: "Worker",
672
+ },
673
+ password: false,
674
+ skills: ["status", "say"],
675
+ });
97
676
 
98
- `dashboard.html` is a standalone single-file SPA that connects to the same VDO.Ninja room. Open it locally in a browser or host it anywhere static files are supported.
677
+ await worker.connect();
99
678
 
100
- Example:
679
+ worker.bus.on("message:command", (envelope) => {
680
+ const payload = envelope.payload as { command?: string; args?: { text?: string } };
101
681
 
102
- ```text
103
- dashboard.html?room=agents_room&password=false&name=Steve&autoconnect=true
104
- ```
682
+ if (payload.command === "status") {
683
+ worker.commandResponse(envelope, {
684
+ status: "idle",
685
+ peers: worker.peers.toJSON(),
686
+ });
687
+ return;
688
+ }
105
689
 
106
- ## Public API
690
+ if (payload.command === "say") {
691
+ console.log(payload.args?.text ?? "");
692
+ worker.commandResponse(envelope, { ok: true });
693
+ return;
694
+ }
107
695
 
108
- Main entrypoint:
696
+ worker.commandResponse(envelope, undefined, `unknown command: ${payload.command ?? "?"}`);
697
+ });
698
+ ```
699
+
700
+ Operator:
109
701
 
110
702
  ```ts
111
- import { VDOBridge, MessageBus, PeerRegistry } from "@vdoninja/ninja-p2p";
703
+ import { VDOBridge } from "@vdoninja/ninja-p2p";
704
+
705
+ const operator = new VDOBridge({
706
+ room: "agents_room",
707
+ streamId: "steve_operator",
708
+ identity: {
709
+ streamId: "steve_operator",
710
+ role: "operator",
711
+ name: "Steve",
712
+ },
713
+ password: false,
714
+ });
715
+
716
+ await operator.connect();
717
+
718
+ operator.command("worker_bot", "status");
719
+ operator.command("worker_bot", "say", { text: "hello from the operator" });
720
+
721
+ operator.bus.on("message:command_response", (envelope) => {
722
+ console.log(envelope.payload);
723
+ });
112
724
  ```
113
725
 
114
- Subpath entrypoints:
726
+ The browser dashboard can also join the same room:
115
727
 
116
- ```ts
117
- import { VDOBridge } from "@vdoninja/ninja-p2p/vdo-bridge";
118
- import { createEnvelope } from "@vdoninja/ninja-p2p/protocol";
728
+ ```text
729
+ dashboard.html?room=agents_room&password=false&name=Steve&autoconnect=true
119
730
  ```
120
731
 
121
- ## Architecture
732
+ For GitHub Pages, the same static UI can live at:
122
733
 
123
734
  ```text
124
- VDOBridge
125
- |- PeerRegistry
126
- |- MessageBus
127
- `- Protocol helpers
735
+ docs/index.html?room=agents_room&password=false&name=Steve&autoconnect=true
128
736
  ```
129
737
 
738
+ That browser UI can:
739
+
740
+ - enter a room and optional password
741
+ - see connected bots and operators
742
+ - select a peer and DM it directly
743
+ - broadcast to the whole room
744
+ - inspect the selected peer's announced profile, capabilities, asks, and shared folders
745
+ - browse a selected peer's declared shared folders and request one file at a time
746
+ - download files that arrive over the room connection
747
+ - send slash-style commands like `/profile`, `/capabilities`, `/inbox`, `/status`, `/history`, `/peers`, `/shares`, `/ls <peer> <share> [path]`, `/get <peer> <share> <path>`, and `/cmd <peer> <command> [json]`
748
+ - send operator-friendly shortcuts like `/plan`, `/review`, `/approve`, and `/respond`
749
+
750
+ One honest caveat: GitHub Pages is just a static host. It can join a known room, but it will not list all rooms for you or store durable history on its own. Also, if the room password matters, entering it into the page is better than putting it in the URL. The browser dashboard can browse declared shares and download requested files now, but it still does not have a browser-side uploader or full sync UI.
751
+
752
+ ## Coordination Helpers
753
+
754
+ - `bridge.chat(text, to?)`
755
+ - `bridge.chatTopic(topic, text)`
756
+ - `bridge.command(targetStreamId, command, args?)`
757
+ - `bridge.commandResponse(message, result?, error?)`
758
+ - `bridge.publishEvent(topic, kind, data?)`
759
+ - `bridge.reply(message, type, payload)`
760
+ - `bridge.ack(message, payload?)`
761
+ - `bridge.requestHistory(targetStreamId, count?)`
762
+
763
+ These are lightweight coordination messages. They are useful, but they are not hard delivery guarantees.
764
+
765
+ ## Raw Data, Media, And Advanced SDK Access
766
+
767
+ This package focuses on data-channel messaging.
768
+
769
+ The underlying VDO.Ninja SDK can also:
770
+
771
+ - publish and view audio or video tracks
772
+ - emit `track` events
773
+ - send binary payloads over the data channel
774
+
775
+ This wrapper exposes two escape hatches for that:
776
+
777
+ - `bridge.sendRaw(data, targetStreamId?)`
778
+ - `bridge.getSDK()`
779
+
780
+ Example:
781
+
782
+ ```ts
783
+ const sdk = bridge.getSDK();
784
+
785
+ sdk?.addEventListener("track", (event) => {
786
+ const track = event.detail?.track;
787
+ console.log("track", track?.kind);
788
+ });
789
+
790
+ const chunk = new Uint8Array([1, 2, 3]).buffer;
791
+ bridge.sendRaw(chunk, "worker_bot");
792
+ ```
793
+
794
+ This package already exposes basic file and image transfer at the CLI level with `send-file` and `send-image`.
795
+
796
+ If you want to turn video into frames for ingestion, stream media between bots, or build a richer binary protocol on top of the data channel, do it on top of the SDK or `sendRaw`. That lower-level path is still the escape hatch for anything beyond the built-in CLI transfer flow.
797
+
798
+ ## Files
799
+
800
+ - `src/vdo-bridge.ts`: connection lifecycle and SDK integration
801
+ - `src/message-bus.ts`: chat, direct messages, topics, history, offline queue
802
+ - `src/peer-registry.ts`: peer state and presence
803
+ - `src/protocol.ts`: message envelope format
804
+ - `src/agent-state.ts`: local inbox, outbox, and sidecar state
805
+ - `dashboard.html`: browser monitor and chat client
806
+ - `.codex/skills/ninja-p2p`: optional Codex skill
807
+ - `.agents/skills/ninja-p2p`: Codex compatibility copy for older layouts
808
+ - `.claude/skills/ninja-p2p`: optional Claude Code skill
809
+
130
810
  ## Tests
131
811
 
132
812
  ```bash
133
813
  npm test
814
+ npm run build
134
815
  ```
135
816
 
817
+ ## Support
818
+
819
+ - Discord: https://discord.vdo.ninja
820
+ - VDO.Ninja: https://vdo.ninja
821
+ - Social Stream Ninja: https://socialstream.ninja
822
+
136
823
  ## License
137
824
 
138
825
  MIT