chore: execute stage 1 vault migration to hybrid architecture
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
# AI
|
||||
|
||||
## Learning
|
||||
|
||||
* [The Ultimate Guide to Local AI and AI Agents (The Future is Here) - YouTube](https://www.youtube.com/watch?v=mNcXue7X8H0)
|
||||
* Docker Compose based framework for running AI locally
|
||||
* https://github.com/coleam00/local-ai-packaged
|
||||
* https://www.reddit.com/r/LocalLLaMA/
|
||||
*
|
||||
|
||||
## Projects
|
||||
|
||||
* [[self-hosting_AI]]
|
||||
|
||||
## LocalAI Packaged
|
||||
|
||||
### Services
|
||||
|
||||
* [Open WebUI](http://localhost:8080/)
|
||||
* [n8n](http://localhost:5678/)
|
||||
* [Langfuse](http://localhost:3000/)
|
||||
* [Ollama](http://localhost:11434/)
|
||||
* [Qdrant](http://localhost:6333/)
|
||||
|
||||
### Start services
|
||||
|
||||
```shell
|
||||
python start_services.py --profile gpu-nvidia
|
||||
```
|
||||
|
||||
## AgentOS
|
||||
|
||||
* https://github.com/buildermethods/agent-os
|
||||
|
||||
## AG2
|
||||
|
||||
* https://github.com/ag2ai/ag2
|
||||
@@ -0,0 +1,26 @@
|
||||
# booloumud
|
||||
|
||||
* https://store.booloumud.com
|
||||
*
|
||||
|
||||
## Tech
|
||||
|
||||
### DNS
|
||||
|
||||
* Squarespace
|
||||
* booloumud.com --> store.booloumud.com (Shopify)
|
||||
* Porkbun
|
||||
* Transfer in progress, need to re-establish after transfer
|
||||
* booloumud.org --> booloumud.com
|
||||
* booloumud.net --> booloumud.com
|
||||
|
||||
## Designs
|
||||
|
||||
### Earring holders and storage
|
||||
|
||||
* `G:\My Drive\booloumud\designs\earring_display`
|
||||
|
||||
### Tooth pendants
|
||||
|
||||
* [🦷 Real Anatomy Tooth Seth #1・ 3D File for 3D printing・Cults]https://cults3d.com/en/3d-model/art/real-anatomy-tooth-seth-1
|
||||
* https://cults3d.com/en/orders/128683287
|
||||
@@ -0,0 +1,81 @@
|
||||
# chezmoi
|
||||
|
||||
[chezmoi](https://www.chezmoi.io/) is a dotfile manager that keeps configuration files synchronized across machines using a git-backed source directory.
|
||||
|
||||
## Setup
|
||||
|
||||
### Configuration
|
||||
|
||||
Config file: `~/.config/chezmoi/chezmoi.toml`
|
||||
|
||||
```toml
|
||||
[git]
|
||||
autoCommit = true
|
||||
autoPush = true
|
||||
|
||||
[merge]
|
||||
command = "bash"
|
||||
args = [
|
||||
"-c",
|
||||
"cp {{ .Target | quote }} {{ printf \"%s.base\" .Target | quote }} && code --new-window --wait --merge {{ .Destination | quote }} {{ .Target | quote }} {{ printf \"%s.base\" .Target | quote }} {{ .Source | quote }}",
|
||||
]
|
||||
```
|
||||
|
||||
- **autoCommit**: Automatically commits changes after `chezmoi apply`
|
||||
- **autoPush**: Automatically pushes to remote after commit
|
||||
- **merge**: Custom merge command using VS Code's merge editor
|
||||
|
||||
### Source Directory
|
||||
|
||||
`~/.local/share/chezmoi/` - Git repository containing managed dotfiles
|
||||
|
||||
## Managed Dotfiles
|
||||
|
||||
| File/Directory | Description |
|
||||
|----------------|-------------|
|
||||
| `.bash_aliases` | Shell aliases |
|
||||
| `.bashrc` | Bash configuration |
|
||||
| `.tmux.conf` | Tmux configuration |
|
||||
| `.config/opencode/` | OpenCode AI assistant config |
|
||||
| `.gemini/settings.json` | Gemini CLI settings |
|
||||
| `.ssh/authorized_keys` | SSH authorized keys (private) |
|
||||
|
||||
### OpenCode Config
|
||||
|
||||
The `.config/opencode/` directory includes:
|
||||
- `opencode.jsonc` - Main OpenCode configuration
|
||||
- `oh-my-opencode-slim.json` - Slim preset configuration
|
||||
- `executable_opencode-tmux-launch.sh` - Script to launch OpenCode in tmux
|
||||
|
||||
## Common Commands
|
||||
|
||||
```bash
|
||||
# Edit a dotfile in the source directory
|
||||
chezmoi edit ~/.bashrc
|
||||
|
||||
# Apply changes to the home directory
|
||||
chezmoi apply
|
||||
|
||||
# See what would change
|
||||
chezmoi diff
|
||||
|
||||
# Add a new file to chezmoi
|
||||
chezmoi add ~/.newconfig
|
||||
|
||||
# Edit the config file
|
||||
chezmoi edit-config
|
||||
|
||||
# Initialize chezmoi on a new machine
|
||||
chezmoi init https://github.com/username/dotfiles.git
|
||||
```
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Edit dotfiles with `chezmoi edit` (opens source file)
|
||||
2. Apply changes with `chezmoi apply`
|
||||
3. Changes auto-commit and push to git remote
|
||||
|
||||
## Related
|
||||
|
||||
- [[homelab]]
|
||||
- [[dev_environments]]
|
||||
@@ -0,0 +1,145 @@
|
||||
# cigars
|
||||
|
||||
## to try
|
||||
|
||||
* Drew Estate
|
||||
* Deadwood Crazy Alice
|
||||
* Java Mint Maduro
|
||||
* https://www.reddit.com/r/cigars/s/gEAeA9gw2o
|
||||
* https://www.reddit.com/r/cigars/s/O42EdsJXSf
|
||||
* Johnny Tabaconaught
|
||||
* https://www.reddit.com/r/cigars/s/A8KFQ9sovB
|
||||
* Brickhouse
|
||||
* Maduro
|
||||
* https://www.reddit.com/r/cigars/s/bRg03rKkZ1
|
||||
* Crowned Heads Le Careme
|
||||
* https://www.reddit.com/r/cigars/s/798wqgYHMp
|
||||
|
||||
## I like
|
||||
|
||||
* Deadwood
|
||||
* Leather Rose
|
||||
* Girl with No Name
|
||||
* Undercrown Shade
|
||||
* Mild flavor, strong buzz
|
||||
* Famous Smoke Shop
|
||||
* Nicaraguan Selection 3000
|
||||
* Foundation
|
||||
* Tabernacle Havana Seed
|
||||
* Maduro
|
||||
* Dark Natural - a little strong
|
||||
* Gurkha
|
||||
* Rogue
|
||||
* Chateau de Prive - nice burn, very mild, toasted
|
||||
* Evil - leather and mild pepper
|
||||
* L'Atelier
|
||||
* Surrogates Bone Crusher
|
||||
* Oliva
|
||||
* Serie O Corona
|
||||
* 3rd Degree
|
||||
* Master Blends 3
|
||||
* Kentuky Fire Cured
|
||||
* Just a Friend
|
||||
* Fat Molly
|
||||
* Arturo Fuente
|
||||
* Gran Reserva Curly Head Deluxe Maduro - a little shaggy, but inexpensive
|
||||
* Selection Privada No. 1 Double Claro
|
||||
* Rojas
|
||||
* Street Tacos Barbacoa Robusta
|
||||
* Breakfast Tacos Sumatra
|
||||
* Tatuaje
|
||||
* Reserva Broadleaf
|
||||
|
||||
## I don't like
|
||||
|
||||
* Rocky Patel Seed to Smoke Share Toro
|
||||
* Just, gross. Tastes like a book depository.
|
||||
|
||||
## meh
|
||||
|
||||
* Drew Estate
|
||||
* Factory Smokes Belicoso Sweet
|
||||
* Rocky Patel
|
||||
* Seed to Smoke Classic
|
||||
|
||||
## shops
|
||||
|
||||
* https://www.cigarsdirect.com/
|
||||
* Neptune
|
||||
* Famous Smoke Shop
|
||||
|
||||
## Journal
|
||||
|
||||
|
||||
* [[2025-09-18]] - Tatuaje Reserva Broadleaf ([[2024-09-13]])
|
||||
* [[2025-09-16]] - Arturo Fuente Curly Head Delux Maduro ([[2024-11-20]])
|
||||
* [[2025-09-15]] - Acid Twenty (2024-01-16)
|
||||
* [[2025-09-14]] - Gurkha The Tabernacle (2024-11-20)
|
||||
* Chocolate, leather
|
||||
* [[2025-09-13]] - L'Atelier Surrogates Bone Crusher ([[2024-09-13]])
|
||||
* Earthy soil, dark roast coffee. Tight ash, even burn.
|
||||
* [[2025-09-12]] - Arturo Fuente Curly Head Delux Maduro ([[2024-11-20]])
|
||||
* [[2025-09-11]] - Arturo Fuente Curly Head Delux Maduro ([[2024-11-20]])
|
||||
* [[2025-09-10]]
|
||||
* Nub Habano ([[2024-07-08]])
|
||||
* Not bad - mild to medium. Lumber and leather. Wrapper was really thin and fell apart, had to relight a few times
|
||||
* Arturo Fuente Curly Head Delux Maduro ([[2024-11-20]])
|
||||
* [[2025-09-09]] - Famous Smoke Shop Nicaraguan Selection 3000
|
||||
* [[2025-09-05]] - Gurkha Cellar Reserve 18 Years
|
||||
* [[2025-09-04]]
|
||||
* Rojas Breakfast Tacos Sumatra ([[2025-08-01]])
|
||||
* Oliva Serie O ([[2024-11-20]])
|
||||
* [[2025-09-03]] - Gurkha Castle Hall ([[2025-08-01]])
|
||||
* [[2025-08-30]] - Gurkha Beast ([[2025-08-01]])
|
||||
* tight, horrible draw on this stick
|
||||
* once loosened up, not bad - medium-dark, gassy, dark wood
|
||||
* [[2025-08-29]] - Gurkha Evil ([[2025-08-01]])
|
||||
* Mild to medium - leather, a little pepper
|
||||
* [[2025-08-24]] - Gurkha Marquesa ([[2025-08-01]])
|
||||
* [[2025-08-15]] - Oliva Serie O ([[2024-11-20]])
|
||||
* [[2025-08-13]] - Gurkha Chateau de Prive ([[2025-08-01]])
|
||||
* [[2025-08-12]] - Kentucky Fire Cured Fat Molly ([[2025-08-01]])
|
||||
* [[2025-08-11]] - Gurkha Rogue ([[2025-08-01]])
|
||||
* Good medium strength. Some burn issues, esp towards the end
|
||||
* ~[[2025-08-11]] - Rocky Patel Seed to Smoke Shade Toro ([[2025-08-01]])~
|
||||
* Abandoned after one draw - nasty!
|
||||
* [[2025-08-09]] - Rojas Street Tacos Carnitas Toro ([[2025-08-01]])
|
||||
* [[2025-08-07]] - Kentucky Fire Cured Fat Molly ([[2025-08-01]])
|
||||
* [[2025-08-05]] - Rojas Street Tacos Barbacoa Robusta ([[2025-08-01]])
|
||||
* Easy draw, lots of smoke. Pepper, leather, medium strong
|
||||
* [[2025-08-01]] - Rocky Patel Seed to Smoke Classic ([[2025-08-01]])
|
||||
* Dry leaves, flat, not offensive, but not very good
|
||||
* [[2025-07-31]] - Kentuky Fire Cured Muwat ([[2024-07-08]])
|
||||
* [[2025-07-30]] - Oliva Master Blends 3 ([[2024-07-08]])
|
||||
* [[2025-07-20]] - Inferno by Oliva ([[2024-07-08]])
|
||||
* [[2025-07-18]]
|
||||
* Oliva Serie O ([[2024-11-20]])
|
||||
* Selection Privada No. 1 Double Claro ([[2024-01-19]])
|
||||
* [[2025-07-16]] - Oliva Serie O ([[2024-11-20]])
|
||||
* [[2025-07-14]] - Selection Privada No. 1 Double Claro ([[2024-01-19]])
|
||||
* [[2025-07-11]] - Oliva Serie V ([[2024-12-25]])
|
||||
* [[2025-07-10]] - Acid Progeny ([[2024-01-16]])
|
||||
* Cedary, spicy wood
|
||||
* [[2025-07-08]] - Selection Privada No. 1 Double Claro ([[2024-01-19]])
|
||||
* [[2025-07-08]] - Oliva Serie O ([[2024-11-20]])
|
||||
* [[2025-07-07]] - Oliva 3rd Degree ([[2024-07-08]])
|
||||
* Strong, but not smoky. Tight, even burn. Took a while to get through, pretty buzzy.
|
||||
* [[2025-07-06]] - Undercrown Shade ([[2024-01]])
|
||||
* [[2025-07-03]] - Oliva Serie O ([[2024-11-20]])
|
||||
* [[2025-07-01]] - Factory Smokes Belicoso Sweet ([[2024-01-16]])
|
||||
* [[2025-06-30]] - Selection Privada No. 1 Double Claro ([[2024-01-19]])
|
||||
* [[2025-06-25]] - Selection Privada No. 1 Double Claro
|
||||
|
||||
|
||||
[//begin]: # "Autogenerated link references for markdown compatibility"
|
||||
[2025-09-10]: 2025-09-10.md "2025-09-10"
|
||||
[2025-09-09]: 2025-09-09.md "2025-09-09"
|
||||
[2025-08-30]: 2025-08-30.md "2025-08-30"
|
||||
[2025-08-29]: 2025-08-29.md "2025-08-29"
|
||||
[2025-08-24]: 2025-08-24.md "2025-08-24"
|
||||
[2025-08-15]: 2025-08-15.md "2025-08-15"
|
||||
[2025-07-06]: 2025-07-06.md "2025-07-06"
|
||||
[2025-07-03]: 2025-07-03.md "2025-07-03"
|
||||
[2025-07-01]: 2025-07-01.md "2025-07-01"
|
||||
[2025-06-30]: 2025-06-30.md "2025-06-30"
|
||||
[//end]: # "Autogenerated link references"
|
||||
@@ -0,0 +1,3 @@
|
||||
# dev environments
|
||||
|
||||
* https://bitwarden.com/help/ssh-agent/
|
||||
@@ -0,0 +1,5 @@
|
||||
# gitea
|
||||
|
||||
user:pass is `compose:compose` for now, used docker compose template
|
||||
|
||||
external access for SSH is `ssh://git@git.hobbithole.org:4222`
|
||||
@@ -0,0 +1,183 @@
|
||||
# homelab
|
||||
|
||||
* OPNsense firewall: https://opnsense.hh.lan:8443
|
||||
* 192.168.86.45
|
||||
* Proxmox virtualization cluster: https://proxmox1.hh.lan
|
||||
|
||||
## services
|
||||
|
||||
* HomeAssistant home automation
|
||||
* http://homeassistant.local:8123/
|
||||
* https://ha.hh.lan
|
||||
* Frigate NVR (security cameras): https://frigate.local:8971
|
||||
* Paperless document repository
|
||||
* https://paperless.hobbithole.org
|
||||
* https://paperless.hh.lan
|
||||
|
||||
### Gitea
|
||||
|
||||
* https://git.hobbithole.org
|
||||
* http://gitea.hh.lan:3000
|
||||
* SSH key stored in bitwarden
|
||||
* used `docker-compose-template` VM template
|
||||
* Moved host `sshd` to `tcp:2222` so gitea container can use `tcp:22`
|
||||
|
||||
## things to set up
|
||||
|
||||
* Network UPS Tool? (NUT)
|
||||
* Monitor reservoir levels
|
||||
* https://dwr.state.co.us/Tools/StationsLite/UNIRESCO?params=STORAGE
|
||||
* Caddy
|
||||
* Authentik
|
||||
* Proxmox backup
|
||||
* CrashPlan (or other backup service)
|
||||
* [Proxmox Crashplan](https://nguvu.org/proxmox/proxmox-crashplan-install/)
|
||||
* https://github.com/nix-community/terraform-nixos/blob/master/examples/hermetic_config/default.tf
|
||||
* https://spacelift.io/blog/terraform-proxmox-provider#5-run-terraform-to-create-the-vm
|
||||
* Home auth
|
||||
* Windows auth
|
||||
* SSO access to services
|
||||
* Bitwarden self-hosted org
|
||||
* [Self-host an Organization](https://bitwarden.com/help/self-host-an-organization/)
|
||||
* OpenBao (Vault fork) - https://openbao.org/docs/install/
|
||||
|
||||
## things to research
|
||||
|
||||
* Pangolin
|
||||
* Suricata
|
||||
* [Wiki.js](https://js.wiki/)
|
||||
* Komodo
|
||||
* https://github.com/moghtech/komodo
|
||||
* 🦎 a tool to build and deploy software on many servers 🦎
|
||||
* headscale / tailscale
|
||||
* [GitHub - juanfont/headscale: An open source, self-hosted implementation of the Tailscale control server](https://github.com/juanfont/headscale)
|
||||
* [Tailscale · Best VPN Service for Secure Networks](https://tailscale.com/)
|
||||
|
||||
### Home auth
|
||||
|
||||
## Hardware
|
||||
|
||||
* unnamed switch (TODO)
|
||||
* [Mikrotik CSS318-16G-2S+IN](https://mikrotik.com/product/css318_16g_2s_in#fndtn-downloads)
|
||||
* SwOS management interface: http://192.168.86.54
|
||||
* [manual](https://help.mikrotik.com/docs/spaces/SWOS/pages/76415036/CRS3xx+and+CSS326-24G-2S+series+Manual#CRS3xxandCSS32624G2S+seriesManual-LAG)
|
||||
* lifebalance
|
||||
* Lenovo Legion T7 34IRZ8
|
||||
* Intel Core i9-14900K
|
||||
* 62 GiB RAM
|
||||
* NVIDIA GeForce RTX 4090 (24 GiB VRAM)
|
||||
* Debian GNU/Linux forky/sid
|
||||
* [[self-hosting_AI]]
|
||||
* [[rclone_google_drive]]
|
||||
* proxmox1
|
||||
* Beelink Mini PC EQi12, Intel Core 1220P(Max 4.4GHz 10C/12T), 16GB DDR4 500GB PCle4.0 SSD Mini Computers,Dual LAN/Wifi6/BT5.2,Dual 4K Display,Built-in Power Supply Office PC
|
||||
* proxmox2
|
||||
* Beelink Mini PC EQi12, Intel Core 1220P(Max 4.4GHz 10C/12T), 16GB DDR4 500GB PCle4.0 SSD Mini Computers,Dual LAN/Wifi6/BT5.2,Dual 4K Display,Built-in Power Supply Office PC
|
||||
* proxmox3
|
||||
* Beelink Mini PC EQi12, Intel Core 1220P(Max 4.4GHz 10C/12T), 16GB DDR4 500GB PCle4.0 SSD Mini Computers,Dual LAN/Wifi6/BT5.2,Dual 4K Display,Built-in Power Supply Office PC
|
||||
* frigate
|
||||
* Beelink EQ14 Mini PC, Intel Twin Lake N150(Up to 3.6GHz) 16GB DDR4 500GB NVMe SSD, 2.5G Dual LAN Mini Computer Supports WiFi6, BT5.2, USB3.2, 4K@60Hz Dual HDMI Display, Home-Server/Network Firewall
|
||||
|
||||
## Network
|
||||
|
||||
```mermaid
|
||||
graph TD;
|
||||
internet((Internet))<-->nest_wifi_pro(Nest Wifi Pro);
|
||||
nest_wifi_pro<-->mikrotik;
|
||||
mikrotik<==>LACP(LACP/VLAN trunk);
|
||||
vlan42("vlan42 (home)");
|
||||
vlan86("vlan86 (wifi)");
|
||||
vlan60("vlan60 (work)");
|
||||
vlan200("vlan200 (services)");
|
||||
LACP<-->vlan42;
|
||||
LACP<-->vlan60;
|
||||
LACP<-->vlan86;
|
||||
LACP<-->vlan200;
|
||||
vlan42<-->proxmox_eth0[eth0]<-->proxmox;
|
||||
vlan42<-->proxmox_eth1[eth1]<-->proxmox;
|
||||
vlan60<-->proxmox_eth0[eth0]<-->proxmox;
|
||||
vlan60<-->proxmox_eth1[eth1]<-->proxmox;
|
||||
vlan86<-->proxmox_eth0[eth0]<-->proxmox;
|
||||
vlan86<-->proxmox_eth1[eth1]<-->proxmox;
|
||||
vlan200<-->proxmox_eth0[eth0]<-->proxmox;
|
||||
vlan200<-->proxmox_eth1[eth1]<-->proxmox;
|
||||
proxmox<-->bond0<-->vmbr0<-->VMs;
|
||||
vlan200<-->vault_eth3[eth3]<-->vault;
|
||||
vlan200<-->vault_eth4[eth4]<-->vault;
|
||||
```
|
||||
|
||||
### DNS
|
||||
|
||||
```mermaid
|
||||
graph LR;
|
||||
internet((Internet))<-->porkbun;
|
||||
porkbun<-->hobbithole_org(hobbithole.org);
|
||||
hobbithole_org<-->opnsense;
|
||||
opnsense<-->caddy;
|
||||
caddy<-->vault;
|
||||
caddy<-->proxmox;
|
||||
opnsense<-->hh_lan(hh.lan)<-->bind<-->unbound;
|
||||
unbound<-->vault;
|
||||
unbound<-->proxmox;
|
||||
proxmox[proxmox + VMs];
|
||||
```
|
||||
|
||||
* External domain: `hobbithole.org`
|
||||
* Hosted on SquareSpace, about to move over to PorkBun
|
||||
* Transfer requested [[2025-06-15]]
|
||||
* Email forwarding
|
||||
* gandalf@hobbithole.org --> gibsta@gmail.com
|
||||
* treasury@hobbithole.org --> hobbitholetreasury@googlegroups.com
|
||||
* Records
|
||||
|
||||
| Host | Type | Priority | TTL | Data |
|
||||
| -------------- | ----- | -------- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| @ | A | N/A | 4 hrs | 66.186.208.83 |
|
||||
| backup | CNAME | N/A | 4 hrs | hobbithole.org |
|
||||
| frigate | CNAME | N/A | 4 hrs | hobbithole.org |
|
||||
| home | CNAME | N/A | 4 hrs | hobbithole.org |
|
||||
| nestmtx | CNAME | N/A | 4 hrs | hobbithole.org |
|
||||
| radarr | CNAME | N/A | 4 hrs | hobbithole.org |
|
||||
| sab | CNAME | N/A | 4 hrs | hobbithole.org |
|
||||
| sonarr | CNAME | N/A | 4 hrs | hobbithole.org |
|
||||
| tv | CNAME | N/A | 4 hrs | hobbithole.org |
|
||||
| vault | CNAME | N/A | 4 hrs | hobbithole.org |
|
||||
| y3t4fz4ttvom | CNAME | N/A | 4 hrs | gv-3ccjjbudvp5ki7.dv.googlehosted.com |
|
||||
| @ | MX | N/A | 4 hrs | mxa.mailgun.org |
|
||||
| @ | MX | N/A | 4 hrs | mxb.mailgun.org |
|
||||
| @ | TXT | N/A | 4 hrs | v=spf1 include:mailgun.org ~all |
|
||||
| krs._domainkey | TXT | N/A | 4 hrs | k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDjzUREnJNjiTg2oKAUdaFixMkblPmbiQTW2kinGFIFji16qN50L02DyBxanRz9Z2IK/uhLJ0I4angMTuSr338/ZE6xfjuJIqNMIOw0kgPnxo4qj5HxDiygUSbLHuxMnWzlOddzGgHpytPgpk9gYlw3b2Tt0K5Ym20ie7GaAXv+QIDAQAB |
|
||||
|
||||
* Internal domain: `hh.lan`
|
||||
* Unbound transparent domain --> BIND authoritative domain
|
||||
* Hosted on OPNsense
|
||||
*
|
||||
|
||||
* hobby domains
|
||||
* Transferring to Porkbun
|
||||
* b3n.ooo
|
||||
* benmiller.xyz
|
||||
* beepmill.com
|
||||
|
||||
### IPAM
|
||||
|
||||
* wifi: `192.168.86.0/24`
|
||||
* home: `192.168.42.0/24`
|
||||
* services: `192.168.200.0/24`
|
||||
* work: `172.16.60.0/24`
|
||||
|
||||
## Proxmox
|
||||
|
||||
### Hosts
|
||||
|
||||
* `proxmox1.hh.lan`
|
||||
* 192.168.200.101
|
||||
* `proxmox2.hh.lan`
|
||||
* 192.168.200.102
|
||||
* `proxmox3.hh.lan`
|
||||
* 192.168.200.103
|
||||
|
||||
|
||||
[//begin]: # "Autogenerated link references for markdown compatibility"
|
||||
[2025-06-15]: 2025-06-15.md "2025-06-15"
|
||||
[//end]: # "Autogenerated link references"
|
||||
@@ -0,0 +1,31 @@
|
||||
# keyboards
|
||||
|
||||
* [Cosmos Keyboard](https://ryanis.cool/cosmos/) - keyboard customizer
|
||||
* [First attempt](https://ryanis.cool/cosmos/beta#cm:Cp8BChUSBRCAbyAnEgASABIAOB5AgIaKwAcKGRIFEIBjICcSABIAEgMQsDsSAxCwazgKQAAKHBIFEIBXICcSABIAEgMQsC8SAxCwXzgJQIDwvAIKERIFEIBLICcSABIAEgA4HUAAChESBRCAPyAnEgASABIAODFAAAoYEgIgJxIAEgQQoIAKEgIQMDgyQICGisAHGABA6IWgrvBVSNyMq9ABCmcKChIFEEBQ8gI4wAwKCxIGEMCAAiAoOKgUCgkSBBBAICg4kBwKCxIGEEAgKEAAOPgjChgSEhBAIAAwyAFAgICADUiAgLCsATAWOAAYCiIKCMgBEMgBGAAgAEDbkaSc8DdIhI+U1qB4CpUBCnYSFgiAMBDAgAIgAECMhdiWEEiNhYC43Q0SEwiAMBBAIABAmcSWCEiNhYC43Q0SDyAAQK6F3ANImYmIntDcEBIQIABA4YPY0AFI6ZOgl5DwERIPIABA0OKPOEiDj6CXkL0SEhEgAEDvhbyXsAFI4Z3QjbDYEjgAGAMiCgjIARDIARgAIABAno3MrPAzSKap3MaAtAgYhCCCAQIEAmAD)
|
||||
* Svalboard
|
||||
* https://svalboard.com/
|
||||
* Characorder
|
||||
* Control panel: https://charachorder.io/
|
||||
* Practice: https://www.iq-eq.io/#/
|
||||
*
|
||||
|
||||
## Custom Build 1
|
||||
|
||||
* Dactyl Manuform style built with Cosmos Keyboard Configurator
|
||||
* https://ryanis.cool/cosmos/beta#cm:Cn4KDxIFEJBBIBMSABIAODFAAAoPEgUQkE0gExIAEgA4HUAAChsSBRCQWSATEgASAxCwLxIDELBfOAlAgPCG+AEKGRIFEJBlIBMSABIDELA7EgMQsGs4CkCAgAwKExIFEJBxIBMSABIAOB5AgJqL0AIYAEDqhaCu8FVI3Iyr0AEKaAoXEhMQwIACQICAmAJIwpmglZC8AVBDOAgKFRIQEEBAgIAgSNCVgN2Q9QNQC1CeAgoUEhAQQECAgPgBSOaZ/KeQC1BXUH8KA1CCAhgCIgoIyAEQyAEYACAAQMuL/J/QMUitkdyNwZMGCngKDxIFEJA1IBMSABIAODJAAAoPEgUQkCkgExIAEgA4HkAAChgSBRCQHSATEgASABIDELBfOApAgISK2AIKFhIFEJARIBMSABIAEgMQsGs4CUCA6DQKExIFEJAFIBMSABIAOB1AgJqOsAMYAUDphaCu8FVI3IqryAEKaQoXEhMQwIACQICAmAJIwpmclaC8AVBDOAcKFRIQEEBAgIAgSNCV/Nyg9QNQC1CdAgoVEhAQQECAgPgBSOaZgKygC1BXUIABCgNQgQIYAyIKCMgBEMgBGAAgAEDMi/yf0DFIrZHgjbGTBiIDIK4NggEKAJ4FyAFllwEBAlhCYANoAPoBCRCIDhg8KGQoMg==
|
||||
* https://www.printables.com/model/158559-handwire-hot-swap-socket-for-mechanical-keyboard-s
|
||||
* `G:\My Drive\making\files\cosmotyl`
|
||||
|
||||
### Wiring
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
* https://ryanis.cool/cosmos/docs/qmk-rp2040/#wire-the-keyboard
|
||||
*
|
||||
|
||||
|
||||
## Training
|
||||
|
||||
* https://typecelerate.com/
|
||||
@@ -0,0 +1,5 @@
|
||||
# opentofu
|
||||
|
||||
* https://search.opentofu.org/provider/bpg/proxmox/latest
|
||||
* http://gitea.hh.lan:3000/ben/homelab_tofu
|
||||
* GCS backend: [`gs://deskbound-mournful-synthetic4`](https://console.cloud.google.com/storage/browser/deskbound-mournful-synthetic4)
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
created: 2025-06-28T14:27:34-06:00
|
||||
modified: 2025-06-28T14:30:15-06:00
|
||||
---
|
||||
|
||||
# pool
|
||||
|
||||
https://a.co/d/08ZOxSHk
|
||||
INTEX Ultra XTR 18 ft x 9 ft 52 in Above Ground Pool Set, Rectangular Swimming Pool with Steel Frame, 1500 GPH Sand Filter Pump, Ladder, Cover, & Ground Cloth
|
||||
|
||||
18 ft x 9 ft x 52in rectangular frame design and a 4,545 gallon water capacity.
|
||||
|
||||
# upgrades TODO
|
||||
|
||||
* valve upgrade, pvc
|
||||
* https://youtu.be/4gmdtYiSq9g?si=aD4ZbZJyZU8ngQHE
|
||||
@@ -0,0 +1,96 @@
|
||||
# rclone google drive
|
||||
|
||||
Related: [[homelab]]
|
||||
|
||||
## Current setup
|
||||
|
||||
This machine (`lifebalance`) is configured to access Google Drive through `rclone`.
|
||||
|
||||
* Remote name: `gdrive`
|
||||
* Config file: `~/.config/rclone/rclone.conf`
|
||||
* Mount point: `~/gdrive`
|
||||
* Auth flow used: local browser OAuth on the machine during `rclone config create`
|
||||
|
||||
## Installation
|
||||
|
||||
Installed from Debian packages:
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y rclone
|
||||
```
|
||||
|
||||
## Remote configuration
|
||||
|
||||
The Google Drive remote was created with full-drive scope and verified successfully.
|
||||
|
||||
Useful commands:
|
||||
|
||||
```bash
|
||||
rclone listremotes
|
||||
rclone lsd gdrive:
|
||||
rclone ls gdrive:docs
|
||||
```
|
||||
|
||||
## Persistent mount
|
||||
|
||||
The Drive mount is managed by a user systemd service.
|
||||
|
||||
* Service file: `~/.config/systemd/user/rclone-gdrive.service`
|
||||
* Mount command:
|
||||
|
||||
```bash
|
||||
/usr/bin/rclone mount gdrive: /home/ben/gdrive --config=/home/ben/.config/rclone/rclone.conf --vfs-cache-mode=writes
|
||||
```
|
||||
|
||||
Service contents:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Rclone mount for Google Drive
|
||||
Wants=network-online.target
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/bin/rclone mount gdrive: /home/ben/gdrive --config=/home/ben/.config/rclone/rclone.conf --vfs-cache-mode=writes
|
||||
ExecStop=/usr/bin/fusermount3 -uz /home/ben/gdrive
|
||||
Restart=on-failure
|
||||
RestartSec=10
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
```
|
||||
|
||||
## Service management
|
||||
|
||||
```bash
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user enable --now rclone-gdrive.service
|
||||
systemctl --user status rclone-gdrive.service
|
||||
systemctl --user restart rclone-gdrive.service
|
||||
systemctl --user stop rclone-gdrive.service
|
||||
systemctl --user start rclone-gdrive.service
|
||||
```
|
||||
|
||||
Note: this mount starts automatically when the user session starts. If it should start before login after reboot, enable lingering for the user.
|
||||
|
||||
## Verification
|
||||
|
||||
These checks succeeded:
|
||||
|
||||
```bash
|
||||
mountpoint ~/gdrive
|
||||
ls ~/gdrive
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If the mount stops working:
|
||||
|
||||
```bash
|
||||
systemctl --user status rclone-gdrive.service
|
||||
journalctl --user -u rclone-gdrive.service -n 100 --no-pager
|
||||
fusermount3 -uz ~/gdrive
|
||||
systemctl --user restart rclone-gdrive.service
|
||||
```
|
||||
@@ -0,0 +1,616 @@
|
||||
|
||||
# self-hosting AI on lifebalance
|
||||
|
||||
Related: [[AI]], [[homelab]]
|
||||
|
||||
## Current host baseline
|
||||
|
||||
* Hostname: `lifebalance`
|
||||
* Hardware: Lenovo Legion T7 34IRZ8, Intel Core i9-14900K, 62 GiB RAM, NVIDIA GeForce RTX 4090 (24 GiB VRAM), 1.9 TB NVMe (`/home` on a 1.6 TB logical volume)
|
||||
* OS: Debian GNU/Linux forky/sid, kernel `6.18.15+deb14-amd64`
|
||||
* NVIDIA stack: driver `550.163.01`, CUDA `12.4`
|
||||
* Container stack: Docker `29.3.1`, containerd `2.2.2`, NVIDIA Container Toolkit `1.19.0`
|
||||
|
||||
## Current AI status
|
||||
|
||||
* No AI model server is currently running on `lifebalance`.
|
||||
* `docker.service` and `containerd.service` are running.
|
||||
* No `ollama` binary was found.
|
||||
* No `conda` install was found.
|
||||
* Global `python3` is `3.13.12`.
|
||||
* A dedicated `~/sglang` virtualenv exists, but it currently only has `pip` and `uv` installed.
|
||||
|
||||
## Evidence of previous setup
|
||||
|
||||
### SGLang
|
||||
|
||||
* Virtualenv: `~/sglang`
|
||||
* Startup script: `~/sglang/bin/start-sglang.sh`
|
||||
* Intended launch command:
|
||||
|
||||
```shell
|
||||
python -m sglang.launch_server \
|
||||
--model Qwen/Qwen3-8B-AWQ \
|
||||
--port 30000 \
|
||||
--host 127.0.0.1 \
|
||||
--mem-fraction-static 0.88 \
|
||||
--context-length 32768 \
|
||||
--dtype auto \
|
||||
--trust-remote-code
|
||||
```
|
||||
|
||||
* Notes:
|
||||
* configured for localhost-only serving on port `30000`
|
||||
* sized to use most of the 4090 VRAM
|
||||
* comment suggests it was intended for "oh-my-opencode utility agents"
|
||||
* the script comments still reference `~/scripts/start-sglang.sh`, but the file currently lives in `~/sglang/bin/start-sglang.sh`
|
||||
* the venv is currently incomplete, so this script would not run without reinstalling `sglang`
|
||||
|
||||
### Unsloth (Docker)
|
||||
|
||||
* Shell history shows installation of the NVIDIA container toolkit followed by `docker run ... --gpus all unsloth/unsloth`.
|
||||
* Current Docker artifacts:
|
||||
* image present: `unsloth/unsloth:latest` (~40.8 GB)
|
||||
* stopped container: `brave_dewdney`
|
||||
* published ports: `8888`, `8000`, `2222`
|
||||
* bind mount: `/home/ben/work:/workspace/work`
|
||||
* Notes:
|
||||
* `/home/ben/work` is currently empty
|
||||
* only `/workspace/work` was bind-mounted, so data under `/workspace/.cache/huggingface` would have lived inside the container layer instead of a persistent host path
|
||||
* shell history/container environment included a hard-coded Jupyter password; do not reuse that pattern without rotating the credential and moving it into a safer secret/env file flow
|
||||
|
||||
### LocalAI Packaged / Ollama notes
|
||||
|
||||
* [[AI]] already contains notes for a `local-ai-packaged` stack with:
|
||||
* Open WebUI
|
||||
* n8n
|
||||
* Langfuse
|
||||
* Ollama
|
||||
* Qdrant
|
||||
* `python start_services.py --profile gpu-nvidia`
|
||||
* I did not find:
|
||||
* a local checkout of that repo on `lifebalance`
|
||||
* a `start_services.py` file on this PC
|
||||
* an installed `ollama` binary
|
||||
* matching running containers or service units
|
||||
* This likely refers to another machine, a deleted checkout, or a plan that was documented before the actual install happened.
|
||||
|
||||
### Related but separate artifacts
|
||||
|
||||
* `homefoam/local-ai-beepmill.code-workspace` points at a missing `../local-ai-beepmill` folder.
|
||||
* `code/homelab_tofu/vm_beepboop.tf` defines a `beepboop` VM on `proxmox1` with GPU passthrough, 12 GiB RAM, and a 150 GiB disk.
|
||||
* `beepboop` may have been intended as a separate AI host, but there is not enough evidence on `lifebalance` to say it was actually used for this stack.
|
||||
|
||||
## Gaps to resolve
|
||||
|
||||
These are the main unanswered execution details, not fundamental direction questions:
|
||||
|
||||
* pick the exact `sglang` container image/tag strategy for reproducible deployment
|
||||
* decide whether model files should be stored explicitly under `${AI_DATA_ROOT}/models` or primarily re-hydrated through Hugging Face cache paths
|
||||
* define the exact Compose profile/default-start behavior for `open-webui`
|
||||
* decide the local secret storage pattern outside git (`.env`, separate secret file, password manager, or similar)
|
||||
* define the minimum backup policy for `open-webui` state, exported manifests, and any future adapters/checkpoints
|
||||
* document the exact fresh-host prerequisite list before the first real deployment
|
||||
|
||||
## Working plan v1
|
||||
|
||||
### Planning assumptions
|
||||
|
||||
These are the current decisions for planning purposes:
|
||||
|
||||
* first success = a local-only inference API on `lifebalance`
|
||||
* phase 1 should be Docker-first
|
||||
* phase 1 should target `Qwen3 8B AWQ` first
|
||||
* `Open WebUI` should come after the `SGLang` API is working
|
||||
* `lifebalance` is now the canonical LLM host; `beepboop` is no longer the intended host for this project
|
||||
* use a custom large-data storage root from day 1 instead of tool defaults
|
||||
* plan for host recreation from the beginning
|
||||
* keep reproducible stack-definition files in a separate dedicated repo/worktree, not inside this KB repo
|
||||
* phase 1 should include:
|
||||
* OpenAI-style API access
|
||||
* model switching
|
||||
* a web UI
|
||||
* quantized models
|
||||
* training/fine-tuning should come later, not in the initial stack
|
||||
|
||||
### Recommended architecture
|
||||
|
||||
Use a phased hybrid approach:
|
||||
|
||||
* **Phase 1 baseline:** `SGLang + Open WebUI`
|
||||
* **Phase 2 convenience track:** add `Ollama` only if easier model switching and broader casual experimentation become more important
|
||||
* **Phase 3 training track:** keep `Unsloth` separate as an occasional training/fine-tuning workflow, not part of the always-on serving stack
|
||||
|
||||
### Why this is the current recommendation
|
||||
|
||||
* The primary goal is a strong local inference API, not just a chat UI.
|
||||
* `SGLang` fits that goal better than starting with an Ollama-first stack.
|
||||
* There is already evidence of prior `SGLang` experimentation on this machine, so this path builds on existing intent.
|
||||
* `Open WebUI` can still provide the human-facing UI without forcing Ollama to be the primary backend.
|
||||
* This keeps the first phase local-only while optimizing earlier for agent/tool use.
|
||||
|
||||
### Why not start with Ollama as the primary backend
|
||||
|
||||
* It is more convenient for casual local experimentation than for an API-first serving plan.
|
||||
* It may still be useful later, but it is no longer the best fit for the primary phase-1 objective.
|
||||
* We can add it later without redesigning the whole stack.
|
||||
|
||||
### Why not start with SGLang as the only component
|
||||
|
||||
* A web UI still matters in phase 1.
|
||||
* `Open WebUI` remains useful as the human-facing interface even if `SGLang` is the main backend.
|
||||
|
||||
### Why not start with Unsloth
|
||||
|
||||
* The first outcome should be reliable inference, not training.
|
||||
* Training adds larger storage, cache, dataset, and secret-management concerns.
|
||||
* Keeping training separate reduces operational complexity.
|
||||
|
||||
## Phased roadmap
|
||||
|
||||
### Phase 1 — stable local workstation stack
|
||||
|
||||
Goal: a local-only, Docker-managed baseline for everyday use.
|
||||
|
||||
Planned components:
|
||||
|
||||
* `sglang` for local model serving
|
||||
* `open-webui` as the follow-on chat/testing interface after the API baseline is working
|
||||
* persistent host directories for:
|
||||
* models
|
||||
* app data
|
||||
* logs
|
||||
* exported configuration
|
||||
|
||||
Success criteria:
|
||||
|
||||
* at least one primary quantized model is served reliably
|
||||
* the UI works locally on `lifebalance`
|
||||
* the API is usable by local scripts/tools and is documented as the canonical local endpoint
|
||||
* all services bind locally first, or are otherwise restricted to local use
|
||||
* storage locations are explicit and documented before large downloads begin
|
||||
|
||||
### Phase 2 — convenience and model-flexibility lane
|
||||
|
||||
Goal: add easier model switching and a broader casual-use path only if phase-1 usage shows it is worth the extra moving parts.
|
||||
|
||||
Planned changes:
|
||||
|
||||
* evaluate whether adding `Ollama` improves day-to-day experimentation enough to justify dual backends
|
||||
* keep `SGLang` as the canonical agent/API backend unless there is a good reason to change that
|
||||
* decide whether:
|
||||
* `Open WebUI` should talk to SGLang only
|
||||
* `Open WebUI` should talk to Ollama only
|
||||
* both backends should coexist for different purposes
|
||||
|
||||
Success criteria:
|
||||
|
||||
* any second backend has a clear purpose
|
||||
* model/API behavior is predictable and documented
|
||||
* added convenience does not make the core serving path harder to operate
|
||||
|
||||
### Phase 3 — training and fine-tuning lane
|
||||
|
||||
Goal: support occasional LoRA/fine-tuning experiments without destabilizing the serving stack.
|
||||
|
||||
Planned components:
|
||||
|
||||
* a separate `Unsloth` workflow
|
||||
* dedicated storage/caching locations for datasets, checkpoints, and Hugging Face assets
|
||||
* clear separation between:
|
||||
* always-on inference services
|
||||
* temporary experiment/training workloads
|
||||
|
||||
Success criteria:
|
||||
|
||||
* training artifacts persist outside disposable containers
|
||||
* secrets are not passed via shell history
|
||||
* training jobs do not accidentally overwrite or disrupt inference setup
|
||||
|
||||
## Planned implementation decisions
|
||||
|
||||
When work begins, prefer:
|
||||
|
||||
* one project directory for Compose files, env files, and documentation
|
||||
* one persistent storage root for models/caches/data
|
||||
* localhost-first networking before any LAN exposure
|
||||
* explicit secrets handling instead of shell-history passwords
|
||||
* one canonical source of truth in this note for ports, paths, and services
|
||||
|
||||
### Recommended storage layout
|
||||
|
||||
Use a configurable storage root variable instead of hard-coding paths throughout the stack.
|
||||
|
||||
Recommended current value on `lifebalance`:
|
||||
|
||||
```shell
|
||||
AI_DATA_ROOT=/home/ben/llm-data
|
||||
```
|
||||
|
||||
Recommended layout under that root:
|
||||
|
||||
```text
|
||||
${AI_DATA_ROOT}/
|
||||
models/ # durable model files when not using opaque tool defaults
|
||||
huggingface/ # HF cache and downloads
|
||||
sglang/ # SGLang-specific state/config
|
||||
open-webui/ # Open WebUI persistent app data
|
||||
logs/ # service logs kept outside containers
|
||||
exports/ # saved manifests, model lists, config exports
|
||||
scratch/ # temporary working area
|
||||
```
|
||||
|
||||
Rationale:
|
||||
|
||||
* `lifebalance` has a large `/home` logical volume, so `/home/ben/llm-data` is a practical first location.
|
||||
* The path should still be treated as configurable so another host can recreate the same setup with a different mount point.
|
||||
* The important invariant is the directory structure and variable name, not the literal absolute path.
|
||||
|
||||
### Reproducibility-first approach
|
||||
|
||||
Treat the AI stack as something that should be rebuildable on a fresh host with minimal guesswork.
|
||||
|
||||
Preferred pattern:
|
||||
|
||||
* one small project directory for the stack definition
|
||||
* one configurable data root for persistent state
|
||||
* one env file for host-specific values
|
||||
* one setup note as the source of truth for how the stack is intended to work
|
||||
|
||||
### Project repo and workflow pivot
|
||||
|
||||
The implementation repo now exists at:
|
||||
|
||||
* `/home/ben/code/ai-stack`
|
||||
|
||||
Current repo state:
|
||||
|
||||
* git repo initialized
|
||||
* default branch set to `main`
|
||||
* OpenSpec initialized in the repo
|
||||
* tool integrations generated for `codex` and `opencode`
|
||||
* first OpenSpec change created: `bootstrap-local-ai-stack`
|
||||
|
||||
Repository intent:
|
||||
|
||||
* `openspec/` becomes the spec/change-management home for implementation work
|
||||
* this Foam note remains the KB-facing planning and operator-context note
|
||||
* implementation artifacts should now be tracked in the repo, with this note linking back to them as needed
|
||||
|
||||
Current OpenSpec structure in the repo:
|
||||
|
||||
```text
|
||||
/home/ben/code/ai-stack/
|
||||
README.md
|
||||
openspec/
|
||||
changes/
|
||||
bootstrap-local-ai-stack/
|
||||
proposal.md
|
||||
design.md
|
||||
tasks.md
|
||||
specs/
|
||||
local-ai-stack/
|
||||
spec.md
|
||||
specs/
|
||||
.codex/
|
||||
.opencode/
|
||||
```
|
||||
|
||||
Operational implication:
|
||||
|
||||
* future concrete stack work should start as OpenSpec changes in `ai-stack`
|
||||
* Foam should reference the repo and summarize decisions, rather than becoming the only place where implementation structure lives
|
||||
* the current baseline implementation change is `openspec/changes/bootstrap-local-ai-stack/`
|
||||
|
||||
## Stack definition v1
|
||||
|
||||
This is the concrete definition for the separate stack repo/worktree that now exists outside this KB at `/home/ben/code/ai-stack`.
|
||||
|
||||
### Scope of v1
|
||||
|
||||
Include in v1:
|
||||
|
||||
* one Docker Compose stack definition repo called `ai-stack`
|
||||
* one always-on inference service: `sglang`
|
||||
* one follow-on UI service: `open-webui`
|
||||
* one shared host data root: `${AI_DATA_ROOT}`
|
||||
* localhost-only published ports by default
|
||||
* enough docs and templates to recreate the stack on another host
|
||||
|
||||
Do **not** include in v1:
|
||||
|
||||
* `ollama`
|
||||
* `unsloth`
|
||||
* training jobs
|
||||
* public LAN exposure by default
|
||||
* extra observability/services unless a real need appears
|
||||
|
||||
### Service topology
|
||||
|
||||
```text
|
||||
local tools / scripts
|
||||
|
|
||||
v
|
||||
127.0.0.1:30000
|
||||
sglang API
|
||||
|
|
||||
+---- model weights / HF cache / logs under ${AI_DATA_ROOT}
|
||||
|
||||
127.0.0.1:3001
|
||||
Open WebUI
|
||||
|
|
||||
v
|
||||
talks to sglang over local Docker networking or local host endpoint
|
||||
```
|
||||
|
||||
Operational intent:
|
||||
|
||||
* `sglang` is the canonical local inference backend
|
||||
* `open-webui` is a convenience client on top of that backend, not the center of the stack
|
||||
* if `open-webui` breaks, the API stack should still be usable directly
|
||||
|
||||
### Repo/worktree layout
|
||||
|
||||
```text
|
||||
ai-stack/
|
||||
compose.yaml
|
||||
.env.example
|
||||
.gitignore
|
||||
README.md
|
||||
docs/
|
||||
architecture.md
|
||||
recovery-checklist.md
|
||||
model-inventory.md
|
||||
sglang/
|
||||
launch.env.example
|
||||
notes.md
|
||||
open-webui/
|
||||
notes.md
|
||||
scripts/
|
||||
preflight-checklist.md
|
||||
```
|
||||
|
||||
File intent:
|
||||
|
||||
* `compose.yaml` = the canonical service definition
|
||||
* `.env.example` = documented host-specific variables with placeholder values only
|
||||
* `.gitignore` = protect `.env`, logs, caches, exports, and downloaded assets from accidental commits
|
||||
* `README.md` = operator-first quickstart for bring-up, shutdown, update, and rebuild
|
||||
* `docs/architecture.md` = why the stack is shaped this way
|
||||
* `docs/recovery-checklist.md` = fresh-host rebuild order
|
||||
* `docs/model-inventory.md` = canonical list of intended models/adapters and where they are expected to come from
|
||||
* `sglang/launch.env.example` = model/server launch parameters that may vary by host or model choice
|
||||
* `sglang/notes.md` = operational notes for the inference service
|
||||
* `open-webui/notes.md` = operational notes for the UI layer
|
||||
* `scripts/preflight-checklist.md` = manual prerequisites/validation list before first start
|
||||
|
||||
### Compose contract
|
||||
|
||||
Initial Compose services:
|
||||
|
||||
* `sglang`
|
||||
* required in v1
|
||||
* NVIDIA-enabled container
|
||||
* publishes `127.0.0.1:30000:30000`
|
||||
* mounts model/cache/state/log paths from `${AI_DATA_ROOT}`
|
||||
* uses `Qwen/Qwen3-8B-AWQ` as the first default model
|
||||
* should be startable independently of any UI
|
||||
* `open-webui`
|
||||
* optional during initial API bring-up, but part of the v1 repo definition
|
||||
* publishes `127.0.0.1:3001:8080`
|
||||
* persists app state under `${AI_DATA_ROOT}/open-webui`
|
||||
* points at the existing `sglang` OpenAI-compatible endpoint
|
||||
|
||||
Recommended Compose profiles:
|
||||
|
||||
* default / baseline: `sglang`
|
||||
* optional UI profile: `open-webui`
|
||||
|
||||
Meaning:
|
||||
|
||||
* the inference API can come up first by itself
|
||||
* the UI can be layered on later without redefining the stack
|
||||
|
||||
### Host path contract
|
||||
|
||||
`AI_DATA_ROOT` remains the root for all durable local state.
|
||||
|
||||
```text
|
||||
${AI_DATA_ROOT}/
|
||||
models/ # model files if intentionally stored outside tool-managed caches
|
||||
huggingface/ # HF_HOME / HF hub cache
|
||||
sglang/ # sglang-specific state, configs, temp runtime data
|
||||
open-webui/ # persistent UI state
|
||||
logs/ # host-visible logs
|
||||
exports/ # inventories, backup manifests, saved config exports
|
||||
scratch/ # temporary manual work area
|
||||
```
|
||||
|
||||
Path rules:
|
||||
|
||||
* containers should only write durable state inside `${AI_DATA_ROOT}`
|
||||
* container-internal default paths should be overridden where practical
|
||||
* logs worth keeping should land on the host, not only inside container stdout history
|
||||
|
||||
### Env contract
|
||||
|
||||
The real `.env` should stay outside git. `.env.example` should document the contract.
|
||||
|
||||
Expected variables for v1:
|
||||
|
||||
```dotenv
|
||||
AI_DATA_ROOT=/home/ben/llm-data
|
||||
SGLANG_HOST_PORT=30000
|
||||
OPEN_WEBUI_HOST_PORT=3001
|
||||
SGLANG_MODEL=Qwen/Qwen3-8B-AWQ
|
||||
SGLANG_CONTEXT_LENGTH=32768
|
||||
SGLANG_MEM_FRACTION_STATIC=0.88
|
||||
SGLANG_DTYPE=auto
|
||||
HF_HOME=/home/ben/llm-data/huggingface
|
||||
OPEN_WEBUI_DATA_DIR=/home/ben/llm-data/open-webui
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
* secrets should be added only if/when a service actually needs them
|
||||
* avoid putting host-specific absolute paths directly into `compose.yaml` when a variable will do
|
||||
* if another host replaces `lifebalance`, the main required change should be env values, not Compose structure
|
||||
|
||||
### Canonical endpoints and names
|
||||
|
||||
Use these as the first-pass defaults unless execution reveals a conflict:
|
||||
|
||||
* stack repo/worktree name: `ai-stack`
|
||||
* primary service name: `sglang`
|
||||
* UI service name: `open-webui`
|
||||
* canonical local inference endpoint: `http://127.0.0.1:30000/v1`
|
||||
* canonical local UI URL: `http://127.0.0.1:3001`
|
||||
* primary model identifier: `Qwen/Qwen3-8B-AWQ`
|
||||
|
||||
### Operating rules for v1
|
||||
|
||||
* prefer explicit image tags over floating `latest` where possible
|
||||
* prefer localhost binding over broad exposure
|
||||
* keep `sglang` usable without `open-webui`
|
||||
* treat model downloads as reproducible inputs, not irreplaceable state
|
||||
* treat UI state, manifests, and future adapters/checkpoints as state worth intentional preservation
|
||||
* do not add routing until there is a real second-model need
|
||||
|
||||
### Future extension points
|
||||
|
||||
Planned later, but not part of the initial stack definition:
|
||||
|
||||
* `ollama` as a separate convenience lane if model switching becomes more valuable than keeping one backend
|
||||
* a routing/gateway layer only after there are multiple active model backends to justify it
|
||||
* `unsloth` as a separate workflow/repo path for training or fine-tuning
|
||||
|
||||
### What should be reproducible vs backed up
|
||||
|
||||
Rebuildable from config:
|
||||
|
||||
* container definitions
|
||||
* image tags
|
||||
* port mappings
|
||||
* bind mounts
|
||||
* service-level configuration
|
||||
* startup commands
|
||||
* model identifiers to download
|
||||
|
||||
Back up or preserve intentionally:
|
||||
|
||||
* secrets outside git
|
||||
* exported model inventory/manifests
|
||||
* any local UI/app data worth keeping
|
||||
* any future training outputs, datasets, adapters, or checkpoints
|
||||
|
||||
Usually re-download instead of backing up:
|
||||
|
||||
* public base model weights
|
||||
* Hugging Face cache contents
|
||||
* container images
|
||||
|
||||
Optional exception:
|
||||
|
||||
* if download time becomes painful, a local backup of model files may still be worth doing, but that should be a conscious backup policy rather than an accident of where files ended up
|
||||
|
||||
### What belongs in git vs not in git
|
||||
|
||||
Commit:
|
||||
|
||||
* Compose files
|
||||
* config templates
|
||||
* `.env.example`
|
||||
* setup scripts that do not contain secrets
|
||||
* documentation, recovery notes, and model manifests
|
||||
|
||||
Never commit:
|
||||
|
||||
* `.env` with real values
|
||||
* API tokens, auth secrets, passwords
|
||||
* downloaded model weights
|
||||
* Hugging Face cache directories
|
||||
* logs
|
||||
* databases/app state unless deliberately exporting sanitized fixtures
|
||||
|
||||
## Implementation checklist (draft)
|
||||
|
||||
This is a future execution checklist only. It does **not** mean these steps have been performed yet.
|
||||
|
||||
### 1. Create the reproducible stack-definition repo/worktree
|
||||
|
||||
- [ ] create a dedicated repo/worktree for the AI stack definition
|
||||
- [ ] add `compose.yaml`
|
||||
- [ ] add `.env.example`
|
||||
- [ ] add a `README.md` with recovery/rebuild instructions
|
||||
- [ ] add config templates for `sglang` and later `open-webui`
|
||||
- [ ] add `.gitignore` rules for secrets, logs, caches, and downloaded assets
|
||||
|
||||
### 2. Define host-specific variables and conventions
|
||||
|
||||
- [ ] define `AI_DATA_ROOT`
|
||||
- [ ] define canonical service names, ports, and container names
|
||||
- [ ] define the canonical local API endpoint for `sglang`
|
||||
- [ ] define where logs should live on the host
|
||||
- [ ] define the host-specific values that belong in `.env` rather than in committed files
|
||||
|
||||
### 3. Create the persistent storage layout
|
||||
|
||||
- [ ] create `${AI_DATA_ROOT}`
|
||||
- [ ] create `${AI_DATA_ROOT}/models`
|
||||
- [ ] create `${AI_DATA_ROOT}/huggingface`
|
||||
- [ ] create `${AI_DATA_ROOT}/sglang`
|
||||
- [ ] create `${AI_DATA_ROOT}/open-webui`
|
||||
- [ ] create `${AI_DATA_ROOT}/logs`
|
||||
- [ ] create `${AI_DATA_ROOT}/exports`
|
||||
- [ ] create `${AI_DATA_ROOT}/scratch`
|
||||
- [ ] document ownership/permissions expectations for these paths
|
||||
|
||||
### 4. Prepare secrets and env handling
|
||||
|
||||
- [ ] decide how local secrets will be stored outside git
|
||||
- [ ] create `.env` from `.env.example`
|
||||
- [ ] ensure no passwords or tokens are passed through shell history
|
||||
- [ ] document which values are required for a fresh-host rebuild
|
||||
|
||||
### 5. Stand up the SGLang API baseline
|
||||
|
||||
- [ ] define the `sglang` image/tag strategy
|
||||
- [ ] define bind mounts for model/cache/log locations
|
||||
- [ ] define the startup command for `Qwen3 8B AWQ`
|
||||
- [ ] keep networking local-only by default
|
||||
- [ ] document how the service is started, stopped, restarted, and updated
|
||||
- [ ] document how the model is fetched or made available reproducibly
|
||||
|
||||
### 6. Validate the API baseline
|
||||
|
||||
- [ ] confirm the service starts cleanly
|
||||
- [ ] confirm the model loads successfully on the 4090
|
||||
- [ ] confirm the local OpenAI-compatible endpoint works
|
||||
- [ ] confirm logs are written to the expected host path
|
||||
- [ ] document basic smoke tests for future rebuild validation
|
||||
|
||||
### 7. Add Open WebUI after the API baseline is stable
|
||||
|
||||
- [ ] add `open-webui` to the stack-definition repo/worktree
|
||||
- [ ] bind its persistent data to `${AI_DATA_ROOT}/open-webui`
|
||||
- [ ] connect it to the existing `sglang` API
|
||||
- [ ] document the intended UI URL and local-only access model
|
||||
- [ ] document what configuration is UI state vs committed config
|
||||
|
||||
### 8. Capture disaster-recovery details
|
||||
|
||||
- [ ] document host prerequisites required before stack deployment
|
||||
- [ ] document the exact rebuild order on a fresh machine
|
||||
- [ ] document what must be restored from backup vs re-downloaded
|
||||
- [ ] export a model/config inventory into `${AI_DATA_ROOT}/exports`
|
||||
- [ ] add a short recovery checklist for "lifebalance died, rebuild elsewhere"
|
||||
|
||||
### 9. Leave room for later phases
|
||||
|
||||
- [ ] define how a future `ollama` lane would coexist without replacing `sglang` as the primary API
|
||||
- [ ] define how a future `unsloth` workflow would keep training artifacts separate from inference services
|
||||
- [ ] document what additional storage/backup policy would be needed for adapters, datasets, and checkpoints
|
||||
|
||||
|
||||
[AI]: AI.md "AI"
|
||||
[homelab]: homelab.md "homelab"
|
||||
@@ -0,0 +1,70 @@
|
||||
# tmux
|
||||
|
||||
Terminal multiplexer configuration managed via [[chezmoi]].
|
||||
|
||||
## Configuration
|
||||
|
||||
`~/.tmux.conf` - sourced from chezmoi at `~/.local/share/chezmoi/dot_tmux.conf`
|
||||
|
||||
```conf
|
||||
# TPM - Tmux Plugin Manager
|
||||
set -g @plugin 'tmux-plugins/tpm'
|
||||
set -g @plugin 'tmux-plugins/tmux-sensible'
|
||||
|
||||
# Session persistence
|
||||
set -g @plugin 'tmux-plugins/tmux-resurrect'
|
||||
set -g @plugin 'tmux-plugins/tmux-continuum'
|
||||
|
||||
# Resurrect options
|
||||
set -g @resurrect-capture-pane-contents 'on'
|
||||
|
||||
# Continuum options
|
||||
set -g @continuum-restore 'on'
|
||||
set -g @continuum-save-interval '15'
|
||||
|
||||
# Initialize TPM (must be at the bottom)
|
||||
run '~/.tmux/plugins/tpm/tpm'
|
||||
|
||||
# Base settings
|
||||
set-option -g mouse
|
||||
set-window-option -g window-size latest
|
||||
set-window-option -g aggressive-resize on
|
||||
```
|
||||
|
||||
## Plugins
|
||||
|
||||
### TPM (Tmux Plugin Manager)
|
||||
Plugin manager for tmux. Install new plugins by adding them to `.tmux.conf` then pressing `prefix + I`.
|
||||
|
||||
### tmux-sensible
|
||||
Basic settings that most tmux users want. Included by default.
|
||||
|
||||
### tmux-resurrect
|
||||
Saves and restores tmux environment after restart.
|
||||
|
||||
- `prefix + Ctrl-s` - Save current environment
|
||||
- `prefix + Ctrl-r` - Restore last save
|
||||
|
||||
Saves: sessions, windows, panes, layouts, working directories, running programs
|
||||
|
||||
### tmux-continuum
|
||||
Automatic saving and restoring. Requires tmux-resurrect.
|
||||
|
||||
- Auto-saves every 15 minutes (configurable via `@continuum-save-interval`)
|
||||
- Auto-restores on tmux start when `@continuum-restore 'on'`
|
||||
|
||||
Saves stored in `~/.tmux/resurrect/` (~5KB per save)
|
||||
|
||||
## Base Settings
|
||||
|
||||
| Setting | Description |
|
||||
|---------|-------------|
|
||||
| `mouse` | Enable mouse support (click, scroll, resize) |
|
||||
| `window-size latest` | Use newest window size when creating new windows |
|
||||
| `aggressive-resize` | Aggressively resize windows to fit smallest client |
|
||||
|
||||
## Installation
|
||||
|
||||
After updating `.tmux.conf`:
|
||||
1. Reload config: `tmux source-file ~/.tmux.conf`
|
||||
2. Install plugins: press `prefix + I` inside tmux
|
||||
@@ -0,0 +1,25 @@
|
||||
---
|
||||
created: 2025-08-20T11:26:28-06:00
|
||||
modified: 2026-07-15T14:44:40-06:00
|
||||
---
|
||||
|
||||
# to watch
|
||||
|
||||
- [x] Department Q
|
||||
- [ ] Superman
|
||||
- [ ] Thunderbolts
|
||||
- [x] Alien Earth
|
||||
- [ ] Honey Don't
|
||||
- [ ] Loki season 2
|
||||
- [ ] The Naked Gun
|
||||
- [ ] Decameron
|
||||
- [ ] The Death of Stalin
|
||||
- [ ] Love Lies Bleeding
|
||||
- [ ] Fleabag
|
||||
- [ ] The Midnight Hour
|
||||
- [ ] Paprika
|
||||
- [ ] What We Do In The Shadows
|
||||
- [x] Bugonia
|
||||
- [ ] Beef
|
||||
- [ ] Parasite
|
||||
- [ ] The Killings at Parish Station
|
||||
Reference in New Issue
Block a user