shouldivibecodeit

Should I vibe codeTransmit?

Build a focused SFTP and object-storage client with bookmarks and transfer queue

An FTP client is a credential store with a file list on top. Yours will also skip host key verification.

?

Their verdict, the Transmit 5 licence price and the build-time estimate come from their entry, MIT-licensed. Checked 2026-08-04.

Can you build it?asked by canivibecodeit.com ↗YESone-shottable · one sitting
?

Our verdict, the regret score and everything below it. Editorial and unsponsored — nobody can pay to be moved.

Should you ship it?asked by usYOUR FUNERALit’ll work. then it’ll get you.

The honest answer

why the verdict is what it is

Listing a remote directory over SFTP is thirty lines, and an agent will produce them before your coffee is cold. The problem is everything that has to be true around those thirty lines. A transfer client is structurally a credential store — hostnames, usernames, passwords and key passphrases for the machines that run your business, saved precisely because typing them every time is the point of the app. Generated code puts those in a JSON file next to the binary, and generated SSH code accepts unknown host keys, because that is what makes the example work on the first run. Then somebody adds a sync mode, and now a path-join bug can delete a remote directory tree. Panic charges forty-five dollars once. That is nowhere near the expensive part of this decision.

What actually breaks

not "if". the specific failures.

  • Credential storage. A config file holding hosts and passwords is readable by every process running as you, and it rides straight into Time Machine, iCloud Drive and whichever backup you have forgotten about
  • Host key verification, which generated SSH code disables by default because that is what makes the tutorial run — and which is the only thing standing between café wifi and your production server
  • Sync and mirror modes, where one wrong path join turns 'upload my site' into a remote delete of everything that was not in the local folder
  • Partial uploads over a live file. Writing index.php in place serves a truncated file to every visitor for the duration of the transfer
  • Resume and integrity. Transfers get interrupted, and a client that reports success on a short file has corrupted the deploy silently
  • Permissions and ownership, which do not survive a naive upload and are the difference between a working site and a 500 you debug for an hour
and then, at 3am

The airport wifi is doing what airport wifi does, and your client connects to something claiming to be your production host. It has no stored fingerprint to compare against, because you never wrote that part — the library's example used an auto-add host key policy and it worked first try, so it stayed. You authenticate. Somewhere, a box now holds a valid username and password for the machine serving your customers, plus a copy of the deploy you were pushing. Nothing on your screen looks wrong: the transfer completes, the site loads, you close the laptop. You find out five weeks later from your host's abuse team, and the only honest answer to 'when were these credentials exposed' is 'any time I have used this on a network I do not own', which is not an answer anybody can work with.

Is that you?

the verdict is a default, not a law

ship it if
  • It is a script for one host, credentials come from ssh-agent or the environment, and it stores nothing
  • You are automating a single upload to a machine you could rebuild from scratch this afternoon
  • It never points at anything you cannot afford to lose or re-provision
don’t ship it if
  • It saves passwords or key passphrases anywhere other than the OS keychain
  • It does not verify host keys against a pinned store and hard-fail on mismatch
  • It has a delete, mirror or sync mode that can run without a dry run
  • It touches production, which for most people is the only reason they wanted it

If you build it anyway

the checklist, then the prompt that enforces it

  1. Do not implement the protocol. Use libssh2, paramiko or an equivalent maintained library, and configure it the way its security documentation says rather than the way its README example does.
  2. Verify host keys against a known_hosts store, pin on first use, and hard-fail on mismatch. Never expose 'accept any key' as an option, not even behind a checkbox you promise not to tick.
  3. Credentials belong in the OS keychain — Keychain Services, libsecret, DPAPI. Never a config file, never a plist you wrote, never a log line, never the crash reporter.
  4. Delete, mirror and sync are separate opt-in features that dry-run first, print the exact list of remote paths that would be removed, and require confirmation on that list.
  5. Upload to a temporary name and rename into place, so a live file is never half-written and a failed transfer leaves the old version serving.
  6. Verify after transfer: compare size, and a checksum wherever the server can produce one. A client that lies about success is worse than one that fails loudly.
  7. Redact credentials from every log line and every error path before you write the first log line, not after the first paste into an issue tracker.
the guardrail prompt
I am building a desktop SFTP and object-storage client with saved connections. This is a credential store before it is a file browser, so build it in that order and refuse the shortcuts.

1. Never implement SSH, TLS or FTP yourself. Use a maintained library and
   follow its security guidance rather than its quickstart example.
