A modern desktop client for SFTP, FTP, SSH, S3-compatible, WebDAV, and cloud storage.
Save a server once, then browse its files in a dual-pane view and open a terminal against the same session — plus an Agent Bridge that lets Claude Code (or any MCP agent) run commands on a box through your authenticated session, with per-command approval and zero credentials shared.
English | Español | 中文版 | Português
Download · Screenshots · Features · Agent Bridge · Architecture · Roadmap · Docs · Contributing · Discord
⏱️ Download, connect, transfer — in under a minute
Grab the latest installer from the Releases page — every push to main publishes fresh builds for all three desktop platforms plus the standalone faro-cli.
| Platform | Installer | First-launch note |
|---|---|---|
| macOS (Intel + Apple Silicon) | .dmg (universal) |
One-time xattr step ↓ |
| Windows (x64) | .exe (NSIS) or .msi |
SmartScreen → More info → Run anyway |
| Linux (x64) | .AppImage, .deb, .rpm |
chmod +x the AppImage |
Builds are unsigned (no Apple Developer / Windows EV certificate yet), so each OS guards the first launch:
- macOS — after dragging Faro.app to /Applications, run this once in Terminal, then open the app normally:
It's needed because the build isn't notarized by Apple; without it macOS reports the app as "damaged."
xattr -cr /Applications/Faro.app
- Windows — on the "Windows protected your PC" prompt, click More info → Run anyway.
Prefer to build from source? See Develop below.
Captured from a mock-data build — every hostname, IP, username, and path below is fictional. See
docs/screenshots/CAPTURE.mdfor the shot list and how to reproduce them.
| Dual-pane browser | Disk Usage Explorer |
|---|---|
![]() |
![]() |
| Local and remote side by side, drag-and-drop transfers between them | WinDirStat-style treemap over any backend, with a server-side fast path |
| Server rail | Integrated terminal |
|---|---|
![]() |
![]() |
| Discord-style connection bubbles, with an expandable labeled mode | A real SSH shell tab against the same session you're browsing |
| Agent Bridge | Object storage |
|---|---|
![]() |
![]() |
| Approve (or auto-approve) each command an AI agent runs on a live session | Browse S3 buckets like a filesystem alongside your SFTP servers |
| Transfers | Directory sync |
|---|---|
![]() |
![]() |
| Queued downloads/uploads with progress and overwrite prompts | Preview a one-way sync plan before anything moves |
View all screenshots
| File actions | Agent Bridge approval |
|---|---|
![]() |
![]() |
| Duplicate, properties, "download folder as .tar.gz/.zip", "open terminal here" | Every agent command prompts with the exact command before it runs |
| New connection | Settings |
|---|---|
![]() |
![]() |
| One profile editor for all thirteen backends, protocol picker in a rail | Themes, terminal behavior, transfers, and the default editor |
One connection list, thirteen backends. Browse, transfer, sync, and the disk-usage / diff / search tools work the same on every one — all behind a single
RemoteFstrait.
| SFTP / FTP / FTPS The classics, done right — one SSH session shared between the file browser and the terminal pane. |
S3-compatible Presets for AWS, Cloudflare R2, Backblaze B2, Wasabi, DigitalOcean Spaces, MinIO, Storj, Hetzner, Scaleway, Oracle OCI, IBM COS, Supabase, and generic self-hosted (Ceph RGW, Garage, SeaweedFS). |
| Azure Blob & Google Cloud Storage First-class object storage alongside your servers. |
WebDAV & HTTP(S) Nextcloud / ownCloud browsing, plus read-only HTTP autoindex and direct-URL sources. |
| Cloud drives Dropbox, OneDrive, Google Drive, and Box — loopback + PKCE OAuth, only the refresh token in your OS keychain. |
Faro Agent Faro's own paired agent as a backend — browse, transfer, and exec on a machine with no SSH server. |
| Drag-and-drop transfers Between panes, recursive directories, multi-select, overwrite/skip/rename policies, multipart upload for objects > 16 MB. |
Directory sync Preview a one-way plan (Additive or Mirror), then run it — on any two backends. |
| Continuous folder sync Attach a local folder to a remote path and it stays mirrored — watcher + poll reconciler, exclude patterns, mirror-delete cap. |
Edit in place Open a remote file in your local editor; auto-upload on every save, with a live status-bar pill. |
| Disk Usage Explorer WinDirStat/WizTree-style treemap + size-ranked tree over any backend, with a shell du/find fast path. |
Directory Diff Meld/Beyond-Compare for any two backends — including remote ↔ remote (staging vs prod, two buckets). Compare by size or --hash. |
| Fleet Search Find by name or content — rg/grep server-side on SSH and Agent servers, flat key listing on buckets. |
CLI parity All three are in faro-cli (diff, search) and exposed as MCP tools (faro_diff, faro_search). |
| Agent Bridge Lend your authenticated session to Claude Code or any MCP agent — localhost only, bearer token, per-command approval. Details ↓ |
Fleet Skills AI-authorable, multi-step shell workflows that fan out across servers — AI-authored skills land as proposals needing one human approval. |
| MCP-native Auto-discovered tools in Claude Code; a ready-to-paste SKILL.md for plain HTTP agents. |
Live audit log Every command, approval, and denial, right in the Bridge panel. |
| Faro Agent Control a Windows/macOS/Linux box with no SSH server — 6-digit pairing code, Noise-encrypted, key-pinned. Details ↓ |
Multi-tab terminals Real SSH shell tabs sharing one session per profile; tabs survive switches without re-establishing the channel. |
| Known-hosts verification Interactive fingerprint prompt; mismatched keys get a danger-toned UI so MITM attempts are obvious. |
ssh-agent everywhere$SSH_AUTH_SOCK on unix, OpenSSH-for-Windows pipe, and Pageant on Windows. |
| Profile importers Bring connections in from ~/.ssh/config, FileZilla's sitemanager.xml, and PuTTY sessions. |
Keyboard-first Command palette (Ctrl/⌘-K), sortable columns, breadcrumbs, in-pane filter, toasts, custom title bar with menus. |
faro-cliScripts every backend the GUI speaks, using the same saved profiles. Details ↓ |
Capability-aware UI chmod/mkdir hide on backends that don't support them; protocol chips show what you're connected to. |
Let a local AI agent run commands on your servers — safely.
This is the part that makes Faro more than a file client. Connect to a server once, and Faro can lend that already-authenticated SSH session to a local AI agent — Claude Code, Cursor, anything that speaks MCP — so the agent operates on the box without installing anything remote and without ever seeing your credentials. Faro stays the gatekeeper.
Why it's different: most "AI over SSH" setups make you hand the agent your keys or stand up a server-side daemon. Faro does neither. The agent borrows the session you already opened, you approve every command, and nothing reaches the server except the commands you OK.
Wire it into Claude Code — native MCP, auto-discovered tools:
- Connect to a server, open the Bridge panel (status-bar pill), hit Start, and flip on Allow agent access.
- Copy the one-liner the panel generates and run it in your project:
claude mcp add --transport http faro http://127.0.0.1:<port>/mcp \ --header "Authorization: Bearer <token>"
- Claude Code now has two tools —
faro_list_sessionsandfaro_exec. Ask it "check disk usage on the server" and it runs through Faro. (Prefer curl or another agent? The panel also exports a ready-to-pasteSKILL.mdfor the plain HTTP API.)
The guardrails — all on by default:
- 🔒 Localhost only — bound to
127.0.0.1on a random port. - 🔑 Bearer token — per-launch, required on every request.
- ☑️ Per-session opt-in — no connection is reachable until you turn it on.
- 🙋 Approve every command — each
execpops a prompt in Faro and blocks until you click Approve (or it times out). - 📋 Live audit log — every command, approval, and denial, right in the panel.
Surface: GET /health, GET /sessions, POST /exec, and POST /mcp (MCP Streamable HTTP). It's a hand-rolled localhost server on the existing tokio runtime — zero new dependencies.
Reach a whole computer — Windows, macOS, or Linux — the way you already drive a
remote server, but without setting up an SSH server on it. Pair it once with
a 6-digit code (RustDesk-style) and it appears in Faro as a connection you can
browse, transfer files through, and run native commands on. And because the
Agent Bridge brokers Faro's sessions to a local AI, this lets
Claude Code run PowerShell on your Windows box or sh on your Mac, from
anywhere — through one encrypted, pinned, policy-gated link.
If both machines already have Faro, there's nothing to download. On the one you want to control, open Settings → Remote control, toggle it on, and click Show pairing code — then enter that code on your other Faro. Done.
For a headless server, one line installs the agent, registers it as a service, and opens a pairing window:
curl -fsSL https://github.com/jhd3197/Faro/releases/latest/download/install-agentd.sh | shOr drive the faro-agentd binary yourself — one port now both serves paired
controllers and accepts new pairings, so nothing needs restarting:
faro-agentd pair # serve + open a pairing window; prints a 6-digit code
# then in Faro: New Connection → Faro Agent → pick this machine → enter the code.
# Done — it's pinned; no code next time.
faro-agentd run # serve paired controllers (no pairing window)
faro-agentd install # run as a service so it survives reboots
faro-agentd install --read-only # …serving browse + read + report only
faro-agentd info # this machine's identity + who's pairedHow it's secured — the link is a Noise
handshake (X25519 + ChaCha20-Poly1305), end-to-end encrypted independent of any
relay. Pairing mixes the code in as a PSK so an active man-in-the-middle can't
complete it; afterward both sides pin each other's static key and an
unrecognised peer is refused. The controlled machine keeps its own policy
(exec/write/read-only) and audit log, so a paired controller can never do more
than its owner allowed. LAN discovery is mDNS; internet-wide reach (rendezvous +
relay) is a later phase. See docs/remote-agent.md.
Every backend is one RemoteFs implementation, so the dual-pane browser, the
transfer queue, sync, disk-usage explorer, diff, and search all pick it up for
free. Capability differences (no shell on a bucket, read-only on HTTP) hide the
affordances they don't support rather than reinventing them.
| Backend | Browse | Transfer | Sync | Shell |
|---|---|---|---|---|
| SFTP (SSH) | ✓ | ✓ | ✓ | ✓ |
| FTP | ✓ | ✓ | ✓ | — |
| FTPS (explicit) | ✓ | ✓ | ✓ | — |
| S3-compatible (AWS, R2, B2, Wasabi, …) | ✓ | ✓ | ✓ | — |
| Azure Blob | ✓ | ✓ | ✓ | — |
| Google Cloud Storage | ✓ | ✓ | ✓ | — |
| WebDAV (Nextcloud, ownCloud, …) | ✓ | ✓ | ✓ | — |
| HTTP(S) (autoindex / direct URL) | ✓ | download | ← only | — |
| Dropbox | ✓ | ✓ | ✓ | — |
| OneDrive | ✓ | ✓ | ✓ | — |
| Google Drive | ✓ | ✓ | ✓ | — |
| Box | ✓ | ✓ | ✓ | — |
| Faro Agent | ✓ | ✓ | ✓ | exec |
Cloud drives authorize once through your browser (loopback + PKCE OAuth); Faro stores only the refresh token in your OS keychain and never sees your password. HTTP(S) is a read-only source — point it at an nginx/Apache autoindex to browse, or a direct URL to pull one artifact; uploads, renames, and deletes are refused.
┌──────────────────────────────────────────────────────────────┐
│ React + TypeScript + Tauri webview │
│ Dual-pane browser · xterm.js terminal · sync / diff / │
│ disk-usage / search / skills panels · Agent Bridge │
└──────────────────────────┬───────────────────────────────────┘
│ Tauri commands + events
┌──────────────────────────┴───────────────────────────────────┐
│ Rust core (faro_lib) │
│ RemoteFs → Local·Sftp·Ftp·Object(S3/Azure/GCS)·WebDav· │
│ Http·Dropbox·OneDrive·GDrive·Box·Agent │
│ SessionManager pools one session per profile │
│ TransferManager → concurrent file + directory transfers │
│ scan.rs (bounded walk + fast paths) → diskscan · diff · │
│ search · sync::plan · faro.db (SQLite) │
│ foldersync.rs → continuous watched sync pairs │
│ bridge.rs → localhost MCP/HTTP + approvals + Skills │
│ oauth.rs · importers/ · known_hosts + HostKeyVerifier │
└───────────────┬───────────────────────────┬──────────────────┘
│ same Rust core │ Noise protocol
┌───────────────┴──────────────┐ ┌──────────┴──────────────────┐
│ faro-cli (clap) │ │ faro-agentd (controlled │
│ ls·cp·mv·rm·sync·diff· │ │ machine): handshake · pin · │
│ search·exec·agent·skill │ │ policy · native exec + fs │
└──────────────────────────────┘ └─────────────────────────────┘
The wedge: everything goes through one RemoteFs trait. Adding a new backend means writing one trait impl and one builder; the dual-pane browser, the sync planner, the disk-usage / diff / search tools, the CLI, and the transfer engine all pick it up automatically.
npm install
npm run tauri devFirst build is slow — it's compiling the Rust crate tree. Subsequent builds are ~30 s.
Prerequisites: Node 20+, Rust 1.88+ (rustc --version — Tauri 2's transitive deps require it).
A standalone binary, faro-cli — its own workspace crate under src-tauri/faro-cli/ — reuses your saved GUI profiles. Prebuilt binaries ship with every release, or build it yourself:
cd src-tauri
cargo build -p faro-cli --release
# → src-tauri/target/release/faro-cli
# File ops — any backend, using your saved profiles
faro-cli profiles list
faro-cli ls prod:/var/log
faro-cli cp ./report.pdf prod:/var/www/uploads
faro-cli sync ./site prod:/var/www/site --mirror --dry-run
faro-cli rm prod:/tmp/build --recursive
# Compare and search — remote↔remote works too
faro-cli diff prod:/etc staging:/etc --hash
faro-cli search prod:/var/log "OutOfMemory" --content --regex
faro-cli exec prod 'systemctl status api' # SSH profile shell
# Drive the app's Agent Bridge (goes through Faro's approval + console)
faro-cli agent exec prod 'journalctl -u api -n 100'
faro-cli agent exec prod --detach 'apt-get -y upgrade' # background job id
faro-cli agent write prod /etc/app/patch.conf --from-file ./patch.conf
faro-cli skill run deploy --target all --param branch=main --dry-run
# Fetch an auth-walled page with a saved HTTP(S) profile's creds
faro-cli fetch https://staging.example.com/admin
faro-cli self-update --check # the CLI ships separately and can lag the appThe CLI mirrors the GUI: ls · cp · mv · rm · mkdir · sync · diff · search · exec · profiles, plus agent (drive the running Agent Bridge — exec,
script, write, read, background job/jobs, search, download,
upload), skill, fetch, and self-update. Path syntax: bare paths are
local (including Windows C:\…), name:/path references a saved profile — so
diff/sync can span two remotes. It prompts on stdin for unknown host keys
and never writes secrets to disk that the GUI hadn't already saved.
src/ React frontend
components/ DualPaneBrowser, FileBrowser, Terminal,
SyncDialog/SyncSettings, DiskUsage/DiskTreemap,
DirectoryDiff, FleetSearch, SkillsPanel, AgentBridge,
ProfileEditor, ImportDialog, HostKeyModal, …
stores/ Zustand stores (bridge, sync, connections, …)
lib/ipc.ts Typed wrappers around Tauri commands
lib/types.ts Shared types (mirror Rust serde structs)
mock/ VITE_MOCK demo data + invoke/listen fakes (screenshots)
src-tauri/src/
commands.rs Tauri command surface
bridge.rs Agent Bridge — localhost MCP/HTTP server, per-command
approval, audit log, Fleet Skills store + runner
remotefs/ RemoteFs trait + Local/Sftp/Ftp/Object/WebDav/Http/
Dropbox/OneDrive/GDrive/Box/Agent impls
session/ One session type per backend, SessionManager,
HostKeyVerifier trait
oauth.rs Loopback + PKCE OAuth (Dropbox/OneDrive/Drive/Box)
scan.rs Bounded-concurrency RemoteFs walk + strategy select
db.rs faro.db (bundled SQLite) — scan/sync state index
diskscan.rs / diff.rs / search.rs scan-engine consumers
foldersync.rs Continuous watched sync pairs (watcher + reconciler)
sync.rs Two-tree one-shot sync planner
transfer.rs Per-backend streaming transfers + progress
terminal.rs PTY over russh, emits events
agent.rs / agent_host.rs Faro Agent client + in-app "Remote control" host
cli_updater.rs faro-cli version-drift check + self-update
editor.rs · deeplink.rs · importers/ · known_hosts.rs · virtualfs/
src-tauri/faro-cli/ Standalone CLI crate — path-depends on faro_lib
src/main.rs clap + indicatif: ls·cp·mv·rm·mkdir·sync·diff·search·
exec·agent·skill·fetch·self-update
src-tauri/faro-agent-proto/ Faro Agent wire protocol (Noise channel, msg set,
identity/pairing) — Tauri-free, shared by both ends
src-tauri/faro-agentd/ Headless daemon run on a controlled machine:
src/{server,ops,config,discovery}.rs handshake·pin·policy·native exec+fs·mDNS
If you installed Rust via Chocolatey (choco install rust), there's a rustc.exe at C:\ProgramData\chocolatey\bin that shadows the rustup-managed toolchain. rustup update stable updates the rustup copy but doesn't touch the chocolatey one, so rustc --version keeps reporting the old version and Tauri builds fail with messages like rustc 1.85.0 is not supported by darling@0.23.0.
# Option A — uninstall the chocolatey copy (recommended)
choco uninstall rust
# Option B — keep both, but make rustup win for this shell
$env:Path = "$env:USERPROFILE\.cargo\bin;$env:Path"- v1.0 — one-way sync mode
- v1.1 —
faro-clibinary - v1.2 — edit-in-place external editor
- v1.3 — custom title bar with File/Edit/View/Help menus + integrated window controls; GitHub Actions release pipeline + CI
- v1.3 — UI density pass (named themes, command palette, sortable detail columns, breadcrumbs, in-pane filter, toasts); the 🤖 Agent Bridge (AI-agent command access over native MCP); and 🖥️ Faro Agent — control a paired Windows/macOS/Linux machine (browse, transfer, native exec) over an encrypted, pinned link, no SSH server required. Now with in-app Remote control (host the agent from the Faro app — no separate download), a single always-pairable daemon port,
faro-agentd installservice setup + one-line headless installer, andfaro://deep links for one-click "Connect with Faro" from a hosting panel - recent — more backends (S3 presets for a dozen vendors, Google Cloud Storage, WebDAV, read-only HTTP, and the Dropbox / OneDrive / Google Drive / Box OAuth clouds); Disk Usage Explorer, Directory Diff (incl. remote↔remote), and Fleet Search over any backend; Fleet Skills (AI-authorable fleet automations); continuous folder sync with exclude patterns + mirror-delete guard; and a sharper
faro-cli/ Agent-Bridge remote-exec DX — background jobs,agent write,agent script/--stdin, authenticatedfetch, and CLI version-drift self-update - next — SMB/CIFS backend (NAS / Windows shares); on-demand "virtual folder" placeholders (Windows-first, feature-flagged today); bidirectional sync + conflict resolution; brand/protocol logos on the rail and picker; Faro Agent internet reach (rendezvous + NAT hole-punch + relay fallback); transfer speed limits and queue editing (priority/retry/pause)
- release polish — code signing (Apple Developer / Windows EV cert), Tauri auto-updater, landing page
| Document | Description |
|---|---|
| Remote Agent | Faro Agent protocol, pairing, and security model |
| Deep Links | faro:// one-click "Connect with Faro" links |
| Screenshot Capture | The shot list and how to reproduce README screenshots |
| Updater Key Custody | Signing-key handling for the Tauri updater |
| Layer | Technology |
|---|---|
| App shell | Tauri 2 (Rust) |
| Frontend | React 18, TypeScript, Vite, Zustand, xterm.js, Tailwind CSS |
| Backend core | Rust — one RemoteFs trait over 13 backends |
| SSH | russh (SFTP + PTY), ssh-agent / Pageant integration |
| Object storage | S3, Azure Blob, Google Cloud Storage SDKs |
| Cloud drives | Loopback + PKCE OAuth (Dropbox, OneDrive, Google Drive, Box) |
| Agent link | Noise protocol (X25519 + ChaCha20-Poly1305), mDNS discovery |
| AI surface | MCP Streamable HTTP + localhost REST bridge |
| State | Bundled SQLite (faro.db) |
| CLI | faro-cli (clap) · faro-agentd headless daemon |
Contributions are welcome!
fork → feature branch → commit → push → pull request
Priority areas: new backends (one RemoteFs impl and it works everywhere), UI/UX polish, documentation, test coverage.
# Replace src-tauri/icons/source.png with a 1024×1024 PNG, then:
npm run tauri icon src-tauri/icons/source.pngscripts/process-icon.py handles cropping a black-bordered source PNG to its rounded-square art and writing source.png at the right size.
Faro is free and open source. If it saves you time, you can help keep it going:
- ⭐ Star the repo — it costs nothing and helps a lot
- 💖 GitHub Sponsors
- ☕ Buy Me a Coffee
TRC-20 has the lowest fees — usually under a dollar — so it's the friendliest option for a small donation. ERC-20 gas can cost more than the donation itself.
QR codes are generated locally by scripts/generate-funding-qr.mjs, which checksum-validates every address before encoding.
ServerKit — A lightweight, modern server control panel for managing web apps, databases, Docker containers, and security — without the complexity of Kubernetes or the cost of managed platforms.
Faro is the desktop companion for hands-on file transfer, shells, and ad-hoc work across all your boxes; ServerKit manages your servers from the browser.
LocalKit — Spin up local WordPress sites in one click. Each site runs as its own isolated Docker Compose project, and you can push code or push/pull databases straight to your ServerKit server through the serverkit-localkit extension.
DeviceKit — A unified Android device fleet & test-automation platform. Control a fleet of devices from one dashboard — run automations, stream screens in real time, catch visual regressions, and debug failures with AI-powered analysis.
Join the Discord to ask questions, share feedback, or get help with your setup.
MIT — see LICENSE.
Faro — Servers · storage · sessions, all in one workspace.
Made with ❤️ by Juan Denis















