Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"name": "mgraphctl",
"displayName": "mgraphctl",
"source": "./",
"version": "0.2.0",
"version": "0.2.1",
"description": "Work with Microsoft 365 — Outlook mail and calendar, Teams chats and channels, presence, meetings and transcripts, SharePoint, OneDrive, OneNote, Planner, To Do, people and org chart — through the Microsoft Graph API (Python CLI run with uv).",
"author": {
"name": "Sviatoslav Sviridov",
Expand Down
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/claude-code-plugin.json",
"name": "mgraphctl",
"version": "0.2.0",
"version": "0.2.1",
"description": "Work with Microsoft 365 — Outlook mail and calendar, Teams chats and channels, presence, meetings and transcripts, SharePoint, OneDrive, OneNote, Planner, To Do, people and org chart — through the Microsoft Graph API (Python CLI run with uv).",
"author": {
"name": "Sviatoslav Sviridov",
Expand Down
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## [0.2.1] — 2026-09-06

- The skill's command reference is one file per noun. `reference/commands.md` keeps the
conventions every verb shares — argument resolution, the list envelope, paging defaults, exit
codes, environment variables — and indexes `reference/commands/<noun>.md`, so answering a
question about one noun reads roughly a tenth of what the single 87 KB file cost. `api` and
`search` move from the `config` section to `top-level.md`, where they belong.
- SKILL.md documents the `config` verbs, which the cheat-sheet had omitted, and no longer
compares the CLI with the Node `msgraph` skill: the "Differences from" section is gone, as are
the P0/P1/P2 parity tiers. Where a verb needs more than the `default` scope set it now says so
in place, as `Beyond \`default\`:`; a verb without that line works with `default`.
- The README links the skill's command documentation.

## [0.2.0] — 2026-09-06

- The plugin runs under the Claude desktop app. The supported Python floor drops to 3.10
Expand Down
8 changes: 5 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ src/mgraphctl/
config.py errors.py fixtures.py
skills/mgraphctl/
SKILL.md # the skill (<=400 lines; every verb via the shim)
reference/commands.md # one `### noun verb` heading per registered verb
reference/commands.md # shared conventions + index of the per-noun files
reference/commands/<noun>.md # one `### noun verb` heading per registered verb
evals/evals.json
tests/ # test_cli_<noun>.py per noun; @covers ties tests to verbs
.claude-plugin/ # plugin.json + single-entry marketplace.json
Expand All @@ -47,8 +48,9 @@ scripts/ # stdlib-only helpers CI runs: scan_secrets.py, e

## Invariants the tests enforce

- Every registered verb has a `@covers` test, a `--json` flag, and a heading in
`reference/commands.md` (`test_surface.py`, `test_docs.py`).
- Every registered verb has a `@covers` test, a `--json` flag, and a heading in some
`reference/commands/<noun>.md`, which `reference/commands.md` links (`test_surface.py`,
`test_docs.py`).
- The five version strings agree and are bare `X.Y.Z` (`test_version.py`).
- SKILL.md frontmatter follows the Agent Skills rules: name pattern, description <= 1024 chars,
no XML-shaped tags (`test_docs.py`).
Expand Down
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,22 @@ uv run --project <plugin> --frozen --no-dev mgraphctl login
Every other command reads the cached sign-in silently and never opens a browser or a device-code
prompt — a missing or expired token fails with an actionable hint instead.

## Commands

All 123 verbs are documented inside the skill, and `--help` works at every level.

| Where | What |
|---|---|
| [`skills/mgraphctl/SKILL.md`](skills/mgraphctl/SKILL.md) | the skill itself: setup, a cheat-sheet of every noun and its verbs, recipes, guardrails, exit codes |
| [`skills/mgraphctl/reference/commands.md`](skills/mgraphctl/reference/commands.md) | the conventions every verb shares — argument resolution, the list envelope, paging defaults, exit codes, environment variables — and the index of the files below |
| [`skills/mgraphctl/reference/commands/`](skills/mgraphctl/reference/commands/) | one file per noun (`mail.md`, `calendar.md`, `teams.md`, …): each verb's options, the Graph call it makes and the scopes it needs |

```bash
${CLAUDE_PLUGIN_ROOT}/mgraphctl --help
${CLAUDE_PLUGIN_ROOT}/mgraphctl mail --help
${CLAUDE_PLUGIN_ROOT}/mgraphctl mail list --help
```

## Where things live

- Virtual environment: under `${CLAUDE_PLUGIN_DATA}` when Claude Code sets it, otherwise
Expand Down
1 change: 1 addition & 0 deletions VERSIONING.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,4 @@ summarises it.
|-----|------|---------|
| `mgraphctl--v0.1.0` | 2026-09-05 | Initial release: parity with `msgraph`, config file, keychain token storage, client id guard. |
| `mgraphctl--v0.2.0` | 2026-09-06 | Python floor drops to 3.10, so the plugin runs under the Claude desktop app. |
| `mgraphctl--v0.2.1` | 2026-09-06 | Command reference split into one file per noun. |
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "mgraphctl"
version = "0.2.0"
version = "0.2.1"
description = "Microsoft Graph CLI behind the mgraphctl Claude Code skill"
readme = "README.md"
license = "MIT"
Expand Down
47 changes: 15 additions & 32 deletions skills/mgraphctl/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@ description: >
allowed-tools: Bash(${CLAUDE_PLUGIN_ROOT}/mgraphctl *)
metadata:
author: Sviatoslav Sviridov
version: "0.2.0"
version: "0.2.1"
---

# Microsoft Graph (Python CLI)

Read the user's Microsoft 365 data and, with their confirmation, write to it. Every capability is
one `noun verb` command. `reference/commands.md` in this skill directory has the full option table,
Graph call, scopes and tier for all 118 verbs — open it whenever a flag is not on this page.
one `noun verb` command. `reference/commands.md` in this skill directory holds the conventions
they share and indexes `reference/commands/<noun>.md`, one file per noun, carrying the option
table, Graph call and scopes for all 123 verbs. Open the one noun's file a task needs.

## Setup

Expand Down Expand Up @@ -70,12 +71,14 @@ command to run.

## Command cheat-sheet

Two examples per noun. Full option tables are in `reference/commands.md`.
Two examples per noun. Full option tables are in `reference/commands/<noun>.md`.

**Top level** — `login`, `logout`, `status`, `claims`, `me`, `version`, `api`, `search`
**Top level** — `login`, `logout`, `status`, `claims`, `me`, `version`, `api`, `search`, and
`config path|show|init|set|unset`, which reads the user's setup — never change it unasked.

```bash
${CLAUDE_PLUGIN_ROOT}/mgraphctl me --json
${CLAUDE_PLUGIN_ROOT}/mgraphctl config show --json
${CLAUDE_PLUGIN_ROOT}/mgraphctl search "quarterly plan" --type driveItem
```

Expand Down Expand Up @@ -240,9 +243,8 @@ ${CLAUDE_PLUGIN_ROOT}/mgraphctl meetings list --start -1d --subject standup --re
${CLAUDE_PLUGIN_ROOT}/mgraphctl meetings transcript MEETINGID TRANSCRIPTID --output /tmp/standup.txt
```

Summarise the saved file. With a Microsoft 365 Copilot licence, ask Graph for the recap instead —
this is Node's `transcripts --insights`, in two steps: resolve the meeting id with `meetings list
--subject … --resolve`, then
Summarise the saved file. With a Microsoft 365 Copilot licence, ask Graph for the recap instead,
in two steps: resolve the meeting id with `meetings list --subject … --resolve`, then

```bash
${CLAUDE_PLUGIN_ROOT}/mgraphctl meetings insights MEETINGID --json
Expand Down Expand Up @@ -275,11 +277,9 @@ ${CLAUDE_PLUGIN_ROOT}/mgraphctl people search "Anna" --json
`onedrive mkdir`, `onedrive move`, `onedrive rename`, `onedrive delete`, `onedrive share`,
`sharepoint upload`, `onenote create`, `planner create`, `planner update`, `planner complete`,
`planner delete`, `todo create`, `todo update`, `todo complete`, `todo delete`,
`todo from-mail`, and any `api` call whose method is not GET. `--dry-run` withholds the
write; the GET lookups that turn names into ids (folder, calendar, team/channel, chat by
UPN, section, plan/bucket, To Do list, assignee UPN, and the message read by
`todo from-mail`) still run — pass ids (`id:`, GUID, `19:…`) for a fully offline dry run.
`chats dm --dry-run` alone makes no request.
`todo from-mail`, and any `api` call whose method is not GET. `--dry-run` withholds the write,
but the GET lookups that turn names into ids still run; pass ids (`id:`, GUID, `19:…`) for a
fully offline dry run. `reference/commands.md` lists which lookups those are.
2. **Never run `login`.** Give the user the command and wait. No data command ever opens a browser.
3. **Use `--json` when you are parsing, text when you are showing the user.** Text tables are made
for reading; JSON is stable and complete.
Expand Down Expand Up @@ -353,8 +353,8 @@ Errors are one stderr block: `error[<CODE>]: <message>`, an optional `request-id

Each of these (except `NO_COLOR`, `COLUMNS` and the proxies) can also live in
`~/.mgraphctl/config.toml` as the name without `MGRAPHCTL_`, lower-cased; flag beats env beats
file. `config show` prints every effective value and its source; `config set KEY VALUE` edits one.
Do not set these yourself; they belong to the user's environment.
file. `config show` prints every effective value and its source. Do not set these yourself; they
belong to the user's environment.

## Scopes and consent

Expand All @@ -379,20 +379,3 @@ Three scopes are in neither set and are asked for one at a time with `login --sc
Many tenants require an administrator to consent once before any of this works. `CONSENT_REQUIRED`
prints the admin-consent URL — pass it to the user for their administrator. You cannot grant it,
and retrying will not help.

## Differences from the `msgraph` (Node) skill

What changed:

- Node's flag-driven modes became `noun verb`: `emails --read ID` is `mail read ID`,
`calendar --create` is `calendar create`, `teams --dm` is `chats dm`, `channels --team-id T
--send` is `teams channel send TEAM CHANNEL --body`.
- `sharepoint --file-url URL` is `sharepoint url URL`; Node's `--dry-run` there is now `--info`.
- The whole `transcripts` mode is the `meetings` noun: `transcripts --meeting M --transcript T` is
`meetings transcript M T`, and `transcripts --insights` is `meetings list --subject … --resolve`
followed by `meetings insights MEETINGID`.
- `mail list` defaults to the Inbox, where Node listed the whole mailbox — pass `--folder all` for
the old behaviour.
- Exit codes differ: auth failures are 3 and not-found is 4, where Node often exited 0 or 2. Check
the exit code, not just the text.
- `org` has no summary mode; compose it from `org manager`, `org reports` and `people search`.
Loading