Skip to main content

One CLI for Granola: decrypt on-disk creds and drive the documented internal API (read/share/edit notes).

Project description

granola

One CLI for Granola on Windows & macOS — using Granola's own on-disk session, no API key, no password prompt. It covers two things:

  1. Credentials — decrypt the on-disk chain (Windows DPAPI / macOS Keychain → DEK → cred file), auto-refresh the token (single-use rotation, with safe write-back), print it, or export a portable session file for headless/Linux use.
  2. The documented internal API for a note — read, share, edit — plus a generic call for any of the ~392 internal endpoints.

Unofficial. Uses the internal api.granola.ai surface the desktop app uses; it can change without notice. Credential decrypt works on Windows (DPAPI) and macOS (Keychain); the API layer is portable once you have a token.

Install

uv tool install .          # or: pipx install .
granola auth status

Requires Python ≥ 3.10. Dependencies: httpx, cryptography.

Usage

# auth / engine
granola auth status                  # token status (no secrets; --include-secrets to show)
granola auth token                   # print a valid access token
granola auth refresh                 # force-refresh the selected source
granola auth export session.json     # write a portable, refreshable session file (0600)
granola routes [filter]              # endpoint name -> URL map
granola call <endpoint> --body '{"limit":5}'   # any endpoint, raw

# read
granola notes --limit 20             # recent notes
granola get <id>                     # full ~50-field record (--json for all)
granola meta <id>                    # creator / attendees / conferencing
granola transcript <id>              # transcript as markdown
granola panels <id>                  # AI summary panels

# share / access
granola who <id>                                     # who has access (+ user_ids)
granola share <id> --email teammate@example.com --name "Teammate"  # add collaborator
granola unshare <id> --email teammate@example.com                  # revoke (no email sent)
granola role <id> --user <user_id> --role viewer     # change role
granola folder-who "Team Notes"                       # who has folder-level access
granola share-folder "Team Notes" --email teammate@example.com       # folder ACL (existing users; inherited access)
granola share-folder "Team Notes" --email teammate@example.com --per-note   # invite + direct access on each note
granola unshare-folder "Team Notes" --email teammate@example.com     # revoke folder-level access

# edit
granola update <id> --title "New title"
granola delete <id> --yes            # PERMANENT hard delete

Roles: owner · collaborator · viewer.

See docs/api-gotchas.md for endpoint quirks baked into the typed verbs.

Headless / portable sessions

Credential decrypt needs the Keychain (macOS) or DPAPI (Windows), so it only runs on the machine you signed in on. To drive the API from a headless Linux box or CI, export a session file once and carry it over:

# On your macOS/Windows machine (where Granola is signed in):
granola auth export ~/session.json     # minimal, refreshable, written 0600

# Sign OUT of the Granola desktop app, so only this session holds the refresh token.
# (Desktop + session sharing one single-use refresh token will fight and log each
#  other out on rotation.)

# On the headless box:
export GRANOLA_SESSION=~/session.json
granola notes --limit 20               # refreshes + writes back to the file in place

Every command takes global auth options (before the command) that pick the token source:

--email EMAIL          select an account from local desktop credentials
--session PATH         use a refreshable session file
--access-token TOKEN   use this bearer token directly (no refresh)
--no-refresh           never auto-refresh

Environment equivalents: GRANOLA_SESSION, GRANOLA_ACCESS_TOKEN.

Precedence: a refreshable session (--session / GRANOLA_SESSION) beats a static token (--access-token / GRANOLA_ACCESS_TOKEN); a flag beats its env var; the desktop store is the fallback. If both a static token and a session are set, the session wins and the CLI warns — a static token can't refresh and would silently go stale.

Use --access-token (or granola auth export --no-refresh-token) for short-lived CI where you don't want a long-lived rotating secret on the box.

If a session's refresh token ever dies (the desktop rotated it, or it was revoked), you can't re-bootstrap headlessly — re-run granola auth export on your macOS/Windows machine and copy the file over.

Platforms

Windows macOS
Data dir %APPDATA%\Granola ~/Library/Application Support/Granola
Key source Local StateDPAPI (CurrentUser) login Keychain item Granola Safe Storage / Granola Key
storage.dek unwrap AES-256-GCM (Chromium key) AES-128-CBC (PBKDF2 saltysalt/1003 — Electron safeStorage)
Cred file stored-accounts.json.enc (accounts[].tokens) supabase.json.enc (workos_tokens)
Final decrypt AES-256-GCM(DEK) AES-256-GCM(DEK)

The decrypt must run as the logged-in user (DPAPI / Keychain are user-scoped). On macOS the first run may show a Keychain access prompt for the Granola Safe Storage item — allow it. The macOS crypto is verified against harperreed/muesli's known-good vectors (tests/test_macos_crypto.py).

Layout

granola/
  config, crypto, _http, store        # engine: decrypt the on-disk cred chain
  auth.py       token primitives: refresh exchange, expiry, status (persistence-free)
  sources.py    token sources (desktop / session-file / static) + precedence
  routes, client                      # endpoint resolution + API client
  notes.py      read ops (list/get/meta/transcript/panels)
  sharing.py    collaborators (who/share/unshare/role/share-folder)
  editing.py    update-document / hard-delete
  cli.py        the `granola` command

License

MIT.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

granola_cli-0.1.0.tar.gz (54.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

granola_cli-0.1.0-py3-none-any.whl (31.3 kB view details)

Uploaded Python 3

File details

Details for the file granola_cli-0.1.0.tar.gz.

File metadata

  • Download URL: granola_cli-0.1.0.tar.gz
  • Upload date:
  • Size: 54.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for granola_cli-0.1.0.tar.gz
Algorithm Hash digest
SHA256 ed0d7849b8553c2735e0fe0615a3e35e8c6014e96ececc1a22690ae9e2d63469
MD5 2c680875d2ca26a6c35a7321607a3e1d
BLAKE2b-256 73d377e15e0dff9d49895d3e2f9daf0ebe2471aa8cf8a80c8e73ea6695ddfd28

See more details on using hashes here.

Provenance

The following attestation bundles were made for granola_cli-0.1.0.tar.gz:

Publisher: release.yml on xuelongmu/granola-cli

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file granola_cli-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: granola_cli-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 31.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for granola_cli-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 289cce2f8fbeb16b88ca5648e81868127f224f207d7c1a4a0b20d3999e02b1f0
MD5 754e3e814125f4525a9f53125945b805
BLAKE2b-256 7213aada5060da3c709cc45ca7433e8027f8035a8b2a33dbd23fd1897bfbd495

See more details on using hashes here.

Provenance

The following attestation bundles were made for granola_cli-0.1.0-py3-none-any.whl:

Publisher: release.yml on xuelongmu/granola-cli

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page