Install ADHD Progress Hub¶
ADHD Progress Hub is a self-hosted server.
Recommended: use Docker Compose with a published image for a persistent home server or VPS. Use source + uv for development, or install only the CLI on machines that connect to an existing Hub.
Pick an install path¶
- New persistent server: use Docker Compose with a published image.
- Developing ADHD Hub itself: use the repository Compose file or source +
uv. - Simple single container: use
docker run. - Client machine only: install the CLI, then follow Connect.
- Local subprocess MCP only: use
adhd-hub mcp-stdio.
Choose an install method¶
| Method | Best for | Updates |
|---|---|---|
| Docker Compose + published image | Recommended self-hosted server | docker compose pull && docker compose up -d |
| Docker Compose + local build | Developing an unreleased checkout | Rebuild from the checkout |
docker run |
Small/simple container deployments | Pull and recreate the container |
Source + uv |
Development or non-container server | Pull source, uv sync, restart |
adhd-hub mcp-stdio |
Local subprocess MCP clients / inspectors | Update the installed CLI or source checkout |
uv tool install |
Client CLI only | Re-run with --upgrade |
Already have a Hub running? Client machines can use the Hub’s /install.sh or /install.ps1 instead of installing the server. If uv is missing, the scripts ask before using Astral’s official installer; non-interactive installs require ADHD_HUB_INSTALL_UV=1. See Connect.
Persist /data
In the container image, Hub state lives under /data. Mount a named volume or bind mount there before you rely on the Hub. Without persistent storage, container recreation can remove threads, wiki files, preferences, sessions, and local configuration.
What lives under /data¶
| Path | Contents |
|---|---|
hub.sqlite3 |
Projects (including tags), threads, progress notes, AI scan-line cache, meta |
ai.json |
AI scan-line / Settings → AI helpers (API key encrypted with ADHD_HUB_AUTH_TOKEN) |
prefs.json |
Dashboard preferences (timezone, etc.) |
forge.json / openclaw.json |
Optional forge / OpenClaw config |
wiki/ |
Local markdown wiki / progress files |
browser_sessions.sqlite3 / connect.sqlite3 |
Browser sessions and CLI connect grants |
Keep all of these paths on the same mounted volume.
Container persistence rules:
- Set
ADHD_HUB_DATA_DIR=/data. - Mount a named volume or host directory at
/data. - Do not rely on relative
./datainside the container; it resolves to/app/data. - Current images can remap the known
/app/datadefault and recover leftovers when/datais empty, but explicit/datais still the safe configuration. - Older images without that remapping can lose
/app/datawhen the container is recreated.
Docker Compose with a published image¶
Create a directory for the deployment:
Create .env with at least a strong server token:
ADHD_HUB_AUTH_TOKEN=replace-with-a-long-random-value
# Set this when browsers/agents reach the Hub through another hostname or URL:
# ADHD_HUB_PUBLIC_URL=https://adhd-hub.example.com
Generate a token with Python if needed:
Create compose.yml:
services:
adhd-hub:
image: ghcr.io/uniskela/adhd-hub:latest
container_name: adhd-hub
restart: unless-stopped
ports:
- "8787:8787"
env_file:
- .env
environment:
ADHD_HUB_HOST: "0.0.0.0"
ADHD_HUB_PORT: "8787"
# Absolute /data only — must match the volume mount. Do not use ./data here.
ADHD_HUB_DATA_DIR: /data
volumes:
# Named volume survives image upgrades. Avoid `docker compose down -v`.
- adhd_hub_data:/data
# Bind-mount alternative (host folder you control):
# - ./hub-data:/data
volumes:
adhd_hub_data:
Keep the Compose project directory name (and COMPOSE_PROJECT_NAME if set) stable — renaming it creates a new empty volume and looks like data loss.
The same release tags are also published as docker.io/uniskela/adhd-hub. Release images are available as latest, X.Y.Z, and X.Y. Pin an X.Y.Z tag if you want upgrades to happen only when you deliberately change the image tag.
Start the Hub and check it:
Then open http://<host>:8787/ui/. Sign in with ADHD_HUB_AUTH_TOKEN for initial setup/recovery and create a dashboard password for normal browser use. See Authentication.
Host port versus container port¶
The Compose environment: block above deliberately pins the container to 0.0.0.0:8787 and /data. Values in environment: override the same names from env_file.
To expose the Hub on host port 9000, change only the port mapping:
Do not set ADHD_HUB_PORT=9000 in .env while the Compose file still overrides it to 8787.
Use the repository Compose file¶
The repository's docker-compose.yml is convenient when you cloned the source tree. It contains build: ., so it builds the current checkout and tags that local build with the current project version.
git clone https://github.com/uniskela/adhd-hub.git
cd adhd-hub
cp .env.example .env
# Edit ADHD_HUB_AUTH_TOKEN before exposing the service.
docker compose up -d --build
For Cloudflare Tunnel (Hub on the Compose network only, no host 8787 publish), uncomment the commented cloudflared service in docker-compose.yml and follow Remote MCP access.
For a normal server that should consume released images without a source checkout, prefer the published-image Compose example above.
Plain docker run¶
A named volume provides the same persistent /data storage:
docker volume create adhd_hub_data
docker run -d \
--name adhd-hub \
--restart unless-stopped \
-p 8787:8787 \
--env-file .env \
-e ADHD_HUB_HOST=0.0.0.0 \
-e ADHD_HUB_PORT=8787 \
-e ADHD_HUB_DATA_DIR=/data \
-v adhd_hub_data:/data \
ghcr.io/uniskela/adhd-hub:latest
Run the server from source with uv¶
Python 3.12 or newer is required. ADHD Hub is not currently published on PyPI.
git clone https://github.com/uniskela/adhd-hub.git
cd adhd-hub
cp .env.example .env
# Edit ADHD_HUB_AUTH_TOKEN.
uv sync
uv run adhd-hub serve --host 127.0.0.1 --port 8787
Use 127.0.0.1 for a local-only server. If you deliberately bind outside loopback, set a strong token first and use a trusted private network or HTTPS reverse proxy.
Optional local stdio MCP process¶
If the coding agent or MCP inspector can launch a local subprocess, run the Hub tool catalog directly over stdio:
This loads the normal Hub settings and ADHD_HUB_DATA_DIR, so tools persist to the same kind of SQLite/Markdown store as the HTTP server. Stdio does not start the REST API, dashboard, OAuth endpoints, or background scheduler, and it does not use an HTTP bearer header. Treat it as a local single-process alternative, not a replacement for the persistent Docker/serve deployment when you need remote access, UI, scheduled reminders, or OpenClaw jobs.
See Connect for MCP client snippets.
Install only the client CLI¶
Machines that connect Cursor/Codex/Claude to an already-running Hub do not need to run the server. Install the CLI from GitHub:
Or use the Hub's Connect one-liner, which prefers a wheel served by the running Hub and falls back to GitHub. adhd-hub is not currently on PyPI.
Configuration¶
All server settings use the ADHD_HUB_ prefix. Start with .env.example, then use the Environment variables reference for every supported setting and its default.
Settings precedence is:
- process environment variables;
- the first non-empty TOML config found from
--config,./config.toml, then~/.config/adhd-hub/config.toml; ./.env;- built-in defaults.
For Docker Compose, remember that a service's explicit environment: entries override values loaded through env_file.
Reverse proxy, HTTPS, and Tailscale¶
When browsers or agents reach the Hub through another URL, set ADHD_HUB_PUBLIC_URL to that external base URL. This is also used for MCP OAuth discovery.
Behind Caddy, nginx, Tailscale Serve, or another trusted TLS terminator:
ADHD_HUB_PUBLIC_URL=https://adhd-hub.example.com
ADHD_HUB_TRUST_PROXY_HEADERS=true
# Optional if you want to force Secure cookies:
# ADHD_HUB_COOKIE_SECURE=true
Only trust forwarded headers from a proxy you control. For a Proxmox/Tailscale layout, migration instructions, and homelab-specific networking, see Homelab deployment. To expose Hub MCP to Cursor Cloud (or similar) via Cloudflare Tunnel — including the commented Compose cloudflared opt-in — see Remote MCP access.
Connect coding agents after the server is running¶
Open Settings → Coding agents and copy the generated command, or run the CLI directly:
adhd-hub connect /path/to/project \
--hub http://<hub-host>:8787 \
--agents cursor,codex,claude
adhd-hub doctor \
--hub http://<hub-host>:8787 \
--project /path/to/project
See Connect a machine or project for browser login, MCP OAuth, skills, agent selection, and doctor output.
Upgrade a container install¶
With a published image:
docker compose pull
docker compose up -d
docker compose logs --tail=100 adhd-hub
curl -fsS http://127.0.0.1:8787/api/health
A named/bind-mounted /data volume survives container replacement. Do not remove that volume during a normal upgrade (docker compose down is fine; down -v is not).
Verify the mount after upgrading:
docker compose exec adhd-hub ls -la /data
# Expect hub.sqlite3; ai.json appears after you save AI settings in /ui.
curl -fsS http://127.0.0.1:8787/api/health
# health.data_dir should be "/data" and health.data_dir_populated true once used.
If tags or AI settings vanished after an upgrade, check whether Hub was writing to ephemeral /app/data (relative ADHD_HUB_DATA_DIR) instead of the volume. Current images remap relative paths to /data and will copy leftover /app/data into the volume when /data is empty. Keep ADHD_HUB_AUTH_TOKEN stable — changing it does not delete ai.json, but the stored API key can no longer be decrypted until you re-enter it in Settings.
For a local-build checkout:
The repository Compose file tags a local image (adhd-hub:X.Y.Z). docker compose pull does not refresh that local tag — use --build, or switch to the published-image Compose example above for pull-based upgrades.
Back up before important changes¶
Use Settings → Your data → Download backup or the CLI export before a major upgrade/migration. Keep /data persistent and backed up as well. The Homelab deployment guide covers a full instance migration and encrypted exports.