Skip to content

Design and implement Claude dynamic workflow inspector #35

Description

@badcuban

Summary

Add first-class support for Claude Code dynamic workflows in Threadlines. The goal is to let users intentionally trigger Claude workflows, see when Ultracode causes Claude to orchestrate work in the background, and inspect workflow/subagent activity without flooding the main chat transcript.

This issue is intended as the design/reference ticket before implementation. It combines the current repo shape with current Claude workflow/Agent SDK capabilities.

Why this matters

Claude workflows can spawn many agents and perform a lot of background coordination. If Threadlines only renders the final assistant text, users lose trust because the app appears idle while expensive work is happening. If Threadlines dumps every subagent stream into chat, the conversation becomes unusable. We need a middle path: compact chat status plus a dedicated workflow surface for details, costs, subagents, raw activity, and final results.

Research snapshot

Current Claude behavior/capabilities to design around:

  • Claude Code supports dynamic workflows that can be triggered by asking Claude to use/run a workflow, by selecting Ultracode behavior, or via workflow tooling in SDK contexts.
  • The /workflows view in Claude surfaces run progress, agent activity, and token usage. Threadlines needs an equivalent web-native surface.
  • Workflows may spawn up to 16 concurrent agents and up to 1,000 agents total per run. The UI must assume high cardinality and avoid one chat row per internal update.
  • Workflow scripts coordinate agents but do not directly access shell/filesystem; agents do the work.
  • Workflow runs can have names, run ids, task ids, summaries, transcript directories, script paths, statuses, and token usage.
  • The Claude Agent SDK can expose richer internals through options/events:
    • includePartialMessages: true already exists in our adapter.
    • forwardSubagentText?: boolean can forward subagent text/thinking blocks with parent_tool_use_id; by default only subagent tool_use/tool_result blocks are emitted.
    • includeHookEvents?: boolean can emit hook events.
    • Hooks include SubagentStart, SubagentStop, TaskCreated, TaskCompleted, and related metadata such as agent_id, agent_type, session_id, transcript_path, cwd, and effort.
    • The SDK Workflow tool returns fields such as status, taskId, taskType, workflowName, runId, summary, transcriptDir, and scriptPath.

Relevant official docs:

Current Threadlines repo context

Backend/provider:

  • apps/server/src/provider/Layers/ClaudeAdapter.ts already uses @anthropic-ai/claude-agent-sdk and includePartialMessages: true.
  • The adapter already handles stream deltas, tool input deltas, Claude task messages, permission events, and plan/task projection.
  • Workflow currently falls through to a generic dynamic tool call path rather than a first-class workflow item.
  • Agent, Task, and related subagent tool names are already classified as collab_agent_tool_call.
  • Claude Ultracode is already represented in model effort handling. The adapter maps ultracode to SDK effort xhigh while setting settings.ultracode = true.

Contracts/orchestration:

  • packages/contracts/src/providerRuntime.ts already has canonical task lifecycle events: task.started, task.progress, task.completed.
  • It also has item lifecycle, hook, tool progress, and content delta event families.
  • apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts already treats provider task events as pending background work and can synthesize subagent.result activity from child provider output.
  • apps/server/src/orchestration/Layers/ProviderActivityProjection.ts already projects task/hook/tool progress into OrchestrationThreadActivity.

Web/UI:

  • apps/web/src/session-logic.ts already derives subagent progress, subagent result rows, work log entries, and timeline entries.
  • apps/web/src/components/chat/ThreadActivityPopover.tsx already has a compact header popover for tasks/subagents/background runs.
  • apps/web/src/components/chat/MessagesTimeline.tsx already renders subagent result rows outside the normal assistant message flow.
  • apps/web/src/components/chat/TraitsPicker.tsx already gives Ultracode a special model/effort presentation.
  • apps/web/src/components/ChatRightPanelInlineSidebar.tsx already provides a resizable right panel pattern we can reuse or generalize for a workflow inspector.

