617 lines
21 KiB
Markdown
617 lines
21 KiB
Markdown
|
|
# 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"
|