Skip to main content

grugnotes-cli

Command-line client for the Grug Notes /api/v1/ API.

The /api/v1/ API is public API surface. New server endpoints may be callable by custom clients before this CLI exposes first-class commands for them.

Setup

pip install grugnotes-cli
grugnotes auth          # opens settings page, paste your API key
grugnotes status        # verify connection

API keys are fixed to one space. A key may be broad within that space or limited to a selected prompt allowlist. Permissions are set at creation; create a new key if you need different access.

Security defaults

  • grugnotes auth stores the API key in plain text at ~/.grugnotes. The CLI sets that file to owner-only permissions (0600) and refuses symlinked config paths.
  • sync init --save-key and sync reset --save-key save the active API key into .grugnotes.json so each sync directory remembers its own key. This is useful when you have multiple API keys for different spaces. Keys from --api-key or GRUGNOTES_API_KEY are ephemeral by default and require --save-key to persist. Keys from ~/.grugnotes (global config) are always saved automatically. Precedence: --api-key > GRUGNOTES_API_KEY > .grugnotes.json (local) > ~/.grugnotes (global).
  • For CI, shared machines, or ephemeral shells, prefer GRUGNOTES_API_KEY instead of saving a key locally.
  • The CLI refuses plain http:// base URLs unless the host is loopback (localhost, 127.0.0.1, or ::1). To deliberately use insecure HTTP against a non-localhost host, pass --allow-insecure-http or set GRUGNOTES_ALLOW_INSECURE_HTTP=1.
  • Avoid --api-key when possible; shell history and process lists can leak it. Prefer grugnotes auth or GRUGNOTES_API_KEY.
  • Saved API keys are bound to the base URL they were stored with. If you switch --base-url or GRUGNOTES_BASE_URL, the CLI refuses to reuse the saved key unless you provide an explicit key for that host.
  • Sync commands refuse to operate on symlinked sync directories or directories that contain symlinked sync paths or prompt metadata directories.
  • sync init and sync reset write a local .gitignore covering .grugnotes/, .grugnotes.json, .prompt.json, and *.conflict.md.

Testing

On Apple Silicon, run CLI tests under the x86_64 virtualenv so the xxhash wheel matches the interpreter architecture:

source activate.sh && arch -x86_64 python -m pytest cli/grugnotes_cli/tests -q

Upgrade Note

Legacy .grugnotes.json entries that used sha256:... synced hashes are migrated in place to xxhash as files are scanned (sync status, sync push, sync pull, or sync watch startup). This avoids a one-time "push everything" after upgrade.

Legacy state entries with deleted_remotely=true are also migrated. During migration:

  • unchanged local tracked files are removed;
  • locally edited tracked files are moved to .grugnotes/trash/....

Commands

notes — list notes

grugnotes notes                              # all notes
grugnotes notes daily-notes                  # filter by prompt
grugnotes notes --from 2026-03-01 --to 2026-03-03
grugnotes notes --page 2 --limit 50           # pagination

read — read a note

grugnotes read 42                            # by id
grugnotes read 2026-03-03                    # list notes from a date
grugnotes read daily-notes                   # list notes from a prompt
grugnotes read daily-notes/2026-03-03        # by prompt + filename slug
grugnotes read daily-notes/2026-03-03-2      # suffixed same-date sibling

create — create a note

grugnotes create daily-notes "Hello world"
grugnotes create daily-notes "More text" --date 2026-03-03
grugnotes create daily-notes "Append this" --append

edit — edit a note

grugnotes edit 42 --notes "Full replacement"
grugnotes edit 42 --old "typo" --new "fixed"

prompts / prompt — list or show prompts

grugnotes prompts                             # list all
grugnotes prompts --page 2 --limit 50         # pagination
grugnotes prompt daily-notes                  # show one prompt

Searches synced prompt metadata locally (no API call). Matches by exact name, then startswith, then contains.

grugnotes prompts-search daily

sync — initialize, inspect, and reconcile

