Hypagon Gateway

⚡ Hypagon Gateway

The local browser for AI agents.

Hypagon — browser automation, local intelligence

"I'll hack the Gibson"
— Dade Murphy (AKA Crash Override), Circa 1995

version tools resources license platform

🧭 Index


🕶️ What it is

Hypagon Gateway is a visible, stateful web browser that any MCP agent can drive.

Most agent browsers are a library you integrate, or a cloud you rent. Hypagon Gateway is a desktop application you own: a real Chromium window on your machine, controlled over the Model Context Protocol. Your agent runs where you already run it — local or remote — and Hypagon Gateway supplies the browser, the input, and the memory.

Hypagon Gateway searches Google, opens AI Mode and answers its question

Recorded from the running app: Google → “hypagon definition” → AI Mode. Open the MP4 if your browser does not animate WebP.

[!WARNING] EXPERIMENTAL PROTOTYPE: Hypagon Gateway is currently under active, experimental development. Tool contracts, telemetry tuning, and database schemas may evolve rapidly. Built for developers experimenting with multimodal local AI agents.

[!IMPORTANT] RESEARCH PURPOSES ONLY: This software is provided strictly for educational, testing, and local AI agent research purposes. It is not intended for malicious use, automated credential stuffing, unauthorized exploitation, or violating third-party websites' Terms of Service. Users are responsible for complying with all applicable laws and terms.

Installers: grab them from Releases — Windows Setup/Portable/zip, macOS dmg/zip (x64 + arm64), Linux AppImage/deb/tar.gz. macOS is unsigned for now: right-click → Open (or xattr -dr com.apple.quarantine "/Applications/Hypagon Gateway.app"). Built by GitHub Actions; see docs/BUILDING.md.

🤘 A Punk-Ethos, DIY Alternative to browser-use, Playwright Agents & Hosted Browser Clouds

Most "AI browser" tooling today is a library you integrate, or a cloud you rent. browser-use is a popular MIT-licensed Python framework that drives Playwright with its own agent loop (plus an optional hosted cloud); Playwright / Puppeteer / Selenium are general-purpose drivers where you write the loop; and managed browser clouds run a remote Chromium and bill per session. They're good tools — this isn't a rivalry, it's a different shape.

Hypagon Gateway is the other road: a single, self-hosted desktop app you own (Electron, no account, no dashboard). It runs a real, visible Chromium on your own machine and speaks MCP over stdio (+ a localhost bridge), so it drops into whatever agent runner and whichever model you already use — local or remote, with no cloud account, no API key, no seat pricing, and no telemetry leaving your box.

That's the punk ethos: one operator, one machine, a tool you can read, fork and keep. Built by one person, not a company. No VC, no roadmap-by-committee, no dashboard.

How it differs, honestly

browser-use (Python / Playwright) Playwright · Puppeteer agents Hosted browser clouds Hypagon Gateway
Shape Library with its own agent loop Driver — you write the loop Managed remote browser MCP server any MCP client can call
Browser Playwright Chromium (often headless) Playwright / Puppeteer Remote Chromium Visible Chromium (headless: false) in an Electron chassis
Where it runs Your machine, or their cloud Your machine / your CI Their datacentre Your machine, always — local-first
Model Bring your own (usually a cloud LLM) Bring your own Bring your own Bring your own — local or remote
Input Playwright-driven events Playwright-driven events CDP over the wire Focus-independent CDP input + Bézier ghost cursor + Gaussian typing (isTrusted: true)
Memory Framework-level, BYO store none Their store Local LanceDB "Cortex" — semantic recall of everything it harvests
Cost MIT + your LLM (+ optional cloud) Free + your LLM Per-session billing MIT. No cloud, no metering, no telemetry.

What that buys you in practice

New here? Plain-English FAQ

What is this, in one sentence? A web browser that an AI can drive for you: it opens real pages, reads them, clicks, types, fills in forms, and remembers what it found.

Is it a browser I use myself? It's a real browser window. You can watch it, and you can take over at any time — most people just let their AI do the driving.

Do I need to be a programmer? To use it with an AI assistant you already have: no — you paste one line of configuration into that assistant. To change how it behaves internally: yes, it's a code project.

What's an "MCP server", in plain terms? MCP is a standard plug shape for AI tools. If your AI app accepts MCP plugins, it can use this one. Claude Desktop, Cursor and several other apps speak it.

Can I install an agent skill too? Yes. The hb-browser and hb-wrap skills are at skills/.

hermes skills install https://raw.githubusercontent.com/hyperbolictonic/hypagon/main/skills/hb-browser/SKILL.md
hermes skills install https://raw.githubusercontent.com/hyperbolictonic/hypagon/main/skills/hb-wrap/SKILL.md

npx skills add hyperbolictonic/hypagon --skill hb-browser
npx skills add hyperbolictonic/hypagon --skill hb-wrap

Add -g -y to the npx commands for a non-interactive global install.

Which AI can drive it? Any assistant that supports MCP — a cloud service, or a model running on your own computer. You choose, and you aren't locked to one provider.

Do I need to pay for anything? No subscription and no account. The software is free and open source. The only cost is whatever you already pay for your AI, if anything.

Where does my data go? Nowhere. The pages it reads, the notes it keeps and the logs all stay on your computer. There's no company server in the middle and no usage tracking.

Could a website tell it's a bot? It's built to be hard to spot: a normal visible browser, mouse movement and typing that look human, and it clears cookie banners politely. Nothing is unbeatable, but it isn't the obvious "automated script" that gets blocked.

What happens at a CAPTCHA? It doesn't solve them. It asks you to step in (it can send a notification and bring the window forward), then continues once you're done.

