Skip to content

feat: native subagent & workflow observability - #5219

Merged
t3dotgg merged 42 commits into
mainfrom
t3code/native-subagent-observability
Aug 6, 2026
Merged

feat: native subagent & workflow observability#5219
t3dotgg merged 42 commits into
mainfrom
t3code/native-subagent-observability

Conversation

@t3dotgg

@t3dotgg t3dotgg commented Aug 2, 2026

Copy link
Copy Markdown
Member

Problem

When a thread spawns subagents, runs a workflow, or drives Codex collab agents, the UI showed nothing useful: subagent tool calls and narration interleaved anonymously into the parent chat, progress ticks spammed the work log, background shells masqueraded as agents, the sidebar showed no status once the turn settled, and Stop only killed the parent turn while the fleet kept burning tokens.

Spec (final, decisions locked): https://n0hbggyouhn1.postplan.dev

image

Solution

Surface agents using only native provider emissions on the current orchestrator — no dependency on orchestrator v2 (#2829), zero migrations, zero new tables. Widened task.* activity payloads ride the existing event-sourced activity path; a client-side fold in client-runtime derives orchestration-v2-shaped subagent state (field names match #4779, so the v2 merge is a mapper swap).

Server

  • Contracts: additive TaskAgentLinkage on all task payloads (role, model, workflow name/phases, run handles, output file, owning agentId), new task.updated event, typed usage, tool attribution (agentId/parentToolUseId)
  • ClaudeAdapter: carries previously-dropped fields, handles task_updated, resolves parent_tool_use_id on tool events, keeps subagent narration out of the parent transcript (leak + Working-timer-reset fix), attributes subagent-internal shells to their owning agent, defensive workflow_progress parse, Workflow run handles
  • Codex: registers multi-agent-v2 children from thread/started/subAgentActivity (root-thread guard from live probe), intercepts child notifications, synthesizes the same task.* lifecycle (idle = resumable, cumulative usage, real names from agentPath)
  • Stop-everything: interrupt stops every live Claude task (Query.stopTask) and interrupts every live Codex child turn before the parent turn
  • Sidebar liveness: ThreadBackgroundLivenessService (in-memory, no persistence) exposes backgroundLiveness: working | monitoring on the thread shell — fleets read Working, watch loops read Monitoring
  • orchestration.getWorkflowScript RPC with TOCTOU-safe containment (open-then-verify inode, realpath under ~/.claude/projects, .js-only, size cap)

Web

  • Agents right-panel surface (the only roster): live workflows as bordered sections with a phase rail (per-phase segments with member status dots) and collapsible phase sections (live open, done collapsed); flat agent rows (no unfold); settled runs collapse to one line under "Earlier"; {} script opens a read-only script view
  • Spawn CTA row in chat: one anchored row per workflow run / direct-spawn batch, exempt from turn folds and overflow, membership pinned at first row (parallel-batch fix), coordinator status authoritative for workflows
  • Quiet timeline: agent-attributed tool rows re-homed to the panel, timelineBypass rows fold into the CTA, background shells stay ordinary work-log rows
  • All in-flight states present as Working (monitoring-pill rule); idle presents as settled

Mobile: same quiet-timeline fold; task.completed kept as terminal signal.

Verification

  • client-runtime: 30 fold tests (identity/activations, usage merges, bounds, cascade, nested agents); web: 1772 incl. quiet-timeline fixtures built from real persisted threads; server: adapter/ingestion/liveness/script-containment suites incl. a symlink-escape test and a stop-everything test
  • Live-tested over multiple rounds: Claude direct spawns + workflows (incl. 10-parallel), Codex collab fleets (10 agents), rerun workflows, monitoring threads — each round's findings fixed against exported wire/DB data

Remaining gaps

  • Codex fixtures should be generated from the captured wire logs (three schema-vs-wire divergences were found live)
  • Settled Codex rows show "assistant message" filler instead of a result summary
  • Script viewer is plain <pre> (no Shiki)
  • Mobile has only the timeline fold, no Agents sheet yet
  • Deferred by design: approval deep-links, transcript drill-in, forwardSubagentText/agentProgressSummaries off

🤖 Generated with Claude Code (Claude Fable 5)

Note

Add native subagent and workflow observability with an Agents panel, background liveness banner, and spawn CTA rows in the chat timeline

  • Adds a new Agents right panel surface (AgentsPanel.tsx) showing live status, elapsed timers, and activity text for each subagent or workflow member.
  • Introduces a background liveness banner in the chat view with a pulsing dot and Stop button when background work is detected via the new ThreadBackgroundLiveness service; sidebar rows show 'Working' or 'Monitoring' pills accordingly.
  • Adds spawn CTA rows to the chat timeline that collapse multiple subagent/workflow lifecycle entries into a single row with status, token count, and an affordance to open the Agents panel.
  • Enriches the Claude and Codex adapters with task.updated and tool.progress event emission, stable per-task activity IDs, agent linkage fields (agentKind, agentId, toolUseId, runHandles), workflow member coalescing, and interrupt-all-live-tasks behavior on turn stop.
  • Adds a getWorkflowScript WebSocket RPC backed by a TOCTOU-safe reader that serves .js files under ~/.claude/projects up to 256 KiB with structured error reasons.
  • Risk: RIGHT_PANEL_STORAGE_VERSION bumps from 7 to 8, invalidating persisted right panel state for existing users; task.progress activity IDs change from event-scoped to stable per-task IDs, which may affect clients that stored or compared those IDs.

Macroscope summarized f7673f3.

Dispositions (review round, explicit)

  • Spec divergence — accepted. The linked spec predates seven rounds of live testing. The rich inline workflow card, live strip, and expanded activity rows were built, tested live, and deliberately replaced by the single spawn CTA + Agents panel ("too much at once" — live-test decision). The spec link stays for design history; this description is the source of truth for what ships.
  • Mobile — accepted tradeoff for this PR. Mobile gets the quiet timeline and preserved terminal signals (Claude task.completed, Codex terminal task.updated, nested-agent terminals) but no Agents surface yet. Live fleets are less visible on mobile until they settle. The read-only mobile Agents sheet is the tracked fast-follow.
  • Script RPC scope — accepted with containment. getWorkflowScript takes threadId but does not yet verify the path against that thread's recorded runHandles (that registry is Orchestrator v2's read model; this PR is zero-migration by design). Access is bounded to the local paired user's own ~/.claude/projects (realpath re-containment, .js-only, TOCTOU-safe open, size cap). Thread-scoped verification is a small follow-up once v2's projection lands.
  • Event-rate bound. Workflow member fan-out is coalesced by a material-transition filter (emit only when a rendered field changes), and progress activities upsert under stable thread-scoped ids — worst case per coordinator tick is now proportional to changed members, not fleet size.

