agent-first-http 0.13.0

Give your AI agent its own private browser — so it reads the real page, past logins and bot walls, without ever touching yours.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
# afhttp CLI reference

<!-- Generated by `afhttp --docs`. Do not edit by hand. -->

Give your AI agent its own private browser — so it reads the real page, past logins and bot walls, without ever touching yours.

`afhttp` is compiled from a closed `cli-spec-v1` registry: one source for argv parsing, typed invocation values, which parameter combinations are legal, output contracts, and help. An invocation runs only when it matches exactly one registered combination.

## Global arguments

AFDATA registers these itself, so the syntax in [Commands](#commands) leaves them out.

| Argument | Where | What it does |
|---|---|---|
| `--help` | every command | Every legal shape of that command, complete, plus its subcommands. JSON by default; `--output plain` for a terminal. |
| `--version` | afhttp only | Name, version, and build identity as one protocol result. |
| `--docs` | afhttp only | This document, rendered from the registry. |
| `--output <FORMAT>` | per output contract | Render as json (default `json`). |
| `--output-to <DESTINATION>` | per output contract | Route results and diagnostics to split, stdout, stderr (default `split`). |
| `--stdout-file <PATH>`, `--stderr-file <PATH>` | per output contract | Append that stream to a file instead. |

Success output is protocol events, on those terms, unless a command's own **Output** line says otherwise.

A **shape** is one legal set of arguments that may appear together, under a stable id. Where a command has more than one, each id is a heading below. `--help` returns them all at once, so discovering a command costs one call; there is no recursive mode across commands, and this document is that view.

## Commands

- [`afhttp capabilities`](#afhttp-capabilities) — Query a host's /capabilities endpoint.
- [`afhttp cdp`](#afhttp-cdp) — Send one raw CDP method to a tab and return its result.
- [`afhttp container install`](#afhttp-container-install) — Build the host image if missing, run the container, and print the client command.
- [`afhttp container logs`](#afhttp-container-logs) — Capture the container logs, or stream them raw.
- [`afhttp container status`](#afhttp-container-status) — Report whether the host is running, with its endpoint and client command.
- [`afhttp container uninstall`](#afhttp-container-uninstall) — Stop and remove the container.
- [`afhttp fetch`](#afhttp-fetch) — Fetch a URL over HTTP or a real browser and write the requested artifacts.
- [`afhttp health`](#afhttp-health) — Query a host's /health endpoint.
- [`afhttp host`](#afhttp-host) — Run the browser host: launch a backend browser and serve /cdp for clients.
- [`afhttp panel`](#afhttp-panel) — Mint a short-lived takeover URL for a running takeover-ready host.
- [`afhttp profile cookies`](#afhttp-profile-cookies) — Show the non-expired cookies in a profile's jar, with values redacted.
- [`afhttp profile delete`](#afhttp-profile-delete) — Delete a profile and all of its on-disk state.
- [`afhttp profile downloads`](#afhttp-profile-downloads) — List files captured in a profile's browser download directory.
- [`afhttp profile info`](#afhttp-profile-info) — Show one profile's size, last use, and lock state.
- [`afhttp profile list`](#afhttp-profile-list) — List the on-disk profiles under the profiles root.
- [`afhttp profile lock-status`](#afhttp-profile-lock-status) — Report whether a profile is currently locked by a running host.
- [`afhttp profile prune`](#afhttp-profile-prune) — Delete profiles whose last use is older than a cutoff.
- [`afhttp skill install`](#afhttp-skill-install) — Install or refresh the Agent-First HTTP skill.
- [`afhttp skill status`](#afhttp-skill-status) — Show whether the Agent-First HTTP skill is installed, valid, and up to date.
- [`afhttp skill uninstall`](#afhttp-skill-uninstall) — Remove an afhttp-managed Agent-First HTTP skill.
- [`afhttp tabs close`](#afhttp-tabs-close) — Close one CDP target by its target id.
- [`afhttp tabs list`](#afhttp-tabs-list) — List the CDP targets currently attached to a host.
- [`afhttp ui takeover`](#afhttp-ui-takeover) — Put the takeover panel in front of a person and block until that session ends.
- [`afhttp upload`](#afhttp-upload) — Upload a local file into a browser tab's file input via DOM.setFileInputFiles.

### `afhttp capabilities`

Query a host's /capabilities endpoint.

```
afhttp capabilities [--endpoint-url <URL>] [--token-secret <SOURCE>]
```

| Argument | Meaning |
|---|---|
| `--endpoint-url` | CDP endpoint of a running host; falls back to AFHTTP_ENDPOINT_URL, then to the local afhttp-host container |
| `--token-secret` | Token for a protected host; falls back to AFHTTP_TOKEN_SECRET, then to the discovered host's own token (the value, or where to read it: env:NAME, file[+FORMAT]:PATH#DOT_PATH, container:NAME, literal:VALUE) |

### `afhttp cdp`

Send one raw CDP method to a tab and return its result.

```
afhttp cdp <METHOD> [--endpoint-url <URL>] [--token-secret <SOURCE>] --tab <TARGET_ID> [--params <JSON|@->] [--wait-event <EVENT:TIMEOUT>]
```

| Argument | Meaning |
|---|---|
| `METHOD` | CDP method name |
| `--endpoint-url` | CDP endpoint of a running host; falls back to AFHTTP_ENDPOINT_URL, then to the local afhttp-host container |
| `--token-secret` | Token for a protected host; falls back to AFHTTP_TOKEN_SECRET, then to the discovered host's own token (the value, or where to read it: env:NAME, file[+FORMAT]:PATH#DOT_PATH, container:NAME, literal:VALUE) |
| `--tab` | CDP target id to drive |
| `--params` | Method parameters as a JSON literal, or @- to read them from stdin |
| `--wait-event` | Wait for a CDP event before exiting, for example Page.loadEventFired:5s |

### `afhttp container install`

Build the host image if missing, run the container, and print the client command.

#### `container-install` — Build from the release pinned to this binary's version

```
afhttp container install [--runtime <docker|podman|apple>] [--name <NAME>] [--port <PORT>] [--profile <NAME>] [--shm-size <SIZE>] [--takeover-provider <off|kasmvnc>] [--with <lightpanda|fingerprint-chromium|camoufox|chrome|brave|kasmvnc>...] [--rebuild] [--reveal-token-secret] [<HOST_ARG>...]
```

#### `container-install-from-source` — Compile from a source checkout, which always rebuilds

```
afhttp container install [--runtime <docker|podman|apple>] [--name <NAME>] [--port <PORT>] [--profile <NAME>] [--shm-size <SIZE>] [--takeover-provider <off|kasmvnc>] [--with <lightpanda|fingerprint-chromium|camoufox|chrome|brave|kasmvnc>...] --from-source [--context <DIR>] [--reveal-token-secret] [<HOST_ARG>...]
```

Arguments across every shape above:

| Argument | Meaning |
|---|---|
| `--runtime` | Container runtime; auto-detected when omitted, then AFHTTP_CONTAINER_RUNTIME |
| `--name` | Container name |
| `--port` | Host CDP port, published on 127.0.0.1 |
| `--profile` | Initial profile inside the container; defaults to - for ephemeral |
| `--shm-size` | Chromium /dev/shm size; defaults to 1g, or 2g when takeover is on |
| `--takeover-provider` | Takeover provider for the built host; off builds a lean headless host |
| `--with` | Extra image component to build |
| `--rebuild` | Rebuild the image even if it already exists |
| `--from-source` | Compile the image from a source checkout instead of a prebuilt release |
| `--context` | Source checkout for --from-source; defaults to the current directory, then this binary's own checkout |
| `--reveal-token-secret` | Include the long-lived host token in the result instead of redacting it |
| `HOST_ARG` | Arguments forwarded to `afhttp host` inside the container, after -- |

### `afhttp container logs`

Capture the container logs, or stream them raw.

#### `container-logs` — Capture the logs to a file and return a JSON summary of the tail

```
afhttp container logs [--runtime <docker|podman|apple>] [--name <NAME>]
```

#### `container-logs-raw` — Forward the runtime's own log bytes; the only shape that can follow

```
afhttp container logs [--runtime <docker|podman|apple>] [--name <NAME>] [--follow] --raw
```

Output differs by combination:

- protocol events; `--output` json (default `json`), `--output-to` split/stdout/stderr (default `split`); redirect with `--stdout-file` or `--stderr-file`
- raw bytes on success; rejects `--output` and `--output-to`; redirect with `--stdout-file` or `--stderr-file`. Failures are still strict JSON on stderr

Arguments across every shape above:

| Argument | Meaning |
|---|---|
| `--runtime` | Container runtime; auto-detected when omitted, then AFHTTP_CONTAINER_RUNTIME |
| `--name` | Container name |
| `--follow` | Keep following the log output |
| `--raw` | Stream raw runtime logs instead of returning a JSON summary |

### `afhttp container status`

Report whether the host is running, with its endpoint and client command.

```
afhttp container status [--runtime <docker|podman|apple>] [--name <NAME>] [--port <PORT>] [--reveal-token-secret]
```

| Argument | Meaning |
|---|---|
| `--runtime` | Container runtime; auto-detected when omitted, then AFHTTP_CONTAINER_RUNTIME |
| `--name` | Container name |
| `--port` | Published host port, used to format the endpoint and client command |
| `--reveal-token-secret` | Include the long-lived host token in the result instead of redacting it |

### `afhttp container uninstall`

Stop and remove the container.

```
afhttp container uninstall [--runtime <docker|podman|apple>] [--name <NAME>] [--purge]
```

| Argument | Meaning |
|---|---|
| `--runtime` | Container runtime; auto-detected when omitted, then AFHTTP_CONTAINER_RUNTIME |
| `--name` | Container name |
| `--purge` | Also remove the built image and the cached context |

### `afhttp fetch`

Fetch a URL over HTTP or a real browser and write the requested artifacts.

#### `fetch` — Fetch with no request body

```
afhttp fetch <URL> [--endpoint-url <URL>] [--token-secret <SOURCE>] [--browser <auto|chromium|chrome|fingerprint-chromium|edge|brave|lightpanda|camoufox>] [--browser-bin <PATH>] [--render <none|auto|always>] [--tab <new|<id>>] [--profile <NAME>] [--wait <SPEC>] [--header <NAME:VALUE>...] [--cookie <NAME=VALUE>...] [--user-agent <UA>] [--evaluate-after-wait <JS>...] [--want <body|rendered_html|text|content|content_json|screenshot|network|console|observation|storage>...] [--method <METHOD>] [--network-bodies <off|xhr|all>] [--network-body-max-bytes <BYTES>] [--readiness-idle-ms <MS>] [--readiness-stable-ms <MS>] [--readiness-min-text-bytes <BYTES>] [--no-network-redact] [--out <DIR>] [--cookie-jar <PATH>] [--no-cookie-jar] [--observe-main-wait-ms <MS>] [--max-response-bytes <BYTES>] [--retry <N>] [--backoff-ms <MS>] [--proxy-url <URL>] [--ca-cert <PATH>] [--tls-insecure] [--timeout-ms <MS>] [--capture-ws] [--capture-sse]
```

#### `fetch-data` — Fetch with a raw request body from --data

```
afhttp fetch <URL> [--endpoint-url <URL>] [--token-secret <SOURCE>] [--browser <auto|chromium|chrome|fingerprint-chromium|edge|brave|lightpanda|camoufox>] [--browser-bin <PATH>] [--render <none|auto|always>] [--tab <new|<id>>] [--profile <NAME>] [--wait <SPEC>] [--header <NAME:VALUE>...] [--cookie <NAME=VALUE>...] [--user-agent <UA>] [--evaluate-after-wait <JS>...] [--want <body|rendered_html|text|content|content_json|screenshot|network|console|observation|storage>...] [--method <METHOD>] --data <STRING|@FILE> [--network-bodies <off|xhr|all>] [--network-body-max-bytes <BYTES>] [--readiness-idle-ms <MS>] [--readiness-stable-ms <MS>] [--readiness-min-text-bytes <BYTES>] [--no-network-redact] [--out <DIR>] [--cookie-jar <PATH>] [--no-cookie-jar] [--observe-main-wait-ms <MS>] [--max-response-bytes <BYTES>] [--retry <N>] [--backoff-ms <MS>] [--proxy-url <URL>] [--ca-cert <PATH>] [--tls-insecure] [--timeout-ms <MS>] [--capture-ws] [--capture-sse]
```

#### `fetch-form` — Fetch with URL-encoded fields from --form

```
afhttp fetch <URL> [--endpoint-url <URL>] [--token-secret <SOURCE>] [--browser <auto|chromium|chrome|fingerprint-chromium|edge|brave|lightpanda|camoufox>] [--browser-bin <PATH>] [--render <none|auto|always>] [--tab <new|<id>>] [--profile <NAME>] [--wait <SPEC>] [--header <NAME:VALUE>...] [--cookie <NAME=VALUE>...] [--user-agent <UA>] [--evaluate-after-wait <JS>...] [--want <body|rendered_html|text|content|content_json|screenshot|network|console|observation|storage>...] [--method <METHOD>] --form <NAME=VALUE>... [--network-bodies <off|xhr|all>] [--network-body-max-bytes <BYTES>] [--readiness-idle-ms <MS>] [--readiness-stable-ms <MS>] [--readiness-min-text-bytes <BYTES>] [--no-network-redact] [--out <DIR>] [--cookie-jar <PATH>] [--no-cookie-jar] [--observe-main-wait-ms <MS>] [--max-response-bytes <BYTES>] [--retry <N>] [--backoff-ms <MS>] [--proxy-url <URL>] [--ca-cert <PATH>] [--tls-insecure] [--timeout-ms <MS>] [--capture-ws] [--capture-sse]
```

#### `fetch-takeover` — Hand a wall to a human, with no request body

```
afhttp fetch <URL> [--endpoint-url <URL>] [--token-secret <SOURCE>] [--browser <auto|chromium|chrome|fingerprint-chromium|edge|brave|lightpanda|camoufox>] [--browser-bin <PATH>] [--render <auto|always>] [--tab <new|<id>>] --takeover [--profile <NAME>] [--wait <SPEC>] [--header <NAME:VALUE>...] [--cookie <NAME=VALUE>...] [--user-agent <UA>] [--evaluate-after-wait <JS>...] [--want <body|rendered_html|text|content|content_json|screenshot|network|console|observation|storage>...] [--method <METHOD>] [--network-bodies <off|xhr|all>] [--network-body-max-bytes <BYTES>] [--readiness-idle-ms <MS>] [--readiness-stable-ms <MS>] [--readiness-min-text-bytes <BYTES>] [--no-network-redact] [--out <DIR>] [--cookie-jar <PATH>] [--no-cookie-jar] [--observe-main-wait-ms <MS>] [--max-response-bytes <BYTES>] [--retry <N>] [--backoff-ms <MS>] [--proxy-url <URL>] [--ca-cert <PATH>] [--tls-insecure] [--timeout-ms <MS>] [--capture-ws] [--capture-sse]
```

#### `fetch-takeover-data` — Hand a wall to a human, with a raw request body from --data

```
afhttp fetch <URL> [--endpoint-url <URL>] [--token-secret <SOURCE>] [--browser <auto|chromium|chrome|fingerprint-chromium|edge|brave|lightpanda|camoufox>] [--browser-bin <PATH>] [--render <auto|always>] [--tab <new|<id>>] --takeover [--profile <NAME>] [--wait <SPEC>] [--header <NAME:VALUE>...] [--cookie <NAME=VALUE>...] [--user-agent <UA>] [--evaluate-after-wait <JS>...] [--want <body|rendered_html|text|content|content_json|screenshot|network|console|observation|storage>...] [--method <METHOD>] --data <STRING|@FILE> [--network-bodies <off|xhr|all>] [--network-body-max-bytes <BYTES>] [--readiness-idle-ms <MS>] [--readiness-stable-ms <MS>] [--readiness-min-text-bytes <BYTES>] [--no-network-redact] [--out <DIR>] [--cookie-jar <PATH>] [--no-cookie-jar] [--observe-main-wait-ms <MS>] [--max-response-bytes <BYTES>] [--retry <N>] [--backoff-ms <MS>] [--proxy-url <URL>] [--ca-cert <PATH>] [--tls-insecure] [--timeout-ms <MS>] [--capture-ws] [--capture-sse]
```

#### `fetch-takeover-form` — Hand a wall to a human, with URL-encoded fields from --form

```
afhttp fetch <URL> [--endpoint-url <URL>] [--token-secret <SOURCE>] [--browser <auto|chromium|chrome|fingerprint-chromium|edge|brave|lightpanda|camoufox>] [--browser-bin <PATH>] [--render <auto|always>] [--tab <new|<id>>] --takeover [--profile <NAME>] [--wait <SPEC>] [--header <NAME:VALUE>...] [--cookie <NAME=VALUE>...] [--user-agent <UA>] [--evaluate-after-wait <JS>...] [--want <body|rendered_html|text|content|content_json|screenshot|network|console|observation|storage>...] [--method <METHOD>] --form <NAME=VALUE>... [--network-bodies <off|xhr|all>] [--network-body-max-bytes <BYTES>] [--readiness-idle-ms <MS>] [--readiness-stable-ms <MS>] [--readiness-min-text-bytes <BYTES>] [--no-network-redact] [--out <DIR>] [--cookie-jar <PATH>] [--no-cookie-jar] [--observe-main-wait-ms <MS>] [--max-response-bytes <BYTES>] [--retry <N>] [--backoff-ms <MS>] [--proxy-url <URL>] [--ca-cert <PATH>] [--tls-insecure] [--timeout-ms <MS>] [--capture-ws] [--capture-sse]
```

Arguments across every shape above:

| Argument | Meaning |
|---|---|
| `URL` | URL to fetch |
| `--endpoint-url` | CDP endpoint of a running host; falls back to AFHTTP_ENDPOINT_URL, then to the local afhttp-host container |
| `--token-secret` | Token for a protected host; falls back to AFHTTP_TOKEN_SECRET, then to the discovered host's own token (the value, or where to read it: env:NAME, file[+FORMAT]:PATH#DOT_PATH, container:NAME, literal:VALUE) |
| `--browser` | Browser backend for the inline host; ignored when --endpoint-url is set |
| `--browser-bin` | Browser binary for the inline host when auto-discovery cannot find one |
| `--render` | Render strategy: none is the HTTP fast path, auto escalates on failure, always uses the browser |
| `--tab` | new allocates a temporary target; a CDP target id reuses and keeps it |
| `--takeover` | Escalate captcha, login, or 2FA walls to human takeover |
| `--profile` | Host profile to switch to for this fetch; defaults to the URL's registrable domain under --takeover |
| `--wait` | Readiness signal: auto | load | idle | selector:<css> | selector-visible:<css> | ms:<n> |
| `--header` | Request header, as Name:value |
| `--cookie` | Request cookie, in Set-Cookie syntax |
| `--user-agent` | Override the User-Agent header for this fetch |
| `--evaluate-after-wait` | JavaScript evaluated in page context after readiness |
| `--want` | Artifact to capture; defaults to body on the HTTP path and the browser set when rendering. storage is sensitive and opt-in |
| `--method` | HTTP method |
| `--data` | Request body; @ reads the rest as a file path |
| `--form` | URL-encoded form field; sends application/x-www-form-urlencoded |
| `--network-bodies` | Capture network response bodies; xhr captures XHR/fetch only |
| `--network-body-max-bytes` | Per-body byte cap for captured network sub-requests |
| `--readiness-idle-ms` | Network quiet window used by --wait auto |
| `--readiness-stable-ms` | DOM/text unchanged window used by --wait auto |
| `--readiness-min-text-bytes` | Low visible-text threshold that only warns about --wait auto quality |
| `--no-network-redact` | Write raw Authorization/Cookie headers and token query parameters to network.json |
| `--out` | Directory for artifacts; defaults to afhttp-out under the temp directory |
| `--cookie-jar` | Override the profile cookie-jar path; must match the host profile. Honors AFHTTP_COOKIE_JAR |
| `--no-cookie-jar` | Replay no cookies and merge no Set-Cookie back; wins over --cookie-jar |
| `--observe-main-wait-ms` | Maximum wait for the browser's main-document event |
| `--max-response-bytes` | Maximum main HTTP-path response body size; 0 disables the cap |
| `--retry` | Retry attempts after the first, for retryable errors only |
| `--backoff-ms` | Fixed delay between retries |
| `--proxy-url` | Upstream proxy for the HTTP fast path; ambient HTTP_PROXY is never honored |
| `--ca-cert` | PEM file with extra root CAs for the HTTP path |
| `--tls-insecure` | Disable TLS certificate verification on the HTTP path |
| `--timeout-ms` | Overall fetch timeout for both the HTTP and browser paths |
| `--capture-ws` | Capture WebSocket frame payloads; treat the artifact as sensitive |
| `--capture-sse` | Capture SSE event payloads; treat the artifact as sensitive |

### `afhttp health`

Query a host's /health endpoint.

```
afhttp health [--endpoint-url <URL>] [--token-secret <SOURCE>]
```

| Argument | Meaning |
|---|---|
| `--endpoint-url` | CDP endpoint of a running host; falls back to AFHTTP_ENDPOINT_URL, then to the local afhttp-host container |
| `--token-secret` | Token for a protected host; falls back to AFHTTP_TOKEN_SECRET, then to the discovered host's own token (the value, or where to read it: env:NAME, file[+FORMAT]:PATH#DOT_PATH, container:NAME, literal:VALUE) |

### `afhttp host`

Run the browser host: launch a backend browser and serve /cdp for clients.

#### `host` — Serve no takeover surface; --display picks headless or headful

```
afhttp host --listen <tcp:HOST:PORT|unix:PATH> [--profile <NAME>] [--display <headless|headful>] [--takeover-provider off] [--browser <auto|chromium|chrome|fingerprint-chromium|edge|brave|lightpanda|camoufox>] [--browser-bin <PATH>] [--token-secret <SOURCE>] [--no-health] [--health-public <off|minimal>] [--engine-env <NAME=VALUE>...] [--browser-arg <FLAG>...] [--proxy-url <URL>] [--recent-requests-cap <N>]
```

#### `host-takeover` — Serve a KasmVNC real-display takeover, which is always headful

```
afhttp host --listen <tcp:HOST:PORT|unix:PATH> [--profile <NAME>] --takeover-provider kasmvnc [--takeover-quality-percent <PERCENT>] [--browser <auto|chromium|chrome|fingerprint-chromium|edge|brave|lightpanda|camoufox>] [--browser-bin <PATH>] [--token-secret <SOURCE>] [--no-health] [--health-public <off|minimal>] [--engine-env <NAME=VALUE>...] [--browser-arg <FLAG>...] [--proxy-url <URL>] [--recent-requests-cap <N>]
```

Output: protocol events; `--output` json (default `json`), `--output-to` split/stdout/stderr (default `stdout`); redirect with `--stdout-file` or `--stderr-file`.

Arguments across every shape above:

| Argument | Meaning |
|---|---|
| `--listen` | Listener address; a non-loopback TCP address also requires --token-secret |
| `--profile` | Initial profile name, or - for an ephemeral profile |
| `--display` | Browser display mode |
| `--takeover-provider` | Real-display takeover provider served at /takeover/panel |
| `--takeover-quality-percent` | Takeover image quality from 0 to 100; lower trades clarity for bandwidth |
| `--browser` | Browser backend |
| `--browser-bin` | Override the browser binary path |
| `--token-secret` | Token this host requires from callers (the value, or where to read it: env:NAME, file[+FORMAT]:PATH#DOT_PATH, container:NAME, literal:VALUE) |
| `--no-health` | Stop serving /health and /capabilities, which are on by default |
| `--health-public` | Serve /health unauthenticated with a minimal payload |
| `--engine-env` | Environment variable for the browser subprocess; all others are scrubbed |
| `--browser-arg` | Raw backend flag appended after the host's defaults |
| `--proxy-url` | Upstream browser proxy; ambient HTTP_PROXY is never inherited |
| `--recent-requests-cap` | Enable /recent-requests with a bounded ring of N entries; 0 is off |

### `afhttp panel`

Mint a short-lived takeover URL for a running takeover-ready host.

```
afhttp panel [--endpoint-url <URL>] [--token-secret <SOURCE>]
```

| Argument | Meaning |
|---|---|
| `--endpoint-url` | CDP endpoint of a running host; falls back to AFHTTP_ENDPOINT_URL, then to the local afhttp-host container |
| `--token-secret` | Token for a protected host; falls back to AFHTTP_TOKEN_SECRET, then to the discovered host's own token (the value, or where to read it: env:NAME, file[+FORMAT]:PATH#DOT_PATH, container:NAME, literal:VALUE) |

### `afhttp profile cookies`

Show the non-expired cookies in a profile's jar, with values redacted.

```
afhttp profile cookies <NAME> [--backend <BACKEND>] [--profile-root <DIR>]
```

| Argument | Meaning |
|---|---|
| `NAME` | Profile name |
| `--backend` | Browser backend scope; required when one profile name exists under several |
| `--profile-root` | Profiles root directory; defaults to $XDG_DATA_HOME/afhttp/profiles |

### `afhttp profile delete`

Delete a profile and all of its on-disk state.

```
afhttp profile delete <NAME> [--backend <BACKEND>] --confirm <NAME> [--profile-root <DIR>]
```

| Argument | Meaning |
|---|---|
| `NAME` | Profile name to delete |
| `--backend` | Browser backend scope; required when one profile name exists under several |
| `--confirm` | Confirmation guard; must equal the profile name |
| `--profile-root` | Profiles root directory; defaults to $XDG_DATA_HOME/afhttp/profiles |

### `afhttp profile downloads`

List files captured in a profile's browser download directory.

```
afhttp profile downloads <NAME> [--backend <BACKEND>] [--profile-root <DIR>]
```

| Argument | Meaning |
|---|---|
| `NAME` | Profile name |
| `--backend` | Browser backend scope; required when one profile name exists under several |
| `--profile-root` | Profiles root directory; defaults to $XDG_DATA_HOME/afhttp/profiles |

### `afhttp profile info`

Show one profile's size, last use, and lock state.

```
afhttp profile info <NAME> [--backend <BACKEND>] [--profile-root <DIR>]
```

| Argument | Meaning |
|---|---|
| `NAME` | Profile name |
| `--backend` | Browser backend scope; required when one profile name exists under several |
| `--profile-root` | Profiles root directory; defaults to $XDG_DATA_HOME/afhttp/profiles |

### `afhttp profile list`

List the on-disk profiles under the profiles root.

```
afhttp profile list [--profile-root <DIR>]
```

| Argument | Meaning |
|---|---|
| `--profile-root` | Profiles root directory; defaults to $XDG_DATA_HOME/afhttp/profiles |

### `afhttp profile lock-status`

Report whether a profile is currently locked by a running host.

```
afhttp profile lock-status <NAME> [--backend <BACKEND>] [--profile-root <DIR>]
```

| Argument | Meaning |
|---|---|
| `NAME` | Profile name |
| `--backend` | Browser backend scope; required when one profile name exists under several |
| `--profile-root` | Profiles root directory; defaults to $XDG_DATA_HOME/afhttp/profiles |

### `afhttp profile prune`

Delete profiles whose last use is older than a cutoff.

```
afhttp profile prune --older-than <DURATION> [--dry-run] [--profile-root <DIR>]
```

| Argument | Meaning |
|---|---|
| `--older-than` | Age cutoff such as 30d or 12h; profiles last used before it are removed |
| `--dry-run` | Report what would be deleted without deleting anything |
| `--profile-root` | Profiles root directory; defaults to $XDG_DATA_HOME/afhttp/profiles |

### `afhttp skill install`

Install or refresh the Agent-First HTTP skill.

#### `skill-install-every-agent` — Target every agent that supports the scope

```
afhttp skill install [--agent all] [--scope <personal|workspace>] [--force]
```

#### `skill-install-one-agent` — Target one named agent; only this shape accepts --skills-dir

```
afhttp skill install --agent <codex|claude-code|opencode|hermes> [--scope <personal|workspace>] [--skills-dir <DIR>] [--force]
```

Arguments across every shape above:

| Argument | Meaning |
|---|---|
| `--agent` | Agent to manage |
| `--scope` | Skill scope |
| `--skills-dir` | Directory that contains skill folders |
| `--force` | Overwrite or remove an Agent-First HTTP skill this tool did not manage |

### `afhttp skill status`

Show whether the Agent-First HTTP skill is installed, valid, and up to date.

#### `skill-status-every-agent` — Target every agent that supports the scope

```
afhttp skill status [--agent all] [--scope <personal|workspace>]
```

#### `skill-status-one-agent` — Target one named agent; only this shape accepts --skills-dir

```
afhttp skill status --agent <codex|claude-code|opencode|hermes> [--scope <personal|workspace>] [--skills-dir <DIR>]
```

Arguments across every shape above:

| Argument | Meaning |
|---|---|
| `--agent` | Agent to manage |
| `--scope` | Skill scope |
| `--skills-dir` | Directory that contains skill folders |

### `afhttp skill uninstall`

Remove an afhttp-managed Agent-First HTTP skill.

#### `skill-uninstall-every-agent` — Target every agent that supports the scope

```
afhttp skill uninstall [--agent all] [--scope <personal|workspace>] [--force]
```

#### `skill-uninstall-one-agent` — Target one named agent; only this shape accepts --skills-dir

```
afhttp skill uninstall --agent <codex|claude-code|opencode|hermes> [--scope <personal|workspace>] [--skills-dir <DIR>] [--force]
```

Arguments across every shape above:

| Argument | Meaning |
|---|---|
| `--agent` | Agent to manage |
| `--scope` | Skill scope |
| `--skills-dir` | Directory that contains skill folders |
| `--force` | Overwrite or remove an Agent-First HTTP skill this tool did not manage |

### `afhttp tabs close`

Close one CDP target by its target id.

```
afhttp tabs close --tab <TARGET_ID> [--endpoint-url <URL>] [--token-secret <SOURCE>]
```

| Argument | Meaning |
|---|---|
| `--tab` | CDP target id to close |
| `--endpoint-url` | CDP endpoint of a running host; falls back to AFHTTP_ENDPOINT_URL, then to the local afhttp-host container |
| `--token-secret` | Token for a protected host; falls back to AFHTTP_TOKEN_SECRET, then to the discovered host's own token (the value, or where to read it: env:NAME, file[+FORMAT]:PATH#DOT_PATH, container:NAME, literal:VALUE) |

### `afhttp tabs list`

List the CDP targets currently attached to a host.

```
afhttp tabs list [--endpoint-url <URL>] [--token-secret <SOURCE>]
```

| Argument | Meaning |
|---|---|
| `--endpoint-url` | CDP endpoint of a running host; falls back to AFHTTP_ENDPOINT_URL, then to the local afhttp-host container |
| `--token-secret` | Token for a protected host; falls back to AFHTTP_TOKEN_SECRET, then to the discovered host's own token (the value, or where to read it: env:NAME, file[+FORMAT]:PATH#DOT_PATH, container:NAME, literal:VALUE) |

### `afhttp ui takeover`

Put the takeover panel in front of a person and block until that session ends.

#### `ui-takeover` — Mint a fresh panel credential from a running host, then deliver it

```
afhttp ui takeover [--endpoint-url <URL>] [--token-secret <SOURCE>] [--mode <window|link|session>]
```

#### `ui-takeover-url` — Deliver a panel URL that was already minted; needs no host of its own

```
afhttp ui takeover --takeover-url-secret <URL> [--mode <window|link|session>]
```

Output: protocol events; `--output` json (default `json`), `--output-to` split/stdout/stderr (default `stdout`); redirect with `--stdout-file` or `--stderr-file`.

Arguments across every shape above:

| Argument | Meaning |
|---|---|
| `--endpoint-url` | CDP endpoint of a running host; falls back to AFHTTP_ENDPOINT_URL, then to the local afhttp-host container |
| `--token-secret` | Token for a protected host; falls back to AFHTTP_TOKEN_SECRET, then to the discovered host's own token (the value, or where to read it: env:NAME, file[+FORMAT]:PATH#DOT_PATH, container:NAME, literal:VALUE) |
| `--takeover-url-secret` | Panel URL a previous `panel` or `fetch --takeover` already minted |
| `--mode` | How this reaches the person: window a browser window is open on this machine; link the page is reachable from this machine's network at the link URL; session the session is registered only; open it with `afui session open` or reach it through `afui session serve`. Falls back to AFUI_DELIVERY, then window |

### `afhttp upload`

Upload a local file into a browser tab's file input via DOM.setFileInputFiles.

```
afhttp upload [--endpoint-url <URL>] [--token-secret <SOURCE>] --tab <TARGET_ID> --selector <CSS> --file <PATH>
```

| Argument | Meaning |
|---|---|
| `--endpoint-url` | CDP endpoint of a running host; falls back to AFHTTP_ENDPOINT_URL, then to the local afhttp-host container |
| `--token-secret` | Token for a protected host; falls back to AFHTTP_TOKEN_SECRET, then to the discovered host's own token (the value, or where to read it: env:NAME, file[+FORMAT]:PATH#DOT_PATH, container:NAME, literal:VALUE) |
| `--tab` | CDP target id to operate in |
| `--selector` | CSS selector for the <input type=file> element |
| `--file` | Local file to upload |

## Exit codes

| Code | Meaning |
|---|---|
| 0 | The command ran and succeeded. |
| 1 | The command ran and failed. The event carries a domain `error.code`. |
| 2 | The invocation was rejected before anything ran. `error.code` is one of the `cli_*` codes below. |

The split is the useful one for a caller: exit 2 means the call was never made, so retrying it unchanged cannot help, while exit 1 means it was.

## CLI errors

Every structural failure emits one strict JSON `kind:"error"` event on stderr, leaves stdout empty, and exits 2. The `code` names the failure — `cli_unknown_argument` for an unknown spelling, `cli_unregistered_combination` for registered arguments in a mixture that is not, and one each for `cli_unknown_command`, `cli_missing_argument_value`, `cli_invalid_argument_value`, `cli_duplicate_argument`, `cli_unexpected_positional`, and `cli_invalid_utf8`. `message` identifies a safe argument spelling or the failure category and `hint` gives the command to run next; neither ever quotes a raw value, including secrets. These are decided before any config, secret source, filesystem, network, or domain I/O.

Two exit-1 codes describe the tool itself rather than the call: `cli_invocation_invalid` means the program misread its own resolved invocation — an unknown action id, or an argument id the selected combination cannot produce — and `output_setup_failed` means an output sink (`--stdout-file`, `--stderr-file`, stream redirection) could not be established. Both are defects to report, not inputs to correct; retrying the same command cannot help.

Domain failures (exit 1) carry their own stable `error.code` instead, drawn from whatever this tool defines rather than from the `cli_*` set. Error events are routinely logged, so a message never quotes a value that came from an argument able to carry a credential — a header, a cookie, a token, a password, a proxy URL, an environment value, a form field. Such an error names the argument and the shape that was wrong, and stops there. A value that cannot be a secret — a path, a dot-path, a session name — is quoted, because an error that cannot say which one it means is not worth logging either.