Files
claudetools/.claude/skills/synology/SKILL.md
Howard Enos fc36f98450 synology: full read-surface sweep + FileStation ls graceful fallback
Exercised every Web API + SSH read command live against cascadesDS.
- All reads OK; `ls <folder>` (FileStation list) is 407-denied for the admin
  account on this box (confirmed on-box as SYSTEM_ADMIN) -> now catches the
  400/407 and prints an SSH file-browse hint. `ls` share-roots still works.
- SSH backend (info/df/run + privileged synowebapi) verified.
- Documented MSYS path-mangling of bare `ls /path` arg on Windows.
- SKILL.md: per-command results; flagged write/setter path as not-yet-live.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 11:19:04 -07:00

10 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

  • [VERIFIED 2026-06-25 — HOWARD-HOME, Cascades VPN up] Full read-surface exercise against the device. Device is DS718+, DSM 7.2.1-69057 Update 11, 6 GB RAM, serial 1920PEN537202; ext4, 2x WD10EZEX 1 TB (volume1 913G, 43% used). 10 shares (incl. hidden pacs, Activities, chat, Sandra Fish); 30 packages running incl. Active Backup for Business 3.1.0, Synology Drive Server 3.5.0, Chat, VPN Server, Hybrid Share. 41 users, 4 groups (administrators, http, MainOffice, users).
  • Command-by-command results (Web API): test apis sysinfo util storage shares users groups packages services connections ls (share roots) callall OK. Auth (sid + synotoken CSRF), API discovery, version-by-maxVersion routing, and the generic call power-tool all confirmed live.
  • SSH backend (syno-ssh.sh): info df run confirmed OK (incl. privileged sudo -S and on-box synowebapi --exec at /usr/syno/bin/synowebapi). This is the path for real file browsing.
  • ls <folder> (FileStation list) is DENIED for the admin account on this box — returns 407 on-box (SYSTEM_ADMIN) / 400 via Web API even for valid subfolders; the built-in admin lacks FileStation file privileges. ls (no path / share roots via list_share) works fine. For actual file/folder browsing use the SSH backend: syno-ssh.sh run "ls -la /volume1/<share>/<subpath>" --confirm. (ls <folder> now catches this and prints the SSH hint.) Windows note: a bare ls /Public arg is also rewritten by MSYS path-conversion — prefer MSYS_NO_PATHCONV=1 or the call ... folder_path=/x form, but the 407 denial blocks it regardless.
  • WRITE/SETTER PATH NOT YET EXERCISED LIVE. Session-expiry re-login (106/119), the mutating-verb gate, and read-modify-write setters are coded to spec but no mutating call has been made against the device yet. Gate is verified only on the read path. First real change will confirm CSRF on a write end-to-end.
  • Built originally from a 5-agent scan of the DSM 7 help tree + authoritative API sources (kwent _full.json, N4S4/synology-api, Synology Web API guides) — see references/dsm-api.md.
  • Live fixes from this run (2026-06-25): services used SYNO.Core.Service.list which 103s on DSM 7.2.1 — corrected to get (returns {"service":[...]}). apis | head raised a BrokenPipeError traceback — now caught and exits cleanly. ls <folder> now degrades to an SSH hint on the FileStation 400/407 denial.
  • 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.