m365-agent-cli 1.2.0 → 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,916 +1,916 @@
1
- # m365-agent-cli
2
-
3
- > **Credits:** This repository is heavily extended from the original project by [foeken/clippy](https://github.com/foeken/clippy).
4
-
5
- A powerful command-line interface for Microsoft 365 using Exchange Web Services (EWS) and Microsoft Graph. Manage your calendar, email, OneDrive files, Microsoft Planner tasks, and SharePoint Sites directly from the terminal.
6
-
7
- ## The Ultimate AI Personal Assistant (PA)
8
-
9
- The Personal Assistant (PA) playbook and skills have been moved to their own dedicated repository.
10
-
11
- To use this tool as a highly effective Personal Assistant within OpenClaw, please visit the **[openclaw-personal-assistant](https://github.com/markus-lassfolk/openclaw-personal-assistant)** repository for the Master Guide, ecosystem requirements, and skill installation instructions.
12
-
13
- ---
14
-
15
- ## Installation
16
-
17
- ```bash
18
- # Clone the repository
19
- git clone https://github.com/markus-lassfolk/m365-agent-cli.git
20
- cd m365-agent-cli
21
-
22
- # Install dependencies
23
- bun install
24
- # Install OpenClaw Skills (optional, gives your AI agent superpowers)
25
- mkdir -p ~/.openclaw/workspace/skills
26
- cp -r skills/* ~/.openclaw/workspace/skills/
27
-
28
-
29
- # Run directly
30
- bun run src/cli.ts <command>
31
-
32
- # Or link globally
33
- bun link
34
- m365-agent-cli <command>
35
- ```
36
-
37
- ### Published package (npm)
38
-
39
- ```bash
40
- npm install -g m365-agent-cli
41
- m365-agent-cli update
42
- ```
43
-
44
- `update` checks the npm registry and runs `npm install -g m365-agent-cli@latest` (or `bun install -g` when you run the CLI with Bun). Maintainers: versioning, tags, and npm publish are documented in [docs/RELEASE.md](docs/RELEASE.md).
45
-
46
- ## Authentication
47
-
48
- **Need help setting up the Azure AD App?** Follow our [Automated Entra ID App Setup Guide](docs/ENTRA_SETUP.md) for bash and PowerShell scripts that configure the exact permissions you need in seconds.
49
-
50
- **EWS retirement:** Microsoft is phasing out EWS for Exchange Online in favor of Microsoft Graph. Track migration work in [docs/EWS_TO_GRAPH_MIGRATION_EPIC.md](docs/EWS_TO_GRAPH_MIGRATION_EPIC.md) (phased plan, inventory, Graph-primary + EWS-fallback strategy).
51
-
52
- **Optional error reporting:** To receive CLI crashes and unhandled errors in [GlitchTip](https://glitchtip.com/) (Sentry-compatible), set **`GLITCHTIP_DSN`** (or **`SENTRY_DSN`**) in your environment. See [docs/GLITCHTIP.md](docs/GLITCHTIP.md).
53
-
54
- m365-agent-cli uses OAuth2 with a refresh token to authenticate against Microsoft 365. You need an Azure AD app registration.
55
-
56
- ### Setup
57
-
58
- If you used the setup scripts from `docs/ENTRA_SETUP.md`, your `EWS_CLIENT_ID` is already appended to your `~/.config/m365-agent-cli/.env` file.
59
-
60
- The easiest way to obtain your refresh tokens is to run the interactive login command:
61
-
62
- ```bash
63
- m365-agent-cli login
64
- ```
65
-
66
- This will initiate the Microsoft Device Code flow and automatically save `EWS_REFRESH_TOKEN` and `GRAPH_REFRESH_TOKEN` into your `~/.config/m365-agent-cli/.env` file upon successful authentication.
67
-
68
- Alternatively, you can manually create a `~/.config/m365-agent-cli/.env` file (or set environment variables):
69
-
70
- ```bash
71
- EWS_CLIENT_ID=your-azure-app-client-id
72
- EWS_REFRESH_TOKEN=your-refresh-token
73
- EWS_USERNAME=your@email.com
74
- EWS_ENDPOINT=https://outlook.office365.com/EWS/Exchange.asmx
75
- EWS_TENANT_ID=common # or your tenant ID
76
- ```
77
-
78
- ### Shared Mailbox Access
79
-
80
- To send from or access a shared mailbox, set the default in your env:
81
-
82
- ```bash
83
- EWS_TARGET_MAILBOX=shared@company.com
84
- ```
85
-
86
- Or pass `--mailbox` per-command (see examples below).
87
-
88
- ### How It Works
89
-
90
- 1. m365-agent-cli uses the refresh token to obtain a short-lived access token via Microsoft's OAuth2 endpoint
91
- 2. Access tokens are cached under `~/.config/m365-agent-cli/`:
92
- - **EWS:** `token-cache-{identity}.json` (default identity: `default`)
93
- - **Microsoft Graph:** `graph-token-cache-{identity}.json` (same identity name; default `default`)
94
- - A legacy `graph-token-cache.json` (no identity suffix) is migrated once to `graph-token-cache-default.json` when present.
95
- Tokens are refreshed automatically when expired.
96
- 3. Microsoft may rotate the refresh token on each use — the latest one is cached automatically in the same directory
97
-
98
- ### Verify Authentication
99
-
100
- ```bash
101
- # Check who you're logged in as
102
- m365-agent-cli whoami
103
-
104
- # Verify your Graph API token scopes
105
- m365-agent-cli verify-token
106
- ```
107
-
108
- ---
109
-
110
- ## Options: root vs per-command
111
-
112
- `m365-agent-cli --help` shows only options registered on the **root** program, currently:
113
-
114
- ```bash
115
- --read-only # Run in read-only mode, blocking mutating operations
116
- --version, -V # CLI version (semver from package)
117
- ```
118
-
119
- Many **subcommands** accept their own flags. Common patterns (not every command has every flag—use `m365-agent-cli <command> --help`):
120
-
121
- ```bash
122
- --json # Machine-readable output (where supported)
123
- --token <token> # Use a specific access token (overrides cache)
124
- --identity <name> # Token cache profile (default: default). Selects EWS and Graph cache files for that name.
125
- --user <email> # Graph delegation: target another user/mailbox (supported commands only; needs permissions)
126
- ```
127
-
128
- **EWS shared mailbox:** use `--mailbox <email>` on calendar, mail, send, folders, drafts, respond, findtime, delegates, auto-reply, and related flows.
129
-
130
- ### Read-Only Mode
131
-
132
- When read-only mode is on (`READ_ONLY_MODE=true` in env / `~/.config/m365-agent-cli/.env`, or `--read-only` on the **root** command), the CLI calls `checkReadOnly()` before the listed actions and exits with an error **before** the mutating request is sent.
133
-
134
- The table below matches **`checkReadOnly` in the source** (search the repo for `checkReadOnly(` to verify after changes). Anything **not** listed here is either read-only or not wired to read-only yet.
135
-
136
- | Command | Blocked actions (read-only on) |
137
- | --- | --- |
138
- | `create-event` | Entire command |
139
- | `update-event` | Entire command |
140
- | `delete-event` | Entire command |
141
- | `forward-event` | Entire command |
142
- | `counter` | Entire command |
143
- | `respond` | `accept`, `decline`, `tentative` (not `respond list`) |
144
- | `send` | Entire command |
145
- | `mail` | Mutating flags only: `--flag`, `--unflag`, `--mark-read`, `--mark-unread`, `--complete`, `--sensitivity`, `--move`, `--reply`, `--reply-all`, `--forward`, `--set-categories`, `--clear-categories` (listing, `--read`, `--download` stay allowed) |
146
- | `drafts` | `--create`, `--edit`, `--send`, `--delete` (plain list/read allowed) |
147
- | `folders` | `--create`, `--rename` (with `--to`), `--delete` (listing folders allowed) |
148
- | `files` | `upload`, `upload-large`, `delete`, `share`, `restore`, `checkin` |
149
- | `planner` | `create-task`, `update-task`, `delete-task`, `create-plan` (`--group` or beta `--roster`), `update-plan`, `delete-plan`, `create-bucket`, `update-bucket`, `delete-bucket`, `list-user-tasks`, `list-user-plans`, `update-task-details`, `update-plan-details`, `add-checklist-item`, `update-checklist-item`, `remove-checklist-item`, `add-reference`, `remove-reference`, `update-task-board`, `add-favorite`, `remove-favorite`, `roster` (beta: `create`, `get`, `list-members`, `add-member`, `remove-member`) |
150
- | `sharepoint` / `sp` | `create-item`, `update-item` |
151
- | `pages` | `update`, `publish` |
152
- | `rules` | `create`, `update`, `delete` |
153
- | `todo` | `create`, `update`, `complete`, `delete`, `add-checklist`, `update-checklist`, `delete-checklist`, `get-checklist-item`, `create-list`, `update-list`, `delete-list`, `add-attachment`, `get-attachment`, `download-attachment`, `delete-attachment`, `add-reference-attachment`, `add-linked-resource`, `remove-linked-resource`, `upload-attachment-large`, `linked-resource` (`create`, `update`, `delete`), `extension` (`set`, `update`, `delete`), `list-extension` (`set`, `update`, `delete`) |
154
- | `subscribe` | Creating a subscription; `subscribe cancel <id>` |
155
- | `delegates` | `add`, `update`, `remove` |
156
- | `oof` | Write path only (when `--status`, `--internal-message`, `--external-message`, `--start`, or `--end` is used to change settings) |
157
- | `auto-reply` | Entire command (EWS auto-reply rules) |
158
- | `outlook-categories` | `create`, `update`, `delete` (not `list`) |
159
- | `outlook-graph` | `create-folder`, `update-folder`, `delete-folder`, `send-mail`, `patch-message`, `delete-message`, `move-message`, `copy-message`, `create-reply`, `create-reply-all`, `create-forward`, `send-message`, `create-contact`, `update-contact`, `delete-contact` |
160
- | `graph-calendar` | `accept`, `decline`, `tentative` |
161
-
162
- **Intentionally not gated** (no `checkReadOnly` today): read/query helpers such as `schedule`, `suggest`, `findtime`, `calendar`, `graph-calendar list-calendars` / `get-calendar` / `list-view` / `get-event`, `outlook-graph list-mail` / `list-messages` / `list-message-attachments` / `get-message-attachment` / `download-message-attachment` / `get-message` / `list-folders` / `list-contacts` / `get-contact` / `get-folder`, `subscriptions list`, `rules list` / `rules get`, `todo` list-only usage, **`outlook-categories list`** (mutating `outlook-categories create|update|delete` **are** gated), `files` list/search/meta/download/convert/analytics/versions, etc. Those calls do not use the guard in code; if a new subcommand adds writes, it should call `checkReadOnly` and this table should be updated.
163
-
164
- You can enable Read-Only mode in two ways:
165
-
166
- 1. **Global flag**: Pass **`--read-only` immediately after** `m365-agent-cli` (before the subcommand). Commander treats this as a root option; placing it after the subcommand will not enable read-only mode.
167
-
168
- ```bash
169
- m365-agent-cli --read-only create-event "Test" 09:00 10:00
170
- # Error: Command blocked. The CLI is running in read-only mode.
171
- ```
172
-
173
- 2. **Environment variable**: Set `READ_ONLY_MODE=true` in your environment or `~/.config/m365-agent-cli/.env` file.
174
-
175
- ```bash
176
- export READ_ONLY_MODE=true
177
- m365-agent-cli planner update-task <taskId> --title "New"
178
- # Error: Command blocked. The CLI is running in read-only mode.
179
- ```
180
-
181
- ---
182
-
183
- ## Calendar Commands
184
-
185
- ### View Calendar
186
-
187
- ```bash
188
- # Today's events
189
- m365-agent-cli calendar
190
-
191
- # Specific day
192
- m365-agent-cli calendar tomorrow
193
- m365-agent-cli calendar monday
194
- m365-agent-cli calendar 2024-02-15
195
-
196
- # Date ranges
197
- m365-agent-cli calendar monday friday
198
- m365-agent-cli calendar 2024-02-15 2024-02-20
199
-
200
- # Week views
201
- m365-agent-cli calendar week # This week (Mon-Sun)
202
- m365-agent-cli calendar lastweek
203
- m365-agent-cli calendar nextweek
204
-
205
- # Include details (attendees, body preview, categories)
206
- m365-agent-cli calendar -v
207
- m365-agent-cli calendar week --verbose
208
-
209
- # Shared mailbox calendar
210
- m365-agent-cli calendar --mailbox shared@company.com
211
- m365-agent-cli calendar nextweek --mailbox shared@company.com
212
- ```
213
-
214
- ### Calendar: rolling ranges and business (weekday) windows
215
-
216
- Besides a single day or `start end` date range, **`calendar`** supports **one** of these span modes (not combinable with each other or with an `[end]` argument; not with `week` / `lastweek` / `nextweek`):
217
-
218
- ```bash
219
- # Next 5 calendar days starting today (includes today)
220
- m365-agent-cli calendar today --days 5
221
-
222
- # Previous 3 calendar days ending on today
223
- m365-agent-cli calendar today --previous-days 3
224
-
225
- # Next 10 weekdays (Mon–Fri) starting from the anchor day
226
- # (if anchor is Sat/Sun, counting starts from the next Monday)
227
- m365-agent-cli calendar today --business-days 10
228
-
229
- # Typo-tolerant alias for --business-days
230
- m365-agent-cli calendar today --busness-days 5
231
-
232
- # 5 weekdays backward ending on or before the anchor
233
- m365-agent-cli calendar today --previous-business-days 5
234
- ```
235
-
236
- ### Create Events
237
-
238
- ```bash
239
- # Basic event
240
- m365-agent-cli create-event "Team Standup" 09:00 09:30
241
-
242
- # With options
243
- m365-agent-cli create-event "Project Review" 14:00 15:00 \
244
- --day tomorrow \
245
- --description "Q1 review meeting" \
246
- --attendees "alice@company.com,bob@company.com" \
247
- --teams \
248
- --room "Conference Room A"
249
-
250
- # Specify a timezone explicitly
251
- m365-agent-cli create-event "Global Sync" 09:00 10:00 --timezone "Pacific Standard Time"
252
-
253
- # All-day event with category and sensitivity
254
- m365-agent-cli create-event "Holiday" --all-day --category "Personal" --sensitivity private
255
-
256
- # Find an available room automatically
257
- m365-agent-cli create-event "Workshop" 10:00 12:00 --find-room
258
-
259
- # List available rooms
260
- m365-agent-cli create-event "x" 10:00 11:00 --list-rooms
261
-
262
- # Create in shared mailbox calendar
263
- m365-agent-cli create-event "Team Standup" 09:00 09:30 --mailbox shared@company.com
264
- ```
265
-
266
- ### Recurring Events
267
-
268
- ```bash
269
- # Daily standup
270
- m365-agent-cli create-event "Daily Standup" 09:00 09:15 --repeat daily
271
-
272
- # Weekly on specific days
273
- m365-agent-cli create-event "Team Sync" 14:00 15:00 \
274
- --repeat weekly \
275
- --days mon,wed,fri
276
-
277
- # Monthly, 10 occurrences
278
- m365-agent-cli create-event "Monthly Review" 10:00 11:00 \
279
- --repeat monthly \
280
- --count 10
281
-
282
- # Every 2 weeks until a date
283
- m365-agent-cli create-event "Sprint Planning" 09:00 11:00 \
284
- --repeat weekly \
285
- --every 2 \
286
- --until 2024-12-31
287
- ```
288
-
289
- ### Update Events
290
-
291
- ```bash
292
- # List today's events
293
- m365-agent-cli update-event
294
-
295
- # Update by event ID
296
- m365-agent-cli update-event --id <eventId> --title "New Title"
297
- m365-agent-cli update-event --id <eventId> --start 10:00 --end 11:00
298
- m365-agent-cli update-event --id <eventId> --add-attendee "new@company.com"
299
- m365-agent-cli update-event --id <eventId> --room "Room B"
300
- m365-agent-cli update-event --id <eventId> --location "Off-site"
301
- m365-agent-cli update-event --id <eventId> --teams # Add Teams meeting
302
- m365-agent-cli update-event --id <eventId> --no-teams # Remove Teams meeting
303
- m365-agent-cli update-event --id <eventId> --all-day # Make all-day
304
- m365-agent-cli update-event --id <eventId> --sensitivity private
305
- m365-agent-cli update-event --id <eventId> --category "Project A" --category Review
306
- m365-agent-cli update-event --id <eventId> --clear-categories
307
-
308
- # Show events from a specific day
309
- m365-agent-cli update-event --day tomorrow
310
-
311
- # Update event in shared mailbox calendar
312
- m365-agent-cli update-event --id <eventId> --title "Updated Title" --mailbox shared@company.com
313
- ```
314
-
315
- ### Delete/Cancel Events
316
-
317
- ```bash
318
- # List your events
319
- m365-agent-cli delete-event
320
-
321
- # Delete event by ID
322
- m365-agent-cli delete-event --id <eventId>
323
-
324
- # With cancellation message
325
- m365-agent-cli delete-event --id <eventId> --message "Sorry, need to reschedule"
326
-
327
- # Force delete without sending cancellation
328
- m365-agent-cli delete-event --id <eventId> --force-delete
329
-
330
- # Search for events by title
331
- m365-agent-cli delete-event --search "standup"
332
-
333
- # Delete event in shared mailbox calendar
334
- m365-agent-cli delete-event --id <eventId> --mailbox shared@company.com
335
- ```
336
-
337
- ### Respond to Invitations
338
-
339
- ```bash
340
- # List events needing response
341
- m365-agent-cli respond
342
-
343
- # Accept/decline/tentative by event ID
344
- m365-agent-cli respond accept --id <eventId>
345
- m365-agent-cli respond decline --id <eventId> --comment "Conflict with another meeting"
346
- m365-agent-cli respond tentative --id <eventId>
347
-
348
- # Don't send response to organizer
349
- m365-agent-cli respond accept --id <eventId> --no-notify
350
-
351
- # Only show required invitations (exclude optional)
352
- m365-agent-cli respond list --only-required
353
-
354
- # Respond to invitation in shared mailbox calendar
355
- m365-agent-cli respond accept --id <eventId> --mailbox shared@company.com
356
- ```
357
-
358
- ### Find Meeting Times
359
-
360
- ```bash
361
- # Find free slots next week for yourself and others
362
- m365-agent-cli findtime nextweek alice@company.com bob@company.com
363
-
364
- # Specific date range (keywords or YYYY-MM-DD)
365
- m365-agent-cli findtime monday friday alice@company.com
366
- m365-agent-cli findtime 2026-04-01 2026-04-03 alice@company.com
367
-
368
- # Custom duration and working hours
369
- m365-agent-cli findtime nextweek alice@company.com --duration 60 --start 10 --end 16
370
-
371
- # Only check specified people (exclude yourself from availability check)
372
- m365-agent-cli findtime nextweek alice@company.com --solo
373
- ```
374
-
375
- ---
376
-
377
- ## Email Commands
378
-
379
- ### List & Read Email
380
-
381
- ```bash
382
- # Inbox (default)
383
- m365-agent-cli mail
384
-
385
- # Other folders
386
- m365-agent-cli mail sent
387
- m365-agent-cli mail drafts
388
- m365-agent-cli mail deleted
389
- m365-agent-cli mail archive
390
-
391
- # Pagination
392
- m365-agent-cli mail -n 20 # Show 20 emails
393
- m365-agent-cli mail -p 2 # Page 2
394
-
395
- # Filters
396
- m365-agent-cli mail --unread # Only unread
397
- m365-agent-cli mail --flagged # Only flagged
398
- m365-agent-cli mail -s "invoice" # Search
399
-
400
- # Read an email
401
- m365-agent-cli mail -r 1 # Read email #1
402
-
403
- # Download attachments
404
- m365-agent-cli mail -d 3 # Download from email #3
405
- m365-agent-cli mail -d 3 -o ~/Downloads
406
-
407
- # Shared mailbox inbox
408
- m365-agent-cli mail --mailbox shared@company.com
409
- ```
410
-
411
- ### Categories on mail (Outlook)
412
-
413
- Messages use **category name strings** (same as Outlook). **Colors** come from the mailbox **master category list**, not from a separate field per message. List master categories (names + preset color) via Graph:
414
-
415
- ```bash
416
- m365-agent-cli outlook-categories list
417
- m365-agent-cli outlook-categories list --user colleague@company.com # delegation, if permitted
418
- ```
419
-
420
- Manage the master list (names + **preset** colors `preset0`..`preset24`; requires Graph **`MailboxSettings.ReadWrite`**):
421
-
422
- ```bash
423
- m365-agent-cli outlook-categories create --name "Project A" --color preset9
424
- m365-agent-cli outlook-categories update --id <categoryGuid> --name "Project A (new)" --color preset12
425
- m365-agent-cli outlook-categories delete --id <categoryGuid>
426
- ```
427
-
428
- Set or clear categories on a message **by ID** from list/read output:
429
-
430
- ```bash
431
- m365-agent-cli mail --set-categories <messageId> --category Work --category "Follow up"
432
- m365-agent-cli mail --clear-categories <messageId>
433
- ```
434
-
435
- Category names appear in **`mail`** list (text and JSON) and when reading a message (`-r`).
436
-
437
- ### Send Email
438
-
439
- ```bash
440
- # Simple email (--body is optional)
441
- m365-agent-cli send \
442
- --to "recipient@example.com" \
443
- --subject "Hello"
444
-
445
- # With body
446
- m365-agent-cli send \
447
- --to "recipient@example.com" \
448
- --subject "Hello" \
449
- --body "This is the message body"
450
-
451
- # Multiple recipients, CC, BCC
452
- m365-agent-cli send \
453
- --to "alice@example.com,bob@example.com" \
454
- --cc "manager@example.com" \
455
- --bcc "archive@example.com" \
456
- --subject "Team Update" \
457
- --body "..."
458
-
459
- # With markdown formatting
460
- m365-agent-cli send \
461
- --to "user@example.com" \
462
- --subject "Update" \
463
- --body "**Bold text** and a [link](https://example.com)" \
464
- --markdown
465
-
466
- # With attachments
467
- m365-agent-cli send \
468
- --to "user@example.com" \
469
- --subject "Report" \
470
- --body "Please find attached." \
471
- --attach "report.pdf,data.xlsx"
472
-
473
- # Send from shared mailbox
474
- m365-agent-cli send \
475
- --to "recipient@example.com" \
476
- --subject "From shared mailbox" \
477
- --body "..." \
478
- --mailbox shared@company.com
479
- ```
480
-
481
- ### Reply & Forward
482
-
483
- ```bash
484
- # Reply to an email
485
- m365-agent-cli mail --reply 1 --message "Thanks for your email!"
486
-
487
- # Reply all
488
- m365-agent-cli mail --reply-all 1 --message "Thanks everyone!"
489
-
490
- # Reply with markdown
491
- m365-agent-cli mail --reply 1 --message "**Got it!** Will do." --markdown
492
-
493
- # Save reply as draft instead of sending
494
- m365-agent-cli mail --reply 1 --message "Draft reply" --draft
495
-
496
- # Forward an email (uses --to-addr, not --to)
497
- m365-agent-cli mail --forward 1 --to-addr "colleague@example.com"
498
- m365-agent-cli mail --forward 1 --to-addr "a@example.com,b@example.com" --message "FYI"
499
-
500
- # Reply or forward with file/link attachments and/or Outlook categories (draft workflow)
501
- m365-agent-cli mail --reply <messageId> --message "See attached" --attach "report.pdf"
502
- m365-agent-cli mail --forward <messageId> --to-addr "boss@company.com" --message "FYI" --attach-link "https://contoso.com/doc"
503
- m365-agent-cli mail --reply <messageId> --message "Tagged" --with-category Work --with-category "Follow up"
504
-
505
- # Forward or reply as draft (optionally with --attach / --attach-link / --with-category)
506
- m365-agent-cli mail --forward <messageId> --to-addr "a@b.com" --draft
507
- m365-agent-cli mail --reply <messageId> --message "Will edit later" --draft
508
-
509
- # Reply/forward from shared mailbox
510
- m365-agent-cli mail --reply 1 --message "..." --mailbox shared@company.com
511
- m365-agent-cli mail --reply-all 1 --message "..." --mailbox shared@company.com
512
- m365-agent-cli mail --forward 1 --to-addr "colleague@example.com" --mailbox shared@company.com
513
- ```
514
-
515
- ### Email Actions
516
-
517
- ```bash
518
- # Mark as read/unread
519
- m365-agent-cli mail --mark-read 1
520
- m365-agent-cli mail --mark-unread 2
521
-
522
- # Flag emails
523
- m365-agent-cli mail --flag 1
524
- m365-agent-cli mail --unflag 2
525
- m365-agent-cli mail --complete 3 # Mark flag as complete
526
- m365-agent-cli mail --flag 1 --start-date 2026-05-01 --due 2026-05-05
527
-
528
- # Set sensitivity
529
- m365-agent-cli mail --sensitivity <emailId> --level confidential
530
-
531
- # Move to folder (--to here is for folder destination, not email recipient)
532
- m365-agent-cli mail --move 1 --to archive
533
- m365-agent-cli mail --move 2 --to deleted
534
- m365-agent-cli mail --move 3 --to "My Custom Folder"
535
- ```
536
-
537
- See **Categories on mail** above for `--set-categories` / `--clear-categories`.
538
-
539
- ### Manage Drafts
540
-
541
- ```bash
542
- # List drafts
543
- m365-agent-cli drafts
544
-
545
- # Read a draft
546
- m365-agent-cli drafts -r 1
547
-
548
- # Create a draft
549
- m365-agent-cli drafts --create \
550
- --to "recipient@example.com" \
551
- --subject "Draft Email" \
552
- --body "Work in progress..."
553
-
554
- # Categories on drafts (same name strings as Outlook; see outlook-categories list)
555
- m365-agent-cli drafts --create --to "a@b.com" --subject "Hi" --body "..." --category Work
556
- m365-agent-cli drafts --edit <draftId> --category Review --category "Follow up"
557
- m365-agent-cli drafts --edit <draftId> --clear-categories
558
-
559
- # Create with attachment
560
- m365-agent-cli drafts --create \
561
- --to "user@example.com" \
562
- --subject "Report" \
563
- --body "See attached" \
564
- --attach "report.pdf"
565
-
566
- # Edit a draft
567
- m365-agent-cli drafts --edit 1 --body "Updated content"
568
- m365-agent-cli drafts --edit 1 --subject "New Subject"
569
-
570
- # Send a draft
571
- m365-agent-cli drafts --send 1
572
-
573
- # Delete a draft
574
- m365-agent-cli drafts --delete 1
575
- ```
576
-
577
- ### Manage Folders
578
-
579
- ```bash
580
- # List all folders
581
- m365-agent-cli folders
582
-
583
- # Create a folder
584
- m365-agent-cli folders --create "Projects"
585
-
586
- # Rename a folder
587
- m365-agent-cli folders --rename "Projects" --to "Active Projects"
588
-
589
- # Delete a folder
590
- m365-agent-cli folders --delete "Old Folder"
591
- ```
592
-
593
- ---
594
-
595
- ## OneDrive / Office Online Commands
596
-
597
- ### List, Search, and Inspect Files
598
-
599
- ```bash
600
- # List root files
601
- m365-agent-cli files list
602
-
603
- # List a folder by item ID
604
- m365-agent-cli files list --folder <folderId>
605
-
606
- # Search OneDrive
607
- m365-agent-cli files search "budget 2026"
608
-
609
- # Inspect metadata
610
- m365-agent-cli files meta <fileId>
611
-
612
- # Get file analytics
613
- m365-agent-cli files analytics <fileId>
614
-
615
- # File versions
616
- m365-agent-cli files versions <fileId>
617
- m365-agent-cli files restore <fileId> <versionId>
618
- ```
619
-
620
- ### Upload, Download, Delete, and Share
621
-
622
- ```bash
623
- # Upload a normal file (<=250MB)
624
- m365-agent-cli files upload ./report.docx
625
-
626
- # Upload to a specific folder
627
- m365-agent-cli files upload ./report.docx --folder <folderId>
628
-
629
- # Upload a large file (>250MB, up to 4GB via chunked upload)
630
- m365-agent-cli files upload-large ./video.mp4
631
- m365-agent-cli files upload-large ./backup.zip --folder <folderId>
632
-
633
- # Download a file
634
- m365-agent-cli files download <fileId>
635
- m365-agent-cli files download <fileId> --out ./local-copy.docx
636
-
637
- # Convert and download (e.g., to PDF)
638
- m365-agent-cli files convert <fileId> --format pdf --out ./converted.pdf
639
-
640
- # Delete a file
641
- m365-agent-cli files delete <fileId>
642
-
643
- # Create a share link
644
- m365-agent-cli files share <fileId> --type view --scope org
645
- m365-agent-cli files share <fileId> --type edit --scope anonymous
646
- ```
647
-
648
- ### Collaborative Editing via Office Online
649
-
650
- Microsoft Graph cannot join or control a live Office Online editing session. What m365-agent-cli can do is prepare the handoff properly:
651
-
652
- 1. Find the document in OneDrive
653
- 2. Create an organization-scoped edit link (or anonymous)
654
- 3. Return the Office Online URL (`webUrl`) for the user to open
655
- 4. Optionally checkout the file first for exclusive editing workflows
656
-
657
- ```bash
658
- # Search for the document first
659
- m365-agent-cli files search "budget 2026.xlsx"
660
-
661
- # Create a collaboration handoff for Word/Excel/PowerPoint Online
662
- m365-agent-cli files share <fileId> --collab
663
-
664
- # Same, but checkout the file first (exclusive edit lock)
665
- m365-agent-cli files share <fileId> --collab --lock
666
-
667
- # When the exclusive-edit workflow is done, check the file back in
668
- m365-agent-cli files checkin <fileId> --comment "Updated Q1 numbers"
669
- ```
670
-
671
- **Supported collaboration file types:** `.docx`, `.xlsx`, `.pptx`
672
-
673
- Legacy Office formats such as `.doc`, `.xls`, and `.ppt` must be converted first.
674
-
675
- **Important clarification:**
676
-
677
- - m365-agent-cli does **not** participate in the real-time editing session
678
- - Office Online handles the actual co-authoring once the user opens the returned URL
679
- - m365-agent-cli handles the file lifecycle around that workflow
680
-
681
- ---
682
-
683
- ## Microsoft Planner Commands
684
-
685
- Manage tasks and plans in Microsoft Planner. Planner uses **six label slots** per task (`category1`..`category6`); **display names** for those slots are defined in **plan details**. The CLI accepts slots as **`1`..`6`** or **`category1`..`category6`**.
686
-
687
- ```bash
688
- # List tasks assigned to you (label names shown when plan details are available)
689
- m365-agent-cli planner list-my-tasks
690
-
691
- # List your plans
692
- m365-agent-cli planner list-plans
693
- m365-agent-cli planner list-plans -g <groupId>
694
-
695
- # List another user's Planner tasks/plans (Graph may return 403 depending on tenant/token)
696
- m365-agent-cli planner list-user-tasks --user <azureAdObjectId>
697
- m365-agent-cli planner list-user-plans --user <azureAdObjectId>
698
-
699
- # Beta: roster container (create roster → add members → create-plan --roster <rosterId>)
700
- m365-agent-cli planner roster create
701
- m365-agent-cli planner roster add-member -r <rosterId> --user <userId>
702
- m365-agent-cli planner create-plan --roster <rosterId> -t "Roster plan"
703
-
704
- # View plan structure
705
- m365-agent-cli planner list-buckets --plan <planId>
706
- m365-agent-cli planner list-tasks --plan <planId>
707
-
708
- # Create and update tasks
709
- m365-agent-cli planner create-task --plan <planId> --title "New Task" -b <bucketId>
710
- m365-agent-cli planner create-task --plan <planId> --title "Labeled" --label 1 --label category3
711
-
712
- m365-agent-cli planner update-task -i <taskId> --title "Updated Task" --percent 50 --assign <userId>
713
- m365-agent-cli planner update-task -i <taskId> --label 2 --unlabel 1
714
- m365-agent-cli planner update-task -i <taskId> --clear-labels
715
- ```
716
-
717
- ---
718
-
719
- ## Microsoft To Do
720
-
721
- To Do tasks support **string categories** (independent of Outlook mailbox master categories).
722
-
723
- ```bash
724
- # Create with categories
725
- m365-agent-cli todo create -t "Buy milk" --category Shopping --category Errands
726
-
727
- # Update fields including categories (see: m365-agent-cli todo update --help)
728
- m365-agent-cli todo update -l Tasks -t <taskId> --category Work --category Urgent
729
- m365-agent-cli todo update -l Tasks -t <taskId> --clear-categories
730
-
731
- # One checklist row (Graph GET checklistItems/{id}); download file attachment bytes ($value)
732
- m365-agent-cli todo get-checklist-item -l Tasks -t <taskId> -c <checklistItemId>
733
- m365-agent-cli todo download-attachment -l Tasks -t <taskId> -a <attachmentId> -o ./file.bin
734
- ```
735
-
736
- ## Outlook Graph REST (`outlook-graph`)
737
-
738
- Microsoft Graph endpoints for **mail folders**, **messages** (folder or mailbox-wide list, **sendMail**, PATCH, move, copy, attachments, reply/reply-all/forward drafts + send), and **personal contacts** (complements EWS **`mail`** / **`folders`**). Requires appropriate **Mail.** and **Contacts.** scopes.
739
-
740
- ```bash
741
- m365-agent-cli outlook-graph list-folders
742
- m365-agent-cli outlook-graph list-messages --folder inbox --top 25
743
- m365-agent-cli outlook-graph list-mail --top 25
744
- m365-agent-cli outlook-graph list-mail --search "quarterly report" --all
745
- m365-agent-cli outlook-graph get-message -i <messageId>
746
- m365-agent-cli outlook-graph send-mail --json-file mail.json
747
- m365-agent-cli outlook-graph patch-message <id> --json-file patch.json
748
- m365-agent-cli outlook-graph list-message-attachments -i <messageId>
749
- m365-agent-cli outlook-graph download-message-attachment -i <id> -a <attId> -o ./file.bin
750
- m365-agent-cli outlook-graph create-reply <messageId>
751
- m365-agent-cli outlook-graph send-message <draftId>
752
- m365-agent-cli outlook-graph list-contacts
753
- ```
754
-
755
- ## Graph calendar REST (`graph-calendar`)
756
-
757
- Microsoft Graph endpoints for **calendars**, **calendarView** (time-range queries), **single events**, and **invitation responses** (`accept` / `decline` / `tentative`). Complements EWS **`calendar`** and **`respond`** when you need Graph IDs or REST-only flows. Requires **`Calendars.Read`** (read) or **`Calendars.ReadWrite`** (writes / responses).
758
-
759
- ```bash
760
- m365-agent-cli graph-calendar list-calendars
761
- m365-agent-cli graph-calendar list-view --start 2026-04-01T00:00:00Z --end 2026-04-08T00:00:00Z
762
- m365-agent-cli graph-calendar list-view --start ... --end ... --calendar <calendarId>
763
- m365-agent-cli graph-calendar get-event <eventId>
764
- m365-agent-cli graph-calendar accept <eventId> --comment "Will attend"
765
- ```
766
-
767
- ## SharePoint Commands
768
-
769
- Manage SharePoint lists and Site Pages.
770
-
771
- ### SharePoint Lists (`m365-agent-cli sharepoint` or `m365-agent-cli sp`)
772
-
773
- ```bash
774
- # List all SharePoint lists in a site
775
- m365-agent-cli sp lists --site-id <siteId>
776
-
777
- # Get items from a list
778
- m365-agent-cli sp items --site-id <siteId> --list-id <listId>
779
-
780
- # Create and update items
781
- m365-agent-cli sp create-item --site-id <siteId> --list-id <listId> --fields '{"Title": "New Item"}'
782
- m365-agent-cli sp update-item --site-id <siteId> --list-id <listId> --item-id <itemId> --fields '{"Title": "Updated Item"}'
783
- ```
784
-
785
- ### SharePoint Site Pages (`m365-agent-cli pages`)
786
-
787
- ```bash
788
- # List site pages
789
- m365-agent-cli pages list <siteId>
790
-
791
- # Get a site page
792
- m365-agent-cli pages get <siteId> <pageId>
793
-
794
- # Update a site page
795
- m365-agent-cli pages update <siteId> <pageId> --title "New Title" --name "new-name.aspx"
796
-
797
- # Publish a site page
798
- m365-agent-cli pages publish <siteId> <pageId>
799
- ```
800
-
801
- ---
802
-
803
- ## People & Room Search
804
-
805
- ```bash
806
- # Search for people
807
- m365-agent-cli find "john"
808
-
809
- # Search for rooms
810
- m365-agent-cli find "conference" --rooms
811
-
812
- # Only people (exclude rooms)
813
- m365-agent-cli find "smith" --people
814
- ```
815
-
816
- ---
817
-
818
- ## Additional commands
819
-
820
- These commands are not expanded step-by-step above; use **`m365-agent-cli <command> --help`** for flags and examples.
821
-
822
- | Command | What it does |
823
- | --- | --- |
824
- | **`forward-event`** (`forward`) | Forward a calendar invitation to more recipients (Graph). |
825
- | **`graph-calendar`** | Graph **calendars**, **calendarView**, **get-event**, **accept** / **decline** / **tentative** (vs EWS `calendar` / `respond`). |
826
- | **`counter`** (`propose-new-time`) | Propose a new time for an existing event (Graph). |
827
- | **`schedule`** | Merged free/busy for one or more people over a time window (`getSchedule`). |
828
- | **`suggest`** | Meeting-time suggestions via Graph (`findMeetingTimes`). |
829
- | **`rooms`** | Search and filter room resources (capacity, equipment, floor, etc.). |
830
- | **`oof`** | Mailbox out-of-office **settings** (Graph mailbox settings API). |
831
- | **`auto-reply`** | EWS **inbox-rule** based auto-reply templates (distinct from `oof`). |
832
- | **`rules`** | Inbox message rules (Graph). |
833
- | **`delegates`** | Calendar/mailbox delegate permissions (EWS). |
834
- | **`subscribe`** / **`subscriptions`** | Graph **change notifications** (create or list/cancel subscriptions). |
835
- | **`serve`** | Local **webhook receiver** for subscription callbacks (pair with `subscribe`). |
836
-
837
- ---
838
-
839
- ## Examples
840
-
841
- ### Morning Routine Script
842
-
843
- ```bash
844
- #!/bin/bash
845
- echo "=== Today's Calendar ==="
846
- m365-agent-cli calendar
847
-
848
- echo -e "=== Unread Emails ==="
849
- m365-agent-cli mail --unread -n 5
850
-
851
- echo -e "=== Pending Invitations ==="
852
- m365-agent-cli respond
853
- ```
854
-
855
- ### Quick Meeting Setup
856
-
857
- ```bash
858
- # Find a time when everyone is free and create the meeting
859
- m365-agent-cli create-event "Project Kickoff" 14:00 15:00 \
860
- --day tomorrow \
861
- --attendees "team@company.com" \
862
- --teams \
863
- --find-room \
864
- --description "Initial project planning session"
865
- ```
866
-
867
- ### Email Report with Attachment
868
-
869
- ```bash
870
- m365-agent-cli send \
871
- --to "manager@company.com" \
872
- --subject "Weekly Report - $(date +%Y-%m-%d)" \
873
- --body "Please find this week's report attached." \
874
- --attach "weekly-report.pdf"
875
- ```
876
-
877
- ### Shared Mailbox Operations
878
-
879
- ```bash
880
- # Check shared mailbox calendar
881
- m365-agent-cli calendar --mailbox shared@company.com
882
-
883
- # Send email from shared mailbox
884
- m365-agent-cli send \
885
- --to "team@company.com" \
886
- --subject "Team Update" \
887
- --body "..." \
888
- --mailbox shared@company.com
889
-
890
- # Read shared mailbox inbox
891
- m365-agent-cli mail --mailbox shared@company.com
892
-
893
- # Reply from shared mailbox
894
- m365-agent-cli mail --reply 1 --message "Done!" --mailbox shared@company.com
895
- ```
896
-
897
- ---
898
-
899
- ## Security practices
900
-
901
- - **Graph search queries** and **markdown links** are validated/escaped where applicable
902
- - **Date and email inputs** are validated before API calls
903
- - **Token cache files** under `~/.config/m365-agent-cli/` are written with owner-only permissions where supported
904
- - **String pattern replacement** avoids regex injection from malformed `$pattern` values
905
-
906
- ---
907
-
908
- ## Requirements
909
-
910
- - [Bun](https://bun.sh) runtime
911
- - Microsoft 365 account
912
- - Azure AD app registration with EWS permissions (`EWS.AccessAsUser.All`)
913
-
914
- ## License
915
-
916
- MIT
1
+ # m365-agent-cli
2
+
3
+ > **Credits:** This repository is heavily extended from the original project by [foeken/clippy](https://github.com/foeken/clippy).
4
+
5
+ A powerful command-line interface for Microsoft 365 using Exchange Web Services (EWS) and Microsoft Graph. Manage your calendar, email, OneDrive files, Microsoft Planner tasks, and SharePoint Sites directly from the terminal.
6
+
7
+ ## The Ultimate AI Personal Assistant (PA)
8
+
9
+ The Personal Assistant (PA) playbook and skills have been moved to their own dedicated repository.
10
+
11
+ To use this tool as a highly effective Personal Assistant within OpenClaw, please visit the **[openclaw-personal-assistant](https://github.com/markus-lassfolk/openclaw-personal-assistant)** repository for the Master Guide, ecosystem requirements, and skill installation instructions.
12
+
13
+ ---
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ # Clone the repository
19
+ git clone https://github.com/markus-lassfolk/m365-agent-cli.git
20
+ cd m365-agent-cli
21
+
22
+ # Install dependencies
23
+ bun install
24
+ # Install OpenClaw Skills (optional, gives your AI agent superpowers)
25
+ mkdir -p ~/.openclaw/workspace/skills
26
+ cp -r skills/* ~/.openclaw/workspace/skills/
27
+
28
+
29
+ # Run directly
30
+ bun run src/cli.ts <command>
31
+
32
+ # Or link globally
33
+ bun link
34
+ m365-agent-cli <command>
35
+ ```
36
+
37
+ ### Published package (npm)
38
+
39
+ ```bash
40
+ npm install -g m365-agent-cli
41
+ m365-agent-cli update
42
+ ```
43
+
44
+ `update` checks the npm registry and runs `npm install -g m365-agent-cli@latest` (or `bun install -g` when you run the CLI with Bun). Maintainers: versioning, tags, and npm publish are documented in [docs/RELEASE.md](docs/RELEASE.md).
45
+
46
+ ## Authentication
47
+
48
+ **Need help setting up the Azure AD App?** Follow our [Automated Entra ID App Setup Guide](docs/ENTRA_SETUP.md) for bash and PowerShell scripts that configure the exact permissions you need in seconds.
49
+
50
+ **EWS retirement:** Microsoft is phasing out EWS for Exchange Online in favor of Microsoft Graph. Track migration work in [docs/EWS_TO_GRAPH_MIGRATION_EPIC.md](docs/EWS_TO_GRAPH_MIGRATION_EPIC.md) (phased plan, inventory, Graph-primary + EWS-fallback strategy).
51
+
52
+ **Optional error reporting:** To receive CLI crashes and unhandled errors in [GlitchTip](https://glitchtip.com/) (Sentry-compatible), set **`GLITCHTIP_DSN`** (or **`SENTRY_DSN`**) in your environment. See [docs/GLITCHTIP.md](docs/GLITCHTIP.md).
53
+
54
+ m365-agent-cli uses OAuth2 with a refresh token to authenticate against Microsoft 365. You need an Azure AD app registration.
55
+
56
+ ### Setup
57
+
58
+ If you used the setup scripts from `docs/ENTRA_SETUP.md`, your `EWS_CLIENT_ID` is already appended to your `~/.config/m365-agent-cli/.env` file.
59
+
60
+ The easiest way to obtain your refresh tokens is to run the interactive login command:
61
+
62
+ ```bash
63
+ m365-agent-cli login
64
+ ```
65
+
66
+ This will initiate the Microsoft Device Code flow and automatically save `EWS_REFRESH_TOKEN` and `GRAPH_REFRESH_TOKEN` into your `~/.config/m365-agent-cli/.env` file upon successful authentication.
67
+
68
+ Alternatively, you can manually create a `~/.config/m365-agent-cli/.env` file (or set environment variables):
69
+
70
+ ```bash
71
+ EWS_CLIENT_ID=your-azure-app-client-id
72
+ EWS_REFRESH_TOKEN=your-refresh-token
73
+ EWS_USERNAME=your@email.com
74
+ EWS_ENDPOINT=https://outlook.office365.com/EWS/Exchange.asmx
75
+ EWS_TENANT_ID=common # or your tenant ID
76
+ ```
77
+
78
+ ### Shared Mailbox Access
79
+
80
+ To send from or access a shared mailbox, set the default in your env:
81
+
82
+ ```bash
83
+ EWS_TARGET_MAILBOX=shared@company.com
84
+ ```
85
+
86
+ Or pass `--mailbox` per-command (see examples below).
87
+
88
+ ### How It Works
89
+
90
+ 1. m365-agent-cli uses the refresh token to obtain a short-lived access token via Microsoft's OAuth2 endpoint
91
+ 2. Access tokens are cached under `~/.config/m365-agent-cli/`:
92
+ - **EWS:** `token-cache-{identity}.json` (default identity: `default`)
93
+ - **Microsoft Graph:** `graph-token-cache-{identity}.json` (same identity name; default `default`)
94
+ - A legacy `graph-token-cache.json` (no identity suffix) is migrated once to `graph-token-cache-default.json` when present.
95
+ Tokens are refreshed automatically when expired.
96
+ 3. Microsoft may rotate the refresh token on each use — the latest one is cached automatically in the same directory
97
+
98
+ ### Verify Authentication
99
+
100
+ ```bash
101
+ # Check who you're logged in as
102
+ m365-agent-cli whoami
103
+
104
+ # Verify your Graph API token scopes
105
+ m365-agent-cli verify-token
106
+ ```
107
+
108
+ ---
109
+
110
+ ## Options: root vs per-command
111
+
112
+ `m365-agent-cli --help` shows only options registered on the **root** program, currently:
113
+
114
+ ```bash
115
+ --read-only # Run in read-only mode, blocking mutating operations
116
+ --version, -V # CLI version (semver from package)
117
+ ```
118
+
119
+ Many **subcommands** accept their own flags. Common patterns (not every command has every flag—use `m365-agent-cli <command> --help`):
120
+
121
+ ```bash
122
+ --json # Machine-readable output (where supported)
123
+ --token <token> # Use a specific access token (overrides cache)
124
+ --identity <name> # Token cache profile (default: default). Selects EWS and Graph cache files for that name.
125
+ --user <email> # Graph delegation: target another user/mailbox (supported commands only; needs permissions)
126
+ ```
127
+
128
+ **EWS shared mailbox:** use `--mailbox <email>` on calendar, mail, send, folders, drafts, respond, findtime, delegates, auto-reply, and related flows.
129
+
130
+ ### Read-Only Mode
131
+
132
+ When read-only mode is on (`READ_ONLY_MODE=true` in env / `~/.config/m365-agent-cli/.env`, or `--read-only` on the **root** command), the CLI calls `checkReadOnly()` before the listed actions and exits with an error **before** the mutating request is sent.
133
+
134
+ The table below matches **`checkReadOnly` in the source** (search the repo for `checkReadOnly(` to verify after changes). Anything **not** listed here is either read-only or not wired to read-only yet.
135
+
136
+ | Command | Blocked actions (read-only on) |
137
+ | --- | --- |
138
+ | `create-event` | Entire command |
139
+ | `update-event` | Entire command |
140
+ | `delete-event` | Entire command |
141
+ | `forward-event` | Entire command |
142
+ | `counter` | Entire command |
143
+ | `respond` | `accept`, `decline`, `tentative` (not `respond list`) |
144
+ | `send` | Entire command |
145
+ | `mail` | Mutating flags only: `--flag`, `--unflag`, `--mark-read`, `--mark-unread`, `--complete`, `--sensitivity`, `--move`, `--reply`, `--reply-all`, `--forward`, `--set-categories`, `--clear-categories` (listing, `--read`, `--download` stay allowed) |
146
+ | `drafts` | `--create`, `--edit`, `--send`, `--delete` (plain list/read allowed) |
147
+ | `folders` | `--create`, `--rename` (with `--to`), `--delete` (listing folders allowed) |
148
+ | `files` | `upload`, `upload-large`, `delete`, `share`, `restore`, `checkin` |
149
+ | `planner` | `create-task`, `update-task`, `delete-task`, `create-plan` (`--group` or beta `--roster`), `update-plan`, `delete-plan`, `create-bucket`, `update-bucket`, `delete-bucket`, `list-user-tasks`, `list-user-plans`, `update-task-details`, `update-plan-details`, `add-checklist-item`, `update-checklist-item`, `remove-checklist-item`, `add-reference`, `remove-reference`, `update-task-board`, `add-favorite`, `remove-favorite`, `roster` (beta: `create`, `get`, `list-members`, `add-member`, `remove-member`) |
150
+ | `sharepoint` / `sp` | `create-item`, `update-item` |
151
+ | `pages` | `update`, `publish` |
152
+ | `rules` | `create`, `update`, `delete` |
153
+ | `todo` | `create`, `update`, `complete`, `delete`, `add-checklist`, `update-checklist`, `delete-checklist`, `get-checklist-item`, `create-list`, `update-list`, `delete-list`, `add-attachment`, `get-attachment`, `download-attachment`, `delete-attachment`, `add-reference-attachment`, `add-linked-resource`, `remove-linked-resource`, `upload-attachment-large`, `linked-resource` (`create`, `update`, `delete`), `extension` (`set`, `update`, `delete`), `list-extension` (`set`, `update`, `delete`) |
154
+ | `subscribe` | Creating a subscription; `subscribe cancel <id>` |
155
+ | `delegates` | `add`, `update`, `remove` |
156
+ | `oof` | Write path only (when `--status`, `--internal-message`, `--external-message`, `--start`, or `--end` is used to change settings) |
157
+ | `auto-reply` | Entire command (EWS auto-reply rules) |
158
+ | `outlook-categories` | `create`, `update`, `delete` (not `list`) |
159
+ | `outlook-graph` | `create-folder`, `update-folder`, `delete-folder`, `send-mail`, `patch-message`, `delete-message`, `move-message`, `copy-message`, `create-reply`, `create-reply-all`, `create-forward`, `send-message`, `create-contact`, `update-contact`, `delete-contact` |
160
+ | `graph-calendar` | `accept`, `decline`, `tentative` |
161
+
162
+ **Intentionally not gated** (no `checkReadOnly` today): read/query helpers such as `schedule`, `suggest`, `findtime`, `calendar`, `graph-calendar list-calendars` / `get-calendar` / `list-view` / `get-event`, `outlook-graph list-mail` / `list-messages` / `list-message-attachments` / `get-message-attachment` / `download-message-attachment` / `get-message` / `list-folders` / `list-contacts` / `get-contact` / `get-folder`, `subscriptions list`, `rules list` / `rules get`, `todo` list-only usage, **`outlook-categories list`** (mutating `outlook-categories create|update|delete` **are** gated), `files` list/search/meta/download/convert/analytics/versions, etc. Those calls do not use the guard in code; if a new subcommand adds writes, it should call `checkReadOnly` and this table should be updated.
163
+
164
+ You can enable Read-Only mode in two ways:
165
+
166
+ 1. **Global flag**: Pass **`--read-only` immediately after** `m365-agent-cli` (before the subcommand). Commander treats this as a root option; placing it after the subcommand will not enable read-only mode.
167
+
168
+ ```bash
169
+ m365-agent-cli --read-only create-event "Test" 09:00 10:00
170
+ # Error: Command blocked. The CLI is running in read-only mode.
171
+ ```
172
+
173
+ 2. **Environment variable**: Set `READ_ONLY_MODE=true` in your environment or `~/.config/m365-agent-cli/.env` file.
174
+
175
+ ```bash
176
+ export READ_ONLY_MODE=true
177
+ m365-agent-cli planner update-task <taskId> --title "New"
178
+ # Error: Command blocked. The CLI is running in read-only mode.
179
+ ```
180
+
181
+ ---
182
+
183
+ ## Calendar Commands
184
+
185
+ ### View Calendar
186
+
187
+ ```bash
188
+ # Today's events
189
+ m365-agent-cli calendar
190
+
191
+ # Specific day
192
+ m365-agent-cli calendar tomorrow
193
+ m365-agent-cli calendar monday
194
+ m365-agent-cli calendar 2024-02-15
195
+
196
+ # Date ranges
197
+ m365-agent-cli calendar monday friday
198
+ m365-agent-cli calendar 2024-02-15 2024-02-20
199
+
200
+ # Week views
201
+ m365-agent-cli calendar week # This week (Mon-Sun)
202
+ m365-agent-cli calendar lastweek
203
+ m365-agent-cli calendar nextweek
204
+
205
+ # Include details (attendees, body preview, categories)
206
+ m365-agent-cli calendar -v
207
+ m365-agent-cli calendar week --verbose
208
+
209
+ # Shared mailbox calendar
210
+ m365-agent-cli calendar --mailbox shared@company.com
211
+ m365-agent-cli calendar nextweek --mailbox shared@company.com
212
+ ```
213
+
214
+ ### Calendar: rolling ranges and business (weekday) windows
215
+
216
+ Besides a single day or `start end` date range, **`calendar`** supports **one** of these span modes (not combinable with each other or with an `[end]` argument; not with `week` / `lastweek` / `nextweek`):
217
+
218
+ ```bash
219
+ # Next 5 calendar days starting today (includes today)
220
+ m365-agent-cli calendar today --days 5
221
+
222
+ # Previous 3 calendar days ending on today
223
+ m365-agent-cli calendar today --previous-days 3
224
+
225
+ # Next 10 weekdays (Mon–Fri) starting from the anchor day
226
+ # (if anchor is Sat/Sun, counting starts from the next Monday)
227
+ m365-agent-cli calendar today --business-days 10
228
+
229
+ # Typo-tolerant alias for --business-days
230
+ m365-agent-cli calendar today --busness-days 5
231
+
232
+ # 5 weekdays backward ending on or before the anchor
233
+ m365-agent-cli calendar today --previous-business-days 5
234
+ ```
235
+
236
+ ### Create Events
237
+
238
+ ```bash
239
+ # Basic event
240
+ m365-agent-cli create-event "Team Standup" 09:00 09:30
241
+
242
+ # With options
243
+ m365-agent-cli create-event "Project Review" 14:00 15:00 \
244
+ --day tomorrow \
245
+ --description "Q1 review meeting" \
246
+ --attendees "alice@company.com,bob@company.com" \
247
+ --teams \
248
+ --room "Conference Room A"
249
+
250
+ # Specify a timezone explicitly
251
+ m365-agent-cli create-event "Global Sync" 09:00 10:00 --timezone "Pacific Standard Time"
252
+
253
+ # All-day event with category and sensitivity
254
+ m365-agent-cli create-event "Holiday" --all-day --category "Personal" --sensitivity private
255
+
256
+ # Find an available room automatically
257
+ m365-agent-cli create-event "Workshop" 10:00 12:00 --find-room
258
+
259
+ # List available rooms
260
+ m365-agent-cli create-event "x" 10:00 11:00 --list-rooms
261
+
262
+ # Create in shared mailbox calendar
263
+ m365-agent-cli create-event "Team Standup" 09:00 09:30 --mailbox shared@company.com
264
+ ```
265
+
266
+ ### Recurring Events
267
+
268
+ ```bash
269
+ # Daily standup
270
+ m365-agent-cli create-event "Daily Standup" 09:00 09:15 --repeat daily
271
+
272
+ # Weekly on specific days
273
+ m365-agent-cli create-event "Team Sync" 14:00 15:00 \
274
+ --repeat weekly \
275
+ --days mon,wed,fri
276
+
277
+ # Monthly, 10 occurrences
278
+ m365-agent-cli create-event "Monthly Review" 10:00 11:00 \
279
+ --repeat monthly \
280
+ --count 10
281
+
282
+ # Every 2 weeks until a date
283
+ m365-agent-cli create-event "Sprint Planning" 09:00 11:00 \
284
+ --repeat weekly \
285
+ --every 2 \
286
+ --until 2024-12-31
287
+ ```
288
+
289
+ ### Update Events
290
+
291
+ ```bash
292
+ # List today's events
293
+ m365-agent-cli update-event
294
+
295
+ # Update by event ID
296
+ m365-agent-cli update-event --id <eventId> --title "New Title"
297
+ m365-agent-cli update-event --id <eventId> --start 10:00 --end 11:00
298
+ m365-agent-cli update-event --id <eventId> --add-attendee "new@company.com"
299
+ m365-agent-cli update-event --id <eventId> --room "Room B"
300
+ m365-agent-cli update-event --id <eventId> --location "Off-site"
301
+ m365-agent-cli update-event --id <eventId> --teams # Add Teams meeting
302
+ m365-agent-cli update-event --id <eventId> --no-teams # Remove Teams meeting
303
+ m365-agent-cli update-event --id <eventId> --all-day # Make all-day
304
+ m365-agent-cli update-event --id <eventId> --sensitivity private
305
+ m365-agent-cli update-event --id <eventId> --category "Project A" --category Review
306
+ m365-agent-cli update-event --id <eventId> --clear-categories
307
+
308
+ # Show events from a specific day
309
+ m365-agent-cli update-event --day tomorrow
310
+
311
+ # Update event in shared mailbox calendar
312
+ m365-agent-cli update-event --id <eventId> --title "Updated Title" --mailbox shared@company.com
313
+ ```
314
+
315
+ ### Delete/Cancel Events
316
+
317
+ ```bash
318
+ # List your events
319
+ m365-agent-cli delete-event
320
+
321
+ # Delete event by ID
322
+ m365-agent-cli delete-event --id <eventId>
323
+
324
+ # With cancellation message
325
+ m365-agent-cli delete-event --id <eventId> --message "Sorry, need to reschedule"
326
+
327
+ # Force delete without sending cancellation
328
+ m365-agent-cli delete-event --id <eventId> --force-delete
329
+
330
+ # Search for events by title
331
+ m365-agent-cli delete-event --search "standup"
332
+
333
+ # Delete event in shared mailbox calendar
334
+ m365-agent-cli delete-event --id <eventId> --mailbox shared@company.com
335
+ ```
336
+
337
+ ### Respond to Invitations
338
+
339
+ ```bash
340
+ # List events needing response
341
+ m365-agent-cli respond
342
+
343
+ # Accept/decline/tentative by event ID
344
+ m365-agent-cli respond accept --id <eventId>
345
+ m365-agent-cli respond decline --id <eventId> --comment "Conflict with another meeting"
346
+ m365-agent-cli respond tentative --id <eventId>
347
+
348
+ # Don't send response to organizer
349
+ m365-agent-cli respond accept --id <eventId> --no-notify
350
+
351
+ # Only show required invitations (exclude optional)
352
+ m365-agent-cli respond list --only-required
353
+
354
+ # Respond to invitation in shared mailbox calendar
355
+ m365-agent-cli respond accept --id <eventId> --mailbox shared@company.com
356
+ ```
357
+
358
+ ### Find Meeting Times
359
+
360
+ ```bash
361
+ # Find free slots next week for yourself and others
362
+ m365-agent-cli findtime nextweek alice@company.com bob@company.com
363
+
364
+ # Specific date range (keywords or YYYY-MM-DD)
365
+ m365-agent-cli findtime monday friday alice@company.com
366
+ m365-agent-cli findtime 2026-04-01 2026-04-03 alice@company.com
367
+
368
+ # Custom duration and working hours
369
+ m365-agent-cli findtime nextweek alice@company.com --duration 60 --start 10 --end 16
370
+
371
+ # Only check specified people (exclude yourself from availability check)
372
+ m365-agent-cli findtime nextweek alice@company.com --solo
373
+ ```
374
+
375
+ ---
376
+
377
+ ## Email Commands
378
+
379
+ ### List & Read Email
380
+
381
+ ```bash
382
+ # Inbox (default)
383
+ m365-agent-cli mail
384
+
385
+ # Other folders
386
+ m365-agent-cli mail sent
387
+ m365-agent-cli mail drafts
388
+ m365-agent-cli mail deleted
389
+ m365-agent-cli mail archive
390
+
391
+ # Pagination
392
+ m365-agent-cli mail -n 20 # Show 20 emails
393
+ m365-agent-cli mail -p 2 # Page 2
394
+
395
+ # Filters
396
+ m365-agent-cli mail --unread # Only unread
397
+ m365-agent-cli mail --flagged # Only flagged
398
+ m365-agent-cli mail -s "invoice" # Search
399
+
400
+ # Read an email
401
+ m365-agent-cli mail -r 1 # Read email #1
402
+
403
+ # Download attachments
404
+ m365-agent-cli mail -d 3 # Download from email #3
405
+ m365-agent-cli mail -d 3 -o ~/Downloads
406
+
407
+ # Shared mailbox inbox
408
+ m365-agent-cli mail --mailbox shared@company.com
409
+ ```
410
+
411
+ ### Categories on mail (Outlook)
412
+
413
+ Messages use **category name strings** (same as Outlook). **Colors** come from the mailbox **master category list**, not from a separate field per message. List master categories (names + preset color) via Graph:
414
+
415
+ ```bash
416
+ m365-agent-cli outlook-categories list
417
+ m365-agent-cli outlook-categories list --user colleague@company.com # delegation, if permitted
418
+ ```
419
+
420
+ Manage the master list (names + **preset** colors `preset0`..`preset24`; requires Graph **`MailboxSettings.ReadWrite`**):
421
+
422
+ ```bash
423
+ m365-agent-cli outlook-categories create --name "Project A" --color preset9
424
+ m365-agent-cli outlook-categories update --id <categoryGuid> --name "Project A (new)" --color preset12
425
+ m365-agent-cli outlook-categories delete --id <categoryGuid>
426
+ ```
427
+
428
+ Set or clear categories on a message **by ID** from list/read output:
429
+
430
+ ```bash
431
+ m365-agent-cli mail --set-categories <messageId> --category Work --category "Follow up"
432
+ m365-agent-cli mail --clear-categories <messageId>
433
+ ```
434
+
435
+ Category names appear in **`mail`** list (text and JSON) and when reading a message (`-r`).
436
+
437
+ ### Send Email
438
+
439
+ ```bash
440
+ # Simple email (--body is optional)
441
+ m365-agent-cli send \
442
+ --to "recipient@example.com" \
443
+ --subject "Hello"
444
+
445
+ # With body
446
+ m365-agent-cli send \
447
+ --to "recipient@example.com" \
448
+ --subject "Hello" \
449
+ --body "This is the message body"
450
+
451
+ # Multiple recipients, CC, BCC
452
+ m365-agent-cli send \
453
+ --to "alice@example.com,bob@example.com" \
454
+ --cc "manager@example.com" \
455
+ --bcc "archive@example.com" \
456
+ --subject "Team Update" \
457
+ --body "..."
458
+
459
+ # With markdown formatting
460
+ m365-agent-cli send \
461
+ --to "user@example.com" \
462
+ --subject "Update" \
463
+ --body "**Bold text** and a [link](https://example.com)" \
464
+ --markdown
465
+
466
+ # With attachments
467
+ m365-agent-cli send \
468
+ --to "user@example.com" \
469
+ --subject "Report" \
470
+ --body "Please find attached." \
471
+ --attach "report.pdf,data.xlsx"
472
+
473
+ # Send from shared mailbox
474
+ m365-agent-cli send \
475
+ --to "recipient@example.com" \
476
+ --subject "From shared mailbox" \
477
+ --body "..." \
478
+ --mailbox shared@company.com
479
+ ```
480
+
481
+ ### Reply & Forward
482
+
483
+ ```bash
484
+ # Reply to an email
485
+ m365-agent-cli mail --reply 1 --message "Thanks for your email!"
486
+
487
+ # Reply all
488
+ m365-agent-cli mail --reply-all 1 --message "Thanks everyone!"
489
+
490
+ # Reply with markdown
491
+ m365-agent-cli mail --reply 1 --message "**Got it!** Will do." --markdown
492
+
493
+ # Save reply as draft instead of sending
494
+ m365-agent-cli mail --reply 1 --message "Draft reply" --draft
495
+
496
+ # Forward an email (uses --to-addr, not --to)
497
+ m365-agent-cli mail --forward 1 --to-addr "colleague@example.com"
498
+ m365-agent-cli mail --forward 1 --to-addr "a@example.com,b@example.com" --message "FYI"
499
+
500
+ # Reply or forward with file/link attachments and/or Outlook categories (draft workflow)
501
+ m365-agent-cli mail --reply <messageId> --message "See attached" --attach "report.pdf"
502
+ m365-agent-cli mail --forward <messageId> --to-addr "boss@company.com" --message "FYI" --attach-link "https://contoso.com/doc"
503
+ m365-agent-cli mail --reply <messageId> --message "Tagged" --with-category Work --with-category "Follow up"
504
+
505
+ # Forward or reply as draft (optionally with --attach / --attach-link / --with-category)
506
+ m365-agent-cli mail --forward <messageId> --to-addr "a@b.com" --draft
507
+ m365-agent-cli mail --reply <messageId> --message "Will edit later" --draft
508
+
509
+ # Reply/forward from shared mailbox
510
+ m365-agent-cli mail --reply 1 --message "..." --mailbox shared@company.com
511
+ m365-agent-cli mail --reply-all 1 --message "..." --mailbox shared@company.com
512
+ m365-agent-cli mail --forward 1 --to-addr "colleague@example.com" --mailbox shared@company.com
513
+ ```
514
+
515
+ ### Email Actions
516
+
517
+ ```bash
518
+ # Mark as read/unread
519
+ m365-agent-cli mail --mark-read 1
520
+ m365-agent-cli mail --mark-unread 2
521
+
522
+ # Flag emails
523
+ m365-agent-cli mail --flag 1
524
+ m365-agent-cli mail --unflag 2
525
+ m365-agent-cli mail --complete 3 # Mark flag as complete
526
+ m365-agent-cli mail --flag 1 --start-date 2026-05-01 --due 2026-05-05
527
+
528
+ # Set sensitivity
529
+ m365-agent-cli mail --sensitivity <emailId> --level confidential
530
+
531
+ # Move to folder (--to here is for folder destination, not email recipient)
532
+ m365-agent-cli mail --move 1 --to archive
533
+ m365-agent-cli mail --move 2 --to deleted
534
+ m365-agent-cli mail --move 3 --to "My Custom Folder"
535
+ ```
536
+
537
+ See **Categories on mail** above for `--set-categories` / `--clear-categories`.
538
+
539
+ ### Manage Drafts
540
+
541
+ ```bash
542
+ # List drafts
543
+ m365-agent-cli drafts
544
+
545
+ # Read a draft
546
+ m365-agent-cli drafts -r 1
547
+
548
+ # Create a draft
549
+ m365-agent-cli drafts --create \
550
+ --to "recipient@example.com" \
551
+ --subject "Draft Email" \
552
+ --body "Work in progress..."
553
+
554
+ # Categories on drafts (same name strings as Outlook; see outlook-categories list)
555
+ m365-agent-cli drafts --create --to "a@b.com" --subject "Hi" --body "..." --category Work
556
+ m365-agent-cli drafts --edit <draftId> --category Review --category "Follow up"
557
+ m365-agent-cli drafts --edit <draftId> --clear-categories
558
+
559
+ # Create with attachment
560
+ m365-agent-cli drafts --create \
561
+ --to "user@example.com" \
562
+ --subject "Report" \
563
+ --body "See attached" \
564
+ --attach "report.pdf"
565
+
566
+ # Edit a draft
567
+ m365-agent-cli drafts --edit 1 --body "Updated content"
568
+ m365-agent-cli drafts --edit 1 --subject "New Subject"
569
+
570
+ # Send a draft
571
+ m365-agent-cli drafts --send 1
572
+
573
+ # Delete a draft
574
+ m365-agent-cli drafts --delete 1
575
+ ```
576
+
577
+ ### Manage Folders
578
+
579
+ ```bash
580
+ # List all folders
581
+ m365-agent-cli folders
582
+
583
+ # Create a folder
584
+ m365-agent-cli folders --create "Projects"
585
+
586
+ # Rename a folder
587
+ m365-agent-cli folders --rename "Projects" --to "Active Projects"
588
+
589
+ # Delete a folder
590
+ m365-agent-cli folders --delete "Old Folder"
591
+ ```
592
+
593
+ ---
594
+
595
+ ## OneDrive / Office Online Commands
596
+
597
+ ### List, Search, and Inspect Files
598
+
599
+ ```bash
600
+ # List root files
601
+ m365-agent-cli files list
602
+
603
+ # List a folder by item ID
604
+ m365-agent-cli files list --folder <folderId>
605
+
606
+ # Search OneDrive
607
+ m365-agent-cli files search "budget 2026"
608
+
609
+ # Inspect metadata
610
+ m365-agent-cli files meta <fileId>
611
+
612
+ # Get file analytics
613
+ m365-agent-cli files analytics <fileId>
614
+
615
+ # File versions
616
+ m365-agent-cli files versions <fileId>
617
+ m365-agent-cli files restore <fileId> <versionId>
618
+ ```
619
+
620
+ ### Upload, Download, Delete, and Share
621
+
622
+ ```bash
623
+ # Upload a normal file (<=250MB)
624
+ m365-agent-cli files upload ./report.docx
625
+
626
+ # Upload to a specific folder
627
+ m365-agent-cli files upload ./report.docx --folder <folderId>
628
+
629
+ # Upload a large file (>250MB, up to 4GB via chunked upload)
630
+ m365-agent-cli files upload-large ./video.mp4
631
+ m365-agent-cli files upload-large ./backup.zip --folder <folderId>
632
+
633
+ # Download a file
634
+ m365-agent-cli files download <fileId>
635
+ m365-agent-cli files download <fileId> --out ./local-copy.docx
636
+
637
+ # Convert and download (e.g., to PDF)
638
+ m365-agent-cli files convert <fileId> --format pdf --out ./converted.pdf
639
+
640
+ # Delete a file
641
+ m365-agent-cli files delete <fileId>
642
+
643
+ # Create a share link
644
+ m365-agent-cli files share <fileId> --type view --scope org
645
+ m365-agent-cli files share <fileId> --type edit --scope anonymous
646
+ ```
647
+
648
+ ### Collaborative Editing via Office Online
649
+
650
+ Microsoft Graph cannot join or control a live Office Online editing session. What m365-agent-cli can do is prepare the handoff properly:
651
+
652
+ 1. Find the document in OneDrive
653
+ 2. Create an organization-scoped edit link (or anonymous)
654
+ 3. Return the Office Online URL (`webUrl`) for the user to open
655
+ 4. Optionally checkout the file first for exclusive editing workflows
656
+
657
+ ```bash
658
+ # Search for the document first
659
+ m365-agent-cli files search "budget 2026.xlsx"
660
+
661
+ # Create a collaboration handoff for Word/Excel/PowerPoint Online
662
+ m365-agent-cli files share <fileId> --collab
663
+
664
+ # Same, but checkout the file first (exclusive edit lock)
665
+ m365-agent-cli files share <fileId> --collab --lock
666
+
667
+ # When the exclusive-edit workflow is done, check the file back in
668
+ m365-agent-cli files checkin <fileId> --comment "Updated Q1 numbers"
669
+ ```
670
+
671
+ **Supported collaboration file types:** `.docx`, `.xlsx`, `.pptx`
672
+
673
+ Legacy Office formats such as `.doc`, `.xls`, and `.ppt` must be converted first.
674
+
675
+ **Important clarification:**
676
+
677
+ - m365-agent-cli does **not** participate in the real-time editing session
678
+ - Office Online handles the actual co-authoring once the user opens the returned URL
679
+ - m365-agent-cli handles the file lifecycle around that workflow
680
+
681
+ ---
682
+
683
+ ## Microsoft Planner Commands
684
+
685
+ Manage tasks and plans in Microsoft Planner. Planner uses **six label slots** per task (`category1`..`category6`); **display names** for those slots are defined in **plan details**. The CLI accepts slots as **`1`..`6`** or **`category1`..`category6`**.
686
+
687
+ ```bash
688
+ # List tasks assigned to you (label names shown when plan details are available)
689
+ m365-agent-cli planner list-my-tasks
690
+
691
+ # List your plans
692
+ m365-agent-cli planner list-plans
693
+ m365-agent-cli planner list-plans -g <groupId>
694
+
695
+ # List another user's Planner tasks/plans (Graph may return 403 depending on tenant/token)
696
+ m365-agent-cli planner list-user-tasks --user <azureAdObjectId>
697
+ m365-agent-cli planner list-user-plans --user <azureAdObjectId>
698
+
699
+ # Beta: roster container (create roster → add members → create-plan --roster <rosterId>)
700
+ m365-agent-cli planner roster create
701
+ m365-agent-cli planner roster add-member -r <rosterId> --user <userId>
702
+ m365-agent-cli planner create-plan --roster <rosterId> -t "Roster plan"
703
+
704
+ # View plan structure
705
+ m365-agent-cli planner list-buckets --plan <planId>
706
+ m365-agent-cli planner list-tasks --plan <planId>
707
+
708
+ # Create and update tasks
709
+ m365-agent-cli planner create-task --plan <planId> --title "New Task" -b <bucketId>
710
+ m365-agent-cli planner create-task --plan <planId> --title "Labeled" --label 1 --label category3
711
+
712
+ m365-agent-cli planner update-task -i <taskId> --title "Updated Task" --percent 50 --assign <userId>
713
+ m365-agent-cli planner update-task -i <taskId> --label 2 --unlabel 1
714
+ m365-agent-cli planner update-task -i <taskId> --clear-labels
715
+ ```
716
+
717
+ ---
718
+
719
+ ## Microsoft To Do
720
+
721
+ To Do tasks support **string categories** (independent of Outlook mailbox master categories).
722
+
723
+ ```bash
724
+ # Create with categories
725
+ m365-agent-cli todo create -t "Buy milk" --category Shopping --category Errands
726
+
727
+ # Update fields including categories (see: m365-agent-cli todo update --help)
728
+ m365-agent-cli todo update -l Tasks -t <taskId> --category Work --category Urgent
729
+ m365-agent-cli todo update -l Tasks -t <taskId> --clear-categories
730
+
731
+ # One checklist row (Graph GET checklistItems/{id}); download file attachment bytes ($value)
732
+ m365-agent-cli todo get-checklist-item -l Tasks -t <taskId> -c <checklistItemId>
733
+ m365-agent-cli todo download-attachment -l Tasks -t <taskId> -a <attachmentId> -o ./file.bin
734
+ ```
735
+
736
+ ## Outlook Graph REST (`outlook-graph`)
737
+
738
+ Microsoft Graph endpoints for **mail folders**, **messages** (folder or mailbox-wide list, **sendMail**, PATCH, move, copy, attachments, reply/reply-all/forward drafts + send), and **personal contacts** (complements EWS **`mail`** / **`folders`**). Requires appropriate **Mail.** and **Contacts.** scopes.
739
+
740
+ ```bash
741
+ m365-agent-cli outlook-graph list-folders
742
+ m365-agent-cli outlook-graph list-messages --folder inbox --top 25
743
+ m365-agent-cli outlook-graph list-mail --top 25
744
+ m365-agent-cli outlook-graph list-mail --search "quarterly report" --all
745
+ m365-agent-cli outlook-graph get-message -i <messageId>
746
+ m365-agent-cli outlook-graph send-mail --json-file mail.json
747
+ m365-agent-cli outlook-graph patch-message <id> --json-file patch.json
748
+ m365-agent-cli outlook-graph list-message-attachments -i <messageId>
749
+ m365-agent-cli outlook-graph download-message-attachment -i <id> -a <attId> -o ./file.bin
750
+ m365-agent-cli outlook-graph create-reply <messageId>
751
+ m365-agent-cli outlook-graph send-message <draftId>
752
+ m365-agent-cli outlook-graph list-contacts
753
+ ```
754
+
755
+ ## Graph calendar REST (`graph-calendar`)
756
+
757
+ Microsoft Graph endpoints for **calendars**, **calendarView** (time-range queries), **single events**, and **invitation responses** (`accept` / `decline` / `tentative`). Complements EWS **`calendar`** and **`respond`** when you need Graph IDs or REST-only flows. Requires **`Calendars.Read`** (read) or **`Calendars.ReadWrite`** (writes / responses).
758
+
759
+ ```bash
760
+ m365-agent-cli graph-calendar list-calendars
761
+ m365-agent-cli graph-calendar list-view --start 2026-04-01T00:00:00Z --end 2026-04-08T00:00:00Z
762
+ m365-agent-cli graph-calendar list-view --start ... --end ... --calendar <calendarId>
763
+ m365-agent-cli graph-calendar get-event <eventId>
764
+ m365-agent-cli graph-calendar accept <eventId> --comment "Will attend"
765
+ ```
766
+
767
+ ## SharePoint Commands
768
+
769
+ Manage SharePoint lists and Site Pages.
770
+
771
+ ### SharePoint Lists (`m365-agent-cli sharepoint` or `m365-agent-cli sp`)
772
+
773
+ ```bash
774
+ # List all SharePoint lists in a site
775
+ m365-agent-cli sp lists --site-id <siteId>
776
+
777
+ # Get items from a list
778
+ m365-agent-cli sp items --site-id <siteId> --list-id <listId>
779
+
780
+ # Create and update items
781
+ m365-agent-cli sp create-item --site-id <siteId> --list-id <listId> --fields '{"Title": "New Item"}'
782
+ m365-agent-cli sp update-item --site-id <siteId> --list-id <listId> --item-id <itemId> --fields '{"Title": "Updated Item"}'
783
+ ```
784
+
785
+ ### SharePoint Site Pages (`m365-agent-cli pages`)
786
+
787
+ ```bash
788
+ # List site pages
789
+ m365-agent-cli pages list <siteId>
790
+
791
+ # Get a site page
792
+ m365-agent-cli pages get <siteId> <pageId>
793
+
794
+ # Update a site page
795
+ m365-agent-cli pages update <siteId> <pageId> --title "New Title" --name "new-name.aspx"
796
+
797
+ # Publish a site page
798
+ m365-agent-cli pages publish <siteId> <pageId>
799
+ ```
800
+
801
+ ---
802
+
803
+ ## People & Room Search
804
+
805
+ ```bash
806
+ # Search for people
807
+ m365-agent-cli find "john"
808
+
809
+ # Search for rooms
810
+ m365-agent-cli find "conference" --rooms
811
+
812
+ # Only people (exclude rooms)
813
+ m365-agent-cli find "smith" --people
814
+ ```
815
+
816
+ ---
817
+
818
+ ## Additional commands
819
+
820
+ These commands are not expanded step-by-step above; use **`m365-agent-cli <command> --help`** for flags and examples.
821
+
822
+ | Command | What it does |
823
+ | --- | --- |
824
+ | **`forward-event`** (`forward`) | Forward a calendar invitation to more recipients (Graph). |
825
+ | **`graph-calendar`** | Graph **calendars**, **calendarView**, **get-event**, **accept** / **decline** / **tentative** (vs EWS `calendar` / `respond`). |
826
+ | **`counter`** (`propose-new-time`) | Propose a new time for an existing event (Graph). |
827
+ | **`schedule`** | Merged free/busy for one or more people over a time window (`getSchedule`). |
828
+ | **`suggest`** | Meeting-time suggestions via Graph (`findMeetingTimes`). |
829
+ | **`rooms`** | Search and filter room resources (capacity, equipment, floor, etc.). |
830
+ | **`oof`** | Mailbox out-of-office **settings** (Graph mailbox settings API). |
831
+ | **`auto-reply`** | EWS **inbox-rule** based auto-reply templates (distinct from `oof`). |
832
+ | **`rules`** | Inbox message rules (Graph). |
833
+ | **`delegates`** | Calendar/mailbox delegate permissions (EWS). |
834
+ | **`subscribe`** / **`subscriptions`** | Graph **change notifications** (create or list/cancel subscriptions). |
835
+ | **`serve`** | Local **webhook receiver** for subscription callbacks (pair with `subscribe`). |
836
+
837
+ ---
838
+
839
+ ## Examples
840
+
841
+ ### Morning Routine Script
842
+
843
+ ```bash
844
+ #!/bin/bash
845
+ echo "=== Today's Calendar ==="
846
+ m365-agent-cli calendar
847
+
848
+ echo -e "=== Unread Emails ==="
849
+ m365-agent-cli mail --unread -n 5
850
+
851
+ echo -e "=== Pending Invitations ==="
852
+ m365-agent-cli respond
853
+ ```
854
+
855
+ ### Quick Meeting Setup
856
+
857
+ ```bash
858
+ # Find a time when everyone is free and create the meeting
859
+ m365-agent-cli create-event "Project Kickoff" 14:00 15:00 \
860
+ --day tomorrow \
861
+ --attendees "team@company.com" \
862
+ --teams \
863
+ --find-room \
864
+ --description "Initial project planning session"
865
+ ```
866
+
867
+ ### Email Report with Attachment
868
+
869
+ ```bash
870
+ m365-agent-cli send \
871
+ --to "manager@company.com" \
872
+ --subject "Weekly Report - $(date +%Y-%m-%d)" \
873
+ --body "Please find this week's report attached." \
874
+ --attach "weekly-report.pdf"
875
+ ```
876
+
877
+ ### Shared Mailbox Operations
878
+
879
+ ```bash
880
+ # Check shared mailbox calendar
881
+ m365-agent-cli calendar --mailbox shared@company.com
882
+
883
+ # Send email from shared mailbox
884
+ m365-agent-cli send \
885
+ --to "team@company.com" \
886
+ --subject "Team Update" \
887
+ --body "..." \
888
+ --mailbox shared@company.com
889
+
890
+ # Read shared mailbox inbox
891
+ m365-agent-cli mail --mailbox shared@company.com
892
+
893
+ # Reply from shared mailbox
894
+ m365-agent-cli mail --reply 1 --message "Done!" --mailbox shared@company.com
895
+ ```
896
+
897
+ ---
898
+
899
+ ## Security practices
900
+
901
+ - **Graph search queries** and **markdown links** are validated/escaped where applicable
902
+ - **Date and email inputs** are validated before API calls
903
+ - **Token cache files** under `~/.config/m365-agent-cli/` are written with owner-only permissions where supported
904
+ - **String pattern replacement** avoids regex injection from malformed `$pattern` values
905
+
906
+ ---
907
+
908
+ ## Requirements
909
+
910
+ - [Bun](https://bun.sh) runtime
911
+ - Microsoft 365 account
912
+ - Azure AD app registration with EWS permissions (`EWS.AccessAsUser.All`)
913
+
914
+ ## License
915
+
916
+ MIT