Skip to content

CLI reference

blop is a local-first OpenTelemetry observability CLI. Monitoring commands are the primary entry point. Active browser checks use the same CLI to verify an authored user flow through Browser Harness.

Terminal window
blop [command] [options]
blop setup opencode [--port PORT] [--json]
blop opencode [OPEN_CODE_ARGS...]
blop monitor start [--host 127.0.0.1] [--port 27686] [--db PATH] [--detach]
blop monitor stop
blop monitor status [--json]
blop status [--json]
blop services [--since DURATION] [--json]
blop traces [--service NAME] [--status STATUS] [--operation NAME] [--since DURATION] [--duration-min MS] [--limit N] [--cursor TOKEN] [attr.KEY=VALUE] [--json]
blop trace TRACE_ID [--include spans,logs,attributes] [--json]
blop trace-logs TRACE_ID [--since DURATION] [--limit N] [--cursor TOKEN] [--json]
blop spans [--service NAME] [--trace-id ID] [--operation NAME] [--parent-operation NAME] [--status STATUS] [--since DURATION] [--limit N] [attr.KEY=VALUE] [attrContains.KEY=TEXT] [--json]
blop span SPAN_ID [--json]
blop span-logs SPAN_ID [--since DURATION] [--limit N] [--cursor TOKEN] [--json]
blop logs [--service NAME] [--severity LEVEL] [--trace-id ID] [--span-id ID] [--contains TEXT] [--since DURATION] [--limit N] [--cursor TOKEN] [attr.KEY=VALUE] [attrContains.KEY=TEXT] [--json]
blop trace-stats GROUP_BY count|avg_duration|p95_duration|error_rate [--since DURATION] [--json]
blop log-stats GROUP_BY [--since DURATION] [--json]
blop facets traces|logs FIELD [--key ATTRIBUTE] [--since DURATION] [--json]
blop audit [--service NAME] [--since DURATION] [--baseline DURATION] [--duration-min MS] [--fail-on error|regression|never] [--json]

Bare blop is an alias for blop monitor start during the monitoring-first transition. Filters use named flags rather than positional conventions. Defaults stay useful and bounded: the CLI passes a 15-minute lookback unless --since says otherwise, list defaults are 20 traces / 100 logs, and hard caps are 100 traces / 500 logs per query with a 24-hour maximum lookback.

blop setup opencode detects OpenCode, enables its native OpenTelemetry setting, and starts or reuses a local collector. It preserves comments and unrelated settings in opencode.jsonc. If the default port belongs to another service, Blop leaves that process alone and selects the next free local port.

Command or flag Behavior
blop setup opencode Configure OpenCode and ensure a collector is ready.
--port <n> Require one collector port instead of automatic selection.
--json Print one blop.setup/v1 setup document.
blop opencode [args...] Launch OpenCode with every argument preserved.

The launcher injects the saved collector URL through OTEL_EXPORTER_OTLP_ENDPOINT and adds a default service.namespace=opencode-agents resource attribute. It does not edit shell profiles, Home Manager, tmux, or system environment settings.

Run a real model-backed turn before checking blop traces --service opencode. Commands such as opencode --version validate process launch but do not emit agent telemetry. See Monitor OpenCode agents for the full setup and team-tagging workflow.

Runs the OTLP collector in the foreground and prints its endpoints and database path:

blop monitor listening on http://127.0.0.1:27686
OTLP: POST http://127.0.0.1:27686/v1/traces POST http://127.0.0.1:27686/v1/logs
Query: GET http://127.0.0.1:27686/api/health ...
DB: ~/.local/state/blop/monitor/telemetry.sqlite
Flag Short Type Default Notes
--monitor-host <host> --host string 127.0.0.1 Bind host. Loopback only unless explicitly overridden.
--monitor-port <n> -p, --port int 27686 Bind port.
--db <path> string platform state dir SQLite database path.

Stop a foreground collector with Ctrl+C. Add --detach to start or adopt an identity-verified background collector; use blop monitor status and blop monitor stop to inspect or stop it. --json is valid for monitor status, monitor stop, and monitor start --detach, not for a long-running foreground process. --db selects the SQLite path for collector lifecycle commands and is rejected on query commands. Concurrent starts serialize through a startup lock, and stop refuses to signal an unrelated process that happens to use the same port.

The store persists across restarts. Time- and size-based retention trim it in bounded batches. Trace and log writes run in one lazy worker thread so health and query routes stay responsive during SQLite ingestion.

Cheap and deterministic collector health: reachability, database path, retention window, service/trace/span/log counts, and the latest telemetry timestamp. blop status --json also reports the effective non-secret configuration.

Services observed in the window, derived from the standard service.name resource attribute.

Terminal window
$ blop services --since 1h

Query commands discover running collectors safely. An explicit --host, --port, --base-url, or BLOP_MONITOR_URL is always used as written and never falls back. Otherwise Blop selects the running collector whose working directory is the longest parent of the current directory, accepts a sole running collector, and rejects an ambiguous choice.

