Skip to content
Conduit

skill

telemaco

A headless browser engine in Rust, built for web scraping and AI agents.

AlbertoBarrago/telemacocommunitylistedunreviewed

Set up

Skills are installed by placing their folder where your agent loads skills.

The download comes from github.com/AlbertoBarrago/telemaco itself, not from our server, so what you get is exactly what its author published.

Install instructions come from the README

Skills do not use an MCP config. Follow the steps in the README below.

README

synced Oct 25, 2026

Telemaco runs real JavaScript through V8 (deno_core), keeps a real DOM tree, owns its layout and paint pipeline, speaks the Chrome DevTools Protocol, and acts as a drop-in replacement for headless Chrome with Puppeteer and Playwright. Rendering and stealth are first-class capabilities. It targets web scraping and AI agent automation.

Telemaco is a derivative work of Obscura (Apache-2.0). It started as a fork and evolved into a distinct project with its own identity and a practical, scraping- and agent-oriented focus. See NOTICE for the full attribution.

How Telemaco differs from Obscura

Obscura is a browser engine; Telemaco is a browser engine for automation. Where Obscura focuses on the rendering core, Telemaco adds the surfaces that make it useful in production: a full CDP server for Puppeteer and Playwright, a stateful MCP server for AI agents, stealth against bot detection, parallel scraping, and a one-command installer that wires it into 15 coding agents.

Why Telemaco over headless Chrome?

MetricTelemacoHeadless Chrome
Memory30 MB200+ MB
Binary size70 MB300+ MB
Page load85 ms~500 ms
StartupInstant~2s
Anti-detectBuilt-inNone
PuppeteerYesYes
PlaywrightYesYes

Roughly 12x faster page loads and 6x less memory than headless Chrome on framework pages, with the same CDP automation surface.

Highlights

  • Native rendering: CSS layout and paint, viewport and full-page screenshots, activity-driven CDP screencasting, and PDF export. No Chromium, no WebView.
  • Stealth mode: wreq/BoringSSL transport, per-session fingerprint randomization, consistent browser identity, and a tracker blocklist. Rendering stays fully available when stealth is on.
  • CDP compatible: telemaco serve speaks the Chrome DevTools Protocol, so Puppeteer, Playwright, and chromiumoxide connect out of the box.
  • MCP server: stateful browser automation tools for Claude Desktop, Cursor, and any MCP client, over stdio or HTTP.
  • Hardened by default: SSRF guards on loopback, RFC1918, and link-local targets; a V8 termination watchdog per page; process-level hard deadlines, so one bad page can never hang a worker.

Install

install.sh (recommended)

curl -fsSL https://raw.githubusercontent.com/AlbertoBarrago/telemaco/main/install.sh | bash

Installs the prebuilt binary for your platform (or builds from source if none is published yet), adds it to your PATH, then offers to run telemaco install to configure your AI coding agents. Options: --prefix <dir>, --from-source, --yes, --uninstall (removes the binary only; run telemaco uninstall first to also remove agent configs). See Agent setup below for telemaco install / telemaco uninstall.

Homebrew (macOS)

brew tap albertobarrago/telemaco
brew install telemaco

Installs the render-enabled build (full DOM, layout, screenshots, PDF) as telemaco, with telemaco-worker alongside it for scrape. The stealth variant is a separate formula that installs as telemaco-stealth, so the two can coexist:

brew install telemaco-stealth
telemaco-stealth --stealth fetch https://example.com --dump text

Bottles are published for Apple Silicon and Intel macOS. On Linux use install.sh or a prebuilt archive. Upgrades go through brew upgrade rather than telemaco update, which would replace a binary Homebrew owns.

Updating

telemaco update            # replace the binaries with the latest release
telemaco update --check    # report only; exit 1 means an update is available

The update keeps the build variant you installed, so a stealth install stays a stealth install rather than quietly becoming the plain one. Both telemaco and telemaco-worker are replaced together, since a mismatched pair breaks scrape. The download is verified by running it before anything is replaced, and the replacement itself is a rename, so a failure leaves the working install untouched.

Run interactively, telemaco checks once a day whether a newer release exists and says so. It never does this when stderr is not a terminal, which covers scripts, CI, and MCP clients: a browser people reach for to avoid leaving traces should not contact GitHub on its own. TELEMACO_NO_UPDATE_CHECK=1 switches the check off entirely.

update refuses when the binary it would replace turns out to be cargo build output, which happens when ~/.local/bin/telemaco is a symlink into a checkout: replacing it would drop a downloaded binary into a build directory, where the next cargo build silently reverts it. A directory named target is only treated as build output when a Cargo.toml sits beside it.

