The vault was 155 pages / 31,210 lines, most of it measurement ledgers for payloads that no longer run. A throughput figure for a runtime nobody operates is not a record: AI moves faster than the vault, so the number is wrong before anyone reads it, and a wrong number in a runbook gets believed. Per the new purpose test in `AGENTS.md` → *Documentation Policy*, it is destroyed. Gone (`.AGENTTRASH/20261019-destruction/`, KILL-LIST.txt is the manifest): - the `frank-medium` endpoint and its five era pages, `frank-npu`, FastFlowLM, the ikllama/kingjones/dealign/frank-redo eras, the ling/swift15/freetoken/ubatch campaign pages, qwen3.8 spec-matrix and strix-optimizations, the two "Running Qwen3.6 …" pages; - the whole `Pipeline Parallelism/` folder (no live script passes a pipeline flag) and the multi-device/x4-pair/hybrid/offload experiment pages; - every vLLM page — no vLLM endpoint exists on this fleet; - `LLM/deployment.md` (`Architecture/Deployment Flow.md` is the test-referenced owner) and the external surveys (SGLang, Lemonade, llama.cpp forks/diff, self-hosted app census, the TTS survey) that were obsolete by construction; - `log.md`, 2,380 lines. Git holds the chronology; a causal law belongs to the page that owns the thing it governs, never to a diary. Survivors: 101 pages, 17,542 lines, 0 OKF violations, 0 unresolved links. Eras tables keep the window, payload, runtime, reason and rollback pointer; the rate columns are blanked. The live shapes stay verbatim — those numbers are what the deployer and `models.yml` consume.
6.1 KiB
type, title, description, tags, timestamp
| type | title | description | tags | timestamp | |||||
|---|---|---|---|---|---|---|---|---|---|
| reference | SSH and Remote Access | Passwordless SSH bootstrap without sshpass, remote execution against fish login shells, and frozen-GUI triage. |
|
2026-10-05T00:00:00-07:00 |
SSH and Remote Access
Passwordless SSH bootstrap without sshpass/expect
Use when you must install your pubkey on remote hosts but sshpass and
expect are not installed and you only have a password. Modern OpenSSH
(≥ 8.4) can drive the password prompt from a helper program, so the password
flows through the process env only — never a file, never argv.
- Generate a key (if none):
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N "" -C "host-deploy-$(date +%Y%m%d)" - Create an askpass helper that echoes the password from an env var (the
helper itself stores NO secret):
printf '#!/bin/sh\necho "$DEPLOY_PW"\n' > /tmp/askpass.sh chmod 700 /tmp/askpass.sh - Copy the pubkey, forcing the askpass path and detaching from the TTY:
Password via the transient
env DEPLOY_PW='<password>' \ SSH_ASKPASS=/tmp/askpass.sh \ SSH_ASKPASS_REQUIRE=force \ setsid ssh-copy-id -o StrictHostKeyChecking=accept-new -o ConnectTimeout=10 user@hostenvargument only. - Add host aliases in
~/.ssh/configso deploy scripts resolve names (HostName,User,IdentityFile,IdentitiesOnly yes). - Verify with
ssh -o BatchMode=yes myhost 'echo OK; hostname'— BatchMode fails fast if a password would be required; a clean success proves the key works.
Gotchas: without SSH_ASKPASS_REQUIRE=force, ssh ignores SSH_ASKPASS when a
TTY is present and prompts interactively (hangs in a non-interactive tool)
setsid detaches the controlling terminal — required on older OpenSSH even
with force; the helper must be executable (chmod 700) and print ONLY the
password; IdentitiesOnly yes stops ssh offering other agent keys that could
be rejected first ("Too many authentication failures"). Passwordless sudo
on the target is a separate concern (NOPASSWD / FRANK_SUDO_PW).
Remote execution on a fish login shell
Running remote commands or shipping files over SSH to a host whose login
shell is fish (blankpad: user blank, reachable only as mDNS FQDN
blankpad.local / 192.168.0.83 — the bare hostname does not resolve from the
workstation).
- Auth:
SSHPASS='<pw>' sshpass -e ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no user@host '…'— password via env, never argv (ps-visible). - Remote exec:
ssh host 'cmd'pipes the command string to the login shell (fish). Bashisms —for … do,$?, heredoc markers — fail at parse time on fish (Missing end to balance this for loop). Always wrap compound commands:ssh host 'bash -c "for b in a b c; do command -v $b || echo MISSING; done"'(escape inner$). - File shipping: never combine
cat > /remote/path <<EOFwith a trailingbash -sin the same ssh command —catdrains stdin, so the interpreter silently runs on empty stdin and prints nothing (a silent no-op that looks like success). Ship real bytes via stdin redirect:ssh host 'cat > /remote/path' < localfile, then verify byte-truth withmd5sumon both ends. - Exit codes:
$?in an unquoted remote command is parsed by fish ($statusthere) — wrap in bash or drop the status echo; ssh's own exit code propagates to the caller anyway.
Both traps fired during the 2026-09-09 blankpad dotfiles deploy: the first
probe died on fish loop parsing; a cat > ship silently swallowed the
heredoc meant for bash -s, deploying wrong bytes until md5-compared.
Related: dankserver's login shell is ZSH — never start an unquoted word with
= in an ssh one-liner (echo === aborts the whole chain).
GUI hang — remote diagnosis over SSH
Use when the desktop is frozen, VT switches do nothing, but SSH still works.
- Find the smoking gun — the kernel hung-task reporter already logged
it:
Look for
journalctl -b -p err --since "-2 hours" --no-pager | tail -80INFO: task X blocked for more than N secondsandblocked on a semaphore likely last held by task Y:PID(modern kernels name the lock holder outright). - Full stacks for victim and holder:
Victim
journalctl -b -k --since "<hang minute -5>" --no-pager | tail -120 cat /proc/<pid>/status | head -5 # State: R (spinning) vs D (blocked)D+ holderR= livelock/deadlock with the lock held;voluntary_ctxt_switchesin the millions on anRkthread = spinning, not progressing. - Hardware or software? GPU/CPU still alive, no Xid errors?
Instant answers with no Xid ⇒ driver lock issue, not hardware.
nvidia-smi --query-gpu=driver_version,pstate,temperature.gpu,clocks_event_reasons.active --format=csv journalctl -b -k --no-pager | grep -i xid - Trigger window: block start = first hung message timestamp − reported
seconds; then inspect user-session events around it
(
journalctl -b --since "<start-2m>" --until "<start+1m>" | grep -v audit). - Collateral: other
Dtasks (ps -eo pid,stat,comm | awk '$2 ~ /D/') USB workers, etc.
Recoverability verdict: compositor in D state is unkillable and a
spinning kernel thread holding the lock cannot be poked — the only exit is
reboot: sync && systemctl reboot --force --force (double-force skips
stop-jobs waiting forever on D-state PIDs). If the holder is D (sleeping on
something that can complete, e.g. storage), recovery may be possible by
clearing that dependency first.
After diagnosing: map stack symbols to driver internals to name the exact
subsystem, check upstream for the exact symbols + driver version, and propose
targeted off-switches (NVreg_RegistryDwords, module params from
/proc/driver/nvidia/params) rather than blanket driver swaps.
Related
- Fleet Ops Playbook — incident procedures that run over these sessions
- Remote Job Runner — long jobs that must survive session loss
- Deploy State Triage — the deploy flow these credentials serve