I often need to publish some notes somewhere, just to keep it or to hand it to someone, and I always found it painful to interrupt my work, go create a Google doc and copy-paste the content. I'm lazy as a good dev should, so here I am with the solution.
In you terminal, you type:
share SECURITY_AUDIT_JAN_15.md
or in Claude Code:
/share that doc
And it returns this shareable link:
I don't even know if this is feasible with Google Docs and I don't really care because, in case you haven't noticed yet, Fileverse is simply the best alternative in town.
dDocs are end-to-end encrypted documents: content is encrypted client-side before it ever leaves your machine, references are anchored onchain, and sharing works through a link that carries the decryption key in the URL fragment (the part after #, which browsers never send to servers). No account required for readers. No ads, no tracking, no platform lock-in.
The Fileverse API makes this scriptable: it's a small self-hosted server you run locally. By the end of this tutorial you'll be able to do this from any project on your machine:
share SECURITY_AUDIT_JAN_15.md
...and get back:
Published: SECURITY_AUDIT_JAN_15.md
ddocId: 5dKEgEgsSbFVrCsmSv4yf4
link: [https://docs.fileverse.io/0x21b9d1591b1440BA8D3f2470E18f7d9f29e4E345/10#key=-GcNYlM5tVR9Kh2LNfFMZBFgGkgMLR6gHXIFKrtIZ0kCvAX5spcEpV-clnfqjVzE](https://docs.fileverse.io/0x21b9d1591b1440BA8D3f2470E18f7d9f29e4E345/10#key=-GcNYlM5tVR9Kh2LNfFMZBFgGkgMLR6gHXIFKrtIZ0kCvAX5spcEpV-clnfqjVzE)
That link is instantly shareable with anyone. Bonus: it also works as a /share slash command in Claude Code.
Note: you do NOT deploy this API anywhere. It runs on
127.0.0.1. That's the point — encryption happens on your device.
Prerequisites
-
Node.js v18+ (
node -vto check) -
macOS or Linux with
bash,curl, andpython3(all preinstalled on macOS) - git
- Optionally: Claude Code for the slash-command part
Step 1 — Fileverse signup
- Go to ddocs.new
- Create your account / portal (a portal is your onchain document space)
Step 2 — Get your API key
- In ddocs.new, open Settings
- Enable Developer Mode
- Generate your API key and copy it
Treat this key like a password. It never lives in a script or in git — only in a local config file.
Step 3 — Install and run the local API server
npm install -g @fileverse/api
fileverse-api --apiKey="YOUR_API_KEY"
The first run fetches your key data, writes config to ~/.fileverse/.env, runs database migrations, and starts the API server (port 8001) plus a background worker that publishes your docs onchain.
You should see:
✓ Fileverse API is running!
API Server: http://127.0.0.1:8001
Worker: Active
Troubleshooting: ERR_MODULE_NOT_FOUND: Cannot find package 'y-protocols'
At the time of writing, the npm package can hit a missing-dependency error on some setups (like mine!). Fix:
npm install -g y-protocols yjs
npm uninstall -g @fileverse/api
npm install -g @fileverse/api
Then run fileverse-api --apiKey="..." again.
Step 4 — Install share
Clone the dotfiles repo and run its installer:
git clone https://github.com/julienbrg/dotfiles.git ~/dotfiles
cd ~/dotfiles
./install.sh
install.sh symlinks two files into place: the share command (into ~/.local/bin/share) and the Claude Code /share command (into ~/.claude/commands/share.md). It's safe to re-run — anything already at those paths gets backed up as .bak first.
Make sure ~/.local/bin is on your PATH (zsh shown; use ~/.bashrc for bash):
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
What share does behind the scenes
share <file> is a single command, but it handles the whole publish flow for you:
-
Reads your API key from
~/.fileverse/.env— nothing is ever hardcoded or passed on the command line. -
Checks whether the local server is already running. If not, it starts
fileverse-apiitself and waits (up to 45s) for it to become healthy. If it was already running,shareleaves it alone — it only ever stops a server it started itself. - Uploads the file to the local API, which encrypts it client-side and kicks off the onchain sync.
- Polls until the sync completes, retrying once automatically if a sync event fails.
- Prints the shareable link, then shuts back down any server it started in step 2.
It also remembers every file it publishes (in ~/.fileverse/shared.tsv), so re-sharing the same file updates the existing doc instead of creating a new one (more on this in Step 6).
A couple of details worth knowing if something goes sideways:
- Parsing is done in Python rather than
jq, because the API echoes your document content back in its response, and markdown can contain raw control characters that breakjq. Python's JSON parser handles it fine. - If a run gets interrupted mid-sync, nothing is lost — sync state lives in a local SQLite database, so the next
sharerun just picks up where it left off.
Step 5 — Verify setup
# 1. Server config exists?
cat ~/.fileverse/.env # should show API_KEY=... and DB_PATH=...
# 2. Command is found and executable?
which share # → /Users/you/.local/bin/share
# 3. Publish something!
cd ~/any-project
share SECURITY_AUDIT_JAN_15.md
Expected output:
Created ddoc o84yyFHUropP47AYiAqpXe, waiting for onchain sync...
Published: SECURITY_AUDIT_JAN_15.md
ddocId: o84yyFHUropP47AYiAqpXe
link: [https://docs.fileverse.io/0x21b9d1591b1440BA8D3f2470E18f7d9f29e4E345/10#key=-GcNYlM5tVR9Kh2LNfFMZBFgGkgMLR6gHXIFKrtIZ0kCvAX5spcEpV-clnfqjVzE](https://docs.fileverse.io/0x21b9d1591b1440BA8D3f2470E18f7d9f29e4E345/10#key=-GcNYlM5tVR9Kh2LNfFMZBFgGkgMLR6gHXIFKrtIZ0kCvAX5spcEpV-clnfqjVzE)
Open the link in a browser — your document, decrypted client-side.
Sharing model: the link is view-only, for everyone including you — it carries the decryption key, not edit rights. Anyone with the link can read the doc, so treat the link itself as the secret, and remember there's no easy "unshare" once it's out.
One thing to know: docs published through the API don't join your regular file list at ddocs.new — once you've opened a link they show up under "Recently accessed", but view-only, same as for anyone else with the link. Their edit keys live only in the local API database (~/.fileverse/fileverse-api.db), so the browser app can't edit them. To change a published doc, update it from your machine — see the next step.
Step 6 — Updating a published doc
share keeps a small ledger of everything it has published (~/.fileverse/shared.tsv). Re-run it on a file you've already shared, and instead of creating a new doc it updates the existing one in place — the link stays the same:
share SECURITY_AUDIT_JAN_15.md
Already published as ddoc o84yyFHUropP47AYiAqpXe — updating it, link stays the same.
Updated ddoc o84yyFHUropP47AYiAqpXe, waiting for on-chain sync...
Updated: SECURITY_AUDIT_JAN_15.md
ddocId: o84yyFHUropP47AYiAqpXe
link: https://docs.fileverse.io/0x21b9...#key=zMUB4xQb...
Files are tracked by absolute path, so a README.md in one project and a README.md in another are (correctly) two different docs.
For a doc published before the ledger existed, pass its ddocId explicitly once — that updates the doc and records the mapping, so from then on the plain share <file> does the right thing:
share SECURITY_AUDIT_JAN_15.md o84yyFHUropP47AYiAqpXe
Lost a ddocId? The API package also installs a ddctl CLI — ddctl list shows everything you've published, and ddctl update <ddocId> even opens the doc in your $EDITOR.
Step 7 — Claude Code /share command
install.sh already symlinked this in Step 4, so /share works out of the box in every project. It's a markdown file (~/.claude/commands/share.md) that delegates entirely to the share script — Claude runs one Bash call, and only the ~4-line result (not your whole document) enters the conversation. Faster, cheaper, and deterministic.
/share SECURITY_AUDIT_JAN_15.md
If Claude Code prompts for permission the first time, pick "Yes, and don't ask again" — that's expected the first time you use any new command, and it won't ask again after that.
Make it your own
This tutorial points at my own dotfiles repo so you can try share immediately. To keep your own copy under your control long-term: fork julienbrg/dotfiles (or just copy bin/share and claude/commands/share.md into your own dotfiles repo), point install.sh at your fork, and push. Same install.sh pattern works on any new machine:
git clone git@github.com:YOUR_USERNAME/dotfiles.git ~/dotfiles
cd ~/dotfiles && ./install.sh
npm install -g @fileverse/api
fileverse-api --apiKey="YOUR_KEY" # regenerate a key per machine
⚠️ The one rule that matters: never commit secrets. share reads the API key from ~/.fileverse/.env at runtime — that file stays outside the repo, and install.sh never touches it. If you ever paste a key into a chat, an issue, or a commit, regenerate it in ddocs.new Settings → Developer Mode. Keys are cheap; leaked keys are not.
Recap
| Piece | Location | Purpose |
|---|---|---|
| API key + config | ~/.fileverse/.env |
Secrets, never in git |
share script |
dotfiles/bin/share → symlinked to ~/.local/bin/share
|
Publish from any terminal |
| Claude command |
dotfiles/claude/commands/share.md → symlinked to ~/.claude/commands/share.md
|
/share <file> [ddocId] in Claude Code |
| dDocs UI | ddocs.new | Account + API keys (API-published docs appear view-only, under "Recently accessed") |
Happy sharing! 🚀
Built with the Fileverse API (AGPL-3.0). Not affiliated with Fileverse — just a fan of encrypted, self-hosted publishing.
Top comments (0)