hermes-agent/docs/ink-env-flags.md
alt-glitch 4108fe6014 tui(diag): Ink 1Hz memwatch collector — OpenTUI-compatible memory trace
Ink had no continuous memory trace (only point-in-time heapdumps + a threshold
monitor), so HERMES_TUI_DIAGNOSTICS=1 gave OpenTUI dogfood data with no Ink
equivalent. Port OpenTUI's memlog collector to Ink so both engines emit
byte-identical ~/.hermes/logs/memwatch/<boot>-<pid>.jsonl traces feeding one
memwatch-report.mjs.

- lib/memlog.ts: 1Hz unref'd sampler, {t,rss_kb,heap_used_kb,external_kb}
  (no mounted — Ink has no windowing), 14-day prune, silent-disable on error
- gated by HERMES_TUI_MEMLOG defaulting to the HERMES_TUI_DIAGNOSTICS master
  switch (same as OpenTUI — one export covers both engines)
- wired into entry.tsx alongside the existing monitor; stop on beforeExit
- lib/memlog.test.ts: gate/schema/retention/silent-disable (7 tests)
- docs/ink-env-flags.md (new) + docs/opentui-env-flags.md updated
2026-06-15 15:58:02 +05:30

3.3 KiB
Raw Blame History

Ink TUI — diagnostic environment flags

Non-secret behavioral knobs for the Ink engine (ui-tui/). These are environment overrides, not .env secrets — set them in your shell for a session, or export them in your shell rc to make them sticky. They mirror the OpenTUI engine's flags (docs/opentui-env-flags.md) so a single switch covers both engines.

Flag Default What it does
HERMES_TUI_DIAGNOSTICS off Master diagnostics switch. Turning it on enables the developer/profiling surface across the TUI — including the memory self-sampler below. One export HERMES_TUI_DIAGNOSTICS=1 in your shell rc covers every session you start, on either engine.
HERMES_TUI_MEMLOG = HERMES_TUI_DIAGNOSTICS In-process 1Hz memory self-sampling (ui-tui/src/lib/memlog.ts) → ~/.hermes/logs/memwatch/<boot>-<pid>.jsonl. Defaults to the master switch; set =1 / =0 to force it on/off independently.

What the memory trace captures

Each Ink session, when sampling is enabled, appends one JSON line per second to its own file under ~/.hermes/logs/memwatch/, keyed by boot time + pid:

{"t":1781514892,"rss_kb":92148,"heap_used_kb":7234,"external_kb":2378}
  • t — unix seconds.
  • rss_kb — resident set size (the number that matters for the native-RSS-gap story: rss climbing while heap stays flat is the #15141-class signal).
  • heap_used_kb — V8 heap in use.
  • external_kb — off-heap (buffers, native allocations).

Ink emits no mounted / peak_mounted field. Those are OpenTUI's windowing dev counters; Ink has no windowing, so it logs the rss/heap/external core only. memwatch-report.mjs treats mounted as optional, so Ink lines aggregate cleanly alongside OpenTUI's.

Why this exists — cross-engine memory comparison

The filename scheme, directory, and line schema are byte-compatible with OpenTUI's collector (ui-opentui/src/boundary/memlog.ts). Both engines write to the same ~/.hermes/logs/memwatch/ directory, so one aggregator reads both:

# enable on either/both engines (master switch covers both)
export HERMES_TUI_DIAGNOSTICS=1
HERMES_TUI_ENGINE=ink     hermes --tui   # Ink session → its own .jsonl
HERMES_TUI_ENGINE=opentui hermes --tui   # OpenTUI session → its own .jsonl

# fleet table across BOTH engines' sessions:
cd ~/github/tui-bench && node memwatch-report.mjs

This is what makes a true side-by-side real-world memory arc possible — cold floor → load → plateau/leak — instead of comparing OpenTUI dogfood traces against an Ink harness with no equivalent data.

Cost & safety

  • ~50 bytes/s when on; one process.memoryUsage() + one short append per second. The interval is unref'd — it never keeps the process alive.
  • 14-day retention: older traces are pruned (best-effort) at start.
  • Every failure path disables the logger silently. Diagnostics must never break the TUI — this is the one place the "errors propagate" rule is intentionally inverted, matching the OpenTUI collector.
  • Off by default: regular users write nothing.

Getting a meaningful trace

A short scroll-through won't show growth. For a comparison against OpenTUI's 45h sessions, drive a tool-heavy 23h Ink session as the floor (see docs/plans/opentui-ink-asymmetry-note.md for why the harness ≠ dogfood data).