Note

High Risk
Touches provider adapters, runtime ingestion, interrupt/stop paths, and Codex child-notification routing—security-sensitive file read RPC and behavior changes that can hide or mis-route live agent signals if classification drifts.

Overview
Adds end-to-end subagent and workflow observability on the existing activity stream: ingestion stamps agentKind and linkage on task.* / tool rows, uses stable thread-scoped progress ids so ticks upsert instead of flooding retention, and maps Claude task_updated plus Codex collabAgent/* into shared task.updated / bypassed terminal updates.

Server behavior changes: ThreadBackgroundLiveness (in-memory) drives backgroundLiveness: working | monitoring on thread shells; runtime ingestion records task lifecycle and clears on session.exited. Stop now stops live Claude tasks (stopTask) and bounded Codex child turn/interrupt before the parent. Claude drops subagent narration from the parent transcript, attributes tools via parent_tool_use_id, parses workflow_progress with member coalescing, and Codex registers v2 children with explicit routing (root self-activity guard, interception before legacy suppressor). New read-scoped getWorkflowScript RPC reads .js under ~/.claude/projects with realpath containment and TOCTOU-safe open.

Mobile mirrors the web quiet timeline: hide agent-internal background work but keep nested agent terminals and Codex terminal bypass task.updated rows; task rows collapse by taskId.

Reviewed by Cursor Bugbot for commit f7673f3. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • New Features

    • Added an Agents panel showing live and completed subagent workflows, phases, status, usage, and activity.
    • Added workflow script inspection with loading, truncation, and error states.
    • Added Working and Monitoring thread statuses with live background-task counts and a Stop action.
    • Added support for multi-agent collaboration, including nested tasks, progress, retries, and interruptions.
  • Bug Fixes

    • Reduced duplicate and internal activity in the work log while preserving meaningful task progress.
    • Improved task status, ownership, and usage reporting across providers.

…imeline)

Surface Claude Code subagents/workflows and Codex collab agents in the UI
using only native provider emissions. Zero migrations, zero new tables:
widened task.* activity payloads ride the existing event-sourced activity
path, and a client-side fold in client-runtime derives v2-shaped subagent
state (field names match #4779 so the orchestration-v2 merge is mechanical).

Server:
- contracts: TaskAgentLinkage on all task payloads, new task.updated event,
  typed RuntimeTaskUsage, tool attribution (agentId/parentToolUseId)
- ClaudeAdapter: carry subagent_type/workflow_name/tool_use_id/outputFile,
  handle task_updated (was dropped), attribute subagent tool events via
  parent_tool_use_id, defensive workflow_progress parse, Workflow run handles
- CodexSessionRuntime/Adapter: register multi-agent-v2 children from
  thread/started + subAgentActivity, intercept child notifications, and
  synthesize task.* lifecycle (idle=resumable, cumulative usage) [WIP:
  routing is probe-gated per spec]
- ingestion: task.updated + agent-owned tool.progress persisted; wire-slim
  regression test proving agent fields survive to the client

Web:
- Agents right-panel surface (workflow phase groups, direct spawns, static
  status dots, DOM-write elapsed timers, expandable activity ring)
- composer live strip + inline workflow run card (8-row urgency cap)
- quiet timeline: one lifecycle row per agent (collapse by taskId), agent-
  attributed tool rows re-homed to the panel, timelineBypass rows suppressed

Mobile: same quiet-timeline fold; task.completed kept as terminal signal.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 39.08% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the primary change: native subagent and workflow observability.
Description check ✅ Passed The description explains the problem, solution, UI changes, verification, tradeoffs, and remaining gaps, although it does not use every template heading.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Aug 2, 2026
Comment thread apps/web/src/components/AgentsPanel.tsx
Comment thread packages/client-runtime/src/state/subagentRuntime.ts Outdated
Comment thread packages/client-runtime/src/state/subagentRuntime.ts
Comment thread apps/web/src/components/chat/WorkflowRunCard.tsx Outdated
Comment thread packages/client-runtime/src/state/subagentRuntime.ts
Comment thread apps/server/src/provider/Layers/CodexAdapter.ts
Comment thread packages/client-runtime/src/state/subagentRuntime.ts Outdated
Comment thread apps/server/src/provider/Layers/CodexSessionRuntime.ts Outdated
Comment thread packages/client-runtime/src/state/subagentRuntime.ts
@macroscopeapp

macroscopeapp Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

1 blocking correctness issue found. Diff is too large for automated approval analysis. A human reviewer should evaluate this PR.

You can customize Macroscope's approvability policy. Learn more.

…w card

Per live-test feedback the roster rendered three times at once (panel, card,
strip). New rule: the Agents panel is the only roster. The chat gets one
anchored CTA row per spawn batch (workflow run, or a turn's direct spawns):
'Kicked off N subagents · <workflow> — <phase> · N active · Σ tok — Open
Agents'. Live status derives from the shared panel model at render time;
the row freezes to past tense on settle. Strip and card components deleted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread apps/web/src/components/chat/MessagesTimeline.tsx
Comment thread apps/web/src/components/chat/MessagesTimeline.tsx Outdated
Comment thread apps/web/src/components/chat/MessagesTimeline.tsx
Comment thread apps/web/src/components/chat/MessagesTimeline.tsx
Live-test round 2 fixes:
- Shells/monitors/plan tasks no longer masquerade as subagents: taskType
  rides on every task payload (adapter linkage + ingestion allowlist) and
  the fold excludes non-agent task types from the roster. 'Run 12s stall'
  background shells stay in the ordinary work log.
- The spawn CTA no longer says completed while a workflow is mid-flight:
  for workflow batches the coordinator's own terminal state is authoritative
  (dynamic spawns can make the known-member list momentarily all-settled).
- Agents panel rows are flat status lines: the per-agent unfold (recent
  tool-call feed) is gone. The only expansion is run-granularity: settled
  workflow runs collapse to one summary line under 'Earlier', click to list
  members. Live workflows and direct spawns sort first in bordered sections
  with settled/total counts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread apps/web/src/session-logic.ts
Comment thread apps/web/src/session-logic.ts
Comment thread packages/client-runtime/src/state/subagentRuntime.ts
Comment thread packages/client-runtime/src/state/subagentRuntime.ts
Comment thread apps/web/src/session-logic.ts
Comment thread packages/client-runtime/src/state/subagentRuntime.ts
Rerun workflows looked invisible: the launching turn settles in seconds
('Worked for 8.9s') and turn-folding collapsed all its work entries —
including the spawn CTA — while the fleet runs on in the background. CTA
rows are now exempt from turn folds and pinned outside the '+N tool calls'
overflow toggle, so a live run is always visible at its spawn point. Each
rerun gets its own CTA row (grouping keys on the coordinator id, which is
unique per run).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread apps/web/src/components/chat/MessagesTimeline.logic.ts Outdated
Comment thread apps/web/src/components/chat/MessagesTimeline.logic.ts
t3dotgg and others added 3 commits August 2, 2026 02:04
Live-test finding: statuses drifted (waiting/stalled agents alarming or
reading wrong) while fleets ran. Adopts the monitoring-pill rule from the
PR-monitoring design: one steady in-flight presentation.

- Panel and CTA: pending/running/waiting all render as Working (sky, no
  amber); detail stays in the activity sub-line; footer shows one working
  count. Only settled states differentiate (completed/failed/stopped).
- Fold: when a workflow coordinator settles, members that never received
  their own terminal row cascade to the coordinator's outcome (completed,
  or interrupted on failure) instead of reading as working forever.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Live-test: the CTA only appeared after the workflow finished. Two causes,
reproduced against the exact persisted thread data:
- workEntryIndicatesToolNeutralStatus swallowed spawn rows mid-run (they
  derive from task.progress, tone 'thinking' = neutral) — visible only
  once a terminal row flipped them to success. CTA rows are now exempt.
- collapse-by-group let the newest progress tick's id/createdAt/turnId win,
  drifting the row to the bottom of the timeline mid-run. The group anchor
  (spawn point) is now pinned.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Live-test: a thread running a 9-agent workflow and a thread babysitting a
PR both showed no sidebar status once their turns settled. The pill only
reflected turn/session state.

- Server: in-memory per-thread background liveness registry fed by the
  task lifecycle ingestion already processes (no persistence, no
  migration); exposed additively on the thread shell as
  backgroundLiveness: working | monitoring | null.
- Vocabulary (per Theo): two states only. Agent/workflow fleets present as
  plain Working; Monitoring is reserved for watch loops (monitor tasks and
  turn-outliving background shells — PR babysitting, log tails) when they
  are the only live work.
- Web: pill resolver and SidebarV2 status honor backgroundLiveness with
  the same recede treatment as Working (inbox-zero); Monitoring gets a
  steady label, no shimmer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Effect service conventions review: one clear violation (new shared mutable state held in a module global and consumed by two Effect services) plus one file-layout nit. Everything else in the changed Effect code (namespace imports from effect/* subpaths, per-session Map state inside Effect.gen, contract schemas) looks conformant.

Posted via Macroscope — Effect Service Conventions

Comment thread apps/server/src/orchestration/Layers/ProjectionSnapshotQuery.ts Outdated
Comment thread apps/server/src/orchestration/threadBackgroundLiveness.ts Outdated
Comment thread apps/server/src/orchestration/threadBackgroundLiveness.ts Outdated
Comment thread apps/server/src/orchestration/threadBackgroundLiveness.ts Outdated
Comment thread apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts Outdated
Live-test: plain Task-tool subagents vanished from the Agents panel and
CTA. The SDK reports them as taskType 'local_agent', which the agent-type
allowlist didn't anticipate — real agents were silently classified as
background work. Classification is now a denylist (shell/local_bash/
monitor/plan are background; anything else, including future agent-flavored
type names, is an agent).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread packages/client-runtime/src/state/subagentRuntime.ts Outdated
First live Codex probe (5 collab agents on gpt-5.6-sol) surfaced three
gaps, fixed against the persisted wire data:
- Children registered only via subAgentActivity (no thread/started with a
  spawn source), so no task.started ever formed and rows carried bare
  thread-id titles. subAgentActivity 'started' now synthesizes the
  task.started with agentPath-leaf naming.
- Codex child rows are ALL timelineBypass, so the quiet-timeline filter
  suppressed every row before the CTA could form — a Codex fleet had no
  chat presence at all. Bypassed agent lifecycle rows now feed the CTA
  collapse (still max one row per batch); non-agent bypassed rows stay
  suppressed.
- Idle now counts as not-live in the sidebar registry: an all-idle
  (resting, resumable) fleet no longer pins the thread at Working.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread apps/web/src/session-logic.ts
t3dotgg and others added 4 commits August 2, 2026 02:53
Live-test round 2 on Codex direct spawns:
- Idle (resting, resumable) agents wore a sky dot and sat in the live
  section, reading as stuck in-progress after the work finished. Idle now
  renders muted and sorts with settled.
- Progress rows carried the bare child thread id as title, clobbering the
  real name (math_one → UUID) from task.started. The runtime now stamps
  the registered child's identity (nickname/role/agentPath) on every
  synthetic collabAgent event, the adapter only emits title when it has a
  real name, and subAgentActivity registration derives a nickname from the
  agentPath leaf.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Live probe on 10 parallel collab agents: the wire emits subAgentActivity
{agentPath: '/root', kind: interacted} about the ROOT thread during collab
runs. Registration adopted the root as a child, so every subsequent root
notification — including the final assistant message and turn/completed —
was intercepted into the agent panel instead of the chat. The parent
looked hung ('Working 5m') after all subagents finished, with its report
riding an 'assistant message' row on the root's panel entry.

Registration now refuses the session's root thread (by id and by /root
path), and interception has a belt-and-braces root check.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… row

Claude background subagents settle between turns, so their completion rows
arrive under later synthetic turn ids (or none). Batch keying by each
row's own turn splintered ten parallel spawns into a stream of 'Kicked
off N subagents' rows (live thread 7ac7ef05: completions spread across 8
different turn ids). Membership is now decided once at the first row seen
per taskId — task.started rows (which carry the true spawn turn) seed the
batch and collapse into its CTA instead of being skipped.

Repro test derives exactly one CTA with all 10 agents from the persisted
thread export.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nscript

Two live-test findings with parallel Claude subagents, one root cause:
even with forwardSubagentText off, the SDK forwards subagent-owned
messages tagged parent_tool_use_id, and the adapter emitted them as
parent conversation.

- Subagent assistant snapshots became interleaved leak messages ('sleep
  ran successfully…') AND spawned a synthetic turn per completion — which
  is also why the Working timer kept resetting to 0: each synthetic turn
  restarted the elapsed clock. Subagent-owned assistant messages now only
  advance the resume cursor.
- Subagent-owned text/thinking stream blocks wrote into the parent
  transcript; they are now dropped (tool_use blocks still flow, with
  agentId attribution, for the quiet-timeline re-homing).

Subagent results still reach the UI through the task.* lifecycle
(task_notification summaries) — the panel loses nothing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One finding on the new readWorkflowScript service module. The ThreadBackgroundLiveness service module (canonical single-file layout, inline interface, Foo["Service"], make/layer, env-acquired dependency in ingestion and the snapshot query) and the now-structured OrchestrationGetWorkflowScriptError look good.

Posted via Macroscope — Effect Service Conventions

Comment thread apps/server/src/orchestration/workflowScriptQuery.ts
Comment thread apps/server/src/provider/Layers/CodexSessionRuntime.ts
Comment thread apps/server/src/provider/Layers/CodexSessionRuntime.ts
Comment thread apps/server/src/provider/Layers/ClaudeAdapter.ts Outdated
…registration merge and live-turn cleanup

- ClaudeAdapter no longer emits a separate phases-only coordinator
  task.progress: it shared the stable ingestion activity id with the
  full row and the thinner upsert overwrote usage/progress text every
  tick (review finding). Phases now ride the one full row.
- Codex child registration merges across both paths: thread/started no
  longer clobbers a subAgentActivity-captured spawnTurnId with the
  now-settled (undefined) activeTurnId, and a later subAgentActivity
  fills missing agentPath/nickname instead of being discarded.
- thread/closed and child error drop the live-turn entry, so Stop no
  longer wastes a turn/interrupt RPC on a dead thread before reaching
  the parent.
- Mock peer imports use the repo's namespace-import convention (fixes
  the Check lint failure — the remaining 4 errors were ours, not
  main's; SettingsFontPreviews et al are warnings).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread apps/server/src/provider/Layers/CodexSessionRuntime.ts Outdated
…fill

- workflowScriptQuery fails the two TOCTOU containment checks with their
  own tagged reasons (not-regular-file / changed-during-read) instead of
  manufacturing Errors for the read-failed catch to fold into cause —
  clears the standing Effect Service Conventions finding.
- Collab test script write suppresses preferSchemaOverJson (fixture
  bytes for a child process, not a wire codec) — clears the Check
  failure the new integration test introduced.
- Registration merge keeps spawnTurnId registration-time-only: a later
  subAgentActivity for an already-registered child no longer backfills
  an unrelated current turn as the spawn batch (Bugbot follow-up to the
  merge fix).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread apps/server/src/provider/Layers/CodexSessionRuntime.ts
t3dotgg and others added 2 commits August 5, 2026 19:53
…p ordering coverage

- spawnTurnId is registration-time-only on BOTH registration paths now:
  thread/started for an already-known child keeps its value (set or
  unset) instead of backfilling from whichever parent turn is active
  later, which stamped old children onto new fleet CTAs.
- Workflow member fan-out gets a material-transition filter: the wire
  repeats the full member array every coordinator tick, so a 100-agent
  fleet amplified one provider tick into up to 100 runtime events
  (event-log writes, queue pressure, reducer work). Members now emit
  only when a rendered field changed.
- Stop-everything no longer depends on registration timing: the foreign
  pre-registration suppression path records/clears live child turns, so
  a child whose turn/started precedes its registration is still
  interrupted. New it.live integration test drives the real runtime
  through pre-registration turn/started (child A), post-registration
  turn/started (child B), a failing child interrupt, and asserts all
  three turn/interrupt RPCs (A, B, parent) reach the mock peer.
- Mock peer records interrupts to a sidecar file and supports
  holdTurnOpen / failInterruptFor scripting.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 404fb52. Configure here.

Comment thread packages/client-runtime/src/state/subagentRuntime.ts Outdated
t3dotgg and others added 3 commits August 5, 2026 20:00
- Replace all Array.prototype.toSorted() in the client-runtime fold with
  .slice().sort(): Hermes doesn't implement ES2023 array methods, and
  mobile loading this module would throw at runtime (matches the prior
  thread-search toSorted incident).
- Move the preferSchemaOverJson suppression to a line the directive
  actually covers (tsgo flagged the misplaced one as no-effect, which
  failed Check).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
tsgo flags a directive that suppresses nothing as TS377000 and Check
fails on it. The JSON.parse inside a named arrow doesn't trigger
preferSchemaOverJson in the first place, so the directive was pure
noise.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ng regression test

- Child-stop fan-out is bounded on both providers: per-child 3s and
  overall 10s deadlines (timeoutOption) around stopTask / child
  turn/interrupt, so a wedged child whose RPC never settles cannot block
  the parent interrupt — which is guaranteed to run afterward. The Codex
  integration test's child A now HANGS (never responds) instead of
  rejecting, and asserts B's and the parent's interrupts still arrive.
- The workflow-member fingerprint delimiter was a literal 0x00 byte,
  which made ripgrep treat the rest of ClaudeAdapter.ts as binary; now
  an escaped \u001f.
- New adapter regression test for member coalescing: identical
  workflow_progress snapshots emit zero member events; a single member's
  token advance emits exactly one.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread apps/server/src/provider/Layers/CodexSessionRuntime.ts Outdated
…ible

The child error branch settled every error as systemError and dropped
the live-turn entry, ignoring willRetry — a retrying child kept running
but was orphaned from Stop and shown failed. Mirrors the root error
handler: willRetry keeps the child running; only terminal errors clean
up and emit systemError.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@t3dotgg
t3dotgg merged commit a2ca89a into main Aug 6, 2026
17 checks passed
@t3dotgg
t3dotgg deleted the t3code/native-subagent-observability branch August 6, 2026 04:32
omegent-app Bot added a commit to patroza/t3code that referenced this pull request Aug 6, 2026
Imports the tree delta from the fork/candidates tree recorded in the
fork-dev/2026-08-06.1 checkpoint to a rebuilt fork/candidates carrying upstream
main a2ca89a. Five upstream commits enter the product:

  a2ca89a feat: native subagent & workflow observability (pingdotgg#5219)
  990bb0b fix: reconnect faster after remote server updates (pingdotgg#5404)
  7251f1a Prevent terminal loading flash (pingdotgg#5432)
  30e4715 fix(web): preserve terminal font size when splitting (pingdotgg#5444)
  de592a0 Enrich terminal font previews (pingdotgg#5428)

  importedCandidatesCommit: 9655a9ba955197361044ef6f8f97e35841ff779e
  importedCandidatesTree:   50f9bfab717c30a8ea90d52060349e209502d116
  importedUpstreamCommit:   a2ca89a
  previousCandidatesTree:   9b4cd3e

Seven files conflicted against the fork/dev product tree. Most are independent
additions on both sides and resolve as unions: upstream's backgroundLiveness
alongside identity's originSource/participantSummaries, upstream's agent-spawn
CTA rows alongside the imported user-input Q&A timeline.

Two needed more than a union.

apps/mobile threadActivity.ts: upstream's isAgentInternalActivity skip guard
must run before identity's resolved-user-input enrichment. Concatenating the
sides in the other order would enrich and push agent-internal rows that
upstream intends to drop.

apps/web Sidebar.logic.ts: the 3-way merge welded upstream's hasPlanReadyPrompt
condition onto the "Wake Required" return body, so a plan-ready thread would
have rendered as Wake Required and no thread could ever reach Plan Ready. Both
branches are restored with their own bodies. The status rank map is merged onto
upstream's new scale with Wake Required kept at the Working/Connecting tier,
matching its relative position before the import.

Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
omegent-app Bot added a commit to patroza/t3code that referenced this pull request Aug 6, 2026
Imports the tree delta from the fork/candidates tree recorded in the
fork-dev/2026-08-06.1 checkpoint to a rebuilt fork/candidates carrying upstream
main a2ca89a. Five upstream commits enter the product:

  a2ca89a feat: native subagent & workflow observability (pingdotgg#5219)
  990bb0b fix: reconnect faster after remote server updates (pingdotgg#5404)
  7251f1a Prevent terminal loading flash (pingdotgg#5432)
  30e4715 fix(web): preserve terminal font size when splitting (pingdotgg#5444)
  de592a0 Enrich terminal font previews (pingdotgg#5428)

  importedCandidatesCommit: 9655a9b
  importedCandidatesTree:   50f9bfa
  importedUpstreamCommit:   a2ca89a
  previousCandidatesTree:   9b4cd3e

Seven files conflicted against the fork/dev product tree. Most are independent
additions on both sides and resolve as unions: upstream's backgroundLiveness
alongside identity's originSource/participantSummaries, upstream's agent-spawn
CTA rows alongside the imported user-input Q&A timeline.

Two needed more than a union.

apps/mobile threadActivity.ts: upstream's isAgentInternalActivity skip guard
must run before identity's resolved-user-input enrichment. Concatenating the
sides in the other order would enrich and push agent-internal rows that
upstream intends to drop.

apps/web Sidebar.logic.ts: the 3-way merge welded upstream's hasPlanReadyPrompt
condition onto the "Wake Required" return body, so a plan-ready thread would
have rendered as Wake Required and no thread could ever reach Plan Ready. Both
branches are restored with their own bodies. The status rank map is merged onto
upstream's new scale with Wake Required kept at the Working/Connecting tier,
matching its relative position before the import.

Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
cursor Bot added a commit to aaditagrawal/t3code that referenced this pull request Aug 6, 2026
…gent-obs-63f7

sync: port upstream native subagent & workflow observability (pingdotgg#5219)
omegent-app Bot added a commit to patroza/t3code that referenced this pull request Aug 6, 2026
Imports the tree delta from the fork/candidates tree recorded in the
fork-dev/2026-08-06.1 checkpoint to a rebuilt fork/candidates carrying upstream
main a2ca89a. Five upstream commits enter the product:

  a2ca89a feat: native subagent & workflow observability (pingdotgg#5219)
  990bb0b fix: reconnect faster after remote server updates (pingdotgg#5404)
  7251f1a Prevent terminal loading flash (pingdotgg#5432)
  30e4715 fix(web): preserve terminal font size when splitting (pingdotgg#5444)
  de592a0 Enrich terminal font previews (pingdotgg#5428)

  importedCandidatesCommit: 9655a9b
  importedCandidatesTree:   50f9bfa
  importedUpstreamCommit:   a2ca89a
  previousCandidatesTree:   9b4cd3e

Seven files conflicted against the fork/dev product tree. Most are independent
additions on both sides and resolve as unions: upstream's backgroundLiveness
alongside identity's originSource/participantSummaries, upstream's agent-spawn
CTA rows alongside the imported user-input Q&A timeline.

Two needed more than a union.

apps/mobile threadActivity.ts: upstream's isAgentInternalActivity skip guard
must run before identity's resolved-user-input enrichment. Concatenating the
sides in the other order would enrich and push agent-internal rows that
upstream intends to drop.

apps/web Sidebar.logic.ts: the 3-way merge welded upstream's hasPlanReadyPrompt
condition onto the "Wake Required" return body, so a plan-ready thread would
have rendered as Wake Required and no thread could ever reach Plan Ready. Both
branches are restored with their own bodies. The status rank map is merged onto
upstream's new scale with Wake Required kept at the Working/Connecting tier,
matching its relative position before the import.

Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 6, 2026
First run of the provenance synchronization from
[#342](#342) — and the answer to
"get the latest upstream onto
`fork/dev`". Five upstream commits enter the product:

| | |
| --- | --- |
| `a2ca89aa` | feat: native subagent & workflow observability (pingdotgg#5219) |
| `990bb0b6` | fix: reconnect faster after remote server updates (pingdotgg#5404)
|
| `7251f1a1` | Prevent terminal loading flash (pingdotgg#5432) |
| `30e47153` | fix(web): preserve terminal font size when splitting
(pingdotgg#5444) |
| `de592a00` | Enrich terminal font previews (pingdotgg#5428) |

54 files, +7,055 / −175.

## Checkpoint

```json
{
  "importedCandidatesCommit": "9655a9ba955197361044ef6f8f97e35841ff779e",
  "importedCandidatesTree":   "50f9bfab717c30a8ea90d52060349e209502d116",
  "importedUpstreamCommit":   "a2ca89aa10f13a2222e08afd98c66285121d5ba2",
  "previousCandidatesTree":   "9b4cd3e1c774c3c436e43305c151edf596b2936a"
}
```

`previousCandidatesTree` is C1 from tag `fork-dev/2026-08-06.1`. Tag the
merge commit
`fork-dev/2026-08-06.2` with the values above once this lands.

## Two resolutions worth reviewing

Most of the 7 conflicted files are independent additions on both sides
and resolve as unions —
upstream's `backgroundLiveness` beside identity's
`originSource`/`participantSummaries`, upstream's
agent-spawn CTA rows beside the imported user-input Q&A timeline. Two
were not unions:

**`apps/web/src/components/Sidebar.logic.ts`** — the 3-way merge welded
upstream's
`hasPlanReadyPrompt` condition onto the `"Wake Required"` return body.
Left alone, a plan-ready
thread would render as **Wake Required** and no thread could ever reach
**Plan Ready**. Both
branches are restored with their own bodies. The status rank map is
merged onto upstream's new scale
with `Wake Required` at the `Working`/`Connecting` tier — its relative
position before the import.
**That tier placement is a judgement call; say if you want it ranked
differently.**

**`apps/mobile/src/lib/threadActivity.ts`** — upstream's
`isAgentInternalActivity` skip guard must
run *before* identity's resolved-user-input enrichment. The other order
enriches and pushes exactly
the agent-internal rows upstream means to drop.

## Validation

- All 12 `fork/candidates` commits replayed onto the rebuilt `fork/tim`;
`a2ca89aa1` confirmed an
  ancestor of the new candidates tip.
- No residual conflict markers; brace balance checked on the hand-edited
files.
- **Typecheck and tests have not run locally** — the rebase workspace
has no `node_modules`. Fork CI
on this PR is the first real verification. Do not merge on the strength
of this description.

## Provenance branches not yet pushed

`fork/base` → `4a73589` and `fork/tim` → `b1c5fa5` are rebased and
`fork/candidates` → `9655a9ba`
is rebuilt, but all three are **local only**. The ruleset *Protect
fork/tim, candidates, integration*
sets `non_fast_forward` with no bypass actor and the app token has no
`administration` scope, so I
cannot force-push them. Until they are pushed,
`importedCandidatesCommit` refers to a commit that
exists nowhere on the remote. The tree is what the delta depends on, but
the checkpoint is not fully
honest until that push happens.

Co-authored by [@patroza](https://github.com/patroza)

opened by [Patrick Roza](https://discord.com/users/95218063095377920) in
chat thread **Discord** ·
[Discord](https://discord.com/channels/1083767712431480922/1534783738322485399/1534783738322485399)
· [T3](https://t3vm/?thread=584a9ad3-243e-4308-8a13-49acdd758b17)

Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com>
Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
github-actions Bot added a commit to omarcresp/t3code-flake that referenced this pull request Aug 6, 2026
vortechron pushed a commit to vortechron/void that referenced this pull request Aug 6, 2026
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit a2ca89a)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant