Skip to content

feat: coding agent workspace template - #57

Merged
yyyyaaa merged 4 commits into
mainfrom
feat/agent-ui
Oct 23, 2026
Merged

yyyyaaa merged 4 commits into
mainfrom
feat/agent-ui

Conversation

@yyyyaaa

@yyyyaaa yyyyaaa commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Adds a Coding Agent workspace template (@constructive/coding-agent) for running several coding sessions at once, plus the shared kit changes it needs.

Template

  • Layouts: sessions sit in a tab strip or a project sidebar, and each one is the same component in both.
  • Session view: a transcript built from the AI kit, and a composer with a model picker, attachments and a follow-up queue.
  • Side panel: diff review with line comments, file tabs, a browser tab and a file tree.
  • Terminal dock: a shell along the bottom of the session.
  • Background sessions: every open session stays mounted. A tab shows its live status and marks itself when the agent needs an answer, fails or finishes.
  • Sub-agents: sub-agents, orchestrator/worker runs, messages between agents, handoffs, phases and a shared task board appear in the transcript. Agents and Tasks tabs list them, and you can open or steer any agent.
  • Worktrees: changes are kept per worktree. A toolbar chip in the review shows each worktree's pull request and only its failing or running checks.
  • Conversation rail: a rail on the transcript's edge previews each turn and jumps to it. Long threads render in chunks, and diffs draw as they scroll into view.

Harness model

A session either plays a demo script or shows a real harness's event log. Both are folded by one pure reducer, and controls reach the host as actions.

flowchart LR
  S[script] --> E[HarnessEvent log]
  H[host events / createHarnessStore] --> E
  E -->|reduceHarness| V[HarnessView]
  V --> UI[transcript, panels, rail, tabs]
  UI -->|onAction: send, stop-run, permission, answer, rerun-checks…| HOST[host runtime]
  HOST --> H
Loading
const store = createHarnessStore();
harness.subscribe(sessionId, (event) => store.push(event));

<CodingAgent
  data={{ ...data, sessions: data.sessions.map((s) => ({ ...s, store })) }}
  onAction={harness.control}
/>;

Kit changes

  • ModelSelector: compact 30px rows and a ring-shadow surface. The side card is no longer clipped by the popover.
  • Shared helpers:
    • popoverSurfaceClass
    • CommandList density="compact"
    • iconButtonClass
    • useElementSize / useScrollbarInset
    • unscaledRect, which FluidHighlight uses so it measures correctly while a popup scales in
  • AI components: status icon sizing, wrapping, alignment and dir="auto" fixes in Tool, PlanTracker, ApprovalCard, AskCard and Message. ChatContainer now merges a caller's ref with its own.
  • Agent status: agents-builder gets rail and ring status indicators, and a shared statusSignal.
  • Theme: the fine-pointer scrollbar styles move into @layer base, so scrollbar-hide and similar utilities win again for mouse users.

Docs

  • New page: /blocks/coding-agent has a live preview with an example picker for the tabs layout, the sidebar layout and sub-agents.
  • Harness guide: a "Driving sessions from your harness" section with a store-based example.
  • File split: lib/application-blocks is split into one module per template.

Stories

Templates/CodingAgent: Tabs, Sidebar, With terminal, Multi-agent, Multi-agent (sidebar), and Long thread (stress test). The break-ui stories add worst-case data.

🤖 Generated with Claude Code

https://claude.ai/code/session_012nboNEcwNWwE4SXw9jxVAv

- `statusIndicator: 'rail' | 'rings'` on AgentsBuilder (default `rail`)
  picks how the sidebar and run panel show an agent's state
- Rail: each agent's stretch of its project rail lights up, seamless and
  centred on the line: a light travels down it while running, amber or
  blue breathes while waiting, red holds on failure, dashed when queued
- Rail, collapsed: a slim capsule beside each agent's square, the same
  size for every state, no words, nothing once a run is done
- Rings: a ring before each name whose arc is the run's progress; in the
  collapsed rail it circles the initials, with the tag word below
- `AgentSummary.progress` (0 to 1) feeds the arc; the template fills it
  from plan steps while a run plays
- Run panel status lines, header, and "Run complete" use the chosen
  indicator; in-flight names and initials keep their shimmer