Self-update is not available on Windows yet; a running .exe cannot be replaced in place, so the command says so instead of half-finishing.

Prebuilt binaries

Grab the latest archive from Releases:

# Linux x86_64
curl -LO https://github.com/AlbertoBarrago/telemaco/releases/latest/download/telemaco-x86_64-linux.tar.gz
tar xzf telemaco-x86_64-linux.tar.gz
./telemaco fetch https://example.com --eval "document.title"

Release archives include both telemaco and telemaco-worker; keep them in the same directory for the parallel scrape command.

Archive suffixRenderingStealth transport
noneYesNo
-stealthYesYes
-no-renderNoNo
-no-render-stealthNoYes

Docker

Pull the published image:

docker pull albz222/telemaco:latest
docker run -d --name telemaco -p 127.0.0.1:9222:9222 albz222/telemaco:latest

Images are tagged by version (albz222/telemaco:0.2.5) as well as latest, and built for linux/amd64 and linux/arm64. The container runs the CDP server on port 9222 by default, so Puppeteer and Playwright can connect to ws://127.0.0.1:9222 straight away.

Run a one-off command instead of the server by overriding the entrypoint:

docker run --rm --entrypoint /telemaco albz222/telemaco:latest \
  fetch https://example.com --dump markdown

Or build it yourself from a checkout:

docker build -t telemaco .
docker run -d --name telemaco -p 127.0.0.1:9222:9222 telemaco

Multi-stage build on distroless/cc: no shell, no package manager.

Build from source

git clone https://github.com/AlbertoBarrago/telemaco.git
cd telemaco

# Rendering
CARGO_INCREMENTAL=0 cargo build --release -p telemaco-cli --bins --features render

# Rendering and stealth
CARGO_INCREMENTAL=0 cargo build --release -p telemaco-cli --bins --features render,stealth

# No rendering
CARGO_INCREMENTAL=0 cargo build --release -p telemaco-cli --bins --no-default-features

# No rendering, with stealth
CARGO_INCREMENTAL=0 cargo build --release -p telemaco-cli --bins --no-default-features --features stealth

Requires Rust 1.75+ (rustup.rs). The first build compiles V8 from source: about 5 minutes and a few GB of disk, cached afterwards. The stealth build also compiles BoringSSL, which needs CMake and Clang. On Ubuntu/Debian:

sudo apt-get install build-essential cmake clang libclang-dev llvm-dev

Crates.io

Every crate is published to crates.io, so you can use Telemaco as a library in your own Rust project or build its CLI from the registry:

# The headless browser, ready to drive from Rust
cargo add telemaco

Install the CLI as a binary from crates.io too:

cargo install telemaco-cli --features render

The publishable set: telemaco (embeddable API), telemaco-cli, and the workspace crates telemaco-dom, telemaco-net, telemaco-js, telemaco-browser, telemaco-cdp, telemaco-mcp, telemaco-render.

The two libraries that define how a page renders are Telemaco-owned forks, published and maintained here rather than pinned to upstream schedules:

  • mentore: the layout engine, a fork of Taffy.
  • athena-text: the text engine, a fork of cosmic-text (including the CSS line-breaking work).

Both publish exactly the version Telemaco builds against, under the same lib names (taffy / cosmic_text), so the crate source is unchanged: the layout and text output never move underneath a release.

API reference: the workspace crates that embed V8 (telemaco, telemaco-js, telemaco-browser, telemaco-cdp, telemaco-mcp) cannot be rendered by docs.rs because building them requires compiling V8. The generated rustdoc for every crate is published with the site and browsable at albz.it/telemaco/api (also available in-repo under api/).

Quick start

Fetch a page

# Page title
telemaco fetch https://example.com --eval "document.title"

# Extract all links
telemaco fetch https://example.com --dump links

# Render JavaScript and dump HTML
telemaco fetch https://news.ycombinator.com --dump html

# Write output to a file
telemaco fetch https://example.com --dump text --output page.txt

# Stream the raw response body verbatim (binary-safe, bypasses the JS/DOM layer)
telemaco fetch https://picsum.photos/200/300 --dump original > photo.jpg

# List every sub-resource URL the page would fetch (NDJSON)
telemaco fetch https://example.com --dump assets

# Fetch through an HTTP or SOCKS proxy
telemaco --proxy socks5://127.0.0.1:1080 fetch https://example.com --dump text

