pālana

Help

A practical guide to the app: install it, connect hosts, move files, work with ZFS, and understand every plan before it runs.

What pālana is#

pālana is a two-pane file manager for people with servers. Either pane can address any machine you can reach over SSH: your NAS on the left, your media host on the right, or your Mac in either pane. Browse, copy, move, and rename across those hosts from one window.

Its central rule: nothing runs until you've seen it. Press the copy key and pālana doesn't copy—it shows you the plan: what it's about to do in plain words, and the exact command underneath. Press Enter, and it runs precisely that, with live output. Press Esc, and nothing happened.

If you can use SSH, you can use pālana. Terminal users will recognize the vim keys; everyone else can start with the window, labeled.

Install it#

  1. Download the .dmg from the releases page. It is signed and notarized for macOS.
  2. Drag pālana to Applications and open it. macOS 14 or later.
  3. That's the install. Nothing goes on your servers — pālana uses the ssh and rsync they already have.

Free and open source, GPL-3.0. Currently v0.4-beta; expect rough edges. Report broken or missing behavior in the issue tracker.

Connect your machines#

There's no account and no server list to fill in. pālana reads ~/.ssh/config—the file on your Mac that already knows your machines. If you can type ssh koan in a terminal and land on koan, then koan is already in pālana's menus. That's the whole model: your SSH setup is the setup.

Never touched that file? Open Settings (⌘,) and click Add a host. It asks five small questions—a nickname, the address, your username—shows you the exact lines it will write, backs the file up, and writes them. If you don't have an SSH key yet, it shows you the two commands that make one and install it. It never runs them for you; your keys stay yours.

Two things worth knowing on day one:

local is a host. Point a pane at local:~ and pālana is a regular file manager for your Mac — useful long before you have a rack.

~ means the server's home, not your Mac's. koan:~ resolves to the home directory for the user your config uses on koan.

Get around#

Click the address at the top of a pane and type host:path — or press ⇧⌘G for the same thing as a dialog. The at the pane's corner lists every host you have. After that, it's a file manager:

or j kmove the cursor—arrows and vim keys are both first-class
enter a folder, or open a file in its Mac app
/ hup to the parent
tabswitch panes
/jump—type a few letters, the cursor finds the file
spaceselect, and move to the next row
8star a folder—* opens your favorites

For the complete key map, see the keyboard. ? opens the same reference inside the app.

Copy & move#

Select files with space. Press y to copy them to the other pane, or m to move them. The panel at the bottom opens and shows the plan; nothing has run yet:

move · the plan ⏎ enter runs
⏎ press enter to run this plan · esc dismisses it
move · move to another machine
1 entry · 41.3 GB
jodo:/tank/media/camera → koan:/rpool/cold
how: rsync, run host-to-host · using the forwarded ssh key

$ rsync -a -s --partial --info=progress2 /tank/media/camera/archive-2025 koan:/rpool/cold/
  runs only after the copy above is verified: $ rm -rf /tank/media/camera/archive-2025

Read the plan top to bottom. The first line classifies the operation; here, it is a move to another machine. A same-disk move is marked instant. A move that requires copying and deleting is named as such. The middle lines show size, destination conflicts, route, and transport. The final line is the exact command that will run.

Press and it runs right there, output streaming, progress bar moving, ending with done—every step ran and checked out. Press esc and it's as if you never asked.

Between two servers, the fast path is server to server. Your Mac issues the command; it is not in the byte path. For a 41 GB folder, that can be the difference between minutes and an afternoon.

Notice the last line of the plan too: on a move, the delete half is gated. pālana copies, then counts files on both ends, and only deletes the originals when the counts agree. You watch all of it happen — the counting is two visible commands, not a spinner. If you're interested in why plans work this way, read the plan is the product.

Delete, rename, create#

Same rhythm, different letters—every one shows its plan first.

d deletes the selection—the plan shows the exact rm before Enter releases it. r renames the file under the cursor: a name field opens, you type, —and the composed command checks the new name first, so a rename can never overwrite an existing file. a creates: type a name for a file, end with / for a folder. t touches—bumps the modification time, for when a tool downstream cares.

Drag & drop#

Dragging works the way your hands expect, with one pālana twist: a drop never acts by itself—it composes the same plan the keys do, and waits for your Enter.

Drag between panes to copy; hold to move instead. Drop onto a folder row and the files land inside that folder. Drag in from Finder; drag out of a local pane to anywhere on your Mac—Mail, a browser upload, the Desktop.

Edit a remote file#

Press on a config file sitting on a server, and it opens in whatever app you'd normally use. pālana notes, in one line, that it's watching: save the file, and it offers to send your edit back to the server — as a plan, naturally. Prefer zero friction? Flip one setting and save just means save: edits go back on their own.

The exception that never changes: if the file changed on the server while you were editing, pālana always stops and asks before your version overwrites theirs.

Preview & the shell#

v turns the right pane into a preview that follows your cursor in the left—text files, images, PDFs. Remote text is fetched frugally (a bounded read, not the whole file); remote binaries stay a facts card instead of a surprise download.