Product goals

  1. Let users intentionally trigger a Claude workflow from Threadlines.
  2. Make Ultracode workflow behavior visible and understandable without requiring users to know Claude CLI internals.
  3. Keep the main chat readable by default.
  4. Provide a dedicated workflow inspector for users who want the full background picture.
  5. Preserve enough raw detail for debugging provider issues and understanding cost.
  6. Make workflow progress survive reconnects/restarts as well as our existing event log allows.
  7. Avoid making this Claude-specific UI impossible to reuse for future Codex/background orchestration surfaces.

Non-goals for the first implementation

  • Do not build a visual workflow authoring canvas.
  • Do not attempt to edit or persist custom workflow scripts from the GUI in the MVP.
  • Do not dump every subagent token into the chat transcript.
  • Do not make workflows the default for every Claude turn.
  • Do not change existing Codex behavior as part of this work unless shared UI components require small contract-safe generalization.

Suggested user-facing UX

1. Composer entry point: Run mode selector

Add a compact run-mode control near the composer send controls. It should feel like an execution mode, not a full settings panel.

Suggested modes:

  • Normal - current behavior.
  • Workflow - asks Claude to use a workflow for this turn when available.
  • Auto or Ultracode - shown when the selected Claude model/effort supports Ultracode; indicates Claude may decide to orchestrate workflow-style background work.

Possible UI shape:

  • Segmented control or small dropdown next to Send.
  • Icon: use a workflow/network/branches-style icon from lucide if available.
  • Tooltip text should be concise: ?Use Claude workflow orchestration for this turn.?
  • If the selected provider/model does not support workflows, disable with a tooltip: ?Claude workflows require a compatible Claude Code runtime/model.?

Behavior details:

  • Selecting Workflow should be turn-scoped by default. After sending, return to the previous default unless the user pins it.
  • Provide a small pin/remember option in the dropdown, not as a separate persistent visible toggle.
  • When Workflow is active and the user sends, add a provider turn directive rather than permanently mutating the user's prompt text if possible.
  • If provider turn directives are not ready, first implementation can prepend a hidden/internal instruction such as ?Use a workflow for this task if appropriate,? but it should be represented in provider metadata so the UI can explain why a workflow started.

2. Ultracode tie-in

We already expose Ultracode as a reasoning level for Claude models that support it. Workflow UX should build on that instead of adding a competing concept.

Recommended behavior:

  • Keep Ultracode in the model/effort selector as the high-effort reasoning option.
  • Add a short affordance in the Ultracode option/tooltip: ?May use Claude workflow orchestration for complex tasks.?
  • When Ultracode is selected, show the workflow inspector affordance only after actual workflow/task/subagent activity appears. Do not pre-open a heavy panel for every Ultracode turn.
  • If the user explicitly chooses Workflow while Ultracode is selected, treat it as one unified request: high-effort + workflow orchestration. Do not duplicate prompts or show two separate modes.
  • If Ultracode is unavailable for the selected Claude model, the run-mode control should still allow Workflow only if the runtime supports the Workflow tool independently. Otherwise disable it.

3. Main chat transcript

Main chat should stay high-signal.

Render at most:

  • A compact workflow status row/card at the start of a workflow run.
  • Important workflow phase changes.
  • Final workflow summary/result.
  • Failure/cancellation/permission-required states.

Avoid:

  • Streaming every subagent thought/text block into main chat.
  • Rendering hundreds of task updates inline.
  • Intermixing raw hook/tool events with normal assistant messages.

Suggested chat card content:

  • Workflow name or inferred title.
  • Status: queued/running/paused/failed/completed.
  • Agent count: active/completed/failed.
  • Current phase or last meaningful activity.
  • Token/cost summary when available.
  • ?Open details? button that opens/focuses the workflow inspector.

4. Header activity popover

Extend the existing ThreadActivityPopover so workflow runs are included alongside tasks, subagents, and background runs.

