Rename: Hamlet -> Ham Lab (binary/module/service/config hamlab)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Mitchell-Johnson
2026-09-17 10:40:40 -07:00
co-authored by Claude Fable 5.1
parent 436732dac0
commit d76da4b37a
18 changed files with 61 additions and 61 deletions
+16 -16
View File
@@ -1,4 +1,4 @@
# Hamlet — MVP plan
# Ham Lab — MVP plan
Proxmox-style web console for a bare-metal Debian 13 host. First target: `core`
(10.0.0.234). MVP is **service + shell + persistent terminals**; everything else is a
@@ -13,17 +13,17 @@ stub tab or a roadmap item.
| Transport | One WebSocket per attached terminal; REST for everything else | Standard; NPM passes WebSockets with one toggle. |
| Frontend | **React + TypeScript + Vite**, `xterm.js` (+ fit, webgl, web-links addons) | Matches `calorie-counter` / `wedding-website`, so no new toolchain to learn. |
| Auth | Single-user **password login**, argon2id hash, HttpOnly/Secure/SameSite=Strict session cookie, login rate-limit, Origin check on WS upgrade | This is a root-capable shell on the public internet. Auth is MVP, not roadmap. |
| Service | `hamlet.service`, `User=core`, `Restart=always`, binary at `/usr/local/bin/hamlet` | Same pattern as `calorie-counter.service`. Runs as `core` so `sudo` works in the terminal without a password, as on the SSH path. |
| Service | `hamlab.service`, `User=core`, `Restart=always`, binary at `/usr/local/bin/hamlab` | Same pattern as `calorie-counter.service`. Runs as `core` so `sudo` works in the terminal without a password, as on the SSH path. |
| Listen | `10.0.0.234:8100` (free) | NPM is a container, so loopback-only won't do. Firewalling to NPM is a later hardening step. |
| Data | `/home/core/apps/hamlet/` — `config.yaml`, `state.db` (SQLite) | `apps/` is the nightly rsync target to `grid`, so it's backed up for free. |
| Ingress | NPM proxy host `hamlet.bigham.dev` → `:8100`, LE cert, WebSockets on, caching off, force-SSL + HSTS + HTTP/2 set in a **second** API call (NPM drops them on create-with-new-cert) | `*.bigham.dev` already resolves; the proxy host alone makes it live. |
| Repo | Gitea `mitchell/hamlet`, private, `main` | Created 2026-09-17. |
| Data | `/home/core/apps/hamlab/` — `config.yaml`, `state.db` (SQLite) | `apps/` is the nightly rsync target to `grid`, so it's backed up for free. |
| Ingress | NPM proxy host `hamlab.bigham.dev` → `:8100`, LE cert, WebSockets on, caching off, force-SSL + HSTS + HTTP/2 set in a **second** API call (NPM drops them on create-with-new-cert) | `*.bigham.dev` already resolves; the proxy host alone makes it live. |
| Repo | Gitea `mitchell/hamlab`, private, `main` | Created 2026-09-17. |
## Layout
```
┌──────────────────────────────────────────────────────────────┐
│ header: Hamlet · core · load 0.42 · ● connected · [logout] │
│ header: Ham Lab · core · load 0.42 · ● connected · [logout] │
├──────────────┬───────────────────────────────────────────────┤
│ ▾ Terminal │ │
│ shell 1 ● │ │
@@ -34,7 +34,7 @@ stub tab or a roadmap item.
│ ▸ ZFS │ │
│ ▸ Dashboard │ │
├──────────────┴───────────────────────────────────────────────┤
│ footer: v0.1.0 · up 12d · hamlet.bigham.dev │
│ footer: v0.1.0 · up 12d · hamlab.bigham.dev │
└──────────────────────────────────────────────────────────────┘
```
@@ -80,8 +80,8 @@ Everything under `/api` except `login` and `/healthz` requires the session cooki
## Project layout
```
hamlet/
cmd/hamlet/main.go serve | passwd | version
hamlab/
cmd/hamlab/main.go serve | passwd | version
internal/
auth/ argon2id, sessions, rate limit
term/ PTY manager, ring buffer, attach/detach
@@ -90,16 +90,16 @@ hamlet/
web/ go:embed of web/dist
web/ Vite + React + TS + xterm.js, PWA manifest + SW
deploy/
hamlet.service
install.sh build → /usr/local/bin/hamlet → systemctl restart
hamlab.service
install.sh build → /usr/local/bin/hamlab → systemctl restart
Makefile build / dev / deploy / lint / test
```
## Milestones
**M0 — skeleton** (service boots, login works)
- Go module, chi, config loading, `hamlet passwd`, argon2id login, session cookie.
- `hamlet.service` on `core`, `:8100`, serves a placeholder page.
- Go module, chi, config loading, `hamlab passwd`, argon2id login, session cookie.
- `hamlab.service` on `core`, `:8100`, serves a placeholder page.
- `make deploy` from `core` itself.
**M1 — terminals** (the MVP feature)
@@ -111,7 +111,7 @@ hamlet/
- Mobile drawer, key bar, fit-on-rotate.
- `manifest.webmanifest`, icons (Ham logo on black, same recipe as HamTV), service
worker caching the app shell only (never `/api`).
- NPM proxy host for `hamlet.bigham.dev`; verify WS through NPM; force-SSL/HSTS/HTTP2.
- NPM proxy host for `hamlab.bigham.dev`; verify WS through NPM; force-SSL/HSTS/HTTP2.
- Stub groups for Services / Cron / ZFS / Dashboard.
**Done when:** from the phone, open the PWA, log in, open two terminals, run
@@ -120,7 +120,7 @@ something long in one, switch away and back, refresh — it's all still there.
## Roadmap (not MVP — notes only)
- **tmux-backed sessions** so shells survive a daemon restart / redeploy. Would spawn
`tmux new -A -s hamlet-<id>`; needs `mouse on` and status-bar handling in xterm.
`tmux new -A -s hamlab-<id>`; needs `mouse on` and status-bar handling in xterm.
- **Services tab** — `systemctl list-units`, per-unit page: status, last 200 journal
lines (live-tail via WS), start/stop/restart/enable buttons, unit file viewer.
- **Cron tab** — parse `/etc/crontab`, `/etc/cron.d/*`, user crontabs, and systemd
@@ -129,7 +129,7 @@ something long in one, switch away and back, refresh — it's all still there.
scrub status, and the `freeing` counter. `grid` is the target, which implies
multi-host.
- **Dashboard** — CPU/mem/load/net, disks and SMART (`smartctl -j`), temps and fans
(`sensors -j`), UPS from `pwrstat`. Hamlet collects on a timer into a SQLite
(`sensors -j`), UPS from `pwrstat`. Ham Lab collects on a timer into a SQLite
ring (e.g. 10 s resolution, 7 days) and draws sparklines. This is where the
"collects its own data" requirement lands; no Prometheus dependency.
- **Multi-host** — same binary as a headless *agent* on `grid` / Mac mini /