Releases: Netis/heron
Releases · Netis/heron
Release list
Heron v0.7.3
[0.7.3] — 2026-08-17
Fixed
- Opening an agent turn made the timeline wait on every request and response
body in it. The detail panel fetched the calls list body-bearing, and the
timeline, stat cards, agent breakdown and collapsed cards are built from
scalars — none of them reads a body. Measured against a production store, that
list is 2–20 MB and 0.4–4.8 s where the same list without bodies is 16–60 KB
and ~10 ms; the panel then parsed those megabytes on the main thread. It now
paints off the small shape and pulls bodies afterwards as a background
upgrade, so nothing the reader is waiting for is behind them. - Turns over the 50-call threshold fetched the bodies anyway, then threw them
away. Whether to ask for bodies was decided fromcall_count, which arrives
from a different request — so on mount the answer defaulted to "yes" and the
body-bearing fetch went out for every turn, to be abandoned a few ms later
when the count came back over the threshold.apiFetchpassed no
AbortSignal, so "abandoned" still meant downloading, parsing and caching the
full response: a 102-call turn pulled 20.6 MB it could never render. The span
and body endpoints now pass the signal, and the query no longer fires before
its own precondition is known — the same turn now costs 60 KB to open.
What's Changed
- ci(prod): chain deploy-prod off release.yml — the release trigger never fires by @vaderyang in #193
- soak: say whether the load gate is enforcing, because the log said it wasn't by @vaderyang in #194
- fix(console): the turn timeline waited on every body in the turn (v0.7.3) by @vaderyang in #195
Full Changelog: v0.7.2...v0.7.3
Heron v0.7.2
[0.7.2] — 2026-08-15
Added
- sglake (sglog) storage backend.
[storage] backend = "sglake"runs the
whole console against a Splunk-compatible log platform, alongside DuckDB and
ClickHouse — writes over the HTTP Event Collector, reads in SPL, all thirty
StorageBackendmethods. Unlike the SQL backends, stored request and response
bodies are full-text searchable (search index=heron_bodies "SELECT * FROM users"). Retention is pushed as per-index TTLs rather thanDELETE, since
the store is append-only.heron sglake-propsprints the index-time
extraction stanzas that keep aggregates on the columnar path; they are
generated from the event structs themselves, so they cannot drift from the
schema. See docs/design/10-sglake.md, which also
documents the known divergences — proxy pairing does not annotate traces on an
append-only store.
Fixed
- Pagination could return the same row on two pages and skip another. Every
paginated list ordered by a non-unique key (request_timemost often) with no
tie-break, andLIMIT/OFFSETissues one query per page, so the engine was
free to order tied rows differently between them. Walking 26 spans that shared
a timestamp five at a time returned 18 distinct rows. All paginated queries in
the DuckDB and ClickHouse backends now end their sort with the row id. - DuckDB truncated
duration_mson HTTP exchanges to whole milliseconds, so
every sub-millisecond exchange showed0.0. ClickHouse already computed it
from microseconds. /api/metrics/timeseriescould be asked for an unbounded number of
buckets — a 7-day window at 10s granularity materialises 60,480 points per
series. It now refuses above 20,000 and names a granularity that fits.
Changed
- The agent-trace panel switches to lazy per-call body loading above 50 calls
rather than 200, measured against the real cost of answering with bodies.
What's Changed
- docs(readme): swap hero GIF to the live dashboard view by @vaderyang in #178
- feat(storage): sglake backend — full-text searchable bodies, and five defects it exposed by @vaderyang in #191
- ci(prod): production tracks releases, gated on a read-path smoke by @vaderyang in #192
Full Changelog: v0.7.1...v0.7.2
Heron v0.7.1
[0.7.1] — 2026-06-24
Fixed
- Console blank-page regression from the v0.7.0 OTel rename. The traces API
serializesspan_ids(renamed fromcall_ids), but theAgentTurnDetail
type and theagent-breakdowncomponent still readcall_ids, so opening an
agent trace detail threwTypeError: undefined is not an object (evaluating '…call_ids.length')and — with no React error boundary — blanked the entire
console. Aligned the type + component tospan_idsand guarded the access so
a missing field degrades to "0 calls" instead of a white screen.
Changed
- UI vocabulary aligned with the OTel model. Renamed user-visible labels:
"Agent Turns" → "Agent Traces" and "HTTP Exchanges" → "HTTP Logs" (nav, detail
titles, the overview gauge, the "Trace ID" metadata row, empty/error states,
the SFT export tooltip, and the distribution chart). A trace is one agent
interaction; a step within it remains a turn/span. Backend metric names, route
paths, and code identifiers are unchanged.
What's Changed
- v0.7.1: fix console blank page (span_ids) + UI rename (Agent Traces / HTTP Logs) by @vaderyang in #177
Full Changelog: v0.7.0...v0.7.1
Heron v0.7.0
[0.7.0] — 2026-06-24
Added
- eBPF capture discoverability — an experimental, opt-in advisory. When no
eBPF source is active, the server now logs a one-line notice (Linux only) that
on-host TLS capture exists and how to enable it (ebpfcargo feature + a
type = "ebpf"source — there is no--ebpfruntime flag). The Settings
page's eBPF capture toggle is now tagged experimental and its description
spells out the opt-in requirements.
Changed
- OpenTelemetry-aligned rename of the storage entities and HTTP API. The
agent_turnstable is nowtraces,llm_callsis nowspans, and
traces.call_idsis nowspan_ids; a new forward-lookingspans.kind
column (always'llm'today) leaves room for wire-visible tool spans. The
Rust domain/query types (AgentTurn→Trace,Turn*/Call*DTOs →
Trace*/Span*) andStorageBackendmethods (write_calls→write_spans,
query_turns→query_traces, …) follow suit. New canonical routes
/api/traces*and/api/spans*; the pre-rename/api/agent-turns*and
/api/llm-calls*keep working as deprecated aliases (RFC 8594Deprecation
header). Retention config keyscalls/turnsare accepted as serde aliases
forspans/traces. Existing DuckDB/ClickHouse databases auto-migrate in
place on init() with no data loss (idempotent detect-then-rename).
Docs
- README rebuilt for the launch — GIF-first, conversion-driven layout.
Headline tagline "The Wireshark for AI Agents", a hero demo GIF up top, a
30-second pcap-replay quick start, and a three-up "What Makes Heron Different"
table (agent-turn reconstruction · service topology · SFT trajectory export),
while preserving the existing technical accuracy (passive positioning across
wire and on-host TLS boundary, opt-in eBPF,docs/configure.mdlinks,
just-based contributor flow). API examples updated to the canonical
/api/tracesroutes. - Corrected launch collateral added under
launch/. Paste-ready Product
Hunt / Hacker News / Twitter copy aligned to the shipped product: install via
thecurl … install.shone-liner (no npm package), canonical/api/traces
endpoint, and v0.7.0 framing.
What's Changed
- ci: repoint agent-loop wrappers to Netis/olympus (agent-ops renamed) by @vaderyang in #165
- Upgrade Olympus mechanism to v0.4.0 (full post-rename migration: .olympus.json + olympus_ref) by @vaderyang in #167
- fix(turn): keep eBPF-sourced turns whose opening call was missed by @vaderyang in #168
- fix(ebpf): detach uprobe links for dead inodes to stop bpf_link fd leak by @vaderyang in #172
- chore(olympus): align .olympus.json — current model + Greek-deity agent names by @vaderyang in #173
- refactor: OpenTelemetry-aligned rename (agent_turns→traces, llm_calls→spans) by @vaderyang in #174
- Launch v0.7.0 → main: README rebuild + collateral + eBPF advisory by @vaderyang in #176
Full Changelog: v0.6.0...v0.7.0
Heron v0.6.0
[0.6.0] — 2026-06-16
Changed
- eBPF on-host SSL-uprobe capture is now a first-class, soak-gated
capability (experimental since 0.5.1). It lifts the plaintext of
TLS-encrypted LLM calls directly at the in-processSSL_read/SSL_write
boundary — covering dynamically-linked OpenSSL/BoringSSL (Pythonopenai/
anthropicSDKs, curl, Node, most CLIs) and statically-linked, symbol-stripped
BoringSSL single-executable runtimes (Claude Code's / opencode's Bun binaries,
located by byte-signature offset) — and stamps every call with its owning
process (pid · command · executable). A new stagingebpf-soakgate replays
real TLS traffic through the freshly deployed binary and asserts the uprobe
attaches, traffic is captured, and a process-attributedLlmCallis parsed and
persisted end-to-end; both prod promotion and release now require a passing
ebpf-soakedstatus alongsidestaging-soaked, so on-host capture can no
longer silently regress into prod or a cut release.
Fixed
- eBPF SSL uprobes attach under the non-root staging service. The staging
unit granted onlyCAP_BPF+CAP_PERFMON, but the kernel gates uprobe
perf_event_open(perf_uprobe_init) onCAP_SYS_ADMINspecifically — which
those caps don't cover andperf_event_paranoiddoesn't relax. TheSSL_write
uprobe attach therefore failed withperf_event_open failed, and because a
failed capture source is non-fatal (the co-located packet tap keeps the
pipeline healthy) the symptom was a silentebpf_uprobes_attached = 0rather
than a crash — which is why theebpf-soakgate had never passed. The
committed staging unit now carriesCAP_SYS_ADMIN(matching what the prod
deploy already injects), so the gate goes green and on-host capture works under
a non-root service.
Docs
- README repositioned from "network wire" to passive capture. The headline
"Agent observability from the network wire" became inaccurate once on-host eBPF
landed — those bytes never touch the wire (on a client they're the
pre-encryption plaintext). It now leads with the durable differentiator
(passive; no SDK, sidecar, or proxy; never in the request path) and names both
capture surfaces: off the network wire, or lifted from the host's TLS boundary
by eBPF.
What's Changed
- ci(ebpf): staging eBPF verification gate before prod by @vaderyang in #148
- fix(ebpf): follow inode rotation & reach already-running sessions (v0.5.4) by @vaderyang in #157
- fix(wire/anthropic): don't record control-plane telemetry as model=unknown LLM calls (v0.5.5) by @vaderyang in #158
- fix(agents/claude-cli): drop security-monitor sidecar from agent-turns (v0.5.6) by @vaderyang in #159
- docs(readme): elevate eBPF on-host capture to a first-class capability by @vaderyang in #160
- fix(ebpf): grant CAP_SYS_ADMIN to staging unit so SSL uprobes attach by @vaderyang in #161
- docs(readme): reposition from "network wire" to passive (wire or eBPF) by @vaderyang in #162
- release: v0.6.0 — eBPF on-host capture promoted to first-class (soak-gated) by @vaderyang in #163
Full Changelog: v0.5.3...v0.6.0
Heron v0.5.3
[0.5.3] — 2026-06-15
Fixed
- eBPF capture of large and multi-connection TLS traffic. A big
SSL_*
buffer is split into several ring-buffer events; the synthesizer used to append
each at a running sequence counter, so a silently-dropped or reordered chunk
shifted every later byte and spliced the next request's bytes into the previous
body (invalid JSON → no captured call). The BPF program now stamps each event
with its absolute per-(connection, direction)stream offset and the
synthesizer places every chunk at that offset, so a dropped chunk leaves a gap
at its true position instead. Connections also finalize properly now — an
SSL_freeuprobe (dynamic libssl) and anSSL_read-returns-0 EOF (static
targets) emit a close, and a per-connection generation folded into the
synthetic tuple gives a reusedSSL*pointer a fresh, non-overlapping flow
key. - Claude Code conversations form agent-turns. The Anthropic
mid-conversation-systemfeature appends a trailingrole=systemnotice after
the user's prompt, so the messages array often ends withsystemon a fresh
turn.is_user_turn_start/extract_user_inputnow skip trailing system
messages and evaluate the last non-system one, so fresh turns are recognized
(and their prompt preview populated) instead of being discarded as
"no user start". - In-progress turn timestamps rendered as the year ~58423. Active-turn
registry rows emittedstart_time/end_timein microseconds, but the field is
milliseconds (the DB path returnsepoch_ms, the console renders with
new Date(ms)). A µs value read as ms is 1000× too far in the future. Both
active-registry conversions now divide to milliseconds, matching finalized
turns. Added a timestamp-unit test suite across the eBPF clock and the API
boundary.
What's Changed
- feat(prod): build the eBPF-enabled binary in deploy-prod by @vaderyang in #150
- fix(prod): raise container fd limit for the eBPF build by @vaderyang in #151
- feat(console): eBPF capture status card on pipeline-health by @vaderyang in #152
- fix(ebpf): correct large/multi-connection capture + form Claude Code agent-turns by @vaderyang in #155
- release: v0.5.3 — eBPF capture correctness + timestamp fix & test suite by @vaderyang in #156
Full Changelog: v0.5.2...v0.5.3
Heron v0.5.2
[0.5.2] — 2026-06-11
Added
- eBPF capture is now a managed Settings source. The console's pipeline
Settings lists, adds, edits, and removes the on-host eBPF SSL-uprobe source
like any other ingress, with an availability guard: a binary built without the
ebpffeature reportsebpf_available = falseon/api/runtime-config, and
the API rejects an eBPF source on such a build so a stray config can't wedge
the next boot. (The capture engine itself shipped in 0.5.1; this makes it
operable from the UI.) - eBPF metrics in pipeline-health. A new
ebpfmetric group surfaces the
capture path's health — uprobes attached, events received / dropped, bytes
captured, frames synthesized, active connections, and process-cache size — in
the debug pipeline-health view and on/api/internal-metrics.
Changed
- Console theme aligned to the Kami parchment design system. Replaced the
too-dark palette with the canonical parchment surfaces (paper canvas, lifted
ivory, ink-blue accent), matching the heron-ai.pages.dev landing site.
Docs
- Refreshed the README screenshots in the corrected Kami theme.
What's Changed
- feat(ebpf): Settings enable/disable toggle + pipeline-health metrics by @vaderyang in #147
- fix(console): align Kami theme to the parchment design system by @vaderyang in #145
- docs: refresh README screenshots in the corrected Kami theme by @vaderyang in #146
- release: v0.5.2 — eBPF Settings source + metrics, Kami theme by @vaderyang in #149
Full Changelog: v0.5.1...v0.5.2
Heron v0.5.1
[0.5.1] — 2026-06-11
Added — eBPF on-host TLS capture (experimental, Linux)
- New
ebpfcapture source: a fourth ingress alongside the packet taps
(pcap/pcap-file/cloud-probe). It attaches uprobes to the target's
SSL_read/SSL_writeand reads plaintext at the in-process TLS boundary —
so Heron can observe TLS-encrypted LLM calls on the host that makes them,
with no proxy, TLS terminator, or MITM, and nothing on the request path.
Plaintext chunks are dressed as synthetic Ethernet/IP/TCP frames
(FlowSynthesizer) and fed through the existing dispatcher → reassembler →
HTTP/SSE parser → wire-API decoder → turn tracker unchanged. - Process attribution. Every eBPF-captured call carries its owning process
(pid·comm· resolved executable), threaded end-to-end through
RawPacket→ParsedPacket→TcpFlow→LlmCallinto the
process_pid/process_comm/process_exestorage columns (DuckDB Phase-7
migration + ClickHouse mirror) and surfaced in the console's LLM-calls list and
call detail. Packet-tap sources leave it null. - Target coverage. Dynamically-linked OpenSSL/BoringSSL by exported symbol
(Python SDKs, curl, …), and statically-linked, symbol-stripped BoringSSL —
e.g. Claude Code's Bun runtime — located by byte-signature → ELF file offset →
offset uprobe. A built-inflavor = "bun"ships read-anchored prologue
signatures, so stock Bun / Claude Code works with zero manual derivation. - Linux-only and off by default: built behind the non-default
ebpfcargo
feature onh-capture(absent from prebuilt release binaries). Needs
CAP_BPF+CAP_PERFMON(kernel ≥ 5.8) or root, plus kernel BTF;heron doctorreports acapture.ebpfcheck. HTTP/1.x only, like every source. See
docs/design/02-capture.mdanddocs/design/03-ebpf-static-targets.md.
Added
- SFT trajectory export from reconstructed agent turns and sessions:
OpenAI-stylemessagesJSONL with tool calls, tool results, and assistant
reasoning preserved and tool-call arguments rehydrated to objects. Export a
single turn/session from its detail view, or batch-export the current Agent
Turns filter as one-line-per-turn JSONL (Anthropic + OpenAI-chat wire formats;
unsupported formats reported and skipped). - Three-theme console, switchable from the sidebar and persisted per browser:
Kami (warm washi-paper, the new default), Dark, and Light —
charts, topology graph, and timeline gantt all re-theme.
Fixed
- ClickHouse SQL literal escaping (dialect-aware): a backslash in a
dimension-filter value could break out of the quoted literal in the ClickHouse
backend. Escaping is now dialect-aware across both backends.
Security / CI
- Self-hosted CI runners are gated to same-repo PRs, closing fork-PR code
execution; a release may only be cut from a commit that passedstaging-soak,
and prod deploys are gated on the load soak.
What's Changed
- test(chaos): fault injection under sustained concurrent write load (PR3) by @vaderyang in #121
- feat(test): pcap regression corpus framework (scrub + manifest + golden, git-LFS) by @vaderyang in #120
- feat(staging): nightly longevity soak — the 102 GB endurance catcher (PR4) by @vaderyang in #122
- ci(perf-gates): enforce load soak before prod + require staging-soaked before release by @vaderyang in #123
- docs: quality/release pipeline + v0.5.0 refresh (ClickHouse, perf gates) by @vaderyang in #124
- feat(test): cliproxy mixed-format (#96) — precise OpenAI-shape + Anthropic-usage cells by @vaderyang in #125
- feat(triage): warm maintainer-voice replies on every verdict; reproduce before auto-queuing by @vaderyang in #126
- dogfood: delegate triage to the agent-ops reusable workflow by @vaderyang in #127
- dogfood: delegate issue-implement (wiwi) to agent-ops@v0.1.0 by @vaderyang in #129
- dogfood: delegate pr-review + pr-revise to agent-ops@v0.2.0 by @vaderyang in #131
- dogfood: delegate leakage guard + bump triage/implement to agent-ops@v0.2.0 by @vaderyang in #132
- dogfood: remove in-tree agent-bot fallbacks (all surfaces delegated + proven) by @vaderyang in #133
- feat(console): three-theme redesign — Dark Observatory, Light Atelier, Kami by @vaderyang in #134
- feat(export): SFT trajectory export from agent turns/sessions by @vaderyang in #135
- fix(staging-soak): measure steady-state RSS growth, not warm-up by @vaderyang in #136
- chore(pr-review): bump agent-ops pin to v0.3.1 (diff-injection review fix) by @vaderyang in #137
- fix(deploy-prod): rebuild console bundle before cargo build (stale embedded UI) by @vaderyang in #138
- fix(deploy-prod): resolve bun via ~/.bun/bin fallback (non-login deploy shell) by @vaderyang in #139
- feat(console): default to Kami theme + refresh README screenshots in Kami by @vaderyang in #140
- fix(ci): gate self-hosted CI to same-repo PRs by @vaderyang in #143
- fix(storage): dialect-aware SQL literal escaping for the ClickHouse backend by @vaderyang in #142
- feat(capture): native eBPF SSL-uprobe capture (process attribution + static-binary targets) by @vaderyang in #141
- release: v0.5.1 — eBPF capture docs + VERSION/CHANGELOG by @vaderyang in #144
Full Changelog: v0.5.0...v0.5.1
Heron v0.5.0
[0.5.0] — 2026-06-04
Added — ClickHouse storage backend
- New
h-storage-clickhousecrate: a drop-inStorageBackendimplementation
backed by ClickHouse (HTTP interface, async serde RowBinary via the
clickhousecrate), selected withstorage.backend = "clickhouse". Mirrors
the DuckDB backend's full read + write surface. Fact tables useMergeTree;
agent_turnsusesReplacingMergeTree(_version)(FINAL reads; version-bumped
full-row re-insert forupdate_turn_metadata). Timestamps are
DateTime64(6, 'UTC')mapped toi64micros. Retention runs via lightweight
DELETEon the shared[storage.retention]schedule. - Backend-neutral logic (dimension-filter SQL builders, header/token-estimate
converters, the serving-software classifier) extracted from
h-storage-duckdbintoh-storage(dialect/convert/classify) and
shared by both backends — single source of truth. storage_benchbinary +scripts/bench-storage.sh(just bench-storage):
ClickHouse-vs-DuckDB write-throughput + read-latency comparison through the
identical workload. Findings + methodology in
docs/design/bench-clickhouse-vs-duckdb.md.- ClickHouse
query_servicesoptimised 46× (5129 ms → 112 ms at 1M rows): the
body-sampleROW_NUMBERwindow (which read every row's ~2 KB body columns)
became anid IN (… LIMIT N BY …)two-phase fetch;arrayDistinct(groupArray)
→groupUniqArray(N);quantileExact→quantileTDigest.
Fixed
- Agent-sessions
agent_kindmulti-select returned nothing. Selecting more
than one agent kind sent a CSV (claude-cli,codex-cli) that the sessions
query exact-matched as a single literal, so the list went empty; selecting one
kind worked. Fixed in both the DuckDB and ClickHouse backends. Root-caused
beyond the symptom:agent_kindis now CSV-parsed once at the API boundary
into aVec(like every other multi-select filter), so no storage backend
ever sees a raw CSV to mis-handle. - Agent classifier no longer flags unrecognized tool names as "suspicious".
Tools from non-Claude-Code agents (e.g.web_search,read_file,
memory_get) were tagged suspicious purely for being absent from a hardcoded
registry. Any named tool is now classified as a function-call surface; the
registry treadmill is gone.
Internal
- Perf/reliability gate for the release pipeline: a
rate_pps-throttled
pcap-file load-soak (tara --load) and criterion hot-path micro-benchmarks. - Deploy pipeline hardening: staging-soak stamps its
staging-soakedstatus via
the REST API (the runner has nogh), anddeploy-prodsupersedes older
waiting approvals instead of letting them pile up and wedge the queue.
What's Changed
- chore(rebrand): scrub residual TokenScope brand strings → Heron by @vaderyang in #72
- fix(storage): Phase-5 migration adds agent columns nullable (DuckDB compat) by @vaderyang in #76
- ci: move runner label tokenscope → heron by @vaderyang in #73
- pr-review: post_review.py downgrades APPROVE → COMMENT on heading-format drift by @vaderyang in #77
- check-leakage: also flag machine-specific username paths by @vaderyang in #78
- heron panics on shutdown: JoinHandle polled after completion (supervisor double-poll, exit 101) by @vaderyang in #80
- fix(llm): register AgentClassifier{Unknown,Mixed}Count on llm worker — stops silent capture loss (#81) by @vaderyang in #82
- docs: launch assets — README badges, technical blog, launch posts by @vaderyang in #87
- docs: warn that a bare cargo build ships a blank console (--features console) by @vaderyang in #83
- feat(staging): continuous auto-deploy to heron-stage VM (Quality Infra L6) by @vaderyang in #84
- ci(staging): add workflow_dispatch manual deploy to deploy-staging by @vaderyang in #89
- ci: bump test-job timeout 25→60m for the on-main artifact build by @vaderyang in #90
- chore(deps): bump DuckDB 1.5.1 → 1.5.3 (fixes checkpoint/ART bug behind the prod outage) by @vaderyang in #92
- feat(agent-bot): mara — prod observer that auto-files heron incidents by @vaderyang in #86
- fix(classifier): expand known-tool registry to current CLI inventory (#85) by @vaderyang in #93
- feat(h-llm): cap stored request/response bodies for 1M-token contexts (#68) by @vaderyang in #95
- feat(staging): tara soak runner — replay-invariant gate after deploy (L7) by @vaderyang in #94
- feat(prod): gated auto-deploy to production (deploy-prod — quality-chain tail) by @vaderyang in #97
- docs: add issue-filing guide + triage-gate explainer by @vaderyang in #98
- fix(classifier): unrecognized tool names are function calls, not "suspicious" (#85) by @vaderyang in #101
- feat(capture): pcap-file loop/duration replay mode (load-soak primitive) by @vaderyang in #99
- docs: scrub internal deployment specifics from pr-review-agent doc by @vaderyang in #100
- feat(mara): confirm-debounce — a deploy/restart blip no longer files a phantom incident by @vaderyang in #104
- chore(ci): run CI on dedicated
ci-poolrunner, off the agent pool by @vaderyang in #112 - feat(perf): tara load + memory soak — the pre-deploy perf/reliability gate (PR1) by @vaderyang in #106
- CI hygiene (§5): scrub internal CI backend model identifier from workflow + script comments (follow-up to #100) by @vaderyang in #109
- feat(storage): ClickHouse backend (drop-in) + storage benchmark by @vaderyang in #103
- CLIproxy 混合格式问题:OpenAI 请求 → Anthropic 响应,usage token 解析不到 by @vaderyang in #107
- feat(agent-bot): wiwi auto-revises on vivi CHANGES_REQUESTED (bounded loop) by @vaderyang in #113
- feat(perf): criterion hot-path micro-benchmarks + CI bitrot gate (PR2) by @vaderyang in #110
- chore(agent-bot): move auto-merge allowlists out of committed source by @vaderyang in #102
- ci(staging): stamp
staging-soakedcommit status — prod go/no-go signal by @vaderyang in #114 - agent-sessions: agent-kind 过滤把整段 CSV 当单值精确匹配,选中后列表清空 by @vaderyang in #111
- fix(staging-soak): stamp staging-soaked status with curl, not gh — unblocks ALL prod deploys by @vaderyang in #115
- refactor(filters): parse agent_kind CSV at the API layer (Vec), not in storage — root-cause fix by @vaderyang in #116
- fix(deploy-prod): supersede older waiting runs (cancel-in-progress: true) — kills the pile-up wedge by @vaderyang in #117
- chore(release): v0.5.0 by @vaderyang in #119
Full Changelog: v0.4.0...v0.5.0
Heron v0.4.0
[0.4.0] — 2026-05-29
Changed — Rebrand to Heron
- Project renamed TokenScope → Heron. The binary is now
heron
(wastokenscope); the 10 internal library crates moved from the
ts-*prefix toh-*; the GitHub repo is nowNetis/heron(the old
URL redirects). Console title, logo (a new heron mark), and all
install/docs URLs updated.
Added — Quality infrastructure
- Deterministic fault-injection harness for the DuckDB backend
(feature-gated) plus recovery tests that drive the FATAL → reopen →
every-surface-works path without relying on real load pressure. - Schema-migration tests over synthesized legacy DB shapes, locking the
auto-migration paths against silent regression. - CI lint gates: referenced-secret provisioning, secret-value sanity,
validated-constructor scoping, and an infra-leakage gate that fails on
any non-allow-listed private IP or private-key block in tracked files.
Security / privacy
- Removed the demo deploy tooling, which hard-coded a server address, a
jump-host username, and a plaintext password. Demo setup is now an
AI-agent prompt in the docs instead. - Scrubbed internal infrastructure identity (private IPs, hostnames)
from source comments, docs, scripts, and test fixtures; tests now use
RFC5737 documentation ranges.
Added — Agent-era observer (H002)
- Agent traffic classification: every LlmCall carries
is_agent_request,
tool_surface,agent_topology,tool_call_count,tool_names. Every
AgentTurn rolls uptool_surfaces,tool_call_total,agent_topology,
suspicious_skills. Newtool_surfacedimension onllm_metrics. - Console: agent-aware columns and filters on Agent Turns; Agent breakdown
section on turn detail; tool-surface facet on Performance. - Config:
[agent_classifier]block indefault.tomlfor tool taxonomy. - Internal metrics:
agent_classifier.unknown_count,
classifier_mixed_count.
Capture
- Default live-capture configuration now covers common LLM-serving ports,
reducing the need for explicit CLI capture filters in quickstart flows.
LLM wire-API support
- OpenAI Chat streaming now captures
delta.reasoning_contentand
delta.reasoning, with console rendering before normal content. - OpenCode agent profile detection added for clients that expose a stable
x-session-affinityanchor.
Agent turn tracking
- Generic fallback turn grouping now requires a tool/function-call anchor, so
text-only SDK calls stay on the LLM Calls page instead of producing
synthetic one-call Agent Turns.
Metrics
- TTFT handling now distinguishes streaming and non-streaming calls, with
stream-only TTFT charts and backfilled rollups from stored call data. - Dashboard active-resource history added for TCP connections and agent
turns. - Long-range chart axes use date-aware labels for multi-day windows.
Console
- Settings page added for capture sources, including interface discovery,
source editing, grouped source-type controls, and restart flow. - LLM Calls gained stream/non-stream filtering.
- List pages persist the selected item in the URL.
- Agent-kind filter options are derived from observed data in the active
window instead of a fixed list.
API
GET /api/capture/interfaceslists available capture interfaces.PUT /api/capture/sourcesupdates capture-source configuration and
restarts the process when needed.
Documentation
- README reframed around agent observability with refreshed screenshots.
- README quickstart now uses the default live-capture command and no longer
includes an explicit capture-filter example. - Removed the LLM call detail screenshot and its README reference.
- Removed project-origin/company copy from public docs.
Development
- Headless PR review workflow added for CI.
- Repository instructions now require PR text to scrub private environment
details before publication.
What's Changed
- feat(settings): in-app capture configuration + self-restart by @vaderyang in #12
- feat(dashboard): TTFT stream/non-stream split + rollup backfill + filters by @vaderyang in #13
- feat(dashboard): Active TCP Connections + Active Agent Turns charts by @vaderyang in #14
- fix(ts-llm/chat-sse): capture delta.reasoning_content + delta.reasoning by @vaderyang in #15
- feat(filters): dynamic agent_kind dropdown from actual data in window by @vaderyang in #16
- feat(ts-llm/agents): opencode profile keyed off x-session-affinity by @vaderyang in #17
- feat(console/list-pages): persist selected item id in URL by @vaderyang in #18
- feat(ci): headless PR review agent (phase 1) by @vaderyang in #28
- docs(README): reframe as agent observability + Playwright-driven screenshots by @vaderyang in #30
- Clean up README capture docs by @vaderyang in #32
- fix(pr-review): :4000 LiteLLM + auth secret + NO_PROXY + auto-merge trusted PRs by @vaderyang in #31
- fix(pr-review): drop dup no_proxy env key by @vaderyang in #33
- fix(pr-review): override inherited http_proxy so curl reaches LiteLLM by @vaderyang in #34
- fix(pr-review): keep http_proxy; only set no_proxy by @vaderyang in #35
- fix(pr-review): overlay reviewer scripts from default branch by @vaderyang in #36
- fix(pr-review): never APPROVE on agent failure / unstructured body by @vaderyang in #37
- fix(pr-review): feed prompt via stdin to claude --print by @vaderyang in #38
- feat(console): selected_at anchor recovers item window on stale shared link by @vaderyang in #19
- fix(pr-review): brand as "vivi"; never post failures to PR by @vaderyang in #39
- feat(console): TPS instead of TPOT, agent-turns column reorder, sidebar logo by @vaderyang in #20
- ci: opt all JS actions into Node.js 24 runtime by @vaderyang in #40
- feat(console/charts): x-axis tick adapts to time-range duration by @vaderyang in #21
- fix(console/agent-sessions): keep prior data during refetch (no flash) by @vaderyang in #24
- feat(api): lite mode for /calls — unblock mega-turn detail page by @vaderyang in #23
- feat: fold llmproxy duplicate turns by passive pair detection by @vaderyang in #22
- feat(services): Path view + Overview agent charts (deploy roll-up) by @vaderyang in #27
- Fix dynamic agent kind filters by @vaderyang in #29
- Fix generic agent turn grouping by @vaderyang in #41
- Revise unreleased changelog by @vaderyang in #42
- Update repository agent guidance by @vaderyang in #43
- Add local agent workflow skills by @vaderyang in #44
- Add agent-bot: issue triage + wiwi dev agent + auto-merge by @vaderyang in #45
- post_review: use ADMIN_GH_TOKEN for the admin-merge fallback by @vaderyang in #46
- Reject out-of-range time params; clamp SQL timestamp formatter by @vaderyang in #47
- pair_sweeper: CHECKPOINT after each batch + reopen on FATAL by @vaderyang in #48
- agent-bot: use AGENT_GH_TOKEN for the agent:try label fan-out by @vaderyang in #51
- ci: P0 lint gates for secret-ref + validated-constructor classes by @vaderyang in #53
- DuckDB FATAL recovery: rebuild every connection (closes #50) by @vaderyang in #52
- wiwi: drop PAT from actions/checkout; embed in push URL instead by @vaderyang in #54
- wiwi: bump timeout to 120m + stream claude output live by @vaderyang in #55
- wiwi: clear extraheader before push so PAT (workflow scope) wins by @vaderyang in #56
- ci: lint secret VALUES, not just references (catches the '-' bug) by @vaderyang in #57
- wiwi: enforce commit + add auto-commit fallback by @vaderyang in #58
- Rebrand → Heron (Phase 1: rename app binary tokenscope → heron) by @vaderyang in #59
- agent-bot: tolerate transient LiteLLM outages — pre-flight wait + mid-run retry by @vaderyang in #63
- ci: deterministic recovery + schema-migration tests (P1 quality infra) by @vaderyang in #64
- ci(pr-review): bump vivi agent + job timeout to 7200s/120min by @vaderyang in #67
- Rebrand → Heron Phase 2: rename ts-* library crates → h-* by @vaderyang in #66
- chore(rebrand+privacy): repo→heron, scrub infra leakage, leakage gate, heron logo by @vaderyang in #69
- fix(privacy): scrub internal IP left in test fixture (lost in #69 race) by @vaderyang in #70
- chore(release): 0.4.0 — Heron rebrand + quality infra + privacy by @vaderyang in #71
**Full Chang...