Collapsed row example:

  • Workflow: Refactor auth flow
  • 6 agents active, 14 completed
  • Last update: running tests
  • Progress/status chip.

The popover should be a quick glance, not the detailed surface. It should deep-link/open the inspector for the selected run.

5. Dedicated workflow inspector surface

Add a right-side ?Workflow? panel. This can reuse the existing resizable right panel pattern, but should not be jammed into the source-control panel permanently. Ideally the right panel becomes a generic session sidebar with tabs or modes:

  • Source Control
  • Workflow
  • Activity / Logs (future)

If that is too much for MVP, add a workflow drawer/panel opened from the chat card and header popover.

Recommended inspector layout:

Header

  • Workflow name.
  • Run id / task id copy affordance.
  • Status chip.
  • Started time / elapsed time.
  • Model and effort, including Ultracode when active.
  • Token usage/cost summary when available.
  • Stop/cancel/resume actions if supported and safe.

Overview tab

  • Current phase.
  • Short workflow summary.
  • User trigger source: explicit workflow mode, Ultracode auto-orchestration, prompt-requested workflow, resumed workflow.
  • Agent totals: active, completed, failed, cancelled.
  • Permission waits.
  • Recent notable events.

Agents tab

A dense list/table of spawned agents:

  • Agent id.
  • Agent type/name.
  • Status.
  • Parent workflow/run id.
  • Current tool or last activity.
  • Started/ended time.
  • Token usage if available.
  • Final summary/result.
  • Transcript/path indicator if available and safe to expose.

Rows should be expandable. Expanded rows can show:

  • Tool calls/results summary.
  • Final assistant text/result.
  • Errors.
  • Raw event snippets.

Default should be collapsed and grouped by status/phase so a 100-agent run remains navigable.

Timeline tab

Chronological event stream with filtering:

  • Workflow started/completed.
  • Task created/completed.
  • Subagent started/stopped.
  • Permission requested/resolved.
  • Tool call started/completed.
  • Summary/result emitted.

Filters:

  • All.
  • Workflow.
  • Agents.
  • Tools.
  • Permissions.
  • Errors.

This is where verbose activity belongs, not the chat transcript.

Raw tab

For debugging and development builds:

  • Canonical provider event JSON.
  • Native Claude event JSON when captured.
  • Copy button.
  • Redaction guard if paths/prompts/secrets may be included.

This tab can be behind a developer toggle if needed.

Backend implementation plan

Phase 1: Capture spike with fixtures

Goal: prove exactly what Claude emits for workflow runs in our environment before committing the contract shape.

Tasks:

  • Create one or more local manual capture scripts or temporary tests that run Claude through the existing SDK version.
  • Capture examples for:
    • Explicit prompt: ?use a workflow?.
    • Ultracode effort.
    • Workflow with multiple subagents.
    • Workflow failure/cancel/permission wait if feasible.
  • Capture with and without:
    • forwardSubagentText: true.
    • includeHookEvents: true.
  • Save sanitized fixtures for tests.

Decision needed after spike:

  • Whether forwardSubagentText should be default-on, default-off, or enabled only while the workflow inspector is open/developer mode is active.
  • Whether hook events provide enough stable lifecycle metadata to drive the inspector.

Phase 2: Provider adapter changes

In apps/server/src/provider/Layers/ClaudeAdapter.ts:

  • Classify Workflow tool calls as a first-class workflow item or a specialized task item rather than generic dynamic_tool_call.
  • Add a Workflow title in titleForToolName.
  • Preserve Workflow tool output fields:
    • status
    • taskId
    • taskType
    • workflowName
    • runId
    • summary
    • transcriptDir
    • scriptPath
  • Preserve workflow_name from SDK task-started messages when present.
  • Consider adding includeHookEvents: true for Claude sessions, at least when workflows are active or when the user has enabled detailed activity.
  • Consider enabling forwardSubagentText: true behind a feature flag or workflow-detail setting.
  • Ensure settings.ultracode = true remains tied to the existing Ultracode effort selection.
  • Add a provider-level concept of turn trigger/source:
    • normal
    • explicit workflow mode
    • ultracode-selected
    • prompt-requested workflow
    • resumed workflow

