@peekdev/cli
v0.1.0-alpha.30
Published
peek command-line tool for the local-first browser-session forensics workflow — a thin read-mostly client of ~/.peek/sessions.db: status, sessions list/show/export/delete, the `peek init` MCP-client wizard, `peek audit log`, and `peek audit verify`.
Maintainers
Readme
@peekdev/cli
Your real browser, exposed to your AI coding agent over MCP — capture once, query forever, never leaves your machine.

Docs: https://peek.cubenest.in
Requires Node.js ≥ 22. peek's native
better-sqlite3dependency only ships prebuilt binaries for Node 22+ — on Node 20 (notably Windows, which has no C/C++ toolchain by default) the install falls back to compiling from source and fails. Use Node 22 or newer.
npm install -g @peekdev/cli
peek initpeek init is an interactive wizard. It:
- Installs the native messaging host for the Peek Chrome extension (writes
~/Library/Application Support/Google/Chrome/NativeMessagingHosts/com.cubenest.peek.jsonon macOS, equivalent on Linux + Windows). - Detects your AI coding-agent client (Claude Code, Cursor, Cline, Windsurf, VS Code) and adds the
peek-mcpserver to its MCP configuration. - Prints a one-line "install the extension" link.
Then you install the Peek Chrome extension — available on the Chrome Web Store (contributors and local builds can instead load it unpacked from packages/peek-extension/chrome-mv3/, see @peekdev/extension) — open the side panel on the site you want to capture, and click Enable on this site. Your AI agent can now query the recording.
What this is NOT
- Not a session-replay product for production traffic. Peek is a developer-side tool — captures happen on your machine, in your browser, when you explicitly enable them per site.
- Not Sentry, LogRocket, or FullStory. There is no cloud, no upload, no telemetry, no signup. Captures live in
~/.peek/sessions.dbuntil you delete them — or set a retention policy and prune them explicitly (peek never deletes silently; see Retention). - Not a screen recorder. Peek captures structured DOM/console/network via rrweb, not pixels. AI agents query JSON, not video frames.
Commands
peek init # interactive install (see above)
peek status # health check — extension connected? DB writable?
peek sessions list [--origin <url>] [--limit <n>] [--json] # list recent sessions
peek sessions search [--q <text>] [--origin <url>] [--since <dur|iso>] [--until <dur|iso>] [--status <active|finalized>] [--errors <console|network|any>] [--limit <n>] [--json] # search sessions by metadata/facets
peek sessions show <id> # print one session as Markdown (metadata + errors)
peek sessions export <id> [--format <markdown|json|playwright|bundle>] [--out <file>] # export (default markdown); --format bundle writes a portable *.peekbundle
peek sessions import <file> [--keep-id] [--force] # import a *.peekbundle into the local store (local-first, masked-at-capture, no cloud)
peek sessions delete <id> # delete one session
peek sessions delete --all-older-than <dur> # delete every session older than e.g. 7d
peek retention set [--max-age <dur>] [--max-size <size>] [--keep <n>] | --clear # configure the prune policy
peek retention show # print the configured policy
peek retention preview [overrides…] # dry-run: what the policy would prune (non-destructive)
peek retention apply [--yes] [--include-stale-active] [overrides…] # prune per the policy (asks to confirm)
peek audit log [--since <dur>] [--tool <name>] [--client <name>] [--json] # act-tool audit log
peek audit verify [--dir <path>] [--bundle <file>] [--json] # verify the audit log hash chain, or a received *.peekaudit archive (exit 0 ok, 1 anomaly, 2 tampered)
peek audit bundle [--dir <path>] [--out <file>] # package the audit log + head into a portable *.peekaudit evidence archive
peek connect add <surface> [--name <n>] [--command <c>] [--args=<arg>] # register a connector (surface: slack)
peek connect list # list configured connectors
peek connect remove <name> # remove a connector from the registry
peek connect start # start the detached supervisor daemon
peek connect stop # stop the running supervisor daemon
peek connect status [name] # show supervisor and per-connector status
peek connect logs [name] [--follow] [--lines <n>] # print or tail connector logs
peek <cmd> --help # usage for any subcommand--format html is reserved but not yet implemented (it exits non-zero with a message — use markdown, json, playwright, or bundle). --format bundle produces a self-contained *.peekbundle (gzipped tar with a SHA-256 integrity manifest); sessions are masked at capture (passwords, auth/cookie headers, and detected PII are redacted), but a full-page snapshot can still include other on-screen text and non-password field values — review what was on screen before sharing a bundle. All commands read ~/.peek/sessions.db except sessions delete and sessions import (and peek init, which writes the install config). Nothing leaves your machine.
Retention
The local store is unbounded by default. To cap it, configure a policy and prune explicitly — peek never deletes silently:
peek retention set --max-age 30d --max-size 2GB --keep 20
peek retention preview # dry-run: exactly what would be pruned
peek retention apply # prune (confirms first; --yes to skip)A policy can prune by age (--max-age), by total event-blob size (--max-size, evicting oldest-first), or both, and the --keep N floor guarantees the N most-recent sessions are never pruned. Pruning never deletes an in-progress (active) recording — pass --include-stale-active to also remove crashed/abandoned active sessions past the age cutoff. It frees the on-disk event blobs (the bulk of ~/.peek); the SQLite index file is compacted separately. peek status shows total store size and how much is over your policy. The policy lives in ~/.peek/policy.json (honoring PEEK_HOME).
Audit log integrity
The audit log (~/.peek/audit.log) is hash-chained: each JSONL entry carries a seq counter and a prevHash field (SHA-256 of the previous line), written under a file lock. A small sidecar (audit.head.json) records the tail hash so that tail truncation is also detectable.
peek audit verify [--dir <path>] [--bundle <file>] [--json] recomputes the chain and reports:
| Status | Meaning | Exit code |
|---|---|:---:|
| intact | chain is complete and unbroken | 0 |
| head-missing | chain is internally consistent but the sidecar is absent (tail truncation cannot be ruled out) | 0 |
| no-log | no audit log exists yet | 0 |
| incomplete-final | last line is an incomplete write (likely a crash mid-write) | 1 |
| gaps | intentional gaps from lock-contention fallback entries | 1 |
| broken | prevHash mismatch — a line was edited or reordered | 2 |
| truncated | log ends before the recorded head (lines were removed from the tail) | 2 |
| prefix-tampered | pre-chain prelude was modified | 2 |
The audit log is tamper-evident, not tamper-proof. It detects accidental corruption, truncation, reordering, and edits, but does not stop a determined local attacker who recomputes the whole chain. There are no keys, no external anchor, and no egress.
peek audit bundle [--dir <path>] [--out <file>] packages the audit log and its head sidecar into a portable *.peekaudit evidence archive (with a SHA-256 integrity manifest); a recipient verifies it independently with peek audit verify --bundle <file>.
Connector daemon
peek connect manages a supervised connector daemon — a long-running background process that spawns and monitors per-surface connector subprocesses (e.g. a Slack connector that streams workspace events into the local store). Connector registrations are stored in ~/.peek/connect/connectors.json; the daemon runs detached and logs each connector's stdout/stderr to a per-connector file under ~/.peek/connect/logs/.
# First, register a connector for a surface (currently: slack).
# Run it interactively once to capture tokens and pair the connection,
# then start the daemon so it supervises and auto-restarts it.
peek connect add slack --name my-slack
peek connect start # spawns the detached supervisor
# Ongoing management
peek connect status # show supervisor uptime + connector states
peek connect logs my-slack # last N lines of the connector's log
peek connect logs my-slack --follow # tail -f the log (Ctrl-C to stop)
peek connect stop # graceful SIGTERM to the supervisorThe --args=<arg> flag on connect add is repeatable — pass it multiple times to build the connector's argv. --command overrides the default binary for the surface (useful for a custom connector binary).
Querying from an AI agent
After peek init, the peek-mcp server is available to your AI client as an MCP toolset. Sample queries:
- "what's in my latest peek session?"
- "show me the console errors from session
abc123between t=10s and t=15s" - "find network requests with status >= 400 from the last 5 minutes of recording on
example.com" - "generate a Playwright reproduction script from session
abc123"
The MCP server exposes 18 tools — listing, session search, session summaries, console/network drill-down, user-action history, DOM reconstruction and history, Playwright-repro generation, a live ref-tagged page view, non-destructive element highlighting, audit-log chain verification, and (with explicit per-origin permission) actions like clicks/inputs/navigation plus a pause-and-hand-back-to-the-user input handoff. See @peekdev/mcp for the tool reference.
Privacy
Peek is local-first. The CLI reads from ~/.peek/sessions.db (SQLite); the extension records into it; the MCP server queries it. There is no network destination. There is no telemetry. There is no auto-update channel. The native host runs as your user, not as a daemon.
The extension uses per-origin host permissions — recording is off for every site by default. You enable it explicitly from the side panel for each origin you care about. The five-level permission model (0 Off → 1 Read-only → 2 Suggest-only → 3 Act-with-confirm → 4 YOLO), plus a cross-level destructive-action blocklist that always prompts, is enforced server-side, not just in the UI.
Full data-handling policy: docs/peek/PRIVACY_POLICY.md. Chrome Web Store permission justifications: docs/peek/PERMISSION_JUSTIFICATION.md.
Supported AI clients
peek init configures the MCP server into:
| Client | Detection |
|---|---|
| Claude Code (CLI) | ~/.claude.json |
| Cursor | ~/.cursor/mcp.json |
| VS Code | .vscode/mcp.json (project-scoped) |
| Windsurf | ~/.codeium/windsurf/mcp_config.json |
| Cline (VS Code) | manual config (lives in VS Code's per-OS globalStorage) |
Windows path note. The
~in these paths is your home directory (e.g.C:\Users\<username>). The CLI resolves it automatically via Node'sos.homedir()+path.join, so the same config locations work on Windows, macOS, and Linux.
If your client isn't auto-detected (for example Continue or Zed, which peek init does not detect), paste the manual MCP JSON config shown below into that client's MCP settings. peek init also prints this block when it can't find a known client. The MCP server speaks the standard stdio protocol (spec 2025-11-25 + 2025-03-26 back-compat).
{
"mcpServers": {
"peek": {
"command": "npx",
"args": ["-y", "@peekdev/mcp@latest"]
}
}
}Claude Code skill
When Claude Code is among the configured clients (or ~/.claude.json already exists), peek init also drops a SKILL.md into ~/.claude/skills/peek/. Claude Code loads it on session start and uses it to decide when to reach for peek's MCP tools — investigating an error from a manual repro, generating a Playwright test from a session, querying DOM state at a past moment, etc.
The skill is idempotent on re-run (no-op when the on-disk content matches the bundled source). Skip the install with peek init --skip-skill. Want it without running peek init? See the curl-able recipe at docs/peek/distribution/claude-code-skill.md.
Cursor — project-level recipe
peek init writes Cursor's MCP server entry to the global config at ~/.cursor/mcp.json — every project opened in Cursor inherits it. If you'd rather scope peek to one project (a repo where peek captures matter but other repos on the same machine should not surface the tools), drop a .cursor/mcp.json into the workspace root:
{
"mcpServers": {
"peek": {
"command": "npx",
"args": ["-y", "@peekdev/mcp@latest"]
}
}
}Commit it or add it to .gitignore — Cursor reads either. Cursor's docs document the global file as "tools available everywhere" and the project file as "project-specific tools" (see cursor.com/docs/context/mcp for current merge semantics).
This is the same block peek init writes to the global file, so the two configs are interchangeable. You still need the Peek Chrome extension installed — from the Chrome Web Store, or loaded unpacked from packages/peek-extension/chrome-mv3/ for local builds (see @peekdev/extension) — and the native messaging host registered — run peek init --skip-clients if you want the host installed without touching any MCP config.
Versioning & compatibility
Semantic Versioning. Currently 0.1.0-alpha.x — pre-release; the CLI surface is stable in spirit but flags may rename. See SUPPORTED.md for the compatibility matrix.
@peekdev/cli depends on @peekdev/mcp as a workspace peer. Both are versioned and published together via Changesets + OIDC Trusted Publishing.
Full release history: CHANGELOG.md.
License
Apache 2.0. The bundled rrweb engine remains MIT-licensed; see NOTICE.
Contributions are accepted under the Developer Certificate of Origin (DCO) — sign your commits with git commit -s. See CONTRIBUTING.md + SECURITY.md.
