Skip to content

Shell Completions

Axium provides a fast, hierarchical shell completion system for instant command discovery across core commands, Spokes, and Gears.


Overview

The completion system offers:

  • Fast lookups - Target <50ms response time via cached command registry
  • Hierarchical matching - Multi-word commands (daemon start, env set prod)
  • Dynamic updates - Automatically refreshes when Spokes/Gears load
  • Shell agnostic - Works with zsh, bash, and fish
  • No external dependencies - Pure Python implementation

Architecture

Shell Tab Press
Shell Completion Function
axium completions list "prefix"
Load Cache (~/.config/axium/completions.json)
Filter Matches
Return to Shell (<50ms total)

Command Registry

All commands are registered in a central registry:

# Core commands registered on startup
registry.introspect_typer_app(app, source="core")

# Spoke commands registered when loaded
registry.introspect_typer_app(spoke_app, source="aws-spoke")

# Gear commands registered when loaded
registry.introspect_typer_app(gear_app, source="ansible-gear")

Completion Cache

The registry is serialized to ~/.config/axium/completions.json:

{
  "commands": [
    "bootstrap",
    "config edit",
    "config path",
    "config show",
    "daemon logs",
    "daemon reload",
    "daemon start",
    "daemon status",
    "daemon stop",
    "env get",
    "env list",
    "env set",
    "env show",
    "gear list",
    "gear perms-edit",
    "gear perms-show"
  ],
  "generated_at": "2025-10-13T17:30:00Z",
  "command_count": 42
}

Installation

Auto-Detection

axium completions install

Detects your shell from $SHELL and outputs installation instructions.

Manual Shell Selection

# ZSH
axium completions install --shell zsh

# Bash
axium completions install --shell bash

# Fish
axium completions install --shell fish

Shell Integration

ZSH

Add to ~/.zshrc:

# Axium shell completion for zsh
_axium_completion() {
  local prefix current
  current="${words[CURRENT]}"

  # Build prefix from all axium arguments up to current position
  if [[ $CURRENT -eq 2 ]]; then
    # Completing first argument after 'axium'
    prefix="$current"
  else
    # Completing subsequent arguments
    # Join all previous words (2 to CURRENT-1) with spaces
    prefix="${(j: :)words[2,CURRENT-1]}"
    # Add trailing space if current word is empty (user pressed space before tab)
    [[ -z "$current" ]] && prefix="$prefix " || prefix="$prefix $current"
  fi

  local -a completions
  completions=($(axium completions list --shell zsh "$prefix" 2>/dev/null))
  compadd -Q -- "${completions[@]}"
}
compdef _axium_completion axium

# Then run: source ~/.zshrc

Bash

Add to ~/.bashrc:

# Axium shell completion for bash
_axium_completion() {
  local cur prev words cword
  _init_completion || return
  COMPREPLY=($(axium completions list --shell bash "$cur" 2>/dev/null))
}
complete -F _axium_completion axium

# Then run: source ~/.bashrc

Fish

Create ~/.config/fish/completions/axium.fish:

# Axium shell completion for fish
complete -c axium -f -a '(axium completions list --shell fish (commandline -ct) 2>/dev/null)'

# Completions available immediately

Usage

Basic Completion

axium <TAB>
# Shows: bootstrap  config  daemon  env  gear  hud  ...

axium d<TAB>
# Completes to: axium daemon

axium daemon <TAB>
# Shows: logs  reload  start  status  stop

Hierarchical Completion

axium env <TAB>
# Shows: get  list  set  show

axium env s<TAB>
# Shows: set  show

axium daemon sta<TAB>
# Completes to: axium daemon start

Multi-Word Commands

axium gear perms<TAB>
# Shows: perms-edit  perms-show

axium config <TAB>
# Shows: edit  path  show

Cache Management

Automatic Regeneration

The completion cache regenerates automatically when:

  • Spokes are loaded, reloaded, or unloaded
  • Gears are loaded or unloaded
  • Daemon configuration is reloaded
  • Command registry changes

