The Problem

Agents that need to drive a browser are forced into proprietary SDKs (OpenClaw, Playwright‑MCP, etc.). Switching agents or scripting from a shell requires rewriting large amounts of code or abandoning the tool entirely. A lightweight, language‑agnostic HTTP bridge to Chrome would let any AI agent or script issue clicks, reads, and navigation without a heavy dependency stack.

What This Does

pinchtab ships a single 12 MB Go binary that starts Chrome, exposes an HTTP API, and returns accessibility‑oriented snapshots. Core files are in the repository root:

  • main.go – parses flags, creates the HTTP router, and launches the server.
  • bridge.go & cdp.go – wrap Chrome DevTools Protocol (CDP) calls; bridge.go starts Chrome with the appropriate profile and headless flag, while cdp.go marshals JSON requests/responses.
  • handlers.go, handler_snapshot.go, handler_test.go – implement the /snapshot, /text, /action, /screenshot, etc. endpoints, delegating to snapshot.go and state.go.
  • readability.js & stealth.js – JavaScript snippets injected into pages for content extraction and bot‑detection evasion.
  • config.go – reads runtime options (e.g., BRIDGE_HEADLESS) from environment variables.

The Go code is a single package; the static import graph shows two internal modules with no import edges and no circular dependencies, meaning each file is largely self‑contained.

How It Is Wired

  1. Entry point – main.go calls config.Load() (config.go) then bridge.Start() (bridge.go).
  2. bridge.Start() launches Chrome (exec.Command) with the user profile under ~/.pinchtab/chrome-profile/ and returns a CDP client.
  3. The HTTP router (net/http) registers handlers from handlers.go. Each handler receives the request, extracts parameters, and calls a core function: /snapshot → snapshot.Get() (snapshot.go) → CDP Page.getLayoutMetrics & DOM.getDocument. /text → snapshot.ReadableText() which injects readability.js via CDP Runtime.evaluate. * /action → state.ApplyAction() (state.go) → CDP Input.dispatchMouseEvent / Runtime.evaluate.
  4. Responses are marshaled to JSON and written back to the client.

The widest blast‑radius files are handlers.go (995 lines, all endpoint routing) and cdp.go (low‑level CDP plumbing). Because the import graph has 0 edges, changes in one file rarely affect others, but the monolithic handlers.go concentrates most routing logic, so refactoring it reduces risk. No external database or filesystem writes occur beyond Chrome’s profile directory.

How To Use It

# Clone and build
git clone https://github.com/moses-y/pinchtab
cd pinchtab
go build -o pinchtab .

# Run directly (headful)
./pinchtab

# Run headless (environment flag)
BRIDGE_HEADLESS=true ./pinchtab

Docker alternative (image built from the provided Dockerfile):

docker build -t pinchtab .
docker run -d -p 9867:9867 --security-opt seccomp=unconfined pinchtab
curl http://localhost:9867/health

Configuration is read from environment variables defined in config.go (e.g., BRIDGE_HEADLESS, BRIDGE_PORT). The README demonstrates basic curl calls against /text and /action.

Real‑World Use

An LLM‑driven assistant can keep a persistent login session by launching pinchtab once, logging in via the Chrome window, and then issuing:

curl -X POST localhost:9867/action -d '{"kind":"click","ref":"e5"}'
curl localhost:9867/text?tabId=1

The assistant receives a concise accessibility tree (~800 tokens) instead of a full DOM dump, enabling cheaper token usage while still interacting with the page.

Code Health & Issues

Measured findings (static analysis)

  • Medium – Deep nesting – cdp.go, handlers.go; max indentation depth 7.
  • Medium – Duplicated code – handler_snapshot.go, handlers.go; identical 6‑line block.
  • Medium – Oversized file – handlers.go (995 LOC).

Health audit

  • High – Pin third‑party actions – .github/workflows/* uses @vN tags.
  • Medium – Least‑privilege GITHUB_TOKEN – .github/workflows/ci.yml lacks explicit permissions.
  • Medium – Enable Dependabot – No dependabot config present.
  • Medium – Pin Docker base images – Dockerfile uses mutable golang:1.25-alpine, alpine:latest.
  • Medium – Add vulnerability scan – No dependency‑review step in CI.
  • Medium – Checkout persist‑credentials – .github/workflows/ci.yml keeps token in .git/config.
  • Low – Job timeouts – .github/workflows/ci.yml lacks timeout-minutes.

Repository hygiene: tests (*_test.go) exist, CI via GitHub Actions, Dockerfile present, MIT license, no committed secrets, lockfile (go.sum) committed.

The Bottom Line

pinchtab delivers a compact, language‑agnostic browser bridge that fits well into AI‑agent pipelines, with a clear separation between CDP plumbing and HTTP routing. The codebase is functional but suffers from a single, very large handler file and some duplicated logic, which hampers maintainability. Teams comfortable with Go can quickly adopt it, but should refactor handlers.go and tighten CI/CD security before using it in production.