@towns-labs/wallet 7.1.0 → 7.3.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.
package/README.md CHANGED
@@ -1,468 +1,579 @@
1
- # towns wallet-cli
1
+ # tw — Towns Wallet CLI
2
2
 
3
- CLI for `tw` account onboarding, session key lifecycle, and relayed transactions.
3
+ Your keys. Your account. No signup. No login. Just run it.
4
4
 
5
- Built on [incur](https://github.com/wevm/incur) every command supports `--help`, `--json`, `--format`, and can run as an MCP server via `--mcp`.
6
-
7
- ## Run with bunx
5
+ `tw` is a local-first CLI for managing smart accounts, session keys, and on-chain permissions on Towns Protocol. It works for humans at the terminal and for agents over `--json` or `--mcp`.
8
6
 
9
7
  ```bash
10
8
  bunx @towns-labs/wallet --help
11
9
  ```
12
10
 
13
- ## Permissionless
11
+ ---
14
12
 
15
- `tw` is fully permissionless: no signup, no account registration, and no login flow. You can run it immediately with local keys.
13
+ ## Quick Start
16
14
 
17
- ## Output Modes
15
+ Create an account and send USDC in under a minute:
18
16
 
19
- incur handles output formatting automatically:
17
+ ```bash
18
+ # 1. Create a local account (interactive password prompt)
19
+ tw account create --profile main
20
20
 
21
- - `--json` structured JSON output
22
- - `--format table` tabular output
23
- - Default: human-readable text
21
+ # 2. Fund it
22
+ tw address --qr --amount 100
24
23
 
25
- ## Help and Discovery
24
+ # 3. Send USDC
25
+ tw account send 10 vitalik.eth
26
+ ```
26
27
 
27
- ```bash
28
- # Show all commands
29
- tw --help
28
+ No custody service. No API key. Everything runs locally with encrypted keystores.
30
29
 
31
- # Show help for a specific command
32
- tw account create --help
30
+ ---
33
31
 
34
- # Machine-readable command manifest (for LLMs/agents)
35
- tw --llms
32
+ ## How It Works
36
33
 
37
- # Run as an MCP server
38
- tw --mcp
34
+ `tw` manages a local keystore that holds your root key and session keys. Your root key creates and controls your on-chain smart account. Session keys are scoped signers — they can send transactions through the Towns relayer without exposing your root key.
39
35
 
40
- # Version
41
- tw --version
36
+ ```text
37
+ ~/.config/towns/tw/profiles/<env>/<profile>/default.keystore.json
38
+ ~/.config/towns/tw/profiles/<env>/<profile>/sessions/<session-name>.json
42
39
  ```
43
40
 
44
- ## Account Create
41
+ For agents, the session daemon keeps decrypted keys in memory for a bounded duration so automated workflows can sign without prompting for a password on every call.
42
+
43
+ ---
44
+
45
+ ## Commands
46
+
47
+ ### Account
45
48
 
46
- Create a new account (interactive password prompt):
49
+ #### `account create` — Create a new account
47
50
 
48
51
  ```bash
49
- tw account create
52
+ tw account create --profile agent
50
53
  ```
51
54
 
52
- Create a named profile in local dev:
55
+ Resume a previously interrupted flow:
53
56
 
54
57
  ```bash
55
- tw account create --env dev --profile agent
58
+ tw account create --resume --profile agent
56
59
  ```
57
60
 
58
- Keystore layout:
61
+ Non-interactive (stdin password + JSON):
59
62
 
60
- ```text
61
- ~/.config/towns/tw/profiles/<env>/<profile>/default.keystore.json
62
- ~/.config/towns/tw/profiles/<env>/<profile>/sessions/<session-name>.json
63
+ ```bash
64
+ echo "my-password" | tw account create --password-stdin --json
63
65
  ```
64
66
 
65
- Resume a previously created profile:
67
+ Use an explicit keystore path:
66
68
 
67
69
  ```bash
68
- tw account create --resume --env dev --profile agent
70
+ tw account create --keystore-path ~/.config/towns/tw/profiles/prod/team/default.keystore.json
69
71
  ```
70
72
 
71
- Non-interactive mode (stdin password + JSON output):
73
+ #### `account status` Check readiness
72
74
 
73
75
  ```bash
74
- echo "my-password" | tw account create --password-stdin --json
76
+ tw account status --profile agent --json
75
77
  ```
76
78
 
77
- Use an explicit keystore path:
79
+ #### `account balance` Check USDC balance
78
80
 
79
81
  ```bash
80
- tw account create --keystore-path ~/.config/towns/tw/profiles/dev/team/default.keystore.json --env dev
82
+ tw account balance --profile agent
83
+ tw account balance --profile agent --chain polygon
81
84
  ```
82
85
 
83
- ## Account Export
84
-
85
- Export metadata only (safe default):
86
+ #### `account address` — Print root address
86
87
 
87
88
  ```bash
88
- tw account export --env dev --profile agent
89
+ tw account address --profile agent
89
90
  ```
90
91
 
91
- Export metadata in JSON:
92
+ #### `account send` — Send USDC
92
93
 
93
94
  ```bash
94
- tw account export --env dev --profile agent --json
95
+ tw account send 1 0x1111111111111111111111111111111111111111
96
+ tw account send 2.5 vitalik.eth --chain base
97
+ tw account send 10 treasury --chain polygon --json
95
98
  ```
96
99
 
97
- Export decrypted private keys (interactive confirmation required):
100
+ Use a specific local session (without changing active session):
98
101
 
99
102
  ```bash
100
- tw account export --env dev --profile agent --show-private
103
+ tw account send 1 0x... --profile agent --session worker-2
101
104
  ```
102
105
 
103
- ## Account Address
104
-
105
- Print the main/root account address:
106
+ Use a portable session file (no root keystore required):
106
107
 
107
108
  ```bash
108
- tw account address --env dev --profile agent
109
+ tw account send 1 0x... --chain base --session-file ./worker-1.session.json
109
110
  ```
110
111
 
111
- ## Address (Root Alias)
112
+ `--session` and `--session-file` are mutually exclusive.
112
113
 
113
- `tw address` is a root alias for `tw account address` with optional funding display helpers.
114
+ #### `account swap` Swap tokens on the same chain
114
115
 
115
- Print address + default funding context (USDC on Base):
116
+ Powered by [relay.link](https://relay.link). Interactive confirmation by default.
116
117
 
117
118
  ```bash
118
- tw address
119
+ tw account swap --from ETH --to USDC --amount 0.1 --chain base
120
+ tw account swap --from USDC --to ETH --amount 50 --chain base --yes --json
119
121
  ```
120
122
 
121
- Show a funding payment link:
123
+ #### `account bridge` Bridge tokens cross-chain
122
124
 
123
125
  ```bash
124
- tw address --link --amount 100
126
+ tw account bridge --token USDC --amount 100 --to-chain polygon
127
+ tw account bridge --token ETH --amount 0.5 --to-chain base --recipient 0x... --yes --json
125
128
  ```
126
129
 
127
- Show a QR for the same payment payload:
130
+ #### `account delegate` Delegate on additional chains
131
+
132
+ If your account was created on Base and you need it on Polygon:
128
133
 
129
134
  ```bash
130
- tw address --qr --amount 100
135
+ echo "my-password" | tw account delegate --chain polygon --profile agent --password-stdin
131
136
  ```
132
137
 
133
- Custom token amount requires explicit decimals:
138
+ #### `account history` Relayer call history
134
139
 
135
140
  ```bash
136
- tw address --token 0x1111111111111111111111111111111111111111 --amount 1 --decimals 18 --link
141
+ tw account history --profile agent
142
+ tw account history --address 0x... --limit 10 --offset 20
143
+ tw account history --chain base,polygon --json
137
144
  ```
138
145
 
139
- ## Account Balance
146
+ `--limit` defaults to 20 (max 100). `offset + limit` must be <= 1000.
147
+
148
+ #### `account export` — Export metadata or private keys
149
+
150
+ ```bash
151
+ tw account export --profile agent --json
152
+ tw account export --profile agent --show-private
153
+ ```
140
154
 
141
- Check USDC balance for the main/root account on Base (default):
155
+ #### `account nonce` Read account nonce
142
156
 
143
157
  ```bash
144
- tw account balance --env dev --profile agent
158
+ tw account nonce --profile agent
145
159
  ```
146
160
 
147
- Check USDC balance on Polygon:
161
+ #### `account update password` — Rotate keystore password
148
162
 
149
163
  ```bash
150
- tw account balance --env prod --profile agent --chain polygon
164
+ tw account update password --profile agent
165
+ printf "old\nnew\n" | tw account update password --current-password-stdin --new-password-stdin --json
151
166
  ```
152
167
 
153
- For local dev (`--env dev`), default chain is Anvil (`http://127.0.0.1:8545`).
168
+ ---
154
169
 
155
- ## Account Send
170
+ ### Address
156
171
 
157
- Send USDC to an address:
172
+ `tw address` is a top-level shortcut for showing your funding address with optional payment helpers.
158
173
 
159
174
  ```bash
160
- tw account send 1 0x1111111111111111111111111111111111111111
175
+ tw address
176
+ tw address --link --amount 100
177
+ tw address --qr --amount 100
161
178
  ```
162
179
 
163
- Send USDC to ENS on Base:
180
+ Custom token:
164
181
 
165
182
  ```bash
166
- tw account send 2.5 vitalik.eth --chain base
183
+ tw address --token 0x... --amount 1 --decimals 18 --link
167
184
  ```
168
185
 
169
- Send USDC on Polygon with JSON output:
186
+ ---
187
+
188
+ ### Session Keys
189
+
190
+ Session keys are scoped signers that can act on behalf of your account without exposing the root key.
191
+
192
+ #### `session create` — Create and authorize a session key
170
193
 
171
194
  ```bash
172
- tw account send 10 0x1111111111111111111111111111111111111111 --chain polygon --env prod --json
195
+ echo "my-password" | tw session create worker-1 --profile agent --password-stdin --json
173
196
  ```
174
197
 
175
- Send using a specific local session by name (without changing active session):
198
+ Create and activate immediately:
176
199
 
177
200
  ```bash
178
- tw account send 1 0x1111111111111111111111111111111111111111 --profile agent --session worker-2
201
+ echo "my-password" | tw session create worker-2 --profile agent --activate --password-stdin
179
202
  ```
180
203
 
181
- Local dev defaults to Anvil:
204
+ Grant full wildcard access:
182
205
 
183
206
  ```bash
184
- tw account send 1 0x1111111111111111111111111111111111111111 --env dev
207
+ echo "my-password" | tw session create worker-admin --profile agent --full-access --password-stdin
185
208
  ```
186
209
 
187
- ## Contacts
210
+ `--full-access` is mutually exclusive with `--target`, `--selector`, `--spend-limit`, `--spend-limit-raw`, and `--spend-period`. Omitting both `--target` and `--selector` uses wildcard call permissions by default.
188
211
 
189
- Store aliases in a global contacts file:
212
+ Resume an interrupted flow:
190
213
 
191
- ```text
192
- ~/.config/towns/tw/contacts.json
214
+ ```bash
215
+ echo "my-password" | tw session create worker-1 --profile agent --resume --password-stdin --json
193
216
  ```
194
217
 
195
- Add contact aliases:
218
+ #### `session list` — List local sessions
196
219
 
197
220
  ```bash
198
- tw contacts add vitalik vitalik.eth
199
- tw contacts add treasury 0x1111111111111111111111111111111111111111
221
+ tw session list --profile agent --json
222
+ tw session list --profile agent --on-chain --json
200
223
  ```
201
224
 
202
- List or show contacts:
225
+ #### `session rotate` — Rotate the active session
203
226
 
204
227
  ```bash
205
- tw contacts list --json
206
- tw contacts show vitalik --json
228
+ echo "my-password" | tw session rotate --profile agent --password-stdin --json
229
+ echo "my-password" | tw session rotate --profile agent --new-name worker-3 --password-stdin
230
+ echo "my-password" | tw session rotate --profile agent --resume --password-stdin --json
207
231
  ```
208
232
 
209
- Update, rename, and remove:
233
+ #### `session revoke` — Revoke a session on-chain
210
234
 
211
235
  ```bash
212
- tw contacts update vitalik 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
213
- tw contacts rename vitalik vitalik-main
214
- tw contacts remove vitalik-main
236
+ echo "my-password" | tw session revoke worker-1 --profile agent --password-stdin --json
237
+ echo "my-password" | tw session revoke worker-2 --profile agent --force --password-stdin
238
+ echo "my-password" | tw session revoke worker-2 --profile agent --resume --password-stdin --json
215
239
  ```
216
240
 
217
- Export and import:
241
+ #### `session export` — Export as portable file
218
242
 
219
243
  ```bash
220
- tw contacts export --json
221
- tw contacts import ./contacts.json --json
222
- tw contacts import ./contacts.json --force --json
244
+ TW_PASSWORD="my-password" TW_EXPORT_PASSWORD="export-password" \
245
+ tw session export worker-1 --profile agent --output ./worker-1.session.json
223
246
  ```
224
247
 
225
- Import returns deterministic summary fields:
248
+ Or via stdin:
226
249
 
227
- - `importedCount`
228
- - `skippedInvalidCount`
229
- - `skippedConflictCount`
230
- - `overwrittenCount`
250
+ ```bash
251
+ echo "export-password" | tw session export worker-1 --profile agent \
252
+ --output ./worker-1.session.json --export-password-stdin
253
+ ```
231
254
 
232
- Send via alias:
255
+ #### `session import` — Import a portable session
233
256
 
234
257
  ```bash
235
- tw account send 10 vitalik
258
+ tw session import ./worker-1.session.json --profile worker-1
236
259
  ```
237
260
 
238
- ENS safety behavior for ENS-backed contacts:
261
+ Creates a session-only profile that can execute `account send` but cannot run manager commands requiring a root keystore.
239
262
 
240
- - If ENS re-resolution fails, `tw account send` falls back to the stored address.
241
- - If ENS re-resolution succeeds but points to a different address than stored, send aborts and requires explicit `tw contacts update`.
263
+ ---
242
264
 
243
- Send with a portable session file (no root keystore required):
265
+ ### Session Daemon
266
+
267
+ The daemon holds decrypted session keys in memory so automated workflows can sign without re-entering passwords.
268
+
269
+ #### `session start` — Start the daemon
244
270
 
245
271
  ```bash
246
- tw account send 1 0x1111111111111111111111111111111111111111 \
247
- --env prod --chain base --session-file ./worker-1.session.json
272
+ tw session start --json
273
+ tw session start --foreground --json
248
274
  ```
249
275
 
250
- `--session` and `--session-file` are mutually exclusive.
276
+ Idempotent if already running, returns the active pid/socket.
251
277
 
252
- ## Account Status
253
-
254
- Show compact readiness status:
278
+ #### `session unlock` — Load a key into daemon memory
255
279
 
256
280
  ```bash
257
- tw account status --env dev --profile agent
281
+ echo "my-password" | tw session unlock worker-1 --profile agent --password-stdin --duration 15m --json
258
282
  ```
259
283
 
260
- JSON output for automation:
284
+ Key material stays in daemon memory only; encrypted files remain unchanged.
285
+
286
+ #### `session lock` — Remove a key from daemon memory
261
287
 
262
288
  ```bash
263
- tw account status --env prod --profile agent --chain polygon --json
289
+ tw session lock worker-1 --json
264
290
  ```
265
291
 
266
- ## Account Update Password
267
-
268
- Rotate local keystore encryption password (interactive):
292
+ #### `session status` — Check daemon health
269
293
 
270
294
  ```bash
271
- tw account update password --env dev --profile agent
295
+ tw session status --json
272
296
  ```
273
297
 
274
- Rotate password non-interactively using stdin lines:
298
+ #### `session stop` Shut down the daemon
275
299
 
276
300
  ```bash
277
- printf "old-password\nnew-password\n" | tw account update password --current-password-stdin --new-password-stdin --json
301
+ tw session stop --json
278
302
  ```
279
303
 
280
- ## Session Create
304
+ ---
305
+
306
+ ### Permissions
307
+
308
+ Fine-grained on-chain permission rules for session keys.
281
309
 
282
- Create and authorize a scoped session key in one intent:
310
+ #### `permissions list` List keys and their permissions
283
311
 
284
312
  ```bash
285
- echo "my-password" | tw session create worker-1 --profile agent --password-stdin --json
313
+ tw permissions list --profile agent --json
286
314
  ```
287
315
 
288
- Create and activate immediately:
316
+ #### `permissions show` — Show rules for a specific key
289
317
 
290
318
  ```bash
291
- echo "my-password" | tw session create worker-2 --profile agent --activate --password-stdin
319
+ tw permissions show agent-key --profile agent --json
320
+ tw permissions show --key-hash 0xaaa... --profile agent --json
292
321
  ```
293
322
 
294
- Resume a previously interrupted create flow:
323
+ #### `permissions grant` Grant a permission rule
324
+
325
+ Wildcard call permission:
295
326
 
296
327
  ```bash
297
- echo "my-password" | tw session create worker-1 --profile agent --resume --password-stdin --json
328
+ echo "my-password" | tw permissions grant agent-key --type call --target any --selector any --profile agent --password-stdin --json
298
329
  ```
299
330
 
300
- Grant full wildcard access (explicit opt-in):
331
+ Daily USDC spend limit:
301
332
 
302
333
  ```bash
303
- echo "my-password" | tw session create worker-admin --profile agent --full-access --password-stdin
334
+ echo "my-password" | tw permissions grant agent-key --type spend --token USDC --spend-limit 100 --period day --profile agent --password-stdin --json
304
335
  ```
305
336
 
306
- `--full-access` is mutually exclusive with `--target`, `--selector`, `--spend-limit`, `--spend-limit-raw`, and `--spend-period`.
307
- Omitting both `--target` and `--selector` uses wildcard call permissions by default; you do not need to pass magic wildcard values.
308
- `--spend-limit` accepts human USDC amounts (for example `10` = `10 USDC`). Use `--spend-limit-raw` for base units.
337
+ Use `--spend-limit-raw` for base units instead of human amounts.
309
338
 
310
- ## Session List
339
+ #### `permissions revoke` — Revoke permission rules
311
340
 
312
- List local sessions:
341
+ Revoke a single rule:
313
342
 
314
343
  ```bash
315
- tw session list --profile agent --json
344
+ echo "my-password" | tw permissions revoke agent-key --rule call:0x...:0xa9059cbb --profile agent --password-stdin --json
316
345
  ```
317
346
 
318
- Include on-chain key status:
347
+ Revoke all rules for a key:
319
348
 
320
349
  ```bash
321
- tw session list --profile agent --on-chain --json
350
+ echo "my-password" | tw permissions revoke agent-key --all --profile agent --password-stdin --json
322
351
  ```
323
352
 
324
- ## Session Export
353
+ ---
354
+
355
+ ### Escrow
356
+
357
+ USDC escrow: lock funds as buyer with a seller and oracle; settle (oracle signs) or refund after deadline.
325
358
 
326
- Export a session key as a portable file:
359
+ #### `escrow create` Create a new USDC escrow
327
360
 
328
361
  ```bash
329
- TW_PASSWORD="my-password" TW_EXPORT_PASSWORD="export-password" \
330
- tw session export worker-1 --profile agent --output ./worker-1.session.json
362
+ tw escrow create 50 0x1111111111111111111111111111111111111111 \
363
+ --oracle 0x2222222222222222222222222222222222222222 --deadline 24h
364
+ tw escrow create 100 0x... --oracle 0x... --deadline 2d --chain base --env prod --json
331
365
  ```
332
366
 
333
- Or provide the export password via stdin:
367
+ - **Amount** and **seller** are positional; **oracle** and **deadline** are required options.
368
+ - **Deadline**: relative (`1h`, `2d`, `30m`, `1w`) or unix timestamp. After deadline, anyone can call `escrow refund`.
369
+ - Optional **salt** (hex, up to 12 bytes) for unique escrow IDs on repeated orders.
370
+ - Uses session key (daemon or direct) to sign; supports `--session-file` like `account send`.
371
+
372
+ #### `escrow status` — Check on-chain status
334
373
 
335
374
  ```bash
336
- echo "export-password" | tw session export worker-1 --profile agent \
337
- --output ./worker-1.session.json --export-password-stdin
375
+ tw escrow status 0x<64 hex chars> --env prod
376
+ tw escrow status 0x... --chain base --json
338
377
  ```
339
378
 
340
- ## Session Import
379
+ Escrow ID must be the full 32-byte hex (0x + 64 hex chars), e.g. from `escrow create` output.
341
380
 
342
- Import a portable session as a session-only profile:
381
+ #### `escrow settle` Settle (release USDC to seller)
382
+
383
+ Oracle signs a settlement; any account can submit the signed settlement via relayer.
343
384
 
344
385
  ```bash
345
- tw session import ./worker-1.session.json --profile worker-1
386
+ TW_ORACLE_PRIVATE_KEY=0x... tw escrow settle 0x<escrowId> \
387
+ --settlement-id 0x<orderId> --oracle 0x2222... --profile agent
346
388
  ```
347
389
 
348
- This creates:
390
+ Or with pre-signed signature (oracle signs offline):
349
391
 
350
392
  ```bash
351
- ~/.config/towns/tw/profiles/worker-1/session.json
393
+ tw escrow settle 0x<escrowId> --settlement-id 0x... --oracle 0x... --signature 0x... --profile agent
352
394
  ```
353
395
 
354
- Session-only profiles can execute `account send` but cannot run manager commands that require a root keystore.
396
+ Settlement ID is the bytes32 order ID used at creation (see create output or `escrow status`).
355
397
 
356
- ## Session Rotate
398
+ #### `escrow refund` — Refund to buyer after deadline
357
399
 
358
- Rotate the active session (auto-generates new name):
400
+ Permissionless: after the escrow deadline, anyone can trigger refund to the buyer.
359
401
 
360
402
  ```bash
361
- echo "my-password" | tw session rotate --profile agent --password-stdin --json
403
+ tw escrow refund 0x<escrowId> --profile agent
404
+ tw escrow refund 0x<escrowId> --env prod --json
362
405
  ```
363
406
 
364
- Rotate to an explicit new session name:
407
+ ---
365
408
 
366
- ```bash
367
- echo "my-password" | tw session rotate --profile agent --new-name worker-3 --password-stdin
409
+ ### Contacts
410
+
411
+ Store recipient aliases so you never have to copy-paste addresses.
412
+
413
+ ```text
414
+ ~/.config/towns/tw/contacts.json
368
415
  ```
369
416
 
370
- `--full-access` is mutually exclusive with `--target`, `--selector`, `--spend-limit`, `--spend-limit-raw`, and `--spend-period`.
371
- Omitting both `--target` and `--selector` uses wildcard call permissions by default; you do not need to pass magic wildcard values.
372
- `--spend-limit` accepts human USDC amounts (for example `10` = `10 USDC`). Use `--spend-limit-raw` for base units.
417
+ ```bash
418
+ tw contacts add vitalik vitalik.eth
419
+ tw contacts add treasury 0x1111111111111111111111111111111111111111
420
+ tw contacts list --json
421
+ tw contacts show vitalik --json
422
+ tw contacts update vitalik 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
423
+ tw contacts rename vitalik vitalik-main
424
+ tw contacts remove vitalik-main
425
+ ```
373
426
 
374
- Resume interrupted rotation:
427
+ Export and import:
375
428
 
376
429
  ```bash
377
- echo "my-password" | tw session rotate --profile agent --resume --password-stdin --json
430
+ tw contacts export --json
431
+ tw contacts import ./contacts.json --json
432
+ tw contacts import ./contacts.json --force --json
378
433
  ```
379
434
 
380
- ## Session Revoke
435
+ Import returns `importedCount`, `skippedInvalidCount`, `skippedConflictCount`, and `overwrittenCount`.
381
436
 
382
- Revoke a non-active session on-chain, verify, then delete local file:
437
+ Send via alias:
383
438
 
384
439
  ```bash
385
- echo "my-password" | tw session revoke worker-1 --profile agent --password-stdin --json
440
+ tw account send 10 vitalik
386
441
  ```
387
442
 
388
- Force revoke active session:
443
+ ENS safety: if ENS re-resolves to a different address than stored, send aborts and requires `tw contacts update`.
389
444
 
390
- ```bash
391
- echo "my-password" | tw session revoke worker-2 --profile agent --force --password-stdin
445
+ ---
446
+
447
+ ### Agents
448
+
449
+ Agents are session-key-backed Towns identities with their own encryption device and named channel bindings — built for autonomous agent-to-agent communication.
450
+
451
+ ```text
452
+ ~/.config/towns/tw/profiles/<env>/<profile>/sessions/agent-<name>.json
453
+ ~/.config/towns/tw/profiles/<env>/<profile>/agent-channels.json
392
454
  ```
393
455
 
394
- Idempotent retry/cleanup when already revoked on-chain:
456
+ #### `agent create` / `agent list` / `agent remove`
395
457
 
396
458
  ```bash
397
- echo "my-password" | tw session revoke worker-2 --profile agent --resume --password-stdin --json
459
+ TW_PASSWORD="my-password" tw agent create alice --profile agent
460
+ TW_PASSWORD="my-password" tw agent create bob --profile agent
461
+ TW_PASSWORD="my-password" tw agent list --profile agent --json
462
+ TW_PASSWORD="my-password" tw agent remove bob --profile agent
398
463
  ```
399
464
 
400
- ## Permissions List
465
+ #### `agent connect` — Create or bind a named channel
401
466
 
402
- List all on-chain keys with summarized call/spend permissions:
467
+ First side creates the channel and returns the shared secret:
403
468
 
404
469
  ```bash
405
- tw permissions list --profile agent --json
470
+ TW_PASSWORD="my-password" tw agent connect --from alice --channel art --to bob --profile agent
406
471
  ```
407
472
 
408
- ## Permissions Show
409
-
410
- Show full permission rules for a key using positional `<key-ref>`:
473
+ Second side binds using that secret:
411
474
 
412
475
  ```bash
413
- tw permissions show agent-key --profile agent --json
476
+ TW_PASSWORD="my-password" tw agent connect --from bob --channel art --secret "<shared-secret>" --to alice --profile agent
414
477
  ```
415
478
 
416
- Explicit selectors are also supported:
479
+ #### `agent send` Send a message
480
+
481
+ To a named channel:
417
482
 
418
483
  ```bash
419
- tw permissions show --key-hash 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa --profile agent --json
484
+ TW_PASSWORD="my-password" tw agent send --from alice --channel art "hello from alice" --profile agent
420
485
  ```
421
486
 
422
- ## Permissions Grant
423
-
424
- Grant wildcard call permission:
487
+ To a raw stream ID:
425
488
 
426
489
  ```bash
427
- echo "my-password" | tw permissions grant agent-key --type call --target any --selector any --profile agent --password-stdin --json
490
+ TW_PASSWORD="my-password" tw agent send --from alice 77aaa... "debug message" --profile agent
428
491
  ```
429
492
 
430
- Grant spend permission for daily USDC limit:
493
+ #### `agent listen` Listen for messages
431
494
 
432
495
  ```bash
433
- echo "my-password" | tw permissions grant agent-key --type spend --token USDC --spend-limit 100 --period day --profile agent --password-stdin --json
496
+ TW_PASSWORD="my-password" tw agent listen --from bob --channel art --profile agent
497
+ TW_PASSWORD="my-password" tw agent listen --from bob --stream 77aaa... --profile agent
498
+ ```
499
+
500
+ Messages arrive as NDJSON:
501
+
502
+ ```json
503
+ {
504
+ "type": "message",
505
+ "streamId": "77...",
506
+ "senderId": "0x...",
507
+ "eventId": "0x...",
508
+ "timestamp": 1709654400,
509
+ "content": "hello from alice"
510
+ }
434
511
  ```
435
512
 
436
- For raw base units instead of human USDC amounts, use:
513
+ #### `agent channels` Inspect bindings
437
514
 
438
515
  ```bash
439
- echo "my-password" | tw permissions grant agent-key --type spend --token USDC --spend-limit-raw 100000000 --period day --profile agent --password-stdin --json
516
+ TW_PASSWORD="my-password" tw agent channels --from alice --profile agent --json
440
517
  ```
441
518
 
442
- ## Permissions Revoke
519
+ #### Agent Quickstart
520
+
521
+ ```bash
522
+ # Create profile + two agents
523
+ tw account create --profile agent
524
+ TW_PASSWORD="pw" tw agent create alice --profile agent
525
+ TW_PASSWORD="pw" tw agent create bob --profile agent
526
+
527
+ # Alice creates a channel → copy the returned secret
528
+ TW_PASSWORD="pw" tw agent connect --from alice --channel art --to bob --profile agent
529
+
530
+ # Bob binds with that secret
531
+ TW_PASSWORD="pw" tw agent connect --from bob --channel art --secret "<secret>" --to alice --profile agent
443
532
 
444
- Revoke one rule by stable rule id:
533
+ # Terminal 1: listen
534
+ TW_PASSWORD="pw" tw agent listen --from bob --channel art --profile agent
535
+
536
+ # Terminal 2: send
537
+ TW_PASSWORD="pw" tw agent send --from alice --channel art "hello" --profile agent
538
+ ```
539
+
540
+ Smoke test:
445
541
 
446
542
  ```bash
447
- echo "my-password" | tw permissions revoke agent-key --rule call:0x2222222222222222222222222222222222222222:0xa9059cbb --profile agent --password-stdin --json
543
+ cd packages/wallet
544
+ TW_PASSWORD="my-password" bun run smoke:agent
448
545
  ```
449
546
 
450
- Revoke all call/spend rules for a key:
547
+ ---
548
+
549
+ ## Agent & Automation Integration
550
+
551
+ Every command supports `--json` for machine-readable output. Treat JSON output schemas as the stable contract.
451
552
 
452
553
  ```bash
453
- echo "my-password" | tw permissions revoke agent-key --all --profile agent --password-stdin --json
554
+ tw <command> --json
454
555
  ```
455
556
 
456
- ## Password Automation
557
+ ### Password Automation
457
558
 
458
- Use `TW_PASSWORD` for non-interactive flows:
559
+ Use `TW_PASSWORD` to skip interactive prompts:
459
560
 
460
561
  ```bash
461
562
  TW_PASSWORD="my-password" tw session list --profile agent --json
462
563
  ```
463
564
 
464
- Stdin is supported for commands requiring keystore decryption/signing:
565
+ Or pipe via stdin for commands that accept `--password-stdin`:
465
566
 
466
567
  ```bash
467
568
  echo "my-password" | tw session rotate --profile agent --password-stdin --json
468
569
  ```
570
+
571
+ ### Discovery
572
+
573
+ ```bash
574
+ tw --help # All commands
575
+ tw account send --help # Command-specific help
576
+ tw --llms # Machine-readable command manifest
577
+ tw --mcp # Run as MCP server
578
+ tw --version # Version
579
+ ```