skills/truenas-jsonrpc-debug/SKILL.md
Query TrueNAS using the JSON-RPC 2.0 WebSocket API (v25.10+) for storage and NVMe-oF debugging. Use this skill whenever you need to inspect TrueNAS state — NVMe subsystems, ZFS pool health, CSI-provisioned datasets, disk status, or service configuration. Replaces deprecated REST API calls. Trigger when: investigating NVMe-oF attach failures, checking pool/dataset health, verifying NVMe target port bindings, auditing democratic-csi provisioned volumes, or diagnosing any TrueNAS storage issue from within a Kubernetes debugging session.
npx skillsauth add aldengolab/lorist truenas-jsonrpc-debugInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
The TrueNAS REST API is deprecated as of v25.10. All queries now go through a JSON-RPC 2.0
WebSocket endpoint at ws://<host>/api/current (or wss:// for HTTPS).
Use the bundled script scripts/truenas_query.py for all TrueNAS queries.
pip install websockets pyyaml
The credentials file is required for every session. Generate it at the start of each debugging session — it pulls the TrueNAS host and API key from the cluster secret each time:
python3 <skill-path>/scripts/truenas_query.py --get-creds --creds ~/.truenas-creds.json
This writes ~/.truenas-creds.json (persistent, survives reboots unlike /tmp). The file contains
the host IP, port, protocol, and API key extracted from the democratic-csi-driver-config secret.
The democratic-csi API key works for REST provisioning but is rejected by the JSON-RPC WebSocket
endpoint with AUTH_ERR. You need a separate key created in the TrueNAS UI:
claude-debug), create it under your admin account~/.truenas-creds.json:
"username" to the account that owns the key (e.g., "truenas_admin")"api_key" to the new key valueAfter this one-time edit, --get-creds will refresh the host/port and API key from the cluster
secret on future runs but will preserve any username already in the file — so you only need to
set it once.
Auth method used:
username is set in creds: auth.login_ex with API_KEY_PLAIN mechanismusername is null: auth.login_with_api_key (legacy, may not work with v25.10+ keys)python3 <skill-path>/scripts/truenas_query.py \
--creds ~/.truenas-creds.json --diag nvme --out /tmp/tn_nvme.json
Key fields to check in output:
nvmet_ports[*].addr_trsvcid — port number the target is listening on (default 4420)nvmet_ports[*].addr_traddr — IP address the target is bound to (if 0.0.0.0, all interfaces)nvmet_subsystems — list of NQN subsystems (should match what democratic-csi provisioned)nvme_services — whether the NVMe service is runningpython3 <skill-path>/scripts/truenas_query.py \
--creds ~/.truenas-creds.json --diag storage --out /tmp/tn_storage.json
Key fields:
pools[*].status — should be ONLINEcsi_datasets — all datasets matching csi-pvc-* (provisioned by democratic-csi)disks[*].devname and disks[*].status — physical disk healthpython3 <skill-path>/scripts/truenas_query.py \
--creds ~/.truenas-creds.json --diag system
python3 <skill-path>/scripts/truenas_query.py \
--creds ~/.truenas-creds.json --diag all --out /tmp/tn_full.json
# List all services
python3 <skill-path>/scripts/truenas_query.py \
--creds ~/.truenas-creds.json --method service.query
# Query a specific dataset by name
python3 <skill-path>/scripts/truenas_query.py \
--creds ~/.truenas-creds.json \
--method pool.dataset.query \
--params '[["id", "=", "nvme-of-k8s/democratic-csi-provisioner"]]'
# Check NVMe target host port bindings
python3 <skill-path>/scripts/truenas_query.py \
--creds ~/.truenas-creds.json --method nvmet.port.query
Connection URL: ws://<host>:<port>/api/current
Request format:
{"jsonrpc": "2.0", "id": 1, "method": "pool.query", "params": []}
collection_update notifications (no "id") — ignore these| Method | Purpose |
|--------|---------|
| system.info | Version, uptime |
| nvmet.subsystem.query | NVMe subsystem list |
| nvmet.port.query | NVMe listener ports and bound IPs |
| nvmet.namespace.query | NVMe namespaces (backed by zvols) |
| service.query | All service states |
| pool.query | ZFS pool health |
| pool.dataset.query | All datasets (supports filter params) |
| disk.query | Physical disk inventory and health |
| interface.query | Network interfaces and IP addresses |
| network.configuration.config | Hostname, DNS, gateway |
httpConnection in the driver config secret — this is the
HTTP/WS management interface, not the NVMe-oF data port (4420). They are different.shareHost/sharePort in the driver config is the NVMe-oF data endpoint.
The host/port in httpConnection is the management API endpoint.kubectl run -it --rm dns-test --image=busybox --restart=Never -- nslookup <host>development
Build a UEFI Secure Boot PXE netboot server for Ubuntu autoinstall. Use when: designing or implementing network boot infrastructure for automated Ubuntu provisioning with Secure Boot enabled. Covers the complete chain: signed shim+GRUB selection, TFTP layout, kernel parameters, autoinstall config requirements, and post-install bootstrapping scripts. Also applicable when debugging an existing PXE setup that uses the wrong GRUB binary or config paths.
development
Design pattern for running a persistent PXE/TFTP server that safely coexists with already-installed nodes. Use when: building PXE infrastructure that should stay always-on, designing automated bare-metal provisioning in GitOps/Kubernetes environments, or any PXE setup where UEFI boot order has network boot first. Eliminates boot loops without requiring UEFI firmware changes.
development
This skill governs all prose output — Claude's own responses, documentation, PR descriptions, commit messages, README content, comments, and any text the user asks to draft or edit. It should also be used when the user asks to "review my writing", "edit this for clarity", "make this clearer", "simplify this text", "rewrite this", "check my prose", "tighten this up", or "make this more concise". Based on George Orwell's "Politics and the English Language" (1946).
development
Debug Kubernetes pods using hostNetwork: true that crash with "Address already in use" or "failed to create listening socket for port N". Use when: (1) a hostNetwork pod container is in CrashLoopBackOff and logs show a port bind failure, (2) the port works fine in non-hostNetwork pods but fails with hostNetwork, (3) you need to identify which host-level process holds a port from within Kubernetes (no SSH). Covers /proc/net/udp inspection and kubectl debug node with nsenter.