Toolkit
Every script here comes from a specific, dated incident documented on this site — diagnosed on real hardware, fixed, and then generalized into a script that’s safe to hand to a stranger: no silent writes, backups before anything destructive, dry-run modes where it matters.
What’s in it
fix-partuuid-after-clone.sh— detects and fixes the staleroot=PARTUUID=reference thatrpi-cloneand similar tools leave behind after cloning an SD card to a USB SSD/NVMe. From The rpi-clone PARTUUID trap.check-undervoltage.sh— one-shot Raspberry Pi power health check, with or withoutvcgencmdinstalled, plain-English explanations instead of a hex code. From Undervoltage doesn’t look like a power problem.check-journald-persistence.sh— detects the vendor drop-in that keeps Trixie’s journal in RAM, and fixes it properly — including the flush step most published fixes leave out. From Trixie throws away your logs on reboot.-
check-swap-mechanism.sh— reports which swap subsystem actually governs the machine, and finds disk consumed by swap thatswapon,freeand/proc/swapsall decline to mention. From Your Pi’s 2 GB swap file isn’t swap. check-memory-cgroup.sh— answers whether a memory limit set on this machine will actually be enforced. On stock Raspberry Pi OS it will not, anddocker run --memorysays nothing about it. From Your Pi accepts every memory limit you set.check-sysctl-persistence.sh— finds sysctl settings that apply now and disappear at the next reboot, and checks for the compatibility symlink that decides which way it goes. From sysctl -p says it worked.check-wifi-autoconnect-block.sh— tells you whether NetworkManager will bring WiFi back on its own after one failed WPA handshake. On Trixie it will not: the profile is blocked from autoconnect and a headless Pi stays offline until someone runsnmcli connection up. Reports exposure and, on request, installs the 30-second timer that does it for you. From One failed WPA handshake and a headless Pi on Trixie stays off WiFi.check-nmcli-provisioning.sh— flags thenmcliabbreviation that NetworkManager 1.52 made ambiguous, and WiFi profiles left with no key management that look configured and can never associate. From A new NetworkManager property broke a decade of scripts.check-cloudinit-ssh-import.sh— catches a cloud-initssh_import_idthat will never be read, before you flash the card and find out the headless way. From cloud-init calls your user-data valid.check-llama-cache-ram.sh— tells you whether a runningllama-serveruses--cache-ram -1, documented as “no limit”: it keeps less than the default on dense models and has no memory bound on hybrid ones. From llama-server’s--cache-ram -1is not “no limit”.check-decision-temperatures.sh— lists calibration temperatures in Laya checkpoints and edgejev builds that make a decision model’s confidence meaningless — the English checkpoint’s 0.1 for 11+-option questions, which laya clamps at load time but ports inherit from the file. From The Laya checkpoint still ships a 0.1 temperature.check-ollama-gpu-overhead.sh— checks whether the VRAM you reserved withOLLAMA_GPU_OVERHEADis actually left free. Ollama 0.34.x prints the reservation in its log, but the llama-server runner that places the layers never receives it; the script measures free VRAM with a model loaded and prints theLLAMA_ARG_FIT_TARGETto set instead. From Ollama 0.34 logs your OLLAMA_GPU_OVERHEAD reservation as applied.check-ollama-v1-sampling.sh— lists the Ollama models whosetemperature,top_por penalties the OpenAI-compatible API replaces when a client leaves them out, whileollama showkeeps printing the model’s values;--probemeasures it on your server. From Ollama’s OpenAI-compatible API replaces your model’s temperature and top_p with 1.0.check-eog-text-tokens.sh— finds end-of-generation tokens that plain text can produce, for a model in your own llama.cpp build: entries the build forced into its stop list because of how they are spelled. On PLaMo-2 and PLaMo-3 that is the closing strikethrough tag, and output stops at it withfinish_reason: "stop". From llama.cpp picks stop tokens partly by their spelling.check-llama-sleep-race.sh— findsllama-serverprocesses and router presets with--sleep-idle-secondson, where a request that arrives just before the server sleeps is left in the queue or crashes it, and says whether systemd would restart it. From llama-server’s sleep mode loses, or crashes on, a request that arrives just before it sleeps.check-ollama-schema-order.sh— sends a two-key JSON schema in reverse alphabetical order to each Ollama model and reports whether the output kept the declared order; on Ollama’s native chat path it doesn’t. From On one of Ollama’s two chat paths, your JSON schema’s keys are re-sorted.check-ollama-format-think.sh— sends short prompts to a thinking model withthink: trueand a JSON schema, and reports how many replies skipped thinking and came back outside the schema. From With think enabled, Ollama only enforces your JSON schema after the model has thought.check-spec-logprobs.sh— reads/slotsand sends one logprob request to a llama-server, and reports whether the tokens after the first came back with real alternatives or as speculative-decoding placeholders (logprob 0, no alternatives). From With speculative decoding on, llama-server’s logprobs are placeholders.check-gemma4-renderer.sh— applies Ollama’s Gemma 4 template rules to each installed model and lists which ones of 10B or more resolve to the e2b/e4b template because their name has no size in it. Loads nothing. From Ollama picks the Gemma 4 prompt template from the model’s name.check-lora-cache.sh— runs a three-request probe against a llama-server with a LoRA loaded and reports whether a prompt restored from the RAM prompt cache is answered from KV computed under a different LoRA scale. From llama-server’s RAM prompt cache brings a prompt back with KV computed under a different LoRA scale.check-llama-http-stall.sh— on llama-server builds before b11737, compares open client connections with base HTTP threads, and with--watchflags any connection whose request sits unread in the socket for 5 seconds or more. From llama-server can leave a keep-alive connection unread until another one closes.check-llama-anthropic-controls.sh— sends four small requests to llama-server’s Anthropic-compatible/v1/messagesand reports whether a forcedtool_choice,tool_choice: noneandstop_sequencesare honoured. From llama-server’s Anthropic endpoint ignores which tool you ask for.check-llama-responses-status.sh— sends an 8-token request to llama-server’s/v1/responsesand one to/v1/chat/completions, and reports whether a reply cut off by the limit is markedincompleteor, wrongly,completed. From llama-server’s Responses API reports a cut-off reply as completed.check-gguf-pretokenizer.sh— reads a GGUF’s header and flags a pre-tokenizer that llama.cpp will apply wrongly (Nemotron 3 files taggedpixtral); with--serverit compares a running llama-server’s tokenization of multilingual samples with the model’s Hugging Face tokenizer. From llama.cpp splits Hindi, Tamil and Thai differently from how Nemotron 3 was trained.check-ollama-eviction-stall.sh— on an Ollama server with one model slot, says it’s at risk of a request for another model waiting out a keep_alive, finds such stalls in the debug log, and with--releaseunloads the loaded model to free them. From With one model slot, a keep_alive on the loaded Ollama model cancels the swap.check-ollama-dropped-tool-calls.sh— probes a model on your Ollama server for tool calls that are dropped because the name isn’t intools(empty reply,eval_countabove zero). From Ollama drops a tool call to a name that isn’t in tools.check-lora-patterns.py— reads LoRAadapter_config.jsonfiles and lists the modules whoserank_pattern/alpha_patterngive them a scale vLLM won’t apply, with the factor to fold intolora_B. From vLLM serves a LoRA adapter that uses rank_pattern or alpha_pattern at the wrong scale.check-embd-determinism.sh— tells you whether decoding throughllama_batch.embdgives the same logits every time on your build and model, and when it does not, confirms whether the cause is the known heap over-read: on M-RoPE models the batch code reads four positions per token from an array the header told you to size at one. From llama.cpp reads past your pos array on every embedding batch for an M-RoPE model.check-tool-param-names.sh— finds tool parameters namedtype,description,required,propertiesornullable, which Ollama’s gemma4 renderer never shows the model while still marking them required — so the model omits the argument or makes one up. Checks a tools file statically, or probes a live server. From Ollama’s gemma4 renderer never shows the model a tool parameter named type.check-responses-state.sh— tells you whether a Responses-API server honoursprevious_response_idor accepts it, returns 200, and forgets the conversation. Ollama does the second. From Ollama’s Responses API accepts previous_response_id and starts every turn from nothing.check-docker-log-integrity.sh— tells you whetherdocker logsis returning everything on disk, or stopping at a NUL byte with exit 0 and hiding the rest. From docker logs stops at a NUL byte and exits 0.check-overlay-sandbox.sh— on a Docker swarm node, finds containers that are running but have lost their overlay network: failed container starts can take the node’s join count to zero, and a service retrying on a taken host port did it in 20 seconds. Full toolkit only. From A Docker swarm service failing on a taken host port cut every container off its overlay network.check-podman-compat-update-restart.sh— lists the running Podman containers that have no restart policy and probes whether this Podman’s Docker-compatibleupdateendpoint resets the policy tonowhen the body omits it — it does on 5.4.2, even for{}, while Docker keeps it. From Podman’s compat API resets the restart policy on any update that omits it.check-podman-restart-userns.sh— lists Podman containers with a restart policy that are stopped when they should have been restarted, and running ones that will be (rootful, own ID mapping, AppArmor profile, AppArmor host). From On an AppArmor host, rootful Podman restarts a –uidmap container once.check-docker-image-mounts.sh— checks that every running container’stype=imagemount still has the image’s files in it; after a reboot (or, on overlay2, a daemon restart) they come back running and empty. From A Docker type=image mount comes back empty after a reboot.check-docker-lost-network.sh— lists containers that were created on a network and now have none, which on Docker 29 is what one start failing during network setup leaves behind. From Since Docker 29, one failed start leaves a container with only a loopback interface.check-rootless-build-limits.sh— says whether your Docker builds run rootless, wheredocker buildx build --resourcelimits are dropped without a warning, and with--probemeasures it with a one-step build. Full toolkit only. From Rootless Docker builds ignore –resource memory limits.check-docker-exec-umask.sh— reads the shim umask behind every running container and says whetherdocker execthere creates world-writable files, as it does since Docker 29.6 wherever dockerd starts containerd itself (dind, rootless). Full toolkit only. From Since Docker 29.6, docker exec creates world-writable files in docker-in-docker and rootless Docker.check-dockerfile-chown.sh— resolves everyCOPY/ADD --chownin a Dockerfile against the stage’s base image and flags the ones that will build fine and quietly leave the files owned by root. Full toolkit only. From COPY –chown with a user that doesn’t exist builds fine and gives the files to root.check-image-layer-compression.sh— compares each layer’s media type in a registry manifest with the blob’s actual compression, to catch zstd layers that a graphdriver Docker re-pushed labelled gzip. Full toolkit only. From Docker’s graphdriver store pushes pulled zstd layers labelled gzip.check-podman-subpath-cp.sh— lists the Podman containers for which apodman cpwhile stopped will read and write the volume root instead of thesubpath=they mount — a different file out, another container’s file overwritten in. From podman cp on a stopped container ignores the volume’s subpath.check-podman-export-idmap.sh— lists the Podman containers with their own user-namespace mapping, such as rootless--userns=keep-idones, whosepodman exportandpodman cparchives carry every file owner shifted, and checks an export without writing it. From Rootless podman export of a keep-id container shifts every file owner.check-pve-move-delete.sh— on a Proxmox VE node, lists disk moves whose target could not be found afterwards (LOST if “Delete source” then removed the original) and VM disks whose volume no longer exists. From Proxmox’s disk move with Delete source deletes the source even when the copy isn’t there.pve-move-disk-verified.sh— moves a stopped VM’s disk without “Delete source”, compares the copy with the original usingqemu-img compare, and removes the original only if they match. From Proxmox’s disk move with Delete source deletes the source even when the copy isn’t there.check-llama-response-format.sh— tells you whichresponse_formatforms a runningllama-serveractually enforces. The one its README shows is accepted and ignored. From llama-server ignores the response_format its own README shows.check-cloudinit-instance-id.sh— answers whether auser-datayou place on a disk will be acted on at all. On a plain image write it will not be, and cloud-init logs the skip asSUCCESS. From cloud-init never reads the instance-id Raspberry Pi OS sets.check-iptables-backend.sh— tells you whether legacy iptables can work on this kernel at all, before you install something that assumes it. From iptables says your kernel needs upgrading.check-network-config-location.sh— finds where your WiFi credentials are actually stored, and warns when the directory every guide names is empty so your backup silently captures nothing. From tar backed up your WiFi config and exited 0.check-container-firewall-bypass.sh— finds container ports that are reachable from your network while your firewall reports them as denied. Docker’s chains are evaluated before UFW’s, so both are true at once. From UFW says the port is closed.check-swarm-ufw-ingress.sh— lists the ports this host publishes, through Swarm ingress or ordinary bridge networks, that containers on the same host can’t reach because ufw drops them, with the per-port rule and bridge for each. From Since Docker 29.8, a Swarm container can’t reach a port published on its own node when ufw is on.check-ir-tx.sh— lists IR transmitters and flagspwm-ir-txon a 6.18+ kernel, which sends every edge of a code within microseconds whileir-ctlreports success;--probemeasures it from the kernel trace. From On the Pi’s 6.18 kernel, pwm-ir-tx sends every edge of an IR code within microseconds.fix-cloudinit-placement.py— moves a cloud-initssh_import_idto the place cloud-init actually reads it from (top level for the default user, nested for ordinary ones), and refuses rather than guesses on any user-data it does not fully understand. Used by the provisioning pack’srun.sh. From cloud-init validates the SSH key it never reads.check-llama-build-provenance.sh— answers whether a llama.cpp or ggml build will stamp a commit hash from somebody else’s repository, which a release tarball unpacked inside an unrelated git work tree does without a warning. From llama-cli reports a commit hash that is not in llama.cpp.check-ollama-quant-artifact.sh— asks an Ollama model three trivial coding questions and runs what comes back, to catch a quantisation artifact that pulls, verifies and streams fluent text with no working code in it. Never pulls. From An Ollama library tag that pulls, runs, and has no working code in it.check-lora-target-overlap.sh— answers whether a LoRA adapter will be applied to anything under the--lora-target-modulesyou serve with; vLLM loads an adapter that matches none of them and answers from the base model. From vLLM accepts a LoRA adapter it will never apply.
Also relevant if you’re building your own delivery pipeline: Stripe retries a failed webhook for three days — the idempotency bug this toolkit’s own delivery Worker hit and fixed.
New scripts are added as new incidents happen — this is a living collection, not a one-time release.
Pick the checks you need — $5 each
Each pack answers one question and contains only the scripts for it. Buy the one that matches what you are about to do; you are not paying for checks that do not apply to your machine.
Exposure & firewall — $5
Is anything reachable from your network that your firewall says is blocked?
Three checks. Container ports that answer from the LAN while ufw reports them denied, whether the iptables your tools call has any kernel support left, and published ports, Swarm or bridge, that containers on the same host cannot reach because ufw drops them.
Buy Exposure & firewall →Backup & restore integrity — $5
Is your backup actually a backup, and will the clone boot?
Five checks and a safe-move tool. Where your network config really persists before you archive it, the stale PARTUUID that stops a successful-looking clone from booting, the podman cp that copies a different file out of a stopped container, the podman export that writes every owner in the archive shifted, and the Proxmox disk move that deletes the original when the copy is not there.
Buy Backup & restore integrity →Persistence across reboot — $5
Will the settings you just applied still be there after a reboot?
Eight checks. sysctl, the journal, swap, Docker container logs after a power loss, whether your Podman containers still have the restart policy you gave them, whether Podman actually restarts them, Docker image mounts that come back empty, and containers that come back without their network — each a case where the command succeeds, the value reads back, and the next boot disagrees.
Buy Persistence across reboot →Provisioning verification — $5
Did the machine actually get configured the way you told it to?
Four checks. The cloud-init key that is valid, schema-checked, and silently ignored — in both directions — whether your user-data will be acted on at all or parsed and skipped, the network profile a provisioning run really produced, and whether the WiFi you just set up will come back by itself after one failed handshake.
Buy Provisioning verification →Local LLM artifacts — $5
Is the model, adapter, or build you just installed the thing it says it is?
Twenty-five checks. An Ollama quantisation that pulls and runs and returns no working code, a LoRA adapter accepted and applied to zero layers, a build that reports a commit hash from a repository it has never heard of, a response_format the server accepts and then ignores, a previous_response_id that is accepted and dropped, a tool parameter the gemma4 renderer never shows the model, an embedding batch whose positions the library reads past the end of, a prompt cache whose "no limit" setting keeps less than the default, and a decision model whose confidence is sharpened tenfold by a temperature its own library clamps at load time, a VRAM reservation Ollama prints in its log and never passes to the runner that places the layers, model sampling settings the OpenAI-compatible API quietly replaces with 1.0, an end-of-generation token chosen by its spelling that stops a model mid-sentence with a normal finish, a sleep mode that loses or crashes on a request arriving just before it sleeps, a JSON schema whose keys come back alphabetised so the model fills the wrong fields, a JSON schema a thinking model escapes whenever it answers without thinking, logprobs that speculative decoding fills with certainty, a Gemma 4 copy prompted with the small model's template because of its name, a prompt cache that answers a LoRA request from KV computed under another scale, a keep-alive connection left unread until another one closes, an Anthropic-compatible endpoint that ignores which tool you asked for and stops inside the reasoning, a Responses API that reports a cut-off reply as completed, a Nemotron GGUF that llama.cpp splits with the wrong pre-tokenizer, an Ollama model swap that a keep_alive cancels, tool calls Ollama drops because the name was not listed, and a LoRA adapter whose per-module scaling vLLM drops without a word.
Buy Local LLM artifacts →Every script in every pack is also in the complete toolkit below, so there is no reason to buy both.
Get everything — $15
Every script in the toolkit, including the ones that are not in any pack. Buying the 5 packs separately is $25, so this is the cheaper route if you want more than two of them. One-time purchase: the download link is emailed to you immediately, and every script added later is part of the same purchase.
Buy the toolkit →