gn (gn Notes) is a simple CLI note-taking tool for people who prefer plain text over platforms. It uses Markdown files, your existing $EDITOR, and a private GitHub repository to create a simple, portable notes tool that works anywhere.
Open a note, write, save, and quit. gn handles the rest. It automatically pulls the latest version before you edit and securely commits and pushes your changes when you're done. No databases, no subscriptions, no vendor lock-in - just text files, Git, and your terminal.
Download the script directly using the button below, or use the source code inline. Clicking the button will save it locally as gn.sh.
#!/usr/bin/env bash
# --- 1. Configuration ---
NOTES_DIR="$HOME/gn"
REMOTE_BRANCH="main"
mkdir -p "$NOTES_DIR"
cd "$NOTES_DIR" || { echo "Error: Could not access $NOTES_DIR"; exit 1; }
# --- Help Text Function ---
show_help() {
echo "Usage: gn [options] [note_name]"
echo ""
echo "Options:"
echo " -h Show this help message"
echo " -l List all notes in your notes directory"
echo " -g QUERY Search for text across all notes (grep)"
echo " -t Quickly open today's journal note (YYYY-MM-DD.md)"
echo ""
echo "Examples:"
echo " gn Opens index.md"
echo " gn daily-log Opens daily-log.md"
echo " gn work/todo Opens work/todo.md"
echo " gn -g 'api key' Searches notes for the term 'api key'"
echo " gn -t Opens a scratchpad for today's date"
exit 0
}
# --- List Files Function ---
list_notes() {
echo "📂 Current Notes in $NOTES_DIR:"
if [ -d "$NOTES_DIR" ]; then
find . -type f -not -path '*/.*' | sed 's|^\./||' | sort
fi
exit 0
}
# --- Search Inside Notes Function ---
search_notes() {
echo "🔍 Searching for '$1' inside notes..."
grep -Rin "$1" . --exclude-dir=".git"
exit 0
}
# --- Parse Flags ---
while getopts "hlg:t" opt; do
case ${opt} in
h ) show_help ;;
l ) list_notes ;;
g ) search_notes "$OPTARG" ;;
t ) NOTE_NAME=$(date '+%Y-%m-%d') ;;
\? ) show_help ;;
esac
done
shift $((OPTIND -1))
# If -t wasn't passed, get note name from command line arguments
if [ -z "$NOTE_NAME" ]; then
NOTE_NAME="${1:-index}"
fi
if [[ "$NOTE_NAME" != *.md ]]; then
NOTE_NAME="${NOTE_NAME}.md"
fi
NOTE_DIR_PATH=$(dirname "$NOTE_NAME")
if [ "$NOTE_DIR_PATH" != "." ]; then
mkdir -p "$NOTE_DIR_PATH"
fi
# --- Sync From Cloud ---
if git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
echo "🔄 Fetching latest cloud updates..."
git pull origin "$REMOTE_BRANCH" --ff-only --quiet
fi
# --- 3. Open the Editor ---
${EDITOR:-nano} "$NOTE_NAME"
# --- 4. Sync Back to GitHub ---
if git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
if [[ -n $(git status --porcelain) ]]; then
echo "🚀 Syncing changes to GitHub..."
git add -A
git commit -m "Note update: $NOTE_NAME on $(date '+%Y-%m-%d %H:%M:%S')" --quiet
git push origin "$REMOTE_BRANCH" --quiet
echo "✅ Sync complete!"
else
echo "💤 No changes detected. Notes are up to date."
fi
else
echo "⚠️ Warning: This directory is not a Git repository yet. Sync skipped."
fi
Before setting up gn, ensure you have a registered Github account and that Git version control is functional on your computer.
Log into GitHub, click New Repository, and name it gn. Ensure you explicitly change visibility to Private so your data stays hidden. Do not initialize with a README, license, or .gitignore layout template.
Generate an SSH key (skip this if you already have one at ~/.ssh/id_ed25519):
ssh-keygen -t ed25519 -C "you@example.com"
Press Enter to accept the default file location. Optionally add a passphrase when prompted.
Add the key to GitHub:
Click New SSH key, then paste the contents of your public key:
cat ~/.ssh/id_ed25519.pub
Copy the output and paste it into the GitHub key field, then save.
Create the local repo and connect it to GitHub using your SSH remote URL (found on your repo page under Code → SSH):
mkdir -p ~/gn
cd ~/gn
git init -b main
git remote add origin git@github.com:YOUR-USERNAME/gn.git
echo "# Notes" > index.md
git add index.md
git commit -m "Initial commit"
git push -u origin main
Make the gn script executable and copy it into /usr/local/bin, which is already on your PATH by default on Mac, Linux, and BSD - no profile editing needed:
chmod +x gn.sh
sudo cp gn.sh /usr/local/bin/gn
Run gn from your Terminal. Use flags for additional functionality.
gn # Opens your main index.md
gn daily-log # Creates/Opens daily-log.md
gn work/reminders # Creates work/ directory and opens reminders.md
gn -h # Displays help page
gn -l # Lists all your notes
gn -g "todo" # Finds text matching "todo" inside any note
gn -t # Opens today's automated scratchpad entry
Your notes already live in GitHub, so getting them on another machine is straightforward. You just need a new SSH key for that machine, clone the repo, and install gn.
Each machine should have its own SSH key - don't copy the key from your first machine.
ssh-keygen -t ed25519 -C "you@example.com"
Then print the public key so you can copy it:
cat ~/.ssh/id_ed25519.pub
Go to github.com/settings/keys, click New SSH key, paste the public key from the step above, and save. GitHub lets you have multiple SSH keys - one per machine is the right approach.
Instead of git init, you clone the repo that already exists:
git clone git@github.com:YOUR-USERNAME/gn.git ~/gn
This creates ~/gn with all your notes already inside, and the remote already configured.
Download setup.sh using the button above and run it, or just install the script manually:
chmod +x gn.sh
sudo cp gn.sh /usr/local/bin/gn
That's it - run gn from anywhere and it will pull the latest notes before opening the editor, just like on your first machine.
If you're on a machine without a terminal - or just want a quick edit from any browser - you can use github.dev, a full VS Code instance that runs entirely in the browser and commits directly to your repo.
Navigate to your gn repo on GitHub, then press . (period) on your keyboard. The page reloads as a VS Code editor with all your notes in the file tree on the left.
Or just swap github.com for github.dev in the URL directly:
https://github.dev/YOUR-USERNAME/gn
Open any .md file and make your edits. When done, open the Source Control panel (Ctrl+Shift+G / Cmd+Shift+G), enter a commit message, and click the checkmark. The change is pushed to your repo immediately.
The next time you run gn, it automatically pulls any browser edits before opening the editor - no manual sync needed.
Note: if you edit the same note in github.dev and in the terminal without pulling first, git will flag a merge conflict. Always let gn finish its pull step before editing locally.