Tabs, profiles and sessions

Profiles, tabs, incognito, cookies and storage, uploads and downloads, and the trace.

jawbd holds this hierarchy: daemon → profiles → sessions → tabs. The CLI is stateless — everything below lives in the daemon, so jawb click 48 from one terminal works right after jawb observe from another.

Profiles

A profile is a named, persistent, encrypted-at-rest storage partition (cookies, localStorage, cache, permissions). Every persistent profile is encrypted, including default — there's no opt-in and no unencrypted option. The key is wrapped by an OS credential store (Windows DPAPI, macOS Keychain, Linux Secret Service), or by --vault-keyfile <path> if none is available.

$ jawb profile list
* default          encrypted, 0 tabs, not created yet

$ jawb profile create work
created profile work (encrypted: windows-dpapi (current user))

$ jawb profile use work
current profile: work (was default)

$ jawb profile delete work --yes

default cannot be deleted. Profile names match ^[a-z0-9][a-z0-9_-]{0,31}$.

Tabs and navigation

$ jawb open https://example.com
t_bexe91  Example Domain  https://example.com/  (3 elements)
  navigated -> https://example.com/ (3 elements; run `jawb observe` for the page)
rev 0 → 1 (native, 629ms)

$ jawb tabs
* t_bexe91  rev 1   native default    Example Domain  https://example.com/

$ jawb open --tab t_bexe91 https://go.dev/
$ jawb back --tab t_bexe91
$ jawb forward --tab t_bexe91
$ jawb reload --tab t_bexe91
$ jawb tab use t_bexe91
current tab: t_bexe91 (already current)  https://example.com/  [default]
$ jawb close t_bexe91

Tabs are independent and run in parallel: commands to different tabs run concurrently, while commands to the same tab are serialized in arrival order. Two tabs can be driven at once without coordinating.

Each tab starts on the native engine and is promoted to the compatibility bridge the first time it needs one (any Act/See command, or --js). A promoted tab stays on the bridge for the rest of its life — jawb tabs shows the executor per tab.

Incognito

$ jawb open --incognito https://example.com

Creates an ephemeral session backed only by memory — nothing is written to disk (no cookies, storage, cache, or trace bodies with full URLs), except a download you explicitly ask for. That download is deleted when the session's last tab closes or the daemon stops; use `download --to

` to keep a copy. Reach the same incognito session's other tabs with `--tab --new-tab`; a new `--incognito` open always starts a fresh session. `storage export` on an incognito tab needs an explicit `--to ` (otherwise `E_POLICY_DENIED`), and warns that it's writing incognito state to disk.

Cookies and storage

$ jawb cookies --profile work
sid=abc123  domain=127.0.0.1 path=/  expires 1790593348 httponly

$ jawb cookies clear --profile work

$ jawb storage export --profile work --to work-export.json
$ jawb storage import work-export.json --profile work --yes

storage import asks for confirmation (--yes to skip): it replaces the profile's cookies and localStorage.

An export file holds live session cookies in plaintext, so anyone who can read it can sign in as you. storage export --to therefore creates the file readable by you only: mode 0600 on macOS and Linux, and on Windows an access list that grants only your user account and does not inherit the folder's entries. It refuses to write through a symlink, and it refuses to overwrite an existing file unless you pass --force. Delete the file when you no longer need it.

Uploads and downloads

upload <id> <file...> sends file bytes over HTTP, never a path — the daemon can't be used to read arbitrary files off your disk. download <id> [--to <dir>] saves under <data_dir>/downloads/<profile>/ by default; --to <dir> makes the CLI fetch the bytes itself into a directory you name. Both are policy-gated — see policy and confirmation.

Trace

Every command run against the daemon is recorded:

$ jawb trace --tab t_bexe91 --last 3
TS            COMMAND          TAB        EXEC      REV     MS  RESULT
05:55:36.523Z open             t_bexe91   native      1      8  ok
05:55:36.545Z observe          t_bexe91   native      1      2  ok
...

TS is the step's UTC start time. The --json form carries Unix milliseconds (ts, ended_ts).

EXEC shows native or bridge* (the * marks reduced fidelity vs. the native engine). Trace steps also record the policy decision for any gated action.

Following the trace live

jawb trace --follow prints new steps as they happen. With --json (jawbd at API level 36) it prints jawb's event stream instead, one JSON event per line: stream.hello first, then one event per step the trace records, such as nav.open.after, tab.opened, act.click.after, page.observed or confirmation.approved:

$ jawb --json trace --follow --types 'act.*.after,tab.opened'
{"v":1,"type":"stream.hello","ts":1791702900000,"data":{"subscriber":"sub_7w2k9c4m","epoch":"19a0c2f1b3e4x9qk","oldest":null,"filter":{"types":["act.*.after","tab.opened"],"tab":null}}}
{"v":1,"id":"19a0c2f1b3e4x9qk-3","type":"tab.opened","ts":1791702901240,"session":"s_4k2m9q","profile":"default","tab":"t_bexe91","executor":"native","client":"jawb/0.1.1","trigger_depth":0,"trace_id":"tr_01m4mj6yye94xj2w61","data":{"tab":"t_bexe91","opener":"caller","url":"https://shop.example/"}}

--types keeps only the types you name; * may stand for the verb (act.*.after, nav.*.after). --tab keeps one tab's events. Events carry what the trace carries and no more: URLs with query values replaced (origins only for incognito tabs), and never a typed value, a secret or a token. If the connection drops, jawb reconnects and gets what it missed, or a stream.gap line when jawbd restarted or no longer has it (it keeps the last 10,000 events, up to 10 minutes).