Skip to content

Expose generation-bound harness activity in live PTY status #129

Description

@myobie

Problem

DING needs an opt-in reliable answer to “may input be delivered now?” for long-lived agent PTYs. Current PTY state cannot distinguish an active model turn, an idle harness prompt, or a long-running tool/child command. Screen text, title churn, elapsed time, attached-client count, remote st2 presence, and durable event-log tails are not authoritative.

Core DING must remain harness-neutral and preserve its current aggressive behavior when no richer policy is configured. Codex/Claude-specific parsing belongs in optional adapters selected by catalog KDL.

Small generic contract

Add explicit daemon-live activity state and expose it through the existing STATUS response / queryStats() / pty stats --json:

activity: {
  state: "unknown" | "active" | "child_command" | "idle";
  generation: string;
  producerEpoch: string | null;
  sequence: number;
  turnId?: string;
  source?: string;
}
  • New daemon generation starts unknown; never hydrate authority from JSONL.
  • A local generic publisher claims a producer epoch, initially forcing unknown, then submits strictly increasing transitions. Reject stale epoch/sequence updates.
  • idle is accepted only from an explicit adapter/hook transition; never derive it from screen/title/time/presence.
  • Optionally append session_activity JSONL records for audit/fixtures, but live daemon state is authoritative.
  • The generic PTY publisher/read API contains no Codex or Claude schema knowledge.
  • Unconfigured DING keeps current aggressive behavior. A KDL-selected adapter uses this state and fails closed on unknown, unreachable daemon, generation change, or invalid transition.

Adapter comparison

  1. Hook publisher (preferred): Codex/Claude hooks translate turn/tool/prompt-ready transitions into the generic activity protocol. Lowest latency and no JSONL replay ambiguity. A Stop hook must not claim idle until the harness-specific input-ready boundary.
  2. Session JSONL adapter (fallback): external adapter tails Codex/Claude extension data and publishes generic transitions. It must bind file identity/session ID, handle compaction/truncation/clear/crash, claim a new epoch as unknown, and never replay an old terminal idle record as current authority.

Model-free acceptance tests

  • message during active turn is held;
  • message at explicit idle is eligible exactly once;
  • child_command remains non-idle despite silence;
  • compaction and clear do not synthesize idle;
  • adapter crash/epoch replacement resets to unknown;
  • daemon restart/new generation resets to unknown;
  • stale activity JSONL cannot authorize live input;
  • Codex and Claude fixture adapters produce the same generic state trace.

No deployment or harness-specific code in PTY core.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions