Guide 01 / Start here · 2026-08-21

Open a session and read what it reached

Driving a browser and observing one are different jobs. This guide does both in one sitting: act on a page by handle, then read back the decision record the engine wrote as it went.

Outcome. In about ten minutes you will open a session, read a page as a model reads it, act on it, watch a request get refused by policy, and read the log that proves what did and did not reach the network.

A session is the whole agent-facing surface: one page state, one cookie jar, one request log, one policy. open makes one, every verb that follows acts on it, close ends it. You do not type a session id: the opaque one in --json and in the receipts is a durable reference, not an interface. Nothing else is a concept the agent has to learn, which is what lets the placement change later without changing a single command.

1. Open a session

host
$ h5i browser open https://docs.rs/ --allow docs.rs

Read the two lines it prints back before anything else. The placement line says where this session runs, and the requests line says who saw its network. Both are printed on every status afterwards, so you never have to infer either.

what it answers
placed   : this machine (no containment beyond the engine)
requests : engine-claimed (fail-closed, and the engine's own account of what it fetched)

That first line is the honest one. A session started this way is not sandboxed, and h5i says so rather than letting the word browser imply a boundary. What you get without one is the record.

2. Read the page the way a model reads it

host
$ h5i browser snapshot

What comes back is an outline with @ref handles rather than pixels or raw HTML: headings, paragraphs, and the things that can be acted on, each with a handle to act on it by. It arrives inside a fence marking everything within as page content, which is the difference between text the model treats as information and text it treats as an instruction.

Two things are stripped on the way through, both because the page composed them. Escape sequences never survive: ESC in a page title is a page repainting the terminal it is printed into, and nothing a browser has to say needs one. Long values are capped with the truncation stated in the value, because an answer silently shortened is one an agent reasons about as if it were complete.

3. Act by handle, not by guess

host
$ h5i browser click @e3
$ h5i browser snapshot --delta
$ h5i browser type @e5 "serde"
$ h5i browser submit @e5

Use --delta once the loop is running. Re-reading three hundred lines after every click is the wrong shape for an agent, and when the page has changed too much for a difference to be the shorter answer the full outline arrives instead and the reply says which it is.

A handle from a reading the page has moved on from is refused rather than resolved against whatever now sits in that position. That refusal is the feature: a mis-click on a page that changed underneath is the failure that is hardest to see afterwards.

4. Watch a request get refused

The session was started with one origin allowed. Follow a link that leaves it.

host
$ h5i browser click @e9
denied by policy: origin `https://tracker.example` is not in the allowlist

Redirects are checked at every hop, so a server cannot route the session out of its allowlist by answering with a 302. The refusal is an answer with a reason, not a silent no-op, and it is in the log.

5. Read back what it reached

host
$ h5i browser requests

This is the part that is different. The engine is the HTTP client, so this list is a decision record it wrote before the bytes moved rather than a trace assembled beside the network. The order is fixed: check the policy, write the record, then touch the wire. When the record cannot be written, the fetch is refused.

Two consequences worth stating plainly. A request that is not in this list did not happen. And a denied request is in the list, with its reason, so the log shows what was attempted and not only what succeeded.

Pass the cursor from a previous answer back as --since to see only what is new, the same way --delta works on a snapshot.

6. Read the whole session back

requests is the network layer, and the verb to poll inside a loop. When you are writing up what happened, read the timeline instead.

host
$ h5i browser audit

It merges three sources: the verbs you asked for, the decision the engine made about every fetch, and the moments a human took the controls. Ordered across all of them, so the question a review actually asks — was a person driving when that form was submitted — has an answer. A current-holder field cannot give one.

Every row says which lane it came from. The engine’s rows are its own account of itself; the handovers and the ending are h5i’s, written from outside. They are printed apart because a claim rendered as an observation is the one error this product cannot afford.

Read the sources line before the rows. Each log is read, empty, or unavailable. An empty timeline over a log h5i could not see looks exactly like a session that did nothing, and those are different findings.

7. End it, and keep the record

host
$ h5i browser close
$ h5i browser list --all

Closing writes the ending into the session's record instead of deleting it, which is what makes “how did this end” answerable afterwards and what makes the id impossible to reuse. The states are closed, died, expired and evicted, and they are kept apart because they are different facts about the run.

Send a verb to a session that is not live and it is refused with exit code 69 rather than silently restarted. That distinct code is the point of the design: an agent whose retry cannot tell “the session is gone” from “the click did not work” quietly starts a second browser and loses both the page it was reasoning about and the record of losing it.

8. When you want a boundary too

host
$ h5i box --profile browser --engine h5i --name web
$ h5i browser open https://example.com --in web

Every verb above works unchanged. What changes is the requests line: the box enforces its egress allowlist at its own boundary, outside the browser being described, so the lane goes from engine-claimed to host-observed.

Being inside a box does not earn that on its own. A box whose policy lets the browser reach the whole network corroborates nothing, and h5i keeps calling that session engine-claimed. What earns the upgrade is enforcement outside the engine.

Reference

Questions that come up

Is the session sandboxed?
Not by default, and h5i does not claim it is. A session started with no flags runs in your ordinary process space like any other headless browser. The placement line says so on every status. Containment is the --in flag, which places the same session inside a box without changing any verb.
What does engine-claimed mean?
It is the browser's own account of what it fetched: fail-closed, complete, and still the browser describing itself. host-observed means h5i also saw the traffic at a box's boundary, outside the browser. h5i never merges the two labels.
What happens if the browser dies mid-task?
The session is recorded as died, with a time, and the next verb exits 69. Nothing restarts automatically. Use --restore to carry the old session's storage into a new session with a new id; the inheritance is written into the new record and the old id is never reused.
Does the engine run page JavaScript?
Only if you ask for it with --script. Off is the default because with no script realm there is no delivery channel for page-borne injection at all. Turning it on is a decision, not a default you inherit.
Next guide

Watch the page, then take the controls

Put the browser beside the dev server and hand control between agent and human.

Open a session in one command

No project, no repository, no configuration. h5i browser open takes a URL and gives you an id.