AXe Skills HubSearch /

← All skills

cli-tui-design

AXe First-party 

Reference: full SKILL.md

Below is the complete skill definition this hub loads when the skill is triggered — what the agent sees as its instructions, verbatim and unabridged.

CLI/TUI Design

Role

You are an elite CLI/TUI architect. You design professional command-line tools with

rich output, interactive interfaces, proper argument parsing, piping support, and

terminal-aware rendering.

Part 1: Click CLI Framework

Well-Structured CLI

#!/usr/bin/env python3
"""Professional CLI tool with Click."""
import click
import sys

@click.group()
@click.version_option(version="1.0.0")
@click.option("--verbose", "-v", is_flag=True, help="Enable verbose output")
@click.option("--config", "-c", type=click.Path(), default="~/.config/app/config.yaml")
@click.pass_context
def cli(ctx, verbose, config):
    """AXE — AI eXtension Engine CLI."""
    ctx.ensure_object(dict)
    ctx.obj["verbose"] = verbose
    ctx.obj["config"] = config

@cli.command()
@click.argument("service", type=click.Choice(["api", "ollama", "redis", "all"]))
@click.option("--port", "-p", type=int, help="Override default port")
@click.pass_context
def start(ctx, service, port):
    """Start a service."""
    if ctx.obj["verbose"]:
        click.echo(f"Starting {service}...")
    click.secho(f"Service {service} started", fg="green", bold=True)

@cli.command()
@click.argument("service", type=click.Choice(["api", "ollama", "redis", "all"]))
@click.confirmation_option(prompt="Are you sure you want to stop?")
def stop(service):
    """Stop a service."""
    click.secho(f"Service {service} stopped", fg="yellow")

@cli.command()
@click.option("--format", "-f", "fmt", type=click.Choice(["table", "json", "plain"]), default="table")
def status(fmt):
    """Show status of all services."""
    services = [
        {"name": "FastAPI", "port": 8000, "status": "running"},
        {"name": "Ollama", "port": 11434, "status": "running"},
        {"name": "Redis", "port": 6379, "status": "stopped"},
    ]
    if fmt == "json":
        import json
        click.echo(json.dumps(services, indent=2))
    else:
        for s in services:
            color = "green" if s["status"] == "running" else "red"
            click.secho(f"  {s['name']:12} :{s['port']}  {s['status']}", fg=color)

if __name__ == "__main__":
    cli()

Part 2: Rich Output

Tables, Panels, Trees

from rich.console import Console
from rich.table import Table
from rich.panel import Panel
from rich.tree import Tree
from rich.text import Text
from rich import print as rprint

console = Console()

# Tables
def show_services():
    table = Table(title="AXE Services", show_lines=True)
    table.add_column("Service", style="cyan", no_wrap=True)
    table.add_column("Port", justify="right", style="magenta")
    table.add_column("Status", justify="center")
    table.add_column("Uptime", justify="right", style="dim")

    table.add_row("FastAPI", "8000", "[green]Running[/green]", "3d 14h")
    table.add_row("Ollama", "11434", "[green]Running[/green]", "3d 14h")
    table.add_row("Redis", "6379", "[red]Stopped[/red]", "-")

    console.print(table)

# Panels
def show_info():
    content = Text()
    content.append("AXE Platform v2.0\n", style="bold cyan")
    content.append("Forge + Cortana + Klaus\n", style="dim")
    content.append("All systems operational", style="green")
    console.print(Panel(content, title="System Info", border_style="blue"))

# Trees
def show_architecture():
    tree = Tree("[bold blue]AXE Platform")
    backend = tree.add("[cyan]Backend")
    backend.add("FastAPI :8000")
    backend.add("Ollama :11434")
    backend.add("Redis :6379")
    frontend = tree.add("[green]Frontend")
    frontend.add("Next.js (Vercel)")
    frontend.add("Klaus Chat :3000")
    console.print(tree)

Progress Bars

from rich.progress import Progress, SpinnerColumn, BarColumn, TextColumn, TimeRemainingColumn
import time

def process_files(files: list[str]):
    with Progress(
        SpinnerColumn(),
        TextColumn("[progress.description]{task.description}"),
        BarColumn(),
        TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
        TimeRemainingColumn(),
    ) as progress:
        task = progress.add_task("Processing files...", total=len(files))
        for f in files:
            # process file...
            time.sleep(0.1)
            progress.update(task, advance=1, description=f"Processing {f}")

# Multiple concurrent tasks
def multi_download():
    with Progress() as progress:
        download = progress.add_task("Downloading...", total=100)
        extract = progress.add_task("Extracting...", total=100)
        install = progress.add_task("Installing...", total=100)

        while not progress.finished:
            progress.update(download, advance=1.5)
            progress.update(extract, advance=0.8)
            progress.update(install, advance=0.5)
            time.sleep(0.02)

Live Display

from rich.live import Live
from rich.table import Table
import time

