Skip to content

Document Sync

Document sync keeps local markdown folders synchronized with Postgram entities. It is designed for notes, knowledge bases, exported docs, and git repositories where .md files are the source of truth.

How to sync a folder of markdown files, how to schedule sync with cron, how to pull a git repository before syncing, and what the manifest protocol does.

  1. Configure the CLI:
Terminal window
export PGM_API_URL=http://127.0.0.1:3100
export PGM_API_KEY=your-api-key
  1. Preview a sync before uploading anything:
Terminal window
pgm sync ~/Documents/personal-notes --repo personal-notes --dry-run
  1. Sync the folder:
Terminal window
pgm sync ~/Documents/personal-notes
  1. Use a stable repository name when the folder name is not enough:
Terminal window
pgm sync ~/Documents/notes --repo notes --quiet

pgm sync <dir> walks the directory recursively and sends only markdown files ending in .md. Relative file paths become the document identity inside the repository, so renaming a file is treated as one deleted document and one new document.

The walker skips:

  • .git, node_modules, .obsidian, and .trash
  • hidden directories such as .cache
  • any directory containing .pgmignore or .noindex

Each file is hashed locally. Postgram asks only for files whose hash is new or changed, so repeated syncs are cheap.

Cron runs with a minimal environment, so set PGM_API_URL, PGM_API_KEY, and PATH in the crontab or in the script it calls.

SHELL=/bin/zsh
PATH=/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin
PGM_API_URL=https://<your-postgram-host>
PGM_API_KEY=<your-api-key>
*/15 * * * * flock -n /tmp/postgram-notes-sync.lock /path/to/sync-postgram-notes.sh >> /path/to/postgram-sync.log 2>&1

The flock wrapper prevents overlapping runs when a sync takes longer than the cron interval. If your system does not provide flock, run the script less frequently or use the locking tool available on that host.

Use a small shell script when the markdown folder is a git checkout. The script fetches the latest default branch, syncs only after a successful fast-forward, and keeps cron logs useful.

sync-postgram-notes.sh
#!/usr/bin/env bash
set -euo pipefail
export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin"
export PGM_API_URL="${PGM_API_URL:-https://<your-postgram-host>}"
export PGM_API_KEY="${PGM_API_KEY:?PGM_API_KEY is required}"
REPO_DIR="${REPO_DIR:-$HOME/Documents/notes}"
POSTGRAM_REPO="${POSTGRAM_REPO:-notes}"
BRANCH="${BRANCH:-main}"
cd "$REPO_DIR"
git fetch --prune origin "$BRANCH"
git merge --ff-only "origin/$BRANCH"
pgm sync "$REPO_DIR" --repo "$POSTGRAM_REPO" --dry-run --json
pgm sync "$REPO_DIR" --repo "$POSTGRAM_REPO" --quiet

For a cron job, call the script with any overrides inline:

PGM_API_URL=https://<your-postgram-host>
PGM_API_KEY=<your-api-key>
0 * * * * REPO_DIR=/path/to/notes POSTGRAM_REPO=notes /path/to/sync-postgram-notes.sh >> /path/to/postgram-notes.log 2>&1

Remove the dry-run line if you do not need a preview summary in the cron log.

The CLI uses the same sync API that other clients can use directly:

  • POST /api/sync/diff compares local paths and SHA-256 hashes with the server.
  • Batched POST /api/sync/upload sends only new or changed files.
  • POST /api/sync/finalize archives server-side documents that disappeared from the latest manifest.

Check repository state:

Terminal window
curl http://127.0.0.1:3100/api/sync/status/personal-notes \
-H "Authorization: Bearer $PGM_API_KEY"
  • Use stable --repo names. Changing the repo name creates a separate document namespace.
  • Keep generated directories out of the tree or add .pgmignore to directories that should never be indexed.
  • Use --dry-run for safe validation before upload.
  • Batches are capped at 50 files or 4 MiB of markdown content to protect large payload size.
  • If PGM_API_URL points through a reverse proxy, make sure that proxy allows request bodies larger than the upload batch size. The bundled UI nginx proxy uses client_max_body_size 64m; other proxies need an equivalent setting.
  • Keep PGM_API_KEY out of the repository and crontab logs. Use a dedicated, minimally scoped sync key where possible.