2. Host key verification comes first, before any transfer code. Maintain a
   known_hosts store, pin on first connection with an explicit fingerprint
   prompt, and hard-fail on any mismatch. There is no 'accept anyway' option,
   no auto-add policy and no insecure flag. If I ask for one, refuse and
   explain that a man-in-the-middle on untrusted wifi is the exact scenario
   this prevents.
3. Secrets go to the OS keychain, keyed by host and user. Nothing sensitive is
   ever written to a config file, a preferences plist, a cache or a log.
   Prefer ssh-agent and public-key auth over storing a password at all.
4. Redact credentials, tokens and signed URLs in every log statement and
   crash-report path before writing any logging code.
5. Build read-only browsing and download first, and let me use it before you
   write a single byte of upload code.
6. Uploads go to a temporary remote name and are renamed into place on
   success. A live file must never be visible half-written.
7. Verify after every transfer: compare byte size, and a checksum where the
   backend supports one. Report a mismatch as a failure, never as a warning.
8. Delete, mirror and sync come last, are individually opt-in, and always run a
   dry run first that prints the full list of remote paths to be removed and
   waits for confirmation on that exact list. No recursive delete may run from
   a computed path without me seeing the path.
9. Preserve and re-apply file modes on upload, and tell me when it cannot.
10. Object-storage credentials are per-profile and never global environment
    variables, and the app must never write them into a bookmark export.
11. Out of scope, and say so instead of half-building it: server-side
    scripting, scheduled jobs, credential sharing between machines, and
    anything that syncs my bookmarks anywhere.
paste this before you build — not after something breaks31 lines · 2171 chars

That one keeps you out of trouble. For the prompt that actually builds it, canivibecodeit.com has one.

their build prompt ↗

Or don’t build it

the boring option, and the way back out

just pay for it

Immediately, if any of this points at production. Transmit is forty-five dollars once and Cyberduck is free, and both have had their host-key handling, resume logic and sync semantics attacked by more people than will ever read your repository. You are not buying a file list. You are buying somebody else's decade of getting the dangerous parts wrong first, and a keychain integration that has been audited by people whose job that was.

your exit plan, if you already built it

Bookmarks should export as a plain list of hosts, users, ports and remote paths — which is exactly what Transmit and Cyberduck import. Credentials must not be in that export, because they should be in the keychain; if exporting your bookmarks also exports secrets, that is not a convenience, it is the bug this whole entry is about. On the way out, rotate every password and key passphrase the homemade client ever touched, since you do not know what it wrote where.

prior art · someone already did this
Cyberduck

Free, long-maintained Mac and Windows client for FTP, SFTP, WebDAV, S3 and most object stores.

rclone

The command-line answer, with an obsessive dry-run culture and encrypted credential storage built in.

Questions

Why is this YOUR FUNERAL rather than ABSOLUTELY NOT? It stores credentials.

Because of who is downstream. A password manager holds everything for everyone who uses it, and its failure mode is unbounded. A transfer client holds your own infrastructure credentials, on your own machine, for servers you control — the blast radius stops at your estate and the people it serves. That is a genuinely bad day rather than an unrecoverable one, and the distinction is worth keeping if ABSOLUTELY NOT is going to mean anything.

Is skipping host key verification really that likely?

It is close to the default outcome. Every SSH library's example code shows the permissive policy because strict verification fails on first connection and makes a quickstart look broken. Generated code reproduces examples. Unless you asked for pinning explicitly, assume you did not get it, and check before you connect from anywhere you do not control the network.

What is the actual risk in a sync feature?

That deletion is computed rather than chosen. Mirror mode's whole job is to make the remote match the local, which means it derives a list of remote paths to remove. One wrong base path, one trailing slash, one symlink followed, and that list is the entire document root. The remote has no undo and probably no snapshot, so a dry run that prints the deletions and waits is not a nicety — it is the only safety mechanism available.

did you build it?

Every week, someone ships something they shouldn’t have.

New verdicts, the worst thing that landed in the trap, and the occasional incident report. No other email, ever.

also on the regret index
TowerYOUR FUNERAL

Tower's whole pitch is command-Z. Your Undo button works on the operations that were never the problem.

1PasswordABSOLUTELY NOT

The one category where “I rolled my own” has never once been the happy ending.

GitKrakenYOUR FUNERAL

The CLI makes you type --force. Your GUI makes it a button, and the agent will not add --force-with-lease.

last reviewed 2026-08-04 · verdict is editorial and unsponsored · shared entry data from canivibecodeit under MIT · not legal advice