Manage Microsoft 365 Planner plans, buckets, and tasks via Microsoft Graph API. Use when creating, listing, updating, or deleting Planner resources. Supports...
---
name: m365-planner
description: Manage Microsoft 365 Planner plans, buckets, and tasks via Microsoft Graph API. Use when creating, listing, updating, or deleting Planner resources. Supports group-based plan management, task assignment, progress tracking, and recurring tasks. Requires Azure AD app registration with Group.Read.All and Tasks.ReadWrite.All permissions.
license: MIT
version: 1.2.3
---
# M365 Planner Skill
Manage Microsoft 365 Planner through Microsoft Graph API.
## What's New in v1.2.3
- ๐ **English Documentation** โ Complete translation for international ClawHub availability
- ๐ง **Portability** โ Env path now uses `os.homedir()` instead of hardcoded paths
- ๐งน **Security Cleanup** โ Full audit for sensitive data (no IDs, names, domains)
- ๐ฆ **ClawHub-ready** โ Tarball created, node_modules excluded
## What's New in v1.2.2
- ๐ง **Portability** โ Env path now uses `os.homedir()` instead of hardcoded `/home/claw/.openclaw/.env`
- ๐งน **Security Cleanup** โ Full audit for sensitive data (no IDs, names, domains)
- ๐ฆ **ClawHub-ready** โ Tarball created, node_modules excluded
## What's New in v1.2.1
- โ
**Generic Scripts** โ No hardcoded Group-IDs or Plan names anymore
- โ
**Command-Line Parameters** โ All scripts accept IDs as arguments
- โ
**List Plans Improved** โ Shows all groups when no ID provided
- โ
**Flexible Cleanup** โ Works with any plans/buckets
- โ
**ClawHub-ready** โ No project-specific data included
## What's New in v1.1.0
- โ
**Node.js Scripts** โ Standalone scripts without `mgc` CLI
- โ
**If-Match Header Support** โ Correct ETag handling for updates/deletes
- โ
**Group-Based API** โ Direct access via M365 Group-ID
- โ
**Recurring Tasks** โ Note about native Planner recurrence feature
- โ
**Cleanup Scripts** โ Automated task cleanup
## Prerequisites
1. Azure AD App Registration (see Setup below)
2. Node.js v18+ with `@microsoft/microsoft-graph-client` and `axios`
3. M365 Group (not Security Group or Distribution List!)
## Quick Start
```bash
# Test connection
node scripts/test-connection.js
# List all plans
node scripts/list_plans.js
# List plans for specific group
node scripts/list_plans.js <group-id>
# Create plan
node scripts/create_plan.js "Project Name" <group-id>
# Create task
node scripts/create_task.js <plan-id> <bucket-id> "Task Title"
# Delete completed tasks
node scripts/cleanup_verlaengerungen.js <group-id> "<plan-name>" "<bucket-name>"
```
## Setup: Azure AD App Registration
### Step 1: Create App Registration
**Azure Portal:**
1. https://portal.azure.com โ Azure Active Directory โ App registrations
2. "New registration"
3. Name: `M365-Planner-Integration`
4. Supported account types: `Accounts in this organizational directory only`
5. Redirect URI: None (Client Credentials Flow)
**Or via Azure CLI:**
```bash
az login
az ad app create --display-name "M365-Planner-Integration" --sign-in-audience "AzureADMyOrg"
```
Note the **Application (client) ID** from the output.
### Step 2: Add API Permissions
**Important:** Use **Application Permissions** (not Delegated)!
**Azure Portal:**
1. App โ API permissions โ Add a permission
2. Microsoft Graph โ Application permissions
3. Add:
- `Group.Read.All` (not Group.ReadWrite.All โ sufficient for Planner)
- `Tasks.ReadWrite.All`
4. **Grant Admin Consent:** Click "Grant admin consent for [Tenant]"!
**Or via Azure CLI:**
```bash
APP_ID="your-app-id"
# Group.Read.All
az ad app permission add \
--id $APP_ID \
--api 00000003-0000-0000-c000-000000000000 \
--api-permissions 5b567253-7703-48e2-861c-caed61531407=Role
# Tasks.ReadWrite.All
az ad app permission add \
--id $APP_ID \
--api 00000003-0000-0000-c000-000000000000 \
--api-permissions bdfbf15f-ee85-495a-99a9-ef9b2abb1dcb=Role
# Admin Consent
az ad app permission admin-consent --id $APP_ID
```
### Step 3: Create Client Secret
**Azure Portal:**
1. App โ Certificates & secrets โ Client secrets โ New client secret
2. Description: `OpenClaw Integration`
3. Expires: 24 months (Maximum)
4. **Copy values immediately!** โ Only shown once
**Or via Azure CLI:**
```bash
az ad app credential reset \
--id $APP_ID \
--append \
--display-name "OpenClaw Integration"
```
### Step 4: Configure Environment
Store credentials in `~/.openclaw/.env`:
```bash
# Microsoft 365 Planner Credentials
M365_CLIENT_ID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
M365_CLIENT_SECRET="your-secret-value"
M365_TENANT_ID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
```
**Secure permissions:**
```bash
chmod 600 ~/.openclaw/.env
```
### Step 5: Test Connection
```bash
node scripts/test-connection.js
```
Expected output:
```
โ
Access Token successfully received!
๐ Test: M365 Groups...
3 groups found:
- My Team โ
M365/Planner-capable
โ
Connection successful!
```
## Important Notes
### M365 Groups vs. Security Groups
**Planner ONLY works with M365 Groups!**
- โ
**M365 Group** โ Has Exchange mailbox, Teams, Planner (recognizable by mail attribute)
- โ **Security Group** โ Only for permissions, no Planner
- โ **Distribution List** โ Only for email distribution, no Planner
**Check groups:**
```bash
node scripts/test-connection.js
```
Shows all groups with status "โ
M365/Planner-capable".
**Create M365 Group (if none exists):**
- Microsoft 365 Admin Center โ Groups โ Add a group
- Or Teams: Create new team (automatically creates M365 Group)
### If-Match Header (ETag)
**All update and delete operations require the `If-Match` header!**
Planner uses Optimistic Concurrency Control. Requests fail without ETag.
**Delete Example:**
```javascript
// Wrong โ
await client.api(`/planner/tasks/${taskId}`).delete();
// Correct โ
const task = await client.api(`/planner/tasks/${taskId}`).get();
await client.api(`/planner/tasks/${taskId}`)
.headers({ 'If-Match': task['@odata.etag'] })
.delete();
```
**Update Example:**
```javascript
const task = await client.api(`/planner/tasks/${taskId}`).get();
await client.api(`/planner/tasks/${taskId}`)
.headers({ 'If-Match': task['@odata.etag'] })
.update({ percentComplete: 50 });
```
### Group-Based API Endpoints
**Do NOT use:**
```
GET /planner/plans โ (requires complex filter)
```
**Use:**
```
GET /groups/{group-id}/planner/plans โ
```
**Example:**
```javascript
const plans = await client.api(`/groups/${groupId}/planner/plans`).get();
```
### Recurring Tasks
**Microsoft Planner supports native recurring tasks!**
In Planner Web UI or Mobile App:
1. Open task
2. Click "Repeat"
3. Choose frequency: Daily, Weekly, Monthly, Yearly, Custom
**Example:**
- "Domain renewal example.com" โ Repeat yearly
- "Check backup" โ Repeat weekly
โ ๏ธ **API Limitation:** The Graph API does not support creating recurring tasks directly.
Recurring tasks must be set up via Planner UI.
## Common Operations
### Plans
| Operation | Script |
|-----------|--------|
| List all plans | `node scripts/list_plans.js` |
| Create plan | `node scripts/create_plan.js <name> <group-id>` |
| Delete plan | `node scripts/delete_plan.js <plan-id>` |
### Buckets
| Operation | Script |
|-----------|--------|
| List buckets | Integrated in `list_plans.js` |
| Create bucket | `node scripts/create_bucket.js <plan-id> <name>` |
| Delete bucket | `node scripts/delete_bucket.js <bucket-id>` |
### Tasks
| Operation | Script |
|-----------|--------|
| List tasks | Integrated in `list_plans.js` |
| Create task | `node scripts/create_task.js <plan-id> <bucket-id> <title>` |
| Update task | `node scripts/update_task.js <task-id> --percent-complete 50` |
| Delete task | `node scripts/delete_task.js <task-id>` |
| Cleanup | `node scripts/cleanup_verlaengerungen.js <group-id> "<plan-name>" "<bucket-name>"` |
## Helper Scripts
### test-connection.js
Tests connection to Microsoft Graph:
- Request access token
- Display tenant information
- List available M365 Groups
- Check Planner capability
```bash
node scripts/test-connection.js
```
### list_plans.js
Shows all plans in an M365 Group with:
- Buckets and their tasks
- Task status (completed/in progress/open)
- Percentage progress indicator
```bash
# Without argument: Shows all available groups
node scripts/list_plans.js
# With Group ID: Shows plans for specific group
node scripts/list_plans.js <group-id>
```
### create_plan.js
Creates a new plan with default buckets:
- To Do
- In Progress
- Done
```bash
node scripts/create_plan.js "Project Alpha" <group-id>
```
### cleanup_verlaengerungen.js
Cleans up completed tasks from a bucket:
- Deletes tasks with 100% progress
- Keeps open tasks
- Correct If-Match header handling
```bash
node scripts/cleanup_verlaengerungen.js <group-id> "<plan-name>" "<bucket-name>"
```
**Example:**
```bash
node scripts/cleanup_verlaengerungen.js abc-123 "My Project" "Completed"
```
## Troubleshooting
### Error: Insufficient privileges
**Cause:** Admin consent not granted
**Solution:**
```bash
az ad app permission admin-consent --id <app-id>
```
Or in Azure Portal: API permissions โ Grant admin consent
### Error: Group not found
**Cause:** Planner only works with M365 Groups
**Solution:**
1. Check if it's an M365 Group (has mail attribute)
2. Security Groups/Distribution Lists don't work
3. Create new M365 Group (Teams or Admin Center)
### Error: The If-Match header must be specified
**Cause:** Update/Delete without ETag
**Solution:**
```javascript
// First get task for ETag
const task = await client.api(`/planner/tasks/${id}`).get();
// Then update/delete with If-Match header
await client.api(`/planner/tasks/${id}`)
.headers({ 'If-Match': task['@odata.etag'] })
.delete();
```
### Error: This entity set must be queried with a filter
**Cause:** `/planner/plans` endpoint requires filter
**Solution:** Use group-based endpoint:
```javascript
// Wrong โ
const plans = await client.api('/planner/plans').get();
// Correct โ
const plans = await client.api(`/groups/${groupId}/planner/plans`).get();
```
### Error: Cannot find module '@microsoft/microsoft-graph-client'
**Cause:** Node.js packages not installed
**Solution:**
```bash
cd ~/.openclaw/workspace/skills/m365-planner
npm install
```
## Dependencies
Install packages locally in skill directory:
```bash
cd ~/.openclaw/workspace/skills/m365-planner
npm install @microsoft/microsoft-graph-client axios
```
## References
- [Planner API Overview](references/planner-api.md)
- [Setup Guide](references/setup-guide.md)
- [Common Patterns](references/common-patterns.md)
- [Microsoft Graph API Docs](https://docs.microsoft.com/en-us/graph/api/overview)
- [Planner REST API Reference](https://docs.microsoft.com/en-us/graph/api/resources/planner-overview)
## Changelog
### v1.2.3 (2026-04-18)
- ๐ **English Documentation** โ Complete translation for international ClawHub availability
- ๐ง **Portability** โ Env path uses `os.homedir()` for cross-system compatibility
- ๐งน **Security Audit** โ No hardcoded IDs, names, or domains
### v1.2.2 (2026-04-18)
- ๐ง **Portability** โ Env path now uses `os.homedir()` instead of hardcoded `/home/claw/.openclaw/.env`
- ๐งน **Security Cleanup** โ Full audit for sensitive data (no IDs, names, domains)
- ๐ฆ **ClawHub-ready** โ Tarball created, node_modules excluded
### v1.2.1 (2026-04-18)
- โ
**Generic Scripts** โ No hardcoded Group-IDs or Plan names anymore
- โ
**Command-Line Parameters** โ All scripts accept IDs as arguments
- โ
**List Plans Improved** โ Shows all groups when no ID provided
- โ
**Flexible Cleanup** โ Works with any plans/buckets
- โ
**ClawHub-ready** โ No project-specific data included
### v1.1.0 (2026-04-17)
- โ
Node.js Scripts instead of mgc CLI
- โ
If-Match Header Support for updates/deletes
- โ
Group-based API Endpoints
- โ
Test-Connection Script with M365 Group Detection
- โ
List Plans Script with Bucket/Task overview
- โ
Cleanup Script for completed tasks
- โ
Documentation for recurring tasks (native Planner feature)
- โ
Troubleshooting Section expanded
### v1.0.0 (2023-01-19)
- Initial version with mgc CLI
- Azure AD Setup Guide
- Basic CRUD operations
don't have the plugin yet? install it then click "run inline in claude" again.