Potential risk:

  • Forwarding subagent text may substantially increase event volume. The adapter should have clear throttling/backpressure behavior and should not block the main assistant stream.

Phase 3: Contracts

In packages/contracts/src/providerRuntime.ts, add enough schema to represent workflows without baking in Claude-only assumptions.

Two possible approaches:

Option A: Extend task events

Extend existing TaskStartedPayload, TaskProgressPayload, and TaskCompletedPayload with optional fields:

  • workflowRunId?: string
  • workflowName?: string
  • parentTaskId?: string
  • agentId?: string
  • agentType?: string
  • transcriptPath?: string
  • triggerSource?: 'explicit' | 'ultracode' | 'prompt' | 'resume' | 'unknown'
  • usage?: ProviderUsageLike

Pros:

  • Smaller contract change.
  • Reuses existing ingestion/projection paths.

Cons:

  • Workflows become overloaded task events.
  • UI derivation may become harder as workflow complexity grows.

Option B: Add workflow event family

Add provider runtime events such as:

  • workflow.started
  • workflow.progress
  • workflow.agent.started
  • workflow.agent.progress
  • workflow.agent.completed
  • workflow.completed

Pros:

  • Cleaner UI state model.
  • Easier future support for other providers/orchestrators.
  • Avoids overloading generic task events.

Cons:

  • Larger contract/projection work.

Recommendation:

  • Use Option B if the capture spike confirms stable workflow identifiers are available.
  • Use Option A as an MVP if Claude emits workflow data mostly through existing task messages and tool outputs.

Phase 4: Orchestration ingestion/projection

In provider runtime ingestion/projection:

  • Group workflow-related events by workflowRunId or taskId fallback.
  • Track workflow status and agent counts separately from generic pending background tasks.
  • Avoid double-counting one workflow plus all child agents as many independent background tasks in the header.
  • Link child subagent output to the parent workflow.
  • Preserve final subagent results but keep them out of the main chat unless summarized.
  • Add stable activity ids so reconnects do not duplicate rows.
  • Include enough data in OrchestrationThreadActivity for web-only derivation without needing native Claude event parsing in the browser.

Phase 5: Web state derivation

In apps/web/src/session-logic.ts:

  • Add WorkflowProgressState and WorkflowRunRecord derivation.
  • Collect workflow records from canonical runtime/orchestration activities.
  • Associate subagent records with workflow records when parent ids match.
  • Derive compact chat timeline entries:
    • workflow status entry
    • final workflow result/summary entry
    • failure entry
  • Keep verbose workflow internals out of workLogEntries unless user has opened a detailed log view.
  • Make settled workflow records remain visible in the inspector for the latest turn, even if the compact activity popover hides completed items.

Phase 6: UI implementation

Components to add or extend:

  • WorkflowRunCard for main chat compact status.
  • WorkflowInspectorPanel for the dedicated right panel/drawer.
  • WorkflowAgentList for dense agent table/list.
  • WorkflowTimeline for filtered event history.
  • WorkflowStatusBadge shared by cards/popover/panel.
  • Extend ThreadActivityPopover with a workflow section.
  • Extend composer controls with a run-mode selector.
  • Extend TraitsPicker Ultracode copy/tooltip to mention workflow orchestration where appropriate.

UI principles:

  • Dense, operational, and scannable.
  • No marketing-style hero sections.
  • No nested card stacks.
  • Use existing design tokens/components where possible.
  • Avoid long text in small chips/buttons.
  • Use icons with tooltips for actions like open, copy, cancel, filter, expand.

Suggested MVP scope

MVP should answer three user questions well:

  1. ?Is Claude doing workflow/subagent work right now??
  2. ?What agents/tasks are running and what are they doing??
  3. ?What did the workflow cost/do/result in??

