Skip to content

feat(hub): services-index landing page at /#42

Merged
growlf merged 1 commit into
mainfrom
feat/hub-page-medium
May 21, 2026
Merged

feat(hub): services-index landing page at /#42
growlf merged 1 commit into
mainfrom
feat/hub-page-medium

Conversation

@growlf
Copy link
Copy Markdown
Owner

@growlf growlf commented May 21, 2026

Closes the operator-friction Garth flagged: "a single entry point that links all of our resource pages on these deployments into a single web UI for easier access by humans. Memorizing all of the ports and manually typing them all in is tedious."

What changed

New: shepherd/ui/hub.html

Landing page rendered at GET / on shepherd-control (port 40117). Three sections:

  1. Quick-link cards for every service on this host:

    • Shepherd herd (this app's /herd dashboard) → :40117/herd
    • Olla federation + load-balancer → :40114/
    • Smart Router gestalt UI → :40115/gestalt/ui
    • LiteLLM admin UI → :4000/ui
    • Retriever health → :42000/health
    • Ollama API → :11434/api/tags

    Each card shows: emoji + name + short description, live up/down
    status badge (refreshed every 15s), port number, and an Open ↗ link.

    Auto-discovers the host hostname from window.location, so links
    work from localhost, LAN IP, mesh hostname, or VPN-routed access —
    no template substitution required.

  2. Live status banner: 'N / M services up' (refreshes with the cards).

  3. Documentation + hardware guides section linking to:

    • README, Troubleshooting, Retriever guide
    • Intel iGPU Vulkan guide + per-hardware docs index
    • growlf/intel_nuc_skullcanyon_ollama_with_gpu standalone repo (per Garth's per-hardware-target OSS-repo doctrine)
    • ai-stack GitHub repo + open issues + CONTRIBUTING

New: shepherd/ui/hub.js

  • Renders the service cards from a small SERVICES catalog
  • Polls each service's lightweight health endpoint every 15s using fetch(... mode: 'no-cors'); opaque-response = up, throw/timeout = down
  • 3 sec per-probe timeout, runs in parallel via Promise.all
  • Updates the overall-status banner with up/total count

Modified: shepherd/ui/shepherd.css

Appended hub-page styles (~165 lines) under a 'body.hub' selector, leaving the existing kiosk (body.kiosk) styling untouched:

  • .hub-grid: auto-fill card-grid with min 280px columns
  • .service-card: dark theme matching kiosk; colored left-border by status
  • .service-badge: pill-shaped up/down/checking indicator
  • .doc-card: documentation section card grid

Modified: shepherd/shepherd_control/app.py

Two route changes (no other logic touched):

  • GET / → now serves hub.html (was: index.html)
  • GET /herd → new; serves index.html (the existing kiosk herd view)

Static-file mount at /ui/* is unchanged. /herd/aggregate JSON data endpoint is unchanged. The kiosk view JS still works at /herd — it fetches /herd/aggregate as before.

Test plan

  • Python syntax: python3 -m py_compile shepherd/shepherd_control/app.py
  • JS parse: node --check shepherd/ui/hub.js
  • HTML tag balance verified
  • Live: GET / returns hub.html with service cards
  • Live: GET /herd returns existing kiosk view, no regression
  • Live: status badges update correctly for running vs stopped services
  • Live: 'Open ↗' links use the same hostname the user accessed by

Scope notes

Per scope-decision (Medium) on PR #41 / d758e57d:

  • IN scope: hub-page + status badges + docs section
  • OUT of scope (separate PRs): LiteLLM admin login fix; on-cluster substrate-verify Shepherd shows all peers / dashboard-redraw issue. Those are observability-backlog items that fold into followup work.

Summary

Type of change

  • Bug fix
  • New feature / enhancement
  • Documentation update
  • Refactor / cleanup
  • CI / tooling change

Related issues

Testing

  • docker compose config passes with no errors
  • Shell scripts pass shellcheck
  • Manually tested on Intel Arc hardware (if relevant)

Checklist

  • My changes follow the project's code style
  • I have updated documentation where necessary
  • I have not committed secrets or real credentials
  • .env.example is up to date (if env vars were added/removed)

Closes the operator-friction Garth flagged: "a single entry point that
links all of our resource pages on these deployments into a single web
UI for easier access by humans. Memorizing all of the ports and
manually typing them all in is tedious."

# What changed

## New: shepherd/ui/hub.html
Landing page rendered at GET / on shepherd-control (port 40117). Three
sections:

1. Quick-link cards for every service on this host:
   - Shepherd herd (this app's /herd dashboard)  → :40117/herd
   - Olla federation + load-balancer             → :40114/
   - Smart Router gestalt UI                     → :40115/gestalt/ui
   - LiteLLM admin UI                            → :4000/ui
   - Retriever health                            → :42000/health
   - Ollama API                                  → :11434/api/tags

   Each card shows: emoji + name + short description, live up/down
   status badge (refreshed every 15s), port number, and an Open ↗ link.

   Auto-discovers the host hostname from window.location, so links
   work from localhost, LAN IP, mesh hostname, or VPN-routed access —
   no template substitution required.

2. Live status banner: 'N / M services up' (refreshes with the cards).

3. Documentation + hardware guides section linking to:
   - README, Troubleshooting, Retriever guide
   - Intel iGPU Vulkan guide + per-hardware docs index
   - growlf/intel_nuc_skullcanyon_ollama_with_gpu standalone repo
     (per Garth's per-hardware-target OSS-repo doctrine)
   - ai-stack GitHub repo + open issues + CONTRIBUTING

## New: shepherd/ui/hub.js
- Renders the service cards from a small SERVICES catalog
- Polls each service's lightweight health endpoint every 15s using
  fetch(... mode: 'no-cors'); opaque-response = up, throw/timeout = down
- 3 sec per-probe timeout, runs in parallel via Promise.all
- Updates the overall-status banner with up/total count

## Modified: shepherd/ui/shepherd.css
Appended hub-page styles (~165 lines) under a 'body.hub' selector,
leaving the existing kiosk (body.kiosk) styling untouched:
- .hub-grid: auto-fill card-grid with min 280px columns
- .service-card: dark theme matching kiosk; colored left-border by status
- .service-badge: pill-shaped up/down/checking indicator
- .doc-card: documentation section card grid

## Modified: shepherd/shepherd_control/app.py
Two route changes (no other logic touched):
- GET /     → now serves hub.html (was: index.html)
- GET /herd → new; serves index.html (the existing kiosk herd view)

Static-file mount at /ui/* is unchanged. /herd/aggregate JSON data
endpoint is unchanged. The kiosk view JS still works at /herd —
it fetches /herd/aggregate as before.

# Test plan

- [x] Python syntax: python3 -m py_compile shepherd/shepherd_control/app.py
- [x] JS parse: node --check shepherd/ui/hub.js
- [x] HTML tag balance verified
- [ ] Live: GET / returns hub.html with service cards
- [ ] Live: GET /herd returns existing kiosk view, no regression
- [ ] Live: status badges update correctly for running vs stopped services
- [ ] Live: 'Open ↗' links use the same hostname the user accessed by

# Scope notes

Per scope-decision (Medium) on PR #41 / d758e57d:
- IN scope: hub-page + status badges + docs section
- OUT of scope (separate PRs): LiteLLM admin login fix; on-cluster
  substrate-verify Shepherd shows all peers / dashboard-redraw issue.
  Those are observability-backlog items that fold into followup work.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@growlf growlf self-assigned this May 21, 2026
@growlf growlf merged commit 718d79b into main May 21, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant