Skip to content

Add flowition-cockpit: a Claude Code plugin to watch and steer runs - #7

Merged
ben-vargas merged 50 commits into
mainfrom
feat/flowition-cockpit-plugin
Oct 10, 2026
Merged

ben-vargas merged 50 commits into
mainfrom
feat/flowition-cockpit-plugin

Conversation

@ben-vargas

Copy link
Copy Markdown
Owner

What

plugins/flowition-cockpit, a Claude Code plugin (terminal and desktop Code tab) that brings the viewer's essentials into Claude Code, and a root .claude-plugin/marketplace.json so this repository is its marketplace:

/plugin install flowition-cockpit --marketplace ben-vargas/flowition
  • Status line: flo · N running · M questions waiting.
  • /flo pane, run list: cards for runs launched in this session, live runs, and recent runs grouped by day (back-to-back runs of one workflow fold into one card). Filters (All / Live / Needs attention / Completed), search, and a New run form for ~/.flowition/workflows/.
  • Run view: tiles, a progress bar, answerable ask() questions, the result rendered as Markdown, and Agents / Timeline / Phases / Log / Structure tabs.
  • Agent threads: the live transcript (tool calls expand to input and output) with a composer to steer the agent.
  • Controls, each only from a press in the pane: answer, steer, cancel (confirmed), resume (run --resume --detach, the shared handoff marker), delete (rm, to the trash, confirmed), Tell Claude when done, Ask Claude, Open in viewer.
  • Auto-attach: runs Claude launches via Bash or the MCP tools open in the pane and toast on questions and completion.

How

Reads only through the CLI (runs/status --json) and the run directory's append-only files (events.jsonl, agents/<n>.jsonl, read incrementally by byte offset), and acts only through the CLI. No viewer process is needed; Open in viewer reuses a live one's URL via osascript stdin, so the token never lands in a process argument.

Desktop note: the pane's controls are drawn as Client regions, because the desktop's native plugin Button takes a first click as focus alone. A click trace confirmed that; the plugin README records it.