⌘` opens a real terminal on the focused host, right under your panes—your actual ssh, one live session per host, kept warm. The footer always tells you who has the keyboard, and ⌘` hands it back. For quick questions without a shell, ` arms the read keys: d z s p drop df, zfs list, zpool status, zpool list into the panel.

See the whole field#

Press f and the map appears: every machine, its pools and datasets, what it can do (zfs? rsync? sudo?), and when you last looked—reachable · 2 days ago. Pick a node, press , and a pane is there. Press r on any host to re-probe it fresh. F floats a deeper version—every mount on every machine—that you can park on a second display.

pālana shows cached facts with their age and refreshes only when you ask. There is no polling or daemon. When pālana is closed, it has no background process. More on the field →

Datasets & snapshots#

If your servers run ZFS, pālana speaks it natively. In a normal pane, a filled drive mark on a folder means it's a dataset's mountpoint—which is why pālana always knows whether your "move" is instant or actually a 40 GB copy, and says so in the plan.

Press Z and the pane becomes the host's dataset tree. Ten keys cover the lifecycle—c create, n snapshot, b roll back, x destroy, mountpoints, mount/unmount — and every one composes a plan you read first. Destroy asks you to type the word. The pool root is off limits, period. And when you move a whole dataset between ZFS machines, the plan upgrades itself to zfs send | ssh | zfs receive—block-level, dramatically faster than file-by-file.

Two pointers: the full ZFS page for the details, and the mount grant—the one narrow sudoers line that unlocks mount/unmount, and why everything else needs no root at all.

Refusals & fixes#

When an operation cannot run, pālana states the reason and, where possible, the fix.

no usable ssh keythe host wants a key you don't have installed—pālana shows the two commands (ssh-keygen, ssh-copy-id) and waits
unreachableif ssh <host> fails in your terminal, it fails here identically—same ssh, same reason
mounting needs rootmount/unmount are the one thing needing sudo—the refusal includes the exact line to grant: the mount grant
won't work—kind mismatcha file here, a folder there—named before the transfer, not after it half-runs
probe came back unreadablean exotic userland answered strangely; stripped-down BusyBox boxes are supported, some vendor firmware refuses

A host missing from a menu? reload hosts in the menu re-reads your config. A stale-looking map? r re-probes. More in the FAQ page.

Under the hood#

Implementation details for people who want to inspect the commands before they run.

It's your ssh, verbatim. No embedded SSH library. pālana spawns the system ssh binary, so your config, keys, agent, ProxyJump, everything, behave exactly as in your terminal—and holds one ControlMaster session per host, so after the first connection, commands run with near-zero overhead. Remote browsing uses the same SSH configuration, keys, and agent as your terminal.

The plan engine is a pure function. Facts in, plan out, no I/O—which makes it the most tested object in the codebase (the headless core sits above 97% line coverage). The GUI renders state and forwards intent; it is architecturally incapable of composing a shell command. What runs is what the engine planned, byte for byte.

Transfers use standard tools. rsync -a -s --partial --info=progress2 host-to-host with agent forwarding when the probe proved it; a tar stream when one end lacks rsync; zfs send -R … | zfs receive -u for whole datasets (the -u is deliberate—mounting is root's on Linux, and a receive that auto-mounts returns an exit code that lies). Deletes gate on verification: find | wc -l on both ends, or dataset existence for receives, before anything destructive runs.

State is five plain files in ~/Library/Application Support/palana/—topology cache, session, settings, favorites, and an append-only operations log. No database. Delete the cache whenever; the hosts are the system of record.

No daemon. There is no component that can outlive the window. Swift 6, strict concurrency, SwiftPM; GPL-3.0; and the entire design record—every architectural decision with its reasoning—is public in the repo's ho-process/. Full tour: how it works.

FAQ#

Is it free?

The beta is free—a signed, notarized download, no App Store, no account, no telemetry. At 1.0 the signed build becomes a one-time $29 purchase; the source stays GPL-3.0 and free to compile, forever. File a real issue during the beta and your 1.0 license is on me. The license, plainly →

Mac only?

Yes—pālana is a native Mac app, deliberately. The servers can be anything you can ssh into: Linux, BSD, even BusyBox firmware boxes.

Do I need ZFS?

No. pālana is a full SSH file manager on any host. The ZFS surfaces light up only where a host has ZFS—without it, you simply never see them.

Does it install anything on my servers?

No. It runs the ssh, rsync, and (if present) zfs your servers already have. Nothing to deploy, nothing to update, nothing listening.

Is it watching my machines?

No. It runs when you open it and stops when you close it—no daemon, no polling. The map shows cached facts with the date of their last probe.

Do transfers go through my Mac?

Between two servers, no—the fast path runs server-to-server and your Mac only orchestrates. When the route does pass through your Mac (a fallback, or you're one end), the plan's how: line says so. You always know.

SMB? SFTP-only hosts? Docker?

No, no, and no—on purpose. SSH is the only transport, and pālana manages files and datasets, not containers. It is for hosts you administer, not arbitrary remote connections.

Where's my data about pālana itself?

~/Library/Application Support/palana/ — plain JSON and a plain-text log, human-readable, safe to delete (except your favorites, which you'd presumably miss).

What's coming next?

An operations queue (today, one plan runs at a time), then more Workbench tools. The build is public—watch the repo.