Skip to content

feat: persist last PTY output timestamp - #168

Merged
schickling merged 3 commits into
mainfrom
schickling-assistant/session-activity-stamp
Aug 29, 2026
Merged

feat: persist last PTY output timestamp#168
schickling merged 3 commits into
mainfrom
schickling-assistant/session-activity-stamp

Conversation

@schickling-assistant

@schickling-assistant schickling-assistant commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Problem

st2 needs launcher-agnostic coarse session activity for every managed PTY. Existing PTY surfaces are unsuitable:

  • scrollbackUsed is bounded and saturates, so deltas fail on long sessions;
  • pty events is sparse and semantic, not an output stream;
  • pty stats --json measured 520ms/60 sessions (~5.5s projected at 627) and includes resource probes the consumer does not need.

The PTY daemon already processes every output byte to maintain terminal state. It is the unique lowest-cost observer.

Goal

Persist when each session last emitted output, with bounded write amplification and no launcher/harness coupling, so readers can derive activity directly from session metadata.

Decisions

  • Stamp lastOutputAtMs in the existing ptyProcess.onData path: O(1), no new observer.
  • Persist through the locked metadata mutation with a 1s trailing debounce: ≤1 write/s per busy session.
  • Use unix milliseconds (not RFC3339 text): st2 freshness/wire semantics already use ms, avoiding parser dependencies and reducing cross-language cost.
  • The field is evidence only; PTY does not classify active/idle.

Verification

  • npm run typecheck — green.
  • npx vitest run tests/output-activity.test.ts tests/disk-layout-docs.test.ts — 9/9 green, including immediate output followed by exit carrying the final stamp.
  • Full suite: 1609 passed; remaining screenshot/completions/zsh failures reproduced on pristine main (environment/baseline, unrelated).
  • nix build .#pty --no-link — green: /nix/store/y4c3pnafcpmgsa289znrx15qf45vljzf-pty-0.1.0.

VRS

With explicit user authorization, docs/vrs/requirements.md adds R14 (protected requirement): optional unix-ms evidence, absence-before-output, ≤1 metadata write/s during output, final exit persistence, and no activity/liveness interpretation. spec.md defines the exact algorithm and validation matrix; docs/disk-layout.md carries the public record contract. axe vrs check --profile strict docs/vrs is green.

Complexity

One optional metadata field and one per-session debounce flag. No new process, event vocabulary, stream, or background loop.

Concerns

A continuously chatty session performs one small locked metadata write per second. The bound is explicit; st2 consumes the file directly and never asks PTY to classify state.

Friction & bottlenecks

  • branchy new --carry-changes failed against unrelated dirt in the canonical main worktree; created a clean worktree instead.
  • Full tests depend on ambient vim/nano/zsh and contain load/environment failures; focused tests and Nix build are green.

Follow-ups

References

Posted on behalf of @schickling
field value
agent_identity unknown
agent_persona generalist
agent_supervisor unavailable
agent_tool OMP
agent_tool_version 18.0.3
agent_runtime OMP 18.0.3
tooling_profile dotfiles@e4789b0

The daemon already parses every PTY output byte (that is how the
terminal buffer exists), so recording WHEN output last happened is O(1)
in the existing onData path — no new observation machinery. The stamp
persists to the session metadata the daemon already maintains, through
the locked metadata mutation, debounced to at most one write per second
per busy session.

Consumers (st2's observed harness state) derive session activity from
the persisted field instead of observing output streams themselves:
one field, one writer that already sees everything, one reader.
Activity is an activity signal only — deliberately not liveness or
delivery.
Use lastOutputAtMs rather than RFC3339 text: st2's freshness and wire
contracts already use unix milliseconds, so the numeric scalar avoids a
time-parser dependency and is cheaper for every cross-language reader.
Add the user-confirmed R14 contract, exact daemon/debounce/exit-flush
mechanism, and validation-matrix ownership. Extend the integration proof
with immediate-output-then-exit durability.
@schickling
schickling merged commit f990e38 into main Aug 29, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants