56f3b49725
Add the complete TUI (Terminal User Interface) specification section to docs/specification.md, covering architecture, layout, navigation, persona system, reference picker, slash commands, shell mode, session management, and keyboard shortcuts. The section includes 18 HTML-styled ASCII mockup diagrams using the Dracula color palette that render with actual colors in MkDocs. Key specification areas: - MainScreen layout with right-side collapsible sidebar (3 states: hidden, visible, fullscreen cycled by shift+tab) - Direct-to-chat launch with first-run actor selection overlay - Persona system bundling actor + arguments + project/plan scope, cycled with tab; argument presets cycled with ctrl+tab - @ reference picker with fuzzy search for projects/plans/resources - / slash commands mirroring CLI noun:verb patterns (session:new, plan:list, project:show, actor:switch, etc.) - ! shell mode for direct command execution - Multi-session tabs with independent personas and conversations - Escape-cascading navigation back to main screen - Plan detail view with decision tree navigation - Project detail view with resource DAG - Permission approval workflow with diff view - Complete keyboard shortcut reference table New ADR files: - ADR-044: TUI Architecture and Framework (Textual >= 1.0) - ADR-045: TUI Persona System - ADR-046: TUI Reference and Command System (CLI-aligned commands) Also adds TUI mockup CSS classes to docs/stylesheets/extra.css for Dracula-palette diagram rendering (.tui-primary, .tui-secondary, .tui-success, .tui-warning, .tui-error, .tui-dim, .tui-bold, .tui-bold-primary, .tui-bold-warning, .tui-primary-u, .tui-rainbow).
317 lines
19 KiB
Markdown
317 lines
19 KiB
Markdown
---
|
||
adr_number: 45
|
||
title: TUI Persona System
|
||
status_history:
|
||
- - '2026-03-10'
|
||
- Proposed
|
||
- Jeffrey Phillips Freeman
|
||
- - '2026-03-10'
|
||
- Accepted
|
||
- Jeffrey Phillips Freeman
|
||
tier: 4
|
||
authors:
|
||
- Jeffrey Phillips Freeman
|
||
superseded_by: null
|
||
related_adrs:
|
||
- number: 10
|
||
title: Actor and Agent Architecture
|
||
relationship: Personas reference actors defined by the actor architecture
|
||
- number: 17
|
||
title: Automation Profiles
|
||
relationship: Persona argument presets may override automation profile selection
|
||
- number: 20
|
||
title: Session Model
|
||
relationship: Each TUI session binds to a persona which configures the session's actor and scope
|
||
- number: 44
|
||
title: TUI Architecture and Framework
|
||
relationship: Personas are a TUI-specific concept within the TUI architecture
|
||
- number: 9
|
||
title: Project Model
|
||
relationship: Personas scope to projects defined by the project model
|
||
- number: 6
|
||
title: Plan Lifecycle
|
||
relationship: Personas scope to plans that follow the plan lifecycle
|
||
acceptance:
|
||
votes_for:
|
||
- voter: Jeffrey Phillips Freeman <Jeffrey.Freeman@CleverThis.com>
|
||
comment: The persona abstraction elegantly bundles the TUI-specific combination of actor selection, argument configuration, project/plan scoping, and argument presets into a single switchable unit — solving the multi-project workflow ergonomics problem without polluting the domain model
|
||
votes_against: []
|
||
abstentions: []
|
||
---
|
||
## Context
|
||
|
||
In the CLI, each invocation specifies its configuration explicitly: `agents plan use --actor anthropic/claude-4 --project local/api-service --automation-profile trusted ...`. This is appropriate for stateless command execution but creates friction in the TUI, where users conduct long-running interactive sessions and frequently switch between different actor configurations, project scopes, and reasoning modes.
|
||
|
||
Consider a developer managing three projects simultaneously. In the CLI, they would run separate commands with different flags for each project. In the TUI, they need a way to quickly switch their entire working context — the actor, its configuration arguments, and the set of projects and plans the actor should focus on — without re-typing configuration every time.
|
||
|
||
Additionally, the CleverAgents system supports actors with configurable arguments (e.g., `thinking_effort`, `temperature`, `max_tokens`). Power users frequently want to toggle between reasoning modes (e.g., "quick answer" vs. "deep analysis") within the same session. This requires a mechanism to define named argument overlays that can be cycled through rapidly.
|
||
|
||
None of these concerns belong in the domain model: they are purely Presentation-layer ergonomics for the TUI. The domain layer knows about actors, sessions, projects, and plans — but not about the TUI-specific bundling of these into a switchable unit.
|
||
|
||
## Decision Drivers
|
||
|
||
- Users working with multiple projects need to switch their entire working context (actor, arguments, project scope, plan scope) as a single atomic operation, not as individual flag changes
|
||
- Argument presets (e.g., cycling through thinking effort levels) are a common workflow pattern that should be achievable with a single keypress, not by editing configuration
|
||
- The persona concept must remain a TUI-only abstraction — it must not leak into the domain model, ACP protocol, or database schema
|
||
- Default behavior must be sensible without any persona configuration: first-run users should get a working persona automatically based on their actor selection
|
||
- The persona system must integrate cleanly with the existing actor argument system — presets overlay arguments, they do not replace them
|
||
- Personas must be portable (exportable/importable) for team sharing and machine migration
|
||
|
||
## Decision
|
||
|
||
CleverAgents introduces the **Persona** concept as a TUI-only abstraction that bundles:
|
||
|
||
1. **Actor reference** — a namespaced actor name (e.g., `anthropic/claude-4-sonnet`)
|
||
2. **Base arguments** — the default arguments passed to the actor on every invocation
|
||
3. **Scoped projects** — a list of project references that are always included in the session's context
|
||
4. **Scoped plans** — a list of plan references that are always included in the session's context
|
||
5. **Argument presets** — named sets of argument overrides that can be cycled with `ctrl+tab`
|
||
6. **Display metadata** — a short name, optional accent color, and description
|
||
|
||
Personas are:
|
||
|
||
- **Stored locally** in `~/.config/cleveragents/personas/` as individual YAML files
|
||
- **Cyclable** via `tab` in the main chat screen, cycling through a user-configured ordered list
|
||
- **Session-bound** — each TUI session has a current persona; changing the persona mid-session updates the actor and scope for subsequent prompts (previous conversation history is retained)
|
||
- **Auto-generated** on first run from the actor selection, with thinking-level presets auto-detected from the actor's argument schema
|
||
|
||
## Design
|
||
|
||
### Persona Data Model
|
||
|
||
```yaml
|
||
# ~/.config/cleveragents/personas/feature-dev.yaml
|
||
name: "feature-dev"
|
||
description: "Feature development with Claude on main projects"
|
||
actor: "anthropic/claude-4-sonnet"
|
||
color: "$primary" # Textual CSS color token or hex
|
||
|
||
base_arguments:
|
||
thinking_effort: "medium"
|
||
temperature: 0.7
|
||
max_tokens: 16384
|
||
|
||
scoped_projects:
|
||
- "local/cleveragents"
|
||
- "local/api-service"
|
||
|
||
scoped_plans: [] # Usually empty; populated ad-hoc
|
||
|
||
argument_presets:
|
||
- name: "default" # Always present, always first
|
||
display: "default" # Short label for PersonaBar
|
||
overrides: {} # No overrides — uses base_arguments as-is
|
||
|
||
- name: "think-more"
|
||
display: "think: high"
|
||
overrides:
|
||
thinking_effort: "high"
|
||
|
||
- name: "think-max"
|
||
display: "think: max"
|
||
overrides:
|
||
thinking_effort: "max"
|
||
temperature: 0.3 # Lower temperature for deep reasoning
|
||
|
||
- name: "quick"
|
||
display: "quick"
|
||
overrides:
|
||
thinking_effort: "low"
|
||
max_tokens: 4096
|
||
|
||
cycle_order: 1 # Position in tab-cycle list (1-indexed, 0 = not in cycle)
|
||
```
|
||
|
||
### Argument Preset Resolution
|
||
|
||
When the user selects a preset (via `ctrl+tab`), the effective arguments are computed as:
|
||
|
||
```
|
||
effective_arguments = merge(base_arguments, active_preset.overrides)
|
||
```
|
||
|
||
Where `merge` is a shallow dictionary merge — preset keys override base keys, base keys not in the preset are preserved. This is the same semantics as CLI flag overrides of YAML-configured defaults.
|
||
|
||
The "default" preset always has empty overrides (`{}`), meaning it produces exactly `base_arguments`. This ensures the user can always return to their configured baseline.
|
||
|
||
### Auto-Generated Presets
|
||
|
||
When a persona is created (either automatically on first run or manually via the persona editor), the system inspects the actor's argument schema to auto-generate useful presets:
|
||
|
||
1. **Thinking effort detection** — If the actor schema includes a `thinking_effort` argument (as all built-in LLM actors do), three presets are auto-generated:
|
||
- `"default"` → `{}` (uses base `thinking_effort`)
|
||
- `"think: high"` → `{ thinking_effort: "high" }`
|
||
- `"think: max"` → `{ thinking_effort: "max" }`
|
||
|
||
2. **Temperature detection** — If the actor schema includes a `temperature` argument, presets for `"precise"` (`{ temperature: 0.1 }`) and `"creative"` (`{ temperature: 0.9 }`) are appended.
|
||
|
||
3. **No matching arguments** — If the actor has no recognized argument patterns, only the `"default"` preset is created.
|
||
|
||
The user can modify, delete, or add presets at any time via the PersonaEditorModal.
|
||
|
||
### Tab Cycling Behavior
|
||
|
||
The `tab` key in the main chat prompt cycles through personas in the user's configured cycle list:
|
||
|
||
```
|
||
tab: persona_1 → persona_2 → persona_3 → persona_1 → ...
|
||
shift+tab: (used for sidebar cycling, NOT persona reverse-cycling)
|
||
```
|
||
|
||
The cycle list is the set of personas with `cycle_order > 0`, sorted by `cycle_order`. Personas with `cycle_order: 0` exist but are not part of the tab cycle — they can only be selected explicitly via `/persona:set <name>` or through the fullscreen sidebar.
|
||
|
||
When cycling, the PersonaBar updates immediately to show the new persona's name, actor, and current preset. The actor binding for the session is updated — subsequent prompts use the new persona's actor and scope. Previous conversation messages remain visible (they are part of the session history, not the persona).
|
||
|
||
### Ctrl+Tab Preset Cycling
|
||
|
||
`ctrl+tab` cycles through the current persona's argument presets:
|
||
|
||
```
|
||
ctrl+tab: default → think: high → think: max → quick → default → ...
|
||
```
|
||
|
||
The active preset's `display` name appears in the PersonaBar. The effective arguments change immediately for the next prompt.
|
||
|
||
### Persona Lifecycle
|
||
|
||
```
|
||
┌──────────┐ ┌──────────────┐ ┌───────────────┐ ┌──────────┐
|
||
│ First Run │────►│ Auto-create │────►│ Active in │────►│ Modified │
|
||
│ (no │ │ "default" │ │ session │ │ by user │
|
||
│ personas)│ │ persona from │ │ │ │ │
|
||
└──────────┘ │ actor select │ └───────────────┘ └──────────┘
|
||
└──────────────┘ ▲ │
|
||
│ │
|
||
└─── Saved to YAML ──┘
|
||
```
|
||
|
||
1. **First run**: No personas exist. Actor selection overlay creates a `"default"` persona with auto-generated presets.
|
||
2. **Normal startup**: Last active persona is restored from `~/.config/cleveragents/tui-state.yaml`.
|
||
3. **Manual creation**: User creates personas via PersonaEditorModal (from fullscreen sidebar or `/persona:create` command). The editor provides:
|
||
- Actor selection (searchable list from Actor Registry)
|
||
- Base argument editor (form fields derived from actor's argument schema)
|
||
- Project/plan scope selection (checkboxes from Project/Plan registries)
|
||
- Preset editor (add/remove/edit named argument overlays)
|
||
- Cycle order assignment
|
||
4. **Modification**: User edits an existing persona; changes are saved to the YAML file immediately.
|
||
5. **Deletion**: User deletes a persona; the YAML file is removed. If the deleted persona was active, the next persona in the cycle list becomes active (or `"default"` if none remain).
|
||
|
||
### Scope Behavior
|
||
|
||
When a persona has scoped projects or plans:
|
||
|
||
1. **Every prompt** submitted in a session using that persona implicitly includes those project/plan references in the context. This is equivalent to the user typing `@project:<name>` for each scoped project in every prompt.
|
||
2. **The `@` reference system** can add additional projects/plans for a single prompt — these are additive to the persona's scope.
|
||
3. **The sidebar** highlights scoped projects/plans with a distinct indicator (e.g., a pin icon or accent color) to distinguish them from unscoped items.
|
||
4. **Context assembly** (ACMS) receives the combined scope (persona scope + prompt @ references) and prioritizes those resources in the CRP for the resulting plan.
|
||
|
||
### PersonaBar Display
|
||
|
||
The PersonaBar sits directly below the prompt input and is always visible:
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ ❯ What would you like to do? │
|
||
│ ▌@▐ refs ▌/▐ commands ▌!▐ shell │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
feature-dev │ anthropic/claude-4-sonnet │ think: high │ 2 projects │ $0.12
|
||
```
|
||
|
||
| Segment | Content | Style | Updates When |
|
||
|---------|---------|-------|-------------|
|
||
| Persona name | `feature-dev` | `$text-primary` on `$primary 10%` background | `tab` cycle |
|
||
| Actor name | `anthropic/claude-4-sonnet` | `$text-secondary` | `tab` cycle |
|
||
| Preset label | `think: high` | `$text-warning` (differs from default), `$text-muted` (default) | `ctrl+tab` cycle |
|
||
| Scope indicator | `2 projects` / `1 plan, 3 projects` | `$text-muted` | Persona change or `/scope:add/remove` |
|
||
| Session cost | `$0.12` | `$secondary 70%`, right-aligned | After each actor response |
|
||
|
||
### Persona Storage Format
|
||
|
||
Personas are stored as individual YAML files in `~/.config/cleveragents/personas/`:
|
||
|
||
```
|
||
~/.config/cleveragents/
|
||
├── config.toml # Global config (existing)
|
||
├── tui-state.yaml # TUI state (last persona, window sizes, etc.)
|
||
└── personas/
|
||
├── default.yaml
|
||
├── feature-dev.yaml
|
||
├── reviewer.yaml
|
||
└── infra-admin.yaml
|
||
```
|
||
|
||
The TUI state file tracks transient state:
|
||
|
||
```yaml
|
||
# ~/.config/cleveragents/tui-state.yaml
|
||
last_persona: "feature-dev"
|
||
last_preset: "think: high"
|
||
last_session_id: "01HXM8C2..."
|
||
sidebar_state: "visible" # hidden | visible | fullscreen
|
||
theme_override: null # null = use config.toml setting
|
||
window_width: 180
|
||
window_height: 50
|
||
```
|
||
|
||
### Persona Export and Import
|
||
|
||
Personas can be shared between users or machines:
|
||
|
||
```
|
||
/persona:export feature-dev # Writes feature-dev.yaml to current directory
|
||
/persona:import ./feature-dev.yaml # Copies to personas/ directory
|
||
```
|
||
|
||
Exported files are the same YAML format as stored files — no transformation needed. This enables teams to share persona configurations via version control or messaging.
|
||
|
||
## Constraints
|
||
|
||
- Personas must never appear in the domain model, ACP protocol, database schema, or any non-TUI code path — they are a pure Presentation-layer concept
|
||
- Every persona must have exactly one `"default"` argument preset with empty overrides; this preset cannot be deleted or renamed
|
||
- The `cycle_order` field must be unique across all personas with `cycle_order > 0`; validation occurs on save
|
||
- Actor references in personas must resolve to registered actors at session start; if an actor is unregistered, the persona is marked as invalid with a visible warning
|
||
- Base arguments must conform to the referenced actor's argument schema; invalid arguments are rejected at persona save time with a validation error
|
||
- Scoped projects and plans must reference existing entities at session start; stale references produce warnings (not errors) since projects/plans may be created or removed between TUI sessions
|
||
|
||
## Consequences
|
||
|
||
### Positive
|
||
|
||
- Users can switch their entire working context (actor, arguments, project scope) with a single `tab` keypress, dramatically reducing friction in multi-project workflows
|
||
- Argument presets provide instant access to different reasoning modes (quick vs. deep thinking) without editing configuration — a single `ctrl+tab` changes the actor's behavior
|
||
- Auto-generated presets mean first-run users get useful preset cycling without any configuration — the system discovers the actor's capabilities and creates sensible defaults
|
||
- Persona portability (YAML export/import) enables team standardization — a lead developer can define personas for common workflows and share them with the team
|
||
- The strict separation from the domain model means personas can evolve freely without database migrations, ACP version bumps, or backward compatibility concerns
|
||
|
||
### Negative
|
||
|
||
- The persona concept introduces a TUI-specific abstraction that has no CLI equivalent — CLI users must specify actor, arguments, and project scope explicitly on each command (this is by design, but creates a feature gap between interfaces)
|
||
- Auto-generated presets may not match user expectations for all actor types — custom actors with unusual argument schemas may produce unhelpful or no auto-generated presets
|
||
- Persona state is local to the machine; users on multiple machines must manually sync persona files (mitigated by export/import)
|
||
|
||
### Risks
|
||
|
||
- If the actor argument schema changes (e.g., a new version of an actor adds or removes arguments), existing persona base_arguments and preset overrides may become invalid — the system should validate on load and warn rather than fail
|
||
- The `cycle_order` uniqueness constraint may frustrate users who want to reorder personas frequently — consider a drag-and-drop interface in the fullscreen sidebar to simplify reordering
|
||
- Stale project/plan references in scoped_projects/scoped_plans could silently degrade context quality if the user doesn't notice the warning — consider making stale references more prominent (e.g., PersonaBar turns warning color)
|
||
|
||
## Alternatives Considered
|
||
|
||
**Store personas in the database via ACP** — This would make personas available across CLI, TUI, and Web. Rejected because it adds domain complexity for a Presentation-layer concept. Different frontends have different ergonomic needs; the CLI's stateless model doesn't benefit from personas. If cross-frontend persona sharing is needed later, it can be added as a new ACP operation without changing the persona model.
|
||
|
||
**Use environment variables or shell aliases instead of personas** — Users could define shell aliases like `alias ca-dev="agents --actor anthropic/claude-4 --project local/api-service"`. Rejected because this doesn't work within a TUI session (can't change the alias mid-session), doesn't support argument presets, and provides no discoverability or management UI.
|
||
|
||
**Actor profiles (actor-side configuration)** — Define different configurations as separate actors (e.g., `local/claude-quick`, `local/claude-deep`). Rejected because this pollutes the actor registry with configuration variants rather than distinct actors, and doesn't address project scoping.
|
||
|
||
**Session-level configuration only** — Allow changing actor and scope per-session via commands but without the persona bundling. Rejected because it requires multiple commands to switch context (change actor, change scope, change arguments) rather than a single tab press.
|
||
|
||
## Compliance
|
||
|
||
- **Unit tests**: Persona YAML serialization/deserialization round-trip tests for all fields
|
||
- **Validation tests**: Verify that invalid argument schemas, missing actors, duplicate cycle orders, and missing default presets are caught at save time
|
||
- **Integration tests**: Pilot tests verify that `tab` cycling updates the PersonaBar and subsequent prompts use the new persona's actor
|
||
- **Preset tests**: Verify that `ctrl+tab` cycling computes effective arguments correctly (merge semantics)
|
||
- **Auto-generation tests**: Verify that actors with `thinking_effort` arguments produce the expected presets, and actors without recognized arguments produce only the default preset
|
||
- **State persistence tests**: Verify that `tui-state.yaml` correctly saves and restores last persona, preset, and sidebar state across TUI restarts
|
||
- **Export/import tests**: Verify that exported YAML files are valid and importable on a different machine (no absolute paths or machine-specific references)
|