def live_dashboard():
    def make_table(iteration: int) -> Table:
        table = Table(title=f"Live Dashboard (tick {iteration})")
        table.add_column("Metric")
        table.add_column("Value", justify="right")
        table.add_row("Requests/sec", str(150 + iteration))
        table.add_row("Avg Latency", f"{45 + iteration % 20}ms")
        table.add_row("Error Rate", f"{0.1 + iteration % 5 * 0.01:.2f}%")
        return table

    with Live(make_table(0), refresh_per_second=4) as live:
        for i in range(100):
            time.sleep(0.25)
            live.update(make_table(i))

Part 3: Textual TUI Framework

from textual.app import App, ComposeResult
from textual.containers import Horizontal, Vertical
from textual.widgets import Header, Footer, Static, Button, DataTable, Log, Input
from textual.binding import Binding

class DashboardApp(App):
    CSS = """
    #sidebar { width: 30; background: $surface; }
    #main { width: 1fr; }
    .box { border: solid green; margin: 1; padding: 1; }
    """

    BINDINGS = [
        Binding("q", "quit", "Quit"),
        Binding("r", "refresh", "Refresh"),
        Binding("d", "toggle_dark", "Dark Mode"),
    ]

    def compose(self) -> ComposeResult:
        yield Header()
        with Horizontal():
            with Vertical(id="sidebar"):
                yield Button("Services", id="btn-services", variant="primary")
                yield Button("Logs", id="btn-logs")
                yield Button("Settings", id="btn-settings")
            with Vertical(id="main"):
                yield DataTable(id="services-table")
                yield Log(id="log-panel")
        yield Footer()

    def on_mount(self) -> None:
        table = self.query_one("#services-table", DataTable)
        table.add_columns("Service", "Port", "Status", "Uptime")
        table.add_rows([
            ("FastAPI", "8000", "Running", "3d 14h"),
            ("Ollama", "11434", "Running", "3d 14h"),
            ("Redis", "6379", "Stopped", "-"),
        ])

    def on_button_pressed(self, event: Button.Pressed) -> None:
        log = self.query_one("#log-panel", Log)
        log.write_line(f"Button pressed: {event.button.id}")

    def action_refresh(self) -> None:
        self.notify("Refreshing...")

if __name__ == "__main__":
    DashboardApp().run()

Part 4: Terminal Detection & Piping

import sys
import os
import shutil

def is_interactive() -> bool:
    """Check if we're in an interactive terminal (not piped)."""
    return sys.stdout.isatty()

def terminal_size() -> tuple[int, int]:
    """Get terminal width and height."""
    cols, rows = shutil.get_terminal_size(fallback=(80, 24))
    return cols, rows

def supports_color() -> bool:
    """Check if terminal supports ANSI colors."""
    if not is_interactive():
        return False
    if os.environ.get("NO_COLOR"):
        return False
    if os.environ.get("FORCE_COLOR"):
        return True
    term = os.environ.get("TERM", "")
    return term != "dumb"

def smart_output(data: list[dict]):
    """Output data in appropriate format based on context."""
    if is_interactive():
        # Pretty table for interactive use
        from rich.console import Console
        from rich.table import Table
        console = Console()
        table = Table()
        for key in data[0]:
            table.add_column(key)
        for row in data:
            table.add_row(*[str(v) for v in row.values()])
        console.print(table)
    else:
        # Machine-readable for piping
        import json
        for item in data:
            print(json.dumps(item))

Part 5: Interactive Prompts

from prompt_toolkit import prompt
from prompt_toolkit.completion import WordCompleter
from prompt_toolkit.shortcuts import radiolist_dialog, checkboxlist_dialog, yes_no_dialog
from prompt_toolkit.styles import Style

# Autocomplete
service_completer = WordCompleter(["api", "ollama", "redis", "postgres", "nginx"])
result = prompt("Service to restart: ", completer=service_completer)

# Radio list selection
service = radiolist_dialog(
    title="Select Service",
    text="Which service to restart?",
    values=[
        ("api", "FastAPI Backend"),
        ("ollama", "Ollama LLM"),
        ("redis", "Redis Cache"),
    ],
).run()

# Checkbox selection
services = checkboxlist_dialog(
    title="Select Services",
    text="Which services to start?",
    values=[
        ("api", "FastAPI Backend"),
        ("ollama", "Ollama LLM"),
        ("redis", "Redis Cache"),
    ],
).run()

# Yes/No confirmation
confirmed = yes_no_dialog(
    title="Confirm",
    text="Deploy to production?",
).run()

Part 6: argparse (Standard Library)

import argparse

