Render a Markdown file locally with gander <file>, or push it to a shareable URL with gander watch <file> that updates in place on every save. Built so humans and agents can read and collaborate on markdown at the same time.
gander solves the problem of cat-ing a markdown file just to see what your agent wrote — open a browser tab once and the page updates in place on every save. Two workflows cover most of what you'll do:
-
gander watch README.md— upload togander.mdand get a short URL. Every save hot-swaps the rendered page in every connected viewer's browser, so you can read along while your agent iterates on a design doc without copy-pasting or refreshing. (This is shorthand forgander share README.md --watch.) -
gandermd/gander-skill— aSKILL.mdthat wires all of this into your agent runner (OpenCode, Claude Code, Codex CLI, Cursor, Grok Build, Windsurf, and any other agent that loadsSKILL.mdfiles), plus two helper scripts:scripts/save-plan.sh— pipe the agent's plan into./plans/YYYY-MM-DD-<slug>.md, then gander or share it.scripts/watch-markdown.sh— watch a directory for new.mdfiles and prompt to gander each one.
Install the skill with one command:
git clone https://github.com/gandermd/gander-skill && cd gander-skill && ./install.shThat symlinks the skill into ~/.agents/skills/, ~/.claude/skills/, and ~/.cursor/skills/ so every supported agent picks it up automatically.
brew tap gandermd/gander
brew install ganderThis installs gander on your $PATH for macOS and Linux (via Linuxbrew), registers gander(1) under $(brew --prefix)/share/man/man1, and ships bash + zsh completions under $(brew --prefix)/share. Upgrade alongside everything else with brew upgrade, and uninstall cleanly with brew uninstall gander. gander --upgrade keeps working for in-place binary upgrades.
Use this on systems without Homebrew or in CI environments that can't tap a formula:
curl -fsSL https://raw.githubusercontent.com/gandermd/gander-cli/main/install.sh | bashDownloads the latest release binary for your OS/arch from GitHub Releases, verifies its SHA256 checksum, and installs to ~/go/bin/gander (or /usr/local/bin/gander if ~/go/bin doesn't exist). If the download fails (no network, no release for your platform), the script falls back to building from source.
Flags:
--version v0.2.1— install a specific release instead of the latest.--source— skip the download and always build from source.--dry-run— print what would happen without doing it.
The installer requires curl and git (only for the source fallback). Set GITHUB_TOKEN to raise the GitHub API rate limit on shared networks.
If you prefer to look at the script before running it:
git clone https://github.com/gandermd/gander-cli.git
cd gander
./install.shIf you're on a different platform, want to hack on the code, or curl | bash makes you nervous:
git clone https://github.com/gandermd/gander-cli.git
cd gander
go mod tidy
CGO_ENABLED=0 go build -trimpath -ldflags "-X main.Version=v0.2.1" -o gander .
mv gander ~/go/bin/gander # or any directory in your PATH-ldflags "-X main.Version=..." stamps the version so gander --upgrade knows what it's running. Drop it and the build reports dev, which still works but gander --upgrade will go through a redundant update on first run.
gander --upgradeDownloads the latest release binary that matches your OS/arch, verifies its SHA256 checksum, and atomically replaces the running binary. Sets GITHUB_TOKEN in the environment to raise the API rate limit on shared networks.
If you built from source the old-fashioned way, re-run install.sh (or git pull && ./install.sh --source).
gander(1) is bundled in the repository at man/man1/gander.1 and attached to every release as gander-man.tar.gz. Homebrew installs it automatically into $(brew --prefix)/share/man/man1; on other systems, drop the tarball into any directory in $MANPATH:
tar -xzf gander-man.tar.gz -C /usr/local/share/man/man1 # or any directory in $MANPATH
man ganderGenerate a completion script with gander completion {bash|zsh} and source it from your shell rc:
# bash
source <(gander completion bash)
# zsh
eval "$(gander completion zsh)"Homebrew installs the bash + zsh scripts under $(brew --prefix)/share/... automatically. The bundled scripts cover every current subcommand (signup, share, remove, list, manage, completion, --upgrade, --version) and render flag. They're also attached to every release as gander-completions.tar.gz.
- macOS or Linux
- Go 1.22+ only if you build from source or hit the source fallback
- The macOS
opencommand is used to launch the browser (issue #5 tracks Linuxxdg-opensupport)
gander path/to/file.mdThis will:
- Convert the Markdown to HTML
- Write the rendered preview to a temporary file (in your OS temp directory)
- Open it in your default browser via a
file://URL - Exit — the process does not keep running, no port is held open
gander -outfile readme.html README.mdFlags must come before the markdown path, since Go's
flagpackage stops parsing at the first positional argument.
gander --watch README.mdEspecially handy when an agent is writing the file — open the preview once and watch it grow without leaving your browser. On every save the rendered HTML hot-swaps in place and the TOC rebuilds; scroll position is preserved. Press Ctrl+C to stop.
A local HTTP server is started on a random free port (printed in the output) so the browser can receive change notifications over Server-Sent Events.
--watchand-outfilecannot be combined.
If you're running an agent that streams markdown to a file, gander watch is the shortest path from the agent's writes to your browser — open the URL once and every connected viewer sees the latest version in real time. gander.md is the public hosting service for gander. Once you sign up, you can share, watch, list, and remove markdown from your terminal, and viewers see the same live-reload preview you'd see locally.
gander signup --email you@example.com # opens browser form, polls for API token
gander share README.md # opens https://gander.md/s/xK7m2pQa
gander watch README.md # upload + live-update the remote viewer on save
gander share README.md --watch # same as `watch`, spelled out
gander list # table of active shares
gander remove README.md # 404s the short link
gander remove --all # remove every share in your account
gander manage # opens the dashboard in your browser
gander auth <api_token> # install a rotated/issued API tokenThese commands appear in gander --help only after a successful signup,
since they require an API token stored in ~/.gander (api_token,
api_url, email, plus a shares map of local file paths to short IDs).
The CLI ships with https://gander.md as the default endpoint; set
api_url in your config to point at a self-hosted instance.
API tokens can be rotated from the dashboard (gander manage → rotate).
After rotating, install the new token on each machine with
gander auth <token>; the CLI validates it against /api/shares
before overwriting ~/.gander.
Optional JSON config file at ~/.gander lets you set defaults. Any field you omit falls back to its default.
{
"watch": true,
"debounce_ms": 150,
"port": 0,
"api_url": "https://gander.md",
"email": "you@example.com",
"api_token": "gmd_…",
"shares": {
"/abs/path/to/README.md": "xK7m2pQa"
}
}| Field | Default | Description |
|---|---|---|
watch |
false |
Default to live-reload mode when the flag is not explicitly set. |
debounce_ms |
150 |
Coalesce file-change events within this window before re-rendering. |
port |
0 |
HTTP port for the watch server (0 = OS-assigned free port). |
api_url |
https://gander.md |
gandermd endpoint; used by signup, share, remove, list, manage. |
email |
(empty) | Email address registered with gandermd. |
api_token |
(empty) | Bearer token. Set by gander signup. Treat as a password. |
shares |
{} |
Map of local file paths to short IDs, maintained by gander share. |
CLI flags always override the config. Pass --watch=false (or any explicit value) to override ~/.gander for a single run.
For pointing a single checkout at a different gandermd instance (local dev, staging, a self-hosted deployment) without disturbing your prod ~/.gander, set GANDER_CONFIG=<name>. The CLI then reads and writes ~/.gander.<name> instead — fully isolated from the default profile.
GANDER_CONFIG=dev gander signup --email dev@example.com # writes ~/.gander.dev
GANDER_CONFIG=staging gander list # writes ~/.gander.stagingThe legacy ~/.mdp fallback only applies when GANDER_CONFIG is unset; named profiles never fall back to .mdp. Profile names must be a single path component (no /, \, ., or ..).
-outfile string
Optional: write HTML output to a file instead of opening it in the browser
-watch
Watch the file for changes and live-reload the browser preview
-upgrade
Download and install the latest release, then exit
Subcommands:
gander signup --email <addr> Open the signup form in your browser, save the API token
gander share [--watch] <file> Upload to gander.md and open the share link
gander watch <file> Live-share to gander.md and push every save (alias for share --watch)
gander remove [--all] [<file>] Delete a share from gander.md
gander list List shares currently on gander.md
gander manage Open the dashboard in your browser
gander auth <api_token> Install a new API token (e.g. after rotating)
gander --version Print the version and exit
gander completion {bash|zsh} Print a shell completion script
The subcommands appear in help only after a successful gander signup (except completion, which is always available).
Cut a release with scripts/release.sh. From a clean main:
scripts/release.shThat auto-detects the next version from conventional commits since the last tag (feat: → minor, fix: → patch, BREAKING CHANGE / feat!: → major), asks for a y/N confirm, then runs end-to-end:
- Validates a clean working tree, that
ghis authenticated, and that the target tag doesn't already exist. - Creates an annotated
v<version>tag at HEAD and pushes it toorigin. gh run watch --workflow release --exit-statusblocks until the build workflow finishes.- Runs
scripts/bump-homebrew.shto open a Homebrew formula bump PR againstgandermd/homebrew-gander. - Prints the GitHub Release URL, per-asset download URLs, and the Homebrew PR URL.
Useful flags:
--bump {major|minor|patch}— force the bump component off the latest tag.<version>— set the version explicitly, skipping auto-detection.--no-homebrew— release only; skip the Homebrew PR step.--dry-run— print what would happen without tagging or pushing.
The release workflow (.github/workflows/release.yml) builds matrix binaries (gander-{darwin,linux}-{amd64,arm64}), generates a SHA256 sidecar for each, and attaches them to a GitHub Release with auto-generated notes. Existing users pick up the new version with gander --upgrade.
scripts/bump-homebrew.sh also runs standalone for re-bumps after a manual fix:
scripts/bump-homebrew.sh 0.12.0It clones gandermd/homebrew-gander, rewrites Formula/gander.rb (updating every per-asset sha256 and the four on_macos / on_linux URL pairs with SHA256s read from the GitHub release), and opens a PR. Requires gh (authenticated with repo scope) and ruby.
If scripts/release.sh isn't available (e.g. on a fresh checkout without the script), the equivalent manual sequence is:
git checkout main && git pull --ff-only
git tag -a v0.2.0 -m "Release v0.2.0"
git push origin v0.2.0You can then watch the run at https://github.com/gandermd/gander-cli/actions/workflows/release.yml.
MIT License — see LICENSE for details.
- Markdown parsing: uses goldmark (CommonMark compliant)
- HTML sanitization: uses bluemonday for security
- File watching: uses fsnotify when running with
--watch
Without --watch, the CLI is fire-and-forget: it renders once, opens the result in your browser, and exits. With --watch, it starts a tiny localhost HTTP server and pushes hot-swaps over Server-Sent Events on every save.