Documentation

Granola CLI

granola-pp-cli

Install

npx -y @mvanhorn/printing-press-library install granola

Installs the CLI binary and the agent skill for Claude Code, Codex, Cursor, Gemini CLI, Copilot, and more. Add --cli-only or --skill-only for one half. Requires Node.

Documentation

Every Granola feature — plus offline SQLite cross-meeting search, attendee timelines, and a MEMO pipeline runner no other Granola tool has.

granola-pp-cli reads Granola’s local cache directly and adds the queries Granola.ai’s web app and existing community CLIs cannot answer. Cache-first, then internal API, then public API — transparent fallthrough. memo run, memo queue, attendee timeline, recipes coverage, calendar overlay, and talktime are local-data joins no per-meeting tool produces. Works offline; agent-native JSON by default.

Created by @dstevens (Damien Stevens).

Authentication

Three auth surfaces, ordered fastest to most permissioned. The local cache at ~/Library/Application Support/Granola/cache-v6.json needs no credentials. The internal API at api.granola.ai auto-discovers your WorkOS access_token from supabase.json / stored-accounts.json and rotates the refresh token through WorkOS on every call. The public API at public-api.granola.ai accepts a Bearer key in GRANOLA_API_KEY for workspace-scoped queries; it backs the typed notes and folders top-level commands and is the source when you pass --data-source live.

Quick Start

# Confirm cache + WorkOS token + (optional) public API key all resolve.
granola-pp-cli doctor --json

# Hydrate the local SQLite store from cache + any deltas via internal API.
granola-pp-cli sync

# What’s in cache but not yet MEMO’d this week.
granola-pp-cli memo queue --since 7d --json

# Run the full MEMO pipeline on every meeting since yesterday.
granola-pp-cli memo run --since 24h --to ~/Documents/Dev/meeting-transcripts --json

# Every meeting with Trevin in the last 60 days, oldest first, with the recipes applied per row.
granola-pp-cli attendee timeline alice@example.com --since 60d --json --select id,title,started_at,recipes

# Meetings missing the Discovery panel — the Friday retro gap.
granola-pp-cli recipes coverage --since 14d --json

Unique Features

These capabilities aren't available in any other tool for this API.

MEMO pipeline

  • memo run — Run the preflight → extract pipeline on one meeting or every new meeting since a timestamp, emitting the MEMO three-file artifact and an ndjson run-state ledger.

    Replaces the per-meeting shell loop that drives the MEMO pipeline — one call, one ndjson stream, agent-readable.

    granola-pp-cli memo run --since 24h --to ~/Documents/Dev/meeting-transcripts --json
    
  • memo queue — List every meeting whose transcript is in the cache but whose MEMO triple is not yet on disk.

    Answers the daily question “what’s still un-MEMO’d?” without the user opening Granola at all.

    granola-pp-cli memo queue --since 7d --json
    

Attendee intelligence

  • attendee timeline — Every meeting with a given attendee, ordered oldest→newest, with title, date, folder, and recipe-applied flag per row.

    Pre-call prep in one command; surfaces the conversation arc with a single person across months of meetings.

    granola-pp-cli attendee timeline alice@example.com --since 60d --json --select id,title,started_at,folder,recipes
    
  • attendee brief — Pulls the last N meetings with an attendee and stitches together their real cached notes plus real AI panel summaries — no synthesis.

    Eliminates the click-each-meeting copy-paste that account leads do before every external call.

    granola-pp-cli attendee brief alice@example.com --last 3 --panel action-items --json
    

Folders + recipes

  • folder stream — ndjson stream of every meeting in a Granola folder (resolved via documentLists + listRules) with notes and a named panel inlined.

    Replaces the weekly retro workflow of opening a folder and copy-pasting each meeting’s summary into a spreadsheet.

    granola-pp-cli folder stream client-foo --panel summary --json
    
  • recipes coverage — Surface meetings that did NOT have a named panel template/recipe applied within a date range.

    Friday retro question “did I run the Discovery recipe on every new-prospect call?” answered in one row per gap.

    granola-pp-cli recipes coverage discovery --since 14d --json
    

Transcript analytics

  • talktime — Per-segment-source talk-time for one meeting — microphone (you) vs system (everyone else) in minutes.

    Confidence column lets you grade transcript accuracy; mic vs system split is the input to “am I talking too much” retros.

    granola-pp-cli talktime 196037d9 --json
    
  • talktime — Lifts the per-source talk-time aggregation across N meetings since a date — who-talked-most over time.

    Time-defrag retro input that no per-meeting tool can produce.

    granola-pp-cli talktime --by participant --since 7d --json
    

Cache-native data

  • chat list — List and dump Granola’s AI chat threads anchored to a meeting (entities.chat_thread + entities.chat_message in the cache).

    Recovers the AI Q&A history a user has accumulated against a meeting — useful when chasing what you asked about an account weeks ago.

    granola-pp-cli chat list 196037d9 --json
    
  • calendar overlay — Left-anti-join meetingsMetadata calendar events with documents.google_calendar_event to find calendared-but-not-recorded meetings.

    Sarah’s Friday retro and Damien’s “what did I miss” sweep both reduce to this row-level diff.

    granola-pp-cli calendar overlay --week 2026-05-11 --missed-only --json
    

Pipeline hygiene

  • duplicates scan — Hash (title, date-bucket, attendee-email-set) across the cache and a meeting-transcripts repo to surface duplicates at scale.

    Repos accumulate near-duplicate files when meetings are re-extracted; this returns the dupe groups for cleanup.

    granola-pp-cli duplicates scan --root ~/Documents/Dev/meeting-transcripts --json
    
  • tiptap extract — Render documents[id].notes (TipTap JSON: headings, bullet_list, list_item, bold marks, paragraph_break) to canonical markdown instead of falling back to notes_plain.

    The MEMO summary file’s quality is bounded by extractor fidelity; granola.py loses sub-list hierarchy and bold runs.

    granola-pp-cli tiptap extract 196037d9 --as markdown
    

