Skip to main content

A TUI primitive for coding agents — streaming markdown, tool calls, diffs, and more in linear scrollback with zero flicker.

Project description

agentui

A small, opinionated Python library for building coding-agent terminal UIs.

Streaming markdown, tool-call blocks, unified diffs, confirmation prompts, slash commands, and an @-file picker — all in linear scrollback with zero flicker.

Why

Every coding agent — Claude Code, Codex, Aider, Toad — converges on the same terminal UX: linear scrollback, streaming markdown that updates in place without flicker, collapsible tool calls, unified diffs, slash commands, an @-file picker. But in Python, no library delivers this shape as a coherent primitive.

The options today are bad:

  • Textual is a full TUI framework optimized for multi-pane applications. It owns the alt-buffer, breaks native terminal selection, and forces a CSS/widget mental model that's overkill for a chat-shaped agent loop.
  • prompt_toolkit + Rich in REPL mode preserves scrollback and copy-paste, but offers no agent-specific primitives. Every project reinvents streaming markdown, tool-call panels, diff rendering, confirmation prompts, and slash commands from scratch.

Other ecosystems have closed this gap — pi-tui in TypeScript (powering Mastra Code), claude-code-kit (extracted Claude Code components), Bubble Tea + Lip Gloss in Go, Ratatui in Rust. Python had no equivalent.

agentui exists because building a polished agent UI shouldn't require 2000 lines of rendering plumbing. It should take 30.

Install

pip install agentui

For .gitignore-aware @-file completion:

uv pip install agentui[gitignore]

Quick Start

import asyncio
from agentui import Session

async def main():
    async with Session() as ui:
        while True:
            user_input = await ui.prompt("> ")
            if user_input.startswith("/"):
                await ui.handle_command(user_input)
                continue

            async with ui.assistant_turn() as turn:
                async for chunk in your_llm.stream(user_input):
                    await turn.append_markdown(chunk.text)

asyncio.run(main())

That's a working agent chat UI in 14 lines.

Features

Streaming Markdown

Accepts an async iterator of string chunks. Updates in place using synchronized output (CSI ?2026h/l) — zero flicker on modern terminals, graceful degradation elsewhere. When the turn completes, content commits to permanent scrollback.

async with ui.assistant_turn() as turn:
    async for chunk in stream:
        await turn.append_markdown(chunk)

Tool Call Blocks

Structured rendering with name, JSON-pretty arguments, status badge (pending/running/done/error), and result. Collapses automatically after completion.

async with turn.tool_call("search", {"query": "test", "limit": 5}) as tc:
    result = await execute_search(...)
    await tc.complete(result)

Unified Diffs

Colored diff rendering with line numbers, green additions, red deletions. Supports an inline confirmation prompt.

block = turn.diff("src/main.py", unified_diff_string)
approved = await block.confirm()  # prompts user inline

Confirmation Prompts

Yes/no, multi-choice, and free-text — all keyboard-driven, rendered in scrollback.

if await ui.confirm("Apply changes?"):
    apply()

choice = await ui.choose("Pick a model:", ["gpt-4", "claude", "local"])

name = await ui.input("Project name:", default="my-project")

Slash Commands

Register handlers and get tab-completion for free. Built-ins: /help, /quit, /clear.

@ui.command("model", help_text="Switch the active model")
async def cmd_model(session, args):
    session.print(f"Switched to {args}")

@-File Picker

Type @ in the prompt to fuzzy-match files in the current directory. Respects .gitignore (uses pathspec if installed, falls back to basic glob matching).

Interrupt Handling

Ctrl-C during streaming cancels the in-flight turn. Partial content commits cleanly to scrollback — terminal state is never corrupted.

async with ui.assistant_turn() as turn:
    async for chunk in stream:
        if turn.cancelled:
            break
        await turn.append_markdown(chunk)

Architecture

agentui is a thin orchestration layer over two battle-tested libraries:

  • Rich — rendering (markdown, syntax highlighting, panels, tables)
  • prompt_toolkit — input (history, key bindings, completion)

The core innovation is a scrollback-aware live region manager. Only the currently-streaming turn uses a managed region wrapped in synchronized output sequences. When the turn completes, the content becomes ordinary terminal scrollback. Native copy-paste, tmux scrollback, and Cmd-F search keep working.

User application (agent loop)
         |
         | render calls + input prompts
         v
agentui
  ┌────────────┐   ┌───────────────┐
  │ Live region │   │ Input session  │
  │ manager     │   │ (slash cmds,   │
  │ (sync out)  │   │  file picker)  │
  └──────┬──────┘   └───────┬───────┘
         │                  │
  ┌──────▼──────┐   ┌───────▼───────┐
  │    Rich     │   │ prompt_toolkit │
  │   Console   │   │ PromptSession  │
  └─────────────┘   └───────────────┘

API Reference

Session

The main entry point. Async context manager.

Method Description
prompt(message) Async user input with slash command and @-file completion
assistant_turn() Returns a Turn async context manager
print(*args) Print to scrollback (delegates to Rich Console)
confirm(message, default) Yes/no prompt, returns bool
choose(message, options, default) Multi-choice, returns int index
input(message, default) Free-text input, returns str
handle_command(command) Dispatch a /command to its handler
command(name, help_text) Decorator to register a slash command
register_command(name, handler) Non-decorator command registration

Turn

A single assistant response. Async context manager opened via session.assistant_turn().

Method Description
append_markdown(text) Stream a markdown chunk
tool_call(name, args) Returns a ToolCallContext async context manager
diff(path, patch) Render a unified diff block, returns DiffBlock
cancelled bool — whether Ctrl-C was pressed

ToolCallContext

Async context manager for tool execution within a turn.

Method Description
complete(result) Mark done with optional result string
error(message) Mark as errored

DiffBlock

Rendered diff with optional inline confirmation.

Method Description
confirm() Async — prompts user to accept/reject, returns bool
approved `bool

Non-Goals

  • Not a general TUI framework. Use Textual for multi-pane dashboards.
  • Not an agent framework. No LLM client, no tool dispatcher, no memory store. The library renders; you drive.
  • Not alt-buffer / full-screen. The whole point is to preserve native scrollback.

Requirements

  • Python 3.13+
  • rich >= 13.0
  • prompt-toolkit >= 3.0

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

agentic_tui-0.3.0.tar.gz (5.9 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agentic_tui-0.3.0-py3-none-any.whl (20.6 kB view details)

Uploaded Python 3

File details

Details for the file agentic_tui-0.3.0.tar.gz.

File metadata

  • Download URL: agentic_tui-0.3.0.tar.gz
  • Upload date:
  • Size: 5.9 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for agentic_tui-0.3.0.tar.gz
Algorithm Hash digest
SHA256 fe9b469b55b10d944141978d09eaae2b3b854679ecf160d1a8dbadabade9931e
MD5 4391e63eed0ffd9bf34b80613fae59db
BLAKE2b-256 fd8e2fa771e8e5c36c3097859192cfddd89890e96ed1d4f7bc1da2199b3a671f

See more details on using hashes here.

File details

Details for the file agentic_tui-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: agentic_tui-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 20.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for agentic_tui-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0cd028ffeff55bedb5080e0dbfca6cfa75ce6d0e0c2375696ad44ea0ec97fe32
MD5 9e8f0001b803bd610432132659345bc0
BLAKE2b-256 cd2436cefaaf7dcb43555ff22e8c7aacf77af3393ebfbd6732bdd7285de72cc9

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page