Does it run headless on a server? Not really, and that's on purpose. It runs a visible browser on a normal desktop, which is exactly why it looks human. For large-scale server-side scraping, a different tool fits better.

Is using it allowed? It's for personal research and testing. You still have to follow each website's rules and the law — running it yourself doesn't change that. Don't use it to break into accounts or ignore terms of service.

What do I need to run it? A normal Windows desktop (that's the tested target). If your computer can run a browser and an AI assistant, it can run this.

Is it finished? No. It's an experimental project by one developer — expect rough edges and things that change.

FAQ for developers — browsers, memory, and the tricky bits

Is there a self-hosted, open-source alternative to browser-use? Yes — MIT-licensed and entirely local. But note the shape: this is a tool surface, not an agent framework. If you want a Python framework that owns the loop, browser-use is the right tool; if you want a self-hosted browser that your own agent drives, this is it.

Can I use it with Claude Desktop, Cursor, or a local LLM? Yes. It's an MCP server, so any MCP client works - point your client at bin/mcp-server.cjs and the hb-browser tool namespace appears (legacy kuang alias still works).

Does it need a cloud account, API key, or per-session billing? No. There is no cloud tier. The only network calls are the ones your agent makes to the pages it visits (plus, optionally, a search engine via search_web).

Is it headless? Deliberately the opposite. It runs a visible Chromium so a human can watch, take over at a CAPTCHA, and so the session stays an honest, real browser. Headless-at-scale scraping is a different job; this is a single operator's console.

Will Cloudflare block it like Puppeteer / Playwright? It's built for exactly that fight: real CDP input with isTrusted: true, cubic Bézier pointer kinematics, Gaussian typing cadence, a genuine cookie jar, and an autonomous consent-modal breaker. No promises — anti-bot is an arms race — but it is not naive headless emulation.

Can I point it at my existing Playwright test suite? No. This isn't a test driver; Playwright remains excellent for deterministic suites. Grade Eleven is an agent-facing browser an LLM operates.

Where does memory live? Locally, in LanceDB ("Cortex"): harvested pages and vaulted scripts are embedded and semantically recallable, so your agent keeps research context across sessions without a hosted vector store.

Is it production-ready? No — it's an experimental prototype for local AI research. That's rather the point.

Punk ethos, not carte blanche. Owning your tooling doesn't change the law: the RESEARCH PURPOSES ONLY terms at the top of this README still apply. The point is ownership and readability, not immunity.


🎯 Core Architecture Principles

  1. 100% Real Browser Chassis: No headless emulation, synthetic user-agent spoofing, or sandboxed scraping. Hypagon Browser runs a full-fledged, visible Chromium instance (headless: false) with hardware acceleration, audio/video capabilities, and authentic cookie/session persistence.
  2. Multimodal Vision Integration: Specifically tailored for multimodal models (e.g. Bonsai 2 27B). The agent takes high-res viewport screenshots (take_screenshot) to visually understand layouts, buttons, and dynamic canvas states, and can act directly by coordinate, selector, or mark badge (act).
  3. Full Developer Console & Script Execution: Gives the agent full console access (get_console_logs) to inspect runtime errors and API output, plus arbitrary JavaScript evaluation (evaluate_javascript) to interact with complex SPAs.
  4. Behavioral Bot Detection Bypass: Bypasses Cloudflare, Akamai, Datadome, and behavioral bot sensors by avoiding synthetic element.click() events (isTrusted: false). Instead, it dispatches real input events over the Chrome DevTools Protocol (Input.dispatchMouseEvent / Input.dispatchKeyEvent / mouseWheel) accompanied by organic cubic Bézier pointer movement and human Gaussian typing cadence. CDP delivery is focus-independent — it lands even when another application owns the OS foreground — with webContents.sendInputEvent kept only as a fallback.

🎨 Theme & Cyberdeck Interface

Built with Tailwind CSS v4 and DaisyUI 5:


🕹️ Ghost Cursor Telemetry Engine


🎛️ Focus-Independent Input & Background Rendering

Two real-desktop failure modes are handled explicitly so long harvests and HIL flows stay reliable:


🧩 Orthogonal Primitive Layer

The older tool list is being consolidated onto a few orthogonal verbs - one observation model, one action model, one wait model - with the flat tools becoming projections. All primitives run on the TIER-1 humanlike path (real input events; no page DOM mutation beyond Hypagon Browser's own data-mark-id stamp).

Primitive Job Replaces
observe(as, region, budget, cursor) One budgeted, cursor-paged observation model (markdown/text/ax/som/list/table/app_data) get_page_markdown + snapshot_rendered_page + list_marks
act(mark_id | selector | x+y, action, text, secret, await_conditions, dry_run) Unified humanlike click/focus/hover/type/press on a mark ref, CSS selector, or coordinate + optional post-conditions + delta report click_mark/type_mark/click_element/type_text plus a following wait
wait_for(conditions, require, timeout_ms) Declarative readiness gate — the primitive that replaces blind sleeps every sleep/"did it load?" guess
expect(conditions) Immediate assertion (no polling) with per-condition evidence agent-side guessing
find(role, name, contains, regex, tag, selector) Semantic element search → refs (mark ids) hand-written CSS/XPath
extract(kind, ref, selector) Structured reads: repeating list rows, table records, embedded app_data regex over HTML
collect_all(selector, scroll, max_scrolls) Scroll a lazy/virtualized list to the end and dedupe rows in one call a manual scroll-and-harvest sweep
page_state() / diff(since) Cheap monotonic change signature + field-by-field diff for loops re-reading the whole page
bridge_health() Liveness, capabilities[], revision, window, input.transport assuming the bridge is up
export_har(pattern, save) · context_* HAR 1.2 export · named cookie/storage profiles ad-hoc replay · manual session juggling

Refs are marks. A ref is a Set-of-Marks badge id — find returns rows carrying the mark, and act(mark_id=…) consumes it (re-resolving the live centre each time). When there is no badge, the same act also takes selector="…" or x=/y= — one action tool, three address modes.

Wait vocabulary: selector · gone · text/regex · url · role_name · count(min/equals/max) · network_idle · stable(marks|height|text|nodes) · revision.

Structured errors: new endpoints return a machine code (HTTP 400) — STALE_REF (re-scan and re-issue), TIMEOUT, NO_TARGET, BAD_REQUEST, NOT_SUPPORTED.

Full recipes (R1–R5), the wait table, and the error catalogue live in the OKF partition hypagon_docs/partitions/primitives_and_workflows.md, also readable as the MCP resource mark-eleven://okf/partitions/primitives-and-workflows.


📄 Token-Efficient Construct Harvester

🗜️ JEV Page Compaction

Just-Enough-View (JEV) keeps a large page out of the agent's context window. Instead of a full Markdown dump, the agent gets a compact section index — headings, token weights and one-line digests — and fetches only the sections it needs from an in-memory depth store.

Tools: jev_index, read_section, search_page. Full contract and limits: docs/JEV.md.



🧠 LanceDB Persistent Cortex & Semantic Recall

Hypagon Gateway features an embedded, serverless vector database (LanceDB) combined with Tantivy-powered Full-Text Search (BM25) stored locally under ./data/cortex/.


📑 Hardware-Accelerated Multi-Tab Browsing


🛡️ Autonomous Shield-Breaker (Cookie & GDPR Destroyer)


🎯 Set-of-Marks (SoM) Visual Grounding


📝 Single-Turn Batch Form Filler


📥 Download Manager & Cortex Harvester


📥 Media download integration

Read docs/MEDIA.md for the design notes and threat model.


🎥 Timelapse Recorder


🔐 Session & Cookie Jar Vault


📡 Live Network & API Stream Interceptor


⚡ Real-Time WebSocket & SSE Interceptor


💾 Script Vault & LanceDB Semantic Macro Engine


🗔 System Tray & Background Minimization ("Out of the Way")


🚨 Human-In-The-Loop (HIL) Intervention Protocol


🔌 Consolidated Semantic MCP Tools (16 advertised · +2 decision · +3 JEV)

Advertised surface: 17 grouped tools, plus drive and decide when a decision model is configured, and jev_index, read_section and search_page when JEV page compaction is on. The old flat names remain callable by name but are hidden from tools/list; they are listed below as the underlying catalog.

Tool manager: Settings → Tools controls enablement, order, per-tool instructions, per-action instructions for grouped tools, and Core/Research/Automation/Full presets. The default order starts with navigate → observe → act → wait_for → find → extract.

Tier map: TIER 1 · prefer: navigate, observe, act, wait_for, find, extract; TIER 2 · fallback: capture; TIER 3 · deliberate: evaluate_javascript. drive and decide are Tier 1 when a decision model is configured.

Tool Actions / scope
navigate open, back, forward, reload, consent, scroll, recipe
observe markdown, text, AX, Set-of-Marks and components projections
find Semantic target search returning mark refs
act click, focus, hover, type, press, scroll and multi-field fill
wait_for Declarative readiness gate
extract list, table(s), app data, schema.org and lazy-list collect
capture viewport/Set-of-Marks screenshot or rendered snapshot
evaluate_javascript Deliberate page JS execution
devtools state, diff, console, network, streams, HAR, JSON query, fingerprint, health
human_in_loop request/status/resolve HIL, activity/resume, notify, window and tray
collaborate highlight, ask, read, reply and resolve human page threads
browser_workspace tabs, downloads, contexts, recordings and scripts
media status, info, preview, transcript, download, jobs, cancel, list
shadow_iframes frames, focus_walk
research read, search, LLM surface/fetch, crawl, topic research, prerender
memory recall, browsing history and bookmarks
help Categorized operational cheatsheet
jev_index (JEV) Section index for the active page — the preferred read when JEV is on
read_section (JEV) Fetch one indexed section, optionally with children
search_page (JEV) Keyword/regex search across all section text
drive (optional) Goal-driven observe → decide → act loop
decide (optional) Typed decision model

Underlying catalog (hidden aliases)

The table below documents the flat catalog entries. Most are hidden from tools/list behind the groups above; they remain callable by name for compatibility and are useful when editing tool instructions.

Category Tool Parameters Description
⌥ Optional ⌥ drive goal, values?, max_steps?, threshold?, dry_run? Listed first when a decision model is configured. Runs observe → guarded decide → verified act in one call and returns a typed stop reason (done/blocked/human_required/needs_agent/failed/max_steps). Absent otherwise.
⌥ Optional ⌥ decide state, questions, model?, guard?, eliminate?, include_page_text?, include_screenshot? Listed first when configured. One typed decision (choice/score/noul) over a state, answers forwarded verbatim, with an optional guard + elimination. Absent otherwise.
Primitives & Abstraction observe as?: 'markdown' | 'text' | 'ax' | 'som', region?: number | string, budget?: number, cursor?: string, include_offscreen?: boolean, limit?: number The page read (TIER 1). One budgeted observation model with projections. Use budget + next_cursor to page a large page instead of truncating. Absorbed get_page_markdown / harvest_markdown / list_marks; structured reads live on extract.
act mark_id?: number, selector?: string, x?: number, y?: number, action?: 'click' | 'focus' | 'hover' | 'type' | 'press', text?: string, secret?: boolean, clear_first?: boolean, await_conditions?: object[], timeout_ms?: number, dry_run?: boolean The interaction entry point: one humanlike action addressed by mark ref, CSS selector, or coordinates, with optional post-conditions and a delta report. Selectors pierce open shadow roots and resolve a custom-element host to the control a mouse would hit. secret: true redacts typed text from logs; dry_run: true resolves without acting. Typing appends by default - pass clear_first: true on a pre-filled field (origins, search boxes, comboboxes) to replace instead (trusted Ctrl+A + Backspace). Typing is verified: a provable no-op returns ok: false with error.code: "TYPE_NO_EFFECT" and typing evidence (key counts and value lengths - never the text).
wait_for conditions: object[], require?: 'any' | 'all', timeout_ms?: number, poll_ms?: number Declarative readiness gate — polls until every/any condition holds, then returns. The primitive that replaces blind sleeps.
find role?: string, name?: string, contains?: string, regex?: string, tag?: string, selector?: string, limit?: number, include_offscreen?: boolean Semantic element search returning Set-of-Marks refs (mark ids) instead of pixels. Feed ids straight into act.
extract kind?: 'list' | 'table' | 'tables' | 'app_data' | 'schema_org', ref?: number, selector?: string, type?: string, limit?: number Structured, read-only extraction: repeating rows, one table, every table, embedded app JSON (__NEXT_DATA__/JSON-LD), or typed schema.org items (kind:"schema_org" flattens @graph; type filters to e.g. "Recipe"). Article extraction is observe(as:"markdown") (Readability).
collect_all selector?: string, ref?: number, scroll?: 'container' | 'window', step?: number, delay_ms?: number, max_scrolls?: number, max?: number Scrolls a virtualized/lazy list to the end and collects every distinct row (deduped by text+href) in one call, with scroll diagnostics.
expect conditions: object[] Immediate assertion (no polling) over the same vocabulary as wait_for; returns pass/fail plus per-condition evidence.
page_state none Cheap monotonic state signature (revision, url, marks, nodeCount, height, scrollY, textLen, textHash) for change detection without re-reading the page.
diff since?: number Field-by-field diff between the current state and a previously observed revision — shows exactly what changed.
llm_surface url?: string Checks whether a site publishes an LLM-friendly representation (/llms.txt / /llms-full.txt, /sitemap.xml, a <link rel="alternate"> or a real <a href="….md"> page link, or Markdown content negotiation) and returns recommended — "llms_txt" | "llms_full" | "markdown" | "text", or null when there is none (never "rendered"). Also scope ("origin" | "page") and next — the unambiguous next step (llm_fetch(as) or observe({as:"markdown"})). Well-known paths only; cached per origin.
read_url url?: string, max_chars?: number, cursor?: string | number, as?: 'llms_txt' | 'llms_full' | 'markdown' | 'text' Read any URL as Markdown in ONE call. Reads the site's own representation when one covers the URL asked for (a page-level alternate for a page); otherwise a detached render distilled to Markdown (your active tab is never hijacked). A site-wide index is never returned in place of a page — the page is rendered, and reason says why. Always returns text, so you never branch on recommended. Reports via, scope, scope_mismatch and reason; paged with max_chars + next_cursor.
llm_fetch url?: string, as?: 'llms_txt' | 'llms_full' | 'markdown' | 'text' Fetches that advertised Markdown/Text representation (~5–10× cheaper than a render). Gated: refuses (NO_LLM_SURFACE) unless the site advertises a surface. Reports scope + scope_mismatch (page requested, site-wide index returned). Per-page alternates load via a real navigation, not a synthetic fetch.
search_web query: string, engine?: 'google' | 'duckduckgo' | 'bing' | 'brave' | 'startpage' | 'custom', engines?: string[], url_template?: string, max_results?: number Multi-engine web search run in a detached view (your active tab is untouched) with automatic fallback when an engine bot-checks. Returns ranked {title, url, snippet} to feed navigate_to/collect_all. custom takes a {query} template (e.g. SearXNG).
deep_crawl url: string, max_depth?: number, max_pages?: number, match_patterns?: string[], same_origin?: boolean, prefer_llm?: boolean, harvest_to_cortex?: boolean, selector?: string, delay_ms?: number Autonomous BFS crawl from a seed: follows same-origin links within depth/page budgets, distills each page to Markdown, and indexes it into LanceDB Cortex. Each page takes the cheap path first (content-negotiated Markdown/Text, else a detached render). match_patterns scopes by glob or /regex/.
research_topic query: string, max_sources?: number, engine?, engines?: string[], url_template?: string, excerpt_chars?: number, harvest_to_cortex?: boolean, prefer_llm?: boolean Autonomous research mode: searches, gathers the top sources (cheap Markdown path first), distills them, and indexes them into Cortex. Returns extractive, cited evidence — each highlight is a real paragraph mentioning the query terms. It does not write prose; you synthesize the answer.
bridge_health none Liveness + capability discovery: version, revision, capabilities[], window {visible, focused}, input {transport}, lastActionAt.
context_save name?: string Saves the current browsing context (cookies + storage) as a named profile.
context_open name: string Restores (switches to) a named browsing context/profile.
context_list none Lists saved browsing contexts (cookie/storage profiles).
context_delete name: string Deletes a saved browsing context/profile.
† focus_window none Deprecated — use set_window_visibility({ visible: true }). Brings the Cyberdeck window to the foreground (HIL visibility, or the legacy native input fallback).
Navigation navigate_to url: string, auto_dismiss_consent?: boolean Navigates active tab to URL. Auto-dismisses GDPR/cookie overlays by default. Supports 0ms instant elevation if pre-rendered.
† go_to_url url: string, auto_dismiss_consent?: boolean Primary alias for navigate_to. Dispatches visible window navigation.
navigate_history action: 'back' | 'forward' | 'reload' Browser history navigation and reload controls.
† get_page_info none Returns current URL, title, and load state without full extraction.
Shield & Defense dismiss_consent none Autonomously detects and dismisses GDPR/cookie banners via Bézier mouse click.
Interaction † click_element selector?: string, x?: number, y?: number Deprecated — folded into act(selector: …) / act(x: …, y: …). Clicks element by CSS selector or direct viewport (x, y) coordinates.
† type_text text: string, selector?: string Deprecated — folded into act(action: "type", text: …, selector: …). Types text with human Gaussian cadence variance (60–240ms).
fill_form fields: Record<string, string | boolean | number>, submit_selector?: string Fills multiple form inputs, selects, and checkboxes in a single turn.
press_key key: string Presses specific key (e.g. Enter, Tab, Escape, Backspace).
scroll_page direction: 'up' | 'down', amount?: number Incremental momentum wheel scrolling.
Observation & Vision take_screenshot marks?: boolean, detail?: 'full' | 'economy' | 'markdown', include_offscreen?: boolean, max_width?: number, format?: 'jpeg' | 'png', quality?: number Viewport capture. Plain mode (default) returns a bounded 768px fast JPEG (~15ms encode, tiny wire payload); marks: true returns Set-of-Marks with detail: 'full' (PNG), 'economy' (640px JPEG), or 'markdown' (marks table, no image). Returns file path text & native MCP image block. Saved to data/screenshots/ with automatic retention pruning.
† get_page_markdown none Downsamples active DOM to clean token-efficient Markdown with YAML metadata.
† harvest_markdown none Primary alias for get_page_markdown. Extracts clean markdown from the active tab.
snapshot_rendered_page format?: 'ax_tree' | 'markdown' | 'html' | 'unrendered_html', wait_until_idle_ms?: number, pierce_shadow_dom?: boolean, force_rerender?: boolean, save_to_disk?: boolean Rendered Point-in-Time Snapshot. Freezes dynamic SPAs, pierces Shadow DOM, and extracts ultra-token-efficient Accessibility (AX) Trees, rendered Markdown, or unrendered source HTML.
prerender_links urls?: string[], selector?: string, max_pages?: number, harvest_to_cortex?: boolean, wait_until_idle_ms?: number Speculative Pre-rendering Engine. Pre-hydrates candidate links in background views for 0ms instant navigation, and auto-indexes into LanceDB Cortex memory.
evaluate_javascript script: string Evaluates custom JS expression in page context and returns serialized JSON. Accepts script, code, or expression. A powerful tool that can read and mutate — reach for it deliberately (observe/act cover the common cases, and injected JS is a bot-detection signal).
get_console_logs limit?: number Returns recent web page and script console logs, warnings, and errors.
get_fingerprint_profile none Returns active stealth host browser fingerprint and spoofed headers.
Multi-Tab new_tab url?: string Spawns a new independent browser tab instance.
switch_tab tab_id: string Activates and focuses the specified tab.
close_tab tab_id?: string Closes tab and reclaims memory resources.
list_tabs none Returns structured array of all open tabs (IDs, titles, URLs, active status).
LanceDB Memory recall_memory query: string, limit?: number, domain?: string Performs hybrid vector and BM25 full-text search across visited pages and markdown.
browsing_history limit?: number, domain?: string Chronological browsing history from persistent LanceDB cortex.
browsing_history_clear older_than?: string Prunes or purges browsing history from persistent storage.
add_bookmark url?: string, title?: string, notes?: string, tags?: string[] Saves active or specified page with tags and notes in LanceDB.
list_bookmarks query?: string, tag?: string, limit?: number Retrieves or filters saved bookmarks by query terms (title/notes/URL/tags) or exact tag.
delete_bookmark url_or_id: string Deletes bookmark by URL or unique ID.
Downloads & Docs list_downloads none Lists all files downloaded into data/downloads/ with sizes, state, and timestamps.
read_download filename_or_id: string Parses downloaded file (PDF, CSV, JSON, text) into token-efficient markdown.
Timelapse Recording record_start name?: string Starts a timelapse of the Cyberdeck window itself: frames are captured every few hundred ms and played back faster than real time. The finished .webm path becomes an ordinary value you can type into a file-upload field.
record_stop none Stops the timelapse and saves it (VP9/WebM). Returns the absolute path, size, frame count and speed-up factor.
list_recordings limit?: number Lists finished timelapses as absolute paths, newest first — ready for upload fields.
Session Vault † save_session name?: string Captures active cookies and localStorage state into persistent JSON vault.
† restore_session name: string Rehydrates cookies and localStorage state into browser session.
† list_sessions none Lists all stored session snapshots with timestamps and cookie counts.
Network Intelligence get_network_traffic url_pattern?: string, method?: string, resource_type?: string, limit?: number, since?: number | 'last_action' Inspects live HTTP/XHR/Fetch requests captured via Chrome DevTools Protocol (returns compact 1-line markdown summaries). since narrows to requests after an epoch-ms timestamp, a page revision, or the last mutating action.
† get_api_payload request_id: string Retrieves and parses the full raw JSON or text response body for an intercepted request.
query_json_data source: string, source_id?: string, path?: string, view?: string, filter_predicate?: string, max_items?: number, max_string_length?: number Token-Efficient JSON Navigator. Queries large payloads/streams/files via dot/bracket paths (items[0..3].price), extracts schemas, searches keys, and applies filters without context-window blowup.
† clear_network_traffic none Deprecated — use clear_capture({ scope: "network" }). Resets the in-memory network traffic ring buffer.
export_har pattern?: string, limit?: number, save?: boolean Exports captured traffic as a HAR 1.2 log (request/response headers + body previews). save: true writes data/har/har_<ts>.har and returns the path.
list_realtime_streams type?: 'websocket' | 'sse', active_only?: boolean Lists active WebSocket connections and open SSE channels in compact 1-line format.
† get_stream_messages stream_id?: string, type?: string, direction?: string, limit?: number Inspects captured incoming/outgoing frames from WebSockets and SSE token streams.
† clear_stream_messages stream_id?: string Deprecated — use clear_capture({ scope: "streams" }). Clears the in-memory WebSocket and SSE message frame buffer.
clear_capture scope?: 'network' | 'streams' | 'all' Clears the in-memory capture ring buffers: HTTP traffic ("network"), WebSocket/SSE frames ("streams"), or both ("all", default).
Visual Grounding † take_annotated_screenshot none Tags all visible interactive elements with numbered neon badges ([1], [2], etc.). Returns dual content: Set-of-Marks table text & native MCP image block (type: 'image'). Saved to data/screenshots/.
† take_economy_screenshot none Lightweight variant: same marks table, but the image is downscaled to 640px wide and JPEG-encoded (q45, image/jpeg). Saved to data/screenshots/ as annotated_eco_*.jpg.
† list_marks none Text-only variant: returns the marks table with no image and no file written. Ideal for text-only models.
† click_mark mark_id: number Deprecated — folded into act(mark_id: …). Moves humanized Bézier ghost cursor to mark #ID and clicks with 100% accuracy.
† type_mark mark_id: number, text: string, clear_first?: boolean Deprecated — folded into act(mark_id: …, action: "type", text: …). Focuses mark #ID and types with variable human typing cadence.
Shadow DOM & Frames frames include_controls?, screenshots?, selector?, max_frames?, max_controls?, include_offscreen?, max_side? Lists iframes as first-class content: frame rect, URL and controls with viewport-offset coordinates. Opt into per-frame screenshots for cross-origin widgets and embedded checkouts.
focus_walk selector?, x?, y?, direction?, max_steps?, restore? Enters a closed shadow root like a keyboard user: focus the host, send trusted Tab/Shift+Tab steps, and read the accessibility tree to confirm the landed control.
Script Vault & Macros save_script name: string, code: string, description?: string, domain?: string, tags?: string[] Saves and embeds a custom JavaScript macro into LanceDB Cortex.
† recall_script query?: string, domain?: string, tag?: string, limit?: number Deprecated — use list_scripts({ query }). Semantically searches saved scrapers & macros using natural language.
run_script name: string, args?: object Executes a saved script in active tab with dynamic runtime arguments.
list_scripts query?: string, tag?: string, limit?: number Lists or semantically searches registered macros in the persistent vault (query ranks by relevance).
delete_script name: string Removes a script from the persistent vault and vector index.
Desktop & System Tray set_window_visibility visible?: boolean, focus?: boolean Shows/restores the window (and focuses it by default) to make it visible to a human, or minimizes it to the Windows notification tray.
configure_system_tray close_to_tray?: boolean Configures tray options such as close-to-tray background operation.
Human-In-The-Loop & Alert request_human_intervention reason: string, timeout_seconds?: number, bring_to_front?: boolean Halts agent, triggers native OS alert, unhides window, and injects interactive banner for CAPTCHAs/credentials.
resolve_human_intervention id?: string, notes?: string Resolves active intervention request and resumes agent execution.
get_human_intervention_status none Checks active HIL request status and history. Does not report the passive takeover window; use get_human_activity.
get_human_activity none Reports the passive human-takeover window that blocks synthetic input: active, remaining pause and the last human event.
resume_agent none Clears a passive takeover pause after the human confirms. Does not resolve a pending request_human_intervention.
send_notification title: string, message: string, urgency?: string, sound?: boolean Emits non-blocking OS native desktop banner notification to user.
† send_desktop_notification message: string, title?: string, urgency?: string, sound?: boolean Dedicated HIL notification tool to summon the human operator with high-priority desktop sound and alert banner.
Navigation Recipes recipe action?: 'list' | 'save' | 'replay' | 'delete', id?, url?, name?, path?, steps?, expect_timeout_ms? Compiles a page path into descriptor steps and replays it with zero model calls. Scoped to origin + path; retires after three failed replays.
Assistance & Discovery help category?: 'all' | 'recommended' | 'navigation' | 'interaction' | 'primitives' | 'inspection' | 'tabs' | 'memory' | 'macros' | 'network' | 'system' Returns a categorized operational cheatsheet of all available browser automation capabilities (served directly in OKF).

🔌 REST wrappers (hb-rest)

A second, separate MCP server for turning a REST endpoint into a saved, typed tool. It is deliberately not mixed into the browser server: hb-rest ships its own binary, its own stdio process, its own config entry and its own bridge token.

Browser REST wrappers
Binary bin/mcp-server.cjs bin/wrap-server.cjs
Server name hb-browser (legacy: kuang) hb-rest (legacy: kuang-wrap)
Surface 16 advertised browser tools (+2 optional decision tools) 10 wrap_* meta-tools + up to 40 generated wrap_<id> (configurable via HB_WRAP_MAX_TOOLS or legacy KUANG_WRAP_MAX_TOOLS)
Env HB_BRIDGE_URL (legacy: KUANG_BRIDGE_URL) HB_WRAP_TOKEN_FILE (legacy: KUANG_WRAP_TOKEN_FILE)

What it is for: agent access to JSON APIs (dashboards, internal tools, SaaS). The wrapper author — human or agent — defines the request once: method, URL, typed arguments, a response recipe, and a credential name. The agent then calls flat arguments; it never assembles a URL, a header set, or a body envelope, and it never sees a credential value.

Credentials are human-only and host-bound: a static value, or an OAuth2 client-credentials client that mints and caches a token. Secrets are encrypted with the OS keychain (safeStorage), injected only on an approved host, and never enter the MCP process.

// Settings → MCP Clients → REST wrappers generates an entry like this
{
  "mcpServers": {
    "hb-rest": {
      "command": "node",
      "args": ["<path-to-repo>/bin/wrap-server.cjs"],
      "env": { "HB_WRAP_TOKEN_FILE": "<userData>/wrap/token" },
    },
  },
}

Meta-tools: wrap_list, wrap_get, wrap_secret_list, wrap_derive, wrap_create, wrap_update, wrap_delete, wrap_run, wrap_test, wrap_reload.

[!WARNING] Read the limits before relying on it. No human-approval gate for mutating calls · OAuth2 is client_credentials only · the wrap server does not raise HIL itself (a rejected credential returns AUTH_REQUIRED) · exposeAsTool has no Settings control · 40-tool cap · DNS-rebinding residual risk · the token URL is outside allowedHosts. The full, blunt breakdown — what works, what doesn't, what is untested, what is risky — is docs/HYPAGON_REST.md.

Tests: npm run test:wrap (50 offline) · npm run test:wrap:mcp (11 lifecycle) · npm run test:wrap:live (46 against DummyJSON).


🗺️ Codebase Directory Structure & Documentation

Each folder contains a dedicated README.md detailing its responsibilities, dependencies, and internal workflows:

Directory Documentation Link Description
docs/ docs/CODEBASE.md Architecture lowdown, field notes, decision-model notes, build and packaging docs.
scripts/ scripts/README.md Test harnesses, release helpers (check-release-tag, release-notes), the MCP bundle build, and one-off tools.
public/ public/README.md Static web root and the built-in offline Cyberdeck Manual (welcome.html).
public/assets/ public/assets/README.md Tactical high-resolution brand insignia (legacy asset names retained for compatibility).
src/ src/README.md Root source directory organizing process-isolated TypeScript modules.
src/main/ src/main/README.md Electron main process, BrowserChassis coordinator, and HTTP bridge (:4111).
src/main/cortex/ src/main/cortex/README.md Embedded LanceDB vector database, 128-d embedder, chunker, and hybrid semantic recall.
src/main/tabs/ src/main/tabs/README.md Hardware-accelerated WebContentsView multi-tab pooling and popup trapping.
src/main/shield/ src/main/shield/README.md Autonomous Shield Breaker engine auto-dismissing cookie banners and GDPR modals.
src/main/downloads/ src/main/downloads/README.md Deterministic workspace file download routing and automatic document-to-Cortex ingestion.
src/main/session/ src/main/session/README.md Persistent cookie jar and session snapshot vault for cross-run auth persistence.
src/main/network/ src/main/network/README.md Chrome DevTools Protocol wire interceptor capturing background XHR/Fetch JSON streams.
src/main/marks/ src/main/marks/README.md Set-of-Marks visual grounding engine injecting numbered neon badges for zero-ambiguity LLM actuation.
src/main/primitives/ src/main/primitives/README.md Orthogonal primitive layer (observe · act · wait_for · expect · find · extract · collect_all · page_state/diff · export_har) with structured error codes and injected DOM probes.
hypagon_docs/ hypagon_docs/okf.json OKF (Open Knowledge Format) bundle hypagon_browser_docs — playbook/reference partitions exposed as MCP resources.
src/main/scripts/ src/main/scripts/README.md Persistent script vault and LanceDB semantic macro recall engine with parameter injection.
src/main/tray/ src/main/tray/README.md Windows System Tray integration and close-to-tray background minimization.
src/main/hil/ src/main/hil/README.md Human-In-The-Loop cooperative intervention protocol, OS notifications, and in-page alert banners.
src/main/telemetry/ src/main/telemetry/README.md Organic cubic Bézier mouse kinematics, Gaussian typing cadence, and stealth fingerprinting.
src/main/harvester/ src/main/harvester/README.md Mozilla Readability & Turndown token-efficient markdown distillation.
src/preload/ src/preload/README.md Sandboxed ContextBridge IPC exposing typed window.electronAPI to the DOM.
src/renderer/ src/renderer/README.md DaisyUI 5 Cyberdeck HUD, phosphor radar trail canvas, and Cortex modal dialogs.
src/shared/ src/shared/README.md Shared TypeScript contracts, telemetry events, and construct schemas.
src/mcp/ src/mcp/README.md In-process TypeScript MCP server definition for zero-overhead unified execution.
src/main/decide/ + drive/ docs/DECISION_MODELS.md Optional typed decision client, guard, human gate detection, and the observe → decide → act loop.
src/main/recording/ src/main/recording/recording-service.ts Timelapse configuration, window capture handshake, file writing, and the recordings registry.
src/main/search/ · crawl/ · research/ src/mcp/README.md Multi-engine search, breadth-first crawl, and cited research.
src/main/updates/ docs/BUILDING.md electron-updater wiring and release feed handling.

🚀 Quickstart

Development Mode (with Live Reloading)

pnpm dev

One bridge per port, one profile per process. A dev run and an installed build derive the same userData directory, so they share Electron's single-instance lock and the default bridge port 4111. To run both at once, give the dev run its own profile and port:

HB_USER_DATA_DIR="$APPDATA/hypagon-gateway-dev" HB_BRIDGE_PORT=4113 pnpm dev

Then point a second MCP client config at HB_BRIDGE_URL=http://127.0.0.1:4113 and HB_WRAP_TOKEN_FILE=<that profile>/wrap/token. The dev window's Settings → MCP Clients tab generates the config for you, with the right port and profile paths.

pnpm dev:isolated does all of that in one step: it starts the dev build on its own profile and port 4113, and prints a ready-to-paste MCP config.

Production Build & Launch

pnpm run build
pnpm start

MCP Client Configuration (OpenCode, Claude, Cursor, Antigravity, Atomic Chat)

The HUD's Settings → MCP Clients tab generates a correct, copy-ready config for this installation — OpenCode, Claude Desktop, Claude Code, Cursor, VS Code, Windsurf, Google Antigravity, Gemini CLI, Atomic Chat, Zed, and the generic mcpServers shape. It fills in the absolute server path and bridge port, and offers two runtimes:

A minimal Claude-style entry looks like this (the tab generates the real paths):

{
  "mcpServers": {
    "hb-browser": {
      "command": "<path-to-app>/Hypagon Gateway.exe",
      "args": ["<userData>\\bin\\mcp-server.cjs"],
      "env": { "ELECTRON_RUN_AS_NODE": "1" }
    }
  }
}

Note: the Cyberdeck must be running (pnpm run dev or pnpm start) so the stdio server can reach the browser instance on http://127.0.0.1:4111. If you run on another port with HB_BRIDGE_PORT, set HB_BRIDGE_URL for the MCP server — the generated snippet includes it automatically. Installed builds copy the server into userData/bin/ (refreshed on update), because resources/ is temporary for portable and AppImage builds.

Agent Skills

The MCP servers provide the tools; the skills teach the agent which grouped tool to use and give exact recipes. Install either skill directly from GitHub:

hermes skills install https://raw.githubusercontent.com/hyperbolictonic/hypagon/main/skills/hb-browser/SKILL.md
hermes skills install https://raw.githubusercontent.com/hyperbolictonic/hypagon/main/skills/hb-wrap/SKILL.md

Or with the Skills CLI:

npx skills add hyperbolictonic/hypagon --skill hb-browser
npx skills add hyperbolictonic/hypagon --skill hb-wrap

For a non-interactive global install, add -g -y. The source files are skills/hb-browser/SKILL.md and skills/hb-wrap/SKILL.md.

hb-browser covers the grouped tools plus the JEV read path (jev_index → read_section, including the enforce refusal); hb-wrap covers wrapper discovery, wrap_test dry-runs, recipes and credential hand-off.


🧪 Testing

All suites run against the live Cyberdeck on http://127.0.0.1:4111 (start the app first):

Command Suite What it proves
npm run test:harvest Harvest regression (4 checks) Markdown extraction, marks, off-screen marks still work end-to-end.
npm run test:primitives Offline primitives (25 checks) wait_for, extract, observe budget/cursor, collect_all, find+act+delta, expect, page_state/diff, bridge_health capabilities.
npm run test:mcp:primitives MCP stdio primitives (14 checks) The same primitives through a real MCP client — tool schemas, viewport gating, find→act, contexts, focus_window.
npm run test:focus Focus independence (4 checks) Hands the OS foreground to another app (Notepad) and asserts typing/clicks/wheel still land and that input.transport === 'cdp'.
npm run test:mcp-http MCP HTTP host (6 checks) Bearer auth, stateful and stateless MCP clients, session eviction, non-MCP path rejection, and idle expiry.
npm run test:navigation Navigation error mapping DNS, refusal, timeout, certificate and aborted failures map to 400 with stable NAVIGATION_* codes.
npm run test:cloudflared-tunnel Named tunnel manager (3 checks) Registration parse, startup timeout, process failure, and clean shutdown using a fake cloudflared fixture.
npm run test:cloudflared cloudflared manager (4 checks) Release selection, SHA-256 verification, atomic managed install, checksum rejection, unsupported-platform errors, and pure-Node macOS tar extraction.
npm run test:mcp-oauth MCP OAuth server (4 checks) Discovery metadata, forwarded HTTPS origin, authorization code + PKCE, token/refresh, bad verifier and disallowed redirect rejection.
npm run test:devlogs Dev logs MCP smoke Lists/read/searches allowlisted logs and confirms token redaction.
npm run test:remote Remote gateway smoke (experimental) Builds bin/remote-server.cjs, starts it with a token file, rejects unauthenticated calls, lists the browser tools, and tests the app service start/stop/token rotation/tunnel handoff.

Type-check and bundles: npx tsc --noEmit, npm run build, npm run build:mcp.


📚 Documentation & Knowledge (OKF)


📦 Release notes

[!NOTE] What's new in 2.1.1 — Cortex recall for video, and a VS Code-style Settings. media transcript now indexes the full transcript into Cortex under the video URL, so memory recall can answer from a video later (pass index:false to skip). Settings navigation moved from a wrapping top tab strip to a scrollable left rail: the nav scrolls on its own, the active panel scrolls independently, and narrow windows collapse the rail into a horizontal strip. Earlier releases are in CHANGELOG.md.


📄 License

This project is licensed under the MIT License © 2026 hyperbolictonic.


Ono-Sendai Cyberspace 7    Kuang Grade Mark Eleven crest    Mark Eleven tactical emblem

🌌 Neuromancer Inspiration & Cyberpunk Canon

"A Kuang Grade Mark Eleven penetration program. Icebreaker. The military stuff, the heavy artillery."
— William Gibson, Neuromancer (1984)

In William Gibson's genre-defining cyberpunk masterpiece Neuromancer, console cowboys Case and the ROM personality construct of the Dixie Flatline jack into the Matrix using an Ono-Sendai Cyberspace 7 deck. Their ultimate weapon: the Kuang Grade Mark Eleven—a mythical military-grade icebreaker designed to slice through the impenetrable corporate ICE surrounding the Tessier-Ashpool mainframe.

Hypagon Gateway began as a project inspired by that fictional lineage and has been renamed since; the current name is its own. The quote and the original Kuang Grade Mark Eleven reference are preserved here as inspiration; Hypagon Gateway is an independent project and is not affiliated with William Gibson, Neuromancer, or the fictional device.

It carries that inspiration into the modern web: