Port of ../elprice/deploy-citadel.sh: build the image locally for the remote's architecture, ship it over SSH with docker save | docker load, and run docker compose up -d --no-build in /home/pmp/apps/btcprice. The deployment compose is standalone rather than joining btc-network, because citadel runs no btcdata — BTCDATA_URL points at the instance already running on omarchy (http://192.168.50.42:4102). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BdMTk61JgUdNH86ttMi4ce
btcprice
Bitcoin price tracker UI. Serves an HTML page with live price updates streamed from btcdata, which this server proxies over WebSocket and renders as HTML fragments for HTMX.
Quick Start
# Start btcdata first (provides price data)
cd ../btcdata && make run
# Local dev — creates .venv and installs requirements on first run
make run # starts on port 4000
make tailwind # watch Tailwind CSS (separate terminal)
Optionally cp .env.example .env to override BTCDATA_URL; without it the code default
(http://localhost:4100) applies. make run-local requires a .env defining
BTCDATA_LOCAL_URL.
Docker
docker compose up -d starts btcprice only — it does not bring up btcdata. Both compose
files attach to the external btc-network, so create it once and start btcdata separately:
docker network create btc-network # once
cd ../btcdata && docker compose up -d
cd ../btcprice && docker compose up -d
| Service | Local dev | Docker |
|---|---|---|
| btcprice | localhost:4000 | localhost:4041 (container port 4040) |
| btcdata | localhost:4100 | localhost:4102 |
Inside btc-network, btcprice reaches btcdata as http://btcdata:4102.
Deployment (citadel)
./deploy-citadel.sh
Same method as ../elprice/deploy-citadel.sh: builds the image locally for the target's
architecture (citadel is x86_64 → linux/amd64), copies docker-compose.citadel.yml and
.env.citadel to /home/pmp/apps/btcprice on the host as docker-compose.yml / .env,
pipes the image over SSH with docker save | docker load, and runs
docker compose up -d --no-build. No registry involved.
Deployed btcprice listens on http://192.168.50.195:4041 and proxies to the btcdata already
running on omarchy (http://192.168.50.42:4102, set via BTCDATA_URL in .env.citadel) —
citadel runs no btcdata of its own, so the deployment compose is standalone with no
btc-network.
Overridable: BTCPRICE_DEPLOY_HOST, BTCPRICE_DEPLOY_DIR, BTCPRICE_IMAGE_NAME,
BTCPRICE_PLATFORM.
Environment Variables
| Variable | Default | Description |
|---|---|---|
BTCDATA_URL |
http://localhost:4100 |
btcdata service URL the server proxies to |
BTCDATA_LOCAL_URL |
— | Used by make run-local instead of BTCDATA_URL |
DOCKER_BTCDATA_PORT |
4102 |
btcdata's port inside btc-network (local compose only) |
BTCPRICE_PORT |
4041 |
Host port in the citadel deployment (.env.citadel) |
The HTTP port is not configurable via environment: make run hardcodes 4000 and the Docker
image's CMD hardcodes 4040.
How It Works
The browser loads a page with HTMX and the WebSocket extension, which connects back to
btcprice at /ws/price and /ws/strike — the browser never contacts btcdata directly.
Each of those endpoints opens an upstream WebSocket to btcdata (/api/price/ws and
/api/strike/ws), converts each JSON message to an HTML fragment (price_json_to_html,
strike_json_to_html), and forwards it to the browser. HTMX swaps the received
<div id="price-display"> / <div id="strike-display"> into the DOM. Price changes are
color-coded (green up, red down). Reconnection is handled by HTMX.
Tech Stack
Python · FastAPI · Uvicorn · websockets · HTMX · Tailwind CSS v4
The Clojure implementation this replaced is on the clojure branch.