Skip to content

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

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 ./data inside the container; it resolves to /app/data.
  • Current images can remap the known /app/data default and recover leftovers when /data is empty, but explicit /data is still the safe configuration.
  • Older images without that remapping can lose /app/data when the container is recreated.

Docker Compose with a published image

Create a directory for the deployment:

mkdir adhd-hub
cd adhd-hub

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:

python -c "import secrets; print(secrets.token_urlsafe(32))"

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:

docker compose up -d
docker compose logs -f adhd-hub
curl -fsS http://127.0.0.1:8787/api/health

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:

ports:
  - "9000:8787"

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:

adhd-hub mcp-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:

uv tool install "git+https://github.com/uniskela/adhd-hub.git"

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:

  1. process environment variables;
  2. the first non-empty TOML config found from --config, ./config.toml, then ~/.config/adhd-hub/config.toml;
  3. ./.env;
  4. 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:

git pull --ff-only
docker compose up -d --build

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.