# Wait for dynamic content, bound navigation time
telemaco fetch https://example.com --wait-until networkidle0 --timeout 10

# Capture the settled page as PNG
telemaco fetch https://example.com --screenshot page.png

Dump modes: assets, html, text, links, markdown, original, cookies.

Localhost and LAN dev servers

Fetches to private and internal IPs are blocked by default (SSRF protection). For local testing pass --allow-private-network or set TELEMACO_ALLOW_PRIVATE_NETWORK=1:

telemaco fetch http://127.0.0.1:3000 --allow-private-network --dump text

# Works on any subcommand, for example the CDP server for local automation:
telemaco serve --port 9222 --allow-private-network

The full allow/deny rules (including DNS-resolution-time checks) are in docs/Environment-variables.md.

Scrape in parallel

telemaco scrape url1 url2 url3 ... \
  --concurrency 25 \
  --eval "document.querySelector('h1').textContent" \
  --format json

# Suppress scrape progress on stderr for script-friendly output
telemaco scrape https://example.com --quiet --format json

# Workers inherit the global proxy
telemaco --proxy http://127.0.0.1:8080 scrape https://example.com https://news.ycombinator.com

Drive it with Puppeteer or Playwright

telemaco serve --port 9222
// Puppeteer
import puppeteer from 'puppeteer-core';

const browser = await puppeteer.connect({
  browserWSEndpoint: 'ws://127.0.0.1:9222/devtools/browser',
});

const page = await browser.newPage();
await page.goto('https://news.ycombinator.com');

const stories = await page.evaluate(() =>
  Array.from(document.querySelectorAll('.titleline > a'))
    .map(a => ({ title: a.textContent, url: a.href }))
);
console.log(stories);

await browser.disconnect();
// Playwright
import { chromium } from 'playwright-core';

const browser = await chromium.connectOverCDP({
  endpointURL: 'ws://127.0.0.1:9222',
});

const page = await browser.newContext().then(ctx => ctx.newPage());
await page.goto('https://en.wikipedia.org/wiki/Web_scraping');
console.log(await page.title());

await browser.close();

Rendering-enabled builds add page.screenshot() (viewport and full page) and page.pdf():

await page.setViewport({ width: 1440, height: 1000 });
await page.goto('https://example.com', { waitUntil: 'load' });
await page.screenshot({ path: 'page.png', fullPage: true });
await page.pdf({ path: 'page.pdf', format: 'A4', printBackground: true });

MCP (Model Context Protocol)

Telemaco ships an MCP server that exposes browser automation tools to AI agents (Claude Desktop, Cursor, and other MCP clients).

telemaco mcp                      # stdio, for clients that launch a subprocess
telemaco mcp --http --port 8080   # HTTP, endpoint: http://127.0.0.1:8080/mcp

The server answers initialize with plain capabilities. Add --agent-directives to have it also tell the agent, on connect, that Telemaco is how it should reach the web; telemaco install adds this flag when you accept it, so a server you wire up by hand stays neutral.

Claude Desktop config:

{
  "mcpServers": {
    "telemaco": { "command": "telemaco", "args": ["mcp"] }
  }
}

Tools: browser_navigate, browser_snapshot, browser_screenshot, browser_pdf, browser_click, browser_fill, browser_type, browser_press_key, browser_select_option, browser_evaluate, browser_wait_for, browser_network_requests, browser_console_messages, browser_close. Render-enabled builds expose browser_screenshot and browser_pdf; streaming screencasts remain CDP-only.

Agent setup (telemaco install)

telemaco install wires Telemaco into the coding agents on the machine: the MCP server, an instructions block in the agent's memory file, and a prompt hook that reminds the model to use Telemaco when a prompt looks web-bound.

Run interactively it asks before each part that changes how the agent already behaves: the prompt hook, whether the MCP server should tell the agent to reach the web through Telemaco, auto-approving Telemaco's tools, and refusing the agent's own web search. --yes accepts them all; the flags below decline them one at a time.

telemaco install                                     # interactive, detects installed agents
telemaco install --yes                               # non-interactive, accepts the defaults
telemaco install --folder ./my-project               # configure one project directory
telemaco install --folder ~/alt-home -l global        # use that folder as home for a global install
telemaco install --target claude,cursor              # pick agents explicitly
telemaco install --dry-run                           # show what would change, write nothing
telemaco uninstall                                    # remove everything a global install added
telemaco uninstall --folder ./my-project              # remove it from one project directory

