Experience lifecycle manager handling the full journey from draft through live deployment to retirement.
| Server | hydraexperiencelibrary.experiencenet.com (Incus scale on pi-node-004-nvme, behind the edge router) |
| hcloud | hydraexperiencenet context, cx23 nbg1 |
| Config | /root/.hydraexperiencelibrary/config.yaml |
| Data | /root/.hydraexperiencelibrary/ |
| Service | systemctl status hydraexperiencelibrary |
| Logs | journalctl -u hydraexperiencelibrary -f |
| Health | GET /api/v1/health |
# via hydracluster exec on node-50ab5309
incus exec hydraexperiencelibrary -- systemctl status hydraexperiencelibrary
Or via the health endpoint:
curl -s https://hydraexperiencelibrary.experiencenet.com/api/v1/health
# via hydracluster exec on node-50ab5309
incus exec hydraexperiencelibrary -- journalctl -u hydraexperiencelibrary -n 100 --no-pager
Show last 100 lines:
# via hydracluster exec on node-50ab5309
incus exec hydraexperiencelibrary -- journalctl -u hydraexperiencelibrary -n 100 --no-pager
The service runs as the Incus scale hydraexperiencelibrary on
pi-node-004-nvme (node-50ab5309), behind the edge router. The old host
46.225.120.6 is gone; its IP was recycled and belongs to a foreign
machine now. Never ssh there.
# via hydracluster exec on node-50ab5309
incus restart hydraexperiencelibrary
A scale has no self-update path: the image is the unit of update. Tag + push triggers CI, which publishes the OCI image. Then rebuild the scale (via hydracluster exec on node-50ab5309):
hydraskin update hydraexperiencelibrary # dry run
hydraskin update hydraexperiencelibrary --apply # rebuild onto the new image
The rebuild preserves state disks, the expose proxy and labels, and verifies /api/v1/health afterward (verified 2026-08-26, v0.10.6 to v0.10.7 in 12 s).
Creates a new experience in draft state:
curl -X POST https://hydraexperiencelibrary.experiencenet.com/api/v1/experiences \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"name": "Experience Name",
"organization_id": "<organization-id>",
"description": "Description of the experience"
}'
curl -s https://hydraexperiencelibrary.experiencenet.com/api/v1/experiences \
-H "Authorization: Bearer <token>" | jq .
Move an experience to the next lifecycle state (e.g., draft to staging, staging to live):
curl -X POST https://hydraexperiencelibrary.experiencenet.com/api/v1/experiences/<id>/promote \
-H "Authorization: Bearer <token>"
Pause a live experience (can be resumed later):
curl -X POST https://hydraexperiencelibrary.experiencenet.com/api/v1/experiences/<id>/pause \
-H "Authorization: Bearer <token>"
Roll back an experience to a previous build version:
curl -X POST https://hydraexperiencelibrary.experiencenet.com/api/v1/experiences/<id>/rollback \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"target_version": "<version>"
}'
Permanently retire an experience (terminal state):
curl -X POST https://hydraexperiencelibrary.experiencenet.com/api/v1/experiences/<id>/retire \
-H "Authorization: Bearer <token>"
Returns all experiences with status live, a production build, and a non-empty build URL. Used by hydrabody to discover which experience builds to download. Supports optional district and venue query parameters to filter by location:
# All live experiences
curl -s https://hydraexperiencelibrary.experiencenet.com/api/v1/experiences/live \
-H "Authorization: Bearer <token>" | jq .
# Live experiences for a specific venue
curl -s "https://hydraexperiencelibrary.experiencenet.com/api/v1/experiences/live?district=brussels&venue=mercator-hall" \
-H "Authorization: Bearer <token>" | jq .
Response fields:
| Field | Notes |
|---|---|
name |
Experience identifier (slug) |
label |
Human-readable display name (omitted if empty) |
build_number |
Production build number |
build_url |
Download URL for the build ZIP |
exe_path |
Path to the executable on body machines |
orientation |
portrait or landscape (omitted if landscape) |
enable_microphone |
true if the experience uses voice input via hydravoice (omitted if false) |
[
{"name": "rupelmonde-castle-viewer", "build_number": 1, "build_url": "https://releases.experiencenet.com/builds/...", "exe_path": "C:\\experiences\\rupelmonde-castle-viewer\\Rupelmonde.exe"}
]
Returns a URL to hydraheadwebstream for browser streaming of the given experience:
curl -X POST https://hydraexperiencelibrary.experiencenet.com/api/v1/experiences/<name>/stream \
-H "Authorization: Bearer <token>"
Response:
{
"stream_url": "https://hydraheadwebstream.experiencenet.com/?experience=<name>"
}
Requires hydraheadwebstream_url to be configured.
End-to-end health check of the entire deployment pipeline: hydraperforce, hydrarelease, hydradistrict, hydracluster, hydramirror, and local experience status. Supports filtering by district and experience name.
# Full pipeline health for a district and experience
curl -s https://hydraexperiencelibrary.experiencenet.com/api/v1/pipeline/health?district=bxl1-test\&experience=mercator-talks \
-H "Authorization: Bearer <token>" | jq .
# District-only check
curl -s https://hydraexperiencelibrary.experiencenet.com/api/v1/pipeline/health?district=bxl1-test \
-H "Authorization: Bearer <token>" | jq .
# Full pipeline check (all experiences, no district filtering)
curl -s https://hydraexperiencelibrary.experiencenet.com/api/v1/pipeline/health \
-H "Authorization: Bearer <token>" | jq .
Requires the pipeline config section:
pipeline:
hydraperforce_url: "https://hydraperforce.experiencenet.com"
hydrarelease_url: "https://releases.experiencenet.com"
hydradistrict_url: "https://hydradistrict.experiencenet.com"
hydramirror_url_pattern: "https://{district}.hydramirror.experiencenet.com"
draft -> staging -> live -> paused -> retired. Promotion moves forward, rollback reverts to a previous build version. Paused experiences can be resumed to live. Retired is a terminal state./root/.hydraexperiencelibrary/. Each experience file tracks its current state, build version history, and metadata. No database required.hydraheadwebstream_url config field enables stream links. Stream buttons redirect to hydraheadwebstream, which manages its own streaming sessions (moonlight-web-stream instances, Sunshine pairing, WebRTC).orientation: portrait to stream in portrait mode (e.g. 720x1280). The field is exposed via the REST API and consumed by hydraheadwebstream, which passes it to hydraneckwebrtc. Default is landscape (empty or "landscape").release_channel field in hydracluster. Staging promotions only reach nodes with release_channel="staging". Production promotions reach all other nodes (default = production). This allows testing new builds on specific nodes before rolling out to the full fleet.-test (e.g. bxl1-test) share infrastructure with their base district (bxl1). The pipeline health check resolves mirrors via the base district. Test district nodes are invisible to production consumers (e.g. hydraheadwebstream querying eligible bodies in bxl1).If the YAML store becomes corrupted (partial writes, disk issues):
systemctl stop hydraexperiencelibraryls -la /root/.hydraexperiencelibrary/systemctl start hydraexperiencelibraryjournalctl -u hydraexperiencelibrary -n 50 --no-pagercat /root/.hydraexperiencelibrary/config.yamlss -tlnp | grep <port>ls -la $(which hydraexperiencelibrary)hydraexperiencelibrary servecurl -s https://hydraauth.experiencenet.com/api/v1/verify -H "Authorization: Bearer <token>"incus exec hydraexperiencelibrary -- curl -s https://hydraauth.experiencenet.com/api/v1/health (via exec on node-50ab5309)incus exec hydraexperiencelibrary -- date -- token validation may fail if the clock is skewed/root/.hydraexperiencelibrary/ for the current statejournalctl -u hydraexperiencelibrary --since "1 hour ago" | grep <experience-id>curl -s https://hydrarelease.experiencenet.com/api/v1/healthincus exec hydraexperiencelibrary -- curl -s https://hydrarelease.experiencenet.com/api/v1/healthOBSOLETE: the Hetzner snapshot arrangement covered the retired dedicated server. The scale's state lives as a host disk device on pi-node-004-nvme and survives image rebuilds; a scale-level backup policy is an open item.
The snapshot covers the entire server disk, including all experience and build records.
hydraexperiencenet project), open Servers → hydraexperiencelibrary → Backups.curl https://hydraexperiencelibrary.experiencenet.com/api/v1/health