grugnotes sync init
grugnotes sync init --prompt daily-notes
grugnotes sync init --from 2026-03-01 --to 2026-03-03
grugnotes sync init --save-key                # persist API key in this directory
grugnotes sync status
grugnotes sync pull
grugnotes sync push
grugnotes sync reset
grugnotes sync reset --save-key               # persist API key on reset
grugnotes sync watch                          # continuous sync
grugnotes sync watch --interval 60            # poll every 60s (default 30)

All sync subcommands except watch support --dry-run to preview changes without writing files. Sync commands exit with code 2 on unresolved conflicts. sync watch polls at the configured interval while there is recent sync activity, then slows remote checks to 60s after 5 minutes of quiet time. If the remote hash signal is temporarily unavailable, watch mode tolerates 3 unavailable poll cycles before falling back to a direct pull. Poll sleeps add up to 25% jitter to avoid synchronized bursts across many clients.

How sync works

The CLI tracks three versions of each note: the remote copy on the server, the local .md file, and a shadow (the last content both sides agreed on, stored in .grugnotes/shadows/).

On pull, the CLI fetches notes changed since the last sync. If only the remote changed, the local file is updated. If both sides changed the same note, a .conflict.md file is written and further syncs are blocked until you resolve it by deleting the conflict file.

On push, the CLI diffs local files against their shadows and sends a 3-way merge patch to the server. The server rejects the push if someone else saved in between (you'll need to pull first).

watch runs both continuously: a file watcher pushes local edits (debounced 3s), while a lightweight poll checks for remote changes every 30–60s.

File names mirror the server's canonical filename_slug. Untitled same-date siblings use suffixed files such as 2026-03-03-2.md; creating such a file and pushing it creates another untitled block on 2026-03-03.

After upgrading from older CLI versions, the first pull may rename files to match server canonical filename slugs. Renames are keyed by remote block ID; if a target path is occupied, sync writes a .conflict.md file instead of overwriting it.

Scripting pattern: pull → edit → push

When a script modifies synced files (e.g. appending changelog entries), always pull before editing to avoid overwriting changes made on the server:

grugnotes sync pull "$DIR"    # get latest from server
echo "new content" >> "$DIR/file.md"  # edit local files
grugnotes sync push "$DIR"   # push changes back

Pulls are incremental — only notes modified since the last sync are fetched.

JSON output

Most commands accept --json to output machine-readable data instead of human-formatted text. sync watch is the main exception because it is a long-running log stream. Useful for scripting:

grugnotes read daily-notes --json | jq '.data[].date'
grugnotes notes --json | jq '.data | length'

Global flags

grugnotes --base-url https://grugnotes.com status

Or use env vars:

export GRUGNOTES_API_KEY="gn_..."
export GRUGNOTES_BASE_URL="https://grugnotes.com"

AI agent integration

The package includes an AGENTS.md skill file with structured instructions for AI coding agents. After install, find it with:

python -c "import importlib.resources; print(importlib.resources.files('grugnotes_cli').parent / 'AGENTS.md')"

Metadata

Release files for grugnotes-cli 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for grugnotes-cli 0.1.1
File Size Uploaded Provenance
grugnotes_cli-0.1.1.tar.gz 38.6 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for grugnotes-cli 0.1.1
File Interpreter ABI Platform
grugnotes_cli-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 80.8 kB

Release files / grugnotes_cli-0.1.1.tar.gz

Download URL grugnotes_cli-0.1.1.tar.gz
Size 38.6 kB
Tags Source
SHA-256 checksum
How to use checksums
6e7dbb940770f75747dc2df7326c06ac8f2c930118dc6a71f67ade1ee21f482f
BLAKE2b-256 checksum
How to use checksums
7d6ca56ead22574d2a359cea76538090451a25c9748ee87ccea4c8cee6b6268e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 2, 2026.

Transparency log

Release files / grugnotes_cli-0.1.1-py3-none-any.whl

Download URL grugnotes_cli-0.1.1-py3-none-any.whl
Size 42.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
289e6cef0372dab5416961bdff9fc24b11805c57c5b0b60e1d41b3844c54ba15
BLAKE2b-256 checksum
How to use checksums
58f29ac9a67b3c15e6f07ee3387ebd4105bc2f735e5e9b6ac3bcb0fdb846097c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 2, 2026.

Transparency log

Security for grugnotes-cli 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for grugnotes_cli-0.1.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 2, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page