Skip to content

owner ticks aren't inspectable like playbook runs (no session id / transcript captured) #75

Description

@anshulsao

Problem

An owner tick runs a fresh headless claude but captures no session id and discards the model output, so there is no way to answer "what did the last tick actually do / why did it fail?" — unlike a playbook run, which has a pinned session id and a full transcript.

playbook run owner tick
invocation AutoRunArgv: claude --session-id <id> -p … SkipPermissionsRun: claude -p --dangerously-skip-permissions
session id ✅ pinned + recorded ❌ none (sessionless)
transcript ✅ jsonl on disk → flow transcript <task> ❌ none written
model output ✅ rendered cmd.Stdout/Stderr = io.Discard (runSkipPermissions)
status run task status + close-out sweep last_tick_status: ok/error/dead
audit trail full transcript + brief + updates only the journal note the tick writes

Today a tick captures only tick_pid, tick_started, last_tick_at, last_tick_status, and a owners/<slug>/ticks/<ts>.log that holds only flow's own supervisor prints — the actual claude run's stdout/stderr is discarded.

What we lose

  1. No replay of the orchestration decision — why a tick dispatched task X, or decided "nothing to do", is unanswerable.
  2. Opaque failures (sharpest loss) — on last_tick_status='error' the output is discarded, so the failure reason is gone.
  3. No per-tick token/cost attribution.

What softens it (why this is P2, not P1)

The tick's real work is orchestrated through tasks/playbook-runs (orchestrate-never-inline), and those each have a session id + transcript (inspectable via flow transcript / flow show playbook). So downstream work is auditable; only the thin orchestration tick itself is a black box. The journal note (owners/<slug>/updates/<today>-tick.md) is the intended human trail, but it's self-reported and may be empty on error.

Proposed fix

The "fresh session each tick" invariant does not require discarding the id — each tick can mint its own new session id (still fresh, never resumed) and record it:

  • Switch the headless tick from SkipPermissionsRun (discard) → a session-pinned headless run (like AutoRunArgv: claude --session-id <new-id> -p …).
  • Record last_tick_session_id on the owner row.
  • Surface it: flow transcript owner <slug> renders the last tick; flow owner show shows it.

Scoping

  • Minimal: pin + record last_tick_session_id, expose via flow transcript owner <slug>.
  • Fuller: a per-tick run record (session id + status + timestamp) shown as a "recent ticks" list in flow owner show, mirroring how playbook runs render.

Relevant code

  • internal/harness/claude/claude.gorunSkipPermissions (discards output), AutoRunArgv (the session-pinned pattern to mirror)
  • internal/app/owner_tick.goownerTickRunner, cmdOwnerTick, recordOwnerTick
  • internal/flowdb/owners.go — owner row (would add last_tick_session_id)

Context: surfaced while reviewing the owner harness (#71).

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