Files
claudetools/.claude/skills/synology/SKILL.md
Howard Enos 2a1a275511 sync: auto-sync from HOWARD-HOME at 2026-06-24 17:37:00
Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-06-24 17:37:00
2026-06-24 17:37:35 -07:00

8.4 KiB

name, description
name description
synology Control a Synology NAS end-to-end via two surfaces: the DSM Web API (auth + full API discovery + any API method — system, storage, shares, users/groups, packages, services, FileStation, connections) and an SSH backend for the syno* CLI the Web API doesn't expose (filesystem ACLs, low-level share/user/group internals). Reads run freely; mutating calls (set/create/delete/start/stop/reboot/shutdown/...) are gated behind --confirm. Default device is the Cascades NAS (cascadesDS, 192.168.0.120, admin); point at another client's NAS with --vault. Triggers: synology, diskstation, DSM, cascadesDS, NAS, control the synology, synology drive, hyper backup, active backup, synology package/service/share/user, reboot the nas, synology acl.

synology — Synology DSM control (Web API + SSH)

Full control of a Synology NAS. Two complementary backends:

  1. DSM Web API (scripts/syno_client.py) — the structured surface. Auth → discover the device's own API map → call any API method. This is how you "control all functions": apis shows everything the device exposes, call <API> <method> reaches any of it.
  2. SSH syno* CLI (scripts/syno-ssh.sh) — the gaps the Web API doesn't cover: filesystem ACLs (synoacltool), share/user/group CLI internals, package CLI. We already use this for the Cascades share-permission inventory (docs/migration/synology-permission-inventory.md).

Default target = Cascades cascadesDS (192.168.0.120, DSM on :5000, admin) — credential vaulted at clients/cascades-tucson/synology-cascadesds.sops.yaml (host/port/ credentials.username/credentials.password). ext4 filesystem (NOT Btrfs → no Active Backup for Business). Shares: homes, Public, SalesDept, Server, Management. On a private LAN — every command needs the Cascades site VPN up (a connect failure almost always = VPN down). Point at any other NAS with --vault clients/<x>/synology-...sops.yaml (same field layout).

Web API commands

PY="$CLAUDETOOLS_ROOT/.claude/scripts/py.sh"; S=".claude/skills/synology/scripts/syno_client.py"
# verify + discover
bash "$PY" "$S" test                  # login, print model/serial/firmware/RAM/uptime
bash "$PY" "$S" apis [filter]         # the device's full API map (e.g. `apis backup`, `apis drive`)
# reads
bash "$PY" "$S" sysinfo               # SYNO.Core.System — model/serial/RAM/temp/uptime
bash "$PY" "$S" util                  # live CPU/mem/disk/net
bash "$PY" "$S" storage               # volumes/disks/RAID/usage (SYNO.Storage.CGI.Storage)
bash "$PY" "$S" shares | users | groups | packages | services | connections
bash "$PY" "$S" ls [folder_path]      # FileStation: no path = shares; else list a folder
# generic power tool — ANY API method the device exposes
bash "$PY" "$S" call <API> <method> [k=v ...] [k:=json] [--version N] [--post]
bash "$PY" "$S" call SYNO.Core.System.Status get
bash "$PY" "$S" call SYNO.Backup.Task list           # Hyper Backup tasks (if installed)
# writes — ALL gated --confirm
bash "$PY" "$S" pkg-start <id> --confirm | pkg-stop <id> --confirm
bash "$PY" "$S" reboot --confirm | shutdown --confirm
bash "$PY" "$S" call <API> <set-method> k=v --confirm   # any mutating method needs --confirm

call params: k=v for strings, k:=json for typed/array values (e.g. additional:='["size","owner"]'). A method whose name starts with a mutating verb (set/create/delete/start/stop/reboot/…) is auto-detected and refuses to run without --confirm.

SSH commands (the syno* CLI surface)

X=".claude/skills/synology/scripts/syno-ssh.sh"
bash "$X" info | df | shares | users | groups | packages | services   # reads
bash "$X" acl <share>                     # synoacltool -get /volume1/<share> (e.g. acl Server)
bash "$X" reboot --confirm                # synoshutdown -r (use when the Web-API reboot 103s)
bash "$X" shutdown --confirm              # synoshutdown -s
bash "$X" run "<command>" --confirm       # arbitrary command (gated); privileged auto-sudo -S

