TUI¶
AIBA runs entirely in the terminal. There is no web UI, no desktop window, no browser dashboard. Everything — the setup wizard, the REPL, the agent output — renders through a thin rendering layer built on ANSI escape codes and Rich.
Covers: The Rendering Layer, Setup Screens, The REPL, and The Launch Flow¶
The Rendering Layer¶
All terminal output flows through src/services/rendering.py. It has two jobs: color and markdown.
ANSI color palette¶
A dictionary called C holds the color tokens. Every screen, the REPL, and main.py reference C for consistent styling:
| Token | ANSI code | Usage |
|---|---|---|
bold |
\033[1m |
Headings, emphasised labels |
dim |
\033[2m |
Secondary text, descriptions |
purple |
\033[38;5;99m |
The launch banner ("∞ AIBA") |
teal |
\033[38;5;44m |
Interactive prompts (▸), selected values |
green |
\033[38;5;42m |
Success badges, the logo |
yellow |
\033[38;5;221m |
Warnings, usage-limit alerts |
red |
\033[38;5;203m |
Errors, invalid input markers (✗) |
reset |
\033[0m |
Reset to terminal default |
The palette uses 256-color codes rather than 16-color ANSI names (e.g. \033[31m for red). This keeps the look consistent across different terminal themes — OS color schemes don't override AIBA's intended appearance.
Rich markdown rendering¶
Agent output is markdown. AIBA uses Rich to render it to the terminal:
from rich.console import Console
from rich.markdown import Markdown
_console = Console(highlight=False)
def render_markdown(text: str) -> None:
md = Markdown(text, code_theme="monokai")
_console.print(md)
What this gets you:
| Feature | Example |
|---|---|
| Headings | H1–H6 rendered with weight and color |
| Tables | Pipe tables drawn with box-drawing characters |
| Code blocks | Syntax-highlighted with the Monokai theme |
| Inline code | Backtick-wrapped text rendered in a contrasting background |
| Lists | Ordered and unordered, with proper indentation |
| Blockquotes | Indented with a vertical bar |
Rich is only used for agent output. The setup screens and REPL prompts use raw ANSI codes — no Rich overhead.
Utility helpers¶
Two small functions complement the palette:
def hr(char: str = "─", color: str = "dim") -> str:
"""Horizontal rule spanning the terminal width."""
def badge(label: str, value: str) -> str:
"""Dim label followed by teal value, e.g. 'Mode: AGENT'."""
The horizontal rule adapts to the terminal width via shutil.get_terminal_size(). It is used extensively in the setup screens and REPL to separate sections.
Setup Screens¶
When you run python main.py (without beat), AIBA walks you through a 4–5 step wizard. Each step is a function in src/services/screens.py.
Step 1 — Mode¶
∞ A I B A Autonomous Internet Browsing Agent
────────────────────────────────────────────────
Step 1 — Select Mode
[1] Agent Single autonomous agent, full internet access
Best for focused tasks, single-domain research.
[2] Swarm Orchestrated fleet of parallel sub-agents
Best for large-scale research, multi-hop mining.
▸ Enter 1 or 2:
Choices map directly to what gets launched:
| Choice | What runs | How |
|---|---|---|
1 — Agent |
Sub-agent directly | run_sub_agent(prompt) |
2 — Swarm |
Main orchestrator + parallel sub-agents | run_agent(prompt) |
Step 2 — Template¶
Lists every registered template with its description. The template's system prompt shapes the agent's behavior for the entire session.
Templates are configured in src/prompts/templates/ and registered at startup. See Templates for the full catalog.
Step 3 — Effort¶
Step 3 — Effort Level
[1] quick Fast & cheap — minimal tool calls, short responses.
[2] balanced Thorough & pragmatic — cross-check 2–3 sources.
[3] max Exhaustive deep-dive — maximum tools, maximum tokens.
Effort controls temperature, token budgets, and instruction depth. max mode also enables Gemini thinking. See Effort.
Step 4 — Sub-Agent Pool (Swarm only)¶
Appears only in Swarm mode. Sets max_concurrent_sub_agents (range 1–50). The default comes from .env.
Step 5 — Extra Notes¶
Freeform text appended to the template-generated prompt. Press Enter on an empty line (or Ctrl+D) to skip. Useful for adding URLs, specific constraints, or follow-up context.
Launch Summary¶
After all steps, a summary block displays before execution:
═══════════════════════════════════════════════
Launch Summary
═══════════════════════════════════════════════
Mode: SWARM
Sub-agents: 8
Prompt: Find all software engineering jobs posted in the last 24 hours…
═══════════════════════════════════════════════
The REPL¶
After the first result renders, the session drops into an interactive REPL loop. The REPL is already documented in detail at REPL.
In the context of the TUI:
- The REPL uses the same
Cpalette andhr()helper as the setup screens - User input is read via
input()with a teal▸prompt - Each agent response passes through
render_markdown()before display - Commands (
/exit,/save,/clear,/history,/help) are parsed before agent invocation
The Launch Flow¶
Putting it all together, here is the full path from python main.py to a running REPL:
python main.py
│
├── /beat argument? ──> beat_cli() ──> exit (no TUI)
│
└── No argument ──> screens.session()
│
├── Resume saved session? ──Y──> load history ──> REPL
│
└── N ──> screens.mode()
──> screens.template()
──> screens.effort()
──> screens.sub_agents() (swarm only)
──> screens.prompt()
──> screens.confirm()
──> run_sub_agent() or run_agent()
──> first result renders
──> repl.run() > interactive loop
The beat path (python main.py beat ...) bypasses the TUI entirely. It uses argparse in beat_cli.py and runs directly. See beats CLI.