Gaia is a command-line interface (CLI) tool that provides a convenient way to interact with language models through a local or remote API. It features a beautiful terminal UI, configuration management, automatic role detection, response caching, and support for different interaction modes.
- 🚀 Simple and intuitive command-line interface
- 🎨 Beautiful terminal UI with progress bars
- 📺 Interactive TUI prompts (Bubble Tea): when using tool actions (
gaia tool git commit) or operator mode (gaia investigate), context and confirmation prompts use a rich terminal UI in a real terminal — styled boxes, keyboard shortcuts, text wrapping to window width - ⚙️ Comprehensive configuration management with YAML support
- 🔄 Support for different interaction modes (default, describe, code, shell, commit, branch)
- 🤖 Automatic role detection based on message content
- 📦 Automatic model management (pull if not present)
- 💾 Response caching for faster repeated queries
- 🧹 Optional sanitization of prompts before LLM (reduce noise and tokens; configurable levels)
- 🔌 Support for local (Ollama) and remote (OpenAI, Mistral) APIs
- 🛠️ Tool integration for executing external commands
- 📥 Stdin support for piping content
- 🔍 Investigate (operator mode): autonomous investigation with tool execution (e.g. "Why is my disk full?") — plan, run commands, reason, and summarize with safety controls (denylist, confirmation, dry-run)
- Go 1.26 or later
- A running instance of a compatible language model API (e.g., Ollama) or an API key for OpenAI or Mistral
git clone https://github.com/vonglasow/gaia.git
cd gaia
go buildbrew tap vonglasow/tap
brew install gaiabrew upgrade gaiaGaia stores its configuration in ~/.config/gaia/config.yaml. The configuration file is automatically created on first run with sensible defaults.
When you run Gaia inside a project, Gaia looks for a local .gaia.yaml (from your current directory up to the git repository root).
- Local config is useful for project-specific
roles.*prompts andtools.*actions. - On first detection, Gaia asks whether you trust that repository.
- If trusted, local settings override your user config for that repository.
- Trust decisions are stored in
~/.config/gaia/trusted-repos.yamland reused on next runs. - In non-interactive mode (CI, piped execution), untrusted local config is ignored and Gaia uses user/global config only.
Configuration precedence is:
CLI flags > env vars > local .gaia.yaml > ~/.config/gaia/config.yaml > built-in defaults
model: The language model to use (default: "mistral" for Ollama, "gpt-4o-mini" for OpenAI, "mistral-medium-latest" for Mistral)host: API host (default: "localhost" for Ollama, "api.openai.com" for OpenAI, "api.mistral.ai" for Mistral)port: API port (default: 11434 for Ollama, 443 for OpenAI and Mistral)
cache.enabled: Enable/disable response caching (default:true)cache.dir: Cache directory path (default:~/.config/gaia/cache)
Optional preprocessing to reduce noise and token usage before sending messages to the model:
sanitize_before_llm: Enable/disable sanitization (default:false)sanitize.level: Filter intensity —none,light, oraggressive(default:light)- light: Removes debug/metadata lines, timestamps, obvious duplicates, collapses extra newlines
- aggressive: In addition, removes long unstructured runs and redundant sections
sanitize.max_tokens_after: Cap total tokens after sanitization (default:0= no cap)sanitize.log_stats: Log token counts and filtering stats to stderr when sanitization runs (default:true)
The last user message is always preserved. When enabled, a one-line summary is printed to stderr, e.g. [sanitize] tokens before=1200 after=800 removed≈400 ms=2.
auto_role.enabled: Enable automatic role detection (default:true)auto_role.mode: Detection mode -off,heuristic, orhybrid(default:hybrid)off: Disable auto-detection, always use default roleheuristic: Use fast local keyword matching onlyhybrid: Use heuristic first, fallback to LLM for ambiguous cases
auto_role.keywords.<role_name>: Custom keywords for role detection (see below)
Roles define different interaction modes with their respective prompts. The available roles depend on what is configured in your configuration file. By default, the following roles are pre-configured:
Default Roles (Pre-configured):
roles.default: General programming and system administration assistanceroles.describe: Command description and documentationroles.shell: Shell command generationroles.code: Code generation without descriptionsroles.commit: Generate conventional commit messagesroles.branch: Generate branch names
Custom Roles:
You can add custom roles by adding roles.<role_name> keys to your configuration file. Any role defined in the configuration will be available for use.
YAML role directory and inheritance: When roles.directory is set to a
directory path, Gaia loads roles from YAML files in that directory (one role per
file). Roles can inherit from others with extends: ["base", "other-role"].
Parent prompts are concatenated first (separator ---), then the child’s;
signals, threshold, priority, weight, mode and exclusive are merged (child
overrides when defined). Circular or missing parents cause a clear error.
Resolution runs once at load time. Optional: roles.debug (or CLI
--roles-debug) prints resolution and scoring to stderr with prefix [ROLES DEBUG].
Note: The list of available roles is dynamic and depends on your configuration. Use gaia config list to see all configured roles in your setup.
Keywords are used by the heuristic detection to identify the appropriate role. Default keywords are pre-configured for the default roles:
Pre-configured Keywords:
auto_role.keywords.shell: Command-related keywordsauto_role.keywords.code: Programming-related keywordsauto_role.keywords.describe: Question/explanation keywordsauto_role.keywords.commit: Commit message keywordsauto_role.keywords.branch: Branch creation keywords
Custom Keywords:
You can customize these keywords or add keywords for custom roles by adding auto_role.keywords.<role_name> keys to your configuration file. This allows auto-detection to work with your custom roles as well.
Tools allow you to execute external commands with AI-generated content. Example configuration:
tools:
git:
commit:
context_command: "git diff --staged"
role: "commit"
execute_command: "git commit -F {file}"
branch:
context_command: "git diff"
role: "branch"
execute_command: "git checkout -b {response}"Tool configuration fields:
context_command: Command to run to gather context (optional)role: Role to use for AI generationexecute_command: Command to execute with AI response (use{file}for multi-line,{response}for single-line)
The operator mode (gaia investigate) uses the following options (all under operator.):
operator.max_steps: Maximum number of steps per run (default:10)operator.confirm_medium_risk: Ask for confirmation before running medium-risk commands (default:true)operator.dry_run: Iftrue, never execute commands; only show what would be run (default:false)operator.denylist: List of forbidden command patterns (e.g.["rm -rf", "sudo", "mkfs"]). Commands containing these are blocked.operator.allowlist: Optional. If set, only commands that start with or contain one of these patterns are allowed (prefix or substring, case-insensitive; not regex). Example:["df", "du", "find"].operator.output_max_bytes: Maximum length of command output per step (default:4096); longer output is truncated.operator.command_timeout_seconds: Timeout in seconds for each shell command (default:30).operator.treat_exit_code_1_as_success: Whentrue(default), commands that exit with code 1 are treated as success and their output is returned (e.g.git diffwith no changes). Whenfalse, exit code 1 is reported as an error. Useful if you want strict failure detection for all commands.
Example in config.yaml:
operator:
max_steps: 10
confirm_medium_risk: true
denylist:
- "rm -rf"
- "sudo"
- "mkfs"
allowlist: [] # leave empty to allow any command not on denylist
command_timeout_seconds: 30
treat_exit_code_1_as_success: true # default: git diff with no changes (exit 1) is not an errorgaia --config /path/to/custom/config.yaml ask "Hello!"
# or
GAIA_CONFIG=/path/to/custom/config.yaml gaia ask "Hello!"# Ask a question
gaia ask "What is the meaning of life?"
# Ask with piped input
echo "Hello world" | gaia ask "Translate to French"
git diff | gaia ask "Generate commit message"
# Start an interactive chat session
gaia chat
# Check version
gaia version
# Investigate a goal (operator mode: runs tools, reasons, summarizes)
gaia investigate "Why is my disk full?"
gaia investigate --dry-run "What's using the most space?"
gaia investigate --yes "List large files in /tmp" # skip confirmation for medium-risk commands
gaia investigate --debug "Why is CPU high?" # show decisions and observations# View all configuration settings
gaia config list
# Get specific configuration value
gaia config get model
gaia config get auto_role.enabled
# Set configuration value
gaia config set model llama2
gaia config set host 127.0.0.1
gaia config set port 8080
gaia config set auto_role.mode heuristic
# Show configuration file path
gaia config path
# Create default configuration file
gaia config create
# Trust local project overrides for current repository
gaia config trust
# Remove trust for current repository
gaia config untrust
# Show trust status for current repository
gaia config trust --status
# List all trusted repositories
gaia config trusted
# Show trust status for a specific path/repository
gaia config trusted /path/to/repoThe available roles depend on your configuration. By default, the following roles are available:
# Use default role (general assistance)
gaia ask "How do I create a new directory?"
# Explicitly specify a pre-configured role
gaia ask --role describe "ls -la"
gaia ask --role shell "list files in current directory"
gaia ask --role code "Hello world in Python"
gaia ask --role commit "generate commit message"
gaia ask --role branch "create branch name"
# Use a custom role (if configured)
gaia ask --role my_custom_role "custom prompt"
# Auto-detection (enabled by default)
gaia ask "generate git commit message" # Automatically detects "commit" role
gaia ask "create a new branch" # Automatically detects "branch" roleNote: To see all available roles in your configuration, use gaia config list and look for keys starting with roles..
When auto_role.enabled is true (default), Gaia automatically detects the appropriate role based on your message content:
# These will automatically use the appropriate role
gaia ask "what does ls -la do?" # → describe role
gaia ask "list files in directory" # → shell role
gaia ask "write a Python function" # → code role
git diff | gaia ask "generate commit" # → commit roleUse --debug flag to see which role was detected and how:
gaia ask --debug "generate commit message"
# [DEBUG] Auto-detected role: commit (method: heuristic, score: 0.85, reason: matched keywords)# View cache statistics
gaia cache stats
# List all cache entries
gaia cache list
# Dump all cached responses
gaia cache dump
# Clear the cache
gaia cache clear
# Bypass cache for a single command
gaia --no-cache ask "What is AI?"
# Refresh/overwrite cache entry
gaia --refresh-cache ask "What is AI?"--config, -c: Path to alternative configuration file--no-cache: Bypass local response cache for this command--refresh-cache: Regenerate and overwrite cache entries--debug: Enable debug output (shows role detection info)
The chat mode provides an interactive session where you can have a continuous conversation with the model. The conversation history is maintained throughout the session, allowing the model to reference previous messages.
# Start a chat session
gaia chat
# Type your messages and press Enter
# Type 'exit' to end the chat sessionThe investigate command runs an autonomous operator: it plans steps, runs shell commands (e.g. df, du, find), reasons over the results, and returns a summary or suggested actions. Safety is enforced via a denylist, optional allowlist, and confirmation for medium-risk commands.
# Investigate a goal (operator will run commands like df -h, du, etc.)
gaia investigate "Why is my disk full?"
# See what would be run without executing (dry-run)
gaia investigate --dry-run "What's using the most space?"
# Skip confirmation for medium-risk commands (e.g. touch, mkdir)
gaia investigate --yes "List large files in /tmp"
# Show plan, decisions, and tool results (debug)
gaia investigate --debug "Why is CPU high?"
# Limit the number of steps
gaia investigate --max-steps 5 "Quick disk check"Flags:
--max-steps,-n: Maximum number of operator steps (default: 10)--dry-run: Do not execute commands; only show what would be run--yes,-y: Skip confirmation for medium-risk commands--debug: Print each decision (action, tool, args) and observation
Confirmation prompt (TUI): When the operator needs your approval for a medium-risk command, Gaia shows an interactive confirmation screen in a real terminal: the proposed command in a styled box, then y or Enter to allow or n to decline. Content wraps to the terminal width. When not in a TTY, a simple line-based prompt is used.
Safety: Commands containing operator.denylist entries (e.g. sudo, rm -rf) are always blocked. If operator.allowlist is set, only commands that start with or contain an allowlist entry (prefix/substring, case-insensitive) are allowed. Use --dry-run to preview behaviour without executing anything.
Execute configured tool actions that combine AI generation with external command execution:
# Execute a tool action
gaia tool git commit
gaia tool git branch "add user authentication"
# The tool will:
# 1. Run the context_command (if configured) to gather context
# 2. Allow you to modify the context
# 3. Generate content using the specified role
# 4. Ask for confirmation
# 5. Execute the execute_command with the generated contentInteractive prompts (TUI): When you run a tool in a real terminal (TTY), Gaia shows an interactive prompt:
- Context step: Current context (e.g.
git diff) is shown in a styled box. You can press Enter to use it as-is, type new text to replace it, +text to append, or q to quit. All content wraps to the terminal width. - Confirmation step: After the AI generates the message (e.g. commit text), a confirmation screen appears: y or Enter to confirm and run the command, n to cancel.
When stdout is not a terminal (e.g. piping, CI), the same flow uses simple line-based prompts so scripts keep working.
$ gaia ask "What is the meaning of life?"
The meaning of life is a philosophical question that has been debated for centuries...$ cat CVE-2021-4034.py | gaia ask "Analyze and explain this code"
This code is a Python script that exploits the CVE-2021-4034 vulnerability in Python...$ git diff --staged | gaia ask "generate commit message"
feat: add user authentication system
Implement JWT-based authentication with login and registration endpoints.
Add password hashing using bcrypt and session management.$ git diff | gaia ask "create branch name"
feature/user-authentication$ gaia tool git commit
# Shows git diff, allows modification, generates commit message, asks confirmation, executes git commit$ gaia investigate "Why is my disk full?"
# Operator runs e.g. df -h, du, reasons over output, then returns a summary and suggested next steps.
$ gaia investigate --dry-run "What's using space in /var?"
# Same flow but no commands are executed; you see what would be run.Ollama is the default provider for local AI models. Configure it by setting:
host: localhost
port: 11434
model: mistral # or any model available in OllamaFeatures:
- Works completely offline
- Automatic model pulling if not present
- Progress bars during model download
- No API key required
To use OpenAI, configure:
host: api.openai.com
port: 443
model: gpt-4o-mini # or gpt-4, gpt-3.5-turbo, etc.And set the API key:
export OPENAI_API_KEY=your-api-key-hereFeatures:
- Access to OpenAI's latest models
- Streaming responses
- No local model storage required
Add a custom role to your configuration:
roles:
custom:
"You are a specialized assistant for [your domain]. Provide concise, technical answers."Once added, the role will be available for use:
- Explicitly:
gaia ask --role custom "your question" - Via auto-detection (if keywords are configured):
gaia ask "your question"(will auto-detect if keywords match)
auto_role:
enabled: true
mode: hybrid
keywords:
custom_role:
- "keyword1"
- "keyword2"
- "phrase with multiple words"auto_role:
enabled: falseauto_role:
enabled: true
mode: heuristic # Fast, local-only detectionapi/: API interaction, streaming, caching, and auto-role detectionapi/operator/: Operator (investigate) loop: planner, tools, executor, safetycommands/: CLI command definitionsconfig/: Configuration managementmain.go: Application entry point
- cobra: CLI framework
- viper: Configuration management
- bubbletea: Terminal UI framework (progress bars, interactive prompts)
- bubbles: TUI components (e.g. text input for context/edit prompts)
- lipgloss: Styling and layout (boxes, colors, width-aware wrapping)
go test -v ./...The project uses:
go fmtfor formattinggolangci-lintfor linting (version pinned in.golangci-lint-version; CI and pre-commit should use the same version)govulncheckfor vulnerability scanning of Go dependencies (run in CI and via pre-commit when Go files change)semgrepfor static analysis (run via pre-commit; uses--config autofrom the Semgrep Registry)pre-commithooks for automated checks
Align with CI (recommended): install the same golangci-lint version as CI so local lint matches:
# Version is in .golangci-lint-version
go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(cat .golangci-lint-version)Optional (for the govulncheck pre-commit hook): install govulncheck so the local hook can run:
go install golang.org/x/vuln/cmd/govulncheck@latestRun all checks:
pre-commit run -aDependency maintenance (run periodically): check for known vulnerabilities and available updates:
govulncheck ./...
go list -m -u allThis project is licensed under the terms specified in the LICENSE file.
Contributions are welcome! Please feel free to submit a Pull Request. Please ensure:
- Code is formatted and linted
- Tests are added or updated
- Pre-commit hooks pass