chabeau 0.5.0

A full-screen terminal chat interface that connects to various AI APIs for real-time conversations
Documentation

Chabeau - Terminal Chat Interface

Chabeau rendering a complex table

Chabeau is a full-screen terminal chat interface that connects to various AI APIs for real-time conversations. Chabeau brings the convenience of modern chat UIs to the terminal with a focus on speed, ergonomics, and sensible defaults. It is not a coding agent.

See several of Chabeau's features in action in this short video.

Our friendly mascot

Table of Contents

Feature Highlights

  • Full-screen terminal UI with real-time streaming responses
  • Markdown rendering in the chat area (headings, lists, quotes, tables, callouts, superscript/subscript, inline/fenced code) with clickable OSC 8 hyperlinks
  • Built-in support for many common providers (OpenAI, OpenRouter, Poe, Anthropic, Venice AI, Groq, Mistral, Cerebras)
  • Support for quick custom configuration of new OpenAI-compatible providers
  • Interactive dialogs for selecting models and providers
  • Character card support (v2 format) with in-app picker and defaults per provider/model
  • Extensible theming system that degrades gracefully to terminals with limited color support
  • Secure API key storage in system keyring with config-based provider management
  • Multi-line input (IME-friendly) with compose mode for longer responses
  • Message retry and message editing
  • Conversation logging with pause/resume; quick /dump of contents to a file
  • Syntax highlighting for fenced code blocks (Python, Bash, JavaScript, and more)
  • Inline block selection (Ctrl+B) to copy or save fenced code blocks

For features under consideration, see WISHLIST.md.

Getting Started

Install

cargo install chabeau

Authenticate

chabeau auth    # Interactive setup for OpenAI, OpenRouter, Poe, Anthropic, Venice AI, Groq, Mistral, Cerebras, or custom providers

Launch

chabeau         # Uses defaults; opens pickers when needed

Inside the TUI, use /provider and /model to switch, and /help to see a full breakdown of commands and keyboard shortcuts.

Working with Providers and Models

chabeau                              # Start chat with defaults (pickers on demand)
chabeau --provider openai            # Use specific provider
chabeau --model gpt-5                # Use specific model
chabeau --log conversation.log       # Enable logging immediately on startup

Discover available options:

chabeau -p                           # List providers and auth status
chabeau -m                           # List available models
chabeau -p openrouter -m             # List models for specific provider

Manage authentication from the CLI:

chabeau auth                         # Set up authentication
chabeau deauth                       # Remove authentication (interactive)
chabeau deauth --provider openai     # Remove specific provider

Environment variables are used only if no providers are configured, or when you pass --env.

export OPENAI_API_KEY="your-api-key-here"
export OPENAI_BASE_URL="https://api.openai.com/v1"  # Optional
chabeau --env     # Force using env vars even if providers are configured

Environment variable values can make their way into shell histories or other places they shouldn't, so using the keyring is generally advisable.

Configuration

Chabeau stores its configuration in config.toml.

  • Linux: ~/.config/chabeau/config.toml
  • macOS: ~/Library/Application Support/org.permacommons.chabeau/config.toml

Generally, you can rely on the UI: when you use interactive commands like /model, /provider, /theme, or /character, press Alt+Enter (or Ctrl+J) to persist the selection.

Command-line helpers mirror those flows:

# Set default provider
chabeau set default-provider openai

# Set default model for a provider
chabeau set default-model openai gpt-4o

# Persist a theme
chabeau set theme dark

# Set default character (per provider and model)
chabeau set default-character openai gpt-4 hypatia

# Print the current configuration
chabeau set

Both the CLI and TUI run these mutations through the same configuration orchestrator. Chabeau caches the parsed file based on its last-modified timestamp, skipping redundant reloads when nothing has changed, and persists updates atomically so a failed write never clobbers your existing config.toml.

Prefer editing by hand? Copy examples/config.toml.sample to your config directory and adjust it to suit your setup. The sample covers provider defaults, markdown/syntax toggles, custom providers, custom themes, and character assignments.

Character Cards

Chabeau supports character cards in the v2 format, letting you chat with AI personas that define tone, background, and greeting. Cards can be JSON or PNG files (with embedded metadata).

Import and Manage Cards

chabeau import path/to/character.json       # Import JSON card
chabeau import path/to/character.png        # Import PNG with embedded metadata
chabeau import character.json --force       # Overwrite existing card

Cards are stored in the Chabeau configuration directory. Use chabeau -c to print the directory name and any cards Chabeau discovers.

Use Characters in Chat

chabeau -c hypatia                          # Start with character by name
chabeau -c hypatia.json                     # Start with character by filename

In the TUI, /character opens the character picker (↑↓ to navigate, Enter to select, Alt+Enter to set as default). You can also run /character <name> for quick switches.

Defaults and Directories

Set defaults for provider/model combinations via Alt+Enter (or Ctrl+J) in the picker, or on the CLI:

