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).
19 KiB
adr_number, title, status_history, tier, authors, superseded_by, related_adrs, acceptance
| adr_number | title | status_history | tier | authors | superseded_by | related_adrs | acceptance | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 45 | TUI Persona System |
|
4 |
|
null |
|
|
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:
- Actor reference — a namespaced actor name (e.g.,
anthropic/claude-4-sonnet) - Base arguments — the default arguments passed to the actor on every invocation
- Scoped projects — a list of project references that are always included in the session's context
- Scoped plans — a list of plan references that are always included in the session's context
- Argument presets — named sets of argument overrides that can be cycled with
ctrl+tab - Display metadata — a short name, optional accent color, and description
Personas are:
- Stored locally in
~/.config/cleveragents/personas/as individual YAML files - Cyclable via
tabin 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
# ~/.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:
-
Thinking effort detection — If the actor schema includes a
thinking_effortargument (as all built-in LLM actors do), three presets are auto-generated:"default"→{}(uses basethinking_effort)"think: high"→{ thinking_effort: "high" }"think: max"→{ thinking_effort: "max" }
-
Temperature detection — If the actor schema includes a
temperatureargument, presets for"precise"({ temperature: 0.1 }) and"creative"({ temperature: 0.9 }) are appended. -
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 ──┘
- First run: No personas exist. Actor selection overlay creates a
"default"persona with auto-generated presets. - Normal startup: Last active persona is restored from
~/.config/cleveragents/tui-state.yaml. - Manual creation: User creates personas via PersonaEditorModal (from fullscreen sidebar or
/persona:createcommand). 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
- Modification: User edits an existing persona; changes are saved to the YAML file immediately.
- 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:
- 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. - The
@reference system can add additional projects/plans for a single prompt — these are additive to the persona's scope. - The sidebar highlights scoped projects/plans with a distinct indicator (e.g., a pin icon or accent color) to distinguish them from unscoped items.
- 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:
# ~/.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_orderfield must be unique across all personas withcycle_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
tabkeypress, 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+tabchanges 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_orderuniqueness 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
tabcycling updates the PersonaBar and subsequent prompts use the new persona's actor - Preset tests: Verify that
ctrl+tabcycling computes effective arguments correctly (merge semantics) - Auto-generation tests: Verify that actors with
thinking_effortarguments produce the expected presets, and actors without recognized arguments produce only the default preset - State persistence tests: Verify that
tui-state.yamlcorrectly 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)