# nh3-svos -> SVOS v0.0.16 (b51aa5e): kernel 0.0.16, UI 0.0.20, NEW app-judge 0.0.1 (U19; contract § Deployment). # Prime 2026-10-18 ~0933 "go with your picks, cut over now": drafting model gen-large; tasks may run on the six local # chat models. PRE-REQS (done before this playbook): the stage playbook; /root/svos-judge-enroll (mint-secret, root 0600); # /etc/svos/judge.env holding SVOS_JUDGE_GATEWAY_KEY (LiteLLM svos-app-judge, vault nh3-svos/svos-judge-gateway-key). # This playbook: install unit + judge.toml + quiesce entry; stop; backup; switch; config ([[apps]] app-judge, hermes # `models`); start; enrol (credential appended to judge.env + printed NOWHERE); start the judge; front door. # AFTER: Prime's three owner grants (svos-dev's console snippet), then [tasks].judge = "app-judge" + reload. steps: - name: Pre-reqs present sudo: true shell: test -f /opt/svos/releases/b51aa5e/apps-env/bin/svos-judge && test -s /root/svos-judge-enroll && grep -q '^SVOS_JUDGE_GATEWAY_KEY=' /etc/svos/judge.env && ! grep -q '^SVOS_APP_CREDENTIAL=' /etc/svos/judge.env changed_when: "false" - {name: judge unit, upload: {src: configs/svos-apps/svos-judge.service, dest: /etc/systemd/system/svos-judge.service, mode: "0644"}, sudo: true} - {name: judge config, upload: {src: configs/svos-apps/judge.toml, dest: /var/lib/svos/config/apps/judge.toml, mode: "0600"}, sudo: true} - name: judge.toml owned by svc-svos; quiesce hook lists svos-judge; daemon-reload sudo: true shell: | set -e chown svc-svos:svc-svos /var/lib/svos/config/apps/judge.toml h=/etc/qemu/fsfreeze-hook.d/50-svos grep -q "svos-judge.service" $h || { cp -p $h $h.pre-judge; sed -i "s/'svos-postoffice.service', 'svos-voice.service')/'svos-postoffice.service', 'svos-voice.service', 'svos-judge.service')/" $h; } grep -n "svos-judge.service" $h; python3 -m py_compile $h 2>/dev/null || python3 -c "import ast,sys; ast.parse(open('$h').read())" systemctl daemon-reload - name: Stop the local apps then the kernel sudo: true shell: systemctl stop svos-voice svos-knowledge svos-interface svos-kernel; systemctl is-active svos-kernel svos-interface svos-knowledge svos-voice | tr '\n' ' '; echo - name: Offline backup to /var/lib/svos/backup/pre-b51aa5e sudo: true shell: | set -e d=/var/lib/svos/backup/pre-b51aa5e runuser -u svc-svos -- install -d -m 0700 $d runuser -u svc-svos -- python3 -c " import sqlite3 s = sqlite3.connect('/var/lib/svos/state/svos.db'); t = sqlite3.connect('$d/svos.db'); s.backup(t); t.close(); s.close() c = sqlite3.connect('file:$d/svos.db?mode=ro', uri=True); print('integrity', c.execute('pragma integrity_check').fetchone()[0], 'user_version', c.execute('pragma user_version').fetchone()[0])" runuser -u svc-svos -- cp -p /var/lib/svos/config/instance.toml /var/lib/svos/config/instance.toml.pre-b51aa5e - name: Switch current to b51aa5e sudo: true shell: ln -sfn /opt/svos/releases/b51aa5e /opt/svos/current.new && chgrp -h svc-svos /opt/svos/current.new && mv -T /opt/svos/current.new /opt/svos/current && readlink /opt/svos/current - name: Config - [[apps]] app-judge (enrollment sha256 from the minted secret) + the hermes runtime's models; the new kernel must accept it (else restore + 57d90d6) sudo: true shell: | sha=$(sed -nE 's/^sha256 ([0-9a-f]{64})$/\1/p' /root/svos-judge-enroll); test ${#sha} -eq 64 runuser -u svc-svos -- python3 - "$sha" <<'PY' import os, sys sha = sys.argv[1] p = "/var/lib/svos/config/instance.toml"; s = open(p).read() assert 'slug = "app-judge"' not in s anchor = '[[apps]]\nslug = "app-knowledge"\n' assert s.count(anchor) == 1 add = ('[[apps]] # U19 (v0.0.16, 2026-10-18): the judge; enrolled once, unit svos-judge\n' 'slug = "app-judge"\nname = "Judge"\nbase_url = "http://127.0.0.1:8409"\nenrollment_sha256 = "' + sha + '"\n\n') s = s.replace(anchor, add + anchor) old = 'task_toolsets = ["terminal", "file"]\n' assert s.count(old) == 1 s = s.replace(old, old + '# 2026-10-18 (Prime): the chat models a task may run on (the /tasks select = the judge key\'s catalogue ∩ this list)\n' 'models = ["gen-large", "gen", "gen-reasoning", "gen-small", "sec", "sec-reasoning"]\n') t = p + ".tmp"; fd = os.open(t, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600) with os.fdopen(fd, "w") as f: f.write(s) os.replace(t, p); print("edited") PY if runuser -u svc-svos -- /opt/svos/releases/b51aa5e/kernel-env/bin/svos-kernel check-config --data-root /var/lib/svos; then exit 0; fi runuser -u svc-svos -- cp -p /var/lib/svos/config/instance.toml.pre-b51aa5e /var/lib/svos/config/instance.toml ln -sfn /opt/svos/releases/57d90d6 /opt/svos/current.new && chgrp -h svc-svos /opt/svos/current.new && mv -T /opt/svos/current.new /opt/svos/current systemctl start svos-kernel.service svos-interface svos-knowledge svos-voice; echo "RESTORED config + 57d90d6"; exit 1 - name: Start the kernel then the local apps sudo: true shell: | t0=$(date +%s.%N); systemctl start svos-kernel.service; rc=$?; t1=$(date +%s.%N) echo "kernel start rc=$rc after $(python3 -c "print(round($t1-$t0,2))") s" systemctl start svos-interface svos-knowledge svos-voice sleep 8; curl -s http://127.0.0.1:8400/health; echo - name: Enrol app-judge once; append the credential to judge.env (never printed); vault copy is done from nh3-dev sudo: true shell: | set -e grep -q '^SVOS_APP_CREDENTIAL=' /etc/svos/judge.env && { echo "already enrolled"; exit 0; } tok=$(sed -nE 's/^token (sve_[A-Za-z0-9_-]+)$/\1/p' /root/svos-judge-enroll) body=$(printf 'Authorization: Bearer %s\n' "$tok" | curl -s -X POST -H @- http://127.0.0.1:8400/auth/enroll) unset tok printf '%s' "$body" | python3 -c "import sys,json; d=json.load(sys.stdin); assert d['credential'].startswith('svc_'), 'no credential'; print('SVOS_APP_CREDENTIAL=' + d['credential'])" >> /etc/svos/judge.env printf '%s' "$body" | python3 -c "import sys,json; d=json.load(sys.stdin); print('enrolled principal', d.get('principal'), 'kind', d.get('kind'))" unset body; chmod 600 /etc/svos/judge.env; grep -oE '^[A-Z_]+=' /etc/svos/judge.env | tr '\n' ' '; echo - name: Start the judge (its first manifest pins without a card), then the front door sudo: true shell: | systemctl enable --now svos-judge; sleep 6; systemctl is-active svos-judge journalctl -u svos-judge --since "-60s" --no-pager -o cat | grep -iE "regist|manifest|pin|health|degraded|error" | tail -6 | cut -c1-200 /usr/local/sbin/svos-front-inventory 2>&1 | grep -E 'GENERATED|updated|root \*|path /assets' | head -4 verify: - name: Health schema 14 ok, nothing down shell: h=$(curl -s http://127.0.0.1:8400/health); echo "$h"; echo "$h" | grep -q '"status":"ok"' && echo "$h" | grep -q '"down":0' changed_when: "false" - name: Front door inventory current sudo: true shell: /usr/local/sbin/svos-front-inventory --check changed_when: "false"