Scope and checks

  • New files only under plugins/ and .claude-plugin/, plus a README section, an Unreleased CHANGELOG entry and .gitignore lines for what Claude Code generates beside a loaded plugin. src/ and the npm package are unchanged (files doesn't list plugins/).
  • claude plugin validate passes for the plugin and the marketplace. claude plugin test plugins/flowition-cockpit: 25 tests, each UI test run on both the terminal and desktop surfaces. The root suite passes (548).
  • Exercised by hand in the desktop Code tab against real runs: cards, controls, threads, timeline, phases, resume of a failed run, and the wake prompt.

A status line and a /flo pane that bring the viewer's essentials into Claude
Code (terminal and the desktop Code tab):

- Run cards: launched here, live, and recent grouped by day, with back-to-back
  runs of one workflow folded; filters (live, needs attention, completed) and
  search; a New run form that starts a workflow from ~/.flowition/workflows.
- A run view: tiles, a progress bar, answerable ask() questions, the result
  as Markdown, and Agents, Timeline, Phases, Log and Structure tabs.
- Live agent threads (transcripts read incrementally by byte offset) with a
  composer to steer the agent.
- Controls, each only from a press in the pane: answer, steer, cancel
  (confirmed), resume (run --resume --detach, the shared handoff), delete
  (rm, to the trash), Tell Claude when done, Ask Claude, Open in viewer.
- Auto-attach to runs the session launches through Bash or the MCP tools.

It reads only through the CLI and the run directory's append-only files and
acts only through the CLI; no viewer is needed. On the desktop, controls are
drawn as Client faces, since the native plugin Button takes a first click as
focus alone.

The repository root becomes a plugin marketplace (.claude-plugin/
marketplace.json): /plugin install flowition-cockpit --marketplace
ben-vargas/flowition. The npm package is unchanged.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-09T18:33:46.227473Z 4105ff3 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 76cc047746

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/flowition-cockpit/hooks/register.tsx Outdated
Comment thread plugins/flowition-cockpit/hooks/register.tsx Outdated
…n end

Addresses the two Codex review findings on #7.

- The timeline (Timeline, Phases, Log, Structure) was built from one grep of
  events.jsonl through $.process.run, whose stdout is capped at 4 MiB: a
  large run's read could be cut short and then cached against the file's
  full size, so a finished run stayed incomplete for good. events.jsonl is
  now read from where the last read stopped, in chunks of at most 2 MiB
  (well under the cap, and a truncated read is never folded), through its
  last complete line, and folded into the timeline already held
  (foldTimeline). A large run catches up over a few polls with a progress
  note; a live run costs only its growth. Verified on the largest local run
  (1.2 MB, 33 lanes): 64 KiB chunks fold to exactly the one-shot result.
- A reload clears the cached run details but keeps the "Tell Claude when
  done" arming; a run that finished before the first post-reload poll was
  first seen already ended, so hasEnded() never fired and Claude was never
  told. shouldWake() now also wakes an armed run whose first look finds it
  ended (an armed run can only be in that state once it has finished).

Tests: incremental fold equals one-shot fold at every cut point; the wake
rule's cases. 27 pass.
@ben-vargas

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6be33925a3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/flowition-cockpit/hooks/launch-view.tsx Outdated
Comment thread plugins/flowition-cockpit/hooks/register.tsx Outdated
…s mid-render

Addresses the second round of Codex review findings on #7.

- New run listed only the newest 20 workflow files, so older ones could not
  be launched from the pane. The form now has a filter (by project/name)
  once there are more than 10, and a Show more that adds 20 at a time.
- The desktop's face handlers were cleared outright once the registry held
  more than 500 keys, which could happen in the middle of a render and leave
  faces that render had already drawn with no handler until the next redraw.
  Each handler is now stamped with the render that registered it, and the
  registry is pruned in that render's finally block, keeping the last two
  renders' handlers, so nothing a render draws loses its handler.

Tests: 25 extra workflows exercise the filter and Show more on both
surfaces; controls still answer their first press after repeated redraws.
@ben-vargas

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3ab7cd2948

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/flowition-cockpit/hooks/register.tsx Outdated
Comment thread plugins/flowition-cockpit/hooks/lib.ts
Comment thread plugins/flowition-cockpit/hooks/register.tsx Outdated
Comment thread plugins/flowition-cockpit/hooks/register.tsx
Comment thread plugins/flowition-cockpit/hooks/register.tsx Outdated
- A status over $.process.run's 4 MiB cap (a huge result) made every poll
  throw, so the run's end never toasted or woke Claude. readStatus() parses
  the output whole, or, when it is cut or unreadable, reads the run's state
  off its head ({"runId":…,"state":… comes first) and keeps the rest of the
  last good poll, with a note that the result is too large for the pane.
- Cost now sums every attempt: each attempt's final agent event carries that
  attempt's usage, which the timeline fold adds up per lane (status --json
  folds only the last). The selected run's timeline is kept on every tab
  for this. On three real runs, a resumed one among them, the totals match
  the journal sums the viewer uses to the cent.
- The attach-the-next-run fallback is armed only by a Bash launch Claude Code
  backgrounded, never by a failed launch or an MCP error.
- An ended run's unanswered ask() is shown as abandoned, with no Answer
  field, and no longer counts as waiting in the list, its filter or subtitle.
- Runs launched in the session stay attached for the whole session (the cap
  of 20 dropped the oldest, live or not, and with it their toasts).

30 plugin tests pass.
@ben-vargas

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: aff37ec903

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/flowition-cockpit/hooks/register.tsx Outdated
Comment thread plugins/flowition-cockpit/hooks/lib.ts Outdated
…-result

Addresses the fourth round of Codex review findings on #7.

- A single events.jsonl record longer than a read chunk was skipped by
  advancing a fixed byte count, so the next read began mid-line, possibly
  mid-character, and re-measuring decoded text (U+FFFD) let the offset drift:
  the cache could be rejected and the file refolded every poll, or records
  skipped or folded twice. The reader (now catchUpTimeline in lib.ts, the
  process runner injected) only ever starts a read on a line boundary and
  folds through its last newline. A line longer than a chunk has its byte
  length measured raw (awk under LC_ALL=C) and is read whole up to 3.5 MiB,
  or stepped over exactly with a note in the Log tab beyond that.
- deriveRunState reports a malformed result.json as `corrupt-result`; the
  pane matched only `corrupt`. It now colors it as an error and counts it as
  needing attention.

Tests: a byte-accurate fake runner checks odd chunk sizes that split
multibyte characters fold to exactly the one-shot result, an oversized line
read whole or stepped over exactly, and a half-written last line left for
the next poll. Against the real tail/head/awk on macOS, 257-byte chunks over
a 61 KB file of multibyte text consume every byte and match the one-shot
fold. 34 plugin tests pass.
@ben-vargas

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6205b6ca72

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/flowition-cockpit/hooks/register.tsx Outdated
Comment thread plugins/flowition-cockpit/hooks/register.tsx Outdated
Comment thread plugins/flowition-cockpit/hooks/register.tsx Outdated
…ways reconciled

Addresses the fifth round of Codex review findings on #7.

- Output: while a resumed run is live, the engine's spentOutputTokens is the
  new attempt's counter, so preferring it dropped the tile below the run's
  lifetime total. Each agent's tokens are now its finished attempts' (from
  events.jsonl) plus the live attempt's so far, and the tile sums those.
- Wake: an armed run whose cached detail was already terminal (armed while
  the completing poll was in flight) was never polled again, so it stayed
  armed forever. Armed runs are now polled until a poll disarms them, and an
  armed run wakes whenever a poll finds it no longer live.
- Phase: status --json folds every attempt's phase events, so a resumed
  two-phase run read "Phase 4". The tile now shows the phase the run last
  entered, from the timeline (which keeps one entry per phase index).

35 plugin tests pass.
- F1: a cached terminal detail was never re-polled and overwrote the fresh
  listing, so a run resumed elsewhere kept showing its old state. Runs whose
  cached detail the listing contradicts are now polled again, and only a
  detail read in the current poll may correct the listing.
- F2: a drag that left a desktop control before release still pressed it
  (captured moves arrive from outside without a leave). Faces now cancel on a
  captured move outside the region and require the release inside, with a
  cell of slack for the desktop's edge mapping.
- F3: a failed transcript or timeline read jumped past the wake step. Wakes
  and toasts now go out first, and each optional read is isolated.
- F4: a runs listing cut at the 4 MiB cap (or failing) threw before any
  status poll. The listing keeps its complete rows (newest first), a failure
  keeps the last list and is reported, and watched runs are still polled.
- F7: renders were counted across surfaces, so terminal redraws pruned the
  desktop's face handlers. Handlers and their pruning are keyed per surface.
- F5: fan-outs nested in different pipeline stages merged into one container;
  the stage is now part of a container's identity.
- F6: a resumed agent's tokens counted its last attempt twice until new
  progress arrived; the live attempt's count is added only once its output
  postdates the attempt's start.

hooks/review.test.tsx holds integration regressions for F2, F3, F4 and F7
(each fails on the previous commit), and lib.test.ts unit tests for F1, F4,
F5 and F6. 43 plugin tests pass.
- F1: a resume that ended in the same state as the cached detail (failed,
  then failed again) was never re-polled. A cached terminal detail is now
  read again when its events.jsonl has grown since the last read (a resume
  appends to it) or when a minute has passed.
- F2: the drag-off check allowed a cell of slack, so a release at x = -1
  still fired a confirmation. Faces now follow ClientPointerEvent exactly: a
  negative cell, or one at or past the laid-out size, is outside.
- F8: one run's status command rejecting (denied, unstartable, timed out)
  aborted the whole poll. Each run's status is now isolated.
- F9: picking another workflow kept the previous workflow's args, unseen
  behind the new, empty field. A different pick now starts from empty args.
- F10: tool results were paired by a global id map, so a resumed attempt
  reusing a synthesized id (pi's t1-tool1) took an earlier call's output.
  pairToolResults pairs in transcript order within an attempt.

hooks/review.test.tsx gains six round-2 regressions, F1 through the real poll
timer (a started session on the mocked clock); each fails on the previous
commit. 49 plugin tests pass.
- F2: a face fired on any release inside it, even with no press there first
  (a stray up after another control's press). A face now presses only on a
  left release that ends its own left press inside it, and the press is
  consumed, so a repeated release fires nothing.
- F6: when the final status was too large to read, the cached worker stayed
  "running" and its live count was added on top of the events' final usage.
  A live attempt's tokens are added only while the run is live and the lane's
  attempt is unfinished and has produced output since it started.
- F11: an older timeline (events.jsonl reads failing) replaced newer status
  spend with a smaller total. A finished attempt status reports past anything
  the lane has read is added from status, and the run view says when the
  events could not be read.
- F12: on a run no longer live, work still marked running/queued is shown as
  interrupted (cards, phases, timeline, structure), and a phase holding it is
  interrupted, not running.
- F13: a wake prompt refused (dropped, or the call rejected) was lost; it is
  now re-armed and tried at the next poll, up to three times, then the person
  is told. A run disarmed while the completing status was in flight is not
  woken: the wake list is re-read just before submitting.

Seven round-3 regressions added to hooks/review.test.tsx (six fail on the
previous commit; the disarm-in-flight one guards existing behavior). 56
plugin tests pass, and the reviewer's own round-3 reproduction file passes
in full against this commit.
- Spend: an unread attempt is matched to its terminal event (the lane's last paid
  terminal), not timestamps alone; cached replays add nothing; a resumed attempt's
  live output counts once the events have not shown it start.
- Wake: only a final run state (completed, failed, interrupted, stale, corrupt,
  corrupt-result) wakes Claude; an unknown detached launch stays armed and polled.
- Run list: a history over the 4 MiB read is filtered through node to every
  unfinished run plus the newest 2,000, and the list says what it leaves out.
- Agent thread header shows abandoned work as interrupted, with lifetime spend.
- Spend: a finished attempt counts its final usage (usage: null spends nothing), not
  the progress counter status keeps from an earlier attempt.
- Run list: the filtered long-history listing is written to a private temp file and
  read back in chunks, so no number of unfinished runs is cut off; what the pane keeps
  is bounded for $.state's 4 MiB (live and this session's runs first), and the list
  says when anything is left out.
- Oversized status: re-read without the result's value so workers and totals show on
  first open; with no whole status, the agents come from the run's events, and an
  unknown set shows as unknown rather than 'No agents yet'.
- A detail not read whole (a placeholder, or a status too large with no slim re-read)
  is marked partial, and its workers are reconciled with the run's events: new
  agents appear, states follow the lanes, spend comes from the lanes alone.
- The detail cache is bounded for $.state (the run on screen and watched runs
  first), text fields are clipped at parse, and a refused state write no longer
  holds back toasts or completion wakes.
- Drawing budgets: the agent thread draws its newest events within a budget and
  says what it leaves out; Agents, Timeline/Phases/Structure and Log draw within a
  budget, so a run's controls always draw; long errors and labels are clipped.
- An ended run keeps the output its abandoned (interrupted) agent was known to make.
- The long-history filter keeps this session's runs however old, and a listing not
  read whole keeps their last known rows.
@ben-vargas

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ff013c3252

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/flowition-cockpit/hooks/register.tsx Outdated
The viewer's control bridge treats completed as resumable (RESUMABLE_STATES): resuming
a completed run replays every finished agent from the journal. The cockpit now offers
that as Replay… with its own confirmation copy, through the same run --resume --detach.
@ben-vargas

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c70c326a58

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/flowition-cockpit/hooks/lib.ts Outdated
Comment thread plugins/flowition-cockpit/hooks/register.tsx Outdated
… tab

- A resumed run asks an unanswered question again under the same qid: a run coming
  back from an end has asked nothing yet, so its questions toast again.
- The Phases tab draws each phase's rows within the tab's text budget and says how
  many it leaves out, so the run's controls always draw.
- Attaching a run resets its notice baseline to a fresh placeholder: a question or
  end a poll saw while the run was not watched is still announced once.
- A crashed attempt's last known output (its progress) stays spent when a resume
  starts a new attempt; final usage still replaces it when an attempt ends.
- Resume falls back to the journal's metadata for the workflow file when the run's
  first event names none (a run that failed before it started); only the file is read.
- A tool call left without a result by an earlier attempt shows as interrupted, not
  running, while a later attempt runs.
- Attachment generations: every attach (launch, resume, re-attach) takes a new
  generation, and a poll that began before a run's generation neither writes its
  detail nor raises its notices or wake, so a resume's fresh baseline holds.
- Each backgrounded launch is tracked on its own and matched to its own new run, so
  two launches before the next listing both attach.
- The run id comes from the CLI's own lines in the order written (detached launch,
  event lines, the run line, a --json envelope), so a workflow result printed after
  them with a runId field is never taken for the run.
- An agent a resumed run has not taken up again (not among the engine's live agents,
  or its attempt began before the run's latest start) shows interrupted, with no Steer
  or Cancel.
- A refresh takes its attach generation when it begins, before its listing, so a
  run attached during the listing keeps its baseline too.
- A backgrounded launch records the runs already listed and its workflow file, and
  takes only a run created after it began, not listed before it, preferring its file.
- Every run a launch's output names is attached (a command may launch several), at
  most as many as the command launches, from the CLI's own lines only.
- Timeline, Phases and Structure lanes of abandoned work (an ended run's, or an
  earlier attempt's a resume has not taken up) show interrupted and stop at their last
  sign of life.
- Svg and Input are chosen by the surface's declared element table, not by a name
  being present (the engine fills every table with stand-ins): the terminal now draws
  its text status badges and timeline bars instead of invisible Svg.
- A launch's already-listed runs are captured before the command runs, so a poll that
  lists the launched run while Bash is still running cannot exclude it.
- Every resume a command names is attached (compound commands), and each new run whose
  id the output lacks gets its own pending record.
- A queued lane's waiting span honors its end, so abandoned queued work stops too.
- A backgrounded launch that names its workflow file takes only a run of that file;
  an unrelated new run never consumes it (a file named through the shell takes any).
- Backgrounding is read from Bash's own record (backgroundTaskId: explicit, timeout,
  Ctrl+B, message delivery) instead of one presentation message.
- Run ids are read from Bash's whole stdout as well as the model's text, and a --json
  envelope cut short (a large result Bash persists) still names its run from its head.
- Auto-attaching another run leaves the previous run's agent thread, steering and
  pending confirmations, as select() does.
- attach() takes its generation before anything it awaits, and a poll judges late
  attachments afresh wherever it decides: inside its cache update (retries included)
  and at each notice and wake, so a resume during a commit keeps its baseline.
- Launch commands are read as shell words (quotes, escapes, operators) with the CLI's
  own option grammar: option-first commands and quoted paths name their workflow; a
  flowition word that is not the command (echo …) is no launch; a shell-expanded file
  matches any new run.
- Every new-run launch Bash or the shell (`… &`) backgrounded keeps a discovery record;
  runs the output named are attached already and skipped, and unmatched records expire.
- A run whose attach() is still writing its baseline is treated as attached late by
  any poll that begins meanwhile, so the poll cannot overwrite that baseline.
- A backgrounded command's records are reconciled with the runs its output named: once
  listed, each named run takes back the record of its own workflow file, and until then
  the command's records match nothing, so no record is left to take another session's
  run of the same workflow.
- Launch commands read like the shell: backslash-newline continuations vanish, and
  node/bun/npx/nohup wrappers (with their options) are looked through; launch detection
  and launch reading are one parser.
- Launch commands are read from the shell's structure: simple commands within
  and-or lists, pipelines, subshells and compound commands (if/while/for/{ }); '&'
  backgrounds its whole and-or list, groups and pipelines included; a heredoc's body
  is data, not commands; a redirection's '&' (2>&1, &>) is no background.
- A named run reconciles with its command's records only once listed with its
  workflow (not the pre-journal '?'), and first accounts for a foreground launch of
  its own workflow before taking back a backgrounded one's record.
- A resume read off the command line attaches only on evidence it ran: the run turns
  live having not been, or its events grow after the command (a branch that never ran,
  or a refused resume, attaches nothing).
- Every run the output's own CLI lines name is attached, however many (a loop runs
  more launches than the command text shows).
- Named runs reconcile exact workflow matches before shell-expanded wildcards.
- A reached phase with no agents reads as current while the run goes on (waiting on an
  answer), done once a later phase is reached or the run completes.
- A resume attaches on evidence of a new attempt only: the run turning live having not
  been, or a run started/resumed event written after the command; an attempt already
  running that keeps logging progress is no evidence.
- After a foreground run's `run <id>: <status>` line its result follows: a JSON line
  carrying only a status, or a run line the CLI did not set off with a blank line, is
  result text and names no run; loops still name each run (blank-line framing, event
  lines, detached envelopes).
- Phase progression is the current attempt's: a later phase reached only by an earlier
  attempt is not counted as passed.
- A reload keeps each watched run's notice baseline (its state and question
  identities, read from any cached shape) while still dropping the display caches, so
  a run that ended or asked during the reload is announced once.