- ModelSelector: 30px rows, ring-shadow surface, side card no longer
  clipped by the popover, compact search and cost meter
- Popover exports popoverSurfaceClass; CommandList gains density="compact"
- FluidHighlight measures through a popup's scale-in (unscaledRect)
- Tool, PlanTracker, ApprovalCard, AskCard, Message: status icon sizing,
  wrapping, alignment and dir="auto" fixes
- ChatContainer merges a caller's ref with its own
- workspace-kit: iconButtonClass, useElementSize and useScrollbarInset
- agent-status: shared statusSignal; playback exports REDUCED_MOTION_DELAY
- Tabs: reveal tabs wider than the strip; never scroll vertically
- Theme: fine-pointer scrollbar styles move into the base layer so
  scrollbar-hide utilities win
A workspace for running several coding sessions at once:

- Sessions in a tab strip or a project sidebar; each has a transcript
  built from the AI kit, a composer, a resizable side panel (diff review
  with line comments, file tabs, a browser tab, file tree) and a
  terminal dock
- Harness model: sessions play a script, or show a host's events
  (`events` array or `createHarnessStore()`), folded by the pure
  `reduceHarness`; controls reach the host through onAction
- Sub-agents, orchestrator/worker runs, messages between agents,
  handoffs, phases and a shared task board, with Agents and Tasks tabs
- Worktrees, pull requests and CI checks as events; changes are kept per
  worktree; a toolbar chip shows each worktree's PR and failing checks
- A conversation rail on the transcript's edge to preview and jump
  between turns; long threads render in chunks and diffs draw lazily
- Demo data, stories (including a 120-turn stress test), tests, and the
  registry item
- New /blocks/coding-agent page with a live preview whose example picker
  opens the tabs layout, the sidebar layout, or a sub-agents session
- "Driving sessions from your harness" guide with a store-based example
- Split lib/application-blocks into one module per template; building
  blocks carry their own intro instead of a billing default
@tenki-reviewer

tenki-reviewer Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Review complete. 🟡 1 medium

💬 Inline comments (1)

  • 🟡 Stopping the root run leaves its approval pending and resolvable — use-harness.ts:276
🧹 Nitpicks (7) — 🟢 7 low
  • 🟢 Add missing tooltip to coding-agent registryDependencies (registry.json:3825) — The new coding-agent registry entry omits tooltip from its registryDependencies (packages/ui/registry.json:3825), but its file turn-rail.tsx imports Tooltip, TooltipTrigger, TooltipContent, and TooltipProvider from ../tooltip (packages/ui/src/components/coding-agent/turn-rail.tsx:9).
  • 🟢 Move the RUN_TIMING doc comment off runProgress (use-agent-run.ts:40) — The doc comment for RUN_TIMING ("Beat lengths for the scripted run, in milliseconds") was left above the newly inserted runProgress function in packages/ui/src/components/agents-builder/use-agent-run.ts:40, so it attaches to the wrong declaration and RUN_TIMING (line 48) is left undocumented.
  • 🟢 Send to a paused run discards its queued script (use-harness.ts:331) — Sending a message to a paused run silently discards the rest of its script.
  • 🟢 Widening closes panel the user opened while narrow (use-panel-tabs.ts:95) — The narrow action snapshots open once when the panel first closes for narrowness, and restores that snapshot verbatim once there is room again (packages/ui/src/components/coding-agent/use-panel-tabs.ts:104-105).
  • 🟢 Reset stale peek level in LevelMenu on model change (model-selector.tsx:190) — LevelMenu keeps its peek hover state across model switches because ModelDetails is rendered without a key for detailModel (packages/ui/src/components/ai/model-selector.tsx:625-632), so the same LevelMenu instance persists while model changes.
  • 🟢 Rate limit queries a column the demo schema never defines (demo-invitations.ts:155) — The turn-two rate limiter shown in the demo filters on invitations.createdAt (packages/ui/src/components/coding-agent/demo-invitations.ts:155), but the invitations table defined in SCHEMA_WITH_INVITES (demo-invitations.ts:78-93) has no createdAt column — the only createdAt belongs to teams — and no later schema edit adds one.
  • 🟢 Reveal handle can't jump to the task turn (session-timeline.tsx:402) — The reveal handle in SessionTimeline (packages/ui/src/components/coding-agent/session-timeline.tsx:402-406) looks the id up only among run.items; the task row is not a timeline item — it is a synthetic Message with data-item-id={TASK_TURN_ID} rendered only when renderFrom === 0 (session-timeline.tsx:457-459).