chabeau set default-character openai gpt-4 hypatia
chabeau unset default-character openai gpt-4

To use a separate cards directory, set the CHABEAU_CARDS_DIR environment variable before launching Chabeau.

Example cards live in examples/hypatia.json and examples/darwin.json.

Troubleshooting

  • "Character not found": ensure the card is in ~/.config/chabeau/cards/ (or its equivalent on macOS or Windows) or provide the full path.
  • "Invalid card format": verify the JSON structure matches the v2 spec with required fields (name, description, personality, scenario, first_mes, mes_example).
  • "PNG missing metadata": PNG files must contain a chara tEXt chunk with base64-encoded JSON.
  • Cards not appearing in picker: check file permissions and ensure files have .json or .png extensions.

Format Reference

Character cards follow the v2 specification.

Personas

Personas allow you to define different user identities for conversations, each with their own name and optional biographical context. Unlike character cards (which define AI personas), personas define who you are in the conversation.

Configure Personas

Add personas to your config.toml:

[[personas]]
id = "developer"
name = "Alex"
bio = "You are talking to Alex, a senior software developer with expertise in Rust and distributed systems."

[[personas]]
id = "student"
name = "Sam"
bio = "Sam is a computer science student learning about AI and machine learning."

[[personas]]
id = "casual"
name = "Jordan"
# bio is optional - persona will just change the display name

Use Personas in Chat

chabeau --persona developer                 # Start with a specific persona

In the TUI, /persona opens the persona picker (↑↓ to navigate, Enter to select). You can also run /persona <id> for quick switches, or select "[Turn off persona]" to return to anonymous mode.

When a persona is active:

  • Your messages are labeled with the persona's name instead of "You"
  • The persona's bio (if provided) is prepended to the system prompt

Variable Substitutions

Both personas and character cards support {{user}} and {{char}} variable substitutions:

  • {{user}} is replaced with the active persona's display name (or "Anon" if no persona is active)
  • {{char}} is replaced with the character's name (or "Assistant" if no character is active)

Persona vs Character Integration

Personas and character cards work together seamlessly:

  • Character cards define the AI's personality, background, and behavior
  • Personas define your identity and context in the conversation
  • Both support {{user}} and {{char}} variable substitutions
  • The persona's bio is added to the system prompt before the character's instructions

Presets

Presets let you inject reusable system instructions into the first and last system messages that Chabeau sends to the model. They are ideal for lightweight tone or formatting tweaks that you want to toggle quickly.

Configure Presets

Add presets to your config.toml:

[[presets]]
id = "focus"
pre = """
You are collaborating with {{user}}. Keep responses focused and direct.
"""
post = """
Before finishing, list any follow-up actions.
"""

[[presets]]
id = "roleplay"
pre = """
- Engage in roleplay with the user.
- Two paragraphs per turn max.
- Don't be shy to perform actions. Format these in italics, like this: *{{char}} frowns at {{user}}.*
- Be creative! Feel free to take the roleplay into new directions.
"""
  • pre text is wrapped in blank lines and prepended to the very first system message.
  • post text is wrapped in blank lines and appended to the final system message. If no system message exists at either position, Chabeau creates one automatically.
  • Presets support the same {{user}} and {{char}} substitutions as personas and character cards.

Assign defaults per provider/model with default-presets:

[default-presets.openai]
"gpt-4o" = "focus"

Use Presets in Chat

Launch with an ID like --preset focus, or pick interactively with /preset. The picker includes a "Turn off preset" option to clear the active preset.

Appearance and Rendering

Themes

Chabeau ships with built-in themes and supports custom ones. Use /theme in the TUI to preview and Alt+Enter (or Ctrl+J) to persist the choice. On the CLI, run:

chabeau set theme dark   # Set a theme
chabeau themes           # List themes (built-in and custom)
chabeau unset theme      # Revert to default detection

When no explicit theme is set, Chabeau tries to infer a sensible default from your OS preference (e.g., macOS, Windows, GNOME). If no hint is available, it defaults to the dark theme.

Custom themes belong in config.toml under [[custom_themes]]. See src/builtins/themes.toml for color references and examples/config.toml.sample for structure.

Markdown and Syntax Highlighting

Toggle these features at runtime:

  • /markdown on|off|toggle
  • /syntax on|off|toggle

Chabeau persists these preferences to the config file automatically. Syntax colors adapt to the active theme and use the theme’s code block background for consistent contrast.

Color Support

Chabeau detects terminal color depth and adapts themes accordingly:

  • Truecolor: if COLORTERM contains truecolor or 24bit, Chabeau uses 24-bit RGB.
  • 256 colors: if TERM contains 256color, RGB colors are quantized to the xterm-256 palette.
  • ANSI 16: otherwise, colors map to the nearest 16 ANSI colors.

Force a mode when needed with CHABEAU_COLOR=truecolor|256|16.

Keyboard and Workflow Tips

Interface Controls

