Skip to content

Screens

Coding Agent

An agent working in a repo — chat with plan and permission requests on one side, file changes, terminal and a live preview on the other.

2 variantsMIT

Preview

Full screen

Dark mode for Settings

Maya Chen

Add dark mode to Settings → Appearance. Follow the system theme by default and remember the choice.

opus-5.5

Reading the settings page

src/settings/

Reading the settings page

Agent workingWorking · new messages queue

Agent is working

No changes yet. Files the agent edits show up here.

Installation

Copies the screen into components/ and installs every component it uses, with their dependencies and theme tokens.

pnpm dlx shadcn@latest add https://tuffui.com/r/coding-agent.json

Usage

Pass your own data and wire the callbacks to your agent runtime.

import { CodingAgent } from "@/components/coding-agent";
import { ToolCallBlock } from "@/components/ui/tool-call-block";
import { ToolApprovalQueue } from "@/components/ui/tool-approval-queue";

export function AgentScreen({ run }: { run: AgentRun }) {
  return (
    <div className="h-dvh">
      <CodingAgent
        data={{
          title: run.task.title,
          repo: run.repo,
          branch: run.branch,
          model: run.model,
          user: { name: run.user.name },
          // Each turn's content is any React node — tool calls, approvals.
          messages: run.turns.map((turn) => ({
            id: turn.id,
            role: turn.role,
            at: turn.createdAt,
            content:
              turn.role === "user" ? (
                turn.text
              ) : (
                <>
                  {turn.calls.map((call) => (
                    <ToolCallBlock key={call.id} data={call} />
                  ))}
                  {turn.approvals.length > 0 && (
                    <ToolApprovalQueue
                      data={turn.approvals}
                      layout="flat"
                      onDecide={(requests, decision, scope) =>
                        run.decide(requests, decision, scope)
                      }
                    />
                  )}
                </>
              ),
          })),
          activity: run.working ? run.status : undefined,
          files: run.changes,
          terminal: run.lastCommand,
          checkpoints: run.checkpoints,
          preview: { url: run.previewUrl, content: <iframe src={run.previewUrl} /> },
        }}
        status={run.working ? "streaming" : "idle"}
        onSend={(message) => run.send(message.text, message.mode)}
        onStop={() => run.stop()}
        onApply={(selection) => run.apply(selection)}
        onDiscard={() => run.discard()}
        onRestore={(checkpoint) => run.restore(checkpoint.id)}
      />
    </div>
  );
}

Props

PropTypeDefaultDescription
data*CodingAgentData—The task, repo and branch, the thread, the live activity line, changed files, the last terminal run, checkpoints and the preview.
status"idle" | "streaming""idle"While streaming, the composer queues follow-ups and shows Stop instead of Send.
tab"changes" | "terminal" | "preview"—Controls the work panel tab. Uncontrolled it starts on Changes.
onTabChange(tab: WorkTab) => void—Called when the user picks a tab.
onSend(message: ComposerMessage) => void—Called with the text, mode (ask, plan or act), context and model.
onStop() => void—Stop from the composer or the activity line.
onApply(selection: HunkSelection) => void—Apply the kept hunks from the Changes tab.
onDiscard() => void—Discard every change.
applyingbooleanfalsePuts the Apply button in its loading state.
onRestore(checkpoint: Checkpoint) => void—Called after the user confirms restoring to a checkpoint.
classNamestring—Extra classes for the root.
type CodingAgentData = {
  title: string;
  repo: string;
  branch: string;
  model: string;
  user: { name: string; avatar?: string };
  messages: ThreadMessage[];            // from chat-thread; content is a ReactNode
  activity?: AgentStatusData;           // live status at the end of the thread
  files: FileChange[];                  // from file-changes
  terminal: TerminalRun;                // from terminal-output
  checkpoints: Checkpoint[];            // from checkpoint-timeline
  preview: { url: string; content: ReactNode };
};

// Lays out by its own width: from 960px chat and the work panel sit side by side
// and either can be collapsed; below that a switch shows Chat, Changes, Terminal
// or Preview. Give the parent a height.