The change introduces two new registry application blocks — a full coding-agent workspace (harness store, session/timeline/composer UI, panels, demo scripts) and an agents-builder playback surface — plus supporting updates to the AI chat components, base UI primitives, workspace-kit helpers, and motion utilities. The docs app's monolithic application-blocks.ts is split into per-block manifest modules with updated navigation, routes, and preview pages, and the registry manifests, smoke-install case, package exports, and skill docs are updated to match.

Files Change
packages/ui/src/components/coding-agent/* New coding-agent block: harness store/hooks, session surfaces, panels, composer, shortcuts, and demo fixtures
packages/ui/src/components/agents-builder/* New agents-builder block: run panel, status ring, playback engine, and run hook
packages/ui/src/components/ai/*, packages/ui/src/components/{button,collapsible,command,dropdown-menu,popover,tabs}.tsx Refactors and additions to chat/tool/message components and base primitives, incl. fluid-highlight
packages/ui/src/components/workspace-kit/*, packages/ui/src/lib/motion/*, packages/ui/src/{theme.ts,styles/globals.css,package.json,registry.json} Kit primitives, element-size hook, keyframes, and registry/package manifest updates
apps/blocks/src/lib/application-blocks*, application-doc-navigation.ts, showcase components, coding-agent pages, globals.css Manifest modularization, docs navigation, showcase canvas/preview, and Tailwind @source wiring for the new trees
apps/registry/scripts/smoke-install.ts, apps/registry/REGISTRY.md, .agents/skills/constructive-blocks/*, AGENTS.md Smoke-install case, registry docs, and skill documentation updates
packages/ui/src/stories/*, packages/ui/test/* Stories for the new blocks and hydration/coding-agent tests

Reviewed commit: 25997fd

@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​pierre/​trees@​1.0.0-beta.61001009989100
Added@​pierre/​diffs@​1.5.2991009899100

View full report

@yyyyaaa
yyyyaaa merged commit c8a89c3 into main Oct 23, 2026
4 of 5 checks passed

@tenki-reviewer tenki-reviewer 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.

This PR adds the coding-agent and agents-builder application blocks with their harness/playback state machinery, refactors the AI chat components, splits the application-block manifests into modules, and wires the new docs routes — overall solid, with only minor harness state-lifecycle and registry-manifest issues.

Key findings

  • 🟡 Stopping the root run leaves its approval pending and resolvable — use-harness.ts:276

Comment on lines +276 to +277
setStatus(state, runId, isRoot ? 'idle' : 'cancelled');
if (!isRoot) releaseParent(state, runId);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 bug · medium

Stopping the root run leaves its approval pending and resolvable

When the root run is stopped while held at an approval, stopRun sets its status to idle (packages/ui/src/components/coding-agent/use-harness.ts:276), but reduceHarness only strips pending requests on cancelled/done/failed (packages/ui/src/components/coding-agent/harness.ts:444) — idle is excluded. The request therefore stays in view.pending, so RequestDock keeps rendering the approval card for a run that is at rest, while the tab reports idle. Worse, resolving the ghost card still emits: control() builds the host action from view.pending without checking the run's status (packages/ui/src/components/coding-agent/use-harness.ts:529-533), so a permission action with the stale requestId is sent to the host for a run that no longer exists, even though the local reducer correctly no-ops it.

📋 Prompt for AI Agents

In packages/ui/src/components/coding-agent/use-harness.ts, in stopRun (lines 260-278), before setStatus(state, runId, isRoot ? 'idle' : 'cancelled') at line 276, drop any pending request owned by runId: for each entry in state.view.pending with entry.runId === runId, emit { kind: 'request.resolved', runId, requestId: entry.request.id } (or filter the pending list directly) so the approval dock clears. Also update the ended check in packages/ui/src/components/coding-agent/harness.ts line 444 to treat a transition to 'idle' for a run that had a pending human request as ended, so host-driven flows behave the same. This prevents resolving an approval for a run that has already been stopped.

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