Vela RemotePC Agent
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.
New here? Read How it works first for the mental model (API vs agent, tunnel, auth, config). Then come back here for setup.
Features
- Full system control API: filesystem, audio, display, power, notifications, network, input control, system info, monitoring, processes, security, scheduler, maintenance, media, clipboard, Spotify, alerts, docker, push
- 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 onboarding: browser-based QR pairing with code/PIN fallback
- 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
How it works (summary)
Vela runs as two processes:
| Process | Role |
|---|---|
Vela API (vela.service) |
Local FastAPI server that executes desktop operations |
Vela Agent (vela-agent.service) |
Outbound WebSocket tunnel to your VPS; forwards phone requests to the API |
Your phone -> VPS relay -> agent tunnel -> 127.0.0.1:8765 -> Linux.
The optional assistant uses the same API: an LLM picks tools, Vela runs them, the LLM summarizes.
Full explanation (flows, auth layers, pairing, config paths, code map): doc/HOW_IT_WORKS.md
Quick Start
Prerequisites
System Requirements
- Python 3.13+
- Linux desktop (X11 or Wayland)
Required System Packages
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.
Optional Dependencies
- 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)
Setup
From source:
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.sh
If Vela is installed globally (for example via pip), run:
pip install mikesplore-vela
vela --setup
This will:
- Wipe cached local auth tokens and relay credentials (fresh start)
- Prompt for credentials, VPS URL, and agent label
- Generate a
config.yamland fresh.env(empty relay secrets until pairing) - Verify the VPS relay is reachable
- Force pairing, then restart
vela.serviceandvela-agent.serviceso only the new credentials are used
VPS relay: You can use the free relay at
vela.mikesplore.techor specify your own.
./setup.shalso creates a virtual environment and installs Vela from the current source tree. A globally installedvela --setuponly runs setup.Setup links
velaandvela-agentinto~/.local/binso the commands work outside the virtualenv (as long as that directory is on yourPATH).
Post-Setup
Optional integrations (Fireworks, Resend, Spotify) can be filled during vela --setup.
If you skipped them, edit the live credentials file afterward:
vela --env
At minimum, set your Fireworks AI API key if you want 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 manage services with:
vela --enable
OpenAPI docs available at http://127.0.0.1:8765/docs.
Operations dashboard (request audit, latency median/p95, recent errors) is at
http://127.0.0.1:8765/admin/dashboard: sign in with the same username/password as the API.
p95 means the 95th percentile latency: 95% of requests finished at or under that time. It is better than average for spotting slow outliers without being dominated by a single worst request.
Common commands:
vela --setup
vela --start
vela --stop
vela --restart
vela --status
vela --logs
vela --dashboard
vela --env
vela --mcp
vela-agent --start
vela-agent --stop
vela --setupis the only onboarding path. It always starts fresh (no credential reuse).vela --envopens the.envfile your services actually load (may differ from the repo copy).vela --mcpprints the MCP connection link and relay secret for use with Claude/Cline. After editing credentials, runvela --restartso both services reload the new values.
Agent Registration
Vela uses pairing-based onboarding (2026-07-pairing-v1). The agent always initiates outbound requests; VPS never initiates to the device.
1) Start pairing session
Agent calls POST /agents/register/start:
curl -X POST http://<vps-url>:8000/agents/register/start \
-H "Content-Type: application/json" \
-d '{"agent_name":"my-agent","device_info":{"device_fingerprint":"host:user"}}'
VPS returns agent_id, pairing_code, optional pairing_pin, and pairing_expires_in.
The agent creates the QR payload locally from the VPS URL, pairing code, and optional PIN, then shows it with a manual code/PIN fallback.
2) Android completes pair
Android app sends:
curl -X POST http://<vps-url>:8000/pair/complete \
-H "Content-Type: application/json" \
-d '{"pairing_code":"<code>","pairing_pin":"<pin>","agent_label":"My Phone"}'
Agent polls GET /agents/register/status?agent_id=... until it gets PAIRED + activation_token, then immediately calls activation. If activation reports an invalid token, the agent fetches status once and retries activation once with the returned token before it requests a new pairing session.
3) Agent activates
curl -X POST http://<vps-url>:8000/agents/register/activate \
-H "Content-Type: application/json" \
-d '{"agent_id":"<agent-id>","activation_token":"<one-time-token>"}'
VPS returns relay_secret, credential, and scopes.
Agent persists:
RELAY_SECRET(primary secret for VPS auth)AGENT_CREDENTIAL(returned credential)AGENT_ID
4) Runtime reconnect
On normal reconnect:
curl -X POST http://<vps-url>:8000/agents/<agent-id>/ws-token \
-H "X-Secret: <relay-secret>"
Then agent connects ws(s)://<vps>/tunnel?agent_id=<id>&token=<ws_token>.
Configuration
Vela uses two configuration sources:
config.yaml: server settings (host, port, secret key, feature flags, etc.).env: agent credentials/secrets (RELAY_SECRET,AGENT_CREDENTIAL, API keys, etc.)
config.yaml
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/deepseek-v4-flash
assistant_system_prompt: "You are Vela..."
assistant_action_pin: null
assistant_action_timeout_seconds: 120
assistant_enable_thinking: false
Environment variables (.env)
See .env.example for the full list. Key variables:
| Variable | Description |
|---|---|
VPS_URL |
VPS relay URL (e.g. http://your-vps:8000) |
AGENT_ID |
VPS-issued agent identifier after pairing |
RELAY_SECRET |
Primary long-lived secret used as X-Secret for relay auth |
AGENT_CREDENTIAL |
Agent activation credential returned by /agents/register/activate |
AGENT_SECRET |
Backward-compatible alias (currently mirrors RELAY_SECRET) |
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 |
MCP_SERVER_URL |
Public URL of the vela-mcp server (e.g. https://mcp.mikesplore.tech). Used by vela --mcp to build the ready-to-paste MCP link |
API Endpoints
Authentication
POST /auth/token: Login, returns JWT bearer tokenGET /auth/me: Get current user
System Routers
| Prefix | Description |
|---|---|
/fs |
Read/write files, list directories, disk usage |
/audio |
Volume control, audio output switching |
/display |
Screen lock, display info, brightness, screenshots |
/power |
Shutdown, reboot, suspend, power profile |
/notifications |
Send desktop notifications |
/network |
Network info, WiFi management, bluetooth, ping |
/input |
Mouse/keyboard control |
/system |
OS, hardware, resource info |
/monitor |
CPU, memory, disk monitoring |
/processes |
List/kill processes, open/close apps |
/security |
Screen lock, webcam control, login history |
/scheduler |
Task scheduling |
/maintenance |
System maintenance tasks, services, timers |
/media |
Media playback control |
/clipboard |
Clipboard read/write |
/alerts |
Spike monitoring and email alerts |
/spotify |
Spotify playback and search |
/docker |
Docker daemon info, containers, logs, compose |
/push |
FCM device registration + send (via VPS relay) |
/capabilities |
Runtime capability probes and tool availability |
/admin |
Audit dashboard/events |
Assistant
POST /assistant/chat: Natural language chat with LLM-powered tool callingPOST /assistant/stream: Streaming (SSE) version of the chat endpoint
Health
GET /: Root info (name, version, enabled modules)GET /health: Service health checkGET /ping: Connectivity check
Assistant (LLM Integration)
Vela includes a Fireworks AI-powered chat assistant at /assistant/chat. It uses a Fireworks-hosted model (default deepseek-v4-flash) 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)
Security
- 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
Development
Project Structure
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 # Agent CLI entry point
│ │ ├── helpers.py # Re-exports for compatibility
│ │ ├── local_auth.py # Local API JWT for tunnel forwarding
│ │ ├── pairing.py # Relay pairing / activation
│ │ ├── credentials.py # Relay credential persistence
│ │ ├── loop.py # Agent reconnect loop
│ │ ├── envutil.py # Shared agent env helpers
│ │ └── tunnel.py # WebSocket tunnel implementation
│ ├── setup/ # Fresh-start setup (wipe, write config, pair, restart)
│ ├── ui/ # Browser pairing + setup wizard pages
│ ├── cli.py # Service management CLI (vela --start/--restart/...)
│ ├── db/
│ │ ├── __init__.py
│ │ ├── models.py # Database models
│ │ ├── audit_log.py # Audit log storage
│ │ ├── capabilities.py # Capability probe persistence
│ │ └── 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
│ │ ├── registry.py # Capability-gated router loading
│ │ ├── capabilities.py
│ │ ├── admin.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 # Fireworks/LLM planning + streaming
│ │ ├── session.py # Chat session store
│ │ ├── tool_exec.py # Tool call execution against local API
│ │ ├── tools.py # Tool registry definitions
│ │ ├── gatekeeper_tools.py # Gatekeeper tool definitions
│ │ ├── workflow.py # Tool execution stages
│ │ ├── images.py # Image payload handling
│ │ ├── safety.py
│ │ ├── stream.py
│ │ └── prompts.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
Adding a Route
- 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/
Running Tests
python -m pytest
License
Metadata
Release files for mikesplore-vela 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| mikesplore_vela-1.0.0.tar.gz | 243.9 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mikesplore_vela-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 493.8 kB
Release files / mikesplore_vela-1.0.0.tar.gz
| Download URL | mikesplore_vela-1.0.0.tar.gz |
|---|---|
| Size | 243.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9e71d9c5f57c2117e87826755d6da3ae54bdf060210adf119c43e479882dee39
|
|
BLAKE2b-256 checksum How to use checksums |
ce0f1217fa6903eaf82b1a1a6d5b2d2d6e4deacdcd85288e5f6ef8c9b298b350
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / mikesplore_vela-1.0.0-py3-none-any.whl
| Download URL | mikesplore_vela-1.0.0-py3-none-any.whl |
|---|---|
| Size | 249.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
71aef7f26542ad270d7606169b02e768c787effc78dd696bfef21cf1be937e32
|
|
BLAKE2b-256 checksum How to use checksums |
f4c19f87d2e0d71f384dc60f30ce1542d9b0da1166662c8ca314cd74f3e47414
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Security for mikesplore-vela 1.0.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.