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.
Synopsis
Section titled “Synopsis”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 stopblop 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.
OpenCode integration
Section titled “OpenCode integration”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.
Collector lifecycle
Section titled “Collector lifecycle”blop monitor start
Section titled “blop monitor start”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.
blop status
Section titled “blop status”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.
Discovery and drill-down
Section titled “Discovery and drill-down”blop services
Section titled “blop services”Services observed in the window, derived from the standard service.name resource attribute.
$ blop services --since 1hQuery 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.
blop traces
Section titled “blop traces”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. |
$ blop traces --service checkout --status error --since 15m --limit 10 --jsonblop trace
Section titled “blop trace”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).
$ blop trace 4f6c9c2e1b7a4d3e --include logs --jsonUse blop trace-logs TRACE_ID for a bounded, paginated correlated-log list.
blop spans and blop span
Section titled “blop spans and blop span”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.
$ blop spans --service checkout --status error attr.http.route=/orders --json$ blop span 8f3ab280f4d14c2b --jsonblop logs
Section titled “blop logs”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. |
Structured attribute filters
Section titled “Structured attribute filters”Append attribute tokens after traces, spans, or logs:
$ blop traces attr.deployment.environment.name=staging --json$ blop logs attrContains.exception.message=timeout --jsonattr.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.
Aggregates and facets
Section titled “Aggregates and facets”Use aggregates for compact evidence that fits an agent context 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 --jsonTrace 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.
blop audit
Section titled “blop audit”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.
$ blop audit --service checkout --since 15m --baseline 1h --fail-on regression --jsonOutput contract
Section titled “Output contract”Human output
Section titled “Human output”When --json is absent, queries print compact tables and short summaries. Identifiers remain copyable and are never shortened in an ambiguous way.
JSON output
Section titled “JSON output”--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.
Exit codes
Section titled “Exit codes”| 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.
OTLP endpoints
Section titled “OTLP endpoints”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.
Environment variables
Section titled “Environment variables”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.
Active browser checks
Section titled “Active browser checks”Commands
Section titled “Commands”| 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.
blop skills subcommands
Section titled “blop skills subcommands”| 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. |
Runner options
Section titled “Runner options”Discovery & paths
Section titled “Discovery & paths”| 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 |
App under test
Section titled “App under test”| Flag | Short | Type | Default | Notes |
|---|---|---|---|---|
--base-url <url> |
-u |
string | (none) | Resolved against relative agent.goto("/path") |
Browser
Section titled “Browser”| 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 |
Reporting & output
Section titled “Reporting & output”| 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 |
Telemetry export
Section titled “Telemetry export”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 |
Spec file detection
Section titled “Spec file detection”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.
Pattern resolution
Section titled “Pattern resolution”Patterns are evaluated in this order:
- If a pattern resolves to an existing file, that file is included.
- If it resolves to an existing directory, all spec files under it are included recursively.
- Otherwise the pattern is treated as a glob.