Supported: Claude Code, Cursor, OpenAI Codex CLI, Gemini CLI, Google Antigravity, Codeium Windsurf, OpenCode, Roo Code / Cline, Pi Coding Agent, DeepSeek Harness, Qwen Code, Factory Droid, Poolside Agent, Kiro, Hermes Agent.

FlagDescription
-t, --targetComma-separated agent ids, or auto, all, none
-l, --locationglobal (default) or local
-f, --folderA project directory, or the home directory for a global install rooted elsewhere; asks which one when --location does not say
-y, --yesNon-interactive, accept defaults
--stealthPut --stealth in the agent's MCP command
--no-permissionsDo not auto-approve Telemaco tools
--no-block-webLeave the agent's own web search/fetch enabled
--no-prompt-hookSkip the prompt hook; the MCP server and instructions block still install
--dry-runReport the plan without writing
--print-config <agent>Print the MCP snippet for one agent and exit

telemaco uninstall takes the same -t/-l/-f/-y/--dry-run flags and removes Telemaco from the agent configs instead of adding it.

By default the installer adds a guard that refuses the agent's built-in web search and fetch, so web work goes through Telemaco. Decline it interactively or pass --no-block-web; re-running with that flag removes a guard installed earlier. --no-prompt-hook works the same way, and takes the config file with it when the hook was the only thing in it.

Every config file is copied to <file>.telemaco-backup before the first rewrite. A config that is not valid JSON is reported and left untouched rather than replaced; one that uses comments (.vscode/mcp.json and friends) is rewritten as strict JSON, and the note says so.

CLI reference

telemaco fetch <URL>

FlagDefaultDescription
--dumptextassets, html, text, links, markdown, original, cookies
--eval—JS expression evaluated on the page
--wait-untilloadload, domcontentloaded, networkidle0
--timeout30Maximum navigation time in seconds
--waitadaptive, up to 5Post-load settling; an explicit value is a fixed delay in seconds
--selector—Wait for a CSS selector
-s, --screenshot—Write a PNG screenshot (render-enabled build)
--stealthoffAnti-detection mode
--output—Write dump or eval output to a file
--proxy—Inherited global HTTP/SOCKS5 proxy URL

Global flags --proxy, --stealth, and --allow-private-network are valid before or after the subcommand and apply to fetch, serve, scrape, and mcp.

telemaco scrape <URL...>

FlagDefaultDescription
--concurrency10Parallel workers
--eval—JS expression per page
--formatjsonjson or text
--quietoffSuppress scrape progress on stderr

Stealth mode

Build with --features render,stealth, then enable at runtime with the global --stealth flag. Stealth adds the wreq/BoringSSL transport, per-session fingerprint randomization (GPU, screen, canvas, audio, battery), realistic navigator.userAgentData (high-entropy values), trusted dispatched events, and a tracker blocklist. The stealth build retains the complete rendering surface: screenshot, screencast, PDF, CDP, and MCP all keep working.

Architecture

CrateRole
telemaco-cliCLI: fetch, serve (CDP server), scrape, mcp
telemaco-cdpChrome DevTools Protocol server (WebSocket)
telemaco-jsV8/deno_core runtime and DOM ops bridge
telemaco-domDOM tree
telemaco-netHTTP client, stealth transport, cookie jar, robots cache, tracker blocklist
telemaco-browserThe Page type, navigation, JS evaluation
telemaco-renderSelector cascade, retained layout, paint, screenshots, PDF
telemaco-mcpStateful MCP automation tools
telemacoEmbeddable Rust library API

Testing

Run tests with cargo nextest, not cargo test: the engine holds a single V8 isolate per process, and nextest runs each test in its own process.

cargo nextest run --release --features render -p <crate>
cargo nextest run --release --features render --no-fail-fast

The behavioral gate is the acceptance suite in acceptance/, 46 stages that must stay at 46/46:

TELEMACO_BIN=./target/release/telemaco python3 acceptance/run.py

It serves its own fixtures on a port picked at runtime, so it is deterministic, offline, and cannot collide with a server already running. Rendering changes additionally go through render-repros/run.sh, which draws 64 fixtures.

Proxies for production

For production scraping, residential or ISP IPs usually beat datacenter addresses. We use NodeMaven: residential and ISP proxies, sticky sessions, and per-country targeting through the proxy username. Route Telemaco through it with the global --proxy flag. Discount codes: TELEMACO35 (35% off mobile and residential), TELEMACO40 (40% off ISP and static).

License

Telemaco is licensed under the Apache License, Version 2.0.

↑↓ navigate openesc close