Getting it into your agent
One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.
npx skills add peters/horizon --skill horizon-browsergit clone --depth 1 https://github.com/peters/horizonWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/skills/peters/horizon/horizon-browser)<a href="https://agentmods.dev/skills/peters/horizon/horizon-browser"><img src="https://agentmods.dev/badge/skills/peters/horizon/horizon-browser/github.svg" alt="Measured on agentmods" height="20"></a>Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.
<a href="https://agentmods.dev/skills/peters/horizon/horizon-browser"><img src="https://agentmods.dev/badge/skills/peters/horizon/horizon-browser.svg" alt="Reviewed on agentmods" width="80" height="20"></a>- NVIDIA SkillSpector pass
What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5.1 | $0.00020 | $0.06928 |
| Opus 5.5 | $0.00008 | $0.02771 |
| Sonnet 5.5 | $0.00004 | $0.01386 |
| Haiku 4.5 | $0.00002 | $0.00693 |
Grade A, and why
horizon-browser scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured today.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Nothing flagged
None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.
How it starts
The opening of the file, as written. The whole thing — 467 lines — stays where its author put it; the contents beside it link to each section on GitHub.
Horizon browser control
Native VNC Device panels, simulators, and isolated desktop tests use the
horizon-device skill. The workflow below applies to browser pages.
Use the browser_* MCP tools as the only agent-facing browser contract. Do
not inspect Horizon runtime files, connect to raw CDP/BiDi/WebDriver endpoints,
or invoke a browser-control CLI. If the MCP tools are unavailable, report that
the Horizon browser MCP server is not connected.
Start with browser_list when the panel id is unknown. If it returns no panels,
call browser_create; this opens a panel in the current agent's Horizon
workspace and returns its ready panel id once the backend is ready and, when
you passed a url, once that page committed (navigation: committed). A
navigation: pending result means the panel is controllable but the first
page had not committed within the bounded startup wait, so use browser_wait
or browser_panel before reading it; navigation: failed means that page
failed to load (navigation_error says why) and you must navigate again or
fix the URL; navigation: superseded means the user navigated the panel
first, so read panel.url before acting. If browser_list returns a usable panel, reuse
that panel for iframe, popup, dialog, and consent interactions. Never create or
reveal a helper panel as a workaround. You may hold one panel per browser
engine: to run the same check in another engine, call browser_create with an
explicit backend (chromium, firefox or safari) beside your open panel.
Only when the user explicitly requests another independent browser session may
you call browser_create with allow_additional: true; a second panel of the
same engine, a create without backend while you own a panel, and a remote
target while you own a panel need it. A create that is still pending counts
as a panel of its engine. Omit backend to use Horizon's
configured browser, or select chromium, firefox, or safari when the
platform supports it. Read automation_disclosure on browser_list and
browser_panel. In the UI, hover the local backend picker or the remote identity
header to read the same status. common_signals_minimized means the native
navigator.webdriver getter is still native. On Firefox that result needs
firefox_system_access: true and geckodriver 0.37 or newer. The option passes
geckodriver --allow-system-access. Mozilla documents that flag as full
system access for any local client that can reach the driver port. Leave it
false unless that privilege is acceptable. preload_fallback means Firefox
installed a script getter that returns false. Sign-in pages can reject that
getter. The default minimized Firefox session uses that fallback. Chromium
does not install it. A remote Firefox or Chromium session reports
unsupported_by_backend for minimization. Remote Firefox does not clear the
native flag or install the preload. Remote Chromium does not receive the
local automation flag. unreported means an older manifest omitted the
field. That is not an established result. To run at a configured remote target instead of a
local browser, pass target with its name and omit backend; Horizon
resolves the provider and credentials from its configuration, and a
refusal carries a typed code and at most the target, provider or credential
reference name, never a credential value. Such a panel reports
remote_target, remote_device (the model, OS version and hardware
evidence the provider itself reported, verified against the target before
the panel became ready), classic WebDriver and no network capture. A target
that requires a physical device is refused as remote_device_rejected unless
that evidence confirms it, after Horizon attempts to release the session; a
remote_allocation_unknown refusal means a device may still be held, so check
with the user before creating again; remote_authentication_failed,
remote_not_entitled and remote_device_unavailable say which of the
credential, the account's automation access or the device request the provider
refused, with nothing held. Cite remote_device, not the target
name, as real-device evidence. Set visible: false for background automation; use
browser_visibility to show or hide the live panel later without stopping its
session, capture, ownership, or MCP control. Call browser_close on a panel
you own when the user is done with it or a remote device session must be
released now; it stops the session, releases any remote allocation, and the
panel leaves browser_list. Read anything you still need from
browser_audit before closing: it answers only for a live panel. An optional bare-host url
defaults to HTTPS while explicit HTTP remains available. Use browser_panel
for a known panel. Discovery and control are scoped to the workspace that
contains your agent panel: browser_list never shows panels from other
workspaces, every other tool rejects their ids, and a panel's visible field
is host presentation state, not proof that the panel is in your workspace. If
nothing usable is listed, create a panel rather than guessing an id. On a cloud
worker, your injected actor must match a registered workspace session. For a
request addressed to the current worker, an actor outside that workspace receives panel_outside_workspace before a browser starts.
Use the registered session identity; do not retry an unregistered actor. Before
interacting, call browser_snapshot or browser_query and prefer its
short-lived ref in browser_act. Remote iOS clicks and field entry use
synchronous target checks before trusted native input. Verify the visible result
after each action. browser_evaluate works on a driver that omits its script
timeout, and it awaits a returned promise: a rejection is a javascript_error
and an unsettled promise is an evaluation_timeout.
Navigation, another snapshot or query, and
browser_wait can invalidate earlier refs, so reacquire a ref immediately
before an action when the page may have changed.
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- today Changed · +12 lines eb9945a2586c
- yesterday Changed · +25 lines 34f7c506c66d
- 2d ago Changed · +44 lines de7693f1a5c8
- 5d ago Changed · +1 lines 3d79c703341d
- 6d ago Changed · +17 lines 0fc1b37e456c
- 9d ago Changed · +5 lines b89d15aac1b5
- 12d ago Changed · +16 lines 3b6a95698abc
- 13d ago Changed · +32 lines 2b528ba38e69
- 14d ago Changed · +5 lines ac9b9a9b0b83
- 17d ago First seen · 310 lines · 20 tokens per session scan A 9de8fb677228
horizon-browser is a skill published in the GitHub repository peters/horizon (722 stars, last pushed today), licensed MIT. It adds 20 tokens to every session and 6,928 once invoked, about $0.0001 per session on Opus 5.5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-30.
Other skills, from other repositories
web-test
A browser-testing tool for 1C:Enterprise, an enterprise business software platform, using Playwright to automate the web client.
computer-use
Drives the GUI of a visible local app window through orca computer: accessibility tree, clicks, typing, menus, dialogs, and screenshots in native apps and external browser windows (Chrome, Edge, Safari) or webviews. Prefer a programmatic path (shell, filesystem, git, HTTP, existing CLIs) whenever it can complete the…
moli-webfetch
Fetch, inspect, crawl, and capture live, JavaScript-rendered websites with Moli. Use when Codex needs current web content, web research, fact lookup, link following, a bounded crawl, client-rendered or response-gated content, network diagnostics, or a standalone HTML, Markdown, JSON, semantic-tree, viewport or…
moli-websearch
Search the web by keyword or reverse-search images with Moli to find subjects, sources, exact matches, or similar images—even when Moli is not named. For fetching a known URL, use moli-webfetch.
moli-cdp-server
Start Moli's CDP server and connect Playwright, Puppeteer, or raw CDP clients. Use to run a headless-browser CDP endpoint, replace a Chromium process, attach over CDP, enable real layout and screenshot surfaces, or diagnose CDP discovery, connection, and target startup—even when Moli is not named.
webapp-testing
Start/reuse a local app, wait for readiness, inspect rendered state/console/network, act from observed selectors, and verify with evidence.