Docs
Install
Pick one. All three put an mdfly binary on your path.
Shell installer
curl -fsSL https://mdfly.dev/install.sh | sh
The installer verifies the download against the release checksums.
Homebrew
brew install Abir66/mdfly/mdfly
Go
go install github.com/Abir66/mdfly/cmd/mdfly@latest
A binary built with go install reports its version as dev.
Platforms
Release binaries are built for macOS (amd64, arm64), Linux (amd64, arm64) and Windows (amd64). Check the install with mdfly --version.
Quick start
No account and no signup. Publish a file and the URL is the only thing printed to stdout.
mdfly publish notes.md
# https://mdfly.dev/abc12345
Follow linked pages and folders
-r walks linked markdown files and folders into one document.
mdfly publish docs/index.md -r
Publish text without a file
Pipe text in, or pass it with -m.
echo "# Quick note" | mdfly publish
mdfly publish -m "# Quick note"
Open or copy the result
mdfly publish notes.md --open
mdfly publish notes.md | pbcopy
Progress lines such as uploaded 3/3 go to stderr, so piping stdout never picks them up.
Update and delete
mdfly update notes.md
mdfly delete abc12345
Commands
Run mdfly <command> --help for the full flag list. delete, open and remove take a slug or the path of a file you published from this machine. update takes the file; use --slug to target by slug.
Edit tokens
Publishing mints an edit token. mdFly stores it locally under ~/.mdfly/ and sends it when you update or delete that document. Set MDFLY_CONFIG_DIR to keep that state somewhere else. The token is never shown on stdout.
publish [file]
Upload a file, or inline text, and print its URL.
| Flag | Effect |
|---|---|
-r, --recursive |
Follow linked .md files and linked folders transitively. |
-m, --message <text> |
Publish inline text instead of a file. |
--open |
Open the URL in your browser after publishing. |
With no file and no -m, publish reads stdin.
update [file]
Push changes to an existing document. The URL stays the same, and the 30-day lifetime restarts.
| Flag | Effect |
|---|---|
--slug <slug> |
Target a document by slug, for text updates, recovery or when a file maps to several documents. |
-m, --message <text> |
Update with inline text instead of a file. |
-r, --recursive |
Follow linked .md files and linked folders. |
--force |
Overwrite without the concurrency check against the last version you pushed. |
--open |
Open the URL after updating. |
Without --force, an update fails with a conflict if the document changed since you last pushed it.
delete [slug-or-file]
Take a document down on the server. Its URL then answers 410. It asks for confirmation; pass -y to skip the prompt, which is required when stdin is not a terminal.
| Flag | Effect |
|---|---|
--slug <slug> |
Target a document by slug when a file maps to several. |
list
Print the documents you published from this machine, newest first. It reads local state and makes no network call. Columns are slug, tier, updated time, path and URL. With --json it prints an array.
open [slug-or-file]
Open a published document in your browser.
| Flag | Effect |
|---|---|
--slug <slug> |
Target a document by slug when a file maps to several. |
remove [slug-or-file]
Forget a document locally. This touches local state only: the document stays online, and you lose the edit token, so you can no longer update or delete it.
| Flag | Effect |
|---|---|
--slug <slug> |
Target a document by slug when a file maps to several. |
--all |
Remove every tracked document from local state. Cannot be combined with a target or --slug. |
Global flags
Every command accepts these flags.
| Flag | Effect |
|---|---|
--json |
Print machine-readable JSON instead of text. |
-q, --quiet |
Suppress non-error output. |
-y, --yes |
Skip the confirmation prompt of delete and remove --all. |
--api <url> |
Override the API base URL. |
Output streams
stdout carries only the result: the URL, or the --json object. Everything else, including progress and errors, goes to stderr.
API base URL
The API base resolves in this order: --api, the MDFLY_API environment variable, config.toml in the state directory, then the built-in default.
Raw links for agents
Every document has two views from the same content: a rendered page at https://mdfly.dev/<slug>, and the source bytes at https://mdfly.dev/raw/<slug>.
curl https://mdfly.dev/raw/abc12345
Files inside a bundle
Files in a bundle are addressed by path.
curl https://mdfly.dev/raw/abc12345/images/diagram.png
Responses are byte-exact with an appropriate content type: markdown stays markdown, code stays code, and other files come back as themselves.
JSON output for scripts
mdfly publish --json prints one object with these fields.
| Field | Meaning |
|---|---|
url |
The rendered page URL. |
slug |
The document slug. |
manifest_hash |
Hash of the published file manifest. |
tier |
The limit tier the document was published under. |
mdfly publish notes.md --json
Limits
Each published document is capped at:
| Limit | Value |
|---|---|
| Total bundle size | 25 MB |
| File count | 50 files |
| Single file size | 10 MB |
| Lifetime | 30 days |
The CLI checks size and file count before uploading and stops early with exit code 2. The server checks again.
Expiry and removal
Documents expire 30 days after they are published or last updated. An expired or deleted document answers 410 Gone at both its page and raw URLs.
Rate limits
Publishing, updating and deleting are limited to 10 requests per minute and 30 per hour. Reading documents is not limited. Hitting a limit exits with code 5.
Troubleshooting
Exit codes
Every failure maps to one exit code, so scripts can branch on it.
| Code | Meaning |
|---|---|
| 0 | Success. |
| 1 | Unrecognized failure. |
| 2 | Bad input: invalid flag or argument, no content, a missing file, a bundle over the limits, or a request the server rejects as malformed. |
| 3 | Missing or invalid edit token. |
| 4 | Conflict: the document changed since your last push. |
| 5 | Over quota: bundle too large for the server, or rate limited. |
| 6 | Server error, network failure, or an upload that kept failing after retries. |
Rate limited
Exit code 5 with a rate-limit message means you passed 10 writes per minute or 30 per hour. Wait for the minute or hour window to reset (the server’s Retry-After says how long) and retry.
Update conflict
Exit code 4 means the document changed since you last pushed it. If you intend to replace it, run mdfly update <file> --force.
Lost edit token
The token lives in ~/.mdfly/. If it is gone, you cannot update or delete that document. Publish again for a new URL; the old one expires after 30 days.
Delete refuses without confirmation
When stdin is not a terminal, mdfly delete exits with code 2 unless you pass -y.
410 Gone
The document was deleted or has expired. Publish it again to get a new URL.