| Protocols | FTP | FULL | wired via OpenDAL FTP backend |
| Protocols | FTP-SSL (FTPS) | FULL | wired via OpenDAL FTP/TLS backend |
| Protocols | SFTP (SSH) | FULL | wired via OpenDAL SFTP backend (key auth) |
| Protocols | WebDAV (HTTP) | FULL | wired via OpenDAL WebDAV backend |
| Protocols | WebDAV (HTTPS) | FULL | wired via OpenDAL WebDAV/TLS backend |
| Protocols | Amazon S3 | FULL | wired via OpenDAL S3 backend (+ S3-compatible endpoints) |
| Protocols | Google Cloud Storage | FULL | wired via OpenDAL GCS backend |
| Protocols | Azure Blob Storage | FULL | wired via OpenDAL Azblob backend |
| Protocols | Backblaze B2 | FULL | wired via OpenDAL B2 backend |
| Protocols | OpenStack Swift | FULL | wired via OpenDAL Swift backend |
| Protocols | Google Drive | FULL | wired via OpenDAL Gdrive backend (app-supplied OAuth token) |
| Protocols | Dropbox | FULL | wired via OpenDAL Dropbox backend (app-supplied OAuth token) |
| Protocols | Microsoft OneDrive | FULL | wired via OpenDAL OneDrive backend (app-supplied OAuth token) |
| Protocols | Box | PARTIAL | no OpenDAL backend in 0.57; reports needs_transport (honest) |
| Protocols | Local filesystem | FULL | fully wired std::fs transport — list/mkdir/delete/rename/copy |
| Protocols | Protocol/scheme detection | FULL | scheme + aliases (https->WebDAVS, ssh->SFTP) -> Protocol |
| Protocols | Default ports per protocol | FULL | standard ports filled in on import |
| Bookmarks | Bookmark list | FULL | list saved bookmarks |
| Bookmarks | Add bookmark from URL | FULL | scheme://user@host:port/path parsed into a Bookmark |
| Bookmarks | Edit bookmark | FULL | replace a bookmark's fields |
| Bookmarks | Remove bookmark | FULL | delete bookmark + drop its session credential |
| Bookmarks | Import Cyberduck .duck bookmark | FULL | plist <dict> Protocol/Hostname/Port/Username/Nickname/Path |
| Bookmarks | Bookmark URL round-trip | FULL | canonical scheme://user@host:port/path, default port omitted |
| Bookmarks | Nickname | FULL | display name from .duck Nickname or hostname |
| Bookmarks | Default remote path | FULL | opened on connect |
| Bookmarks | Connect mode (passive/active) | PARTIAL | modeled + persisted; applied when the FTP backend lands |
| Bookmarks | Per-bookmark encoding | PARTIAL | UTF-8 default modeled; applied with the transport |
| Bookmarks | Per-bookmark transfer action | FULL | the bookmark transfer_action drives collision handling on every transfer |
| Bookmarks | Per-bookmark connection limit | FULL | scheduling enforces each bookmark's max_connections |
| Bookmarks | Import FileZilla / other clients | FULL | FileZilla sitemanager.xml import (all servers) via bookmark.import_filezilla |
| Bookmarks | Bonjour / zeroconf discovery | MISSING | not modeled |
| Bookmarks | Recent-server history | FULL | recently-connected bookmarks tracked (profile.recent), capped at 20 |
| Browser | Directory listing | FULL | wired via OpenDAL for every protocol (name/path/is_dir/size) |
| Browser | File attributes (size/mtime/perms) | PARTIAL | size+mtime populated for all protocols; POSIX permissions on Local only (OpenDAL doesn't surface remote mode bits) |
| Browser | Create directory | FULL | wired via OpenDAL create_dir |
| Browser | Delete file / directory | FULL | wired via OpenDAL (recursive delete_options) |
| Browser | Rename / move | FULL | wired via OpenDAL rename |
| Browser | Local filesystem browse | FULL | real std::fs directory enumeration |
| Browser | Listing sort (dirs first) | FULL | directories first, then by name |
| Browser | Show hidden files | FULL | dotfiles filtered in fs.list unless settings.show_hidden |
| Browser | Browser filter / search | FULL | client-side name filter wired in the browser pane (drawFiles) |
| Browser | Quick Look preview | FULL | content preview via fs.peek — text shown inline, binary flagged, ranged read (no full download) |
| Browser | Info / permission editor | FULL | info modal: metadata + permission editing via fs.chmod (Local; remote object stores have no perms) |
| Transfers | Download | FULL | wired via OpenDAL read -> local file |
| Transfers | Upload | FULL | wired via OpenDAL write from local file |
| Transfers | Transfer queue | FULL | enqueue / lookup / progress / terminal states |
| Transfers | Queue concurrency cap | FULL | respects the global concurrent-transfer limit |
| Transfers | Byte progress | FULL | transferred/total + fractional progress |
| Transfers | Transfer speed (throughput) | FULL | per-second in/out rate from byte samples |
| Transfers | Cancel transfer | FULL | cancel a queued/running transfer |
| Transfers | Clear finished transfers | FULL | drop terminal transfers from the queue |
| Transfers | Resume partial transfer | FULL | byte-offset resume: appends the remote range to the partial local file (Resume action) |
| Transfers | Collision handling (overwrite/rename/skip) | FULL | overwrite / skip / rename applied per file at transfer time |
| Transfers | Recursive directory transfer | FULL | directory sources recurse for download and upload, per file |
| Transfers | Bandwidth throttle | FULL | chunked + paced download and upload to settings.bandwidth_limit_kbps |
| Synchronization | Synchronize local <-> remote | FULL | bidirectional recursive newest-wins synchronise |
| Synchronization | Comparison (newer / size) | FULL | newer-mtime / size-diff comparison drives sync and the Compare action |
| Sessions | Connect | FULL | builds + root-stat-validates the OpenDAL operator; honest error on failure, never faked |
| Sessions | Disconnect | FULL | graceful teardown to Disconnected |
| Sessions | Session status | FULL | disconnected/connecting/connected/disconnecting/error |
| Sessions | Connection log | FULL | bounded per-session log + session.logs |
| Sessions | Multiple simultaneous sessions | FULL | per-bookmark session tracking |
| Sessions | Lifecycle state machine | FULL | enforced transitions; double-connect rejected |
| Sessions | Reconnect on drop | FULL | connect retried up to settings.reconnect_attempts times on transient failure |
| Credentials | Username / password auth | FULL | passed into the OpenDAL backends (FTP/WebDAV/S3/B2/Azure) |
| Credentials | Private key (SFTP) | FULL | private-key path wired into the OpenDAL SFTP backend |
| Credentials | Key passphrase | PARTIAL | modeled in the credential |
| Credentials | Anonymous login | FULL | empty FTP username logs in anonymously (anonymous / anonymous@) |
| Credentials | Keychain / Secret Service storage | MISSING | session-only today; OS keychain is the phased deliverable |
| Credentials | Cloud token / OAuth | PARTIAL | engine consumes app-supplied OAuth access tokens (Gdrive/Dropbox/OneDrive); interactive OAuth flow is app-layer |
| App | Bookmark sidebar GUI | FULL | sidebar with live status dots + selection |
| App | Connect / disconnect action | FULL | state-aware action button per bookmark |
| App | File browser pane | FULL | listing with name/size/permissions |
| App | Transfer queue pane | FULL | per-transfer kind/path/status + percent |
| App | Status / throughput readout | FULL | human-readable byte sizes |
| App | Log viewer | FULL | live per-session log pane |
| App | Connect-to-server dialog | FULL | URL entry + nickname |
| App | Command palette | FULL | command palette (Cmd/Ctrl-K) |
| App | Embedded terminal | FULL | shared zpwr-embed-terminal panel |
| App | Theme toggle | FULL | dark / light HUD themes |
| App | Profile persistence | FULL | bookmarks + settings saved as JSON |
| App | Preferences | FULL | preferences modal edits settings (show_hidden / concurrency / bandwidth / reconnect) via settings.get+set |
| App | Drag-and-drop transfer | FULL | drop local files onto the browser pane to queue uploads |
| Browser | Batch rename (regex/sequence/case) | FULL | fs.rename_plan previews find/replace + case + zero-padded sequence + prefix/suffix (extension preserved); GUI batch-rename overlay applies via fs.rename — beyond Cyberduck (ForkLift/Transmit) |
| Protocols | Directory-listing parsers (Unix/DOS/MLSD/EPLF) | FULL | listing.parse auto-detects + normalizes ls -l / Windows-IIS / MLSD / EPLF into RemoteFile (FileZilla/lftp/WinSCP) |
| Protocols | FTP reply parsing (single + multiline) | FULL | ftp.parse_reply decodes RFC959 replies with code class + completeness (FileZilla/lftp) |
| Protocols | PASV data-address parsing | FULL | ftp.parse_pasv decodes the 227 passive-mode host/port sextet (FileZilla/lftp) |
| Protocols | EPSV data-port parsing (RFC 2428) | FULL | ftp.parse_epsv decodes the 229 extended-passive port (FileZilla/lftp) |
| Bookmarks | Import WinSCP sessions (.ini) | FULL | bookmark.import_winscp reads Sessions HostName/Port/User/FSProtocol/Ftps (WinSCP) |
| Browser | POSIX permission math (chmod/umask) | FULL | perms.chmod/format apply octal or symbolic (u+rwx, go-w) honoring umask; octal to rwx both ways (WinSCP/lftp/ForkLift) |
| Browser | Path canonicalization | FULL | path.normalize resolves dot / dot-dot and collapses repeated slashes (lftp/rclone) |
| Transfers | Include/exclude filter rules (glob) | FULL | filter.match/apply — shell glob (?, *, **, char-class) with first-match-wins ruleset (rclone/lftp) |
| Transfers | Checksum verification (CRC32/Adler32) | FULL | checksum.compute/verify_file over CRC-32 (IEEE) and Adler-32 (rclone check / FileZilla verify) |
| Transfers | Segmented transfer range math | FULL | transfer.segments splits a byte length into N gap-free ranges (lftp pget -n / rclone multi-thread) |
| Transfers | Preflight batch cost/ETA estimator | FULL | zftp ORIGINAL — transfer.estimate: total bytes + ETA at the cap BEFORE enqueue (beyond FileZilla/WinSCP/rclone) |
| Synchronization | Mirror dry-run diff (bidirectional) | FULL | sync.plan diffs local vs remote trees into upload/download/skip/conflict rows (rclone bisync / lftp mirror --dry-run) |
| Transfers | Content digests (MD5/SHA-1/SHA-256) | FULL | checksum.compute routes MD5 (RFC1321) / SHA-1 (RFC3174) / SHA-256 (FIPS180-4) — self-contained, checked vs published vectors (rclone md5sum/sha1sum, Cyberduck/WinSCP verify) |
| Credentials | SSH host-key fingerprint (MD5+SHA256) | FULL | ssh.fingerprint computes OpenSSH MD5 colon-hex + SHA256 base64 host-key fingerprints from a key blob/line (Cyberduck/WinSCP/OpenSSH host verification) |
| Protocols | SFTP packet framing (SSH_FXP) | FULL | sftp.parse_packet/build_init frame + decode the length-prefixed SSH-FXP wire packets (WinSCP/FileZilla SFTP wire layer) |
| Protocols | SFTP file-attribute (ATTRS) decode | FULL | sftp.parse_attrs decodes the SSH_FXP_ATTRS size/uid/gid/perms/atime/mtime record with presence flags (WinSCP/FileZilla STAT) |
| Protocols | FTP active-mode PORT/EPRT + FXP relay | FULL | ftp.build_port/build_eprt/fxp_port build active-mode PORT (inverse of PASV), RFC2428 EPRT, and the site-to-site FXP relay (FileZilla/lftp) |
| Credentials | .netrc auto-login parsing | FULL | creds.parse_netrc tokenizes machine/login/password/account/default with exact-then-default lookup (lftp/ftp/curl ~/.netrc) |
| Transfers | Brace expansion ({a,b} / {1..n}) | FULL | filter.expand expands comma/nested/numeric-range braces before globbing (bash/lftp mget) |
| Transfers | Base64 transcode (RFC 4648) | FULL | codec.base64_encode/decode standard base64 with padding — HTTP Basic auth / SSH key blobs / .duck data (FileZilla/Cyberduck wire layer) |
| Browser | Path decomposition (dir/base/stem/ext) | FULL | path.split decomposes a normalized POSIX path into directory/base/stem/extension, dotfile-aware (Transmit/Cyberduck path bar + batch rename) |
| Transfers | Retry backoff schedule (exponential) | FULL | transfer.backoff computes capped exponential-backoff retry delays (lftp net:reconnect-interval / rclone --retries backoff) |
| Protocols | FTPS/TLS session negotiation (RFC 4217) | FULL | ftps.negotiate builds the AUTH TLS / PBSZ 0 / PROT command sequence for explicit + implicit FTPS (FileZilla/WinSCP FTPS) |
| Protocols | SFTP version negotiation (v3-v6) + extensions | FULL | sftp.negotiate picks min(client,server) version + flags v4/5/6 attrs; sftp.parse_extensions decodes the VERSION extension-pair list (WinSCP) |
| Protocols | SCP protocol control framing | FULL | scp.parse_control/build_control encode the C/D/E/T sink-source control lines (WinSCP/OpenSSH scp) |
| Protocols | S3 request signing (AWS SigV4) | FULL | s3.sign derives the SigV4 canonical request to string-to-sign to signing key to hex signature, verified vs the AWS get-vanilla test vector (rclone/Cyberduck/CloudMounter S3) |
| Protocols | Azure Blob SharedKey signing | FULL | azure.sign builds the canonicalized SharedKey string-to-sign + base64 HMAC-SHA256 signature over the account key (CloudMounter/Cyberduck Azure) |
| Protocols | WebDAV PROPFIND/multistatus framing | FULL | webdav.propfind_body + parse_multistatus build the listing request + parse the 207 Multi-Status into resources, prefix-tolerant (Cyberduck/CloudMounter DAV) |
| Protocols | Proxy framing (SOCKS5 / HTTP CONNECT) | FULL | proxy.socks5_connect/parse_socks5_reply/http_connect frame RFC1928 SOCKS5 + HTTP CONNECT tunnels with Basic auth (FileZilla/lftp proxy) |
| Credentials | Connection-profile encryption (PBKDF2 + AEAD) | FULL | profile.encrypt/decrypt guard saved credentials with PBKDF2-HMAC-SHA256 key + SHA256-CTR keystream + HMAC-SHA256 tag, vector-checked (WinSCP master password/Transmit) |
| Synchronization | Compare modes (size / size+mtime / checksum) | FULL | sync.compare decides file equality under size-only / size+mtime / checksum modes (rclone --size-only/--checksum, lftp mirror) |
| Synchronization | Conflict resolution policy | FULL | sync.resolve applies newer/larger/local/remote/keep-both to a conflicting path (rclone --conflict-resolve, lftp overwrite policy) |
| Synchronization | Symlink handling policy | FULL | sync.symlink_policy resolves skip/follow/preserve/error per encountered link (rclone --links/--copy-links, lftp) |
| Synchronization | Tree serialize + content fingerprint | FULL | zftp ORIGINAL — tree.serialize/fingerprint canonicalize a tree + SHA-256 Merkle root for O(1) equality; tree.diff classifies add/remove/modify (beyond ForkLift/Beyond Compare folder compare) |
| Transfers | Resume verification | FULL | transfer.resume_check decides resume/restart/complete + byte offset from partial size, remote size, and overlapping-prefix checksums (lftp/FileZilla resume) |
| Transfers | Weighted-fair bandwidth scheduler | FULL | zftp ORIGINAL — queue.schedule orders by priority + shortest-job-first and splits a bandwidth budget by weight with a per-job starvation floor (beyond FileZilla queue priorities) |
| Transfers | Glob to regex translation | FULL | filter.glob_to_regex compiles a shell glob to an anchored regex (?->[^/], *->[^/]*, **->.*) for a regex backend (rclone filter/lftp) |
| Browser | Recursive chmod (capital-X rule) | FULL | perms.chmod_recursive applies a spec over a tree honoring X (dirs / already-exec only), the chmod -R a+rX idiom (WinSCP/ForkLift) |
| Browser | De-duplication rename plan | FULL | dedup.plan appends " (N)" before the extension to resolve name collisions, bumping past existing suffixes (rclone dedupe/ForkLift) |
| Protocols | MLSD/MLST fact parsing (RFC 3659) | FULL | ftp.parse_mlsx decodes typed MLSx facts (type/size/modify/perm) + name into a normalized entry, the machine-typed listing FileZilla/lftp prefer over ls -l |
| Protocols | FEAT capability + OPTS UTF8/MLST/TVFS | FULL | ftp.parse_feat parses a FEAT reply into the capability set (UTF8/MLST/TVFS/MDTM/SIZE/REST) and emits the OPTS UTF8 ON / OPTS MLST follow-ups (FileZilla) |
| Protocols | SFTP realpath/readlink/symlink requests | FULL | sftp.build_path_op frames SSH_FXP_REALPATH/READLINK/SYMLINK requests (OpenSSH linkpath order) (WinSCP/OpenSSH SFTP) |
| Protocols | SFTP statvfs@openssh.com decode | FULL | sftp.parse_statvfs decodes the remote-filesystem space/inode counters + bytes-available (WinSCP remote free-space) |
| Credentials | known_hosts verification (plain + hashed) | FULL | knownhosts.verify parses known_hosts (plaintext, [host]:port, wildcard, hashed |1| HMAC-SHA1) into match/changed/unknown/revoked (Cyberduck/WinSCP/OpenSSH) |
| Credentials | SSH client-config resolution | FULL | ssh.config_resolve reads ~/.ssh/config Host globs with OpenSSH first-value-wins and resolves HostName/User/Port/IdentityFile/ProxyJump (OpenSSH/Transmit/Cyberduck) |
| Transfers | rsync rolling-checksum delta | FULL | delta.signature/plan compute the rsync weak rolling checksum + strong MD5 block signature and a Copy/Data delta that reconstructs the target exactly (rsync/lftp mirror incremental) |
| Browser | ZIP central-directory index | FULL | archive.zip_index walks the ZIP end-of-central-directory + central directory into per-member name/method/crc32/sizes without extracting (ForkLift/WinSCP archive browse) |
| Browser | tar (ustar) archive index | FULL | archive.tar_index walks the 512-byte ustar header blocks into per-member name/size/mode/mtime/type honoring the prefix field (ForkLift/WinSCP) |
| Protocols | Swift TempURL signing (HMAC-SHA1) | FULL | swift.temp_url builds the OpenStack Swift TempURL HMAC-SHA1 signature + query string over METHOD/expires/path (rclone/CloudMounter Swift) |
| Protocols | Backblaze B2 authorization header | FULL | b2.authorization builds the b2_authorize_account Basic base64(keyId:appKey) header for the B2 native API (rclone/Cyberduck/CloudMounter B2) |
| Transfers | Multipart/chunked upload planner | FULL | transfer.multipart_plan lays out upload parts respecting the min-part floor + max-parts ceiling, raising part size to fit (rclone/Cyberduck/CloudMounter S3 multipart) |
| Transfers | Retry classification (transient vs fatal) | FULL | retry.classify labels FTP/HTTP/errno codes transient (retry) vs fatal, so a 421 retries and a 550 does not (lftp net:persist-retries / rclone low-level vs fatal) |
| Transfers | Connection pool + keepalive model | FULL | pool.acquire/maintain decide reuse-LRU/open/wait and which idle conns to reap vs NOOP-keepalive (FileZilla/WinSCP connection reuse + keepalive) |
| Transfers | Transfer-integrity manifest | FULL | zftp ORIGINAL — manifest.build/verify produce a canonical whole-transfer manifest + Merkle root and report per-file ok/corrupt/missing/extra proving the entire batch arrived intact (beyond rclone check / FileZilla per-file verify) |
| Browser | Remote-edit temp-file mapping | FULL | edit.map maps a remote file to a deterministic, filesystem-safe, extension-preserving local temp path with change detection for write-back (Cyberduck/Transmit/WinSCP Edit) |
| Transfers | Token-bucket bandwidth limiter | FULL | bandwidth.token_bucket simulates a capacity+rate token bucket over a request stream into the per-chunk grant/delay schedule (lftp net:limit-rate / rclone --bwlimit) |
| Protocols | S3 pre-signed URL (SigV4 query) | FULL | s3.presign generates an AWS SigV4 query-string pre-signed object URL, verified vs the AWS documented example (rclone link / aws s3 presign) |
| Protocols | S3 CompleteMultipartUpload XML | FULL | s3.complete_multipart builds the CompleteMultipartUpload body with parts sorted + ETags XML-escaped (rclone/Cyberduck/CloudMounter S3 multipart finalize) |
| Protocols | S3 ListObjectsV2 XML parse | FULL | s3.list_objects parses a ListBucketResult into objects/common-prefixes/truncation/continuation-token (rclone/Cyberduck S3 listing) |
| Protocols | SFTP OpenSSH extensions (fsync/hardlink/posix-rename) | FULL | sftp.build_ext_op frames the fsync@/hardlink@/posix-rename@openssh.com SSH_FXP_EXTENDED requests for atomic swap + server-side link (WinSCP/rsync) |
| Protocols | SCP recursive-tree walk | FULL | scp.walk replays a recursive (scp -r) C/D/E/T control stream into a flat node list with full paths, modes, sizes + mtimes (OpenSSH scp sink/WinSCP) |
| Transfers | rclone filter-rule engine (+/-) | FULL | filter.parse_rules parses an rclone --filter file (+ pat / - pat, comments) into a first-match-wins keep/drop set (rclone filter) |
| Transfers | Max-min fair-share bandwidth split | FULL | bandwidth.fair_share divides a global --bwlimit across N transfers by max-min fairness, redistributing an idle flow's surplus (fairer than one token bucket) |
| Transfers | Partial integrity-repair plan | FULL | zftp ORIGINAL — integrity.repair_plan coalesces failed block indices into the minimal set of byte ranges to re-download, healing a corrupt file without a full re-transfer (beyond rclone/FileZilla whole-file re-copy) |
| Transfers | Checksum sidecar parse + verify (.sfv/.md5/SHASUMS) | FULL | sidecar.parse/verify read SFV (CRC-32) and coreutils md5sum/shaNsum sidecars and verify computed digests into match/mismatch/missing (FileZilla/WinSCP/rclone verify-from-sidecar) |
| Browser | Directory delta-listing cache | FULL | zftp ORIGINAL — dircache.diff diffs a previous vs current listing snapshot into added/removed/modified/unchanged so a panel highlights what changed instead of repainting (beyond FileZilla/Cyberduck re-list) |
| Transfers | Resumable chunked-upload session (GCS/OneDrive) | FULL | gcs.resumable_plan lays out alignment-corrected (256K GCS / 320K OneDrive) chunks with Content-Range headers + final flag; gcs.resume_offset parses the committed-bytes Range header (rclone gcs/onedrive resumable upload) |