- A foreground --json run's whole outcome line (exactly runId, status, result|error)
  names its run even after another run's result; other JSON in a result still does not.
- A resume's 'was it live' baseline is read fresh (status) just before the command; a
  state that cannot be read is no evidence.
- A new attempt clears the current phase, so the previous attempt's phase is not shown
  as current before the new one enters any.
- A status JSON line inside a foreground run's result region is doubtful: the next
  --json launch's outcome (with or without a result) or the result's own text, which
  the bytes cannot tell apart. It attaches only on evidence: listed as a run created
  since the command began. A report naming an existing run attaches nothing.
- With the run's events read, the Phase tile shows the current attempt's phase only,
  none before the attempt enters one (not the CLI's accumulated phase history).
- A doubtful id (status JSON in a foreground result region) attaches only as one of the
  command's own launches: a new run not listed before the command, created since, of a
  workflow among the command's new-run launches that the runs its output named do not
  already account for. A single report workflow has no unaccounted launch, so nothing
  its result says attaches.
- Accepting a doubtful id consumes the background-discovery record kept for its launch.
- A failing exit (a workflow that fails exits 1 after its outcome) no longer discards
  doubtful ids or pending resumes; they are judged on their own evidence.
A backgrounded launch keeps its discovery record even when the enclosing Bash call
exits unsuccessfully (`… & wait` on a workflow that fails, a later command in the list
failing); the record still takes only a new run of its own workflow.
The new-run form reads the session's folder each time it opens and pins it to that
form: the form names it, and Start passes it as --cwd, so a full-permission run never
runs somewhere other than the folder the confirmation names.
An answer field is keyed by its run and its question event, not the qid alone: a draft
typed for one run's q0 can never stay in, and be submitted through, another run's q0
field after the pane switches runs (auto-attach, navigation) or the question is asked
again.
The new-run form's args field is bound to the form's args (value), the args Start and
Enter launch with: after switching workflows and back, or reopening the form, the field
shows exactly what will run, never a draft the surface kept that the launch would drop.
A launch from the new-run form that fails (invalid JSON, or the CLI refusing) draws the
args field afresh under a new key, showing the args the form still holds: a surface that
cleared the field on submit shows them again, and a retry launches exactly what is shown.
@ben-vargas

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

…andling; consolidate tests

Auto-attach now reads the run ids the CLI prints (stopping at a foreground run's
result), attaches the runs a command resumes, and gives each backgrounded launch the
next new run of its workflow. The shell-structure parser, doubtful-id bookkeeping,
evidence-checked resumes and loop/compound accounting are gone; a run it does not pick
up still shows under Live.

Oversized output gets one guard each: a run listing cut at the stdout cap shows its
newest rows with a note, a status too large to read keeps its state, the details cache
keeps watched runs (as state and questions when too large), and the timeline drops its
fan-out paths when needed. The node filter programs and temp-file listing are gone.

Resume/Replay now starts once per press; the pane shows Resuming... meanwhile.

Tests: the 22 per-round files become attach, notices, display and controls on one
shared kit; tests for removed machinery are dropped. 244 tests pass.
…d padding too

The desktop draws a face's border and padding around the cells it counts (a chip is
one row), so a click on a chip's lower half reads row 1 and was rejected as outside.
A down delivered with nothing captured is now always on the face; a captured move or
release is off it only past one cell beyond the counted region.
@ben-vargas
ben-vargas merged commit 4e8e4fc into main Oct 10, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant