···8484 bootstrap and reusable-pair workflow still live in `perlsky` itself.
85858686The adapter boundary is documented in [docs/ADAPTERS.md](./docs/ADAPTERS.md).
8787+Representative CLI and `summary.json` examples live in
8888+[docs/SAMPLE_OUTPUT.md](./docs/SAMPLE_OUTPUT.md).
87898890## Extraction Shape
8991
+125
docs/SAMPLE_OUTPUT.md
···11+# Sample Output
22+33+This page shows trimmed examples of what `atproto-smoke` prints and writes.
44+55+## `list-adapters`
66+77+```text
88+- bring-your-own: Use existing accounts on any PDS with minimal configuration.
99+ account strategy: existing-accounts
1010+ note: This is the default adapter and the lowest-friction path for non-Perl PDS implementations.
1111+ note: The suite will not create accounts for you. Supply one account for single-mode or two for dual-mode.
1212+- perlsky: Use perlsky-flavored defaults like cleanup prefixes and adapter tagging.
1313+ account strategy: existing-accounts-or-bootstrap
1414+ note: The standalone suite still expects credentials in the config.
1515+ note: perlsky-specific account bootstrap and reusable-pair helpers live in perlsky, not in atproto-smoke itself.
1616+```
1717+1818+## `write-example --mode dual`
1919+2020+```text
2121+wrote /tmp/config.json using adapter bring-your-own (dual)
2222+```
2323+2424+Generated config:
2525+2626+```json
2727+{
2828+ "pdsUrl": "https://your-pds.example",
2929+ "artifactsDir": "data/browser-smoke/bring-your-own-dual",
3030+ "targetHandle": "alice.mosphere.at",
3131+ "strictErrors": true,
3232+ "primary": {
3333+ "handle": "smoke-primary.your-pds.example",
3434+ "password": "replace-me"
3535+ },
3636+ "secondary": {
3737+ "handle": "smoke-secondary.your-pds.example",
3838+ "password": "replace-me-too"
3939+ }
4040+}
4141+```
4242+4343+## `validate --mode dual`
4444+4545+```json
4646+{
4747+ "pdsUrl": "https://your-pds.example",
4848+ "artifactsDir": "data/browser-smoke/bring-your-own-dual",
4949+ "appUrl": "https://bsky.app",
5050+ "publicApiUrl": "https://public.api.bsky.app",
5151+ "publicCheckTimeoutMs": 180000,
5252+ "stepTimeoutMs": 120000,
5353+ "headless": true,
5454+ "strictErrors": true,
5555+ "publicChecks": true,
5656+ "pdsHost": "your-pds.example",
5757+ "targetHandle": "alice.mosphere.at",
5858+ "primary": {
5959+ "handle": "smoke-primary.your-pds.example",
6060+ "password": "replace-me",
6161+ "birthdate": "1990-01-01",
6262+ "cleanupPostPrefixes": []
6363+ },
6464+ "secondary": {
6565+ "handle": "smoke-secondary.your-pds.example",
6666+ "password": "replace-me-too",
6767+ "birthdate": "1990-01-01",
6868+ "cleanupPostPrefixes": []
6969+ }
7070+}
7171+```
7272+7373+## Real `summary.json`
7474+7575+Trimmed from a clean strict dual-account run:
7676+7777+```json
7878+{
7979+ "startedAt": "2026-03-11T20:04:16.563Z",
8080+ "appUrl": "https://bsky.app",
8181+ "pdsUrl": "https://perlsky.mosphere.at",
8282+ "primaryHandle": "smokee2ea20260311-121322.perlsky.mosphere.at",
8383+ "secondaryHandle": "smokee2eb20260311-121322.perlsky.mosphere.at",
8484+ "steps": [
8585+ {
8686+ "name": "primary-login",
8787+ "status": "ok"
8888+ },
8989+ {
9090+ "name": "primary-age-assurance",
9191+ "status": "ok"
9292+ },
9393+ {
9494+ "name": "secondary-login",
9595+ "status": "ok"
9696+ },
9797+ {
9898+ "name": "secondary-age-assurance",
9999+ "status": "ok"
100100+ },
101101+ {
102102+ "name": "primary-preclean-stale-artifacts",
103103+ "status": "ok"
104104+ }
105105+ ],
106106+ "notes": [
107107+ "account source: pair-file",
108108+ "browser launch candidate succeeded: executable:/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
109109+ ],
110110+ "unexpected": {
111111+ "console": [],
112112+ "requestFailures": [],
113113+ "httpFailures": [],
114114+ "pageErrors": [],
115115+ "total": 0
116116+ },
117117+ "ok": true
118118+}
119119+```
120120+121121+The full artifact from that run lives at:
122122+123123+```text
124124+data/browser-smoke/step-timeout-20260311-2007/summary.json
125125+```