Claude
Skills
Sign in
Back

create-agent-tui

Included with Lifetime
$97 forever

Scaffolds a complete agent TUI in TypeScript using @openrouter/agent — like create-react-app for terminal agents. Generates a customizable terminal interface with three input styles, four tool display modes, ASCII banners, streaming output, session persistence, and configurable tools. Use when building an agent, creating a TUI, scaffolding an agent project, or building a coding assistant.

Web Dev

What this skill does


# Create Agent TUI

Scaffolds a complete agent TUI in TypeScript targeting OpenRouter. The generated project uses `@openrouter/agent` for the inner loop (model calls, tool execution, stop conditions) and provides the outer shell: a customizable terminal interface, configuration, session management, tool definitions, and an entry point.

Architecture draws from three production agent systems:
- **pi-mono/coding-agent** — three-layer separation, JSONL sessions, pluggable tool operations
- **Claude Code** — tool metadata (read-only, destructive, approval), system prompt composition
- **Codex CLI** — layered config, approval flow with session caching, structured logging

## Prerequisites

- Node.js 18+
- `OPENROUTER_API_KEY` from [openrouter.ai/settings/keys](https://openrouter.ai/settings/keys)
- For full SDK reference, see the `openrouter-typescript-sdk` skill

---

## Decision Tree

| User wants to... | Action |
|---|---|
| Build a new agent from scratch | Present checklist below → follow Generation Workflow |
| Add tools to an existing harness | Read [references/tools.md](references/tools.md), present tool checklist only |
| Add a harness module | Read [references/modules.md](references/modules.md), generate the module |
| Add an API server entry point | Read [references/server-entry-points.md](references/server-entry-points.md) |

---

## Interactive Tool Checklist

Present this as a multi-select checklist. Items marked **ON** are pre-selected defaults.

### OpenRouter Server Tools (server-side, zero implementation)

| Tool | Type string | Default | Config |
|------|------------|---------|--------|
| Web Search | `openrouter:web_search` | ON | engine, max_results, domain filtering |
| Datetime | `openrouter:datetime` | ON | timezone |
| Image Generation | `openrouter:image_generation` | OFF | model, quality, size, format |

Server tools go in the `tools` array alongside user-defined tools. No client code needed — OpenRouter executes them.

### User-Defined Tools (client-side, generated into src/tools/)

| Tool | Default | Description |
|------|---------|-------------|
| File Read | ON | Read files with offset/limit, detect images |
| File Write | ON | Write/create files, auto-create directories |
| File Edit | ON | Search-and-replace with diff validation |
| Glob/Find | ON | File discovery by glob pattern |
| Grep/Search | ON | Content search by regex |
| Directory List | ON | List directory contents |
| Shell/Bash | ON | Execute commands with timeout and output capture |
| JS REPL | OFF | Persistent Node.js environment |
| Sub-agent Spawn | OFF | Delegate tasks to child agents |
| Plan/Todo | OFF | Track multi-step task progress |
| Request User Input | OFF | Structured multiple-choice questions |
| Web Fetch | OFF | Fetch and extract text from web pages |
| View Image | OFF | Read local images as base64 |
| Custom Tool Template | ON | Empty skeleton for domain-specific tools |

### Harness Modules (architectural components)

| Module | Default | Description |
|--------|---------|-------------|
| Session Persistence | ON | JSONL append-only conversation log |
| ASCII Logo Banner | OFF | Custom ASCII art banner on startup — ask for project name |
| Context Compaction | OFF | Summarize older messages when context is long |
| System Prompt Composition | OFF | Assemble instructions from static + dynamic context |
| Tool Permissions / Approval | OFF | Gate dangerous tools behind user confirmation |
| Structured Event Logging | OFF | Emit events for tool calls, API requests, errors |
| `@`-file References | OFF | `@filename` to attach file content to next message |
| `!` Shell Shortcut | OFF | `!command` to run shell and inject output into context |
| Multi-line Input | OFF | Shift+Enter for multi-line (requires raw terminal mode) |

### Slash Commands (user-facing REPL commands)

| Command | Default | Description |
|---------|---------|-------------|
| `/model` | ON | Switch model via OpenRouter API |
| `/new` | ON | Start a fresh conversation |
| `/help` | ON | List available commands |
| `/compact` | OFF | Manually trigger context compaction |
| `/session` | OFF | Show session metadata and token usage |
| `/export` | OFF | Save conversation as Markdown |

When slash commands are enabled, generate `src/commands.ts` with a command registry. See [references/slash-commands.md](references/slash-commands.md) for specs.

### Visual Customization (present as single-select for each)

**Input style** — how the prompt looks. See [references/input-styles.md](references/input-styles.md):

| Style | Default | Description |
|-------|---------|-------------|
| `block` | ON | Full-width background box with `›` prompt, adapts to terminal theme |
| `bordered` | | Horizontal `─` lines above and below input |
| `plain` | | Simple `> ` readline prompt, no escape sequences |
| Other | | User describes what they want — implement a custom input style |

**Tool display** — how tool calls appear during execution. See [references/tool-display.md](references/tool-display.md):

| Style | Default | Description |
|-------|---------|-------------|
| `grouped` | ON | Bold action labels with tree-branch output |
| `emoji` | | Per-call `⚡`/`✓` markers with args and timing |
| `minimal` | | Aggregated one-liner summaries |
| `hidden` | | No tool output |
| Other | | User describes what they want — implement a custom display |

**Loader animation** — shown while waiting for model response. See [references/loader.md](references/loader.md):

| Style | Default | Description |
|-------|---------|-------------|
| `spinner` | ON | Braille dot spinner (⠋⠙⠹…) to the left of the text |
| `gradient` | | Scrolling color shimmer over the loader text |
| `minimal` | | Trailing dots (`Working···`) |
| Other | | User describes what they want — implement a custom animation |

Also ask for the **loader text** (default: `"Working"`).

---

## Generation Workflow

After getting checklist selections, follow this workflow:

```
- [ ] Generate package.json with dependencies
- [ ] Generate src/config.ts (add showBanner field if ASCII Logo Banner is ON)
- [ ] Generate src/tools/index.ts wiring selected tools + server tools
- [ ] Generate selected tool files in src/tools/ (see Tool Pattern below, specs in references/tools.md)
- [ ] Generate src/agent.ts (core runner)
- [ ] Generate selected harness modules (specs in references/modules.md)
- [ ] Generate src/terminal-bg.ts (adaptive input background — see references/tui.md)
- [ ] Generate input style functions in src/cli.ts (block/bordered/plain — see references/input-styles.md)
- [ ] Generate src/renderer.ts (tool display — see references/tool-display.md)
- [ ] Generate src/loader.ts (loader animation — see references/loader.md)
- [ ] If slash commands selected: generate src/commands.ts (see references/slash-commands.md)
- [ ] If ASCII Logo Banner is ON: generate src/banner.ts (see ASCII Logo Banner section below)
- [ ] Generate src/cli.ts entry point (or src/server.ts — see references/server-entry-points.md)
- [ ] Generate .env.example with OPENROUTER_API_KEY=
- [ ] Verify: run npx tsc --noEmit to check types
```

---

## Tool Pattern

All user-defined tools follow this pattern using `@openrouter/agent/tool`. Here is one complete example — all other tools in [references/tools.md](references/tools.md) follow the same shape:

```typescript
import { tool } from '@openrouter/agent/tool';
import { z } from 'zod';
import { readFile, stat } from 'fs/promises';

const DEFAULT_LINE_LIMIT = 2000;
const MAX_LINE_CHARS = 2000;

export const fileReadTool = tool({
  name: 'file_read',
  description:
    'Read the contents of a file. Output is capped at 2000 lines by default (use offset/limit to paginate) and any line longer than 2000 characters is truncated. When the response is truncated, the hint field tells you how to continue.',
  inputSchema: z.object({
    path: z.string().describe('Absolute path to the file'),
    offset: z.number().optional().describe('Start readin
Files: 46
Size: 492.0 KB
Complexity: 68/100
Category: Web Dev

Related in Web Dev