Your markdown has to leave home. Keep track of it.
penknife is a terminal home for a folder of markdown: browse it, search it, hand any file to anyone as clean rich text - and when a copy lives on as a gist, know at a glance which side has drifted.
curl -fsSL https://heider.cc/penknife.sh | bash
brew install jhheider/tap/penknife
cargo install penknife
The tour
One folder, at your fingertips
Point it at an Obsidian vault, a notes directory, anywhere
you keep .md files. Browse the tree, preview
any file rendered, and full-text find across everything -
all before you've signed into anything. Once files have
gists, each shows its sync state, verified by content
hash, not timestamp.
The real thing, recorded against the released binary:
browse, preview, and find across a folder.
pShare, without an account
Renders the file to HTML and puts it on your clipboard as rich text. Paste into Google Docs, email, Slack, or Notion - headings, tables, bold, links intact. A deliberate snapshot; nothing to track, nothing to sign into.
zero setupuSync, when you want it
Publishes the file as a GitHub Gist and treats it like a git remote: penknife records what was pushed, notices when either side moves, and shows the drift per file. The folder stays primary.
opt-in, per fileScriptable
The same tools, headless
Every core verb works without the TUI, with disciplined exit codes and machine-readable output - stdout is the payload, stderr is for humans - so penknife slots into pipes, hooks, and CI.
$ penknife render -s notes.md > notes.html # markdown → full HTML doc $ penknife search "Rust" # grep your whole folder ./posts/rust-is-not-the-devil.md:1:# Rust is Not the Devil, Nor the Messiah ./posts/rust-is-not-the-devil.md:3:Rust is a tool - a powerful, occasionally $ url=$(penknife push posts/edikt-launch.md) # publish; stdout is the URL $ penknife status -q || echo "something drifted" # exit codes are the API
Also in the drawer
Small surface, sharp edges
-
Full-text search across every file
(
f), and find-and-replace across a folder with per-change review (s). -
Preview with syntax highlighting, open
in
$EDITOR(e), fuzzy file jump (/), paste your clipboard straight into a new file (V). -
Diff local against remote
(
D), pull gist changes down (d), link or import existing gists (L,I). -
Git-aware: a git menu (
g) when your folder is a repo, plus sort, bulk actions, and per-key shell aliases in config. - Local-first by principle: sync is opt-in per file and never mutates your folder behind your back.
Why it exists
A gist you share is a copy you can lose track of
You write in markdown, in a folder you own. But your writing has to leave that folder: a gist link in Slack, a doc for a colleague, a post on a blog. Which version is current? Did someone edit the shared one? You can't tell without opening each destination and eyeballing it.
penknife treats each published gist like a git remote: it records what was pushed, notices when either side moves, and shows the drift per file. The folder is primary; the gist is a downstream copy.
And when the destination isn't a gist at all - a manager's Doc, an email, a Slack message - penknife hands you the writing as rich text to paste: a deliberate snapshot with nothing to track. Two jobs, kept separate on purpose.
It is not a backup tool, not an editor, and not an Obsidian plugin. It's the missing seam between the folder where you write and the places your writing ends up.