eval is the most powerful automation verb, so it is double locked. The session must be started with extension dev --allow-eval, and the CLI must present the session token that the dev server wrote for this project and browser. Both happen automatically when you run the two commands from the same project root.
When to use eval
- You want to poke at extension state (
chrome.runtime, storage, DOM) without opening DevTools. - An agent needs to run a check inside the page and get a structured value back.
- You want a scriptable REPL against the background worker or a live tab.
Usage
Arguments and flags
Extension pages (
popup, options, sidebar, devtools, newtab, history, bookmarks) answer through their own in-page relay, so the surface must be open in the browser. Use open (documented in Trigger actions and commands) to open one first.
On Firefox, an extension document whose policy forbids eval answers through the debugger protocol instead. Since 4.1.32 that route also takes a statement list: it answers the completion value of the last statement and awaits a promise the statements end on. A result past 256 KiB comes back as a 1024 character preview with truncated: true on the envelope, and pretty output prints a result truncated (byte cap) line.
Pretty output prints the value itself: strings as-is, everything else as indented JSON. The envelope shape appears only under --output json (see Result envelope).
How the unlock works
extension dev --allow-evalstarts the session with eval enabled.--allow-evalalso unlocks the other control verbs, so you do not need both flags.- The dev server writes a random session token to
.extension-js/control-token-<browser>with0600permissions. The token is keyed per browser, so concurrent sessions do not collide. evalreads that token from the project root and presents it during the handshake.
--allow-eval refuses the call, and the refusal names --allow-eval as the flag to add. A missing token fails with E_TOKEN_MISSING, a mismatched or disabled one with E_EVAL_REFUSED.
Failure modes
- The expression threw inside the target:
E_EVAL, with a hint that the expression itself is at fault. This is a result, not a transport error. - A content security policy forbids eval in the target:
E_CSP_BLOCKS_EVAL. An MV3 extension forbids eval in its own documents and content scripts, and a web page can forbid it for itself. On Firefox, the CLI evaluates an extension document through the debugger protocol when the extension’s policy forbids eval. Read the target withinspectwhen you get this code. Since 4.1.32, Firefox also evaluates a web page that forbids eval for itself through the debugger, when exactly one open tab is on that url. With a duplicate tab open the call keeps the refusal and the hint names the tab to close. - No session for the browser:
E_SESSION_NOT_FOUND, with the exactextension devcommand to run. - Target surface not open, or a stale
--tabid:E_TARGET_NOT_FOUND. Useinspect --list-tabsto find live ids. - The call outlived
--timeout:E_TIMEOUT.
0 when the expression succeeds and 1 otherwise, so scripts can gate on it directly. Run doctor when every verb fails and you want the broken leg named.
Next steps
- Find tab ids and DOM state to target with
inspect. - Read or write
chrome.storagewithout writing an expression withstorage. - Read the wider debugging workflow in Debugging.
- Review the machine output format in Result envelope.

