Control your Linux desktop from anywhere β via chat, API, or WebSocket tunnel.
Vela is a FastAPI-based remote PC agent for Linux. It exposes your desktop's capabilities (filesystem, audio, display, processes, notifications, power management, etc.) through a secure REST API, optionally tunneled through a WebSocket relay for remote access.
- Full system control API β filesystem, audio, display, power, notifications, network, input control, system info, monitoring, processes, security, scheduler, maintenance, media, clipboard, Spotify, alerts
- LLM-powered assistant β natural language chat interface via Fireworks AI with tool-calling
- WebSocket tunnel β connect to a remote VPS relay to access your PC from anywhere
- Agent registration β one-time registration with a VPS; automatic secret rotation
- JWT authentication β bcrypt-hashed passwords, bearer token auth, rate-limited
- Filesystem access control β whitelist-based directory permissions
- Rate limiting β per-endpoint rate limits (default 150/min, auth endpoints 10/min)
- systemd integration β runs as user services with auto-restart
Vela connects your phone to your Linux desktop through a secure relay. Here's how the data flows:
sequenceDiagram
participant Phone as Phone / Client
participant VPS as VPS Relay
participant Agent as Vela Agent (tunnel)
participant API as Vela API Server
participant Desktop as Linux Desktop
Phone->>VPS: REST / API call (X-API-Key or JWT)
VPS->>Agent: Forward via WebSocket tunnel
Agent->>API: Forward to local FastAPI (127.0.0.1:8765)
API->>Desktop: Execute system operation
Desktop-->>API: Result
API-->>Agent: Response
Agent-->>VPS: Forward response
VPS-->>Phone: Response
sequenceDiagram
participant Phone as Phone / Client
participant VPS as VPS Relay
participant Agent as Vela Agent (tunnel)
participant API as Vela API Server
participant LLM as Fireworks AI LLM
participant Desktop as Linux Desktop
Phone->>VPS: POST /assistant/chat "How much storage?"
VPS->>Agent: Forward via WebSocket
Agent->>API: Forward to local FastAPI /assistant/chat
API->>LLM: Send message + available tools
LLM-->>API: Intent: check disk space β select filesystem tool
API->>Desktop: Run df / lsblk
Desktop-->>API: Disk usage data
API->>LLM: Send tool result for summarization
LLM-->>API: Natural language response
API-->>Agent: Response
Agent-->>VPS: Forward response
VPS-->>Phone: "Your SSD is 340/500 GB full"
sequenceDiagram
participant Agent as Vela Agent (tunnel)
participant VPS as VPS Relay
Note over Agent,VPS: First-time registration (no secret yet)
Agent->>VPS: POST /register {agent_id, public_address, metadata}
VPS-->>Agent: {secret, ws_token, expires_at}
Note right of Agent: Secret auto-saved to .env
Note over Agent,VPS: Subsequent reconnects (token refresh)
Agent->>VPS: POST /agents/{agent_id}/ws-token + X-Secret
VPS-->>Agent: {ws_token, expires_at}
| Layer | Does | Doesn't |
|---|---|---|
| Phone / Client | Sends requests, displays results | Parse commands, execute anything |
| VPS Relay | Routes requests via WebSocket, manages agent registration | Execute system operations, understand intent |
| Vela Agent (tunnel) | Maintains WebSocket tunnel to VPS, forwards requests to local API server | Execute system operations, communicate with LLM |
| Vela API Server | Executes system operations via routers, handles AI chat with LLM, enforces auth & safety | Connect to the VPS directly β the agent handles that |
| LLM (Fireworks AI) | Understands natural language, selects tools, summarizes results | Execute system calls β the API server handles that |
| Linux Desktop | Runs the actual system (files, processes, audio, etc.) | Make decisions β it just follows OS calls |
- Python 3.13+
- Linux desktop (X11 or Wayland)
Most of these are typically pre-installed on a modern Linux desktop. Missing tools affect only the corresponding feature.
| Feature | Required Commands | Install (Debian/Ubuntu) | Install (Fedora) | Install (Arch) |
|---|---|---|---|---|
| Filesystem | xdg-open |
xdg-utils |
xdg-utils |
xdg-utils |
| Audio | amixer, pactl, canberra-gtk-play |
alsa-utils, pulseaudio-utils, libcanberra-gtk-module |
alsa-utils, pulseaudio-utils, libcanberra-gtk3 |
alsa-utils, pulseaudio-utils, libcanberra |
| Display / Screenshot | xrandr, flameshot, xset, ffmpeg, busctl, brightnessctl, gsettings, loginctl, swaymsg |
x11-xserver-utils, flameshot, x11-xserver-utils, ffmpeg, libglib2.0-bin, brightnessctl, systemd |
xorg-xrandr, flameshot, xorg-xset, ffmpeg, glib2, brightnessctl, systemd |
xorg-xrandr, flameshot, xorg-xset, ffmpeg, glib2, brightnessctl, systemd |
| Input Control | xdotool, xprop, xwininfo |
xdotool, x11-utils |
xdotool, xorg-xprop, xorg-xwininfo |
xdotool, xorg-xprop, xorg-xwininfo |
| Media | playerctl |
playerctl |
playerctl |
playerctl |
| Network | nmcli, bluetoothctl, rfkill, ping, speedtest-cli |
network-manager, bluez, util-linux, iputils-ping, speedtest-cli |
NetworkManager, bluez, util-linux, iputils, speedtest-cli |
networkmanager, bluez, util-linux, iputils, speedtest-cli |
| Notifications | notify-send, dunstctl |
libnotify-bin, dunst |
libnotify, dunst |
libnotify, dunst |
| Power | systemctl, powerprofilesctl |
systemd, power-profiles-daemon |
systemd, power-profiles-daemon |
systemd, power-profiles-daemon |
| Processes | xdotool, xprop, xwininfo |
xdotool, x11-utils |
xdotool, xorg-xprop, xorg-xwininfo |
xdotool, xorg-xprop, xorg-xwininfo |
| Security | loginctl, modprobe, pactl, pkill, last, who, ffmpeg |
systemd, kmod, pulseaudio-utils, procps, util-linux, coreutils, ffmpeg |
systemd, kmod, pulseaudio-utils, procps-ng, util-linux, coreutils, ffmpeg |
systemd, kmod, pulseaudio-utils, procps-ng, util-linux, coreutils, ffmpeg |
| System Info | lspci, lsusb, dmidecode, nvidia-smi, xrandr |
pciutils, usbutils, dmidecode, nvidia-smi, x11-xserver-utils |
pciutils, usbutils, dmidecode, nvidia-smi, xorg-xrandr |
pciutils, usbutils, dmidecode, nvidia-smi, xorg-xrandr |
| Maintenance | journalctl, systemctl, timedatectl, apt-get/dnf/pacman |
systemd |
systemd |
systemd |
| Monitoring | nvidia-smi |
nvidia-smi (NVIDIA GPU only) |
nvidia-smi (NVIDIA GPU only) |
nvidia-smi (NVIDIA GPU only) |
π‘ Tip: Run
which <command>to check if a particular tool is already installed. Missing tools won't crash the app β the corresponding endpoint will return an appropriate error.
- Fireworks AI API key (for the LLM-powered assistant at
/assistant/chat) - Resend API key (for email alerts β CPU/memory spike alerts and daily summaries)
- Spotify Developer credentials (for Spotify playback control)
git clone https://github.com/mikesplore/vela.git
cd vela
# Run the setup script β it will ask you a few questions
# and generate everything automatically
./setup.shThis will:
- Prompt for credentials, VPS URL, agent ID
- Install the Python package and create a virtual environment
- Generate a
config.yamland.envwith default values - Register the agent with the VPS relay (if reachable)
- Install
vela.serviceandvela-agent.serviceas user systemd units
π‘ VPS relay: You can use the free relay at
vela.mikesplore.techor specify your own.
After running setup.sh, open the generated .env file and add your API keys:
nano .envAt minimum, set your Fireworks AI API key (required for the assistant):
FIREWORKS_API_KEY='your-actual-key-here'
If you want email alerts, also set:
RESEND_API_KEY='your-resend-key'
RECIPIENT_EMAIL='your-email@example.com'
Then start the services:
vela-startOpenAPI docs available at http://127.0.0.1:8765/docs.
Vela agents authenticate to the VPS relay using a secret token. Registration follows a two-step flow:
When you run vela-agent for the first time with no AGENT_SECRET, it performs a first-time registration:
# The agent sends a registration request with the agent_id
curl -X POST http://<vps-url>:8000/register \
-H "Content-Type: application/json" \
-d '{"agent_id": "my-agent", "public_address": "http://10.0.0.1:8080", "metadata": {"location": "home", "version": "1.0.0"}}'
# Response includes an agent secret that authenticates this agent going forward:
{
"agent": { ... },
"secret": "ubiuctIGyF_-d7hlIOcrNFBMR5x1CW3Mq-s7Nv5XkKA",
"ws_token": "LY6ggkkI3QU1G9_SeZIt4zrdHiuK6AOhi7kEF6iifis",
"expires_at": "2026-06-22T14:10:38Z"
}The secret is automatically saved to .env and used for all subsequent connections. The ws_token is used to establish the WebSocket tunnel.
On startup, the agent uses its stored AGENT_SECRET to request a fresh WebSocket token from the dedicated token endpoint β it does not re-register:
curl -X POST http://<vps-url>:8000/agents/<agent-id>/ws-token \
-H "X-Secret: <current-secret>"Vela uses two configuration sources:
config.yamlβ server settings (host, port, secret key, feature flags, etc.).envβ agent/credentials (VPS URL, agent secret, API keys, etc.)
host: 127.0.0.1
port: 8765
secret_key: <32+ character random string>
token_expire_minutes: 1440
username: admin
password_hash: <bcrypt hash>
log_level: INFO
allowed_origins: []
allowed_base_dirs:
- /home/youruser
# Rate limiting
rate_limit_default: 100/minute
route_rate_limits:
/auth/token: 10/minute
/ping: 60/minute
# Feature flags
feature_flags:
display: true
audio: true
power: true
notifications: true
network: true
filesystem: true
input_control: true
system_info: true
monitoring: true
processes: true
security: true
scheduler: true
maintenance: true
media: true
clipboard: true
# Fireworks AI assistant
fireworks_api_url: https://api.fireworks.ai/inference/v1
fireworks_api_key: <your-api-key>
fireworks_model: accounts/fireworks/models/qwen3p7-plus
assistant_system_prompt: "You are Vela..."
assistant_action_pin: null
assistant_action_timeout_seconds: 120
assistant_enable_thinking: falseSee .env.example for the full list. Key variables:
| Variable | Description |
|---|---|
VPS_URL |
VPS relay URL (e.g. http://your-vps:8000) |
AGENT_ID |
Unique agent identifier |
AGENT_SECRET |
Agent authentication secret (auto-generated on first registration) |
PUBLIC_ADDRESS |
Public address of this agent (optional, first registration) |
METADATA |
JSON metadata for agent registration (optional) |
FIREWORKS_API_KEY |
Fireworks AI API key for the LLM assistant |
RESEND_API_KEY |
Resend API key for email alerts |
RECIPIENT_EMAIL |
Email address for alert notifications |
SPOTIFY_CLIENT_ID |
Spotify Developer client ID |
SPOTIFY_CLIENT_SECRET |
Spotify Developer client secret |
POST /auth/tokenβ Login, returns JWT bearer tokenGET /auth/meβ Get current user
| Prefix | Description |
|---|---|
/filesystem |
Read/write files, list directories |
/audio |
Volume control, audio output switching |
/display |
Screen lock, display info |
/power |
Shutdown, reboot, suspend |
/notifications |
Send desktop notifications |
/network |
Network info, WiFi management |
/input_control |
Mouse/keyboard control |
/system_info |
OS, hardware, resource info |
/monitoring |
CPU, memory, disk monitoring |
/processes |
List/kill processes |
/security |
Screen lock, webcam control, login history |
/scheduler |
Task scheduling |
/maintenance |
System maintenance tasks |
/media |
Media playback control |
/clipboard |
Clipboard read/write |
/alerts |
Spike monitoring and email alerts |
/spotify |
Spotify playback and search |
POST /assistant/chatβ Natural language chat with LLM-powered tool callingPOST /assistant/streamβ Streaming (SSE) version of the chat endpoint
GET /β Root info (name, version, enabled modules)GET /healthβ Service health checkGET /pingβ Connectivity check
Vela includes a Fireworks AI-powered chat assistant at /assistant/chat. It uses Qwen models with tool-calling to map natural language to system operations.
curl -X POST http://127.0.0.1:8765/assistant/chat \
-H "Authorization: Bearer <jwt-token>" \
-H "Content-Type: application/json" \
-d '{"message": "How much storage do I have left?"}'The assistant:
- Parses natural language into intent
- Selects the appropriate system tool (filesystem, processes, etc.)
- Returns a human-readable response with the result
- Supports streaming responses via
/assistant/stream - Requires PIN confirmation for destructive actions (configurable)
- JWT authentication β all routes require a valid bearer token (except
/auth/token) - Rate limiting β auth endpoints limited to 10 req/min, default 150/min
- Filesystem whitelist β restrict directory access
- Destructive action confirmation β file deletion, power operations require explicit action confirmation
- Optional PIN gate β high-risk AI actions can require a PIN
vela/
βββ app/
β βββ __init__.py
β βββ main.py # FastAPI application entry point
β βββ auth.py # JWT authentication
β βββ dependencies.py # FastAPI dependencies
β βββ middleware.py # Request logging
β βββ prompts.py # Assistant system prompts
β βββ rate_limiter.py # Rate limiting setup
β βββ agent/
β β βββ __init__.py
β β βββ agent.py # VPS registration & WebSocket tunnel agent entry point
β β βββ helpers.py # Agent connection helpers
β β βββ tunnel.py # WebSocket tunnel implementation
β βββ db/
β β βββ __init__.py
β β βββ models.py # Database models
β β βββ pending_actions.py # Pending action storage
β βββ domain/ # Domain models (schemas)
β β βββ __init__.py
β β βββ assistant.py
β β βββ audio.py
β β βββ ...
β β βββ system_info.py
β βββ routers/ # System operation routers
β β βββ __init__.py
β β βββ filesystem.py
β β βββ audio.py
β β βββ ...
β β βββ system_info.py
β βββ services/ # Business logic
β β βββ __init__.py
β β βββ filesystem.py
β β βββ audio.py
β β βββ ...
β β βββ system_info.py
β β βββ assistant/ # LLM assistant service
β β βββ __init__.py
β β βββ helpers.py
β β βββ prompts.py
β β βββ safety.py
β β βββ stream.py
β β βββ tools.py
β βββ utils/
β βββ __init__.py
β βββ config.py # Configuration loading (pydantic-settings)
β βββ errors.py # Error response models
β βββ input_header.py # Input header helper
β βββ run_command.py # Shell command execution
β βββ spotify_client.py # Spotify API client
βββ tests/ # Test suite
β βββ routers/
β βββ services/
β βββ db/
βββ .env.example # Environment variable template
βββ config.yaml # Local configuration (generated)
βββ setup.sh # Setup script
βββ pyproject.toml # Python package metadata
βββ README.md
- Add a service file under
app/services/for business logic (if needed) - Add a router file under
app/routers/with endpoint definitions - Export the router in
app/routers/__init__.py - Add
feature_flagsentry inconfig.yamlif needed - Add a domain model in
app/domain/if new schemas are needed - Add tests under
tests/
python -m pytest