Chrome Extension · AI · Edge ML · 2025

Arkhon AI

Chat with any page, fill forms, browse autonomously — powered by a local LLM running entirely in your browser. Nothing ever leaves your machine.

700MB · 100% on-device Gemma 3 1B · GGUF Zero cloud · Zero egress 163 tests · 9 suites
Solo Chrome MV3 WebAssembly OPFS CDP Agent
CHROME BROWSER ┌────────────────────────────────────────────────────────┐ │ │ │ background.js (Service Worker) │ │ ├─ Tab lifecycle · Message router │ │ ├─ CDP agent · State cache │ │ └─ ensureModelHost() ──────────────────────────────┐ │ │ │ │ │ model-host.html (Pinned tab — survives SW kill) │ │ │ ├─ Gemma 3 1B Q4_K_M via wllama WASM │◄─┘ │ │ ├─ nomic-embed-text ONNX (~70MB) │ │ └─ BM25 retrieval · RAG · Form fill · Agent step │ │ │ │ Every web page (content.js) │ │ └─ FAB (Shadow DOM) → iframe: sidepanel/index.html │ │ React app · Chat · Fill · Agent UI │ └────────────────────────────────────────────────────────┘
Capabilities

Three modes, one local model.

01 · CHAT
Talk to any page

Read this page → extract DOM text → BM25 retrieval → stream answers from Gemma 3 1B. Works on articles, docs, YouTube transcripts, PDFs.

  • One-click page indexing
  • 3 AI-suggested starter questions
  • 60-message per-tab history
  • YouTube transcript extraction
  • PDF iframe text extraction
02 · FILL
Smart form fill

Personal knowledge base embedded via nomic-embed-text ONNX. ORT cosine or BM25 retrieval maps your info to form fields — no typing.

  • Detects inputs across iframes
  • React-compatible (dispatches input + change)
  • Multi-step paginated forms (Greenhouse/Lever)
  • LLM outputs structured JSON → fills by index
  • Handles select, textarea, disabled fields
03 · AGENT
Autonomous browsing

Attach Chrome DevTools Protocol to any tab. Walk the accessibility tree, score elements via ORT, execute click/fill/scroll via CDP — loop until goal is done.

  • Full AX tree via Accessibility.getFullAXTree
  • ORT cosine filter narrows to top-K elements
  • GBNF grammar forces valid JSON actions
  • Auto-reattach if DevTools open externally
  • Clean CDP detach on stop / navigation
Engineering

Key flows, end to end.

Chat query
  1. 01 User clicks "Read this page" — content script extracts DOM text
  2. 02 PC_CMD_INDEX → chunks text (450 chars, 60 overlap, max 500 chunks) → BM25 store per tab
  3. 03 User sends message → PC_CMD_CHAT → BM25 top-k + first 2 intro chunks → cap at 8 000 chars
  4. 04 Gemma prompt → wllama.createCompletion({ stream: true })
  5. 05 Per token: PC_TOKEN → persistent port → React appends → re-render
Agent loop
  1. 01 User types goal → AGENT_START → background attaches CDP to active tab
  2. 02 GET_DOM_TREE_CDP → Accessibility.getFullAXTree → filter interactive nodes
  3. 03 PC_CMD_EMBED_FILTER → ORT cosine scores each DOM line → top-K returned
  4. 04 PC_CMD_AGENT_STEP → Gemma + GBNF grammar → JSON action (click/fill/scroll)
  5. 05 EXECUTE_ACTION_CDP → DOM.resolveNode → Runtime.callFunctionOn → repeat or done
Model host lifecycle
  1. 01 On startup/install → create pinned model-host tab (survives SW's 30s kill)
  2. 02 loadModels() downloads Gemma 3 1B GGUF → caches in OPFS (~700MB)
  3. 03 nomic-embed-text ONNX loaded lazily on first fill/agent call (~70MB)
  4. 04 If pinned tab closed → 25s delay (OPFS lock) → auto-recreate with 3× retry
  5. 05 SW restart → restore hostTabId from session storage → adopt or recreate
Form fill pipeline
  1. 01 User triggers fill → content script scans all input/select/textarea across all iframes
  2. 02 PC_CMD_FILL → ORT cosine (if embeddings ready) or BM25 over knowledge store
  3. 03 LLM outputs {"fieldIndex":"value"} JSON → validated
  4. 04 content.js fills each field by frameId + idx, dispatches input + change events
  5. 05 React-compatible — works on Greenhouse, Lever, Workday-style apps
Engineering depth

Hard problems solved.

Reliability
SW kill immunity
Chrome kills service workers after 30s idle. Arkhon hosts the model in a pinned tab — stays alive for the full browser session. Alarms keep the SW responsive during long agent loops.
OPFS lock handling
Closing the model-host tab while the 700MB GGUF is memory-mapped holds the OPFS SyncAccessHandle for up to 30s. Reconnect waits 25s before recreating — prevents corrupt reads.
Pin-tab deduplication
ensureModelHost() uses a promise-guard (_ensurePromise) so 20 concurrent NEEDS_HOST messages only create exactly one tab — stress-tested across 163 Playwright tests.
Performance
Two-phase FAB injection
FAB appears at opacity:0 immediately at document_end — no SW round-trip. Iframe injected after tab ID is resolved. CSP-blocked hosts fall back to Chrome's native side panel automatically.
BM25 + ORT hybrid retrieval
BM25 is always available (no model needed). ORT cosine search activates after embeddings are indexed. For agent DOM filtering: ORT scores each element against the goal, keeping context tight.
Context capping
4 096 token context window. Page text capped at 8 000 chars (~2 000 tokens) before prompting — prevents WASM heap overflow on long pages while keeping retrieval quality high.
Tech stack
Chrome MV3 Gemma 3 1B wllama WebAssembly OPFS ONNX Runtime nomic-embed-text BM25 React 18 Shadow DOM Chrome DevTools Protocol GBNF Grammar Playwright Service Worker
ARKHON AI · INTISER AHMED · 2025 · Privacy Policy More work →