CLAUDE.md - Development Guide
Guides AI assistants on building and testing a Windows-only CLI tool that automates Classic Outlook via COM.
What this file does
Guides AI assistants on building and testing a Windows-only CLI tool that automates Classic Outlook via COM.
When to use it
- You need a development guide for a CLI tool that talks to Outlook via COM
- You want to enforce a draft-first, safety-gated email workflow
- You are setting up a Claude Code Skill for email automation
- You need patterns for JSON output, error handling, and COM access in a Python project
Assumes this stack
CLAUDE.md - Development Guide
This document provides context for AI assistants (Claude) working on the outlookctl project.
Project Overview
outlookctl is a local CLI tool for automating Classic Outlook on Windows via COM automation. It includes a Claude Code Skill that enables AI-assisted email management.
Key Points
- Local automation only - No external APIs, no OAuth, no cloud services
- COM-based - Uses Windows COM (
Outlook.Application) via pywin32 - Classic Outlook required - New Outlook does not support COM
- Safety-first design - Draft-first workflow, explicit send confirmation
Architecture
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Claude Code │────▶│ outlookctl │────▶│ Classic Outlook │
│ (Skill) │ │ (Python CLI) │ │ (COM) │
└─────────────────┘ └──────────────────┘ └─────────────────┘
Module Responsibilities
| Module | Purpose |
|---|---|
cli.py | Argparse CLI entry point, command routing |
models.py | Dataclasses for JSON serialization |
outlook_com.py | COM automation wrapper, all Outlook interactions |
safety.py | Send confirmation gates, validation |
audit.py | Audit logging for send operations |
Running Commands
During Development
# From project directory
uv run python -m outlookctl.cli <command> [options]
# Examples
uv run python -m outlookctl.cli doctor
uv run python -m outlookctl.cli list --count 5
uv run python -m outlookctl.cli search --from "someone@example.com"
From Any Directory
uv run --project "C:/Users/GordonMickel/work/outlookctl" python -m outlookctl.cli <command>
Running Tests
uv run python -m pytest tests/ -v
Code Patterns
JSON Output
All commands output JSON via models.py dataclasses:
from outlookctl.models import ListResult, MessageSummary, FolderInfo
result = ListResult(
folder=FolderInfo(name="Inbox"),
items=[...],
)
print(json.dumps(result.to_dict(), indent=2))
Error Handling
Use ErrorResult for consistent error output:
from outlookctl.models import ErrorResult
def output_error(error: str, error_code: str = None, remediation: str = None):
result = ErrorResult(error=error, error_code=error_code, remediation=remediation)
print(json.dumps(result.to_dict(), indent=2))
sys.exit(1)
COM Access Pattern
Always use get_outlook_app() which handles retries and error messages:
from outlookctl.outlook_com import get_outlook_app, OutlookNotAvailableError
try:
outlook = get_outlook_app()
# Use outlook object...
except OutlookNotAvailableError as e:
output_error(str(e), "OUTLOOK_UNAVAILABLE")
Safety Gates
All send operations must go through safety validation:
from outlookctl.safety import validate_send_confirmation, SendConfirmationError
try:
validate_send_confirmation(confirm_send="YES")
except SendConfirmationError as e:
output_error(str(e), "CONFIRMATION_REQUIRED")
Skill System
Skill Location
- Personal:
~/.claude/skills/outlook-automation/ - Project:
.claude/skills/outlook-automation/
SKILL.md Structure
---
name: outlook-automation
description: >
Brief description for Claude to understand when to use this skill...
---
# Skill content with usage instructions...
Installing/Updating Skill
uv run python tools/install_skill.py --personal
Important Constraints
Never Auto-Send
The skill instructs Claude to always use draft-first workflow:
- Create draft with
draftcommand - Show preview to user
- Only send after explicit user confirmation
Metadata by Default
Body content should only be retrieved when explicitly requested:
listandsearchreturn metadata only by default- Use
--include-bodyor--include-body-snippetwhen needed
Confirmation Required
The send command requires --confirm-send YES (exact string match).
Common Development Tasks
Adding a New Command
-
Add command handler in
cli.py:def cmd_newcommand(args: argparse.Namespace) -> None: # Implementation -
Add subparser in
create_parser():new_parser = subparsers.add_parser("newcommand", help="...") new_parser.add_argument(...) new_parser.set_defaults(func=cmd_newcommand) -
Add result model in
models.pyif needed -
Update SKILL.md and reference docs
Adding COM Functionality
Add to outlook_com.py, following existing patterns:
- Use
get_outlook_app()for COM connection - Handle exceptions appropriately
- Return typed data (dataclasses from
models.py)
Updating the Skill
After any changes to CLI or behavior:
# Update skill files in skills/outlook-automation/
# Then reinstall:
uv run python tools/install_skill.py --personal
Testing
Unit Tests
uv run python -m pytest tests/ -v
Manual Testing
# Test doctor
uv run python -m outlookctl.cli doctor
# Test list
uv run python -m outlookctl.cli list --count 3
# Test search
uv run python -m outlookctl.cli search --unread-only --count 5
# Test draft (creates actual draft in Outlook)
uv run python -m outlookctl.cli draft --to "test@example.com" --subject "Test" --body-text "Test body"
Skill Testing
Start a new Claude Code session and test prompts:
- "Summarize my latest 5 unread emails"
- "Find emails from GitHub"
- "Draft a reply to the most recent email"
Troubleshooting
"Access is denied" on outlookctl.exe
The globally installed executable has permission issues in Git Bash. Use:
uv run python -m outlookctl.cli <command>
COM Connection Fails
- Ensure Classic Outlook is running
- Check it's not New Outlook (toggle at top-right)
- Run
doctorto diagnose
Tests Fail to Import
uv sync # Ensure dependencies are installed
File Locations
| File | Purpose |
|---|---|
pyproject.toml | Project config, dependencies |
src/outlookctl/ | Main Python package |
skills/outlook-automation/SKILL.md | Skill definition |
skills/outlook-automation/reference/ | Skill documentation |
tools/install_skill.py | Skill installer |
tests/ | pytest tests |
evals/ | Skill evaluation scenarios |
Dependencies
- pywin32 - Windows COM automation
- pytest (dev) - Testing
Version History
- 0.1.0 - Initial implementation
- CLI with doctor, list, get, search, draft, send, attachments save
- Claude Code Skill with safety guardrails
- Draft-first workflow, audit logging
What's inside
13 sections covering architecture, commands, code patterns, skill system, testing, troubleshooting, and file locations
Change this for your project
- Replace
C:/Users/GordonMickel/work/outlookctlwith your own project path - Replace
gmickel/outlookctlwith your own repository name - Replace
outlookctlwith your own package name throughout
Where it goes
Save as CLAUDE.md in your repository root. Claude Code reads it automatically at the start of every session.
Worth borrowing
- Draft-first workflow with explicit send confirmation as a safety pattern
- Using
ErrorResultdataclass for consistent JSON error output across all commands - Separating COM automation into a single wrapper module with retry logic
Related Documents
Code indexing for AI agents: summarization strategies and evaluation systems
Synthesises 2024-2025 research on code indexing for AI agents, covering summarisation strategies, hybrid retrieval architectures, and evaluation benchmarks.
write-script
Guides an AI through writing a YouTube video script with strict structural, language, and quiz rules for a survival channel.
Claude AI Git Workflow Integration
Recommends using the git-ai-commit CLI tool for AI-generated commit messages instead of manual ones.
Missing Business Agents Research — FLUXION 2026
Identifies 12 missing business operations agents for an indie software company and ranks them by impact and effort with €0 implementation plans.