Bounded trace list. Status column marks traces containing error spans.

Flag Type Default Notes
--service <name> string (all) Filter by service.name.
--status <status> enum (all) ok or error.
--operation <name> string (all) Filter by root operation.
--since <duration> duration 15m Lookback like 15m, 2h, 1d.
--duration-min <ms> int (off) Only traces at or above this duration.
--limit <n> int 20 Capped at 100.
--cursor <token> string (off) Continue from the previous JSON page.
Terminal window
$ blop traces --service checkout --status error --since 15m --limit 10 --json

One trace: the span tree with depths, status, durations, and span IDs. --include adds logs, spans, or attributes detail to the JSON payload (logs also prints a correlated-log count in human mode).

Terminal window
$ blop trace 4f6c9c2e1b7a4d3e --include logs --json

Use blop trace-logs TRACE_ID for a bounded, paginated correlated-log list.

Search spans directly when a trace summary is too broad. Filters include service, trace ID, operation, parent operation, status, lookback, limit, exact attributes, and substring attributes. blop span SPAN_ID returns one span with its trace and parent context; blop span-logs SPAN_ID returns correlated logs.

Terminal window
$ blop spans --service checkout --status error attr.http.route=/orders --json
$ blop span 8f3ab280f4d14c2b --json

Bounded log slice with correlation fields.

Flag Type Default Notes
--service <name> string (all) Filter by service.name.
--severity <level> string (all) Substring match, e.g. ERROR, WARN.
--trace-id <id> string (all) Only logs correlated to this trace.
--span-id <id> string (all) Only logs correlated to this span.
--contains <text> string (all) Body text filter.
--since <duration> duration 15m Lookback window.
--limit <n> int 100 Capped at 500.
--cursor <token> string (off) Continue from the previous JSON page.

Append attribute tokens after traces, spans, or logs:

Terminal window
$ blop traces attr.deployment.environment.name=staging --json
$ blop logs attrContains.exception.message=timeout --json

attr.KEY=VALUE is an exact indexed match. attrContains.KEY=TEXT is a substring match supported by span and log search. Attribute tokens are filters, not positional arguments.

Use aggregates for compact evidence that fits an agent context window:

Terminal window
$ blop trace-stats service error_rate --since 30m --json
$ blop trace-stats attr.http.route p95_duration --service api --json
$ blop log-stats severity --since 15m --json
$ blop facets traces attribute_values --key http.route --json

Trace groups are service, operation, status, or attr.KEY; aggregations are count, avg_duration, p95_duration, and error_rate. Log groups are service, severity, scope, or attr.KEY and currently support counts. Trace facets support service, operation, status, attribute_keys, and attribute_values; log facets support service, severity, and scope.

Deterministic analysis over stored telemetry; no LLM is involved. Phase-one findings: error traces and their common root spans, new error signatures compared with a baseline window, slow traces and spans (explicit --duration-min threshold or a baseline delta), bursts of warning/error logs correlated to affected traces, incomplete traces, and services that stopped emitting during the window.

Every finding contains a stable finding code (error_trace, new_error_signature, latency_regression, log_burst, incomplete_trace, no_telemetry), a severity and confidence, a concise summary, observed evidence with trace/span/log identifiers, current and baseline values when declaring a regression, and follow-up blop commands for deeper inspection.

Flag Type Default Notes
--service <name> string (all) Restrict the audit to one service.
--since <duration> duration 15m Current window.
--baseline <duration> duration same as --since Baseline window compared against the current one.
--duration-min <ms> int (off) Explicit slow-trace threshold.
--fail-on <mode> enum never error fails on error-severity findings; regression also fails on new_error_signature and latency_regression.

The audit never claims causality from correlation alone. Wording uses “associated with” or “observed in” unless the telemetry directly proves a dependency.

Terminal window
$ blop audit --service checkout --since 15m --baseline 1h --fail-on regression --json

When --json is absent, queries print compact tables and short summaries. Identifiers remain copyable and are never shortened in an ambiguous way.

--json writes exactly one JSON document to stdout. Diagnostics go to stderr. No spinner, colour code, progress line, or warning ever corrupts stdout. Errors use the same envelope plus an error object with code, message, and optional details.

{
"schema_version": "blop.cli/v1",
"command": "traces",
"generated_at": "2026-08-29T12:00:00.000Z",
"data": [],
"page": {
"limit": 20,
"lookback": "15m",
"returned": 0,
"truncated": false,
"next_cursor": null
},
"warnings": []
}

Rules:

  • snake_case keys;
  • ISO 8601 UTC timestamps;
  • durations in integer nanoseconds in raw records and explicit milliseconds in summaries;
  • IDs represented as lowercase hexadecimal strings;
  • absent optional values are null, not omitted unpredictably;
  • result ordering is deterministic;
  • breaking changes require a new schema_version.

Agents can pass - where a command accepts free-form text, reserving stdin as a convention without shell-escaping large input.