Requires SSH enabled on the NAS (DSM → Terminal & SNMP). Privileged recipes feed the vaulted admin password to sudo -S. Auth: sshpass if present, else OpenSSH SSH_ASKPASS (on Windows the fallback needs MSYS/Git-bash ssh on PATH — system OpenSSH can't exec a shell askpass).

Auth model (DSM Web API)

SYNO.API.Auth login (session=DSM, enable_syno_token=yes) → _sid (session cookie) + a synotoken (CSRF). Both are attached to every subsequent call (the synotoken as X-SYNO-TOKEN header + SynoToken param) so writes pass CSRF. 2FA: pass --otp <code> or SYNO_OTP. The client always logs out at the end. Env overrides for ad-hoc use: SYNO_HOST/SYNO_PORT/SYNO_USER/SYNO_PASS, SYNO_HTTPS=1 (→ :5001, cert verify off).

Full API reference

references/dsm-api.md is the consolidated, sourced map (auth, system/power, storage/shares, users/groups/security, packages, Log Center, Drive, backup, network/services + the SSH syno* surface) with per-row confidence and the 5 "golden rules". Read it before any write — the key ones: discover versions via apis (don't hardcode), CSRF is mandatory for writes (handled), setters are read-modify-write (get → mutate → push back; never construct from scratch), and when a setter's param keys are uncertain run it on-box via synowebapi --exec (validates params).

Why both surfaces (don't reach for SSH first)

The Web API is the default and covers system/storage/shares/users/packages/services/FileStation/ backup/connections. Use SSH only for what the API genuinely lacks — chiefly filesystem ACLs (synoacltool): the Web API tells you a share is in Windows-ACL mode but NOT the per-file ACE list. That ACE data is exactly what the Cascades cutover needs (docs/migration/ synology-permission-analysis-2026-04-22.md).

Open Cascades work this skill serves (verified call recipes)

  • Confirm model/RAM/DSM version (wiki TODO) — test answers it in one call.
  • Log Center syslog collector (docs/network/network-logging-plan.md) — the NAS-as-syslog-SERVER is SYNO.LogCenter.* (needs the Log Center package): apis logcenter to confirm it's installed, then call SYNO.LogCenter.RecvRule list (receive rules), call SYNO.LogCenter.Log list (received logs). NOTE SYNO.Core.SyslogClient.* is the forward-own-logs-out side, not the collector. Schedule the snapshotter as a root task via SYNO.Core.TaskScheduler.Root create.
  • Synology Drive Team Folder migration (PROJECT_STATE pending) — apis synologydrive, then call SYNO.SynologyDrive.TeamFolders list / ... Tasks list / ... Connection list to inspect before the CS-SERVER cutover. (SYNO.C2FS.* is C2 cloud — not this.)
  • Hyper Backup offsite (phase4 §6.4) — call SYNO.Backup.Task list / ... Repository list once configured. (NOTE: Active Backup is installed + running on this ext4 box — the Btrfs requirement is only for ABB dedup/self-healing features, not the package. call SYNO.ActiveBackup.Task list.)

Error logging (mandatory)

On a GENUINE functional failure (DSM login fail, API error, SSH connect/auth rc=255) both scripts log via .claude/scripts/log-skill-error.sh before surfacing. Handled conditions (missing cred, VPN-down connect error surfaced to the user, a method refused for lack of --confirm) are NOT logged.

Status / verification

  • [PLUMBED] Built from a 5-agent scan of the DSM 7 help tree + the authoritative API sources (kwent device-extracted _full.json, N4S4/synology-api, Synology's Web API guides) — see references/dsm-api.md. Auth (sid + synotoken CSRF), API discovery, version-by-maxVersion routing, session-expiry re-login (codes 106/119), the mutating-verb gate, and the generic-error map are all coded to spec but not yet live-exercised against the device (needs the Cascades VPN up). First live test confirms endpoint shapes + fills the model/DSM-version wiki TODO. Mark verified then.
  • DSM 7.2.x reboot/shutdown 103: the Web-API reboot/shutdown can return error 103 on some builds. Fallback is the SSH reboot|shutdown --confirm recipe (synoshutdown -r|-s).
  • Param-schema caveat: method names + versions in the reference are device-authoritative, but many setter param keys are community/inferred. For a production write where keys are uncertain, capture the matching get and round-trip it, or run on-box via synowebapi --exec.