blumkin
Personal Microsoft 365 / Graph skills CLI — named after Rose “Mrs. B” Blumkin, Berkshire’s legendary operator.
Blumkin turns Graph flows into small, invokable skills any coding agent (Cursor, GitHub Copilot, Claude, …) can run via shell — instead of re-implementing auth and Microsoft Graph calls.
It uses delegated Microsoft Graph access (acts as the signed-in user).
Status
M1 shipped (#10): packaging, auth under ~/.config/blumkin/, skills / doctor, calendar today, Cursor skill, hermetic CI + local live tests.
Tracking: #9 Cursor agent integration (M1 MVP).
Install (blumkin on PATH)
pipx install blumkin
pipx ensurepath # first pipx install only; opens a new shell
Then invoke the binary directly — not uv run blumkin:
blumkin --version # version, commit, and which binary answered
blumkin auth login # once per machine / when cache is cold
blumkin auth status
blumkin skills list --json
blumkin calendar today --json
pipx puts blumkin in its bin dir (usually ~/.local/bin); pipx ensurepath
makes sure that is on PATH.
Upgrade
blumkin upgrade
Wraps pipx upgrade blumkin and prints the version and commit you were on and
the one you moved to — bare pipx upgrade cannot tell you whether PATH still
resolves to a dev checkout.
From a clone (developing blumkin)
uv sync --group dev
uv tool install -e . # editable; `blumkin` now points at the checkout
blumkin --version reports the checkout's commit, and blumkin upgrade will
say it is running from a source checkout and leave the tree alone.
To use blumkin from agent sessions in other repos (Cursor personal skill, or
Copilot CLI instructions), see docs/agent-integration.md.
For cutting a release, see docs/RELEASING.md.
Discovering commands
Every group and leaf command has --help with a description and worked
examples:
blumkin --help # top-level map, common workflows, exit codes
blumkin calendar --help # a group's commands + typical flows
blumkin calendar create --help # one command: args, notes, example invocations
blumkin skills list --json is the machine-readable catalog for agents.
Shell completion
blumkin completion <bash|zsh|fish> prints a completion script. Install it once:
# bash
blumkin completion bash > ~/.blumkin-complete.bash
echo 'source ~/.blumkin-complete.bash' >> ~/.bashrc
# zsh
blumkin completion zsh > ~/.blumkin-complete.zsh
echo 'source ~/.blumkin-complete.zsh' >> ~/.zshrc
# fish
blumkin completion fish > ~/.config/fish/completions/blumkin.fish
Open a new shell afterwards. The script calls back into blumkin for
completions, so keep it on PATH.
Config (~/.config/blumkin/)
Create ~/.config/blumkin/config.toml (mode 0600). Prefer named profiles
in one file (see blumkin profiles list --json and --profile):
default_profile = "work"
[profiles.work]
client_id = "<entra-public-client-id>"
tenant_id = "<your-entra-tenant>"
default_tz = "<IANA timezone, e.g. America/New_York>"
provider = "microsoft"
tags = ["@work", "work", "microsoft", "m365"]
[profiles.personal]
provider = "google"
default_tz = "<IANA timezone>"
google_oauth_client_file = "~/path/to/google-oauth-desktop-client.json"
tags = ["@personal", "personal", "google", "gmail"]
Legacy flat keys (no [profiles.*]) still load as one implicit profile named
default, with token files in the config dir root.
Set tenant_id, default_tz, and provider in the profile table (there are no
org-specific code defaults). provider defaults to microsoft when omitted.
Interactive browser auth is public-client only (client_id; plus tenant_id for
Microsoft). Do not set a client secret for these flows.
Microsoft token cache files (under profiles/<name>/, or config dir root for
legacy):
msal_token_cache.jsonauth_record.json
Google Workspace (provider = "google")
Full walkthrough: docs/google-setup.md
(Console project, APIs, consent screen / test users, Desktop client JSON,
named profile, login, smoke, troubleshooting).
Short form — point the profile at your Google Cloud Desktop OAuth client
JSON (the Console download). That file holds client_id / client_secret; do
not put the secret in toml or environment variables. Download that JSON when
you create the client — the secret is shown once and Google will not let you
re-download it later (recovery means Reset secret / a new client; see
docs/google-setup.md §A.4):
[profiles.personal]
provider = "google"
default_tz = "..."
google_oauth_client_file = "~/path/to/google-oauth-desktop-client.json"
tags = ["@personal", "personal", "google", "gmail"]
blumkin auth login records the signed-in address as email = "..." in that
profile the first time (display only - it is never used to pick a profile, and
never rewritten afterwards). blumkin profiles list shows it, so two profiles
are tellable apart at a glance; blumkin doctor warns if the profile is later
signed in as a different account.
Optional: set client_id in toml as well; when omitted it is read from the JSON.
Keep the client JSON mode 0600 and outside the repo.
Supported Google verbs: auth, calendar today / view / freebusy / suggest
/ create / accept / cancel / update (update attaches a Meet link), mail inbox / list / get / folders / attachments (list +
download), and mail writes draft / update-draft / delete-draft /
send-draft / reply / forward, and people resolve (own contacts plus the
Workspace directory; a consumer account just uses contacts), and chat find /
last / send / edit / delete / attachments (a 1:1 is a Chat space;
Drive-backed attachments are listed but not downloadable). Everything else
fails closed with a clear
error. mail folders lists Gmail labels that act as folders. Mail writes use the
gmail.compose scope — re-run blumkin auth login once after upgrading, or those
calls exit 4 (missing_scope).
Token file (written by blumkin auth login): profiles/<name>/google_token.json.
Select a profile with --profile / BLUMKIN_PROFILE (name or unique tag). Use
BLUMKIN_CONFIG_DIR only to select a config directory. Never commit these
files. Optional graph_timeout_seconds in toml also bounds Google HTTP /
token-refresh calls (same knob as Microsoft Graph).
Tests
uv run pytest -m 'not live' # CI-equivalent (mocks / offline)
BLUMKIN_LIVE=1 uv run pytest -m live # live Graph reads + silent refresh
Live tests need ~/.config/blumkin/ by default (override with BLUMKIN_CONFIG_DIR):
config.toml, token cache, auth record, and a usable refresh token. Never commit those files.
Docs
PLAN.md— CLI designHANDOFF.md— session handoffAGENTS.md— contributor / agent ground rulesRETROSPECTIVE-M1.md— M1 ship retrospective (#11)docs/agent-integration.md— using blumkin from Cursor / Copilot CLI, and the frozenskills list --jsoncontractdocs/RELEASING.md— release flow, PyPI trusted publishing, verifying a published releasedocs/google-setup.md— Google Cloud Desktop OAuth + blumkin Google profile.cursor/skills/blumkin/SKILL.md— Cursor agent skill
License
MIT — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file blumkin-0.2.0.tar.gz.
File metadata
- Download URL: blumkin-0.2.0.tar.gz
- Upload date:
- Size: 332.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6df3715f066f468018e145a98d7e35b20028e97d40a1d49a7ee98e97b20c587f
|
|
| MD5 |
8a0893fdbfebaad7a998087014fa86e4
|
|
| BLAKE2b-256 |
143dd10b32e219b3d2b0f1d93ea9e3d3ec3a1a042a787f501daf0e5e2473eb4f
|
Provenance
The following attestation bundles were made for blumkin-0.2.0.tar.gz:
Publisher:
release-please.yml on the-hcma/blumkin
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
blumkin-0.2.0.tar.gz -
Subject digest:
6df3715f066f468018e145a98d7e35b20028e97d40a1d49a7ee98e97b20c587f - Sigstore transparency entry: 2688678762
- Sigstore integration time:
-
Permalink:
the-hcma/blumkin@84e2b135b1c2858b2c325f4a6877b3d725ae3bcb -
Branch / Tag:
refs/heads/main - Owner: https://github.com/the-hcma
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-please.yml@84e2b135b1c2858b2c325f4a6877b3d725ae3bcb -
Trigger Event:
push
-
Statement type:
File details
Details for the file blumkin-0.2.0-py3-none-any.whl.
File metadata
- Download URL: blumkin-0.2.0-py3-none-any.whl
- Upload date:
- Size: 139.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
153a31923c5c3f681ae62c64d5b8e1dd5a477a384ed50c7ca0a110584a18e0a1
|
|
| MD5 |
97b2b71cb590f01c9cbe547c0cc80bac
|
|
| BLAKE2b-256 |
535b1bd49d40415d2318bb122feaa572aacccfa6d60845e255999552967c4ec1
|
Provenance
The following attestation bundles were made for blumkin-0.2.0-py3-none-any.whl:
Publisher:
release-please.yml on the-hcma/blumkin
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
blumkin-0.2.0-py3-none-any.whl -
Subject digest:
153a31923c5c3f681ae62c64d5b8e1dd5a477a384ed50c7ca0a110584a18e0a1 - Sigstore transparency entry: 2688678826
- Sigstore integration time:
-
Permalink:
the-hcma/blumkin@84e2b135b1c2858b2c325f4a6877b3d725ae3bcb -
Branch / Tag:
refs/heads/main - Owner: https://github.com/the-hcma
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-please.yml@84e2b135b1c2858b2c325f4a6877b3d725ae3bcb -
Trigger Event:
push
-
Statement type: