---
title: "Chapter 11: Polish & Introspection"
description: "Clean up tool implementations, add session compaction, self-analysis, and document known issues."
type: lesson
order: 11
chapter: "03-advanced"
---

# Chapter 11: Polish & Introspection

## What We're Building

The final chapter is about making everything work well together. We'll:

- Clean up tool implementations
- Add response limits to prevent context overflow
- Implement session compaction (summarize old context)
- Add session introspection (analyze your own logs)
- Document known issues and future roadmap

## Step 1: Clean Up Tools

Paste:

> look through the tools implementations and make sure that it's clean, and make sure that we are using ripgrep for searching

> add a limit to the size of the response for search_files to make sure that it doesn't return more than 50 lines. also add a 500 line limit to read_file and add some offset parameters to it. remove git commit command also

### The Limit System

**`search_files`** — max 50 matches:

```typescript
const lines = result.trim().split("\n");
if (lines.length > 50) {
  return (
    lines.slice(0, 50).join("\n") +
    `\n... (and ${lines.length - 50} more matches)`
  );
}
```

**`read_file`** — max 500 lines with start/limit:

```typescript
const start = Math.max(0, startLine - 1);
const safeLimit = Math.min(limit, 500);
const end = Math.min(lines.length, start + safeLimit);

if (lines.length > end - start) {
  result += `\n\n(Showing lines ${start + 1}-${end} of ${lines.length}. Use startLine and limit to see more.)`;
}
```

### No Auto-Commit

The system prompt explicitly forbids auto-commit:

```
6. **No Auto-Commit**: NEVER automatically commit changes. You may use
   'git_diff' to verify changes, but you must ask the user for confirmation
   before committing, or wait for the user to commit manually.
```

## Step 2: Session Compaction

As conversations grow, the context window fills up. Compaction summarizes the conversation history into a concise format, preserving essential context while freeing up tokens.

Paste:

> Add session compaction — when the context gets too large, summarize the conversation history into a compact form that preserves the key decisions, code changes, and current state.

The compaction flow:

1. **Detect**: When total tokens exceed ~80% of the context window
2. **Summarize**: An agent (or subagent) reads the conversation and produces a summary
3. **Replace**: Old messages are replaced with a single system message containing the summary
4. **Continue**: The agent continues with fresh context

The summary format:

```
## Session Summary
### Current State
- Branch: main
- Last action: Completed tool refactoring
- Files modified: src/tools/files.ts, src/tools/search.ts

### Key Decisions
1. Use ripgrep for all text search
2. 50-line limit on search results
3. 500-line limit on file reads

### Pending Work
- Session logging needs subagent parent tracking
- TUI improvements pending
```

## Step 3: Session Introspection

Paste:

> add a session-analysis agent that reads the session logs, identifies patterns (which tools are used most, where errors occur, what costs the most), and generates a report with recommendations

The introspection agent:

1. Reads `.session_logs/` files
2. Counts tool usage, error rates, costs
3. Identifies patterns: "You use `read_file` 3× more than `search_files` — consider searching first"
4. Generates recommendations: "Most errors happen in `replace_in_file` — consider adding a preview step"

## Step 4: The ask_user Tool

Paste:

> We need a way for subagents to query the user for questions. Create a subagent who makes a poem about your name, and asks you first what your name is and then a follow up question about a color, and then writes a poem. Then lets test out the subagent to make sure that the main loop handles the handoff correctly, and knows what the final answer is.

The `ask_user` tool in `src/tools/user.ts`:

```typescript
import { askQuestion } from "../lib/readline";

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

This shows labeled prompts like:

```
[poet] What is your name?
> Will

[poet] What is your favorite color?
> blue

[poem about Will and the color blue...]
```

## Step 5: Known Issues & Roadmap

### Things to Be Aware Of

- **Subagent readline**: Multiple subagents using `ask_user` simultaneously can be confusing. The current implementation serializes them.
- **Context overflow**: Without compaction, long sessions degrade. Model behavior at the context limit varies — some get confused, some start repeating.
- **Tool result truncation**: Results over 1,000 characters are truncated in the console display but the full result goes to the LLM.
- **Model selection**: Gemini is cheaper but can be less precise than Opus for complex refactoring. Experiment to find your sweet spot.

### Future Improvements

| Area                        | What Could Be Better                                                        |
| --------------------------- | --------------------------------------------------------------------------- |
| **Streaming**               | Show partial LLM output as it generates (currently waits for full response) |
| **MCP Integration**         | Connect to the Model Context Protocol ecosystem for reusable tools          |
| **Evaluation**              | Automated test suite that validates agent behavior doesn't regress          |
| **Undo/Rollback**           | Git-based recovery from agent mistakes                                      |
| **OpenRouter Alternatives** | Direct Anthropic/Google/OpenAI connections for provider-specific features   |

## Step 6: Final Verification

```
run the full test suite and lint everything
```

```bash
mise run check
```

Everything should pass:

```
✓ sanity.test.ts — all tests pass
✓ tools.test.ts — all tools tested
✓ agent.test.ts — agent loop verified
✓ api.test.ts — API client tested
✓ search.test.ts — ripgrep search tested
✓ web.test.ts — URL download tested
✓ tavily.test.ts — Tavily search tested
✓ subagent.test.ts — subagent spawning tested

Checked 24 files in 85ms. No errors.
```

---

## The Complete Architecture

```
weekend-coding-agent/
├── src/
│   ├── index.ts              # REPL, session setup, cost display
│   ├── agent.ts              # runTurn loop, subagent runner
│   ├── lib/
│   │   ├── api.ts            # OpenRouter client, model stats
│   │   ├── logger.ts         # JSONL session logging
│   │   ├── readline.ts       # Terminal I/O
│   │   └── types.ts          # Message, CompletionResponse
│   ├── tools/
│   │   ├── index.ts          # Tool definitions + dispatch
│   │   ├── files.ts          # listFiles, readFile, writeFile, replaceInFile
│   │   ├── search.ts         # ripgrep search
│   │   ├── system.ts         # bash execution
│   │   ├── web.ts            # URL → markdown
│   │   ├── tavily.ts         # Web search
│   │   ├── git.ts            # git diff
│   │   ├── user.ts           # ask_user (human-in-the-loop)
│   │   └── types.ts          # CommandExecutor, AgentRunner
│   └── prompts/
│       ├── index.ts          # Prompt loader, skill loader
│       ├── default.md        # Main coding agent
│       ├── code-map.md       # Codebase documentation agent
│       ├── tech-researcher.md # Web research agent
│       ├── feature-planner.md # Feature planning agent
│       └── poet.md           # Interactive poem agent
├── skills/
│   ├── big_text/SKILL.md     # figlet ASCII art
│   ├── generate_image/SKILL.md # Image generation
│   └── generate_video/SKILL.md # Video generation
├── tests/                    # Full test suite
├── .session_logs/            # JSONL recording
├── docs/                     # Code maps
├── reports/                  # Research reports
├── .env                      # API keys
├── mise.toml                 # Tasks and tools
└── biome.json                # Linter config
```

---

[← Chapter 10](/build-ai-coding-agent/03-advanced/10-skills/) · [Course Home →](/build-ai-coding-agent/)