See the built-in help for a full list of keyboard controls. A few highlights:

  • Alt+Enter (or Ctrl+J) to start a new line; Enter sends; Shift+arrow moves cursor in the input area.
  • Compose mode (F4) flips the defaults: Enter inserts a newline, Alt+Enter/Ctrl+J sends, arrow keys stay in the input, and Shift+arrow scrolls the transcript.
  • Tab autocompletes slash commands so you can discover options quickly.

Mousewheel

Chabeau avoids capturing the mouse so selection operations (copy/paste) work as expected. Some terminals treat mousewheel events as cursor key input, so scrolling moves the conversation. Others reveal terminal history; in that case, use the cursor keys or PgUp/PgDn instead.

External Editor

Set the EDITOR environment variable to compose longer responses in your favorite editor:

export EDITOR=nano          # or vim, code, etc.
export EDITOR="code --wait" # VS Code with wait

Once set, press Ctrl+T in the TUI to launch the external editor.

Architecture Overview

Chabeau uses a modular design with focused components:

  • main.rs – Entry point
  • builtins/ – Build-time assets embedded into the binary
    • models.toml – Supported provider definitions
    • themes.toml – Built-in UI themes
    • help.md – In-app keyboard shortcut and command reference
  • cli/ – Command-line interface parsing and handling
    • mod.rs – CLI argument parsing and command dispatching
    • model_list.rs – Model listing functionality
    • provider_list.rs – Provider listing functionality
    • character_list.rs – Character card listing functionality
    • theme_list.rs – Theme listing functionality
  • core/ – Core application components
    • app/ – Application state and controllers
      • mod.rs – App struct and module exports
      • actions.rs – Internal action definitions and dispatcher for chat loop updates
      • conversation.rs – Conversation controller for chat flow, retries, and streaming helpers
      • session.rs – Session bootstrap and provider/model state
      • settings.rs – Theme and provider controllers
      • ui_state.rs – UI state management and text input helpers
    • chat_stream.rs – Shared streaming service that feeds responses to the app, UI, and loggers
    • builtin_providers.rs – Built-in provider configuration (loads from builtins/models.toml)
    • config.rs – Configuration management
    • message.rs – Message data structures
  • auth/ – Authentication and provider management
    • mod.rs – Authentication manager implementation
  • character/ – Character card support (v2 format)
    • mod.rs – Module exports and public API
    • card.rs – Character card data structures and v2 spec parsing
    • loader.rs – Card file loading (JSON and PNG with metadata extraction)
    • cache.rs – In-memory caching with invalidation
    • import.rs – Import command and validation logic
  • api/ – API types and models
    • mod.rs – API data structures
    • models.rs – Model fetching and sorting functionality
  • ui/ – Terminal interface rendering
    • mod.rs – UI module declarations
    • chat_loop/ – Mode-aware chat loop orchestrating UI flows, keybindings, and command routing
    • layout.rs – Shared width-aware layout engine for Markdown and plain text
    • markdown.rs / markdown_wrap.rs – Markdown renderer and wrapping helpers that emit span metadata
    • renderer.rs – Terminal interface rendering (chat area, input, pickers)
    • osc_backend.rs / osc_state.rs / osc.rs – Crossterm backend wrapper that emits OSC 8 hyperlinks
    • picker.rs / appearance.rs / theme.rs – Picker controls and theming utilities
  • utils/ – Utility functions and helpers
    • mod.rs – Utility module declarations
    • color.rs – Terminal color detection and palette quantization
    • editor.rs – External editor integration
    • logging.rs – Chat logging functionality
    • scroll.rs – Text wrapping and scroll calculations
    • clipboard.rs – Cross-platform clipboard helper
  • commands/ – Chat command processing and registry-driven dispatch
    • mod.rs – Command handlers and dispatcher
    • registry.rs – Static command metadata registry

Development

Running Tests

cargo test                    # All tests
cargo test scroll::           # Scroll functionality tests
cargo test --release          # Faster execution

Performance

Chabeau includes lightweight performance checks in the unit test suite and supports optional Criterion benches.

  • Built-in perf checks (unit tests):
    • Short history prewrap (50 iters, ~60 lines): warns at ≥ 90ms; fails at ≥ 200ms.
    • Large history prewrap (20 iters, ~400 lines): warns at ≥ 400ms; fails at ≥ 1000ms.
    • Run with: cargo test (warnings print to stderr; tests only fail past the fail thresholds).
  • Optional benches (release mode) using Criterion 0.7:
    • A render_cache bench validates the cached prewrapped rendering path.
    • Run: cargo bench
    • Reports live in target/criterion/ (HTML under report/index.html).
    • To add new benches, create files under benches/ (e.g., benches/my_bench.rs) and use Criterion’s criterion_group!/criterion_main!.
    • Benches import internal modules via src/lib.rs (e.g., use chabeau::...).

License

CC0 1.0 Universal (Public Domain)