# TUI Reference

The `agents tui` command launches the **CleverAgents Terminal User Interface** — a
full-screen, interactive application built on [Textual](https://textual.textualize.io/).
The TUI provides real-time plan monitoring, multi-session management, persona switching,
and rich conversation with actors in a single terminal window.

## Installation

The TUI requires the optional `tui` extra:

```bash
pip install 'cleveragents[tui]'
```

Without this extra, `agents tui` raises an actionable error:

```
RuntimeError: Textual dependency missing. Install with: pip install 'cleveragents[tui]'
```

## Launching the TUI

```bash
agents tui
```

### Options

| Flag | Description |
|------|-------------|
| `--headless` | Run a one-shot startup check without opening the full UI loop (useful for CI smoke tests) |

## Layout

The TUI is composed of the following regions, rendered top-to-bottom:

```
┌─────────────────────────────────────────────────────┐
│  Header (clock)                                     │
├─────────────────────────────────────────────────────┤
│  Conversation area                                  │
│  ┌─────────────────────────────────────────────┐   │
│  │  Help Panel Overlay (F1, hidden by default) │   │
│  └─────────────────────────────────────────────┘   │
│  ┌─────────────────────────────────────────────┐   │
│  │  Reference Picker Overlay (@)               │   │
│  └─────────────────────────────────────────────┘   │
│  ┌─────────────────────────────────────────────┐   │
│  │  Slash Command Overlay (/)                  │   │
│  └─────────────────────────────────────────────┘   │
│  Prompt Input                                       │
│  Persona Bar                                        │
├─────────────────────────────────────────────────────┤
│  Footer (key bindings)                              │
└─────────────────────────────────────────────────────┘
```

## Global Key Bindings

| Key | Action |
|-----|--------|
| `Ctrl+Q` | Quit the TUI immediately |
| `F1` | Toggle the context-sensitive help panel |
| `Ctrl+T` | Cycle to the next argument preset for the active persona |
| `Escape` | Close the current overlay and return to the prompt |

## Input Modes

The prompt detects the input mode from the first character of the text:

| Prefix | Mode | Behaviour |
|--------|------|-----------|
| *(none)* | **Normal** | Message text with optional `@reference` expansion |
| `/` | **Command** | Slash command dispatched to the command router |
| `!` or `$` | **Shell** | Shell command executed via subprocess |

### Normal Mode

Type a message and press `Enter` to submit. Use `@` to open the Reference Picker
overlay and insert file, resource, or plan references inline.

### Command Mode (`/`)

Type `/` to open the Slash Command overlay. A filtered list of matching commands
appears as you type. Press `Enter` to dispatch the selected command.

See [Slash Commands](#slash-commands) for the full catalog.

### Shell Mode (`!`)

Type `!` followed by a shell command to execute it in a subprocess. Output is
captured and displayed in the conversation area.

!!! warning "Shell mode safety"
    Shell execution is gated by the `CLEVERAGENTS_ALLOW_DANGEROUS_SHELL`
    environment variable. Set it to `1` or `true` to permit shell commands.
    When unset, shell commands are blocked.

Before execution, the command is scanned by the **shell danger detection**
subsystem. If a dangerous pattern is matched (e.g. `rm -rf /`, fork bombs,
pipe-to-shell), a warning overlay is shown with the danger level and a
description of the risk. The user can cancel or proceed.

See [Shell Danger Detection](tui_shell_safety.md) for the full reference,
including the built-in pattern registry and how to add custom patterns.

## Help Panel (F1)

Press `F1` at any time to toggle the context-sensitive help panel. The panel
content adapts to the current prompt context:

| Context | Triggered when |
|---------|---------------|
| **Main Screen** | Prompt is empty or contains normal text |
| **Slash Commands** | Prompt starts with `/` |
| **Reference Picker** | Prompt contains `@` |
| **Shell Mode** | Prompt starts with `!` or `$` |

Each context shows global key bindings plus context-specific shortcuts.

## Persona Bar

The status bar at the bottom of the conversation area displays:

```
<persona_name> | <actor_name> | <preset_name> | <N> scope refs
```

- **persona_name** — the active persona (e.g. `default`)
- **actor_name** — the actor bound to the persona (e.g. `openai/gpt-4o`)
- **preset_name** — the active argument preset (e.g. `default`)
- **scope refs** — count of scoped projects and plans

Use `Ctrl+T` to cycle through the argument presets defined in the active persona.

## Slash Commands

The TUI ships with **67 slash commands** across **14 groups**. Type `/` in the
prompt to open the overlay and filter by name.

### Session

| Command | Description |
|---------|-------------|
| `/session:create` | Create a new session tab |
| `/session:list` | Display all sessions |
| `/session:show` | Show session details |
| `/session:switch` | Switch to a session |
| `/session:close` | Close the current session |
| `/session:delete` | Delete a saved session |
| `/session:rename` | Rename current session |
| `/session:export` | Export session to JSON |
| `/session:import` | Import session from JSON |

### Persona

| Command | Description |
|---------|-------------|
| `/persona:list` | Display all personas |
| `/persona:set` | Switch active persona |
| `/persona:create` | Create a persona |
| `/persona:edit` | Edit a persona |
| `/persona:delete` | Delete a persona |
| `/persona:export` | Export persona YAML |
| `/persona:import` | Import persona YAML |

### Scope

| Command | Description |
|---------|-------------|
| `/scope:add` | Add scope reference |
| `/scope:remove` | Remove scope reference |
| `/scope:clear` | Clear session scope additions |
| `/scope:show` | Show effective scope |

### Plan

| Command | Description |
|---------|-------------|
| `/plan:use` | Start a new plan |
| `/plan:list` | List plans |
| `/plan:status` | Show plan status |
| `/plan:tree` | Show decision tree |
| `/plan:execute` | Execute a plan |
| `/plan:apply` | Apply a completed plan |
| `/plan:cancel` | Cancel a plan |
| `/plan:diff` | Show plan diff |
| `/plan:correct` | Correct a decision |
| `/plan:resume` | Resume a plan |
| `/plan:revert` | Revert plan state |
| `/plan:rollback` | Rollback to checkpoint |
| `/plan:explain` | Explain a decision |
| `/plan:errors` | Show plan errors |
| `/plan:artifacts` | Show plan artifacts |
| `/plan:inspect` | Inspect plan details |

### Project

| Command | Description |
|---------|-------------|
| `/project:list` | List projects |
| `/project:create` | Create project |
| `/project:show` | Show project details |
| `/project:delete` | Delete project |
| `/project:inspect` | Inspect project details |
| `/project:context:show` | Show project context policy |

### Actor

| Command | Description |
|---------|-------------|
| `/actor:list` | List actors |
| `/actor:show` | Show actor details |
| `/actor:set-default` | Set default actor |

### Resource

| Command | Description |
|---------|-------------|
| `/resource:list` | List resources |
| `/resource:show` | Show resource details |
| `/resource:tree` | Show resource tree |
| `/resource:inspect` | Inspect resource details |

### Config

| Command | Description |
|---------|-------------|
| `/config:list` | List config entries |
| `/config:get` | Get config value |
| `/config:set` | Set config value |

### Tool

| Command | Description |
|---------|-------------|
| `/tool:list` | List tools |
| `/tool:show` | Show tool details |

### Skill

| Command | Description |
|---------|-------------|
| `/skill:list` | List skills |
| `/skill:show` | Show skill details |

### Invariant

| Command | Description |
|---------|-------------|
| `/invariant:list` | List invariants |
| `/invariant:add` | Add invariant |
| `/invariant:remove` | Remove invariant |

### Profile

| Command | Description |
|---------|-------------|
| `/profile:list` | List automation profiles |
| `/profile:show` | Show automation profile |

### Context

| Command | Description |
|---------|-------------|
| `/context:inspect` | Inspect context state |
| `/context:set` | Set context policy |
| `/context:simulate` | Simulate context assembly |

### Utility

| Command | Description |
|---------|-------------|
| `/clear` | Clear conversation display |
| `/theme` | Switch color theme |
| `/settings` | Open settings |
| `/help` | Show help |
| `/about` | Show version information |
| `/debug` | Toggle debug mode |

## Persona System

Personas are YAML configuration files stored in `~/.config/cleveragents/personas/`
(overridable via `CLEVERAGENTS_CONFIG_DIR`). Each persona binds an actor, optional
argument presets, and scope references to a named identity.

### Persona YAML Schema

```yaml
name: my-persona          # Required. Must not contain path separators.
actor: openai/gpt-4o      # Required. Must be namespaced (namespace/name).
description: "My persona" # Optional.
icon: ""                  # Optional display icon.
color: null               # Optional terminal color.
base_arguments: {}        # Default arguments merged into every request.
scoped_projects: []       # Project names always in scope.
scoped_plans: []          # Plan IDs always in scope.
cycle_order: 0            # Position in Ctrl+T cycle (0 = excluded).
greeting: ""              # Optional greeting message on activation.
argument_presets:         # Named argument override sets.
  - name: default         # Required. Must have empty overrides.
    display: default
    overrides: {}
  - name: verbose
    display: Verbose
    overrides:
      verbosity: high
```

### Rules

- Every persona must contain exactly one `default` preset with empty `overrides`.
- `cycle_order` values must be unique when greater than zero.
- `actor` must be namespaced: `namespace/name`.
- `name` must not contain `/`, `\`, `..`, null bytes, or control characters.

### Persona State

The TUI tracks the active persona and current preset per session in memory.
The last-used persona name is persisted to `~/.config/cleveragents/tui-state.yaml`
and restored on the next launch.

### Import / Export

```bash
# Export a persona to a file
/persona:export  # then provide name and output path

# Import a persona from a file
/persona:import  # then provide the YAML file path
```

Export and import paths must be relative to the current working directory.

## Architecture

The TUI is implemented as a Textual `App` subclass (`CleverAgentsTuiApp`) in
`src/cleveragents/tui/app.py`. It communicates with the application layer
exclusively through the A2A local facade — the same protocol used by the CLI.

Key modules:

| Module | Purpose |
|--------|---------|
| `tui/app.py` | Main Textual app, widget composition, key bindings |
| `tui/persona/schema.py` | `Persona` and `PersonaPreset` Pydantic models |
| `tui/persona/registry.py` | YAML-backed persona storage with file locking |
| `tui/persona/state.py` | In-memory session-to-persona mapping |
| `tui/input/modes.py` | `InputModeRouter` — normal / command / shell dispatch |
| `tui/input/reference_parser.py` | `@reference` expansion and fuzzy suggestions |
| `tui/input/shell_exec.py` | Subprocess shell execution with safety gate |
| `tui/slash_catalog.py` | `SLASH_COMMAND_SPECS` — 67-command catalog |
| `tui/widgets/help_panel_overlay.py` | Context-sensitive F1 help panel |
| `tui/widgets/persona_bar.py` | Bottom status bar showing active persona |
| `tui/widgets/prompt.py` | Prompt input widget |
| `tui/widgets/reference_picker.py` | `@reference` picker overlay |
| `tui/widgets/slash_command_overlay.py` | `/command` picker overlay |
| `tui/widgets/thought_block.py` | Expandable actor reasoning trace widget |
| `tui/permissions/models.py` | `ToolPermissionRequest`, `PermissionDecision`, `DiffDisplayMode` |
| `tui/permissions/screen.py` | `PermissionsScreen` — split-pane diff view for tool permission requests |
| `tui/permissions/service.py` | `PermissionRequestService` — request queue and session-scoped decisions |
| `tui/widgets/permission_question.py` | `PermissionQuestionWidget` — inline single-file permission request widget |
| `tui/widgets/actor_selection_overlay.py` | `ActorSelectionOverlay` — first-run actor selection overlay |
| `tui/shell_safety/pattern_detector.py` | `DangerousPatternDetector` — shell command danger detection |
| `tui/shell_safety/pattern_registry.py` | `DEFAULT_PATTERNS` — built-in dangerous shell pattern registry |
| `tui/first_run.py` | `is_first_run()`, `create_default_persona_for_actor()` — first-run helpers |

## First-Run Experience

On first launch — when no personas are configured — the TUI displays the
`ActorSelectionOverlay` in the centre of the screen. The overlay guides the
user to select an actor from a curated list:

- `anthropic/claude-4-sonnet` *(recommended)*
- `anthropic/claude-4-opus`
- `openai/gpt-4o`
- `openai/o3`
- `google/gemini-2`

**Key bindings inside the overlay:**

| Key | Action |
|-----|--------|
| `j` / `↓` | Move selection down |
| `k` / `↑` | Move selection up |
| `/` | Enter search mode to filter actors |
| `Enter` | Confirm the highlighted actor |

After confirmation, a `"default"` persona is created and the overlay is
dismissed. Subsequent launches restore the last active persona from
`~/.config/cleveragents/tui-state.yaml`.

**Module**: `cleveragents.tui.widgets.actor_selection_overlay`

The `ActorSelectionOverlay` widget exposes:

| Property / Method | Description |
|-------------------|-------------|
| `actors` | Full (unfiltered) actor list |
| `filtered_actors` | Currently filtered actor list |
| `selected_index` | Zero-based index of the highlighted actor |
| `search_query` | Active search filter string |
| `confirmed` | `True` if the user has confirmed a selection |
| `selected_actor` | Confirmed actor name, or `None` if not yet confirmed |
| `show(actors?)` | Display the overlay, optionally overriding the actor list |
| `hide()` | Hide the overlay |
| `move_up()` / `move_down()` | Navigate the list |
| `set_search(query)` | Apply a substring filter (case-insensitive) |
| `confirm()` | Confirm the highlighted actor; returns the actor name or `None` |

The first-run detection helper is in `cleveragents.tui.first_run`:

```python
from cleveragents.tui.first_run import is_first_run, create_default_persona_for_actor

if is_first_run(registry):
    # Show ActorSelectionOverlay, then:
    persona = create_default_persona_for_actor(registry, "openai/gpt-4o")
```

---

## Inline Permission Questions

For **single-file** permission requests, the TUI renders a
`PermissionQuestionWidget` inline in the conversation stream rather than
pushing the full `PermissionsScreen`.

```
Permission Required

The actor wants to write to:
  src/api/main.py

  ❯ a  Allow once
    A  Allow always (this session)
    r  Reject once
    R  Reject always (this session)

Press v to open full PermissionsScreen with diff view
```

**Key bindings:**

| Key | Action |
|-----|--------|
| `a` | Allow once |
| `A` | Allow always (this session) |
| `r` | Reject once |
| `R` | Reject always (this session) |
| `↑` / `↓` | Navigate options |
| `Enter` | Confirm highlighted option |
| `v` | Open full `PermissionsScreen` with diff view |

A `PermissionDecisionEvent` is emitted when the user makes a decision.

See [Permission Question Widget](tui_permission_question.md) for the full
API reference.

---

## Permissions Screen

When an actor requests a write operation on a resource, the TUI raises the
`PermissionsScreen` overlay. The user reviews the proposed changes in a
split-pane layout (file list left, diff view right) and decides whether to
allow or reject the operation.

**Key bindings inside PermissionsScreen:**

| Key | Action |
|-----|--------|
| `a` | Allow this request once |
| `A` | Allow all requests from this tool for the session |
| `r` | Reject this request once |
| `R` | Reject all requests from this tool for the session |
| `d` | Cycle diff mode: unified → side-by-side → context |

See [`tui_permissions.md`](tui_permissions.md) for the full API reference.

## Actor Thought Blocks

Actors that support extended thinking (e.g. Claude extended thinking mode)
emit reasoning traces that are rendered as `ThoughtBlockWidget` instances
in the conversation stream. Thought blocks are displayed with muted styling
and can be expanded or collapsed with `Space`.

See [`tui_thought_block.md`](tui_thought_block.md) for the full API reference.

## Related Documentation

- [ADR-044: TUI Architecture and Framework](../adr/ADR-044-tui-architecture-and-framework.md)
- [ADR-045: TUI Persona System](../adr/ADR-045-tui-persona-system.md)
- [ADR-046: TUI Reference and Command System](../adr/ADR-046-tui-reference-and-command-system.md)
- [TUI Permissions Screen](tui_permissions.md)
- [TUI Permission Question Widget](tui_permission_question.md)
- [TUI Shell Danger Detection](tui_shell_safety.md)
- [TUI Thought Blocks](tui_thought_block.md)
- [Session CLI Reference](session_cli.md)
- [Output Rendering Framework](output_rendering.md)
- [REPL Reference](repl.md)
