Skip to main content

SparkDeck Agent

Remote AI Command Center agent for NVIDIA DGX Spark.

A small FastAPI service that runs on the Spark and gives the SparkDeck iOS app GPU telemetry, Docker container control (start, stop, restart) and discovery of local LLM endpoints.

Install

From the SparkDeck app

Open the device in SparkDeck and use Agent Management > Install Agent. The app connects over SSH and:

  1. creates a virtualenv at ~/.sparkdeck-agent-venv,
  2. installs sparkdeck-agent from PyPI into it,
  3. enables lingering for your user and starts the agent as a systemd user service (sparkdeck-agent start --daemon),
  4. reads the auth token with sparkdeck-agent token.

Update Agent upgrades the package and restarts the service, Restart Agent restarts it, and Uninstall Agent removes the service and the virtualenv.

Manually

DGX OS does not allow system-wide pip install, so use a virtualenv. Create it at ~/.sparkdeck-agent-venv, the location the SparkDeck app looks in:

python3 -m venv ~/.sparkdeck-agent-venv
source ~/.sparkdeck-agent-venv/bin/activate
pip install sparkdeck-agent

# Keep user services running after you log out (once per machine)
loginctl enable-linger "$USER"

# Install and start the systemd user service
sparkdeck-agent start --daemon

Without --daemon, sparkdeck-agent start runs in the foreground. Use --port to override the port.

The app reads the auth token over SSH by running sparkdeck-agent token. You can print it yourself at any time:

sparkdeck-agent token

Command line

Command What it does
sparkdeck-agent start [--port N] [--daemon] Run in the foreground, or install and start the systemd user service
sparkdeck-agent stop Stop the service
sparkdeck-agent status Show version, configuration and service state
sparkdeck-agent token [--reset] Print the auth token, or generate a new one
sparkdeck-agent config Show the configuration values in effect

python -m sparkdeck_agent works as well.

Configuration

Settings are read from ~/.config/sparkdeck/config.toml. The file is parsed with Python's built-in tomllib, which needs Python 3.11 or newer; on older versions the defaults are used. A file that cannot be parsed, an unknown key and a value of the wrong type are each logged as a warning that names the file (for the service: journalctl --user -u sparkdeck-agent). An unknown key or a wrong value is ignored and the rest of the file still applies; a file that cannot be parsed means all the defaults, so the agent listens on every interface.

Key Default Meaning
host "0.0.0.0" Interface to listen on
port 8420 Port to listen on
log_level "info" uvicorn log level
gpu_poll_interval 1.0 Seconds between GPU samples on the WebSocket stream
discovery_ports [11434, 8000, 5000, 8080, 8081] Local ports scanned for LLM endpoints

Restart the service after editing the file: sparkdeck-agent stop && sparkdeck-agent start --daemon.

API

Every /api route requires Authorization: Bearer <token>. The WebSocket also accepts a legacy ?token= query parameter (see the security notes).

Route Description
GET /api/status Hostname, agent version, uptime, GPU, running containers, LLM endpoints
GET /api/gpu/metrics Current GPU metrics
WS /api/gpu/stream One JSON frame of GPU metrics per gpu_poll_interval; a bad token is rejected at the handshake
GET /api/containers All Docker containers
POST /api/containers/{id} Body {"action": "start"}, {"action": "stop"} or {"action": "restart"}
GET /api/models Discovered LLM endpoints
POST /api/chat/proxy OpenAI-style chat request forwarded to a local LLM
POST /api/notify/register Push notification registration (stub)

GPU metrics

The numeric fields (utilization, memory_used, memory_total, temperature, power_draw, fan_speed, memory_utilization) are never null. A value the GPU cannot report, such as fan speed on some systems, is sent as 0 and its field name is listed in unavailable, so clients can show "N/A" instead of a misleading zero. Memory is the exception: an unavailable memory reading is sent as memory_used = 0 and memory_total = 1 (the total stays positive), with "memory" in unavailable.

memory_kind is "unified" when NVML reports no GPU memory and the figures come from the system memory in /proc/meminfo (the case on a GB10), and "dedicated" otherwise.

Token and security notes

  • Treat the token like a password. Anyone who has it can start, stop and restart the Docker containers the agent can reach and use the agent as a proxy to your local LLMs. It is stored in ~/.config/sparkdeck/token (mode 0600); do not paste it into chats, tickets or logs.
  • Reset a token with sparkdeck-agent token --reset. The running agent re-reads the token file whenever it changes, so the old token is rejected from the next request on and no restart is needed. WebSocket streams opened with the old token are closed (code 4001) within one poll interval. The SparkDeck app (1.0.1 and later) refreshes the token automatically over SSH: when the agent rejects its saved token (HTTP 401), the dashboard runs sparkdeck-agent token over SSH, saves the new token and retries once. Agent Management shows Token rejected with a Refresh Token button that does the same. Other clients that cached the old token need the new one.
  • The agent speaks plain HTTP and listens on all interfaces by default. Use it on a trusted network such as your LAN or Tailscale, and never expose port 8420 to the internet. To narrow it, set host in config.toml, for example your Tailscale address (host = "100.101.102.103"). 127.0.0.1 makes the agent reachable only from the Spark itself, so the app cannot connect. sparkdeck-agent config shows the value in effect.
  • WebSocket authentication. Send the token as Authorization: Bearer <token>. The older ?token=<token> query parameter is still accepted for existing app versions, but prefer the header: URLs end up in logs and proxies. The agent masks token=... and Bearer ... values in uvicorn's log output.
  • No API docs. /docs, /redoc and /openapi.json are disabled, so the API surface is not published to anyone who reaches the port.

Development

pip install -e ".[dev]"
pytest

Metadata

Release files for sparkdeck-agent 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sparkdeck-agent 0.1.2
File Size Uploaded Provenance
sparkdeck_agent-0.1.2.tar.gz 31.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for sparkdeck-agent 0.1.2
File Interpreter ABI Platform
sparkdeck_agent-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 55.2 kB

Release files / sparkdeck_agent-0.1.2.tar.gz

Download URL sparkdeck_agent-0.1.2.tar.gz
Size 31.9 kB
Tags Source
SHA-256 checksum
How to use checksums
e9dec7982c8de669e455a85ea1a6e45d137106cb05eb310232fb28b366f7ce81
BLAKE2b-256 checksum
How to use checksums
867a4319085375be004e19227d0e794b4396c48c059f1835a1f957a47c50d96d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Release files / sparkdeck_agent-0.1.2-py3-none-any.whl

Download URL sparkdeck_agent-0.1.2-py3-none-any.whl
Size 23.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
699df918c3f68695cae89eaa632d3ee8b58d25c7b38db412840bad37245f20d7
BLAKE2b-256 checksum
How to use checksums
2241f37cbe05d3e2608daf257735d4f09d02ce8d5fc66f28f8c37cc715eed02c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Security for sparkdeck-agent 0.1.2

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.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page