---
title: "Chapter 08: UI Upgrades"
description: "Improve the terminal interface with model info on startup, status display, collapsible tool blocks, and better input handling."
type: lesson
order: 8
chapter: "03-advanced"
---

# Chapter 08: UI Upgrades

## What We're Building

The agent's current interface is functional but bare. We'll upgrade it with:

- **Splash screen**: Model info, pricing, recent sessions on startup
- **Status bar**: Current model, session cost, message count
- **Tool call display**: Collapsible tool blocks with inline output
- **Better input**: Keyboard shortcuts, paste handling, tab/arrow navigation
- **Agent labels**: Clear indication of which agent is responding

## Step 1: Clean Up Tool Display

Paste this prompt:

> update the search tool in src so that it doesn't look through node_modules by default, only if specifically asked. make sure that everything is properly tested. make sure that typechecking and linting are run all of the time. verify that we are showing reasoning specs, and verify that our usage totals are over the whole conversation

This ensures:

- `search_files` skips `node_modules` unless `includeNodeModules: true`
- Reasoning details from Gemini are displayed
- Usage totals accumulate across the full session (not per-turn)

## Step 2: Improve Welcome Screen

Paste this prompt:

> Improve the welcome screen — show model name, pricing, recent session logs, and a more helpful startup message. Show the selected prompt name and description on startup.

The updated startup in `src/index.ts`:

```typescript
// Fetch and display model stats
console.log("Fetching model stats for", MODEL, "...");
const stats = await fetchModelStats();
if (stats) {
  console.log(`Model: ${stats.name}`);
  console.log(
    `Cost: $${stats.cost.prompt * 1000000} per 1M input tokens, ` +
      `$${stats.cost.completion * 1000000} per 1M output tokens`,
  );
}

// Show selected prompt
const selectedPrompt = getPrompt(promptName);
console.log(
  `Using prompt: ${selectedPrompt.name} - ${selectedPrompt.description}`,
);

console.log("Agent started. Type 'exit' to quit.");
```

## Step 3: Agent Labels for Subagents

When subagents run, we need to know who's talking. Paste:

> update the prompt so we know what agent the message is going to. Like [poem]> or something like that. What would happen if multiple poem agents were running at the same time?

The agent will add a scrolling label in the tool display:

```
--- [Subagent Start] code-map ---
Task: Map the entire codebase

[Tool: list_files] {"path":"src/"}
src/
├── index.ts
├── agent.ts
├── lib/
├── tools/
└── prompts/

[Tool: read_file] {"path":"src/agent.ts"}
[content displayed...]

--- [Subagent End] code-map ---
```

The `agentName` parameter flows through the system from `runTurn` to the `ask_user` tool, which prefixes prompts with the agent name:

```typescript
export async function askUser(
  question: string,
  agentName = "system",
): Promise<string> {
  const answer = await askQuestion(`\n[${agentName}] ${question}\n> `);
  return answer;
}
```

## Step 4: Tool Call Display

The agent already shows tool calls nicely. Here's the current approach in `src/agent.ts`:

```typescript
// For bash commands, show the command directly:
if (toolCall.function.name === "bash" && args.command) {
  console.log(`$ ${args.command}`);
} else {
  const argStr = JSON.stringify(args);
  const displayArgs =
    argStr.length > 100 ? `${argStr.substring(0, 97)}...` : argStr;
  console.log(`[Tool: ${toolCall.function.name}] ${displayArgs}`);
}

// Truncate results if too long:
const displayResult =
  result.length > 1000 ? `${result.substring(0, 1000)}... [truncated]` : result;
console.log(displayResult);
```

## Step 5: Reasoning Display

When the model provides reasoning (Gemini's thinking), it's displayed:

```typescript
if (m.reasoning_details) {
  if (Array.isArray(m.reasoning_details) && m.reasoning_details.length > 0) {
    console.log("\n[Reasoning]:", m.reasoning_details[0].text);
  } else if (typeof m.reasoning_details === "string") {
    console.log("\n[Reasoning]:", m.reasoning_details);
  }
}
```

This shows the model's internal thinking before it takes action — great for understanding why the agent made a particular decision.

## Step 6: Fix Subagent Readline Issues

Subagents that use `ask_user` can interfere with the main input loop:

> when a subagent starts up and finishes, it quits out of the agent. I think it has to do with the readline stuff

The fix ensures that `getInterface()` returns the same readline instance across the whole process:

```typescript
let rl: readline.Interface | null = null;

export function getInterface(): readline.Interface {
  if (!rl) {
    rl = readline.createInterface({
      input: process.stdin,
      output: process.stdout,
      prompt: "> ",
    });
  }
  return rl;
}
```

This singleton pattern prevents multiple readline instances from fighting over stdin/stdout.

---

## The Display Flow

Here's what a typical interaction looks like after all UI upgrades:

```
Fetching model stats for google/gemini-3-pro-preview ...
Model: Google Gemini 3 Pro Preview
Cost: $1.25 per 1M input tokens, $10.00 per 1M output tokens
Using prompt: default - The default full-featured agent.
Agent started. Type 'exit' to quit.

> search for all TypeScript interfaces in the codebase

[Tool: search_files] {"query":"interface ","path":"src/"}

src/lib/types.ts:1:export interface Message {
src/lib/types.ts:11:export interface CompletionResponse {
src/lib/api.ts:7:export interface ModelStats {
src/lib/logger.ts:4:export interface Logger {
src/tools/tavily.ts:1:interface TavilyResult {
src/tools/tavily.ts:8:interface TavilyResponse {
src/tools/types.ts:1:export type CommandExecutor = ...
src/tools/types.ts:3:export type AgentRunner = ...
src/prompts/index.ts:6:export interface Prompt {

Assistant: The codebase has these TypeScript interfaces and types:
[lists and explains each...]

[Turn Usage] Input: 850 | Output: 320 | Cost: $0.004262
[Session Total] Input: 12800 | Output: 4500 | Cost: $0.061000
```

---

[← Chapter 07](/build-ai-coding-agent/02-core/07-research/) · [Next: Chapter 09 →](/build-ai-coding-agent/03-advanced/09-subagents/)