Manual Refresh

# Force regeneration
axium completions refresh

# Output:
 Regenerated completion cache (42 commands)

Cache Location

~/.config/axium/completions.json

Viewing Cache

# List all completions
axium completions list ""

# Filter completions
axium completions list "env"
# Output:
env get
env list
env set
env show

# Multi-word filter
axium completions list "daemon s"
# Output:
daemon start
daemon status

Implementation Details

Completion Algorithm

def get_completions(prefix: str) -> list[str]:
    """
    Get matching completions for prefix.

    Args:
        prefix: Command prefix to match (e.g., "env", "daemon s")

    Returns:
        List of matching command strings
    """
    cache = load_completion_cache()

    if not prefix:
        # Return all commands
        return cache

    # Filter commands that start with prefix
    prefix_lower = prefix.lower()
    matches = [
        cmd for cmd in cache
        if cmd.lower().startswith(prefix_lower)
    ]

    return sorted(matches)

Performance

  • Cache load: ~5-10ms
  • Filtering: ~5-10ms for 100+ commands
  • Total time: ~20-30ms typical, <50ms target

Registry Structure

Commands stored with metadata:

{
    "daemon start": {
        "source": "core",
        "help": "Start the Axium daemon process",
        "path": ["daemon", "start"]
    },
    "spoke list": {
        "source": "core",
        "help": "List all installed Spokes",
        "path": ["spoke", "list"]
    },
    "aws-whoami": {
        "source": "aws-spoke",
        "help": "Show current AWS identity",
        "path": ["aws-whoami"]
    }
}

Troubleshooting

Completions Not Working

Check installation:

# Verify completion function is defined
typeset -f _axium_completion  # zsh
declare -f _axium_completion  # bash

# Reload shell config
source ~/.zshrc  # or ~/.bashrc

Check cache exists:

ls ~/.config/axium/completions.json

# If missing, regenerate
axium completions refresh

Slow Completions

Check response time:

time axium completions list "env"
# Should be <50ms

If slow: - Check cache file size (should be <100KB) - Verify no network calls in completion path - Check for slow disk I/O

Missing Commands

Regenerate cache:

axium completions refresh

Check command registered:

axium completions list "" | grep my-command

Check registry:

from axium.core import registry
commands = registry.list_all_commands()
print([cmd for cmd in commands if "my-command" in cmd])

Duplicate Completions

Check for duplicate registrations:

axium completions list "" | sort | uniq -d

Solution: - Ensure spokes/gears don't register same command - Check for naming conflicts


Advanced Usage

Custom Completion in Spokes

Spokes can register commands that appear in completions:

def register(app, events):
    @app.command("my-spoke-cmd")
    def my_cmd():
        """This appears in completions."""
        pass

    # Completion cache auto-regenerates when spoke loads

Completion Filtering

# Show only env commands
axium completions list "env" | wc -l
# 4

# Show only daemon commands
axium completions list "daemon" | wc -l
# 5

# Show all commands
axium completions list "" | wc -l
# 42

Debugging Completions

# Enable debug logging
AXIUM_DEBUG=1 axium completions list "env" 2>&1 | grep completion

# Check cache generation
AXIUM_DEBUG=1 axium completions refresh

Comparison with Typer Built-in Completions

Feature Axium Completions Typer Built-in
Speed <50ms (cached) Slow (shell startup)
Multi-word
Dynamic updates ✓ Auto Manual
Spoke/Gear discovery
Shell support zsh, bash, fish zsh, bash
Installation Simple Complex

API Reference

CLI Commands

# Install completions (print instructions)
axium completions install [--shell SHELL]

# List matching completions
axium completions list [PREFIX]

# Regenerate cache
axium completions refresh

Python API

from axium.core.completions import (
    generate_completion_cache,
    load_completion_cache,
    get_completions
)

# Generate cache
success = generate_completion_cache()

# Load cache
commands = load_completion_cache()  # list[str]

# Get matches
matches = get_completions("env")  # ["env get", "env list", ...]

See Also