Linux daemon + CLI for the AJAZZ AKP153 macro pad. Assign shell commands to physical buttons via a simple YAML config.
- Linux (Ubuntu/Debian recommended) or WSL2 with usbipd
- Python 3.12+
- uv package manager
- AJAZZ AKP153 connected via USB
# 1. Clone
git clone https://github.com/jrodeiro5/ajazz-deck
cd ajazz-deck
# 2. Install dependencies
uv sync
sudo ./install/udev/install.sh
# 3. Configure your buttons
cp buttons.example.yaml buttons.yaml
nano buttons.yaml # edit with your commands
# 4. Start the daemon
ajazz daemon start # works directly, no uv run needed
# 5. Press a button on your AKP153 — it runs your commandsudo ./install/udev/install.sh
# Unplug and replug AKP153 — daemon starts automatically
⚠️ udev autostart is not supported in WSL. Use usbipd to attach the device, then start the daemon manually or via Task Scheduler.
# Daemon Management
ajazz daemon start|stop|restart|status
ajazz logs [--lines N] # Show last N lines from deck.log
# (default: 20)
# Button Configuration
ajazz button list # Show all configured buttons
ajazz button show <id> # Show button details
ajazz button test <id> # Test button command execution
ajazz button set <id> --label TEXT --command TEXT
[--type shell|clipboard|script] [--icon PATH]
ajazz button remove <id> # Remove button from configuration
# Button Images
ajazz image set <id> --url URL # Set image from URL (auto-resizes to 96×96)
ajazz image set <id> --file PATH # Set image from local file
ajazz image set <id> --generate PROMPT # Generate image with Gemini (requires GOOGLE_API_KEY)
ajazz image show <id> # Show button's current image path
ajazz image clear <id> # Remove image from button
# Configuration & Status
ajazz config show # Display button configuration
ajazz config validate # Validate buttons.yaml syntax- Simple YAML Configuration: Easy button setup with labels and commands
- Button Management: Add, update, remove buttons via CLI with validation
- Button Images: Set custom icons (96×96 px) from URLs, local files, or AI-generated
- Rich CLI Output: Beautiful terminal interface with AJAZZ branding
- udev Autostart: Automatic daemon startup when device is connected
- WSL Support: Full support for Windows Subsystem for Linux
- MCP Integration: Programmatic control from Claude Code, Windsurf, or Zed
- JSON Output: Script-friendly output format for automation
- Log Viewing: Built-in log viewer with configurable line count
- Auto-restart: Daemon automatically restarts when configuration changes
Set custom button icons on the AKP153 display — from image URLs, local files, or AI-generated with Gemini.
# 1. Install dependencies (included in uv sync)
uv sync
# 2. Create .env for AI image generation (optional)
cp .env.example .env
# Get a free Google Gemini API key: https://aistudio.google.com/apikey
# Add it to .env: GOOGLE_API_KEY=your-api-key# Set from URL
ajazz image set 1 --url https://example.com/icon.png
# Set from local file
ajazz image set 2 --file icons/my-icon.png
# Generate with AI (requires GOOGLE_API_KEY in .env)
ajazz image set 3 --generate "red button with checkmark"
# Show current image
ajazz image show 1
# Remove image from button
ajazz image clear 1# Set image from URL
set_button_image_from_url(button_id=1, url="https://...")
# Generate image from text
set_button_image_from_prompt(button_id=2, prompt="red stop sign")
# Remove image
clear_button_image(button_id=3)- Image Format: PNG (converted internally to JPEG for device)
- Dimensions: 96×96 pixels (auto-resized)
- Storage: Icons saved to
icons/{button_id}.png - Generation vs. Display: Images are generated and saved successfully, but will only display on the physical AKP153 device when the daemon is running and the device is connected. The generation process always succeeds; device display depends on daemon state.
AI image generation (ajazz image set --generate) requires a Google Gemini API key.
There are three ways to provide GOOGLE_API_KEY:
cp .env.example .env
# Edit .env and set your key:
# GOOGLE_API_KEY=your-google-api-key-hereThe .env file is loaded automatically at startup and is gitignored.
export GOOGLE_API_KEY="your-google-api-key-here"
# Add to ~/.bashrc or ~/.zshrc to persist across sessions{
"mcpServers": {
"ajazz-deck": {
"type": "stdio",
"command": "uv",
"args": ["run", "python3", "/absolute/path/to/ajazz-deck/mcp_server.py"],
"cwd": "/absolute/path/to/ajazz-deck",
"env": {
"GOOGLE_API_KEY": "your-key-here"
}
}
}
}Note: When using Claude Code MCP, Option C takes priority over Options A and B, since the MCP server process inherits only the env vars defined in
.mcp.json.
Get a free API key at https://aistudio.google.com/apikey.
Control the AKP153 macro pad programmatically from Claude Code, Windsurf, or Zed.
# 1. Copy the example config template
cp .mcp.json.example .mcp.json
# 2. Edit .mcp.json with your absolute paths
nano .mcp.json
# Change "/absolute/path/to/ajazz-deck" to your actual installation path
# 3. (Optional) Add GOOGLE_API_KEY to .mcp.json for AI image generation
# See "API Keys & Image Generation" section below for all options
# 4. Register with Claude Code (from this project directory)
claude mcp add --transport stdio ajazz-deck \
-- ajazz-mcp-
list_buttons— Show all configured buttons -
set_button— Add/update a button configuration -
remove_button— Delete a button -
daemon_status— Check if daemon is running -
daemon_start— Start the daemon -
daemon_stop— Stop the daemon -
get_logs— Retrieve daemon logs
Image Tools:
-
set_button_image_from_url— Download image from URL and set as button icon -
set_button_image_from_prompt— Generate button icon with Gemini AI -
clear_button_image— Remove image from button
from mcp_server import set_button, daemon_start
# Add a button
set_button(button_id=1, label="Terminal", command="xterm")
# Start daemon if not running
daemon_start()buttons:
1:
label: "My Button"
command: "your-shell-command"
type: "shell" # shell, clipboard, or script
image: "icons/my-icon.png" # optional: path to .png icon (96×96)
2:
label: "With Script"
script: "echo hello | xclip"
type: "script"See buttons.example.yaml for a complete working example with 6 buttons.
tail -f deck.log # real-time logs
LOG_LEVEL=DEBUG ajazz daemon start # verbose mode- Ensure AKP153 is connected via USB
- Check
ajazz device statusfor device information - On Linux, verify user is in the
inputgroup:sudo usermod -a -G input $USER
- Validate configuration:
ajazz config validate - Check logs:
tail -f deck.log - Ensure no other daemon is running:
ajazz daemon status
- Verify .mcp.json has correct absolute paths
- Check environment variables are set
- Ensure dependencies are installed:
uv sync
- Follow install/wsl/README-WSL.md for usbipd setup
- Manually attach device:
usbipd attach --wsl --hardware-id 0300:3010
MIT — vendored SDK from MiraboxSpace/StreamDock-Device-SDK