Package Exports
- granola-toolkit
- granola-toolkit/dist/cli.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (granola-toolkit) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
granola-toolkit
Toolkit for working with Granola meetings, notes, and transcripts.
Install
From npm:
npm install -g granola-toolkit
granola --helpWithout a global install:
npx granola-toolkit --help
npx granola-toolkit meeting --helpFor local development:
curl -fsSL https://vite.plus | bash
vp help
vp installRun
Installed command:
granola --help
granola attach --help
granola auth login
granola exports --help
granola folder --help
granola meeting --help
granola notes --help
granola serve --help
granola tui --help
granola transcripts --help
granola web --helpThe published package exposes both granola and granola-toolkit as executable names.
Local build:
vp pack
node dist/cli.js --help
node dist/cli.js attach --help
node dist/cli.js exports --help
node dist/cli.js folder --help
node dist/cli.js meeting --help
node dist/cli.js notes --help
node dist/cli.js serve --help
node dist/cli.js tui --help
node dist/cli.js transcripts --help
node dist/cli.js web --helpYou can also use the package scripts:
npm run build
npm run start -- meeting --help
npm run notes -- --help
npm run tui -- --help
npm run transcripts -- --helpExamples
Export notes:
granola auth login
granola notes
granola notes --folder Team
node dist/cli.js notes --supabase "$HOME/Library/Application Support/Granola/supabase.json"
node dist/cli.js notes --format json --output ./notes-json
granola exports list
granola exports rerun notes-1234abcdExport transcripts:
node dist/cli.js transcripts --cache "$HOME/Library/Application Support/Granola/cache-v3.json"
node dist/cli.js transcripts --format yaml --output ./transcripts-yaml
granola transcripts --folder TeamInspect individual meetings:
granola folder list
granola folder view Team
granola meeting list --limit 10
granola meeting list --search planning
granola meeting list --folder Team
granola meeting view 1234abcd
granola meeting notes 1234abcd
granola meeting transcript 1234abcd --format json
granola meeting export 1234abcd --format yaml
granola meeting open 1234abcd
granola tui
granola tui --meeting 1234abcdRun the local API server:
granola serve
granola serve --port 4096
granola serve --hostname 0.0.0.0 --port 4096
granola serve --network lan --password "change-me"
granola attach http://127.0.0.1:4096
granola attach http://127.0.0.1:4096 --meeting 1234abcd
granola attach http://127.0.0.1:4096 --password "change-me"
granola web
granola web --meeting 1234abcd
granola web --open=false --port 4096
granola web --network lan --password "change-me" --trusted-origins "https://trusted.example"How It Works
Notes
notes exports Granola's generated meeting notes, not the raw transcript.
The flow is:
- read a stored Granola session, or fall back to your local
supabase.json - extract the WorkOS access token from it
- call Granola's paginated documents API
- normalise each document into a structured note export
- choose the best available note content for each document
- render that export as Markdown, JSON, YAML, or raw JSON
- write one file per document into the output directory
When you pass --folder <id|name>, the export is filtered to that folder and, by default, written into a stable per-folder subdirectory under the notes output root.
Content is chosen in this order:
noteslast_viewed_panel.contentlast_viewed_panel.original_content- raw
content
Markdown note files include:
- YAML frontmatter with the document id, created timestamp, updated timestamp, and tags
- a top-level heading from the note title
- converted note body content
Transcripts
transcripts exports Granola's locally cached transcript segments.
The flow is:
- read Granola's cache JSON from disk
- parse the cache payload, whether it is double-encoded or already an object
- normalise transcript data into a structured export per document
- match transcript segments to documents by document id
- render each export as text, JSON, YAML, or raw JSON
- write one file per document into the output directory
When you pass --folder <id|name>, the export is filtered to that folder and, by default, written into a stable per-folder subdirectory under the transcripts output root.
Speaker labels are currently normalised to:
YouformicrophoneSystemfor everything else
Structured output formats are useful when you want to post-process exports in scripts instead of reading the default human-oriented Markdown or text files.
Meetings
meeting combines the API-backed notes path with the local transcript cache so you can inspect one meeting at a time.
The flow is:
- read a stored Granola session, or fall back to
supabase.json - fetch documents from Granola's API
- optionally load the local cache for transcript data
- resolve a meeting by full id or unique id prefix
- render either a list, a combined meeting view, focused notes/transcript output, or a machine-readable export bundle
The human-readable view command shows:
- meeting metadata
- the selected notes content
- transcript lines when the local cache is available
The focused meeting subcommands are:
meeting notesfor just the selected note outputmeeting transcriptfor just the selected transcript outputmeeting opento start the web workspace focused on one meeting
The machine-readable export command includes:
- a meeting summary
- structured note data plus rendered Markdown
- structured transcript data plus rendered transcript text when available
Folders
folder exposes Granola document lists as a first-class concept instead of leaving meetings in one flat global list.
The flow is:
- reuse the shared auth path that
notesandmeetingalready use - call Granola's document-list API, with
v2first andv1fallback - normalise folder metadata and document membership into shared folder records
- attach folder membership to meetings in the shared app core
- let folder commands and meeting filters resolve folders by id, prefix, or unique name
The current CLI surface includes:
folder listfolder view <id|name>meeting list --folder <id|name>notes --folder <id|name>transcripts --folder <id|name>
Server
serve starts a long-lived local Granola Toolkit server on one shared app instance.
The initial server API includes:
GET /healthGET /server/infoPOST /auth/unlockfor password-protected serversPOST /auth/lockto clear the browser/API unlock cookieGET /auth/statusGET /stateGET /eventsfor server-sent state updatesGET /foldersGET /folders/resolve?q=<query>GET /folders/:idGET /meetingsGET /meetings?folderId=<id>for folder-scoped meeting listsGET /meetings?refresh=trueto bypass the local meeting index and force a live refreshGET /meetings/resolve?q=<query>GET /meetings/:idGET /exports/jobsPOST /auth/loginPOST /auth/logoutPOST /auth/modePOST /auth/refreshPOST /exports/noteswith optionalfolderIdPOST /exports/jobs/:id/rerunPOST /exports/transcriptswith optionalfolderId
This is the shared runtime for granola web and granola attach.
Server hardening now includes:
localnetwork mode by default, which binds to127.0.0.1lannetwork mode when you explicitly want other devices to connect- optional password protection for API routes and the browser client
- trusted-origin checks for browser requests, with CORS headers only for allowed origins
- a warning when you expose the server on
lanwithout a password
Web
web starts the same local server as serve, enables the browser client at /, and opens that workspace in your default browser unless you pass --open=false.
You can deep-link into a specific meeting with either:
granola web --meeting <id>granola meeting open <id>
The initial browser client includes:
- a dedicated folder pane with an explicit All meetings scope
- a searchable meeting list
- folder-aware meeting browsing with one-click scope changes
- a fast local-index warm start for meeting browsing before live documents finish loading
- sort and updated-date filters
- quick open by meeting id or title
- browser URL state that preserves the selected folder, meeting, and tab
- a focused meeting workspace with notes, transcript, metadata, and raw tabs
- keyboard-first workspace switching with
1-4,[and] - app-state status from the shared core
- an auth session panel for login, refresh, source switching, and sign-out
- note and transcript export actions backed by the same local API
- folder-scoped export actions that follow the currently selected folder
- a recent export-jobs panel with rerun actions
- stronger empty and error states for list/detail failures
- a server-access panel that can unlock or lock a password-protected local server
Attach
attach connects the terminal workspace to an already running granola serve or granola web instance instead of starting a second isolated app.
Use it when you want:
- two terminal workspaces attached to the same live app state
- one terminal workspace and one browser workspace sharing auth, meeting index, and export-job history
- a password-protected local server to remain the single source of truth
The attach flow uses the existing local HTTP API plus GET /events for live state updates.
Runtime Boundaries
The toolkit now keeps its local persistence and transport contracts explicit:
- one shared local data directory for export jobs, meeting index data, and any file-backed session state
- one versioned local HTTP transport contract, exposed by
GET /server/info - one remote client handshake that validates the transport protocol before attaching
That keeps the current single-package repo simple, while making a future split into separate server/client packages or remote-hosted clients much less invasive.
TUI
tui starts a full-screen terminal workspace on the shared app core, without requiring the local server or browser client. Use attach when you want the same workspace against an existing shared server instance instead.
The initial terminal workspace includes:
- a folder scope inside the navigation pane, including an explicit All meetings view
- a meeting list pane with keyboard navigation
- a detail pane with notes, transcript, metadata, and raw views
- an auth session overlay for import, refresh, source switching, and sign-out
- a footer with app state and key hints
- a quick-open overlay for jumping by title, id, or tag
The main keyboard controls are:
h/l, left / right, orTabto switch between folders and meetingsj/kor arrow keys to move within the active folder or meeting list/orCtrl+Pto open quick openato open auth session actions1-4to switch detail tabsPageUp/PageDownto scroll the detail panerto refresh from live Granola dataqto quit
Local Meeting Index
Interactive meeting browsing now keeps a local index of meeting summaries and metadata.
That index is used to:
- make the web meeting list available quickly on startup
- keep search, sort, and date filtering useful before every live document payload is fetched again
- refresh itself after successful live loads so the next run starts warm
The web client uses the index as a fast path and upgrades to live data automatically when the background refresh completes. The manual Refresh button bypasses the index and forces a live meeting fetch immediately.
Export Jobs
Exports are now tracked as jobs with:
- persistent local history across CLI and web runs
- explicit scope metadata for all-meetings and folder-scoped runs
- running, completed, and failed status
- per-export progress counters
- rerun support from
granola exports rerun <job-id>or the web client
Use granola exports list to inspect recent jobs from the CLI.
Auth
If you do not want to keep passing --supabase, import the desktop app session once:
granola auth login
granola auth status
granola auth refresh
granola auth use stored
granola auth use supabaseThat stores a reusable Granola session locally and lets granola notes use it directly.
granola auth now supports:
loginto import the desktop app session into the toolkit storestatusto inspect the active source, stored-session availability, refresh support, and any last auth errorrefreshto refresh the stored session explicitlyuse storedoruse supabaseto switch the active auth sourcelogoutto delete the stored session
The same auth actions are also available from the web workspace.
Incremental Writes
Both commands keep a small hidden state file in the output directory to track:
- document id to filename
- content hash
- source timestamp
- last export time
That state is used to:
- keep filenames stable even if a meeting title changes later
- skip rewrites when the rendered content is unchanged
- migrate old files cleanly when the output format changes
- delete stale exports when a document disappears from the source data
That makes repeated runs cheap and keeps long-lived export directories much cleaner.
Config
The CLI reads configuration in this order:
- command-line flags
- environment variables
.granola.toml- platform defaults
Supported config keys:
debug = true
supabase = "/Users/yourname/Library/Application Support/Granola/supabase.json"
output = "./notes"
timeout = "2m"
cache-file = "/Users/yourname/Library/Application Support/Granola/cache-v3.json"
transcript-output = "./transcripts"Supported environment variables:
DEBUG_MODESUPABASE_FILEOUTPUTTIMEOUTCACHE_FILETRANSCRIPT_OUTPUTGRANOLA_CLIENT_VERSION
Development Checks
Before pushing changes, run:
vp check
vp test
npm run coverage
vp pack
npm pack --dry-runWhat those do:
vp check: formatting, linting, and type checksvp test: unit testsnpm run coverage: unit tests plus a local coverage report incoverage/coverage-summary.jsonvp pack: builds the CLI bundle intodist/cli.jsnpm pack --dry-run: shows the exact npm package contents without publishing
vp build is for web apps. This repo is a CLI package, so the build step here is vp pack.