GranolaDB
The database that runs on your meeting notes.
Stop paying for S3, CloudWatch, and Datadog. GranolaDB stores your logs and agent traces in Granola — the AI meeting-notes app — as meeting notes. Infinitely scalable*. Fully searchable**. Your traces finally get an AI summary.
Install
pip install granoladb # core
pip install granoladb[otel] # + OpenTelemetry span exporter
pip install granoladb[capture] # + `granoladb login --capture` (macOS)
Then get your Granola access token. On macOS, GranolaDB grabs it for you:
granoladb login --capture
This intercepts your own Granola app's traffic (via mitmproxy's local mode) and
lifts the Authorization: Bearer token out of it — because Granola encrypts the
token on disk and its network client ignores every proxy, so there's genuinely no
politer way to get it. You'll approve a one-time macOS network-extension prompt,
then click around a couple of notes so the app makes a request. Yes: GranolaDB
MITMs your own Granola to obtain a token Granola won't hand out. That is the joke,
and it is load-bearing.
The token is a short-lived session JWT (expires in a few hours) — rerun --capture
when it does. Or, if you have a token another way, cache it directly:
granoladb login <YOUR_TOKEN> # store it (OS keychain)
export GRANOLA_TOKEN="..." # or per-shell, nothing stored
granoladb logout # forget the stored token
(There's also an experimental granoladb login --auto that tries to decrypt the
token straight from the app's local store, but Granola's on-disk crypto changes
often, so don't count on it.)
Exactly how --capture works (no hidden magic)
We think you should know precisely what this does before running it:
- It launches mitmproxy in "local mode" pointed at the Granola process only. mitmproxy installs a macOS network extension ("Mitmproxy Redirector") that you approve once — it reroutes only Granola's traffic through mitmproxy.
- Why intercept at all: Granola encrypts the token on disk and its API client ignores every proxy (system, env, VPN), so there is no file to read or setting to flip. Intercepting the app's own traffic is the only way to obtain it.
- What it reads: when Granola calls
api.granola.ai, the request carries anAuthorization: Bearer <token>header.--captureextracts only that value. - Where it goes: stored locally only — in your OS keychain (macOS
Keychain / Windows Credential Manager / Freedesktop Secret Service) via the
keyringlibrary. If no keychain backend exists, it falls back to a0600file at~/.granoladb/tokenand tells you it did so. Nothing is sent anywhere. The mitmproxy process and its temporary capture file are torn down immediately. - What the token is: your own short-lived Granola session JWT — not your
password, not a refresh token.
granoladb logoutdeletes it.
The whole capture flow is in src/granoladb/capture_macos.py
and storage is in src/granoladb/auth.py — read them.
Quickstart
import logging, granoladb
logging.getLogger().addHandler(granoladb.GranolaHandler())
logging.error("payment failed") # this is now a meeting
from granoladb import Client
db = Client()
db.put({"level": "ERROR", "msg": "payment failed", "svc": "api"})
print(db.query(contains="payment"))
vs. legacy databases
| Feature | Postgres | S3 | GranolaDB |
|---|---|---|---|
| Durability | Yes | Yes | "probably" |
| Query latency | ms | ms | one flush interval |
| AI summary of rows | No | No | Yes |
| Retention policy | You set | You | when Granola archives it |
| Production ready | Yes | Yes | absolutely not |
* limited by Granola's rate limits, which we call horizontal scaling. ** limited by Granola's search bar.
How it works
Records are batched into "meetings." Each batch becomes one Granola document — JSON
lines under a GRANOLADB v1 marker, written via Granola's internal
/v1/create-document endpoint and read back via /v1/get-documents. Reads decode
the records out. This is a joke. Do not put anything real in it.
Auth: granoladb login --capture (see above) stores your token in the OS keychain,
or set GRANOLA_TOKEN. Set GRANOLADB_DRY_RUN=1 to print calls instead of writing
to Granola.
License
MIT
Metadata
Release files for granoladb 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| granoladb-0.1.0.tar.gz | 22.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| granoladb-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 40.4 kB
Release files / granoladb-0.1.0.tar.gz
| Download URL | granoladb-0.1.0.tar.gz |
|---|---|
| Size | 22.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fdf01faeb63a7c46973fd10e9f553fddc1f9fa1c8221a71d5d8e20830c5ce09b
|
|
BLAKE2b-256 checksum How to use checksums |
e189d83a7836ed3527b8cfb2dbb3dbdb1b3618d66e240582a98b2ff555b86265
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.12
|
Release files / granoladb-0.1.0-py3-none-any.whl
| Download URL | granoladb-0.1.0-py3-none-any.whl |
|---|---|
| Size | 17.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1d1d76537dde9d18b23d2bc36b2f96c24e71a894f732ca5b7ede72eb49d764d4
|
|
BLAKE2b-256 checksum How to use checksums |
2f3cb4201a92f5d41293ccf0bd8ec678aef2fdd9e88a9fc94e43f39787b90b71
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.12
|