Custom Scripts run as root on a schedule, so the expensive mistake is not
tangled logic — it is a simple script aimed one directory too high. The prompt
now asks for the dry-run form and an explicit line on what gets destroyed, and
a scan of the generated code blocks raises a banner regardless of whether the
model bothered to warn. Scans fenced code only, so prose mentioning rm does not
trip it.
Explicit buttons rather than an automatic router. Misclassifying a Varaverk
question as chat produces a confident invention about the user's system, which
is exactly what retrieval exists to prevent — with buttons there is no hidden
heuristic to be wrong and the strict profile is the default you land on.
Only Varaverk Assistant retrieves; the other two would be carrying passages
that cannot help write a folder-copy script. Memory goes to all three, since
that is what lets chat know the setup without claiming authority over it.
History depth is per profile and set server-side: retrieval costs ~2500 of
16384, so the profiles that skip it can hold a real conversation. Code
Sketcher is told to flag flags it is unsure of, after it invented
rsync --no-overwrite.
A small operator-written file handed to the model at the start of every
conversation — who you are, how this install is set up, what has already been
decided. Injected ahead of the retrieved passages and marked operator-authored
so it outranks anything they contradict, and never cited as a source.
Deliberately not indexed and deliberately under DATA_DIR: it changes
constantly, vector similarity is the wrong way to retrieve things you were
told to remember, and gitignoring it keeps personal notes out of a pushed
repository. The character cap is a context budget — this text costs its share
of 16k on every single turn.
A multipart POST to this endpoint hangs: no status code is ever returned, and
the request never reaches PHP — no CSRF termination, no fatal, no entry log —
despite leaving the browser with a valid token and a correct body. Every POST
on this host that demonstrably works, including Unraid's own, is
x-www-form-urlencoded. Same fields and same $_POST server-side.
The build-stamp edit replaced the header block's closing tag instead of
keeping it, opening a second php block inside the first. Deployed broken
because the lint in that commit printed OK unconditionally rather than
gating on php -l.
The tab bar uses Unraid's localURL, which swaps content by AJAX without
tearing down the previous page's JavaScript, so old copies keep their timers
and their state. That makes "is the browser running what I deployed"
unanswerable from the server, and explains banner polls arriving far faster
than the 30s timer. The page now stamps its build, says plainly when its own
script is not the one running, and stops the previous copy's timers.
A turn that ended without finish() left busy=true, so send() returned at line
one for every subsequent click — no fetch, no error, and the original
"starting…" still on screen. That is a hang which produces no request and so
no server-side trace of any kind. It now says what happened, and the pending
indicator carries an elapsed counter so stalled and merely slow look different.
GET reaches the endpoint and POST does not, with nothing in the request log,
no CSRF termination and no PHP error — so it fails in the browser before the
request goes out, and the only symptom was the pending indicator sitting
there. Reads the response as text before parsing so an empty body reports as
rejected-before-execution rather than a JSON error, wraps the synchronous
path, and surfaces script errors into the transcript.
The failures this subsystem actually has are configuration drift, so each
check names the setting to change rather than reporting that retrieval
failed. Notably it catches a conf model tag that is no longer installed, and
an index built by a different embedder than the one configured — vectors
from two models are not comparable, and that failure returns confident
nonsense rather than erroring. Diagnostic questions also get recent log
warnings, attached only then because they cost budget the passages need.
Token and poll rather than SSE, so the api layer keeps one response
convention and reuses the pattern manual_sync already proved. History is
capped at three turns because the model is only fully offloaded at 16384
context and unbounded history would cross that silently. The tab exists
only while AI_ENABLED is true, rejected server-side and not merely hidden.