← Open source
Open sourceGoArjia Labs

dumont

One filesystem over everything. dumont puts local disk, S3-compatible object stores, Bunny, archives, and HTTP behind a single consistent interface, so the same handful of verbs work no matter where the bytes live — and data flows between unlike stores with one command.

dumont

The problem it solves

Every storage system speaks its own dialect — S3 multipart, Drive file IDs, Bunny zones, tar offsets, HTTP ranges. dumont puts one filesystem abstraction in front of all of them, so the same handful of verbs (cp, mv, ls, sync, cat, …) work everywhere and data flows between unlike stores with a single command. It's named after Tron's Dumont, guardian of the I/O Tower.

dumont cp aws://bucket/report.csv mydrive://reports/   # copy across unlike stores
dumont sync ./site cdn://www --delete                  # one-way incremental mirror
dumont cat zip:///releases/v2.zip/CHANGELOG.md         # peek inside an archive

One set of verbs, across every backend

cp, mv, and sync stream directly between any two backends — cross-remote by default, no staging through local disk. sync is an idempotent one-way mirror that copies only what changed, with --delete to prune and --dry-run to preview. The safety flags you'd want are there too: --no-clobber, same-file and dir-into-itself guards, and sandboxed local aliases.

Plenty works with no configuration at all — bare paths address the local filesystem, and - is stdin or stdout:

echo "hello" | dumont cp - /tmp/greeting.txt   # write a file from stdin
dumont cp -r ./project /tmp/backup/            # recursive copy into a dir
dumont caps mem                                # what can a backend do?

The backends

Eight backends sit behind one vfs.FileSystem interface today, with Google Drive and WebDAV on the roadmap:

  • local — bare paths, file://, or sandboxed local://alias/path folders
  • s3 — AWS S3, Cloudflare R2, MinIO, GCS-interop; multipart upload and ranged GET
  • bunnystorage / bunnystream — Bunny Edge Storage and the Bunny Stream video API
  • http(s) — read-only sources, with ranged reads where the server supports them
  • zip / tar — read-only views inside a local archive
  • mem — an ephemeral in-memory volume, the reference implementation for tests

Every remote is just a named entry in config whose name becomes the URI scheme, so aws://, r2://, or cdn:// are simply what you called them.

Honest by design

dumont's guiding rule is be honest. Each backend advertises exactly what it can do through a Caps declaration, and an operation it can't perform correctly fails loudly with a typed error — it is never silently emulated in a way that corrupts data. Where emulation makes sense (read-modify-write to add random writes over an object store) it's opt-in and clearly labelled as non-atomic.

That honesty is enforced by a conformance suite: one table-driven battery of behavioral invariants that every backend must pass. mem and local are the reference implementations, and the suite cross-checks each backend's advertised capabilities against its observed behavior — so no backend can lie about atomic rename, random write, or directories.

Safe credentials, composable behavior

Secrets are never written inline. Credentials in config.yaml are references resolved on first use — env:VAR, file:/path (must be 0600), or keychain:service/account — and dumont remote test <name> does a cheap liveness probe so a typo becomes an explicit preflight instead of a confusing first-operation error. Under the hood, behavior is composed rather than baked in: network remotes are automatically wrapped in a transparent metadata cache, and emulate: true layers read-modify-write on top only when you ask for it. It's a single pure-Go binary — no CGo, no daemon, no mounts, just a CLI.