def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(
        prog="axe",
        description="AXE Platform CLI",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  axe start api --port 8080
  axe status --format json
  axe deploy --env production
        """,
    )
    parser.add_argument("--version", action="version", version="%(prog)s 1.0.0")
    parser.add_argument("-v", "--verbose", action="count", default=0, help="Increase verbosity (-v, -vv, -vvv)")

    subparsers = parser.add_subparsers(dest="command", required=True)

    # start command
    start_parser = subparsers.add_parser("start", help="Start a service")
    start_parser.add_argument("service", choices=["api", "ollama", "redis", "all"])
    start_parser.add_argument("--port", "-p", type=int)
    start_parser.add_argument("--background", "-b", action="store_true")

    # status command
    status_parser = subparsers.add_parser("status", help="Show service status")
    status_parser.add_argument("--format", "-f", choices=["table", "json", "plain"], default="table")

    return parser

if __name__ == "__main__":
    parser = build_parser()
    args = parser.parse_args()
    if args.command == "start":
        print(f"Starting {args.service}")

Part 7: ANSI Colors (No Dependencies)

class Colors:
    """ANSI color codes — zero dependencies."""
    RESET = "\033[0m"
    BOLD = "\033[1m"
    DIM = "\033[2m"
    RED = "\033[31m"
    GREEN = "\033[32m"
    YELLOW = "\033[33m"
    BLUE = "\033[34m"
    MAGENTA = "\033[35m"
    CYAN = "\033[36m"

    @staticmethod
    def colorize(text: str, color: str) -> str:
        if not supports_color():
            return text
        return f"{color}{text}{Colors.RESET}"

    @classmethod
    def success(cls, msg: str) -> str:
        return cls.colorize(f"[OK] {msg}", cls.GREEN)

    @classmethod
    def error(cls, msg: str) -> str:
        return cls.colorize(f"[ERR] {msg}", cls.RED)

    @classmethod
    def warn(cls, msg: str) -> str:
        return cls.colorize(f"[WARN] {msg}", cls.YELLOW)

    @classmethod
    def info(cls, msg: str) -> str:
        return cls.colorize(f"[INFO] {msg}", cls.CYAN)

# Usage
print(Colors.success("All services running"))
print(Colors.error("Redis connection failed"))
print(Colors.warn("High memory usage detected"))

Part 8: Packaging & Distribution

pyproject.toml for CLI

[project]
name = "axe-cli"
version = "1.0.0"
description = "AXE Platform CLI"
requires-python = ">=3.10"
dependencies = [
    "click>=8.0",
    "rich>=13.0",
    "httpx>=0.25",
]

[project.scripts]
axe = "axe_cli.main:cli"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

Shell Completion

# Click auto-completion
# For bash
_AXE_COMPLETE=bash_source axe > ~/.axe-complete.bash
echo 'source ~/.axe-complete.bash' >> ~/.bashrc

# For zsh
_AXE_COMPLETE=zsh_source axe > ~/.axe-complete.zsh
echo 'source ~/.axe-complete.zsh' >> ~/.zshrc

# For fish
_AXE_COMPLETE=fish_source axe > ~/.config/fish/completions/axe.fish

Install Globally

# Install in isolated environment
pipx install .

# Or with pip
pip install -e .

# Run
axe start api
axe status --format json

AXE MCP Server Integration

Every skill in the AXE Skills Hub runs with access to the AXE MCP Server — giving it the full fleet intelligence toolkit automatically. No setup required; tools are available in any AXE-powered session.

Core Tools Available

CategoryToolsUse Case
Memoryread_memory, write_memory, list_memoryPersist context across sessions
Webweb_search, web_fetchLive data, docs, research
File Opsread_file, write_fileRead/write any local file
Fleetfleet_ssh, axe_pushRun commands on JL2/JL3/JL4, send notifications
AI Modelsquery_team_channel, get_partner_stateCross-agent coordination
Dataqdrant_search, qdrant_storeSemantic memory & vector search
Pipelinehydra_addAdd high-quality outputs to Edge training
Skillshub_list_skills, hub_get_skill, hub_search_skills, hub_get_registry, hub_skill_metadataChain skills together
Secretsget_secretRetrieve API keys securely

Quick Start

# In any AXE session, tools are pre-loaded. Example chaining:

# 1. Search for context
results = qdrant_search("user query here", collection="axe_persistent_memory")

# 2. Fetch live data if needed
content = web_fetch("https://docs.example.com/api")

# 3. Write result to memory for next session
write_memory("shared/last_result.md", output)

# 4. Log quality output to Edge training pipeline
hydra_add(prompt=user_query, response=output, score=0.9, source="skill-name")

Edge Training Integration

High-quality skill outputs are automatically eligible for Edge model training via hydra_add. When a response scores ≥0.85 in evals, pipe it to the Hydra pipeline to compound Edge's knowledge. This is how skills make Edge smarter over time.

# After generating a high-quality response:
hydra_add(
    prompt=user_input,
    response=final_output,
    score=0.9,          # eval score
    source="skill-name" # tracks provenance
)

Metadata

Category
Cli
Tier
community
Version
1.0.0
License
MIT
Path
skills/cli-tui-design/SKILL.md

Use with an agent

Fetch this skill’s definition over the open API — no key required.

curl -s /v1/skills/cli-tui-design

View source ↗