Usage

Run granola-pp-cli --help for the full command reference and flag list.

Commands

This CLI exposes 35+ commands. Use granola-pp-cli --help for the canonical tree and granola-pp-cli which "<capability>" to find the right command from natural language. Grouped overview:

GroupCommands
MEMO pipelinememo run, memo queue, preflight, extract
Meetingsmeetings list / get / fetch-batch / delete / restore, show
Three streamsnotes-show, panel get, transcript get, tiptap extract
Exportexport <id> -o FILE, export-all --since DATE -o DIR
Cross-meeting analyticsattendee timeline / brief, folder stream, recipes coverage, talktime, calendar overlay, stats frequency / duration / attendees / calendar, collect, duplicates scan, chat list / get
Granola entitiesfolders, folder list / stream, recipes list / describe / coverage, workspaces list
Public API mirrorsnotes list / get, folders (require GRANOLA_API_KEY)
Sync / systemsync, sync-api, doctor, auth login / status / set-token / logout, which, agent-context, version, import
GUI bridge (macOS only)warm <id> <query> — prints by default; --launch activates the Granola desktop app

Output Formats

# Human-readable table (default in terminal, JSON when piped)
granola-pp-cli folders

# JSON for scripting and agents
granola-pp-cli folders --json

# Filter to specific fields
granola-pp-cli folders --json --select id,name,status

# Dry run — show the request without sending
granola-pp-cli folders --dry-run

# Agent mode — JSON + compact + no prompts in one flag
granola-pp-cli folders --agent

Agent Usage

This CLI is designed for AI agent consumption:

  • Non-interactive - never prompts, every input is a flag
  • Pipeable - --json output to stdout, errors to stderr
  • Filterable - --select id,name returns only fields you need
  • Previewable - --dry-run shows the request without sending
  • Read-only by default with a narrow opt-in write surfacemeetings delete, meetings restore, import, and warm --launch mutate state; everything else inspects, exports, syncs, or analyzes
  • Offline-friendly - sync and the meetings list --query <text> FTS path use the local SQLite store
  • Agent-safe by default - no colors or formatting unless --human-friendly is set

Exit codes: 0 success, 2 usage error, 3 not found, 4 auth error, 5 API error, 7 rate limited, 10 config error.

Auto-Refresh

Every command auto-refreshes the local store as its first action. You do not need to run granola-pp-cli sync before meetings list, panel get, or any other read.

Both auth surfaces refresh independently: the desktop encrypted cache (~/Library/Application Support/Granola/cache-v6.json.enc) via the embedded sync path, and the public REST API (when GRANOLA_API_KEY is set or an access token is saved) via the embedded sync-api path. When both are available, both refresh routines fire. When neither is configured, auto-refresh is a silent no-op.

A one-line provenance summary lands on stderr in interactive mode: auto-refresh: cache=ok (1.2s, 47 rows). It is suppressed under --agent, --json, --compact, --quiet, and when stderr is piped — so agent and CI consumers see no chatter on stdout or stderr.

Opt out with --no-refresh for a single command, GRANOLA_NO_AUTO_REFRESH=1 for a shell session or CI job, or by saving a profile with --no-refresh (granola-pp-cli profile save fast --no-refresh). The skip list (commands that never auto-refresh) is sync, sync-api, auth, doctor, help, version, completion, agent-context, profile, feedback, which. Run granola-pp-cli agent-context --json to see the full contract as structured JSON.

Auto-refresh reads from Granola desktop's encrypted cache file; it does not poke the desktop app to refresh from Granola servers. The freshness ceiling is whatever Granola desktop has already pulled.

Health Check

granola-pp-cli doctor

Verifies configuration, credentials, and connectivity to the API.

Configuration

Config file: ~/.config/granola-pp-cli/config.toml

Static request headers can be configured under headers; per-command header overrides take precedence.

Environment variables:

NameKindRequiredDescription
GRANOLA_API_KEYper_callNoSet to your API credential.

Troubleshooting

Authentication errors (exit code 4)

  • Run granola-pp-cli doctor to check credentials
  • Verify the environment variable is set: echo $GRANOLA_API_KEY Not found errors (exit code 3)
  • Check the resource ID is correct
  • Run the list command to see available items

API-specific

  • doctor reports cache file not found — Make sure Granola is installed and you’ve opened it at least once. Override the path with GRANOLA_CACHE_PATH=/custom/path/cache-v6.json.
  • WorkOS token expired warning — Open the Granola desktop app once — it refreshes the token. Or pass a personal API key via GRANOLA_API_KEY to route through the public API instead.
  • memo run --since reports duplicate_of — A file with the same title-date-attendees fingerprint already exists in --to. Pick a different --to directory, remove the existing file, or mv it out of the way.
  • Transcript missing for a recent meeting — Granola hasn’t flushed it yet. Run warm --launch to bring it forward in the GUI, wait 30 s, then re-run preflight.
  • stats / talktime returns empty rows — Auto-refresh runs sync on every command, so this usually means there is nothing to sync. Confirm Granola desktop is signed in and has captured at least one meeting; run granola-pp-cli doctor to verify the cache is decryptable. If you bypassed auto-refresh with --no-refresh or GRANOLA_NO_AUTO_REFRESH=1, run granola-pp-cli sync manually.

Sources & Inspiration

This CLI was built by studying these projects and resources:

Generated by CLI Printing Press

For agents: pass /documentation/granola/agents.md to install this CLI from a prompt.