ms365-connect
Connect to Microsoft 365 (OneDrive, Outlook mail, Calendar, Teams) via Microsoft Graph using the open-source python-o365 (O365) library.
Skill by sonichi
Chalk Labs
Need help deploying ms365-connect?
Chalk Labs sets up agents like this inside real teams: connected to your tools, tested on your data, with a human in the loop where it matters.
Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/sonichi-ms365-connect
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Use cases: productivity
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.
- Tools
- No tools found
- Secrets
- None asked for
- Install scripts
- None found
- Runs as
- Python package
Network hosts it talks to 1
codeload.github.com· found in install command
Files it touches
~/.claude/skills/ms365-connect
What's inside
- Skill name
ms365-connect- Description
- Connect to Microsoft 365 (OneDrive, Outlook mail, Calendar, Teams) via Microsoft Graph using the open-source python-o365 (O365) library. Use when the user wants to list/download OneDrive files, read or send Outlook email, list calendar events, or post a message to a Teams channel from a Sutando workflow.
- License
- MIT
- Instructions
- 122 lines in SKILL.md · view on GitHub
Before installing
- Ships executable scripts
Files (4)
- SKILL.md
- manifest.json
- requirements.txt
- ms365.py · scripts/
SKILL.md (first lines)
# ms365-connect
Microsoft 365 connectivity for Sutando, built on the Apache-2.0
[`python-o365`](https://github.com/O365/python-o365) library (`O365` on PyPI),
which is a thin wrapper over Microsoft Graph.
## What it does
All operations go through Microsoft Graph via python-o365:
- **OneDrive** — list a folder's contents (`onedrive-list`) and download a file
to a local path (`onedrive-get`).
- **Outlook mail** — list recent inbox messages (`outlook-list`) and send an
email (`outlook-send`).
- **Calendar** — list upcoming events over a window of days (`calendar-list`).
- **Teams** — post a message to a channel in a team (`teams-post`).
Authentication is a one-time delegated OAuth2 consent flow (`auth`); the refresh
token is cached on disk so subsequent commands run non-interactively.
## Usage
Run the CLI with `python3 scripts/ms365.py <subcommand>`:
```bash
# One-time: run the OAuth consent flow and cache the token
python3 scripts/ms365.py auth
# OneDrive
python3 scripts/ms365.py onedrive-list # list root
python3 scripts/ms365.py onedrive-list "/Projects/Q3" # list a folder by path
python3 scripts/ms365.py onedrive-get "/Reports/x.pdf" ./x.pdf
# Outlook mail
python3 scripts/ms365.py outlook-list --n 10
python3 scripts/ms365.py outlook-send --to a@b.com --subject "Hi" --body "Hello"
# Calendar
python3 scripts/ms365.py calendar-list --days 7
# Teams
python3 scripts/ms365.py teams-post --team "Engineering" --channel "General" \
--message "Deploy is green"
```
Every subcommand except `auth` requires that `auth` has already been run and a
cached token exists.
## Configuration
Secrets are read from the environment (populate them from the Sutando vault;
**never hardcode**):
| Variable | Purpose |
|----------|---------|
| `MS365_CLIENT_ID` | Azure AD application (client) ID |
| `MS365_CLIENT_SECRET` | Azure AD client secret value |
| `MS365_TENANT_ID` | Directory (tenant) ID, or `common` / `organizations` |
| `MS365_AUTH_FLOW` | `credentials` (default; confidential client, id+secret) or `public` (native client, id only — required when the app's redirect is registered under "Mobile and desktop applications"; symptom of the mismatch: `AADSTS700025` on token exchange). In `public` flow `MS365_CLIENT_SECRET` is not required. |
If any is unset, the CLI exits with a clear message naming the missing variable.
**Token cache:** the OAuth token is stored under the workspace state dir at
`state/ms365-token/o365_token.txt` via python-o365's `FileSystemTokenBackend`.
Override the base with `MS365_STATE_DIR` if the workspace state dir is elsewhere.
Treat this file as a live credential (owner-only permissions).
## Azure AD app registration (one-time, owner does this)
Delegated Graph access requires an app registration. The owner performs this
once in the Azure Portal:
1. **Register the app** — Azure Portal → **Microsoft Entra ID** (Azure AD) →
**App registrations** → **New registration**. Name it (e.g. `Sutando M365`).
For "Supported account types", pick single-tenant unless multi-tenant is
required. Copy the **Application (client) ID** and **Directory (tenant) ID**.
2. **Add a redirect URI** — in the app's **Authentication** blade →
**Add a platform** → **Mobile and desktop applications**, add python-o365's
default native-client redirect:
`https://login.microsoftonline.com/common/oauth2/nativeclient`
(A `http://localhost` redirect also works if you prefer a loopback flow.)
3. **Grant delegated Microsoft Graph scopes** — **API permissions** → **Add a
permission** → **Microsoft Graph** → **Delegated permissions**, add:
| Scope | Why |
|-------|-----|
| `offline_access` | Issue a refresh token so the token cache survives |
| `User.Read` | Read the signed-in user's basic profile |
| `Files.ReadWrite.All` | List and download (and write) OneDrive files |
| `Mail.Read` | Read Outlook inbox messages |
| `Mail.Send` | Send Outlook email as the user |
| `Calendars.ReadWrite` | Read (and create) calendar events |
| `Team.ReadBasic.All` | Look up the team by name (`GET /me/joinedTeams`) — required before posting |
| `Channel.ReadBasic.All` | Look up the channel by name (`GET /teams/{id}/channels`) — required before posting |
| `ChannelMessage.Send` | Post messages to Teams channels |
| `Chat.Read` | Read Teams chat/channel context |
> `teams-post` resolves the team and channel **by display name** before it
> can send, so the two `*.ReadBasic.All` lookup scopes are mandatory — without
> them the lookups return empty and the CLI reports `Team not found` even
> though the team exists.
Click **Grant admin consent** for the tenant if your org requires it.
4. **Create a client secret** — **Certificates & secrets** → **New client
secret**. Copy the secret **Value** immediately (shown once).
5. **Store the 3 credentials in the vault, not in code** — put the
Application (client) ID, the client secret Value, and the Directory (tenant)
ID in the Sutando vault, exposed to this skill as `MS365_CLIENT_ID`,
`MS365_CLIENT_SECRET`, and `MS365_TENANT_ID`.
Then run `python3 scripts/ms365.py auth` once to complete the consent flow and
cache the token.
## RequirementsFrom sonichi/sutando, MIT.
More from sonichi/sutando
- 0.757score
owner-agent-consult
sonichi
Before answering your OWNER, when the answer genuinely depends on something another agent of the same owner holds and you do not, ask that one agent once…
SkillAFreshness: A★ 400Claude Code +9 - 0.757score
marketplace
sonichi
Install marketplace skills, activate cloud tools, check whether installed skills are up to date, or remove them — without the owner opening the Marketplace.
SkillAFreshness: A★ 400Claude Code +9 - 0.757score
tutorial
sonichi
Show a new owner what to try first.
SkillAFreshness: A★ 400Claude Code +9 - 0.757score
macos-tools
sonichi
macOS native integrations: screen capture, calendar, reminders, contacts, email (Mail.app), Spotlight search.
SkillAFreshness: A★ 400Claude Code +9 - 0.757score
import-claude-context
sonichi
Bring the owner's Claude Code history into Sutando: index, extract and haiku-summarise the stock ~/.claude/projects transcripts, stage the result, show the…
SkillAFreshness: A★ 400Claude Code +9 - 0.757score
image-generation
sonichi
Generate an image from a prompt or edit an existing one (Gemini image model, standard library only, any Gemini key the resolver finds) and attach the file to…
SkillAFreshness: A★ 400Claude Code +9 - 0.757score
connect-apps
sonichi
Use when the owner asks about their calendar, email, meetings, Linear, Notion, Slack, Google Drive, GitHub or any other third-party app or the data in it…
SkillAFreshness: A★ 400Claude Code +9 - 0.754score
deal-finder
sonichi
Scan configured sources (Craigslist now; eBay + Facebook Marketplace planned) for used-item listings matching the owner's criteria.
SkillAFreshness: A★ 400Claude Code +9 - 0.754score
quota-tracker
sonichi
Track Claude Code quota usage via Anthropic API rate limit headers.
SkillAFreshness: A★ 400Claude Code +9 - 0.754score
model-switch
sonichi
Change the core's model without the CLI: send /model to the live core's pane through the shared sender, wait for the CLI to accept it (answering its confirm…
SkillAFreshness: A★ 400Claude Code +9 - 0.754score
claude-gemini
sonichi
Use the local Antigravity CLI (agy, Gemini-backed) from Claude Code with the user's existing Gemini authentication or API configuration.
SkillAFreshness: A★ 400Claude Code +9 - 0.754score
phone-conversation
sonichi
Make conversational phone calls and join Zoom meetings via Twilio + Gemini.
SkillAFreshness: A★ 400Claude Code +9
Signals
- Stars
- 400
- Forks
- 98
- Open issues
- 1,202
- Last commit (this folder)
- Aug 7, 2026 (2 months ago)
- Last release
- Aug 20, 2026 (2 months ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- MIT
- Repository
- github.com/sonichi/sutando
- Website
- sutando.ai
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from sonichi
- 0.757score
import-claude-context
sonichi
Bring the owner's Claude Code history into Sutando: index, extract and haiku-summarise the stock ~/.claude/projects transcripts, stage the result, show the…
SkillAFreshness: A★ 400Claude Code +9 - 0.757score
marketplace
sonichi
Install marketplace skills, activate cloud tools, check whether installed skills are up to date, or remove them — without the owner opening the Marketplace.
SkillAFreshness: A★ 400Claude Code +9 - 0.757score
connect-apps
sonichi
Use when the owner asks about their calendar, email, meetings, Linear, Notion, Slack, Google Drive, GitHub or any other third-party app or the data in it…
SkillAFreshness: A★ 400Claude Code +9 - 0.757score
image-generation
sonichi
Generate an image from a prompt or edit an existing one (Gemini image model, standard library only, any Gemini key the resolver finds) and attach the file to…
SkillAFreshness: A★ 400Claude Code +9 - 0.757score
macos-tools
sonichi
macOS native integrations: screen capture, calendar, reminders, contacts, email (Mail.app), Spotlight search.
SkillAFreshness: A★ 400Claude Code +9 - 0.757score
owner-agent-consult
sonichi
Before answering your OWNER, when the answer genuinely depends on something another agent of the same owner holds and you do not, ask that one agent once…
SkillAFreshness: A★ 400Claude Code +9
Done for you
Rather not set it up yourself?
Chalk Labs scopes, builds and runs agents for your team: the task audit, the eval harness, the integrations and the weekly ops report. Fixed scope, priced before we start.
See how we build AI agents →Read the case studies
Chalk Labs is a two-founder AI and growth studio. We build AI agents, CRMs and MVPs for Web3 and AI companies, and have shipped 50+ product and token launches.
- launches shipped
- 50+
- launches shipped
- media placements
- 500+
- media placements
- founders on every account
- 2
- founders on every account
Press we've placed: Forbes · CoinDesk · Decrypt · Cointelegraph · The Block
Rahil Jain, Co-founder, Chalk Labs. Ex-Goldman Sachs engineer. You talk to the person who builds it.
Get ms365-connect running in your business
Tell us what you want to automate. A founder replies within one working day with a plan, not a pitch deck.
Cite this page
ms365-connect skill. Agent Mart. https://agentmart.dev/skills/sonichi-ms365-connect (last updated 2026-10-24)