- name
- ops-streamdeck
- description
- Stream Deck control skill for agents. Provides ability to restart streamdeck daemons, execute button tasks, query status, and manage Stream Deck hardware through a persistent daemon interface. Works with the streamdeck Python package for CLI operations and agent-driven automation.
- allowed-tools
- Bash, Read
- triggers
- ["restart streamdeck","streamdeck button","execute streamdeck task","streamdeck status","streamdeck daemon","start streamdeck","stop streamdeck","streamdeck health check","fix streamdeck buttons","streamdeck broken"]
- metadata
- {"short-description":"Stream Deck daemon control and automation"}
- provides
- ["ops-streamdeck"]
- composes
- ["task-monitor","agentic-evals"]
- disciplines
- ["developer-tooling","observability-operations"]
# Stream Deck Skill
Agent-accessible interface for Stream Deck control. Provides persistent daemon
management, button task execution, and status querying capabilities.
## Architecture
The streamdeck project has two components:
1. **CLI Tool** (`streamdeck` command) - Manual operations by users
2. **Daemon** (this skill) - Persistent service for agent automation
```
┌─────────────────────────────────────────────────────────────────────┐
│ AGENT / AUTOMATION │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Stream Deck Skill (this skill) │ │
│ │ • Restart daemon │ │
│ │ • Execute button tasks │◄──►│
│ │ • Query status │ │
│ └────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Stream Deck Daemon (persistent service) │ │
│ │ • Manages Stream Deck hardware │ │
│ │ • Executes button press events │ │
│ │ • Provides status API │ │
│ └────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Stream Deck CLI (manual operations) │ │
│ │ • User-invoked commands │ │
│ │ • Video chat, lights, monitoring, etc. │ │
│ └────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
```
## Quick Start
### 1. Start the Daemon
```bash
# Start the streamdeck daemon in the background
./run.sh daemon start
# Or start in foreground for debugging
./run.sh daemon start --foreground
```
### 2. Use Agent Commands
```bash
# Restart the daemon
./run.sh restart
# Execute a button task
./run.sh button <button_id> [args...]
# Query daemon status
./run.sh status
# List available buttons
./run.sh list-buttons
# Get daemon logs
./run.sh logs
```
## Commands
### Daemon Management
| Command | Description |
| --------------------------- | ------------------------------------------ |
| `daemon start` | Start the streamdeck daemon (background) |
| `daemon start --foreground` | Start daemon in foreground (for debugging) |
| `daemon stop` | Stop the streamdeck daemon |
| `daemon restart` | Restart the streamdeck daemon |
| `daemon status` | Check if daemon is running |
| `daemon logs` | View daemon logs |
### Button Operations
| Command | Description |
| -------------------- | ------------------------------- |
| `button <id>` | Execute button press event |
| `button <id> --hold` | Execute button long-press event |
| `list-buttons` | List all available button IDs |
| `button-info <id>` | Get information about a button |
### Status Queries
| Command | Description |
| ------------------ | ------------------------- |
| `status` | Get overall daemon status |
| `status --json` | Get status in JSON format |
| `status --buttons` | Get button states |
### Configuration
| Command | Description |
| ---------------------------- | -------------------------- |
| `config` | Show current configuration |
| `config --set <key> <value>` | Set configuration value |
| `config --get <key>` | Get configuration value |
### Prompts Management
| Command | Description |
| ---------------------------------------- | -------------------------------------------------------------- |
| `prompts list` | List available prompts |
| `prompts copy <name>` | Copy prompt content to clipboard |
| `prompts set-button <name> <btn>` | Configure a button for a prompt |
| `prompts set-button ... --switch-page N` | Configure button to switch page after press (1=Home, 2=Page 1) |
### Health Check & Auto-Fix
| Command | Description |
| -------------- | ---------------------------------------------- |
| `health-check` | Verify all services running and icons correct |
| `fix` | Auto-repair broken button configurations |
```bash
# Check if buttons are configured correctly
./run.sh health-check
# Auto-fix broken buttons (stops service, edits config, restarts)
./run.sh fix
```
## CRITICAL: Config File Behavior
The Stream Deck UI (`streamdeck.service`) saves its in-memory state to `~/.streamdeck_ui.json` every ~30 seconds.
**NEVER edit the config while the service is running!** Your changes will be overwritten.
### Correct Procedure for Config Changes
```bash
# 1. STOP the service first
systemctl --user stop streamdeck.service
# 2. Edit the config file
vim ~/.streamdeck_ui.json
# 3. START the service (loads your changes into memory)
systemctl --user start streamdeck.service
```
### Why Socket Updates Are Temporary
The `icon_updater.py` sends updates via Unix socket to change button icons in real-time.
These updates modify the **in-memory state** only. When the service saves its state
(every ~30 seconds), it writes the in-memory values back to the config file.
This means:
- Socket updates appear immediately on the Stream Deck
- But if the config file had different values, those get overwritten
- The next time the service restarts, it loads from the config file
**Use `./run.sh fix` to safely update button configurations.**
## Configuration
The daemon reads configuration from:
1. **Environment Variables:**
- `STREAMDECK_DAEMON_PORT` - Port for daemon API (default: 48970)
- `STREAMDECK_DAEMON_HOST` - Host for daemon API (default: 127.0.0.1)
- `STREAMDECK_LOG_LEVEL` - Log level (DEBUG, INFO, WARNING, ERROR)
2. **Config File:** `~/.streamdeck/daemon.json`
### Example Config
```json
{
"daemon": {
"port": 48970,
"host": "127.0.0.1",
"log_level": "INFO"
},
"buttons": {
"0": {
"name": "Video Chat Start",
"command": "streamdeck videochat start"
},
"1": {
"name": "Video Chat Stop",
"command": "streamdeck videochat stop"
},
"2": {
"name": "Lights Toggle",
"command": "streamdeck lights toggle"
},
"3": {
"name": "Time Tracker Toggle",
"command": "streamdeck time-tracker toggle"
}
}
}
```
## Integration with Stream Deck CLI
The daemon works alongside the existing streamdeck CLI:
- **CLI** - Used for manual operations by humans
- **Daemon** - Used for automated operations by agents
- Both\*\* share the same configuration and codebase
This dual approach ensures:
- ✅ Human users can continue using familiar CLI commands
- ✅ Agents have reliable daemon for automation
- ✅ No breaking changes to existing functionality
- ✅ Consistent behavior across both interfaces
## API Endpoints
The daemon exposes a simple HTTP API:
| Endpoint | Method | Description |
| ------------------------- | ------ | ------------------------- |
| `GET /status` | GET | Get daemon status |
| `GET /buttons` | GET | List all buttons |
| `GET /buttons/{id}` | GET | Get button info |
| `POST /buttons/{id}` | POST | Execute button press |
| `POST /buttons/{id}/hold` | POST | Execute button long-press |
| `POST /restart` | POST | Restart daemon |
| `POST /stop` | POST | Stop daemon |
### Example API Usage
```bash
# Get status
curl http://127.0.0.1:48970/status
# Execute button
curl -X POST http://127.0.0.1:48970/buttons/0
# Get button info
curl http://127.0.0.1:48970/buttons/0
```
## Troubleshooting
### Daemon Won't Start
```bash
# Check if port is already in use
lsof -i :48970
# Check logs for errors
./run.sh logs
# Try starting in foreground to see errors
./run.sh daemon start --foreground
```
### Button Not Executing
```bash
# Check button configuration
./run.sh button-info <id>
# Verify daemon is running
./run.sh status
# Check logs for errors
./run.sh logs
```
### Permission Issues
The daemon requires access to:
- Stream Deck hardware (USB device access)
- Configuration directory (`~/.streamdeck/`)
- Network port (48970) for API
On Linux, ensure user has proper permissions:
```bash
# Add user to dialout group (for serial port access)
sudo usermod -a -G dialout $USER
# Ensure ~/.streamdeck is writable
chmod 755 ~/.streamdeck
```
## Development
### Running Tests
```bash
# Run daemon tests
./sanity.sh
# Run with verbose output
./sanity.sh --verbose
```
### Agentic Evaluation
`ops-streamdeck` composes with `agentic-evals` and carries a committed
multi-trial fixture at `fixtures/agentic_eval.json`.
Use this fixture after changing the skill contract, `run.sh`, service-control
logic, button execution behavior, health checks, or Stream Deck config safety
rules:
```bash
../agentic-evals/run.sh run fixtures/agentic_eval.json
```
The eval exercises a live local status path and a fail-closed malformed button
request. It also runs `./run.sh audit-states`, which non-mutatingly enumerates
every configured Stream Deck page/button/state and reports missing icon paths,
invalid field types, and switch-page warnings from the live
`~/.streamdeck_ui.json` state.
This does not prove physical button rendering, USB hardware availability, light
behavior, daemon API correctness, command semantics for every executable button,
or safe persistent config mutation.
### Adding New Features
To add new button commands:
1. Add button configuration to `~/.streamdeck/daemon.json`
2. Implement command handler in daemon code
3. Test with: `./run.sh button <id>`
## Data Storage
- **Config:** `~/.streamdeck/daemon.json` - Button configurations and daemon settings
- **Logs:** `~/.streamdeck/daemon.log` - Daemon activity logs
- **State:** `~/.streamdeck/daemon.state` - Current button states (runtime only)
## Dependencies
- Python 3.8+
- Stream Deck Python SDK (`streamdeck`)
- FastAPI (for daemon API)
- Uvicorn (for daemon server)
- Pydantic (for API models)
Install dependencies:
```bash
# Via uvx (recommended)
uvx --from "git+https://github.com/grahama1970/streamdeck.git" streamdeck-daemon
# Or manually
pip install streamdeck fastapi uvicorn pydantic
```
## License
MIT License - See LICENSE file for details.
Voir sur GitHub