@xmtp/convos-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +572 -0
  3. package/bin/dev.js +4 -0
  4. package/bin/run.js +4 -0
  5. package/dist/baseCommand.d.ts +46 -0
  6. package/dist/baseCommand.js +171 -0
  7. package/dist/commands/agent/serve.d.ts +67 -0
  8. package/dist/commands/agent/serve.js +662 -0
  9. package/dist/commands/conversation/add-members.d.ts +19 -0
  10. package/dist/commands/conversation/add-members.js +39 -0
  11. package/dist/commands/conversation/consent-state.d.ts +18 -0
  12. package/dist/commands/conversation/consent-state.js +24 -0
  13. package/dist/commands/conversation/download-attachment.d.ts +28 -0
  14. package/dist/commands/conversation/download-attachment.js +164 -0
  15. package/dist/commands/conversation/explode.d.ts +24 -0
  16. package/dist/commands/conversation/explode.js +156 -0
  17. package/dist/commands/conversation/info.d.ts +22 -0
  18. package/dist/commands/conversation/info.js +79 -0
  19. package/dist/commands/conversation/invite.d.ts +26 -0
  20. package/dist/commands/conversation/invite.js +137 -0
  21. package/dist/commands/conversation/lock.d.ts +24 -0
  22. package/dist/commands/conversation/lock.js +98 -0
  23. package/dist/commands/conversation/members.d.ts +22 -0
  24. package/dist/commands/conversation/members.js +39 -0
  25. package/dist/commands/conversation/messages.d.ts +31 -0
  26. package/dist/commands/conversation/messages.js +141 -0
  27. package/dist/commands/conversation/permissions.d.ts +18 -0
  28. package/dist/commands/conversation/permissions.js +33 -0
  29. package/dist/commands/conversation/profiles.d.ts +22 -0
  30. package/dist/commands/conversation/profiles.js +80 -0
  31. package/dist/commands/conversation/remove-members.d.ts +19 -0
  32. package/dist/commands/conversation/remove-members.js +36 -0
  33. package/dist/commands/conversation/send-attachment.d.ts +30 -0
  34. package/dist/commands/conversation/send-attachment.js +187 -0
  35. package/dist/commands/conversation/send-reaction.d.ts +21 -0
  36. package/dist/commands/conversation/send-reaction.js +38 -0
  37. package/dist/commands/conversation/send-remote-attachment.d.ts +30 -0
  38. package/dist/commands/conversation/send-remote-attachment.js +96 -0
  39. package/dist/commands/conversation/send-reply.d.ts +32 -0
  40. package/dist/commands/conversation/send-reply.js +170 -0
  41. package/dist/commands/conversation/send-text.d.ts +24 -0
  42. package/dist/commands/conversation/send-text.js +64 -0
  43. package/dist/commands/conversation/stream.d.ts +24 -0
  44. package/dist/commands/conversation/stream.js +81 -0
  45. package/dist/commands/conversation/sync.d.ts +18 -0
  46. package/dist/commands/conversation/sync.js +25 -0
  47. package/dist/commands/conversation/update-consent.d.ts +19 -0
  48. package/dist/commands/conversation/update-consent.js +35 -0
  49. package/dist/commands/conversation/update-description.d.ts +19 -0
  50. package/dist/commands/conversation/update-description.js +28 -0
  51. package/dist/commands/conversation/update-name.d.ts +19 -0
  52. package/dist/commands/conversation/update-name.js +29 -0
  53. package/dist/commands/conversation/update-profile.d.ts +24 -0
  54. package/dist/commands/conversation/update-profile.js +97 -0
  55. package/dist/commands/conversations/create.d.ts +26 -0
  56. package/dist/commands/conversations/create.js +165 -0
  57. package/dist/commands/conversations/join.d.ts +27 -0
  58. package/dist/commands/conversations/join.js +232 -0
  59. package/dist/commands/conversations/list.d.ts +20 -0
  60. package/dist/commands/conversations/list.js +109 -0
  61. package/dist/commands/conversations/process-join-requests.d.ts +26 -0
  62. package/dist/commands/conversations/process-join-requests.js +261 -0
  63. package/dist/commands/conversations/sync.d.ts +19 -0
  64. package/dist/commands/conversations/sync.js +50 -0
  65. package/dist/commands/identity/create.d.ts +21 -0
  66. package/dist/commands/identity/create.js +56 -0
  67. package/dist/commands/identity/info.d.ts +22 -0
  68. package/dist/commands/identity/info.js +63 -0
  69. package/dist/commands/identity/list.d.ts +19 -0
  70. package/dist/commands/identity/list.js +59 -0
  71. package/dist/commands/identity/remove.d.ts +23 -0
  72. package/dist/commands/identity/remove.js +51 -0
  73. package/dist/commands/init.d.ts +16 -0
  74. package/dist/commands/init.js +91 -0
  75. package/dist/commands/reset.d.ts +17 -0
  76. package/dist/commands/reset.js +93 -0
  77. package/dist/help.d.ts +4 -0
  78. package/dist/help.js +31 -0
  79. package/dist/index.d.ts +9 -0
  80. package/dist/index.js +15 -0
  81. package/dist/utils/client.d.ts +8 -0
  82. package/dist/utils/client.js +58 -0
  83. package/dist/utils/config.d.ts +15 -0
  84. package/dist/utils/config.js +1 -0
  85. package/dist/utils/identities.d.ts +49 -0
  86. package/dist/utils/identities.js +92 -0
  87. package/dist/utils/invite.d.ts +70 -0
  88. package/dist/utils/invite.js +339 -0
  89. package/dist/utils/metadata.d.ts +39 -0
  90. package/dist/utils/metadata.js +180 -0
  91. package/dist/utils/mime.d.ts +2 -0
  92. package/dist/utils/mime.js +42 -0
  93. package/dist/utils/random.d.ts +5 -0
  94. package/dist/utils/random.js +19 -0
  95. package/dist/utils/upload.d.ts +14 -0
  96. package/dist/utils/upload.js +51 -0
  97. package/dist/utils/xmtp.d.ts +45 -0
  98. package/dist/utils/xmtp.js +298 -0
  99. package/oclif.manifest.json +5562 -0
  100. package/package.json +124 -0
  101. package/skills/convos-cli/SKILL.md +588 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025-2026 XMTP Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,572 @@
