Zynk CLI
Automation
Use Zynk CLI one-shot commands, stdin path input, JSON output, dry-run previews, daemon mode, and unattended script habits.
One-shot commands
Automation starts from the one-shot command surface. It is the clearest contract: pass flags and arguments, receive output, and exit.
One-shot shape
$ zynk contacts$ zynk pending$ zynk send Bob report.pdfCommand lifecycle
- One-shot commands run a single action and exit.
- They can route through the daemon when the daemon is running.
- If daemon routing is unavailable, they still run the command directly.
Automation fit
- Use one-shot commands for shell scripts, CI helpers, local wrappers, and scheduled jobs.
- Use interactive shell commands when a human needs completions, progress, or repeated exploration.
- Use daemon mode when scripts run many Zynk commands over time.
Script contract
Treat each command as a small process boundary. Give it complete arguments, keep prompts out of unattended paths, and parse JSON only from commands that document JSON output.
- Surface
- Exit behavior
- Contract
- A successful one-shot command exits after its command-level work is complete. Invalid arguments, bad config, missing paths, and failed startup exit nonzero.
- Surface
- stdout
- Contract
- Human terminal output is the default. Supported successful
--json-outputcommands print one JSON object with a top-leveltypeanddatapayload.
- Surface
- stderr
- Contract
- Validation and startup errors can appear on stderr. Capture stderr separately in wrappers instead of treating it as machine data.
- Surface
- Prompts
- Contract
- Complete one-shot commands such as
pending,send <target> <path>, anddaemon statusdo not need interactive answers. Avoidinstallanduninstallin unattended scripts unless the flags answer the prompts you expect.
- Surface
- Stdin paths
- Contract
sendreads newline-separated paths from stdin only when no path arguments are present.
- Surface
- Daemon sends
- Contract
- A daemon-routed
sendreturns after the request is accepted or queued by the background process; it does not wait for every byte to finish transferring.
- Surface
- Unsupported JSON
- Contract
- If a command is not documented as JSON-stable, do not assume
--json-outputmakes its terminal output parseable.
Stdin paths
The most useful automation path is piping a file list into zynk send. This lets existing shell tools choose files while Zynk handles transfer.
Send from files or stdin
$ zynk send Bob report.pdf ./assets$ fd '*.jpg' | zynk send my:laptop$ rg --files | rg 'invoice' | zynk send AlicePath input
sendaccepts explicit files and folders.- When no path arguments are provided,
sendreads paths from stdin. - Use newline-separated path streams from tools such as
fd,find, orrg --files.
Scripting habits
- Quote paths with spaces when passing them directly.
- Prefer stdin when another command already has the file list.
- Keep the destination explicit in scripts.
JSON output
Use JSON output when a wrapper or script needs structured status instead of terminal text.
Machine output
$ zynk pending --json-output{"type":"pending","data":{"count":0,"transfers":[]}}$ zynk pending --include-messages --json-output{"type":"pending","data":{"count":1,"transfers":[{"index":0,"id":"<transfer-id>","name":"report.pdf","state":"pending"}],"messages":[]}}$ zynk daemon status --json-output{"type":"daemon_status","data":{"running":true,"pid":"12345","user":"<os-user>","uptime_secs":3600,"socket":"/tmp/zynk.sock","socket_exists":true,"lock_file":"<lock-file>"}}$ zynk daemon status --json-output{"type":"daemon_status","data":{"running":false,"pid":null,"user":null,"uptime_secs":null,"socket":"/tmp/zynk.sock","socket_exists":false,"lock_file":"<lock-file>"}}- Command
zynk pending --json-output- Top-level type
pending- Stable fields
data.countcounts transfer rows for the selected window. Each stable transfer row includesindex,idwhen available,name, andstate.data.messagesappears only with--include-messages.
- Command
zynk daemon status --json-output- Top-level type
daemon_status- Stable fields
data.running, nullable stringdata.pid, nullable OS usernamedata.user, nullabledata.uptime_secs,data.socket,data.socket_exists, anddata.lock_file.
- Command
zynk config path --json-output- Top-level type
config_paths- Stable fields
data.config_dir,data.user_config, anddata.system_config.
- Command
zynk show-state-dir --json-output- Top-level type
state_dir- Stable fields
data.pathfor the default or flag-selected state directory used by that run.
JSON boundary
--json-outputis global, but not every command emits a stable JSON payload.- Start with commands that are useful in wrappers:
pending,daemon status,config path, andshow-state-dir. - Treat each command's payload as its own shape instead of assuming all JSON output is interchangeable.
Useful payloads
pending --json-outputgives scripts a machine-readable incoming-transfer inbox.count: 0is a successful no-work result for the command's current time window.- If a script is looking beyond the default window, use
--allor--since <duration>deliberately. daemon status --json-outputgives scripts a machine-readable health check.- Add
--include-messagesonly when the wrapper needs recent incoming messages next to transfers.
JSON errors
JSON output gives wrappers a machine-readable success or error object when the command reaches the JSON-emitting path.
Error shape
$ zynk pending --json-output{"type":"error","code":"<error-code>","message":"<message>"}# stderr may also contain non-JSON diagnostics for startup or argument failuresWrapper handling
- Read the top-level
typebefore readingdata. - Only parse
datawhentypeis the success shape the wrapper expected. - Error objects use top-level
codeandmessage; they do not have the successdataenvelope. - Treat a nonzero process exit as failure even when stdout contains JSON.
stderr is separate
- Startup, validation, and environment failures can still write diagnostic text to stderr.
- Not every failure reaches the JSON-emitting path.
- Capture stderr separately from stdout in scripts.
- Do not try to parse stderr as JSON.
Wrapper example
A small wrapper can let shell tools choose files, preview the action, then run the transfer only after the preview looks right.
Dry-run then send matching paths
$ paths="$(mktemp)"$ trap 'rm -f "$paths"' EXIT$ rg --files "$HOME/Invoices" | rg 'invoice' > "$paths"$ zynk --dry-run send Alice < "$paths"$ zynk send Alice < "$paths"The file list is captured once so the dry run and real send use the same paths.
Dry runs
Dry runs are the bridge between automation and human approval. They let a wrapper inspect the planned action before it executes.
Preview actions
$ zynk --dry-run send Bob report.pdf$ zynk --dry-run accept 0 ~/DownloadsDry-run output is preview JSON, for example send_preview with destination, device, and files, or accept_preview with selector and destination. It is not proof that a real transfer happened.
Dry-run rules
--dry-runpreviews what an action would do without executing it.--dry-runalways bypasses daemon routing.- Use dry runs before wrappers ask a human to confirm a transfer.
Review before execution
- Compare dry-run output against the transfer or accept action your wrapper plans to run.
- A dry run does not replace user permission when a script will transmit real files.
- Keep preview output distinct from JSON status output.
Unattended scripts
Unattended scripts need the account, state directory, executable path, and log handling to be explicit.
Cron or server wrapper
#!/usr/bin/env bashset -euo pipefailexport PATH="$HOME/.local/bin:$PATH"status_json="$(zynk --config ./server.zynk.conf --persistence /var/lib/zynk daemon status --json-output 2>zynk.err)"if ! jq -e '.type == "daemon_status" and .data.running == true' <<<"$status_json" >/dev/null; then echo "Zynk daemon is not running" >&2 cat zynk.err >&2 exit 1fizynk --no-color --json-output pendingUse any JSON parser your environment provides; the important gate is .type == "daemon_status" and .data.running == true before continuing.
Environment
- Set
PATHexplicitly instead of relying on an interactive shell profile. - Pass
--configand--persistencewhen the script must use a specific account or state directory. - Use
daemon status --json-outputas the first health check before a batch of routed commands.
Output handling
- Use
--json-outputonly on commands with documented JSON shapes. - Use
--no-colorfor plain fallback terminal output. - Write stderr and daemon logs somewhere you can inspect after an unattended run.
Daemon scripts
Daemon mode makes repeated scripts cheaper while keeping the background process explicit and observable.
Warm daemon flow
$ zynk --run-mode server$ zynk daemon status --json-output$ zynk pending --json-outputDaemon automation
- Start the daemon explicitly with
zynk --run-mode server. - Check health with
zynk daemon status --json-output. - Stop it with
zynk daemon killwhen rotating accounts, changing state, or investigating stale behavior.
Server discipline
- Persist
persistenceon servers so identity survives restarts. - Avoid running multiple daemons against the same state directory.
- Use logs for daemon lifecycle diagnosis.
Shell completions
Shell completions are an interactive convenience. Keep them separate from automation contracts and unattended script checks.
Generate completions
$ zynk completions zsh > ~/.zsh/completions/_zynk$ zynk completions bash > /etc/bash_completion.d/zynk$ zynk completions fish > ~/.config/fish/completions/zynk.fishSupported shells
zynk completions zshgenerates zsh completions.zynk completions bashgenerates bash completions.zynk completions fishgenerates fish completions.zynk completions powershellgenerates PowerShell completions.zynk completions elvishgenerates Elvish completions.
Install notes
- Completions are generated and redirected by the user.
- Completion generation does not route through the daemon.
- The installer can print completion-generation hints after PATH setup.
- They are useful for humans typing commands, not for machine contracts.