Summary
pb is a small CLI I built in Go to save terminal snippets as plain files and sync them through a private GitHub repository. It works offline, autosaves without filling the history with junk commits, and keeps both copies when two machines disagree.
Why I built it
There is a specific frustration that shows up when you are deep in the terminal and need somewhere to drop a snippet. My day at ValueLabs is distributed systems, tracing logs, and debugging backend logic, and when I am knee-deep in Python and Django configuration, switching context is the enemy.
Opening a browser to paste a JSON payload or a stack trace into some web pastebin breaks that flow. It is also a privacy risk for proprietary code. Note-taking apps have the same problems for this job: they make you leave the terminal, they eat memory, and they lock your text into their own format.
So I wrote down what I actually wanted. It had to work offline. It had to autosave, so closing the terminal by accident never costs a draft. It needed a history of changes. And it had to store everything on infrastructure I already trust.
Go for the binary, GitHub for the storage
My daily stack is Python and Next.js, but I wanted this to be fast and to ship as a single executable, and Go is the right tool for that.
Instead of spinning up a database to hold a few text files, I used something I already had: GitHub, a free, version-controlled backend. pb uses the official GitHub CLI for authentication, so I did not have to build token storage. The first time you initialise it, it creates a private repository called pastebin-cli-store on your account, and that repository is the backend for every snippet.
- Open or create a snippet in the terminal editor.
- Background autosave writes a local recovery snapshot.
- A journal tracks file metadata and pending operations.
- An explicit save creates a durable version.
- An explicit sync reconciles it with the private GitHub repository.
- If both sides changed, a conflict copy is kept.
This is what people mean by local-first. The file on my machine is the real copy. GitHub is where it gets synced, not where it lives.
Autosave without junk history
Building a synced CLI is trickier than it looks, and autosave is where it starts. If every keystroke became a commit, the history would be useless. If nothing was saved until I asked, one closed terminal would lose the draft.
pb splits those two promises. While I type in the built-in editor, it writes recovery snapshots in the background, on my machine only. Its local data lives under the user configuration directory (Go’s os.UserConfigDir), where a journal tracks file metadata and pending operations. A durable version, the kind that reaches GitHub, is only created when I explicitly save or sync.
- The editor buffer contains the current in-memory text.
- A local recovery snapshot protects recent edits from a process crash.
- The working file contains content the user explicitly accepted.
- A Git commit creates a named durable version and history.
- The private remote repository provides an authenticated off-device copy.
- The journal records how these layers relate and which work remains pending.
The safe way to write a snapshot like this is an old trick: write to a temporary file, flush it, then rename it over the previous one. A crash leaves either the old snapshot or the new one, never half of each. The code below is that pattern in outline, not pb’s exact source.
func SaveRecovery(path string, body []byte) error {
tmp := path + ".tmp"
file, err := os.OpenFile(tmp, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o600)
if err != nil {
return err
}
if _, err = file.Write(body); err != nil {
file.Close()
return err
}
if err = file.Sync(); err != nil {
file.Close()
return err
}
if err = file.Close(); err != nil {
return err
}
return os.Rename(tmp, path)
}Sync, and what happens when two machines disagree
I edit a snippet on my work laptop and open it at home. The sync command reconciles the two. Because saving and syncing are separate, editing never waits on the network, and a failed sync never costs me a saved draft.
- Editing makes a snippet an autosaved draft.
- Saving makes it a saved local version.
- Syncing sends it to GitHub.
- If another machine changed it too, a conflict copy is kept.
- Choosing a version returns it to synced.
The hard case is when both machines changed the same snippet before either synced. pb does not blindly overwrite one with the other. It creates a conflict copy, so both versions survive and I choose. Losing a note silently is the one thing a notes tool must never do.
The store is a Git repository, so these are the cases Git’s merge documentation describes. A CLI can hide the commands, but it should not hide the outcome.
Installing it without sudo
The biggest hurdle with small internal tools is getting them onto a machine. I wanted pb to install without administrator rights.
There are shell installers for macOS and Linux and a PowerShell script for Windows. Each one pulls the compiled Go binary from GitHub releases and puts it in a bin directory the user owns.
pb also keeps itself current. It checks GitHub for a newer release about once a day, and the upgrade policy can be set to auto, prompt, or manual, so it never interrupts me mid-thought.
Small and sharp
Building pb was a good exercise in local-first design, and it fixed a very specific itch. I no longer keep terminal output in clunky web apps. I type pb new notes/today.txt, drop the code in, and save.
The best tools are not always big platforms. Sometimes they are the small, sharp utilities we build for ourselves.
References
- Building a GitHub Backed Pastebin CLI in Go
Abhishek Choudhury. Original project article, published April 2026.
- Local-First Software: You Own Your Data, in Spite of the Cloud
Martin Kleppmann, Adam Wiggins, Peter van Hardenberg, and Mark McGranaghan. The principles and trade-offs behind local-first software.
- Package os: UserConfigDir
The Go Authors. Platform-aware application configuration directories.
- git-merge documentation
The Git Project. Merge states, conflicts, abort behavior, and safe preconditions.
- GitHub CLI: gh auth login
GitHub. Authentication modes and credential-storage behavior.
