Read this before you kill, restart, or GPU-starve anything. eiDOS now runs on Sprinter, a Linux box supervised by systemd.
CLAUDE.md's run/restart discipline (nssm services,Restart-Service EidosDashboard,taskkill, PowerShell, "the mind needs ~15.7 GB") describes the OLD Windows host and is wrong here. This file is the source of truth for the live runtime. Authored: 2026-07-03, from live inspection. Update it when the topology changes.
⚠ HISTORICAL — a
cmod-sdeployment window (2026-07-18) that has since been REVERTED. For a stretch the software ran oncmod-s(dual Tesla P100, 32 GB; llama-swap @:9292; gemma-4-12b-it Q8_0 at 262144 ctx / f16 KV;llama-embedding.service; models in/home/cmod/models/; vision disabled for want of thegemma4uvCLIP projector). That is no longer where eiDOS lives. The live host is Sprinter again — RTX 5080 16 GB, llama-swap @:8080, gemma4-12b at 32k ctx, embeddereidos-embed.service@:8082, models in/home/cmod/llm/models/— i.e. exactly the body of this file, below.cmod-sis a separate machine still reachable on the tailnet; it is not this box. (Verified 2026-07-25 on Sprinter;CLAUDE.mdagrees. Kept as a record so the:9292/P100 numbers in older notes and heirlooms are traceable to a real past, not read as current fact.)
- Host: Sprinter · OS: Pop!_OS 24.04 LTS · GPU: RTX 5080, 16 GB · User:
cmod sudois passwordless forcmod— you can stop/start the system services yourself.- Desktop is COSMIC (Wayland);
cosmic-*+claude-desktophold ~1.3 GB of GPU on their own.
A bare kill/pkill of these processes does nothing lasting — systemd respawns them in seconds
(new PID). You must go through systemctl. (Units live in /etc/systemd/system/.)
| Service | Supervises | Listen | Restart | Notes |
|---|---|---|---|---|
eidos-dashboard.service |
dashboard.py — which itself spawns/watchdogs the eidos.py tick loop as a child |
dashboard :8099 | always, 10 s | There is no separate eidos.service; the dashboard is the supervisor. WorkingDirectory=/home/cmod/Documents/Software/eiDOS, runs the repo venv. EIDOS_SUPERVISED deliberately unset → the dashboard Start button restarts the tick loop in place; systemctl restart is what hot-reloads dashboard.py itself. |
llama-swap.service |
llama-swap (:8080), which boots a llama-server child on demand |
swap :8080, child on a dynamic port (e.g. 5801) | always, 5 s | Lazy: loads NO model at startup; first /v1/chat/completions for a model boots it. LD_LIBRARY_PATH=/usr/local/cuda-13.0/lib64. |
eidos-embed.service |
a dedicated llama-server --embedding |
embeddings :8082 | always, 5 s | Semantic recall. nomic-embed-text-v1.5.Q8_0.gguf (768-dim, ~140 MB), full offload, resident in spare VRAM alongside the mind (~0.4 GB). NOT in llama-swap: llama-swap keeps one model resident, so routing embeddings through it would swap out gemma. embedding.py POSTs to :8082/v1/embeddings; enabled via [knowledge] embedding_enabled=true in config.local.toml. Unit template: /home/cmod/llm/deploy/eidos-embed.service. |
systemd(1)
├─ eidos-dashboard.service → dashboard.py (:8099, the watchdog) ──spawns──▶ eidos.py (the tick loop, child)
├─ llama-swap.service → llama-swap (:8080, router) ──spawns──▶ llama-server (one model, dynamic port)
└─ eidos-embed.service → llama-server (:8082, --embedding, nomic 768-dim, resident in spare VRAM)
eiDOS reaches the model directly at http://127.0.0.1:8080 (set in config.local.toml, overriding
config.toml's :8088). The Windows-era monitor tap (:8088), voice (:8098), and IDE (:8100) are NOT
running on Sprinter — don't assume they exist.
Only one model resident at a time (they share the 16 GB serially). ttl: 0 = stay resident.
gemma4-12b— the house mind.gemma-4-12b-it-qat-q4_0.gguf(~6.5 GB) + vision mmproj,-ngl 99(full offload),-c 16384. This is eiDOS's primary model. (Note: ~6.5 GB, not the 15.7 GB CLAUDE.md quotes for the old box — there is real VRAM headroom here.)qwen27b—Qwen_Qwen3.6-27B-Q5_K_L.gguf(~21 GB), partial offload-ngl 30(rest on CPU),-c 8192. Slower; used when selected by name.- Models dir:
/home/cmod/llm/models/. Swap binary + config:/home/cmod/llm/llama-swap/. llama.cpp build:/home/cmod/llm/src/llama.cpp/build/bin/llama-server.
# STOP eiDOS entirely (dashboard + its child tick loop):
sudo systemctl stop eidos-dashboard.service
# FREE ALL VRAM (for an eval / GPU spike): stop the requester, then unload the model.
sudo systemctl stop eidos-dashboard.service # no more LLM requests
sudo systemctl stop llama-swap.service # unloads the resident llama-server child
# ...do your GPU work...
sudo systemctl start llama-swap.service eidos-dashboard.service # restore (eidos boots PAUSED by design)
# RESTART the dashboard CODE (hot-reload dashboard.py):
sudo systemctl restart eidos-dashboard.service
# RESTART just the eidos tick loop, keep the dashboard up:
# use the dashboard Start button / POST http://127.0.0.1:8099/api/control/resume,
# or kill the eidos CHILD pid (the dashboard watchdog respawns it on fresh code).
# Do NOT kill the dashboard for this — that stops the supervisor.
# STATUS / LOGS:
systemctl status eidos-dashboard.service llama-swap.service
journalctl -u eidos-dashboard.service -n 100 --no-pager
# FRESH SLATE (retire the creature, birth a new one — archive workspace, reseed nuggets +
# genesis quests, restart on fresh code, boot PAUSED). Never hand-roll this: the watchdog
# respawns eidos, so the workspace swap must happen with the dashboard STOPPED.
scripts/fresh_slate.sh- Growth panel (
GET :8099/api/growth, built bygrowth.build_growth): the read-only D1–D12 dream-test scoreboard (D1–D10 from PILLARS_PLAN §10; D11 "lives outward" and D12 "memory stays clean" added by HABITAT_PLAN WS5/WS6) + KPI trends + raw vitals, aggregated from existing workspace/state stores. Every metric carries{value, status(measured|unmeasured|human-judged), basis}and is fail-open — it never fakes a number and never crashes on a missing store. The creature can't see this panel (operator-only); it replaces the by-hand functional-review tally.
- Installed 2026-07-10:
/usr/bin/pi(@earendil-works/pi-coding-agent, npm -g, Node 22 from NodeSource). The delegate spawns it detached; result returns tagged[↩ delegate N]. - Provider:
~/.pi/agent/models.jsondefines thehouseprovider → llama-swaphttp://127.0.0.1:8080/v1(OpenAI-compatible), modelsgemma4-12b(default) andqwen27b. Telemetry off in~/.pi/agent/settings.json. - Config:
[delegate]in config.toml (pi_provider = "house",pi_model = "gemma4-12b",pi_path = ""→ PATH). Verified end-to-end: tool_delegate → pi → gemma → runnable artifact.
Restart=always:kill/taskkill/pkill→ systemd relaunches in seconds. Usesystemctl stop.pgrep -f "eidos.py --config"matches your own shell (the pattern is in your command line) — it returns your subshell's PID too, so akill $(pgrep …)can SIGTERM yourself. Use the bracket trick:ps -eo pid,args | grep "[e]idos.py".- eidos boots PAUSED by design (kill-switch). After a start/restart it won't act until resumed
("GO" in the dashboard chat, or
POST :8099/api/control/resume). A plain crash-respawn resumes running. - VRAM budget: gemma (~6.5 GB) leaves ~8 GB free after desktop; qwen27b (~10.6 GB resident w/ partial
offload) leaves only ~3 GB. Check
nvidia-smibefore launching a second llama-server. - CLAUDE.md is Windows-era. Ignore its nssm/
Restart-Service/taskkill/PowerShell instructions on Sprinter; this file supersedes them for the runtime.
The mind now serves at -c 32768, FULL-PRECISION f16 KV, -fa on, -ngl omitted — live and
verified (clean generation + 8k-prompt smoke, ~1.07 GB free with the embedder co-loaded). This is
the SYSTEM DEFAULT for gemma-4-12b @32k on any 16 GB card (memory: gemma-32k-16gb-serving-default).
The serving change and the config budgets are a PAIR (coherence rule:
n_ctx >= max_total_chars/chars_per_token + response_reserve).
The gemma entry cmd: in /home/cmod/llm/llama-swap/config.yaml (as landed):
-c 32768 --parallel 1 -fa on
--cache-type-k f16 --cache-type-v f16
--jinja --reasoning-budget 1000
Why full-precision KV (not q8_0): gemma's sliding-window attention makes the KV tiny (~700 MiB
f16 @32k), so full precision fits without quantization — and it lands at the same ~1 GB free as
q8_0, because q8_0's flash-attention compute buffer offsets its KV savings. So we keep the best
attention quality at zero headroom cost. (q8_0 KV is a tested fallback; f16-without--fa also works
at identical VRAM. No reason to prefer either over f16+fa.)
Three hard-won gotchas on this llama.cpp build (each cost a debugging loop — don't relearn them):
-fa onis two tokens ([on|off|auto]) on this build. Bare-faeats the next arg (error: unknown value for --flash-attn: '--cache-type-k').- Omit
-nglentirely. With-fa on, this build runs a memory auto-fitter that ABORTS if n_gpu_layers is pinned (failed to fit params ... ngl already set to 99, abort→ upstream dies in ~265 ms; llama-swap only reports "upstream command exited prematurely" and swallows the real stderr — setlogLevel: debugto see the spawned command). Without the pin the fitter places layers itself; the 12.7 GB model fits, so all layers still offload to GPU. --reasoning-budget 1000returns empty content for SHORT generations (reasoning eats a smallmax_tokens). Test withmax_tokens: 200, not a tiny value — empty ≠ broken.
Procedure for a rebuild: sudo systemctl stop llama-swap.service → edit the entry as above →
sudo systemctl start → force a load (curl … /v1/chat/completions with max_tokens:200) →
nvidia-smi wants ≥ ~800 MiB free with the desktop up → one ~8k-token-prompt smoke.
Fallback if headroom is thin on a busier desktop: -c 24576. Config backup: config.yaml.bak-pre32k.
The paired budgets (dashboard Settings or config.local.toml), applied WITH the serving flip:
[context]
obs_max_chars = 44000
memory_max_chars = 16000
intelligence_max_chars = 8000
interventions_max_chars = 8000
max_total_chars = 76000
[compaction]
token_threshold = 11000
obs_max_chars = 32000
[wisdom]
block_max_chars = 1400(~19k prompt tokens + ~5k response reserve under 32768 at chars_per_token 4.0 — the same
margin discipline as the 16k sizing.) Restart eidos (dashboard Start) to pick them up.
6. Rollback = revert the yaml entry + remove the overlay keys. Two stale-doc notes while
you're in here: the committed config.toml [llm] block (:9292 / dual P100 / 262k ctx) is a
cmod-s fossil — the local overlay (:8080, gemma4-12b) is what serves on Sprinter; and
the "~6.5 GB gemma" figure above predates the Q8_0 model (12.7 GB). Trust nvidia-smi.
eidos-wisdom-curve.timer→eidos-wisdom-curve.service→scripts/run_wisdom_curve.sh(one-shot,OnCalendar=2026-07-27 03:00, Persistent). Fires ~1 week after the 2026-07-20 wisdom activation to capture the first wise-vs-naive experience-curve datapoint. The wrapper PAUSES the creature (the 3-arm curve needs the GPU to itself; the 27b arm evicts gemma), runswisdom_curve.py --run, then restores it (start+resume). Results →state/wisdom_curve.jsonl+workspace/wisdom_curve_*.log. Inspect:systemctl list-timers eidos-wisdom-curve.timer. Retime: edit/etc/systemd/system/eidos-wisdom-curve.timer+daemon-reload. Cancel:sudo systemctl disable --now eidos-wisdom-curve.timer. Run now by hand:bash scripts/run_wisdom_curve.sh.