Code Meaning
0 Command completed; audit found nothing at or above the configured failure threshold.
1 Audit findings met --fail-on, or an active browser check failed.
2 Invalid arguments or configuration.
3 Collector unavailable.
4 Store/query failure.
5 Timeout.

Top-level CLI errors print stack traces only when BLOP_DEBUG is set.

The collector accepts standard OTLP/HTTP on the conventional endpoints:

Endpoint Content types
POST /v1/traces application/json, application/x-protobuf; optional Content-Encoding: gzip
POST /v1/logs application/json, application/x-protobuf; optional Content-Encoding: gzip

Compressed and decompressed request bodies are capped (default 16 MiB), and unsupported content types are rejected. The collector binds to loopback, never executes application code, and stores enough OpenTelemetry identity to preserve correlation: resource attributes (especially service.name), instrumentation scope, trace/span/parent IDs, kind, status, timestamps, attributes, and events, plus log timestamp, observed timestamp, severity, body, and correlation IDs.

See Monitor HTTP API for every query route. A running collector also exposes /openapi.json and a dependency-free route index at /docs.

See Environment variables for the monitor, OpenTelemetry, provider, and active-runner variables. Monitoring settings currently resolve in this order: CLI flag, environment variable, built-in default. Project and user configuration layers remain planned work.

Command Behavior
blop test [patterns] Discover specs, run them with the agent loop, write reports, exit non-zero on any failure.
blop run [patterns] Same as test.
blop watch [patterns] Run, then re-run on file change. Polls every 1 s.
blop list [patterns] Load specs and print discovered test names. No browser launched.
blop init [path] Scaffold a starter spec at tests/homepage.blop.ts (or the given path).
blop skills <subcommand> Manage bundled SKILL.md files — see Skills.

If patterns are omitted, discovery defaults to **/*.blop.ts and **/*.blop.tsx. Files matching node_modules/, dist/, .blop/, and .git/ are always skipped. Pass --help after a browser command (e.g. blop test --help) to print the full option list.

Subcommand Behavior
blop skills list Print each bundled skill as name@version — description.
blop skills view <name> Print the full content of a named skill.
blop skills check Validate all bundled skills. Exits non-zero on hard errors.
blop skills improve <name> [--write] Distill learnings from .blop/skills journal entries into an improved skill version. Dry-run unless --write.
Flag Short Type Default Notes
--config <file> -c string (auto-discover) Custom path to blop.config.ts
--report-dir <dir> string .blop Output directory for artifacts
Flag Short Type Default Notes
--base-url <url> -u string (none) Resolved against relative agent.goto("/path")
Flag Type Default Notes
--browser <name> enum chromium chromium, camoufox, firefox, or webkit; Camoufox is experimental and supports local or containerized runs
--headed boolean false Show the browser window
--viewport <WxH> string (Playwright default) Example: --viewport 390x844
--containerized boolean false Run the selected browser in a separate warm Docker container; Chromium uses blop-playwright, Camoufox uses blop-camoufox
Flag Type Default Notes
--provider <name> string env Supported native-loop provider name
--model <name> string env Model name
--api-key <key> string env API key — prefer env vars for secrets
--max-steps <n> int (unlimited) Hard cap on agent tool steps. Runs stop on finish, timeout, or the no-progress stall guard.
--workers <n> int 1 Run up to N agent tests concurrently
Flag Short Type Default Notes
--reporter <name> -r enum all basic, json, junit, or all
--verbose -v boolean false Stream agent events to stderr in real time
--progress-file <file> string (none) Append live NDJSON progress: test_start, action, frame, test_finish
--capture-screenshots boolean false Save a screenshot after each browser action (and stream live frames)
--no-stream boolean (stream on) Disable the live CDP screencast; use per-action screenshots
--frame-interval <ms> int 200 Min ms between streamed frame progress lines

The active runner can export its own telemetry to any OTLP backend. Traces, metrics, and logs are exported only when an endpoint is configured. This outbound export does not put control-plane runs in the local SQLite store. See OpenTelemetry.

Flag Type Default Notes
--otel-endpoint <url> string (none) OTLP/HTTP collector base URL, for example http://collector:4318. Enables export for all three signals.
--otel-service-name <name> string blop-runner Value of service.name on exported telemetry
--otel-environment <name> string (none) deployment.environment.name, e.g. staging
--otel-propagate boolean false Send W3C traceparent to the app under test
--otel-propagate-allowlist <hosts> string (empty) Comma-separated hosts allowed to receive trace context

A file is treated as a browser-check spec if its filename matches either:

\.blop\.[cm]?[tj]sx?$
\.agent\.[cm]?[tj]sx?$

So homepage.blop.ts, auth.blop.tsx, and smoke.agent.ts all qualify.

Patterns are evaluated in this order:

  1. If a pattern resolves to an existing file, that file is included.
  2. If it resolves to an existing directory, all spec files under it are included recursively.
  3. Otherwise the pattern is treated as a glob.