The browser#
Ohm opens on a web page and behaves like a browser: a tab strip, an address bar, back, forward and reload. What it adds is hidden tabs, an activity bar of panels, and a console.
Tabs#
Ctrl+T opens a tab, Ctrl+W closes one. Typing in the address bar follows the usual
rules: text with a scheme is a URL, bare localhost or an IP gets http://, other
host-shaped text gets https://, and anything else becomes a search.
When you close the active tab, focus moves to the first visible tab at or to the right of it, falling back to the nearest one on the left — the same rule Chrome uses, and it skips hidden tabs.
A tab can be discarded to free memory: the page is destroyed but the entry stays in the strip with its title and URL, and clicking it loads the page again.
Hidden tabs#
Ctrl+Shift+H opens the hidden-tab drawer. A hidden tab is out of the strip but still
running — background throttling is turned off for it deliberately, because hidden tabs are
where scripts do their work:
local tab = browser.open("https://example.com", { hidden = true })
print(tab.title())
tab.close()
The deep-research pipeline runs entirely this way: it opens searches and fetches pages in hidden tabs, so your view never jumps around while it works.
From the drawer you can show, discard or close a hidden tab. Showing one makes it a normal tab — a tab can never be focused and hidden at the same time.
Popups (window.open, target="_blank") are never handed to the page: the shell intercepts
them and opens a normal tab instead.
The activity bar#
| Icon | Panel | Shortcut |
|---|---|---|
∮ |
Scripts | Ctrl+Shift+E |
▦ |
Projects | Ctrl+Shift+P |
◐ |
Hidden tabs | Ctrl+Shift+H |
✎ |
Editor | |
◎ |
Context: open tabs, page structure, exports | |
? |
Help — this documentation, compiled into the app | |
⚙ |
Settings | |
▤ |
Console | Ctrl+` |
The page is a real Chromium view layered over the UI, which is why opening Settings or maximising the editor hides it entirely rather than shrinking it.
The console#
Ctrl+` opens a console that is both a log and a REPL. It shows output from every script
run — print, log.info/warn/error, and the value of any bare expression — and you can type
Lua or math straight into it:
ohm> print($\frac{22}{7}$)
3.142857143
ohm> x = 41
ohm> x + 1
42
Variables persist between lines. Stopping a run resets the session and says so, because stopping terminates the worker thread.
Click any error line to jump to that line in the editor.
Driving pages from a script#
Scripts control pages through the Chrome DevTools Protocol, so everything you can do by hand is scriptable:
local tab = browser.open("https://news.ycombinator.com", { hidden = true })
tab.waitFor(".titleline", 5000)
local items = tab.queryAll(".titleline > a")
for i, item in ipairs(items) do print(i, item.text) end
tab.close()
click, type, press, scroll, eval, screenshot and waitFor are all available.
waitFor polls every 200 ms and throws on timeout; screenshots are written to
.ohm/shots/ and the path is returned.
See The Ohm language and the script API.