Changelog
Unreleased
Section titled “Unreleased”Per-agent setup commands
Section titled “Per-agent setup commands”- Connect exposes a copyable
blop setup mcp <client>for every MCP table client, including OMP, in both its agent row and manual configuration section. Existing registrations are not forced or replaced by the displayed command. - Overview’s first-spans step uses
blop setup agents, not an individual agent launcher.
Hook-aware setup checks
Section titled “Hook-aware setup checks”- Doctor’s setup check now reads the same installed hook receipts and enabled capture policies as the connected-agent list. It names the installed hooks and capture mode, while retaining unrelated framework setup diagnostics.
- CLI and Connect share this check and the collector’s advertised policy path.
Application run suggestions
Section titled “Application run suggestions”- Overview and Connect select run commands only from application framework
adapters. Agent-only projects use
blop run -- npm run dev, never a coding agent launcher. Existing application framework commands remain unchanged.
Runnable memory setup
Section titled “Runnable memory setup”- Add
memory add --kind --title --bodywith optional tags and an explicit ID, using the existing graph change writer and JSON envelope. Default IDs use SHA-256 of the exact title/body JSON tuple, so identical retries return the existing node without adding a revision. - Make Memory’s agent prompt and human command executable, and use
search --textfor the row’s copy-read action. Addressed detail reads still usememory get.
Local Markdown knowledge
Section titled “Local Markdown knowledge”- Add
memory markdown init|attach|index|list|detach: bounded, explicit, model-free projection of local Markdown notes, heading sections and references. Source folders remain authoritative and read-only; failed scans, including detected root replacement or mid-scan edits, preserve the last complete snapshot with failure freshness. Unsupported administration flags fail before any source or database operation. - Reuse existing memory search/context/get/neighbors and read-only MCP with path/section/hash citations. Stable frontmatter IDs survive renames; deletion and detach remove current retrieval without altering authored memory history.
- Keep projection references unapproved and reject authored mutations of projected
IDs. Local reads distinguish
assessment: not_configured. Resolve exact local trace references without reading or uploading trace bodies. - Preserve authored assertion and approval provenance when a projected endpoint disappears or derived rows are rebuilt; restore visibility when its ID returns.
- Anchor Markdown initialization to Linux procfs directory handles. Unsupported platforms fail explicitly rather than reverting to race-prone pathname writes.
- Correct
.markdowningestion, code-fence closers and heading links; preserve real inner inline links after escaped outer brackets and resolve encoded#and?filename characters while rejecting raw queries. - Preserve exact 1029-character source IDs and 1537-character path/heading citations in graph reads, authored commits/proposals and publication previews, including their published CLI schemas, without truncating identifiers.
Repository memory destinations
Section titled “Repository memory destinations”- Add
memory bind|binding|unbindfor deliberately selected hosted read destinations. User configuration contains no credentials or repository edits; subdirectories and Git worktrees share the canonical repository identity. - Bound CLI/stdio MCP reads reuse the existing profile and managed operations with fresh workspace/project/grant checks. Hosted failures never fall back to local results. Explicit local CLI scope remains offline; Markdown administration and publication consent remain separate.
Optional read assessment
Section titled “Optional read assessment”- Add a shared schema-validated assessment boundary and explicit HTTP adapter, without a mandatory model, new agent tool or provider fallback.
- Preserve read data while adding task/query-bound receipts, exact source revisions/hashes, graph/policy/assessor versions and honest partial coverage. Selected memory never claims to cover unseen working-tree files or diff.
- Enforce configured assessment on hosted direct, managed, CLI/MCP and frozen chat snapshot reads. Timeout, invalid output, changed sources or revoked grants return no unassessed fallback. Authorization stays deterministic code.
Controlled Markdown publication and web receipts
Section titled “Controlled Markdown publication and web receipts”- Publish one explicitly selected indexed Markdown snapshot using the existing destination/payload preview, reviewed hash and hosted owner approval. No directory upload, source reread, synchronization, reference-edge transfer or projection authority. Hosted corrections remain separate explicit edits.
- Preserve citation identity on no-op reindex so unchanged publication retries retain their exact receipt; changed indexed content invalidates the preview.
- Show assessment status, findings, bounded coverage and exact source revisions in the web memory browser, including history. Query/detail failures clear stale detail rather than presenting it alongside a fail-closed error.
Retained integration source receipts
Section titled “Retained integration source receipts”- Resolve
blop.external-linkreferences against existing Linear, Jira and GitHub issue/PR link receipts, through the current owning project/team grant. Exact receipt IDs, optional recorded URLs and UTC capture timestamps are checked without loading provider bodies or returning denied source hints. - Refresh accessibility after ownership/deletion changes while retaining authored knowledge/history. Unsupported content hashes remain unknown; an available retained receipt is neither live provider freshness nor claim verification.
- This does not add a general ticket/PR/CI ingestion feed or source cursor.
1.9.0 (2026-11-04)
Section titled “1.9.0 (2026-11-04)”MCP release gates
Section titled “MCP release gates”- Frame stdio requests on LF rather than Node’s text-line separators, preserving U+2028 and U+2029 inside JSON strings on Node 24, split UTF-8 characters, CRLF, and the final request at EOF.
- Keep the generated MCP client table synchronized with the README only. The generated docs CLI reference no longer has a hand-synchronized MCP block.
Inspector UI rebuilt on the design system (#664)
Section titled “Inspector UI rebuilt on the design system (#664)”- Every Inspector page is rebuilt on the design system and reads the real collector APIs, with in-place live updates on one shared event stream and no page reloads. Focus, selection, open panels and filters survive updates.
- New guarded local writes:
DELETE /api/runs(dry run first, running runs refuse) andPOST /api/inspector/settings/limits. New reads:/api/inspector/overview,/api/inspector/memory,/api/inspector/cloudand/api/test-coverage/history. - Cover text runs through typed escaping; writes need same-origin JSON plus a marker header. The overview gains a “when failures happen” heatmap (#665).
Collector QA fixes
Section titled “Collector QA fixes”- Worker and metric CLI overview paths no longer send a bare ? separator when no filter is set (Node 24 request framing).
- Redact credentials in log bodies from unregistered (plain OTLP) sources, as their attributes already were, and cap those bodies at 64 KiB. Rows stored before this change are not rewritten.
- App-error issue titles lead with the recorded exception, e.g.
TypeError: Cannot read properties of undefined (reading 'amount') in POST /api/checkout (HTTP 500). - Server spans without
http.routeare fingerprinted on the request path (url.path/http.target, ids normalized), so errors on different endpoints are separate issues. Such issues regroup once: new occurrences get a new id. - Hook sessions end: a measured end closes its start span, a
turn_endcloses the open turn when the host has no turn ids, andsession_endcloses whatever the session left open. - The Issues list wraps the “What happened” title (up to 3 lines) instead of cutting it at 28 characters, so issues that share a prefix are told apart.
blop doctorfails the port check when a non-Blop process holds the port.- Too many requests in flight answers 503
overloadedwithRetry-After: 1instead ofcapture_unavailable, and the connection ceiling is raised so a burst gets that 503 rather than a dropped socket.
Inspector Logs implicit time range (#662)
Section titled “Inspector Logs implicit time range (#662)”- Use the default 24-hour Logs range when the URL has no range, including history traversal, instead of restoring a remembered selection. Keep explicit URL ranges authoritative, consistent with Sessions and Issues.
Demo MAST contract (#654)
Section titled “Demo MAST contract (#654)”- Align the demo failure test with the current MAST policy: a downstream app failure alone establishes neither a mode nor a rule. Keep the classifier and the demo’s issue, span, and memory-read assertions unchanged.
Run e2e stitching fixture (#653)
Section titled “Run e2e stitching fixture (#653)”- Exercise the OpenCode plugin OTLP tool-span capture contract alongside AI SDK
model calls and app spans in the
blop runend-to-end fixture. Generic AI SDK spans alone are application telemetry, not coding-agent evidence for doctor stitching. Keep the strict stitching check and verify the plugin-to-app causal chain through MCP.
Quiet hook callbacks (#647)
Section titled “Quiet hook callbacks (#647)”- Native hook events queue durably before the bounded delivery-time identity probe. Offline, restarted, slow, redirected, old or different-store collectors do not produce host callback errors or output; mismatched identities receive no telemetry POST. Pending events drain when the bound collector answers.
blop agents statusanddoctorexpose pending events, paused destinations and held-delivery reasons. Native integrity, input, outbox and enqueue failures remain loud and return non-zero.- Legacy
blop agent hookdelivery failures, including an exhausted budget after enqueue, are silent. Configuration and capture-loss diagnostics keep their existing exit behavior. Legacy queued rows without stable collector identity retain destination-only delivery; native legacy callbacks check the recorded process instance, but background replay cannot protect store identity.
Medium review hardening
Section titled “Medium review hardening”-
Recorded argv also masks prefixed/camelCase credential flags and
-ubasic-auth values, without changing the launched process’s arguments or treating-pas a password flag. Init preflights a redirected.blopparent before any writes. -
OpenCode resolves the collector before configuration writes, rolls back its edits when setup-state publication fails, and refuses switching config paths until the existing setup is removed. Pinned collectors use the version handshake and report registry ownership rather than being unconditionally external.
-
MCP client and marketplace deadlines terminate owned process groups, escalate after a bounded grace period, and settle even when descendants retain pipes. Verification-skill commands apply the same bounded teardown. Desktop installer locks retain owner identity and offer explicit stale-lock recovery instructions; a live installer is never automatically displaced.
-
Agent wiring snapshots only setup-owned files, not retained telemetry/outbox contents. Bulk MCP repair addresses every stale scope and preserves collector pins, including environment-based URLs. MCP results reject oversized fixed sections and disclose content/diff cuts made by replay previews.
-
Evaluation HTTP and CLI share the 128 KiB input limit and the same opaque-ID and actor contracts as storage. Interrupted/malformed mutation receipts retain unknown-outcome guidance. Manage-only queue authors and review-only completers no longer need unrelated read grants; assignment removal releases outstanding claims with revisioned audit, and next-item selection skips stale evidence.
-
Fresh runs replace inherited
blop.run.idwhile preserving other user resource attributes. Usage reports enforce their upper time bound, cap group discovery and retain validated unscoped Codex counters. Worker raw commands preserve leading collector selectors and honor the final output format. Run usage errors preserve--reportafter environment and trigger flags. -
Flow discovery traverses explicitly requested directories outside cwd and accepts
./-prefixed globs. Optional-loader errors distinguish absent packages from broken transitive imports/exports; repair guidance uses the CLI’s original installation context, including setup-doctor warnings. -
OpenCode rollback/removal restores original bytes without a UTF-8 round trip. MCP conflict diagnostics disclose clipped-key collisions and exhausted node budgets; refused MCP rollback selects the drift recovery hint. Init destination refusals use structured invalid-config errors, failed alert sends include a next command, and recorded argv reserves the computed shell-quoted marker size.
-
Collector hostname aliases require the saved collector identity rather than equating IPv4/IPv6 origins blindly. Native rollback’s deletion-only exception rejects added duplicates of owned callbacks. Flow evidence rejects fields whose credential redaction expands beyond the byte contract instead of silently clipping an identifying signature.
-
Doctor normalizes IPv6 socket hosts and HTTPS default ports, shares strict active Codex exporter checks, and honors OpenCode’s active config override. Pi extension recipes are unverified/not-applicable rather than false failures. Monitor init respects preferred config precedence; status MCP and foreground-stop hints pin the resolved collector. Served OpenAPI3 schemas use nullable scalar types and declare alert-action path parameters.
-
Storage compaction checks free capacity on each SQLite volume independently. Resource retention uses indexed bounded age batches; concurrent legacy-log migrations recheck columns under the write lock. Span status filters include server 5xx failures and retain successful spans with unspecified kind.
-
Delete previews enforce the store-format gate on a read-only connection. Deletion and retention remove trace/conversation bookmarks only when their exact retained subject disappears, without resurrecting them on recapture.
-
Issue retractions repair surviving evidence timestamps/titles independently of regression state. Comparisons use one actually observed service/kind/operation cohort on both sides and include null-kind/status-less successes. Provider 429s retain an error causal chain without promoting ordinary app/tool 429s.
-
Service reports select distributed traces through failed spans in that service. Issue navigation preserves failure-class filters, and muting/fixing an issue removes its owned expanded fix-context preview.
-
Why applies project eligibility before limiting open issues and selects that project’s own occurrence, run and trace for shared fingerprints. Git authorship recognizes only final trailer paragraphs, not coauthor examples in body prose.
-
Automatic hook setup preflights native files before enabling capture. Late filesystem failures report retained paths, current consent and the disable command rather than imply rollback. Native removal resumes exact completed restoration steps after interruption while still refusing unrelated drift.
-
Hook and application consent writers share a cross-process lock. Inspector edits verify their expected revision under that lock and return conflict instead of overwriting newer capture restrictions.
-
Amp, Goose and Hermes project observers accept owned descendant directories while retaining the shared bridge’s nested/outside-repository refusal. Amp propagates public-text selection truncation. Hermes forwarding failures emit fixed content-free diagnostics without vetoing host callbacks.
-
Cursor compares complete owned handlers, including timeout, while preserving foreign entries. Missing installed modules are caught inside its callback boundary and still produce the neutral observer response.
-
Disabled hook bindings are excluded before the deliverable batch limit, so held rows cannot starve another binding at the same destination. Replacing a queued start atomically updates lifecycle and pending-end pairings, with new audited identities for changed ends and content-free replacement mappings.
-
Memory initialization applies a hook’s SQLite busy timeout before schema writes, not after a fifteen-second wait. OpenCode session-location lookups have a 500ms deadline; cleanup abandons pending lookups and late results cannot enqueue an event after capture stops.
-
Collector startup brackets IPv6 URLs, probes busy ports on their actual host, and filters registry reuse by an explicitly selected host. Foreground startup refuses an already healthy IPv6 collector rather than starting a duplicate.
-
Lost-run sweeps rotate through bounded pages of runs and launchers, so live entries cannot permanently hide later dead processes. Live events page run starts and completions independently in each cursor’s order.
-
Run, imported-session and app-trace live-event cursors use persistent insertion sequences instead of reusable SQLite rowids. Purging the newest or every row cannot hide recaptured evidence; upserts retain their original insertion order.
-
Bash, Zsh and Fish live completion honor collector flags on the command line. Subcommands offer their own flags and values without list-only parent flags. Bash file candidates preserve whitespace and literal glob characters.
-
Agent launchers refuse explicit collectors that conflict with saved capture bindings and fall back to an unchanged plain launch after wiring refusal. OpenCode native telemetry uses the same selected collector as hooks and MCP. Undo preserves pre-existing identical MCP entries; conflict and hosted-doctor diagnostics do not expose saved credentials or memory content.
-
Recorded commands mask credential aliases without hiding adjacent flag names. Copyable collector hints quote URLs for the shell. JSON metadata keeps authored dictionary keys, prompt versions preserve UTF-8 BOM bytes,
config show --hostaccepts its advertised override, and pending prompts take the default on EOF. -
Init refuses symlinked output files before writing. Collector prerelease versions follow SemVer ordering. Why retains an issue-free trace’s inspector link and escapes producer-controlled reasons; failure-context escapes all terminal fields and pins trace identity on span drill-down.
-
Memory publication preserves rule guards in the reviewed payload and hash. Replacement edits clear omitted optional content, pinned rules respect project applicability in inherited briefs, and approved purge remains possible after access to cited evidence is revoked. Read-log queries accept their 500-node cap.
-
Native hook identity checks and delivery share one one-second callback budget; slow or unavailable collectors leave events durably spooled before host deadlines. Project-only adapters retain actionable rollback-drift errors without probing unsupported global bindings.
-
Alert shutdown waits for active evaluations and delivery receipts before closing storage. A drain requested during a send includes newly queued transitions; paused-only rules still expire history, and failed
alerts test --sendexits nonzero while retaining its delivery diagnostic. -
Metric previews select exact newest nanosecond points before limiting, totals have their own serialized-byte budget, and windows without a contributing delta interval remain unknown. Overview service edges use trace-wide app failure and exclude internal collector services.
-
Protobuf log event names reject invalid wire types. Captured content reports truncation from actual byte clipping, not a producer’s literal marker suffix.
-
Flow evidence projection redacts credentials from service names, operations and fallback error-log signatures before grouping or returning context.
-
The Python application session example batches span export off the asyncio event-loop thread, retaining explicit final flush and shutdown.
-
Sequential monitoring and hook test commands use Node’s native test timeout, removing the GNU
timeoutdependency on macOS. Vector-backend PR checks covermainand both development integration branches.
Review hardening
Section titled “Review hardening”- Run JSON/report output, stored argv and lifecycle command lines now use the same credential-redacted, bounded representation. Agent runs without content capture retain only argv0; split credential flags are masked without changing the child’s arguments. Fix-context repros and latest-run notes redact before collapsing control characters.
- Metric capture classifies original attributes before redaction and omits nested content-bearing containers without consent, preserving typed metadata without promoting containers into session or worktree identifiers. Unscoped numeric token counters retain accounting validation instead of being mistaken for credential attributes.
- MCP conflict descriptions mask camelCase credential fields and bound depth, nodes and output bytes. Failed recovery-snapshot writes preserve the original client failure and report that the previous entry could not be saved.
- Alert history expires during steady-state evaluation as well as transitions. Pending events retain their selected destination, including locally recorded events promoted on connection; disconnect pauses queued sends. Slow hosted delivery no longer blocks evaluation. Agent-connection and native-hook rollbacks refuse later byte edits; invalid project configuration blocks collector startup.
- Structural replay titles use registered agent labels only; unknown agent values cannot inject content or inherited object properties into hosted titles.
CLI core jobs
Section titled “CLI core jobs”New commands
blop why [<run_|iss_|ses_|trace id> | --last] [--all-projects]explains one failure: what broke, the agent step and app span where it broke, the deterministic MAST mode (blop.mast/v1) and failure kind, and the memory the agent read in that session. It ends with the next command and an inspector link. A demo answer is marked as demo data and never hands its issue to a coding agent.blop runs [--failed --since --limit --branch --all-projects]andblop runs show <id> [--timeline]list the runs of this repo and compare a run with the previous run of the same command.blop demo [--clean [--yes]]records a passing and a failing demo run, an issue and a memory read, all taggedblop.demo=true, soblop why --lasthas an answer before anything is instrumented.--clean --yesremoves only demo data.blop claude,blop codexandblop opencode [-- args]start the agent with Blop capture wired: the first launch in a repo wires the hooks, the MCP entry and the capture binding (project scope), lists every file it changed and ends with the exact undo line. They fail open and return the agent’s own exit code.-p <n>and--url <url>before--name the collector.blop config show [--json]prints every setting with its value and source.blop help alllists every command; root help shows the core ones.
Changed behaviour
- Bare
blopis now the status table plus oneNext:line. It starts a stopped collector in the background, never prompts and no longer opens the browser.blop startis an alias ofblop up. blop statustext uses the same table as bareblop. Its--jsonoutput only gains fields, and the envelopenextnow carries the next step.Next:lines and hints carry the-por--urlyou passed, so the suggested command asks the same collector.- Settings resolve in one order: flags,
BLOP_*environment, project.blop/config.json(.blop/monitor.jsonis still read), user config, defaults. An invalidBLOP_*value is ignored with a warning that names it.blop initwrites.blop/config.jsonand the gitignore lines.blop/*and!.blop/config.json, so the config can be committed. - Coding agents (
CLAUDECODE,CODEX_SANDBOX,AI_AGENT,BLOP_AGENT=<name>and similar) getblop.cli/v1JSON by default fromruns,runs show,why,issues,issueandstatus.-o textandBLOP_AGENT=0keep text. blop doctorhas awarningstatus for checks that do not fail the setup (for example a missing optional package).blop runkeeps the child’s exit code and summary through Ctrl-C, escalates SIGTERM and SIGHUP after a grace period, and prints a local summary when the collector never answers.
Store and collector
- A newer or unrecoverable store exits 78 (do not retry).
blop up --recovermoves the store aside, never deletes it, and starts an empty one. - The size cap is enforced, oldest activity first, with recent traces protected.
Status and health report busy retention passes and a WAL held by a reader.
blop up --compactcompacts a large legacy store on request. - The collector exits 70 when its capture worker is exhausted, and a managed one in that state is replaced.
runsrecord their argv and project root (additive, nullable columns).
Agent hooks and MCP
- Native hooks spool to the outbox before contacting the collector, so a down or
hung collector never loses an event. Hooks bind to a stable per-store collector
identity, so a collector restart no longer stops capture. Bindings made before
this change need
blop agents setup <id>once. - A project binding accepts hooks from the repo root or any directory under it that no nested git repository owns.
- New MCP tools
list_runs,get_run,whyandopen_linkmirror the CLI. blop setup mcp <client> --removeon a JSON config gives back the exact bytes from before Blop’s add when nothing else changed since (or deletes the file Blop created); otherwise it takes out only Blop’s entry.- A project hook rollback blocked by global hooks installed later
(
blop setup agents) names the global removal to run first. blop setup opencode --removeon an OpenCode config edited since puts back the user’s ownexperimental.openTelemetryvalue (such asfalse) instead of dropping the key. A setup record from an older Blop that did not record its edits now says the config was left as is, and what to take out by hand.blop codexandblop setup mcp codexwork with Codex 0.165, which prefixes “No MCP server named ‘blop’ found.” withError:; before, a fresh machine was told its Codex install was broken and nothing was wired. Checked against the real Codex 0.165.0 binary in a sandbox.- The first
blop codexlaunch notes that Codex runs new hooks only after you trust them (/hooksin Codex);codex execskips untrusted hooks silently. - A client that runs but refuses (such as a missing
CODEX_HOME) is no longer called a moved or removed install; the hint says to fix what the client reports. blop claude -p <port> <args>without--notes that-pwent to the agent and prints the--form that names the collector.
Install
npm i -g @blopai/cliworks:@blopai/testand@blopai/browser-harnessare optional dependencies.blop testand flow checks without them exit 2 with an install hint.
Removed
blop verify(and its MCP tool, routes and columns): Blop has no trustworthy basis for saying a fix worked. Mark an issue fixed in the inspector.blop connectandblop disconnect: the launchers wire on first launch, andblop agents setup,blop agents install-hooksandblop setup mcpdo the pieces (each with--remove). Typing a removed command is the plain unknown-command error (exit 2).
Known limitations are listed in docs/cli-spec.md, section 11.
Automatic agent hook setup
Section titled “Automatic agent hook setup”- Add
blop setup agentsto detect installed coding agents, start or reuse a local collector, and install supported user-global hooks in one command. - Preserve existing modes, exclusions and foreign settings; support explicit
--capture,--url,--portand per-agent JSON results. Repeated runs do not duplicate hooks; failures do not prevent other agents from being installed. - Keep native OTel recipes and MCP setup separate, and preserve host activation requirements and the distinction between installed hooks and live delivery.
Agent CLI status clarity
Section titled “Agent CLI status clarity”- Show capture enabled/disabled, mode and policy revision in
blop agents status, including metadata-only policies whose content permissions do not change when disabled. Keep live delivery explicitly unverified. - Label native telemetry tiers as static capabilities in agent detection and status output, separate from the current hook setup. Status rereads state on every invocation; JSON contracts are unchanged.
Web audit stack integration
Section titled “Web audit stack integration”- Keep the current CLI and plugin shell while replaying the audit fixes. Share local-time date, duration and percentage formatting across current web pages; expose local collector Issues through the query catalog without mixing hosted test-failure counts.
- Disclose taken sign-up emails in the restored password flow without linking retired password recovery. Refuse cross-workspace invitations, distinguish already-confirmed email links, and retain chat step labels and measured timing.
- Keep permission-denied 403s on the current page. A valid session whose workspace membership ended goes to workspace setup instead of sign-in; current shell, workspace and billing reads use the same discriminator.
- Hide unshipped per-account notification preferences; existing links continue to shipped workspace alert destinations. Preserve shipped Discord and export integrations and show paid-plan restrictions consistently.
- Regenerate the triage last-run migration as
0074_flaky_sway, after the current alert-rule and agent-commit migrations, with a merged-schema snapshot.
Agent graph and map
Section titled “Agent graph and map”- Add the hosted Agent Map and session Graph views,
blop map,blop session, and the read-onlyget_agent_mapMCP tool alongsideget_statusandget_audit. - Preserve the collector’s session-tree, capture-policy and durable-metric reads; project the agent graph separately and stamp validated hook parent-link attributes.
Infrastructure resource samples
Section titled “Infrastructure resource samples”- Project accepted, policy-sanitized OTLP metrics into latest CPU, memory and host/instance uptime samples in the same transaction as durable metric points.
- Keep the existing unknown-payload ingest API, precise metric history and protobuf error responses; malformed or disabled-source points never feed samples.
Inspector: Local Inspector v3 layout
Section titled “Inspector: Local Inspector v3 layout”- Shell:
- The inspector follows the Local Inspector v3 design (
docs/inspector-source/v3/). - Content sits in an inset rounded frame. The rail is 232px, and the current page uses the raise fill.
- A 48px top bar shows This machine, the collector address and the page name.
- Page titles are 20px. The header holds the page’s CLI equivalent and its range control.
- CLI chips are checked against the CLI registry. Detail pages show none.
- Phones keep the app bar and drawer. Tablets get the 64px icon rail.
- The inspector follows the Local Inspector v3 design (
- Home:
- A status strip: Needs attention, Capture, Agent.
- Overview tiles joined in one strip.
- One span activity chart with errors stacked in red. Its axes are HTML, so they stay readable at any width.
- The rail’s Issues item counts open issues.
- Pages:
- Tables sit in cards with small uppercase headers. Tabs are pills.
- Sessions gets a one-line summary. The throughput chart sits in a card.
- Memory rows expand in place to Body, Connected to and Provenance, fetched on demand.
- Issue rows lead with Fix context. It opens the exact text it copies, and Escape closes it.
- The failure heatmap draws hits in red, with HTML axes.
- Run detail reports Test result, Capture health and Runtime evidence separately.
- Connect leads with endpoint, agent and skill cards. Every command is real.
- Settings opens with what agents can do. The local MCP server only reads, so each write names where it happens.
- Coverage’s empty state offers the address to publish to, and a Refresh button that reports what it found.
- Responsive:
- The observation graph uses one column on narrow screens.
- Long branch names, commands and filter options shrink inside their controls.
- Every page fits 320px with no sideways scroll (
test/monitoring/inspector-v3-responsive.test.ts).
- Keys: g m opens Memory, and g o opens Coverage.
Inspector: overview charts from the Blop App design
Section titled “Inspector: overview charts from the Blop App design”- Home: an Overview above span activity, on the same range. It has four tiles
(traces, failure rate, p95 trace duration, model cost), each with its change
against the previous period of equal length and a sparkline. It also shows
trace outcomes as a donut and model cost by model.
- When retention removed any of the previous period, its changes are unknown, never computed against a partial count.
- Cost comes only from priced model-call receipts. Unpriced calls are listed as unpriced and kept out of totals and shares, never counted as zero.
- Issues: failure classes over the last 7 days, and a day-by-hour heatmap of when failures happen (local time).
- Runs: finished runs per day over 14 days, with failures stacked and the pass rate as a line.
- Each read is one bounded read-only snapshot (newest 10,000 rows) with a
visible truncated state. Each chart has an accessible summary and a data
table with the same numbers, and is server-rendered SVG with no inline styles
(the inspector’s CSP stays
style-src 'self'). New fragments:/inspector/fragments/charts/{overview,issue-patterns,runs}.
Inspector: Blop App v20 dark theme
Section titled “Inspector: Blop App v20 dark theme”- The inspector now matches the Blop App v20 design (
docs/inspector-source/): graphite surfaces (#161616page,#141414panels),#edededtext, one blue accent for the current item, selection, focus and chart data, and status colours for meaning only. Dark only (color-scheme: dark). - Inter for the interface and Geist Mono for code, both self-hosted from the
collector (
/inspector-fonts/inter-latin.woff2,inter-latin-ext.woff2); no CDN.scripts/vendor-geist.mjsnow vendors Inter as well. - The rail, nav items, buttons and fields take v20’s proportions: 34px nav rows
with 8px corners, the current page tinted blue, filled buttons in
#2563ebso white labels hold 4.5:1, and smaller page titles (24px). --pass,--warnand--idle, which Memory and Settings read but the theme never defined, are now defined, and their light fallbacks are gone.- A contrast test holds every text token at 4.5:1 and every status colour at 3:1 on each surface.
Inspector: memory traversal, provenance and session associations
Section titled “Inspector: memory traversal, provenance and session associations”- Traverse one, two or three hops with explicit
hopsandcursorURL fields, 200 nodes per page, previous/next navigation, and exact omitted-node/edge counts. Draw only stored edges whose endpoints belong to the selected scope and page. - Cite each drawn edge in its SVG title and readable relation list using the
stored
memory_edgesprimary-key tuple(from, type, to); no standalone edge ID exists. The drawing retains its 160-edge cap and reports omitted edges. - Resolve collector provenance once at startup:
blop up --project <id>andblop monitor start --project <id>overrideBLOP_PROJECT_ID. Show the git origin and repository root without inventing a mapping to authored project IDs; unresolved identity remains labelled unresolved with all-local scope. Project selection, including an explicit all-local selection, overrides the default. Refuse reuse when a requested project differs from the running collector. - Omit git origins that cannot be parsed rather than exposing raw credentials in collector health or inspector provenance.
- Preserve the running collector’s startup project during automatic version upgrades, including all-local scope, instead of inheriting the invoking command’s environment. Keep an explicit restart project authoritative; leave collectors running with a version warning when their scope or identity cannot be verified safely.
- Show separate curated-memory/recorded-evidence session and trace associations from exact saved source identities, reusing local accessibility resolution. Associations neither merge records nor prove session use or causality; the evidence graph has no incoming memory-reference relation.
Memory: shared libSQL and PostgreSQL vector backends
Section titled “Memory: shared libSQL and PostgreSQL vector backends”- Export a SQL-free
VectorBackendcontract with structured scopes, revisioned writes, cosine rows, indexing coverage and bounded cursor pagination. - Preserve local DiskANN/exact scoped retrieval, native warning strings and synchronous write-transaction isolation; keep vector SQL in backend modules for the memory store and runtime-evidence adapter.
- Add an optional dynamically loaded
pgadapter with pgvectorvector(384), HNSW/IVFFlat cosine indexing, scope-before-ranking and pinned model guards. No driver dependency or hosted graph migration is imposed on local users. - Exercise identical backend assertions against temporary libSQL and real PostgreSQL, with explicit skips when no PostgreSQL URL is configured.
- Leave inspector views unchanged under their ownership restriction; their
legacy vector SQL/interface migration remains blocked on permission to edit
those modules. Backend guarantees and boundary:
docs/vector-backends.md.
Inspector: Settings command actions, deep links and truthful states
Section titled “Inspector: Settings command actions, deep links and truthful states”- Give overview commands native keyboard-accessible Copy controls through the shared page-action handler, with polite success/failure announcements and visible commands when scripting is unavailable. Redacted API-key values have no copy control; configured MCP argv is never exposed as arbitrary copy text.
- Serve sticky section navigation and native
?view=settings#connected,#agents,#memory,#evidenceand#askanchors before scripts run. Preserve namespaced overview IDs and anchors across capture-policy swaps; restore detailed-section fragments after asynchronous rendering and preserve the selected project when following section links. - Distinguish missing evidence from unreadable stores and present memory from an unbuilt semantic index. Scope capture freshness to the explicitly selected project’s identity-resolved hooks, not binary detection or another project’s activity. Read at most the newest 1,000 collector observations within seven days through the timestamp index before parsing metadata; label missing sampled capture and excluded older activity explicitly. Unavailable metadata and unselected projects stay unknown.
- Preserve validated credential-free collector URL/port pins in stale MCP repair commands; withhold unsafe or ambiguous pinned repairs.
Inspector: read-only, scope-truthful Memory view
Section titled “Inspector: read-only, scope-truthful Memory view”- Enforce native read-only graph and evidence handles with SQLite URI
mode=ro; semantic reads preserve schema and vectors from obsolete models. - Compute semantic coverage from active, index-eligible nodes in the selected project and current model/revision, without letting retired or foreign nodes block recall. Apply kind/status filters before the 100-hit semantic bound.
- Keep meaning controls and canonical detail/revision/semantic URLs synchronized across fragments. List reads return metadata only, bounded to 200 rows.
- Omit unreadable node records with scoped corruption counts. Resolve exact evidence identities locally; missing or unreadable evidence never inherits a saved positive accessibility label or an unconfirmed link.
- Measure omitted relations, revisions, graph nodes and graph edges separately. Show immutable addressed content, source/relation provenance, revision actors, and revision-pinned CLI commands with Unicode body-section continuation.
Universal agent hooks: selectable global or project capture
Section titled “Universal agent hooks: selectable global or project capture”- Extend native global/project hooks to all 11 registered adapters: Claude Code,
OMP, Pi, OpenCode, Hermes, Gemini CLI, Codex, Goose, Amp, Cursor CLI and Crush.
Setup, install-hooks, status, doctor, capture-policy, run and env use selectable
scopes. Without
--project, scope defaults to global;--project <local-id>implies project scope. Explicit project requires a project; global rejects one. - Use public native hook/plugin contracts without exact host-version allowlists. Agent info/list JSON exposes native, global and version-independent hook capabilities with refusal reasons. Unknown or incompatible callback formats still fail closed; implemented does not mean every release/platform is certified.
- Capture global callbacks under one explicit global source/project label. Exact-physical-cwd project-native installations take precedence even when disabled; matching drift fails closed without global fallback. Preserve collector identity, bounded/redacted local delivery, outbox and policy controls, including existing metadata-only reductions and exclusions. New bindings default to full supported exposed content with 30-day body retention, never hidden thinking or attachment bytes.
- Keep observer integrations non-intercepting: Cursor/Amp omit pre-tool and permission interception; Goose’s PreToolUseResult observer cannot change approvals; Crush exposes top-level PreToolUse only. Unexposed callback content remains unavailable rather than being reconstructed from private history.
- Preserve foreign host settings/plugins and preview/apply, atomic writes and hash-drift-safe removal. Native-only launchers have no fabricated artifacts or fallback: run requires real native installation. Version-2 receipts explicitly mark each file’s host-config role; version-1 receipts remain safely removable. Adapter seams accept config-path/context information for multi-file native formats. Idempotent apply correctly reports no changes.
- Resolve
builtinAdaptersthrough lazy getters to break the real shared-renderer/ registry import cycle, while retaining extensible registry lookup. - Observed gates: package build passed; a plain OMP launch delivered 14 global
events including real tool/reply activity. Pi delivered 9 lifecycle/auth-failure
events and OpenCode delivered 5 prompt/context/model-error events before
provider 401 failures. Gemini delivered no callbacks because auth/client and
workspace-trust gates blocked it. Codex’s model run succeeded but its hook
source/session query returned no events; native
/hookstrust review remains required, with no trust bypass written. Hermes, Goose, Amp, Cursor and Crush were unavailable locally; source-grounded callback/bridge fixtures are not live host/model delivery. No aggregate test-count or blanket certification is claimed. - Retain prior Claude Code 2.1.310 evidence: six main-cycle callbacks from global and bound-project launches without competing-scope duplicates, with prompt, public reply and tool input/output. Subagents, compaction and errors were not exercised; this does not qualify the separate native-plugin mechanism.
Inspector integration: durable metric-only sessions
Section titled “Inspector integration: durable metric-only sessions”- Keep metric-only sessions marked Unknown in server-rendered htmx rows as well as client-rendered rows. Their exact source/session links expose recorded metric totals separately from spans; marking a row wrong cannot fabricate a trace-backed issue.
- Retention preserves both metric pruning and consent-bound log/native-span body expiry.
- Forward request headers to the capture child before body bytes arrive, so route-specific upload limits return 413 immediately instead of a transport timeout when an oversized client sends only its declared Content-Length.
Inspector: chart ranges and reachable empty states
Section titled “Inspector: chart ranges and reachable empty states”- Home’s span-rate, error-rate and p95 charts follow one URL-backed range
selector, including reload and Back/Forward. Home and Issues chart fragments
accept the shared presets from 5m through 30d and
all(retained data, up to 30 days), while preserving explicitfrom/towindows. - Home and Issues leave an absent range implicit: Home defaults to the last 24 hours on both the page and chart fragment; Issues defaults to all retained data (up to 30 days). Neither rewrites the URL or borrows a remembered selection. Explicit changes push history; Back restores the parameter-less default window. Sessions and Logs likewise add no default range on mount.
- Empty Home windows identify older retained spans and offer a one-click 30-day range. Empty retained ranges, expired buckets and capped samples remain separate states.
- Issue sparklines aggregate occurrences over the same selected window as their list, rather than silently showing a fixed 24 hours. Charts retain bounded grids, conditional ETag refresh and activity-driven htmx updates; Sessions and Logs retain their existing explicit range-change behavior.
Inspector: a Resource view in the step detail
Section titled “Inspector: a Resource view in the step detail”- The selected step’s span data is a visible Attributes / Events / Resource
tablist instead of a collapsed “Advanced span attributes” block. The view is
in the URL (
panel=events|resource), so a reload returns to it and Back/Forward step through view changes. - Resource groups the span’s resource by OpenTelemetry namespace (Service, Telemetry SDK, Process, Host, Container, Deployment, Cloud, Other), with counts, mono values, a copy control per row and “Copy all as JSON” of the bounded set the collector returned. A search filters the loaded set client-side (“Showing N of M”); it never reads again or changes the URL.
- It tells the absences apart: an exporter that sent no resource, a span that
is no longer retained, and a metadata-only agent hook source whose resource
is only Blop’s source stamp.
/api/inspector/spanaddsresourceTotalandresourceSource; the 60-entry and 2,000-character caps are unchanged. - Closing the shortcuts sheet no longer takes focus back from a field focused
before its queued close event, which could send
g ityped there to Issues.
Inspector: reactive lists and a light, denser look
Section titled “Inspector: reactive lists and a light, denser look”- Add a small dependency-free reactive layer (
/inspector-reactive.js): a state cell, a resource controller with scope generations, one live-feed owner per document, keyed DOM patching and disposable mounts. Sessions, Logs, Runs and the Settings capture-policy editor use it. A filter change aborts older reads, so a slower reply for the previous scope never paints; a failed new scope drops old rows instead of showing them as matches; kept rows keep their node, focus and scroll position across live refreshes. - Logs refresh live behind the shared Pause / “N new” control and offer Maple’s time-range presets inside the 24-hour log bound (5m, 15m, 30m, 1h, 6h, 12h, 24h; 7d and 30d are listed as unavailable). The log sheet is a right-hand drawer.
- The capture-policy editor keeps draft, accepted policy and write outcome apart: a 409 or an unacknowledged save locks saving until “Read accepted policy” reads the current revision; repeated submits write once.
- The inspector now uses light surfaces with hairline borders, tabular numbers and dot-and-word indicators; every colour is a theme token.
Hook adapter package
Section titled “Hook adapter package”- Move hook implementations into
src/hooks/: a singleHookAdapterregistry owns host formats and launch conventions; shared engines retain binding, outbox, install/rollback and capture behavior. Existing module exports remain intact. Add a public adapter-authoring guide with the folder-plus-registry rule and verified-host acceptance loop.
Persistent native hook installation
Section titled “Persistent native hook installation”- Add
blop agents install-hooks <id> --project <local-id>for persistent OMP user plugins and Claude Code user-settings command hooks. Preview exact diffs by default;--applywrites atomically and--remove --applyrestores hash-checked pre-install bytes. Preserve foreign config and refuse later drift. - Native hooks resolve exact project bindings/policies on disk without launcher
environment, reject stale collector instances before enqueue, and report
native configuration separately from delivery in
agents status. Project launch remains optional and does not register duplicate hooks. OpenCode and Codex native installers remain deliberately deferred pending verified contracts.
Default local content capture
Section titled “Default local content capture”- Local agent content capture is on by default for a newly enabled project
binding: native harness spans now honour the binding’s consent, so prompts,
public replies and tool input/output/errors are retained locally, bounded and
redacted.
blop agents envexports OMP’s verifiedOTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENTvalue per mode. - The inspector shows its “content not included” notice only when a step genuinely has no retained content.
Retention and capture policy settings
Section titled “Retention and capture policy settings”- Body and metadata retention default to 720 hours (30 days). Per-binding body
retention uses
blop agents capture-policy set --retention-hours(1–720); store retention usesBLOP_MONITOR_RETENTION_HOURSafter collector restart. Expired bodies become tombstones, and the replay horizon follows maximum retention. - Settings now edits each existing harness/project binding’s mode, body retention and class exclusions through the CLI’s shared atomic policy writer. Accepted values and revisions update only on success; invalid values, stale revisions and server errors cannot appear as saved. Changes apply to future events and pending delivery, not retained history. Store retention remains explicitly restart-only, not hot-reloadable.
Unreleased (CLI UX overhaul, branch feat/blop-cli-v01)
Section titled “Unreleased (CLI UX overhaul, branch feat/blop-cli-v01)”The JSON contract is blop.cli/v1. Its JSON Schemas ship in this package under schema/ and print with blop schema. Within v1, fields are only added. Most changes below touch output that 1.7.0 did not have yet (it always emitted warnings: [], and run, tail, workers and setup had no envelope), so the practical break for 1.7.0 users is small. Each change is listed so scripts can be checked.
Project-bound native harness content
Section titled “Project-bound native harness content”- Reuse the local hook binding as native span content consent. New bindings default to full/720-hour bodies; absent, mismatched, disabled and narrower bindings remain metadata-only on the native path.
- OMP project
agents envandagents runselect its documented full/summary/none emission mode and export the exact source/installation/project/adapter identity. No new content variables are added to other adapters. - Keep credential redaction and the existing attribute/event byte limits. Native public message structures exclude hidden reasoning, environment dumps and attachment/file fields. Native body expiry removes projection/index/raw copies without changing metadata retention; readers refuse expired bodies.
- Show bounded native content in session/trace step details. Agent-context summaries distinguish retained content from launcher/metadata-only steps; captured text remains inert and is not expanded into the copied summary.
Bounded failure context (#463)
Section titled “Bounded failure context (#463)”- Add
blop failure-context --source KEY --trace ID --since 15m --jsonandGET /api/failure-context, using one source-scoped read snapshot and theblop.failure-context/v1data schema (blop schema failure-context). - Return observed span/log symptoms, deterministic ranks with reasons, exact source/collector/trace/span/log identities, missing parents, capture coverage and pinned exact drill-down queries. Service/session/recorded-attempt selectors intersect; source/owner identity prevents reused-ID leakage.
- Enforce server-side window/row/byte caps and a terminating worker deadline, with two readers maximum. Preserve disabled history, empty/truncated/unknown sources, unavailable stores and stale-revision conflicts as distinct states.
- Keep reads metadata-only, with unknown verification and no inferred agent
links, model diagnosis, hosted-run join, MCP change or new raw store.
Offline
--dbnever starts or contacts a collector. - Qualify real Node
/ok,/fail, unrelated failure and recovery exports through built CLI, curl and genericopenapi-client-axios7.9.1 drill-down. Extend the local-monitoring skill and OpenAPI only for this contract.
Unified evidence-launched browser checks (#490)
Section titled “Unified evidence-launched browser checks (#490)”- Add
blop test init|add|list|run|watchandblop flows(includingls). Keep legacy top-level/spec aliases and the olderflowgroup;run -- <cmd>remains the observability wrapper. - Resolve
flows run --from trace <id>|--from finding <code>read-only from local evidence, with bounded windows/rows/bytes. Missing, stale or over-cap evidence exits 2 before spec loading. Recorded context never chooses a target. - P00 qualification (2026-10-24, Linux x64, Node 22.23.3): clean packed consumers use public SDK revision
691292c78cf737ec6863abd1c65750f61ba31e04, not a workspace patch; real Chromium trace/finding launches exported SDK-ownedblop.evidence.*attributes matching JSON, while plain runs stayed unstamped. Provenance is not causality or independent verification; this is not release/platform certification. - Divergence from older CLI plans:
testis now the browser-check group, not a future issue-to-generated-test command.addscaffolds a reviewed spec only.
Read-only setup doctor (#492)
Section titled “Read-only setup doctor (#492)”- Add
blop setup doctor [--json]for the whole local loop. Onedata.checksarray reports pass/fail/not-applicable, reasons and exact remediation commands. No auto-repair; exit 0 with no failures, otherwise 1. - Check collector/status health, local store permissions/retention/retained amount, pinned Chromium, harness/SDK resolution, Node >=22, agent recipes, Git and binding. Never write telemetry/config/state, launch agents/browsers, start a collector or contact external hosts. Keep stale registry records untouched.
- Identical facts serialize identically: the envelope’s
generated_atuses an explicit fixed epoch sentinel, not an audit timestamp. Publishsetup-doctorschema and teach help/quickstarts/the local-monitoring skill to audit first. - Keep
blop doctorunchanged: it remains an active OTLP round-trip diagnostic. SDK semver is checked, not Git revision integrity; unrecognized recipe shapes remain failures, not inferred success. Non-loopback acknowledgement never enables external probes. - Keep SDK execution off CLI bootstrap so a missing SDK is a doctor finding, not an import-time crash. Browser flag values are checked exhaustively against the SDK public type. Hook checks inspect supported event entries, not arbitrary strings/comments; per-signal destinations/protocols override generic settings.
Bounded local evidence reports
Section titled “Bounded local evidence reports”- Add
blop report --since 2h --format markdown|junit|json, with exact service, session, or stored-finding scopes. Read one local query-only snapshot; never discover/start a collector, run analysis, contact the network, or upload. - Include the source database/revision, explicit half-open window, bounded service/error/log summaries, stored findings, SDK flow outcomes, exact evidence IDs and copyable reproduction/drill-down commands. Keep unknown/unverified/ verified receipt state separate from execution outcome.
- Bound source rows, metadata fields and rendered UTF-8 bytes with explicit truncation. JUnit retains unknown evidence as skipped, not successful checks, and is exercised through the ingest parser.
- Add
--untilfor byte-identical rendering of an unchanged evidence snapshot; report JSON uses the pinned window end asgenerated_at. Publish the report data schema throughblop schema report. Sharing remains a separate decision.
Scoped rich hook capture (unreleased working implementation)
Section titled “Scoped rich hook capture (unreleased working implementation)”- Add strict
blop.agent.hook/v3without widening retained v1/v2. Explicit project setup defaults to full supported public content after notice; preserve existing reductions. Conversation-only, metadata-only and class exclusions filter before producer IPC and again before collector persistence. - Add owned
agents setup/run --projectartifacts for OMP18.11.3 and Claude Code2.1.300, safe removal andcapture-policy show/set. Refuse binary/version, collector-binding, symlink and artifact drift. Do not edit OMP settings or silently restart a collector. Configuration is not callback/delivery proof. - Capture public prompt/assistant/tool input/output/error fields through the shared durable outbox and exact receipt path. Store bodies once, reference them from metadata, retain the original expiry clock and remove expired content indexes. Queued restrictions produce auditable replacement identities.
- Enforce body expiry in exact/token/phrase searches before the physical retention sweep, including indexed coverage. Distinguish malformed body errors, a missing retained copy and known expiry without failing the whole observation page. Bound physical body/index cleanup while retaining observation metadata.
- Open coding-agent sessions on their recorded conversation unless a tab or step link was selected. Preserve public-message availability reasons and show unknown duration rather than inventing a running state. Detail identity now uses the shared resolved activity identity, not a service-name fallback.
- Scoped
agents status --projectchecks owned artifacts, binary/version and selected collector identity without repair or restart. Show each class’s policy permission separately from unverified live acceptance. Preserve bounded run/git metadata when suppressing unconsented native harness bodies. - Policy changes preserve exclusions unless an explicit replacement or
--clear-exclusionsis requested. Add scoped enable/disable and original-time retention updates without requiring a mode change. Use canonical strict flag parsing with repeated exclusions and last-value precedence for scalar flags. - Bind observation pagination to its exact source/session, evidence revision and earliest retained-body expiry. Changed/expired snapshots return409 and offer an explicit first-page refresh instead of mixing versions or retrying a stale cursor. Historical cursor layouts are rejected rather than silently upgraded.
- Keep literal OMP identity independent from historical
opencodeservice naming. Retain exact same-call and recorded-membership graph associations separately from recorded causal parents. Show actual bodies and explicit tool outcomes in the existing bounded inspector. - Claude uses observer-only in-process native mods with the shared sanitizer, no transcript scraping. Serialize awaited bridge writes across concurrent callbacks; retain fixed content-free failure diagnostics. Organization policy can withhold system/compaction callbacks, and is never bypassed.
- Extend the same OpenCode plugin and JSONC editor for scoped2.0.21 setup/run/ removal. Own a directory reference, preserve other config entries/comments, and retain the config document on undo. Pin actual and logical launch cwd. Shared selection excludes history/provider state; retain public system text and exposed compaction summary only. Native event replay uses a stable source-scoped wire identity and the original native clock.
- Classify an exposed nonzero shell exit as failure even when the SDK says execution completed. Correlation failure diagnostics no longer echo exception messages. Fixture behavior and actual one-prompt inspector readback passed; OpenCode’s full model/tool/lifecycle cycle is not qualified, nor is V1.
- Main-cycle live receipts cover OMP/Sol and Claude’s configured default model. Other-host, subagent/compaction/fallback, capacity and publication gates remain separate; no all-host or full-plan certification is implied.
Metadata-only hook lifecycle evidence
Section titled “Metadata-only hook lifecycle evidence”- Emit strict
blop.agent.hook/v2metadata on the existing subprocess → OTLP → local observation path. Mint a UUID before first delivery; isolate source, installation, adapter, session and call identities. Retain each callback as an immutable event observation, with a scoped call key rather than overwriting terminal facts. Retained v1 stays readable without v2 receipt claims. - Keep Stop/agent_end as turn completion, actual shutdown as session end, and compaction phases distinct. Preserve unknown outcome, missing/conflicting aliases, expired/missing starts and measured-zero duration explicitly.
- Sanitize before local bookkeeping/send and again before evidence persistence; omit payload content, paths, claimed machine/worker authority and raw diagnostics. Reuse existing source-filtered observation/graph queries; no inferred causal parents, authored memory, publication or new graph authority.
- Replace pairing-only files with bounded, private
hook-outbox.sqlite: pair and enqueue sanitized metadata in one durable transaction before network delivery. Add exact committed/replayed event-ID/hash/revision receipts in the evidence writer transaction, all-or-nothing hash conflicts and bounded replay after offline restart, sender/drainer crashes or lost responses. - Enforce count/byte/age/disk/batch bounds, one drain lease and collector-owned timer, credential-revision auth pause, opt-out for capture and replay, explicit expiry/refusal/quarantine losses and safe CLI queue/receipt status. Process exit or ordinary HTTP 200 is not delivery; capture completeness remains unknown.
- Preserve exact receipts through the existing authenticated TLS receiver. Meter actual rollback-journal footprint, including expiry and counter transactions; avoid dirtying the outbox on empty collector polls.
- Print explicit OMP/Pi metadata extensions with
agents hook-config; add Pi registry metadata. Reuse the common bridge/outbox, suppress foreign locations and disabled capture, and leave tools to configured native telemetry. - Bound synchronous bridge calls to avoid OMP’s detached turn-end/shutdown race. Qualify OMP18.11.3 real read/edit, success/failure, shutdown, opt-out and offline replay, native-overlap tool ownership and abrupt-exit unknowns; Codex/Pi model/auth blockers and untested compaction remain explicit. H3 stays partial; H4 associations and full H5 are not implied.
Local authored scores and human review
Section titled “Local authored scores and human review”- Add
blop evaluation grant|revoke|calland the existing collector owner’s/api/observations/evaluation/*HTTP actions. Local grants bind one source, principal and permission set, expire within 24 hours, are checked fresh and keep bearer credentials in private files and trusted backends, not browsers. - Store typed numeric/categorical/boolean/text/correction scores, immutable config revisions, per-score comments/history and grant-bound mutation audit separately from recorded evidence. Enforce scoped config/subject checks, explicit expected revisions and canonical idempotent replay. Corrections preserve original output.
- Add revision-safe annotation queues, eligible human assignments, atomic claims, required-score completion, bounded next/list and per-member bulk outcomes. Retain author/reviewer/evaluator provenance and immutable source references after source removal; absence does not invent an expiry/deletion cause.
- Keep P3 partial: collaborative comment threads/anchors, mentions/reactions/ preferences, hosted operation contributions and selected-result memory curation remain unimplemented. No hosted review UI, local MCP writes, telemetry upload or complete P3/release claim.
Observation contracts
Section titled “Observation contracts”- Export browser-safe
@blopai/cli/monitoring/contractsfor exact local/hosted source-scoped subjects, worker-attempt references, provenance, content-state and byte-bounded query/cursor validation. Parsing never grants source access or enables content capture, publication or evaluator execution. - Keep opaque Unicode session IDs distinct from imported coding sessions and service-scoped agent conversations. Reject control characters, malformed Unicode, ambiguous identity and foreign source/machine bindings.
General application sessions
Section titled “General application sessions”- Normalize ten observation types, source-scoped opaque conversation IDs, requested/observed models, environment/release/version, user/tags and bounded typed metadata in the ingestion transaction. Preserve unknown and conflicting dimensions; historical spans require explicit replay to acquire projections.
- Add source-preserving application session list/detail, role-labeled replay, parallel tool association, sparse durable bookmarks and bounded continuation. Keep coding-agent, hook, worker, run and request investigation paths distinct.
- Add explicit
--capture-gen-ai-contentconsent independently of legacy custom attribute capture. Persist new application payloads only in local normalized observations; omit them from legacy raw span/search and hosted structural proxies. Default capture, hook payloads and unclassified status text remain metadata-only. Report ingestion metadata clipping separately from previews. - Bound replay pages to 50 observations/256 KiB, field previews to 4,000 UTF-8 bytes and explicit single-observation full reads to a separate 1 MiB ceiling. Enforce exact source/service/session/trace/span ownership on those reads.
- Bound pending HTTP intake and writer requests to eight with visible overload rejection. Cap hook delivery at one second and keep partial tool duration unknown rather than assigning a measured zero.
- Add runnable standard OTel TypeScript/Python session recipes with async/manual context, parallel tools, W3C client/server extraction, masking and flush/shutdown. Actual isolated runs verified three traces/15 spans per language and capture mode; these controlled producers are not external-agent/provider certification.
- Keep session bookmark/source controls and bounded-content guidance inside the viewport at tablet widths as well as on phones; wrap the action group instead of clipping controls or hiding provenance.
- Read application-session model fields in the bounded observation scan without a second projection lookup per observation; preserve snapshot and source scoping.
- Make capacity investigations reproducible with a separate 10k reduced fixture, raw proc mappings and database inode identities, and per-isolate V8 heap-space statistics. Reduced runs cannot pass full-envelope gates. The round-4 summary index candidate failed full-envelope latency targets and was withdrawn; native allocator retention and the unchanged query/RSS capacity gates remain open.
- Record the round-5 allocator/transactional-summary experiment: exact summary compatibility and reduced query/ingestion improvements, but 344.164/346.383 MiB natural-idle peaks failed the prerequisite for a full run. Both candidates were withdrawn at that checkpoint; no allocator policy or native addon ships. The separate round-6 capture-process qualification is recorded below.
Out-of-process local capture
Section titled “Out-of-process local capture”- Keep the OTLP/query HTTP listener in a database-free parent; normalize, persist,
retain and query the same local store in a listener-free capture child. Preserve
JSON/protobuf/gzip, source/consent boundaries, parent collector identity, SSE and
blop.cli/v1across bounded, backpressured fork IPC. - Fail child outages honestly with
capture_unavailablefor intake/writes andquery_unavailablefor reads. Never replay an interrupted mutation. Bound automatic recovery to two restarts and terminate the child with the collector. - Record parent and child RSS separately. The sanctioned parent RSS gate does not mean total capture memory disappeared; unchanged targets and retention remain authoritative in the capacity plan.
- Record round 6’s full 100k envelope: ingestion/query p95 pass at 356.756/164.489ms, but parent natural loaded-idle peak 151.023 MiB fails strict <150 MiB. Disclose capture child peak 358.516 MiB; retain the architecture and stop without a rerun, waiver, IPC tuning or summary-rollup reapplication.
- Reuse a parent-owned, bounded HTTP forwarding connection pool instead of constructing and closing a virtual socket for every request. Keep the 128 connection ceiling, 64 KiB frames, backpressure, deadlines and no-replay outage behavior unchanged; destroy the pool when the parent stops.
- Close the parent capacity gate in round 7’s single authorized full rerun: natural loaded-idle peak 141.887 MiB, ingestion/query p95 313.222/141.847ms, all three capacity gates PASS. Disclose separate capture child peak 327.324 MiB and parent overall peak 151.547 MiB. At that checkpoint, summary qualification was blocked by missing archives; round 8 resolves it below.
- Maintain exact writer-owned application-session summaries with intake, retention and lost-launcher updates. Read at most 201 indexed aggregate rows globally; preserve the 3,000-observation fold, ties, model/source precedence, partial flags and independent earliest-window detail/replay behavior. Historical WAL snapshots remain read-only and retain their original pre-migration view.
- Rebuild the rollup from the recorded design after temporary source loss and qualify it with fresh all-3,001-row differential proof and one full 100k A+B run: ingestion/query p95 399.192/92.089ms, parent natural loaded-idle peak 138.523 MiB, all three capacity gates and 15 correctness probes PASS. Disclose separate child sampled peak 354.367 MiB and the higher full ingestion tail versus round 7; this is not a total-machine memory or release claim.
Observation investigation
Section titled “Observation investigation”- Add source-bound typed filters, exact bounded facets and token/phrase/full-field content search over already masked, consented observations. API, inspector URL, saved views and JSON page export use the same validated query interpretation; missing, null and empty values remain distinct. Historical, truncated and unsupported metadata/index coverage is explicit; reads never backfill content.
- Persist mutually exclusive usage buckets and immutable exact-decimal cost receipts. Recorded cost, including zero, takes precedence; invalid or missing usage/currency is unavailable, not zero. Append source/model price revisions with effective dates and input-token tiers without repricing earlier receipts.
- Add scoped application-end-user summaries and expanded/grouped execution graphs with exact recorded-parent edges, repeated-call identity, cycle/missing- parent disclosures, bounded responses and an accessible evidence list.
- Add a Sessions → Observations inspector view and a workspace-admitted, read-only hosted telemetry view. Price and saved-view writes stay same-origin local operations; these additions do not enable remote localhost access, publication, arbitrary SQL, tokenization/model downloads or provider calls.
- Adapt selected non-enterprise Langfuse T04/T05 behavioral cases with per-case provenance and controlled-fault receipts. This is not full upstream parity or a performance/release certification; P1 capacity gates remain open.
Shared authored graph core
Section titled “Shared authored graph core”- Export
@blopai/cli/graph: shared native libSQL access, the existing pinned local embedding model and vector ranking, plus revisioned authored memory with source/proposer/approver attribution. Keep the monitoring evidence adapter and its wire schemas separate. - Apply identity/project grants before retrieval, counts and ranking. Preserve explicit rule lookup, conflicts and approved supersession independently of semantic similarity; similarity creates no evidence edges.
- Require exact target/policy revisions and action-bound approval for consequential knowledge changes. Reject ambiguous patches and brief overflow atomically; retain revision history, explicit retire/restore and content-free purge receipts.
- Persist applied graph writes and explicit index receipts in the same transaction as revisions/vectors. Exact index replay and restart recovery do not invoke the model again. Exercise native checkpointed
VACUUM INTObackup/restore for content, history, vectors and action receipts; the driver’s declaredbackup()/serialize()APIs are unimplemented.
Plugin management integration
Section titled “Plugin management integration”- Reject chat continuation through another member’s conversation or thread ID before saving messages or granting tools. Reject an explicit inaccessible project instead of silently anchoring the chat elsewhere. A disposable Postgres smoke reproduced the prior foreign-thread resolution and confirmed the ownership rejection.
- Keep existing mixed-case operation IDs stable while deriving bounded, collision-checked MCP labels. Authorize native run, evidence and historical artifact reads through the same management descriptors without changing their browser query normalization.
- Freeze run targets, refs and scenario selections before launch; atomically claim queued runs once and distinguish cancellation requests from observed executor/provider outcomes. Exercise concurrent claims and native HTTP reads against isolated PostgreSQL.
- Keep reviewed bulk deletion and its completion receipt in one transaction. A failed receipt rolls back child cascades; projects created after the reviewed ALL snapshot remain untouched.
- Make local authored memory available without an account or collector: exact add/patch/history through
blop memory, with stale-revision rejection. The official MCP client can retrieve that same local revision through the eleven-tool read-only stdio catalog while the collector is offline. - Preserve the browser fetch receiver in the shared management client; requester-bound handoff navigation now reaches the authenticated security page in Chromium instead of failing with an illegal invocation. Keep an empty MCP tool catalog usable after every permitted app is disabled, without advertising disabled operations.
- Add delegated device login, protected local profiles, live cloud operation discovery/calls and explicit reviewed-hash publication. Logout revokes the grant before deleting local credentials. Keep payload
--inputindependent of the global--no-inputcontrol. - Load local and hosted memory/procedure sections with
--fieldand Unicode continuation bounds. Bind local proposals to their retained idempotency key; freshness filters apply before authorized search ranking and pagination. - Move active web knowledge and learned procedures into per-workspace graphs through verified, resumable migration; retain legacy Postgres rows only as inert migration data. Resolve run sources against current workspace/project/attempt/artifact ownership and retention.
- Freeze only the small task-consumed memory brief under fresh conversation/grant bindings, outside privileged prompt instructions. Live policy still gates every write; revocation and membership changes invalidate access to the frozen snapshot.
- Expose one shared memory editor with revision-addressed receipts, historical comparison, explicit relationship direction and reviewed per-file document extraction. Keep tall/phone panels scrollable and restore keyboard focus after closing.
- Reject streamed oversized HTTP requests promptly without waiting for both branches of a cloned request body to cancel. Restore a matched native graph/Postgres backup and recover an interrupted completion from its applied graph action without replaying a later revision.
- Bound local CLI/MCP and hosted/web memory reads by bytes as well as row counts: share metadata and Unicode-safe preview pages with lossless hit/edge/revision cursors, metadata-only skill lists and explicitly selected Unicode procedure sections. Preserve complete edge identities even when JSON escaping requires omitting previews. Count addressed metadata omissions and make complete metadata progressively retrievable with a snapshot hash; the editor reconstructs it before changing content, preserving hidden references. Report neighborhood source omissions with
sourceCount/sourcesTruncated; preserve complete core graph-store contracts. Local MCP exposes four collector evidence tools plus seven offline memory reads without account, collector or model initialization. Return compact commit/proposal manifests with explicit omissions so successful large writes are not misreported as unknown oversized responses. - Parse only the registry’s exact declared negative spellings across Node versions;
--no-inputcannot be interpreted as negating the string-valued payload--input.
Local inspector design
Section titled “Local inspector design”- Give Home an issue-first layout, with active agents and recent sessions in a quieter supporting column; stack the same content on smaller screens.
- Refine the dark neutral palette, type hierarchy, navigation, filter boundaries, button states and spacing. Keep fonts self-hosted and status labels explicit.
- Remove status-dot halos, pulsing loading placeholders and repeating onboarding motion. Empty issue queues link to recorded runs instead of repeating setup commands, and explicitly avoid implying that every flow was verified.
- Redesign Sessions, scoped and recent logs, worker evidence, issue detail, run review, Connect, Settings, search and optional Ask around observe → investigate → verify. Make Logs and Workers discoverable from Sessions and keep advanced metadata behind disclosures.
- Show the copied fix-context occurrence beside the handoff action, preserve exact session/worker evidence in agent briefs, and retain source receipts when copying an Ask answer. Distinguish command success, recorded checks and AI interpretation from independent verification.
- Separate collector/agent/app/correlation readiness on Home and Connect. Explain bounded search, effective read-only settings, capture consent and configured-provider traffic without claiming complete evidence or zero network activity.
Active coding agents
Section titled “Active coding agents”- Record agent-launch process start and exit before the agent’s SDK flushes. Home lists observed active agents; Sessions links and filters use the same lifecycle evidence. Nested launches keep their enclosing run open, and lost local launchers stop reading as active after the collector’s sweep.
- Recognize OMP’s native instrumentation scope even with a custom service name, instead of counting its model/tool activity as application requests.
- Refresh Home on streamed activity, recover with polling while disconnected, and use the observed start time for unfinished spans instead of showing a 1970 timestamp.
- Include the required
protocol = "binary"in Codex OTLP configuration recipes. - Keep native conversation details consistent with the Sessions list: agent identity, recorded model, run and git stamp survive the drill-down, including custom-named OMP services.
- Exclude Codex’s anonymous auth/runtime traces from coding-session counts and read its native
modelattribute. A model turn remains visible without inventing conversation links. - Keep agent prompt arguments out of launcher command metadata unless content capture is explicitly enabled; lifecycle observation still records start, exit and run correlation.
- Explain missing application spans without claiming that agent telemetry is absent, and keep Home’s relative timestamps advancing without new telemetry.
Worker lifecycle and cancellation evidence
Section titled “Worker lifecycle and cancellation evidence”- Expose exact lifecycle/model evidence IDs and unknown source coverage/dropped records in mounted worker details. Verify authenticated receiver, CLI, API and inspector agreement without confusing stale connectivity, zero exit codes or unfinished spans with verified task success.
- Mount the shared escaped cancellation renderer in exact worker details: distinguish source-reported exit from digest-bound independent observer evidence, retain execution/child/transport coverage and post-request activity, and expose no worker controls.
- Add optional
startMonitoringServercaller-suppliedcancellationEvidence: {events, policy}. Copy the authenticated upstream snapshot at startup; raw OTLP/HTTP payloads still cannot grant observer authority. Ordinary daemon behavior remains default-deny and does not install an observer or add a transport. - Export
cancellationEventDigestandcancellationCssfrom the monitoring API. Embeddings must load the CSS separately; the fragment no longer emits inline styles, preserving the inspector’s same-origin CSP and theme.
Pi MCP client
Section titled “Pi MCP client”- Add Pi to the inspector’s Coding agent (MCP) tabs and
blop setup mcp pi. Setup preserves existing servers and supports project.mcp.jsonand user~/.config/mcp/mcp.json, with handshake verification and scoped removal. - Pi needs
pi-mcp-adapter; the Connect instructions include installation and reload steps. OMP reads the project configuration natively without that adapter.
Main-branch integration
Section titled “Main-branch integration”- Keep authenticated trace ownership, source capture consent, OpenCode model/version compatibility and interruption cleanup alongside the CLI UX changes.
- Route multi-agent setup, hook/launch, source/filelog commands and graph index/search through the command registry. Agent setup uses the shared persistent collector policy; an explicit port wins over an environment URL.
- All local inspector, chat, run and issue stores use the libSQL adapter against existing SQLite files. Graph snapshots retain user-recorded verification receipts.
- Preserve opaque telemetry
attributesandtagskeys in machine output, queryobservationprovenance, and status ingestion receipts. - Document source policy configuration and agent-hook timeout flags in command help. Help checks cover behavior and readability rather than pinning exact wording snapshots.
Breaking: the collector’s HTTP API is same-origin, and checks Host
Section titled “Breaking: the collector’s HTTP API is same-origin, and checks Host”- No more
Access-Control-Allow-Origin: *outside OTLP ingest. The inspector, its APIs, sessions, session trees and transcripts, issues, fix context, runs, settings, health, the query API and/api/streamsend no CORS header. A page on another origin can no longer read them; a script or tool that called the API from a browser page on another origin breaks. Call it from a local process (curl,fetchin Node, the CLI or MCP), or from the inspector itself. - CORS stays on OTLP ingest only:
POST /v1/traces,/v1/logsand/v1/metricsand theirOPTIONSpreflight answerAccess-Control-Allow-Origin: *, so an OpenTelemetry SDK running in a browser page on your dev server keeps exporting. Those routes take telemetry in and answer only an accepted count. - Host check on every route, OTLP included, with no exemptions (any future
/mcproute too): theHostheader must be127.0.0.1:<port>,localhost:<port>or[::1]:<port>, else403 Forbidden: Host is not this collector's loopback address. This defeats DNS rebinding. A local SDK, the CLI, MCP and the inspector send one of those already. A request through another name (host.docker.internal, a LAN name or an/etc/hostsalias) is refused; the collector binds loopback only. From a container, run the OTel SDK’s exporter against a port forwarded to the host’s loopback (for examplessh -Lor a sidecar) withHost: 127.0.0.1:<port>, or run the instrumented process on the host. A dev-server proxy in front of/v1(Viteserver.proxy) must rewrite Host (changeOrigin: true), or the SDK can export straight to the collector, since OTLP answers CORS. - Origin check outside OTLP ingest: a present
Originmust be the collector’s own (http://plus one of those hosts), on GET too, else 403. - Guarded writes and chat follow the same rule. Issue state, mark-wrong, run start and finish, the workers acknowledgement and the inspector chat accept any of the three loopback Hosts, with
Originequal tohttp://plus that same Host, and still require their marker header, JSON and no cross-site fetch. The inspector opened aslocalhost:<port>or[::1]:<port>now works fully; before, its chat and writes answered 403.
Breaking: JSON
Section titled “Breaking: JSON”- Errors. Every
--jsonfailure is one envelope on stdout withok: falseanderror: {code, message, hint, docs, next}.- Rejected HTTP queries retain optional
error.detailswith the responding collector instance, evidence revision and HTTP status. - Renamed codes:
collector_unavailableis nowcollector_not_running,query_failedis nowquery_rejected, andinvalid_argumentis nowinvalid_value(or a more specific code such asunknown_flagormissing_value). - workers’
invalid_or_unavailable_snapshotis split intoinvalid_value,invalid_snapshot,collector_not_runningand others. graphandevidenceerrors use the envelope instead of ablop.graph/v1error document.
- Rejected HTTP queries retain optional
- Envelope.
- Success envelopes carry
ok: true. - Every envelope has a top-level
next: [{command, when}]. On a failure it repeatserror.next, which is also objects now, not strings. warningsentries are{code, message}objects, not strings. One example isversion_mismatchonupandstatus.
- Success envelopes carry
blop run --json. The old one-line camelCase object{runId, exitCode, sessions, requests, failedRequests, newIssues, regressedIssues, url}is gone.- It is now a
blop.cli/v1envelope. On stderr it is the last line Blop writes, on a line of its own; with--report <file>it goes to that file instead. datahas snake_case keys.new_issuesandregressed_issuesare lists of{id, title, url}. The oldurlis nowdata.collector_url.okis true when the command started, and false only when it never started.- Usage errors of
blop run --jsonalso go to stderr (or to the report), never to stdout.
- It is now a
blop tail -o ndjson(also--jsonand-f json). Each line now hasschema_versionandtype. Keys are snake_case:exitCodeis nowexit_code,endReasonis nowend_reason, andtraceIdis nowtrace_id.blop issues --json. Rows gaintrend_24h.trend24hstays untilblop.cli/v2, and every document carries onedeprecated_fieldwarning, so a non-emptywarningsno longer means something went wrong: branch oncode.blop issue <id> --fix-context --jsonis an envelope with the markdown indata.markdown. It used to print the raw markdown.blop init --json.data.next(a string) is removed. The suggested command is in the envelope’snext[].blop workers overview|detail --jsonis a full envelope:ok,generated_at,pageandnextare added, and the document is pretty-printed. Itsdatakeys are snake_case, for exampleworker_idandconnection.connection_state.blop setup opencode --jsonis ablop.cli/v1envelope with the setup asdata. It used to be a separateblop.setup/v1document.blop evidence ... --jsonandblop graph ... --jsonare envelopes. Text output is still the raw document.blop setup mcp --json(new) is an envelope withcommand: "setup mcp"anddata: {client, scope, target, invocation, action, snippet, backup?, verified, activation?}, or{clients: [...]}with no client. Its error envelopes say"setup mcp"too.blop setup opencode --jsonkeepscommand: "setup".actionisadded,replaced,unchanged,printed,command,removedorabsent;invocationis null with--remove;backupis a path under Blop’s state dir (backups/<client>/).blop init --jsongainsdata.mcpwith--mcp <client>, and without it one morenext[]step,blop setup mcp.- The OpenCode MCP snippet (README, Connect page,
blop setup mcp opencode) gains"timeout": 30000when the command isnpx, because a coldnpxstart outlasts OpenCode’s 5 second default. BLOP_MCP_VERIFY=1(new, internal; do not set it):blop mcpanswers the protocol but never contacts a collector, whatever--url/--portsay. It says so once on stderr (blop mcp: verify mode, no collector contact), and every tool call answers that it is in verify-only mode.blop setup mcpuses it for its start check and for the client’s own health-check, so setup never marks a collector “MCP connected”.- MCP invocation detection no longer trusts an inherited
npm_command=exec: ablopon PATH that is this installation is always used. The Connect page shows install buttons only for that, or for a published pinned npx; another installation on PATH gets the update step (mcp.install_reason: "other_install"). - The npx MCP command is pinned:
npx -y @blopai/cli@<version> mcp(wasnpx -y @blopai/cli mcp, which fetched 1.7.0, a version withoutmcp). The Connect page shows it only when that version is known to be published; otherwise it showsnpm i -g @blopai/cliand no install buttons (mcp.linksis null,mcp.installis the step). blop doctor --json. Rows are{id, category, status, ok, detail, fix, advisory}. A failed blocking check printsok: false, the error, and the checks indata.
Breaking: blop mcp speaks MCP 2026-07-28 too, and its tool results changed shape
Section titled “Breaking: blop mcp speaks MCP 2026-07-28 too, and its tool results changed shape”- Both eras. Legacy clients keep the
initializehandshake andping;2025-11-25joins the accepted versions, and an unknown requested version now gets2025-11-25back (it was2025-06-18). Modern clients getserver/discover(supportedVersions["2026-07-28", "2025-11-25", "2025-06-18", "2025-03-26", "2024-11-05"],capabilities.tools,instructions,ttlMs: 3600000,cacheScope: "public",_meta["io.modelcontextprotocol/serverInfo"],resultType: "complete"). A request whoseparams._metacarries the per-request protocol fields is served statelessly: a missingprotocolVersionorclientCapabilitiesis-32602, a version other than2026-07-28is-32022withdata.supportedanddata.requested, and results carryresultType,serverInfoin_meta, and ontools/listttlMsandcacheScope.pingis not a modern method (-32601with modern_meta). - JSON-RPC edge cases. A request with
"id": null(or a non-integer, non-string id), a JSON array (batches are not part of MCP), a non-object line and a request without a stringmethodget-32600; unparseable JSON stays-32700withid: null. Notifications are never answered. - Tools. Each tool has a
title(List Blop issues,Get Blop issue,Get fix context,Get session or trace timeline) andannotations: {title, readOnlyHint: true, openWorldHint: false};serverInfohastitle: "Blop";instructionsend with “Needs a running Blop collector (blop up). Read-only.” - Results are structured, snake_case and compact. Each result carries
structuredContentthat matches the tool’s newoutputSchema, and the same JSON, compact (no pretty-printing), in its text block (get_fix_context: the markdown). The shapes are the CLI’s:list_issuesis{data, returned, total, truncated, note?}withblop issues --jsonrows (not_seen_in_latest_run,trend_24h, absoluteurl; was camelCase);get_issueis theblop issue <id> --jsondetail (snake_case, plusurl,truncated,occurrences_returned,dropped?,note?);get_fix_context’s structured copy is{id, markdown, fix_context_url, url, truncated};get_sessionkeys are snake_case (session_id,trace_id,source_id,duration_ms,span_id,parent_span_id,metadata.call_id, …). The outputSchemas are composed fromschema/issues,schema/issueand the newschema/mcp-tools(blop schema mcp-tools). - Size. Results are capped near 36 KB (was 50 KB, pretty-printed), under Claude Code’s 10,000-token warning. A cut result stays valid JSON with
truncated: trueand anotenaming the command that shows everything (blop issues --json,blop issue <id> --json,blop issue <id> --fix-context,blop open <id>).get_issueempties whole sections (objects to null, lists to empty) before it drops chain steps, so it still matchesschema/issue. - Which collector.
blop mcpreads the collector of the client’s project:BLOP_PROJECT_DIR, elseCLAUDE_PROJECT_DIR(Claude Code sets it), else its working directory;--urlandBLOP_MONITOR_URLstill win. When several collectors run and none matches, a tool call is anisErrorresult listing each one (url and workdir) and the exactBLOP_MONITOR_URL=...fix; it used to answer silently from the default port. A collector that answers 200 with a body that is not JSON is anisErrorresult too (it used to read as an empty list). get_fix_contextwhose first line alone is over the cap keeps as much of that line as fits (whole characters), then the note; it used to return the note alone.- stdout carries only JSON-RPC messages (now covered by a test that feeds valid, invalid and failing input); diagnostics go to stderr.
blop setup mcp: one client table, Gemini CLI, Windsurf, Claude Desktop, stale entries
Section titled “blop setup mcp: one client table, Gemini CLI, Windsurf, Claude Desktop, stale entries”- One table (
src/monitoring/mcp-clients.ts) now drivesblop setup mcp, the Connect page’s tabs, snippets and install links,mcpConfigSnippets,blop mcp --helpand the README and docs client section (generated between markers bynode scripts/render-mcp-docs.mjs; a test fails when they drift). - New clients.
geminirunsgemini mcp add -s project|user blop <command>(andgemini mcp remove -s <scope> blop), never--trust, and verifies by readingmcpServers.blopback from.gemini/settings.jsonor~/.gemini/settings.json(read only; a backup of the previous file goes to Blop’s state dir). It used to be refused.windsurfandclaude-desktopprint the entry and where it goes and never write (action: "printed", aprint_onlywarning): Windsurf’s config path is moving (~/.config/devin/mcp_config.json, older~/.codeium/windsurf/mcp_config.json), and Claude Desktop has no project and a minimal PATH, so its entry uses the absolute path ofblop.blop init --mcpand completion offer all eight. - User-scope Cursor and VS Code entries carry
env.BLOP_PROJECT_DIR = "${workspaceFolder}", and so do the Connect page’s Cursor snippet and both install links (which install at user level). A user-scope entry written before this has no env and now reads as stale (missing_project_env);blop setup mcp cursor --scope user --forcerewrites it. - The VS Code snippet on Windows wraps npx in
cmd /con the Connect page and in its install link too, as setup already did. Codex’s TOML snippet gainsstartup_timeout_sec = 30when the command is npx. - Connect page JSON.
mcpSnippetsis keyed by client id (claude,codex,cursor,vscode,opencode,gemini,windsurf,claude-desktop;claude-codeis nowclaude), andmcpClientslists the tabs in order. - Stale entries.
blop setup mcpwith no client reports, per client, everyblopentry inentries[]({scope, target, command, args, status, reason, detail, update}). An entry is stale when it pins an older@blopai/cli, runs an unpinned one, uses npx while thisblopis on PATH, names a command that no longer exists, or (user-scope Cursor and VS Code) lacksBLOP_PROJECT_DIR; text output prints onewarning:line on stderr per stale entry with its update command, andnext[]lists them. A server someone else namedblopisstatus: "other"and never offered for--force. A client’sstatuscan now beother, and the text word for a stale one isstale(wasstale command). blop doctorgains anmcpcheck under Agents: ok when no Blop entry is stale (none at all is fine), a warning naming each stale entry with its update command as the fix. It is advisory, so it never fails doctor; the Connect page shows it too.
Breaking: exit codes and refusals
Section titled “Breaking: exit codes and refusals”- Exit-code table. 0 ok, 1 failure, 2 usage, 3 Blop not running, 4 query rejected, 5 timeout, 6 could not verify (
blop init,blop setup mcp: the result could not be confirmed, or nothing was written because it would not work), 129 terminal closed (SIGHUP), 130 interrupted, 143 terminated (SIGTERM) (blop help exit-codes). 129 and 143 come fromblop setup mcpwhen its start check is cut short.- Bad flags used to exit 1; they now exit 2.
- An unreachable collector exits 3.
--state bogusexits 2 before any request is sent.
- Interrupts. Ctrl-C now exits 130 for
blop tail, a foreground collector andblop monitor start. It used to exit 0. - Strict parsing. Unknown flags, extra arguments and a leading
--exit 2.--reasoning-effortwas never implemented and is now an unknown flag. - Output formats.
-otakes only the formats a command lists, and anything else exits 2. For example,skills --jsonused to be ignored and is now refused.--json -o text,-f json -o textandworkers --json -o textexit 2.
blop flow initasks before overwriting. Without a terminal it exits 2 unless--forceis given.- One collector precedence on every command: flag, then env, then the registry or the default.
blop up -p/--portand--host(andblop monitor start) now win overBLOP_MONITOR_URL, as they already did on status, stop, run, open, init, mcp, doctor and the query commands. Before,blop up -p Nin a shell whereeval "$(blop status -o env)"had exportedBLOP_MONITOR_URLsilently reused that collector, or exited 3 when it was gone. blop upreadsBLOP_MONITOR_HOST, the env of--host, as the client commands already did (blop monitor startdid before this release too). It is held to the same rule: 127.0.0.1, ::1 or localhost, anything else exits 2.host_refused(exit 4). A request the collector refuses for itsHost(aBLOP_MONITOR_URLor--urlthat nameshost.docker.internal, a LAN name or an/etc/hostsalias) ishost_refused, with a hint naming the loopback forms. It read asThe collector rejected the query (HTTP 403)(query_rejected).blop mcptool results say the same.blop setup opencode --urlexits 2 (unsupported_flag). It was accepted and ignored; the command starts or reuses a collector by port (-p).blop tail’s help no longer lists exit codes 3, 4 and 5: a collector that is down is waited for, with one warning, and tail reconnects.blop status’s note now says-qsilences stdout only (errors still go to stderr).- Exit never waits more than 5 s for stdout and stderr to drain. A reader that keeps the pipe open and never reads used to hold the process forever; it now exits with the intended code.
Breaking: text output
Section titled “Breaking: text output”blop issues. Piped output is tab-separated with no header (use--headerfor one): ISO times, the full commit, and the inspector URL. The terminal shows an aligned table.blop run. The summary on stderr is a 7-line block instead of one line.blop tail. The status lines are nowwarning: Blop is not running at <url>; waiting for it (start it with blop up)andConnected to Blop at <url>.- Errors. All errors use
error:,usage:,hint:anddocs:lines on stderr. - Help. All help is generated from the command registry. Root help’s
setuprow readsConnect a coding agent: blop setup mcp claude, andblop setup --helplists JSON FIELDS per subcommand (blop setup opencode --help,blop setup mcp --help). blop initends with one more line:Agents: blop setup mcp <client> .... ItsNext:line (andnext[0]in JSON) names the dev command bareblop runwould start, with the lockfile’s package manager (blop run -- pnpm run dev); it always saidnpm run dev.- The MCP line
blop upprints for a coding agent, and themshortcut’s copy, are nowblop setup mcp claude(plus-p Nor--url <url>only when you passed one), spellednpx -y @blopai/cli@<version> setup mcp claudewhenblopis not on PATH and that version is known to be published, andnpm i -g @blopai/cli && blop setup mcp claudeotherwise, the same rule the Connect page uses. They were a hand-builtclaude mcp add blop -- blop mcp [--url ...], which registered a server that could not start for npx users and pinned the URL of a non-default port.blop setup mcp claudechecks that the server starts before it adds it. blop upopens the inspector by the ruleblop openuses: not under--no-inputorBLOP_NO_INPUT,BROWSER=none, over SSH or with no display (it already skipped coding agents and pipes).blop runwith no command runs the package.jsondevscript with the package manager the lockfile names (pnpm, yarn, bun, else npm) and says so in one stderr line. Without adevscript it still exits 2, now with the scripts it found in the hint. A dev script that runs blop itself (blop run,npx blop,bun run src/cli/index.ts) is refused (exit 2,dev_script_runs_blop). A coding agent runningblop rungets one short stderr block before the command starts (inspector URL,blop issues --json,blop run --json).blop runprints one line before the command starts:blop run: telemetry to <url> · service <name> · content capture off (--capture-content) · found ai-sdk (blop init prints their setup)(orno agent SDK found here).--no-summarydrops it and the end summary block. The command’s own stdio is untouched.blop runinsideblop run. Every commandblop runstarts getsBLOP_LOCAL_RUN_ID,BLOP_LOCAL_RUN_PID,BLOP_LOCAL_RUN_STARTandBLOP_LOCAL_RUN_DEPTH, with a collector or without one. While that outerblop runis still running, ablop run -- <cmd>inside it joins its run (no second run, the outer TRACEPARENT and run id are kept; its own--capture-content,--urland--portdo not apply, and it says so once;--jsonreportsrecorded: falsewithnested_run, plusnested_flags_ignoredwhen flags were dropped), and a bareblop runinside it exits 2 (nested_run), so a dev script cannot recurse, even indirectly. A marker whoseblop runhas ended (a shell or terminal that outlived it) is ignored with one stderr note (stale_run_markerin JSON) and a new run starts. With 8 runs already enclosing it,blop runexits 2.--no-summaryalso drops the coding-agent block.- The lockfile and
packageManagerfor bareblop runare also looked up in parent folders, up to the git root (workspaces). - Root help lists
open(INVESTIGATE) andcompletion(MANAGE).
New commands
Section titled “New commands”blop open [<issue|session|run|trace id> | <page>] [--print] [--json]opens the inspector at that object or page (home, sessions, issues, runs, connect, settings) on the resolved collector. It prints the URL instead with--printor--json, for a coding agent, with--no-input, withBROWSER=none, over SSH and with no display. An unknown target exits 2 with did-you-mean.blop issue <id> --webandblop trace <id> --webdo the same for one object.BROWSER=<command>now names the program that opens a URL (also forblop up): a:-separated list (;on Windows), tried in order, with%sfor the URL. When no browser starts,blop openprints the URL. On Windows the URL goes torundll32 url.dll,FileProtocolHandler(notcmd /c start, which cut URLs at&).blop completion bash|zsh|fishprints a completion script generated from the command registry: commands, subcommands, flags and their values, plus live issue and run ids from the running collector (through the hiddenblop __complete, which prints nothing when the collector does not answer).
Renamed commands (old names still work, with a notice on stderr)
Section titled “Renamed commands (old names still work, with a notice on stderr)”blop run x.blop.ts(flow checks) is nowblop flow test.blop runwraps a command.blop test,blop watchandblop listare nowblop flow test|watch|list.blop monitor start|stop|statusare nowblop up,blop stopandblop status.blop statusis a lifecycle command (-o text|json|env,--logs), not a query.
Standalone agent testing and local coverage
Section titled “Standalone agent testing and local coverage”- Move the agent-test DSL, runner, configuration, reporters, optional platform upload, templates and authored examples into
@blopai/test. Import tests from@blopai/test;@blopai/cliretains theblopcommand and delegates Browser Harness flows to that package. Remove the old runtime/reporters/platform exports rather than preserving aliases. - Add opt-in Chromium JavaScript coverage with
--coverageand explicit collector delivery through--coverage-endpoint. Save the report before hosted artifact upload, remove stale coverage artifacts on non-coverage runs, and preserve test identities when a run ends early. - Add the local inspector’s Coverage view: latest report, file/test filters, executed UTF-16 source-character totals, paginated source annotations, test outcomes and visible collection gaps. Persist bounded reports separately from trace storage; do not imply statement/branch coverage, source maps, unloaded-file coverage or a run/trace join.
- Exclude oversized browser-script measurements with explicit warnings instead of losing the run’s report. Validate collector payloads, enforce body and evidence limits, and apply the local write boundary.
- Discover DSL registrations, default exports and named test arrays together, deduplicate repeated exported objects, and retain registered checks on repeated Bun imports.
- Document agent-driven E2E goals, deterministic assertions, evidence, safe targets, runtime/provider failures, flake handling, CI artifacts and coverage limits.
- Move testing ownership to the independent
blop-oss/blop-testrepository; preserve the genuine May 2026 implementation and full dated provenance, squash the standalone import, and consume an immutable public Git source until npm publication is provisioned. Remove the workspace package, portable browser patch and testing release workflow; CLI, dashboard and generated GitHub workflows use the external SDK. Align skill tool results with the browser harness’s caller-origin, untrusted content boundary. - Verify canonical and legacy CLI flow execution against the standalone SDK’s public exports with real Chromium and loopback app/provider fixtures: actual assertions produce exit 0/1 and matching results, JUnit, events and progress. Preserve the immutable shipping Git dependency while using the local clone for this verification; repair the clone’s root example import to use
@blopai/test.