1
+ # @xmtp/convos-cli
2
+
3
+ > [!CAUTION]
4
+ > This CLI is in beta status and ready for you to use. Software in this status may contain bugs or change based on feedback.
5
+
6
+ A command-line interface for [Convos](https://convos.org) — privacy-focused ephemeral messaging built on [XMTP](https://xmtp.org).
7
+
8
+ ## Features
9
+
10
+ - **Per-conversation identities**: Every conversation gets its own XMTP inbox — no linkability across conversations
11
+ - **Invite system**: Generate QR codes and invite links; join conversations without knowing the creator's address
12
+ - **Per-conversation profiles**: Different display name and avatar in each conversation
13
+ - **Explode**: Permanently destroy a conversation and all its cryptographic keys
14
+ - **Lock**: Prevent new members from being added to a conversation
15
+ - **Agent mode**: Single long-running process for bots — streams messages, auto-processes joins, accepts commands via stdin
16
+ - **JSON output**: Every command supports `--json` for scripting and automation
17
+
18
+ ## How Convos Differs from Standard XMTP
19
+
20
+ Standard XMTP uses a single identity (wallet + inbox) across all conversations. Convos creates a **unique identity per conversation** for maximum privacy:
21
+
22
+ | Property | How |
23
+ | -------- | --- |
24
+ | **No linkability** | Conversations cannot be correlated by external observers |
25
+ | **Isolated keys** | Each conversation has its own wallet key, encryption key, and database |
26
+ | **Ephemeral** | Exploding a conversation destroys the cryptographic identity permanently |
27
+ | **Per-conversation profiles** | Different display names and avatars per conversation |
28
+
29
+ ## Requirements
30
+
31
+ - Node.js >= 22
32
+
33
+ ## Installation
34
+
35
+ ```bash
36
+ # npm
37
+ npm install -g @xmtp/convos-cli
38
+
39
+ # pnpm
40
+ pnpm add -g @xmtp/convos-cli
41
+ ```
42
+
43
+ ## Run Without Installing
44
+
45
+ ```bash
46
+ # npx
47
+ npx @xmtp/convos-cli --help
48
+
49
+ # pnpx
50
+ pnpx @xmtp/convos-cli --help
51
+
52
+ # yarn
53
+ yarn dlx @xmtp/convos-cli --help
54
+ ```
55
+
56
+ ## Quick Start
57
+
58
+ ```bash
59
+ # 1. Initialize configuration
60
+ convos init
61
+
62
+ # 2. Create a conversation (auto-creates a per-conversation identity)
63
+ convos conversations create --name "My Group" --profile-name "Alice"
64
+
65
+ # 3. Send a message
66
+ convos conversation send-text <conversation-id> "Hello!"
67
+
68
+ # 4. Generate an invite QR code for others to join
69
+ convos conversation invite <conversation-id>
70
+
71
+ # 5. List all conversations across all identities
72
+ convos conversations list
73
+
74
+ # 6. Stream messages in real-time
75
+ convos conversation stream <conversation-id>
76
+ ```
77
+
78
+ ## Configuration
79
+
80
+ Running `convos init` creates `~/.convos/.env` with:
81
+
82
+ | Variable | Description |
83
+ | ------------------------------ | ------------------------------------------------ |
84
+ | `CONVOS_ENV` | Network: `local`, `dev`, or `production` |
85
+ | `CONVOS_UPLOAD_PROVIDER` | Upload provider for attachments (e.g., `pinata`) |
86
+ | `CONVOS_UPLOAD_PROVIDER_TOKEN` | Authentication token for upload provider |
87
+ | `CONVOS_UPLOAD_PROVIDER_GATEWAY` | Custom gateway URL for upload provider |
88
+
89
+ Unlike standard XMTP, there is **no global wallet key**. Each conversation creates its own identity stored in `~/.convos/identities/`.
90
+
91
+ The default environment is `dev`. Use `--env` to change it:
92
+
93
+ ```bash
94
+ convos init --env production
95
+ ```
96
+
97
+ Configuration is loaded in priority order:
98
+
99
+ 1. CLI flags (highest)
100
+ 2. `--env-file <path>`
101
+ 3. `.env` in current directory
102
+ 4. `~/.convos/.env` (default)
103
+
104
+ ## Command Topics
105
+
106
+ | Topic | Purpose |
107
+ | ----- | ------- |
108
+ | `agent` | Agent mode — long-running sessions with streaming I/O |
109
+ | `identity` | Manage per-conversation identities (inboxes) |
110
+ | `conversations` | List, create, join, and stream conversations |
111
+ | `conversation` | Interact with a specific conversation |
112
+
113
+ Run `convos --help` for all commands, or `convos <command> --help` for details on a specific command.
114
+
115
+ ## Agent Mode
116
+
117
+ The `agent serve` command runs a single long-running process that combines conversation management, message streaming, join request processing, and command handling — purpose-built for AI agents and bots.
118
+
119
+ ```bash
120
+ # Create a new conversation and start serving
121
+ convos agent serve --name "My Bot" --profile-name "Assistant"
122
+
123
+ # Attach to an existing conversation
124
+ convos agent serve <conversation-id>
125
+ ```
126
+
127
+ ### Why Agent Mode?
128
+
129
+ Without `agent serve`, an agent has to juggle multiple processes:
130
+ - `convos conversation stream` for incoming messages
131
+ - `convos conversations process-join-requests --watch` for new members
132
+ - `convos conversation send-text` for each outgoing message (spawning a new process each time)
133
+
134
+ `agent serve` replaces all of that with a single process using an **ndjson** (newline-delimited JSON) protocol on stdin/stdout.
135
+
136
+ ### Protocol
137
+
138
+ **stdout** emits one JSON object per line:
139
+
140
+ | Event | Description | Key Fields |
141
+ | ----- | ----------- | ---------- |
142
+ | `ready` | Session initialized | `conversationId`, `inviteUrl`, `inboxId` |
143
+ | `message` | Incoming message | `id`, `senderInboxId`, `content`, `contentType`, `sentAt` |
144
+ | `member_joined` | New member added | `inboxId`, `conversationId` |
145
+ | `sent` | Outgoing message confirmed | `id`, `text` or `type` + details |
146
+ | `error` | Something went wrong | `message` |
147
+
148
+ **stdin** accepts one JSON command per line:
149
+
150
+ | Command | Required Fields | Optional Fields |
151
+ | ------- | --------------- | --------------- |
152
+ | `send` | `text` | `replyTo` (message ID) |
153
+ | `react` | `messageId`, `emoji` | `action` (`add`/`remove`, default `add`) |
154
+ | `attach` | `file` (local path) | `mimeType`, `replyTo` |
155
+ | `remote-attach` | `url`, `contentDigest`, `secret`, `salt`, `nonce`, `contentLength` | `filename`, `scheme` |
156
+ | `stop` | — | — |
157
+
158
+ **stderr** receives the QR code and diagnostic logs (never interferes with the JSON protocol).
159
+
160
+ ### Example: Echo Bot
161
+
162
+ ```bash
163
+ #!/usr/bin/env bash
164
+ # Start agent, read events, echo back every message
165
+ convos agent serve --name "Echo Bot" --profile-name "🤖 Echo" | \
166
+ while IFS= read -r event; do
167
+ type=$(echo "$event" | jq -r '.event')
168
+ case "$type" in
169
+ ready)
170
+ echo "Bot ready! Invite: $(echo "$event" | jq -r '.inviteUrl')" >&2
171
+ ;;
172
+ message)
173
+ content=$(echo "$event" | jq -r '.content')
174
+ msg_id=$(echo "$event" | jq -r '.id')
175
+ # Echo the message back as a reply
176
+ echo "{\"type\":\"send\",\"text\":\"You said: $content\",\"replyTo\":\"$msg_id\"}"
177
+ ;;
178
+ member_joined)
179
+ echo '{"type":"send","text":"Welcome! 👋"}'
180
+ ;;
181
+ esac
182
+ done
183
+ ```
184
+
185
+ ### Sending Reactions
186
+
187
+ ```bash
188
+ # React to a message
189
+ echo '{"type":"react","messageId":"abc123","emoji":"👍"}'
190
+
191
+ # Remove a reaction
192
+ echo '{"type":"react","messageId":"abc123","emoji":"👍","action":"remove"}'
193
+ ```
194
+
195
+ ### Sending Attachments
196
+
197
+ ```bash
198
+ # Send a file (≤1MB sent inline, larger files auto-uploaded via provider)
199
+ echo '{"type":"attach","file":"./chart.png"}'
200
+
201
+ # Reply with an attachment
202
+ echo '{"type":"attach","file":"./report.pdf","replyTo":"abc123"}'
203
+
204
+ # Send a pre-uploaded encrypted file
205
+ echo '{"type":"remote-attach","url":"https://...","contentDigest":"...","secret":"...","salt":"...","nonce":"...","contentLength":12345}'
206
+ ```
207
+
208
+ ### Agent Flags
209
+
210
+ | Flag | Description |
211
+ | ---- | ----------- |
212
+ | `--name` | Conversation name (when creating new) |
213
+ | `--description` | Conversation description (when creating new) |
214
+ | `--permissions` | `all-members` or `admin-only` (when creating new) |
215
+ | `--profile-name` | Display name for this conversation |
216
+ | `--identity` | Use an existing unlinked identity |
217
+ | `--label` | Local label for the identity |
218
+ | `--no-invite` | Skip generating an invite (attach mode only) |
219
+
220
+ ## Usage Examples
221
+
222
+ ### Identity Management
223
+
224
+ Each conversation has its own XMTP identity (wallet + inbox). Identities are created automatically when you create or join a conversation, but you can also manage them directly.
225
+
226
+ ```bash
227
+ # List all identities
228
+ convos identity list
229
+
230
+ # Create an identity manually
231
+ convos identity create --label "Work Chat" --profile-name "Alice"
232
+
233
+ # View identity details (connects to XMTP to show inbox ID)
234
+ convos identity info <identity-id>
235
+
236
+ # Remove an identity (destroys all keys — irreversible)
237
+ convos identity remove <identity-id> --force
238
+ ```
239
+
240
+ ### Conversations
241
+
242
+ ```bash
243
+ # Create a conversation (auto-creates per-conversation identity)
244
+ convos conversations create --name "Project Team" --profile-name "Alice"
245
+
246
+ # Create with admin-only permissions
247
+ convos conversations create --name "Announcement Channel" --permissions admin-only
248
+
249
+ # List all conversations across all identities
250
+ convos conversations list --sync
251
+
252
+ # Sync all conversations from the network
253
+ convos conversations sync
254
+ ```
255
+
256
+ ### Invites
257
+
258
+ Convos uses a serverless invite system. The creator generates a cryptographic invite slug; the joiner sends a DM join request; the creator's client processes it and adds them to the group.
259
+
260
+ #### Creating Invites
261
+
262
+ ```bash
263
+ # Generate an invite — displays a QR code in the terminal
264
+ convos conversation invite <conversation-id>
265
+
266
+ # Invite that expires in 1 hour
267
+ convos conversation invite <conversation-id> --expires-in 3600
268
+
269
+ # Single-use invite
270
+ convos conversation invite <conversation-id> --single-use
271
+
272
+ # JSON output (suppresses QR code)
273
+ convos conversation invite <conversation-id> --json
274
+ ```
275
+
276
+ #### Joining via Invite
277
+
278
+ ```bash
279
+ # Join using a raw invite slug
280
+ convos conversations join <invite-slug>
281
+
282
+ # Join using a full invite URL
283
+ convos conversations join "https://dev.convos.org/v2?i=<slug>"
284
+
285
+ # Join with a display name
286
+ convos conversations join <slug> --profile-name "Bob"
287
+
288
+ # Send join request without waiting for acceptance
289
+ convos conversations join <slug> --no-wait
290
+
291
+ # Wait up to 2 minutes
292
+ convos conversations join <slug> --timeout 120
293
+ ```
294
+
295
+ #### Processing Join Requests (Creator Side)
296
+
297
+ The creator's client must be running to process incoming join requests:
298
+
299
+ ```bash
300
+ # Process all pending join requests
301
+ convos conversations process-join-requests
302
+
303
+ # Continuously watch for join requests
304
+ convos conversations process-join-requests --watch
305
+
306
+ # Process for a specific conversation only
307
+ convos conversations process-join-requests --conversation <id>
308
+ ```
309
+
310
+ ### Messages
311
+
312
+ ```bash
313
+ # Send different message types
314
+ convos conversation send-text <id> "Hello!"
315
+ convos conversation send-reaction <id> <message-id> add "👍"
316
+ convos conversation send-reply <id> <message-id> "I agree!"
317
+
318
+ # Read messages
319
+ convos conversation messages <id> --sync --limit 10
320
+
321
+ # Stream messages in real-time
322
+ convos conversation stream <id>
323
+ convos conversation stream <id> --timeout 60
324
+ ```
325
+
326
+ ### Attachments
327
+
328
+ ```bash
329
+ # Send a photo (small files ≤1MB sent inline)
330
+ convos conversation send-attachment <id> ./photo.jpg
331
+
332
+ # Large files are automatically encrypted and uploaded via configured provider
333
+ convos conversation send-attachment <id> ./video.mp4
334
+
335
+ # Force remote upload even for small files
336
+ convos conversation send-attachment <id> ./photo.jpg --remote
337
+
338
+ # Override MIME type
339
+ convos conversation send-attachment <id> ./file.bin --mime-type image/png
340
+
341
+ # Per-command upload provider (no .env needed)
342
+ convos conversation send-attachment <id> ./photo.jpg \
343
+ --upload-provider pinata --upload-provider-token <jwt>
344
+
345
+ # Encrypt only (for manual upload workflows)
346
+ convos conversation send-attachment <id> ./photo.jpg --encrypt
347
+
348
+ # Send a pre-uploaded encrypted file
349
+ convos conversation send-remote-attachment <id> <url> \
350
+ --content-digest <hex> --secret <base64> --salt <base64> \
351
+ --nonce <base64> --content-length <bytes>
352
+
353
+ # Download an attachment (handles both inline and remote transparently)
354
+ convos conversation download-attachment <id> <message-id>
355
+
356
+ # Download to a specific path
357
+ convos conversation download-attachment <id> <message-id> --output ./photo.jpg
358
+
359
+ # Reply with a photo
360
+ convos conversation send-reply <id> <message-id> --file ./photo.jpg
361
+ ```
362
+
363
+ To configure an upload provider for large files, add to your `~/.convos/.env`:
364
+
365
+ ```bash
366
+ CONVOS_UPLOAD_PROVIDER=pinata
367
+ CONVOS_UPLOAD_PROVIDER_TOKEN=<your-pinata-jwt>
368
+ # Optional: custom gateway URL
369
+ CONVOS_UPLOAD_PROVIDER_GATEWAY=https://your-gateway.mypinata.cloud
370
+ ```
371
+
372
+ Supported upload providers: `pinata`
373
+
374
+ ### Profiles
375
+
376
+ Each conversation has independent profiles — you can be a different person in each conversation. Profiles are stored in the group's metadata and visible to all members.
377
+
378
+ ```bash
379
+ # Set your display name in a conversation
380
+ convos conversation update-profile <id> --name "Alice"
381
+
382
+ # Set name and avatar
383
+ convos conversation update-profile <id> --name "Alice" --image "https://example.com/avatar.jpg"
384
+
385
+ # Go anonymous (clear profile)
386
+ convos conversation update-profile <id> --name "" --image ""
387
+
388
+ # View all member profiles
389
+ convos conversation profiles <id>
390
+ convos conversation profiles <id> --json
391
+ ```
392
+
393
+ ### Group Management
394
+
395
+ ```bash
396
+ # View members
397
+ convos conversation members <id>
398
+
399
+ # Add/remove members
400
+ convos conversation add-members <id> <inbox-id>
401
+ convos conversation remove-members <id> <inbox-id>
402
+
403
+ # Update metadata
404
+ convos conversation update-name <id> "New Name"
405
+ convos conversation update-description <id> "New description"
406
+
407
+ # View permissions
408
+ convos conversation permissions <id>
409
+ ```
410
+
411
+ ### Lock a Conversation
412
+
413
+ Prevent new members from being added:
414
+
415
+ ```bash
416
+ convos conversation lock <id>
417
+ convos conversation lock <id> --unlock
418
+ ```
419
+
420
+ ### Explode a Conversation
421
+
422
+ Permanently destroy a conversation and all its cryptographic keys:
423
+
424
+ ```bash
425
+ # Explode immediately
426
+ convos conversation explode <id> --force
427
+
428
+ # Schedule explosion for a future date
429
+ convos conversation explode <id> --scheduled "2025-03-01T00:00:00Z"
430
+ ```
431
+
432
+ Exploding sends an `ExplodeSettings` notification to all members (so iOS and other clients trigger their cleanup flow), updates group metadata with the expiration timestamp, removes all members, then destroys the local identity. The conversation becomes unreadable.
433
+
434
+ When using `--scheduled`, members are notified but not removed — clients handle cleanup when the time arrives.
435
+
436
+ ### JSON Output
437
+
438
+ All commands support `--json` for machine-readable output:
439
+
440
+ ```bash
441
+ # Create a conversation and capture the ID
442
+ CONV_ID=$(convos conversations create --name "Test" --json | jq -r '.conversationId')
443
+
444
+ # Send a message
445
+ convos conversation send-text "$CONV_ID" "Hello!"
446
+
447
+ # Read messages as JSON
448
+ convos conversation messages "$CONV_ID" --sync --json
449
+
450
+ # Generate invite and capture the URL
451
+ INVITE_URL=$(convos conversation invite "$CONV_ID" --json | jq -r '.url')
452
+ ```
453
+
454
+ ### Verbose Output
455
+
456
+ Use `--verbose` to see detailed client initialization info. When combined with `--json`, verbose logs go to stderr:
457
+
458
+ ```bash
459
+ convos identity info <id> --verbose
460
+ ```
461
+
462
+ ## Data Directory
463
+
464
+ ```
465
+ ~/.convos/
466
+ ├── .env # Global config (env only)
467
+ ├── identities/
468
+ │ ├── <id-1>.json # Identity: wallet key, db key, conversation link
469
+ │ └── <id-2>.json
470
+ └── db/
471
+ └── dev/ # XMTP databases by environment
472
+ ├── <id-1>.db3
473
+ └── <id-2>.db3
474
+ ```
475
+
476
+ ## Architecture
477
+
478
+ ```
479
+ ┌──────────────────────────────────────────┐
480
+ │ @xmtp/convos-cli │
481
+ │ │
482
+ │ Commands: │
483
+ │ agent serve (long-running bot mode) │
484
+ │ identity create/list/info/remove │
485
+ │ conversations create/join/list/sync │
486
+ │ conversation invite/explode/lock │
487
+ │ conversation send-text/stream/... │
488
+ │ conversation send-attachment/download │
489
+ │ conversation update-profile/profiles │
490
+ │ │
491
+ │ ┌────────────────────────────────────┐ │
492
+ │ │ @xmtp/node-sdk │ │
493
+ │ │ │ │
494
+ │ │ Per-conversation XMTP clients │ │
495
+ │ │ Group/DM management │ │
496
+ │ │ Message encryption & delivery │ │
497
+ │ └────────────────────────────────────┘ │
498
+ └──────────────────────────────────────────┘
499
+ ```
500
+
501
+ ## Library Usage
502
+
503
+ `@xmtp/convos-cli` exports its core functionality for use in other applications:
504
+
505
+ ```typescript
506
+ import {
507
+ createIdentityStore,
508
+ createClientForIdentity,
509
+ createInviteSlug,
510
+ parseInvite,
511
+ verifyInvite,
512
+ parseAppData,
513
+ serializeAppData,
514
+ upsertProfile,
515
+ ConvosBaseCommand,
516
+ } from "@xmtp/convos-cli";
517
+ ```
518
+
519
+ See the [exports](./src/index.ts) for the full API.
520
+
521
+ ## AI Coding Agent Skill
522
+
523
+ This package includes an [agent skill](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview) (`skills/convos-cli/SKILL.md`) that teaches AI coding agents how to use the Convos CLI.
524
+
525
+ **Claude Code**
526
+
527
+ Add the skill directory to your project's `.claude/settings.json`:
528
+
529
+ ```json
530
+ {
531
+ "skills": ["./node_modules/@xmtp/convos-cli/skills"]
532
+ }
533
+ ```
534
+
535
+ **Other agents** (Cursor, Windsurf, Codex, etc.)
536
+
537
+ Use [openskills](https://github.com/numman-ali/openskills) to install the skill:
538
+
539
+ ```bash
540
+ npx openskills install ./node_modules/@xmtp/convos-cli/skills
541
+ ```
542
+
543
+ Or point your agent to `node_modules/@xmtp/convos-cli/skills/convos-cli/SKILL.md` directly.
544
+
545
+ ## Testing
546
+
547
+ ```bash
548
+ # Run all tests (fast, no network required)
549
+ npm test
550
+
551
+ # Watch mode
552
+ npm run test:watch
553
+ ```
554
+
555
+ ## Development
556
+
557
+ ```bash
558
+ # Install dependencies
559
+ npm install
560
+
561
+ # Build TypeScript
562
+ npm run build
563
+
564
+ # Dev mode (tsx, no build needed)
565
+ npm run dev -- conversations list
566
+
567
+ # Run built version
568
+ npm start -- conversations list
569
+
570
+ # Type check without emitting
571
+ npm run typecheck
572
+ ```
package/bin/dev.js ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { execute } from "@oclif/core";
3
+
4
+ await execute({ development: true, dir: import.meta.url });
package/bin/run.js ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { execute } from "@oclif/core";
3
+
4
+ await execute({ dir: import.meta.url });
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Base command for Convos CLI.
3
+ *
4
+ * Provides:
5
+ * - Common flags (--env, --json, --log-level, etc.)
6
+ * - output() and streamOutput() helpers
7
+ * - Config loading from .env files
8
+ *
9
+ * Convos adds: per-conversation identity resolution. Instead of a
10
+ * single wallet key, each conversation has its own identity with
11
+ * its own keys. Commands use getConvosConfig() + the identity store.
12
+ */
13
+ import { Command } from "@oclif/core";
14
+ import type { ConvosConfig } from "./utils/config.js";
15
+ export declare class ConvosBaseCommand extends Command {
16
+ #private;
17
+ /** Flags shared by all commands. */
18
+ static commonFlags: {
19
+ "env-file": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
20
+ env: import("@oclif/core/interfaces").OptionFlag<"local" | "dev" | "production" | undefined, import("@oclif/core/interfaces").CustomOptions>;
21
+ "gateway-host": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
22
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
23
+ verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
24
+ };
25
+ /** Full flag set for commands that create a client. */
26
+ static baseFlags: {
27
+ "log-level": import("@oclif/core/interfaces").OptionFlag<"off" | "error" | "warn" | "info" | "debug" | "trace" | undefined, import("@oclif/core/interfaces").CustomOptions>;
28
+ "structured-logging": import("@oclif/core/interfaces").BooleanFlag<boolean>;
29
+ "app-version": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
30
+ "env-file": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
31
+ env: import("@oclif/core/interfaces").OptionFlag<"local" | "dev" | "production" | undefined, import("@oclif/core/interfaces").CustomOptions>;
32
+ "gateway-host": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
33
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
34
+ verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
35
+ };
36
+ jsonOutput: boolean;
37
+ verbose: boolean;
38
+ init(): Promise<void>;
39
+ output(data: unknown): void;
40
+ streamOutput(data: unknown): void;
41
+ parseBigInt(value: string | undefined, flagName: string): bigint | undefined;
42
+ confirmAction(message: string, force?: boolean): Promise<void>;
43
+ getConvosConfig(): ConvosConfig;
44
+ run(): Promise<void>;
45
+ catch(error: Error): never;
46
+ }