@samkawsarani/granola-cli
v1.1.0
Published
Granola API integration — notes, transcripts, and sync with CLI
Downloads
0
Readme
granola-cli
[!IMPORTANT] Disclaimer: This is an unofficial, open-source community project and is not affiliated with, endorsed by, or connected to Granola Labs, Inc. (the company behind Granola.ai). Granola is a registered trademark of Granola Labs, Inc. This CLI is an independent tool that uses the publicly available Granola API to provide command-line access to your own meeting data.
[!NOTE] This tool has only been tested on macOS. It may work on Windows and Linux, but this has not been verified.
A command-line interface for Granola meeting notes.
Access your meetings, notes, and transcripts directly from the terminal. Built with TypeScript and designed for both interactive use and scripting.
Installation
npm install -g @samkawsarani/granola-cli
# or
bun install -g @samkawsarani/granola-cliQuick Start
# Interactive setup
granola init
# List notes
granola list-notes
granola list-notes --limit 25
granola list-notes --after 2026-01-01
# Get a single note
granola get-note --id not_1d3tmYTlCICgjy
granola get-note --id not_1d3tmYTlCICgjy --transcript
# Sync notes to local Markdown files
granola sync-notes
granola sync-notes --after 2026-01-01
granola sync-notes --format json
granola sync-notes --force
# Install agent skill (for Claude Code / Cursor agents)
granola install-skill
granola install-skill --global
granola install-skill --claude # create .claude symlink without prompting
granola install-skill --force # overwrite existing SKILL.md (reinstall/upgrade)Library Usage
import { listNotes, listAllNotes, getNote, syncNotes } from "@samkawsarani/granola-cli";
// List recent notes (single page)
const page = await listNotes({ pageSize: 10 });
// All notes, auto-paginated
const notes = await listAllNotes({
after: "2026-01-01", // optional: created after date
before: "2026-03-01", // optional: created before date
updatedAfter: "2026-01-01", // optional: updated after date
limit: 100, // optional: max notes to return
});
// Single note with transcript
const note = await getNote("not_1d3tmYTlCICgjy", true);
// Sync notes to local files
const result = await syncNotes({
notesDir: "./granola-notes", // required
after: "2026-01-01", // optional
fmt: "markdown", // optional: "markdown" | "json"
limit: 25, // optional
filenameFormat: "{date}-{title}", // optional
useFolders: true, // optional
syncContent: "transcript", // optional: "transcript" | "summary" | "both"
force: false // optional
});
console.log(result); // { synced: 5, skipped: 12, moved: 0 }Configuration
Run granola init for interactive setup, or set environment variables directly.
| Variable | Default | Description |
|---|---|---|
| GRANOLA_API_KEY | — | Granola API key (required) |
| GRANOLA_NOTES_DIR | ./granola-notes | Directory for synced notes |
| GRANOLA_FILENAME_FORMAT | {date}-{title} | Filename template |
| GRANOLA_USE_FOLDERS | false | Organise into folder subfolders |
| GRANOLA_SYNC_CONTENT | transcript | transcript / summary / both |
Config is written to ~/.config/granola/.env. A local .env in the current directory overrides it.
Sync behaviour
sync-notes is idempotent:
- New notes are fetched and written
- Notes with a changed
updated_atare re-fetched and overwritten - Notes that moved folders (when
GRANOLA_USE_FOLDERS=true) are relocated automatically - Unchanged notes are skipped
State is persisted in {GRANOLA_NOTES_DIR}/sync-state.json. Use --force to re-sync everything.
License
MIT — Copyright (c) 2026 Sam Kawsarani
