A single comet command that drives the Comet browser (Perplexity's
agentic browser) from Claude Code or any shell. Five subcommands —
fetch, open, ask, assist, launch — backed by AppleScript +
the Chrome DevTools Protocol.
This README is written for Claude — a fresh session that needs to know when and how to reach for these tools.
Clone wherever you keep code, then run the installer from inside:
git clone git@github.com:kardolus/comet-cli.git
cd comet-cli
./install.shThe installer symlinks bin/comet into ~/.local/bin/comet, installs
zsh + bash completions into the first writable system completion
directory it finds, and removes any stale symlinks from the previous
flat-script layout (comet-open, comet-ask, etc.). It also prints
fallback instructions for any shell whose completion dir wasn't
writable. Override the symlink directory with COMET_BIN_DIR=....
~/.local/bin is not on PATH in non-interactive shells, so Claude
must invoke the absolute path: ~/.local/bin/comet.
Comet itself must have View → Developer → Allow JavaScript from
Apple Events enabled (ask needs it to poll DOM state). For fetch
and assist, Comet also needs to be running with CDP enabled — run
comet launch once per session.
fetch and assist depend on the Python websockets package. If
your system Python already has it (python3 -c 'import websockets'
succeeds), you're done. Otherwise, install it however your environment
allows — pipx, a virtualenv, or pip3 install --user --break-system-packages websockets.
Manual completion setup (if install.sh couldn't auto-install):
# zsh — add to ~/.zshrc:
fpath=(/path/to/comet-cli/completions $fpath)
autoload -Uz compinit && compinit
# bash — add to ~/.bashrc:
source /path/to/comet-cli/completions/comet.bashTo update later: git pull from the repo.
| Subcommand | What it does | Has page context? | Cost | Latency |
|---|---|---|---|---|
comet fetch <url> |
Open URL in a new Comet tab AND dump its rendered text (or HTML) to stdout in one shot. Default for "Claude needs to read this page." | n/a (it makes the page) | free | ~1–3s |
comet open <url> |
Open URL in a new Comet tab, focus it, return immediately. Use for hand-off to the human, not for reading. | n/a | free | instant |
comet ask "Q" |
Perplexity search; answer with citations to stdout. Human-facing only — Claude should hit the Perplexity API directly. | no | free | 5–30s |
comet ask --mode computer "Q" |
Perplexity Computer (agentic; can click, scrape, navigate). | no | 1 credit | 30s–5min |
comet assist "Q" |
Drive Comet's Assistant sidebar via CDP. Reads whichever tab the human last focused; programmatically-opened tabs are not picked up. | yes — last-focused tab | free for Q&A | ~10–30s |
comet launch |
Restart Comet with --remote-debugging-port=9222 (required by fetch and assist). |
— | — | ~3s |
comet help and comet <subcommand> --help are also available.
Maintainer preference — read this first: comet-cli is a fallback for when the browser itself is the point. Before reaching for it, ask whether a direct API call could answer the question.
- For web search / sourced answers, prefer the Perplexity API directly
(
$PERPLEXITY_API_KEY, POST tohttps://api.perplexity.ai/chat/completionswith asonar-family model). It's the same backend ascomet asksearch mode but returns structured JSON, doesn't steal the user's tab focus, and is faster.comet ask(search) is effectively deprecated for Claude's own use — keep it around for humans who want results in their browser, but Claude should use the API. - For anything else with an API (GitHub, Cloudflare, OpenAI, Vercel, filesystem, etc.) — use the API/MCP, not the browser.
- Only fall back to comet-cli when the browser is genuinely needed: reading JS-rendered content, content behind a login session, or clickops/scraping behind UI state.
Decision flow when comet-cli is the right call:
- Claude needs to read a public page (a URL, no auth needed, no
clicking)? →
comet fetch <url>. Pops the tab, waits for the DOM, returns innerText. Tight loop, no hand-off. - Question is about a page the user is already on (summarize
this tab, draft a reply to this thread)? →
comet assist "...". The sidebar reads the user's last-focused tab. Note: this does not work for tabs Claude just opened programmatically — focus has to come from the human for the sidebar to attach. - Task requires real browser actions — multi-step navigation,
clicking, filling forms, scraping behind a search box, comparing
data across several sites that can't be answered from a single
Perplexity API call? →
comet ask --mode computer "...". Costs a Perplexity credit per task (Pro plan has a monthly cap of a few hundred); can take minutes; can hang or return truncated responses requiring retries. Trycomet fetchfirst if the answer lives in a single page's DOM. - You want to hand off to the human (let them review a pre-filled
prompt, or just show them a URL)? →
comet open <url>.
If comet fetch or comet assist errors with "cannot reach CDP", run
comet launch once.
~/.local/bin/comet fetch https://nu.nl | head -50
~/.local/bin/comet fetch https://example.com --html # raw outerHTML
~/.local/bin/comet fetch https://app/dashboard --wait '.loaded' # wait for SPA selector
~/.local/bin/comet fetch https://search.com?q=foo --close # don't leave the tab aroundFor Claude, use the Perplexity API directly — same backend, no tab takeover. Keep this command for when a human wants the result rendered in their browser:
~/.local/bin/comet ask "What's the current AWS region with the lowest egress price?"Real example — comparing a banh mi sandwich across delivery apps:
~/.local/bin/comet ask --mode computer \
"Lotus Vietnamese Sandwich Brooklyn 11211 — banh mi price on UberEats vs DoorDash vs Grubhub. Cheapest?"Returns a table with item prices, fees, and a verdict.
~/.local/bin/comet open https://example.com/long-article
# (human clicks the new tab so the Assistant sidebar attaches to it)
~/.local/bin/comet assist "Summarize this in 3 bullets and quote the strongest counter-argument."Computer mode occasionally returns a preliminary "I'll check..." message without doing the work, or stalls. From real use:
- Tight prompts win. Long detailed instructions with "IMPORTANT: do X before responding" tend to hang or return early. A one-liner with the restaurant + ZIP + platforms + ask works reliably.
- Default timeout is 300s. Bump with
--timeout 420for hairy multi-site comparisons. - State the final output format inline ("Report price on each + which is cheapest") — keeps the agent from rambling.
- If it returns truncated, retry with a tighter prompt before escalating. Three attempts is the practical ceiling.
- Non-interactive shells: always invoke with the absolute path
~/.local/bin/comet.which cometwill fail in a fresh shell. comet fetchandcomet assistneed CDP: Comet must have been launched viacomet launchat least once per Comet session.comet assist's tab context = last human-focused tab, not whatever Claude just opened programmatically. Usecomet fetchwhen you want Claude to read a page; reservecomet assistfor "the user is already looking at this tab".comet askopens a new tab (as of v0.3.0) — it no longer navigates whatever was previously active. The answer renders in the fresh tab so you can scroll back to it after Claude returns.- Computer mode costs credits;
fetch,open,assist, andlaunchdo not. - Citations in
comet asksearch mode are printed inline (e.g.ubereats\n+1). They're not links — they're Perplexity's source footnotes.
bin/comet # dispatcher
lib/commands/<name> # one self-contained executable per subcommand
completions/_comet # zsh completion
completions/comet.bash # bash completion
install.sh # symlink + completion installer
The dispatcher just execs the matching file in lib/commands/, so
subcommands can be written in any language. open, ask, and
launch are bash; fetch and assist are Python (they use the
websockets package).
rm ~/.local/bin/comet
# plus the completion symlinks (paths printed by install.sh)