Skip to content

Frontend

The frontend is a React 19 SPA that renders the ticket dashboard, the live workspace, review panes, and the navigator surfaces around them.

The UI is data-driven from:

  • /api/* REST endpoints
  • /api/stream SSE updates
  • workflow metadata in shared/workflowMeta.ts
  • ticket artifacts and runtime state from the backend

Top-Level Composition

AreaPurposePrimary files
App shellApp startup, configuration preload, global layoutsrc/App.tsx
Ticket dashboardTicket list, status cards, workspace selectionsrc/components/ticket/*
Active workspaceChooses the live view for the selected phasesrc/components/ticket/ActiveWorkspace.tsx
NavigatorTimeline, approval navigation, context tree, errors, full log entry pointsrc/components/ticket/NavigatorPanel.tsx
Workspace viewsDraft, council, interview, approval, coding, error, canceled, review, full logsrc/components/workspace/*

Active Workspace Routing

ActiveWorkspace.tsx maps workflow metadata to concrete views.

uiViewCurrent component
draftDraftView
councilCouncilView
interview_qaInterviewQAView
approvalApprovalView
codingCodingView
errorErrorView
doneCodingView
canceledCanceledView

Additional routing rules:

  • historical phases usually render through PhaseReviewView
  • fullLogOpen forces FullLogView
  • reviewable past coding still uses CodingView in read-only mode
  • active or selected error occurrences render ErrorView

NavigatorPanel.tsx is more than a left rail. It combines several different navigation modes:

  • PhaseTimeline for the workflow spine
  • ErrorOccurrencesPanel for active and past failures
  • ApprovalNavigator for interview, PRD, and beads approval context
  • ContextTree for context visibility
  • a full-log toggle that opens FullLogView

That split matters because the workspace is designed for both live work and historical review.

Key Workspace Views

ViewPrimary purpose
DraftViewTicket editing and start controls
CouncilViewMulti-model draft and vote phases with artifacts
InterviewQAViewInteractive interview batches, draft persistence, skip flow
ApprovalViewReview and edit interview, PRD, beads, and execution setup artifacts
CodingViewActive bead execution, bead list, logs, diffs, verification actions
ErrorViewLive blocked state or historical error occurrence review
PhaseReviewViewHistorical artifact review for completed phases
FullLogViewFull folded execution log stream

Coding Workspace Surfaces

The coding workspace is broader than a simple log pane.

Current CodingView composes:

  • bead list and progress UI
  • BeadDiffViewer
  • CollapsiblePhaseLogSection
  • LogEntryRow
  • PhaseArtifactsPanel
  • VerificationSummaryPanel

It also merges persisted bead artifacts with runtime bead overlays from the live ticket payload so the UI can show in-progress status and notes without waiting for a full artifact refresh.

Data Hooks

Workflow And Artifacts

HookCurrent roleCurrent return shape
useWorkflowMeta()Loads phase and group metadata{ groups, phases, phaseMap, isLoading }
useTicketArtifacts(ticketId, opts?)Fetches and caches ticket artifacts{ artifacts, isLoading }
useTicketPhaseAttempts(ticketId?, phase?)Reads phase-attempt historyReact Query result

Ticket And Profile Data

HookCurrent role
useTickets(projectId?)Ticket list with auto-refresh for active tickets
useTicket(id)Individual ticket with active-state refresh
useProfile()Singleton profile query against /api/profile
useOpenCodeModels()Connected models only
useAllOpenCodeModels()Full catalog including disconnected providers

Live Updates

useSSE({ ticketId, onEvent }) is the ticket stream hook.

Current behavior:

  • connects to /api/stream
  • persists the latest SSE event id per ticket in browser storage
  • sends ticketId and lastEventId on reconnect when available
  • listens for state_change, progress, log, error, bead_complete, needs_input, and artifact_change
  • invalidates or patches React Query caches in response
  • refetches ticket details, ticket lists, artifacts, interview state, setup-plan state, bead state, and server logs after a reconnect gap
  • returns { lastEventIdRef, connectionState }

Current connectionState values are:

  • connecting
  • connected
  • reconnecting

Interview Draft Persistence

useBatchSubmit(ticketId) is one of the higher-value stateful hooks in the app.

It does more than submit answers:

  • stores draft answers per interview batch
  • tracks skipped questions
  • tracks selected options
  • restores drafts from persisted UI state
  • auto-saves drafts with debounce through ticket UI-state artifacts and only marks a draft saved after the write succeeds
  • flushes the latest unsaved snapshot with a keepalive request on pagehide or beforeunload
  • coordinates submit and skip mutations
  • listens for interview batch updates coming back from the runtime

That makes InterviewQAView resilient across reloads, view changes, and follow-up question rounds.

Approval panes use the same success-aware debounced UI-state pattern for editor drafts. This protects large manual edits if the browser tab closes before the debounce timer finishes.

Artifact And Review Surfaces

Several UI components exist specifically to inspect durable workflow state:

ComponentPurpose
PhaseArtifactsPanelPhase-specific artifact viewer
WorkspacePhaseSummaryCompact summary for the selected phase
VerificationSummaryPanelDelivery actions during PR review
PhaseReviewViewHistorical artifact review with phase-attempt support
FullLogViewRawer, fuller log inspection

The frontend is built around the assumption that users must be able to inspect prior attempts and artifacts without replaying the run mentally from logs.

LogProvider treats server-side execution logs as durable truth. Browser-local logs are merged for responsiveness, but reconnect recovery requests the server log file again and merges by stable entry identity so a frontend restart does not leave the visible log pane stale.

Artifact Processing Notices

Future artifact companion payloads should persist parser and normalizer intervention details in structuredOutput.interventions. The collapsed notice stays compact and may include cheap category or rule labels, while the expanded notice treats interventions as the display source of truth for exact corrections, before/after examples, rule, category, stage, target, raw validator/parser messages, validation errors, and retry diagnostics.

structuredOutput.repairWarnings remains a raw audit string list and can be shown as source messages. When a legacy .ticket/** artifact has recognized warning strings but no explicit interventions, the frontend derives best-effort notice categories at render time without rewriting or migrating the artifact. Generic legacy repair strings stay quiet unless a structured intervention or retry diagnostic is present.

Frontend-State Relationship To Workflow Metadata

The frontend does not hardcode the full workflow. Instead, it derives major behavior from shared/workflowMeta.ts:

  • group ordering for the timeline
  • phase labels
  • uiView mapping
  • whether a phase exposes a review artifact type
  • whether a phase is editable
  • whether multi-model logs are expected
  • whether a phase has question or bead progress semantics

The current timeline group order is To Do, Discovery, Interview, Specs (PRD), Blueprint (Beads), Pre-Implementation, Implementation, Post-Implementation, Done, and Errors. PhaseTimeline hides empty groups, so Errors only appears when the blocked-error phase is visible.

This is why keeping the docs aligned with workflowMeta matters: the UI is built around that shared metadata contract.

Ticket Cancel Confirmation Dialog

The cancel button in DashboardHeader is labeled "Cancel…" (the ellipsis signals that a dialog will open before any action is taken).

Clicking the button opens a confirmation dialog with two optional, unchecked-by-default cleanup checkboxes:

CheckboxEffect when checked
Delete AI-generated artifacts and worktreePermanently removes interview Q&A, PRD drafts, and beads plan entries from the database, and deletes the isolated git worktree (including its branch and any code written to it)
Delete execution logPermanently removes the execution-log.jsonl file for this ticket; effective only when the worktree still exists (worktree removal via the first checkbox already covers the log)

Both options default to unchecked — canceling without checking anything preserves all artifacts exactly as the basic cancel behavior did before.

The dialog calls useCancelTicket which POSTs { deleteContent, deleteLog } to POST /api/tickets/:id/cancel. The hook invalidates the ticket and ticket-list queries on success.

LoopTroop documentation for the current runtime.