A small, dependency-free Nextcloud WebDAV CLI for automation and agent workflows.
It is intentionally boring: one Python script, curl under the hood, semantic exit codes, JSON output, chunked uploads, and atomic verified downloads.
Most Nextcloud automation snippets are fragile curl one-liners. They often save XML error pages as files, treat 404s as success, leak credentials in process argv, or break on large uploads.
This CLI is designed to be safe enough for scripts and autonomous agents:
- semantic exit codes for reliable branching
--jsonoutput for every command- credentials passed to curl through stdin config, not
-u user:tokenargv - chunked upload support for large files
- atomic
.partdownloads with size validation - safer delete semantics for directories and protected roots
- no Python package dependencies
Clone and install:
git clone https://github.com/abner-augusto/nc-cli.git
cd nc-cli
./install.shThe command name is nc-cli, because nc usually means netcat on Unix systems.
This project intentionally does not ship an nc alias.
Run directly:
./bin/nc-cli --versionSet these environment variables:
export NEXTCLOUD_URL="https://cloud.example.com"
export NEXTCLOUD_USER="your-nextcloud-username"
export NEXTCLOUD_APP_PASSWORD="your-nextcloud-app-password"The script also reads ~/.hermes/.env for Hermes Agent deployments. For general use, exporting variables in your shell, systemd unit, or secret manager is cleaner.
Create a Nextcloud app password under:
Settings → Security → App passwords
nc-cli ls /
nc-cli mkdir /Backups
nc-cli upload ./backup.zip /Backups/backup.zip
nc-cli download /Backups/backup.zip ./backup.zip
nc-cli info /Backups/backup.zip --json
nc-cli share /Backups/backup.zipLarge uploads are chunked automatically when they exceed the chunk size, default 100 MB:
nc-cli upload ./huge.tar.zst /Backups/huge.tar.zst
nc-cli upload ./huge.tar.zst /Backups/huge.tar.zst --chunk-size 50
nc-cli upload ./huge.tar.zst /Backups/huge.tar.zst --no-chunkls [path] [--json] [--recursive]
upload <local> <remote> [--json] [--no-chunk] [--chunk-size MB] [--no-clobber]
download <remote> <local> [--json]
mkdir <path> [--json]
mv <src> <dst> [--json] [--overwrite]
cp <src> <dst> [--json] [--overwrite]
rm <path> [--json] [--recursive] [--force]
search <query> [path] [--json]
info <path> [--json]
quota [path] [--json]
share <path> [--json] [--pw PASS|--password-env VAR|--password-stdin]
version
help
All commands support the same wrapper:
{
"ok": true,
"http_code": "207",
"data": {},
"error": null
}Example:
nc-cli upload ./file.txt /Uploads/file.txt --json{
"ok": true,
"http_code": "201",
"data": {
"operation": "upload",
"path": "/Uploads/file.txt",
"bytes": 123,
"chunked": false
},
"error": null
}Full schema: docs/json-output.md.
0: success2: not found / HTTP 4043: auth failure / HTTP 401 or 4034: conflict / HTTP 409 or 4125: server error / HTTP 5xx or unsupported server method6: network error, curl failure, timeout, or incomplete download7: usage error or unsafe operation refused8: size limit / HTTP 4139: checksum mismatch / HTTP 400 on checksum-checked upload
Directory deletion is recursive in WebDAV, so this CLI refuses dangerous deletes by default:
nc-cli rm / # refused
nc-cli rm /SomeDir # refused: directory requires --recursive
nc-cli rm /SomeDir --recursive # allowed
nc-cli rm /Backups --recursive --forceProtected top-level paths require --force in addition to --recursive:
/HERMES-DROP/Obsidian/_INTEGRARTE.ARQ
Those names come from the original Hermes/Nextcloud deployment. Override them without patching code:
export NC_PROTECTED_DELETE_PATHS="/Backups,/Shared Team Folder"Set it to an empty string to disable protected-path checks except for /, which is always refused.
python -m py_compile bin/nc-cli
python -m pip install pytest
pytest -qThe unit suite does not require a live Nextcloud server. It tests command behavior with monkeypatched curl calls.
The original project came from a Hermes Agent skill. If you use Hermes, keep a thin skill wrapper that points to this repository and documents your local deployment conventions.
Do not commit real Nextcloud URLs, users, or app passwords. Use examples/env.example as the template.
MIT.