MVP deliverables:

  • Composer run-mode control with Workflow when supported.
  • Ultracode tooltip/copy update.
  • Backend capture of Workflow tool/task metadata.
  • First-class workflow grouping in orchestration activities.
  • Compact workflow chat card.
  • Workflow section in header activity popover.
  • Right-side inspector with Overview and Agents tabs.
  • Tests for contract parsing, adapter mapping, ingestion grouping, and web derivation.

Defer until after MVP:

  • Raw event tab.
  • Full timeline filters.
  • Resume workflow UI.
  • Custom workflow script creation/editing.
  • Per-agent transcript browser.
  • Cost charts/history.

Permissions, safety, and cost considerations

  • Workflow mode should not silently bypass existing permission UX.
  • If Workflow is added to allowedTools, decide whether it is always allowed or only allowed after explicit user workflow-mode selection.
  • If workflows can spawn many agents, show clear cost/usage signals as soon as usage is available.
  • Provide a clear stop/cancel affordance if Claude SDK/runtime supports it through our session cancellation path.
  • Transcript paths may reveal local directories; avoid displaying full paths in the default UI. Use copy/raw views for developer-oriented inspection.
  • Treat subagent text as potentially verbose and sensitive. Store/project only what we need for UX unless the user enables detailed capture.

Open questions

  • What exact SDK events are emitted for workflows in our current Claude CLI/SDK combination during real runs?
  • Does forwardSubagentText: true create too much event pressure for our current WebSocket/event-log path?
  • Can we reliably identify workflow child agents using parent_tool_use_id, hook agent_id, task ids, or a combination?
  • Should explicit Workflow mode be available for all Claude models with the runtime support, or only for models that expose Ultracode in our selector?
  • Should workflow mode be per-turn, sticky per session, or both?
  • How much raw native event data should be persisted versus kept only in memory/dev logs?
  • Can workflow resume be supported through resumeFromRunId, and does it fit our existing session resume model?

Acceptance criteria

  • Users can trigger a Claude workflow from the composer without editing their prompt manually.
  • Users selecting Ultracode get clear UI that workflow orchestration may happen, and actual workflow activity is surfaced if it happens.
  • Main chat remains readable during a multi-agent workflow run.
  • Workflow/subagent progress is visible in a dedicated workflow UI surface.
  • Workflow agent counts, statuses, summaries, and token usage are displayed when available.
  • Workflow activity survives reconnects to the same degree as existing provider runtime events.
  • Generic subagent/task rendering for non-workflow Claude behavior does not regress.
  • Codex provider behavior does not regress.
  • Required repo checks pass before closing implementation work:
    • vp fmt
    • vp lint
    • vp run typecheck
  • Do not run bun test; this repo uses vp run test for the full Vitest suite.

Suggested test coverage

  • Claude adapter fixture tests for Workflow tool calls/results.
  • Claude adapter fixture tests for hook events and subagent events.
  • Contract schema tests for any new workflow payloads.
  • Provider runtime ingestion tests for workflow grouping and child agent association.
  • Projection tests for workflow activities.
  • session-logic tests for workflow progress derivation and compact timeline rows.
  • UI tests for:
    • composer workflow mode availability/disabled states
    • Ultracode copy/tooltip behavior
    • workflow chat card
    • workflow inspector agent grouping
    • header activity popover workflow section

Implementation notes

Start with a capture spike before changing contracts. The highest-risk part is not rendering; it is making sure we map Claude's actual workflow/subagent event shape into a stable provider-neutral model without overwhelming the event log or chat UI.

A good implementation sequence:

  1. Capture and sanitize real Claude workflow fixtures.
  2. Decide contract shape from evidence.
  3. Add adapter mapping and tests.
  4. Add ingestion/projection grouping and tests.
  5. Add web derivation tests.
  6. Add compact chat/popover UI.
  7. Add dedicated inspector panel.
  8. Polish Ultracode/run-mode UX.
  9. Run vp fmt, vp lint, and vp run typecheck.

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