First-party
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
```python
#!/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
```python
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
```python
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
```python
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
```python
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
```python
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
```python
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)
```python
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)
```python
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
```toml
[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
```bash
# 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
```bash
# 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
| Category | Tools | Use Case |
|----------|-------|----------|
| **Memory** | `read_memory`, `write_memory`, `list_memory` | Persist context across sessions |
| **Web** | `web_search`, `web_fetch` | Live data, docs, research |
| **File Ops** | `read_file`, `write_file` | Read/write any local file |
| **Fleet** | `fleet_ssh`, `axe_push` | Run commands on JL2/JL3/JL4, send notifications |
| **AI Models** | `query_team_channel`, `get_partner_state` | Cross-agent coordination |
| **Data** | `qdrant_search`, `qdrant_store` | Semantic memory & vector search |
| **Pipeline** | `hydra_add` | Add high-quality outputs to Edge training |
| **Skills** | `hub_list_skills`, `hub_get_skill`, `hub_search_skills`, `hub_get_registry`, `hub_skill_metadata` | Chain skills together |
| **Secrets** | `get_secret` | Retrieve API keys securely |
### Quick Start
```python
# 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.
```python
# After generating a high-quality response:
hydra_add(
prompt=user_input,
response=final_output,
score=0.9, # eval score
source="skill-name" # tracks provenance
)
```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.
#!/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()
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)
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)
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))
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()
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))
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()
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}")
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"))
[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"
# 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 in isolated environment
pipx install .
# Or with pip
pip install -e .
# Run
axe start api
axe status --format json
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.
| Category | Tools | Use Case |
|---|---|---|
| Memory | read_memory, write_memory, list_memory | Persist context across sessions |
| Web | web_search, web_fetch | Live data, docs, research |
| File Ops | read_file, write_file | Read/write any local file |
| Fleet | fleet_ssh, axe_push | Run commands on JL2/JL3/JL4, send notifications |
| AI Models | query_team_channel, get_partner_state | Cross-agent coordination |
| Data | qdrant_search, qdrant_store | Semantic memory & vector search |
| Pipeline | hydra_add | Add high-quality outputs to Edge training |
| Skills | hub_list_skills, hub_get_skill, hub_search_skills, hub_get_registry, hub_skill_metadata | Chain skills together |
| Secrets | get_secret | Retrieve API keys securely |
# 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")
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
)
Fetch this skill’s definition over the open API — no key required.
curl -s /v1/skills/cli-tui-design