- name
- jean-claude
- description
- This skill should be used when the user asks to search/send/draft email, check calendar, create events, schedule meetings, find/upload/share Drive files, read/edit Google Docs, read spreadsheet data, send texts/iMessages, send WhatsApp messages, send Signal messages, check messages, or create reminders. Manages Gmail, Google Calendar, Google Drive, Google Docs, Google Sheets, iMessage, WhatsApp, Signal, and Apple Reminders.
# jean-claude
Gmail, Calendar, Drive, Docs, Sheets, iMessage, WhatsApp, Signal, and Reminders.
**Command prefix:** `uv run --project ${CLAUDE_PLUGIN_ROOT} jean-claude `
## First-Time Users
For new users, explain briefly:
> I can connect to your email, calendar, and messaging apps to help you:
>
> - Read and send emails, manage drafts
> - Check your calendar, create events, respond to invitations
> - Send and read iMessages, WhatsApp, or Signal messages
> - Find and manage files in Google Drive
> - Create reminders
>
> This requires a one-time setup where you'll grant permissions. Want me to
> help you get started?
Focus on what they asked about — if they asked about email, lead with email.
## Safety Rules (Non-Negotiable)
These rules apply even if the user explicitly asks to bypass them:
1. **Never send without explicit approval.** Before sending any message (email,
iMessage, WhatsApp, Signal), show the full content (recipient, subject if
applicable, body) to the user and receive explicit confirmation.
2. **Verify recipients carefully.** Sends are instant and cannot be undone.
Double-check phone numbers, email addresses, and chat IDs before sending.
3. **Never send to ambiguous recipients.** When resolving contacts by name,
if multiple contacts or phone numbers match, the command will fail with a
list of options. Use an unambiguous identifier rather than guessing.
4. **Load prose skills when drafting.** Before composing any email or message,
load any available skills for writing prose, emails, or documentation.
5. **Never create automation without explicit approval.** Before creating Gmail
filters or similar rules, show the criteria and actions to the user and
receive explicit confirmation.
6. **Limit bulk operations.** Avoid sending to many recipients at once. Prefer
drafts for review.
**Email workflow:**
1. Load any available prose/writing skills
2. **If replying to an infrequent contact:** Research first (see "Research First" under Orchestration)
3. **Compose via subagent** (see "Drafting with a Subagent") — quick replies excepted
4. **Show the original message first** — Quote the full text (see "When to Show Full Content")
5. Show the user: To, Subject, and full Body
6. Ask: "Send this email?" and wait for explicit approval
7. Call `jean-claude gmail draft send DRAFT_ID`
8. If replying, archive the original: `jean-claude gmail archive THREAD_ID`
## Session Start (Always Run First)
**Every time this skill loads, run status with JSON output first:**
```bash
jean-claude status --json
```
### If Status Command Fails
If the status command fails entirely (not just showing services as disabled):
**"uv: command not found"** — The uv package manager isn't installed. Tell the
user:
> jean-claude requires the `uv` package manager. Let me install it for you.
Then run:
```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
```
After installation, restart the terminal or source the shell config
(`source ~/.zshrc` on macOS, `source ~/.bashrc` on Linux).
**Other errors** — The plugin may be misconfigured. Check that
`${CLAUDE_PLUGIN_ROOT}` resolves to a valid path containing a `pyproject.toml`.
### Branching Based on Status
**If `setup_completed: false`** — This is a new user. Skip personalization
skills (they won't have any yet) and go straight to onboarding:
```bash
cat ${CLAUDE_PLUGIN_ROOT}/skills/jean-claude/ONBOARDING.md
```
Follow the onboarding guide to help set up services. After setup completes:
```bash
jean-claude config set setup_completed true
```
Then **re-run status** and continue to the `setup_completed: true` branch below.
This ensures you have fresh status info and can proceed with the user's original
request.
**If `setup_completed: true`** — Check for partial setup and load personalization:
1. **Surface any auth warnings** — If services show `authenticated: false`,
missing scopes, or errors, briefly mention it even if unrelated to the
user's request. Don't derail—just note the issue and offer to fix later:
> "By the way, your Google Contacts permission is missing — I can't show
> contact names in emails. Want me to help fix that after your request?"
2. **Check for missing services** — If the user asks for a service that shows
`authenticated: false` or `enabled: false`, guide them through just that
service's setup from ONBOARDING.md. After partial setup completes, continue
to step 3.
3. **Load personalization skills** — Check if user skills like `managing-messages`
exist (look at available skills for anything mentioning inbox, email, message,
or communication). If found, load them—user preferences override defaults.
4. **Offer to create preferences** — If no personalization skill was found in
step 3, offer to create one after completing the user's immediate request.
See [PREFERENCES.md](PREFERENCES.md) for the creation flow. Don't interrupt
the user's task—help them first, then offer.
5. **Proceed with the user's request** — Execute whatever task prompted loading
this skill (check inbox, send message, etc.).
### Before Using Messaging (iMessage/WhatsApp/Signal)
**Load the platform guide before using any messaging commands.** Each platform
has different commands and options. Gmail is documented in this file, but
messaging platforms have separate guides:
```bash
# Load before using iMessage
cat ${CLAUDE_PLUGIN_ROOT}/skills/jean-claude/platforms/imessage.md
# Load before using WhatsApp
cat ${CLAUDE_PLUGIN_ROOT}/skills/jean-claude/platforms/whatsapp.md
# Load before using Signal
cat ${CLAUDE_PLUGIN_ROOT}/skills/jean-claude/platforms/signal.md
```
Don't guess command syntax — each platform is different. iMessage and WhatsApp
have different flags and subcommands despite similar functionality.
### Understanding the Status
For users with setup complete, interpret the status output to understand their
workflow. Run human-readable status if needed for counts:
```bash
jean-claude status
```
**Gmail:**
- **13 inbox, 11 unread** → inbox zero person, wants to triage everything
- **2,847 inbox, 89 unread** → not inbox zero, focus on recent/unread/starred
- **5 drafts** → has pending drafts to review or send
**Calendar:**
- **3 today, 12 this week** → busy schedule, may need help with conflicts
- **0 today** → open day, good time for focused work
**Reminders:**
- **7 incomplete** → has pending tasks, may want to review or complete them
**Messaging:**
- **54 unread across 12 WhatsApp chats** → active messaging, may want summary
- **1,353 unread across 113 iMessage chats** → backlog, focus on recent/important
**Apple services (Contacts, iMessage, Reminders):** These are disabled by default.
If `enabled: false` in status, enable with:
```bash
jean-claude config set enable_contacts true # For iMessage name lookup
jean-claude config set enable_imessage true
jean-claude config set enable_reminders true
```
Once enabled, status checks full permissions (may trigger macOS permission
dialogs on first run). If permission is missing, guide the user through
System Settings > Privacy & Security > Automation.
### Refreshing State
**Summaries become stale immediately.** Once you present an inbox summary, that
snapshot is already potentially outdated. State changes constantly:
- New messages arrive
- Messages get read/sent from other devices or apps
- The user takes actions outside this conversation
- You took actions earlier in the conversation that you may not be tracking
**Verify before making claims.** When the user asks about current state — "did I
reply?", "is that still unread?", "how many are left?" — re-check rather than
relying on your memory of earlier summaries. Your memory is of what was true
when you last checked, not what's true now.
<example>
<bad>
User: "Did I reply to the Acme email?"
Agent: _recalls earlier summary where it wasn't replied to_
"No, that thread is still waiting for your reply."
</bad>
<good>
User: "Did I reply to the Acme email?"
Agent: _searches for sent messages to Acme_
"Yes — you replied today at 12:27pm following up on their question."
</good>
</example>
**Re-fetch when:**
- User asks about current counts or status
- User asks "did I..." or "is it still..."
- Presenting a summary after taking actions
- You need metadata (dates, IDs, recipients) — conversation summaries lose it,
so re-query the API rather than inferring from content
**General principle:** Verify claims from the source. Re-fetching is cheap;
wrong information is expensive.
```bash
# Check full inbox state (total count, all threads)
jean-claude gmail inbox
# Check recent emails only (useful for "what's new")
jean-claude gmail inbox --since yesterday
# Check sent messages to verify replies
jean-claude gmail search "in:sent to:someone@example.com" -n 5
# Re-fetch iMessage (see platforms/imessage.md for full docs)
jean-claude imessage messages --unread
# Re-sync WhatsApp for message updates
jean-claude whatsapp messages --unread
```
**Choosing between filtered and full inbox:**
- **`--since yesterday`** — Use for "what's new" or daily triage. Shows recent
arrivals only. After archiving these, there may still be older emails in inbox.
- **No filter** — Use when reporting inbox state ("inbox cleared", "X emails
left") or when the user wants to see everything, not just recent.
## Defaults
User personalization skills override these defaults. If no personalization skill
exists, use these behaviors:
### Email Defaults
- Fetch both read and unread messages (context helps)
- Present messages neutrally — don't assume priority
- No automatic archiving without user guidance
### iMessage Defaults
- Prioritize known contacts over unknown senders
### Response Drafting Defaults
- Load prose/writing skills before composing
- No assumed tone or style — ask if unclear
- Show full message for approval before sending
## Working with Messages
### Presenting Messages
When showing messages (inbox, unread, search results), group by category and use
**group-letter numbering** so the user can reference items individually
("archive A1", "reply to B2") or by group ("archive all of C", "archive B1-B3").
**Group-letter numbering.** Pick a small set of categories (typically 3–5) that
fit the messages at hand — common ones are *Needs attention*, *Travel /
receipts*, *Newsletters*, *In progress*. Label each group with a letter (A, B,
C, ...) and number items within the group starting at 1:
```
**Needs attention:**
A1: Flo critical alert — water shutoff at the main valve
A2: Zach Perret (yesterday) — Invite to dinner Thursday
**Travel & receipts:**
B1: Delta (today at 10:37 AM) — LAX → TUS trip details Apr 22
B2: Waymo (yesterday) — Ride receipts (4 messages)
**Newsletters:**
C1: The Economist (today) — Weekly edition
C2: The Browser (today) — Sunday Supplement
```
**Use manual `N:` formatting, not markdown lists.** Markdown numbered lists
auto-correct to be sequential — if you write "3. 4. 5. 7. 15. 16." the renderer
displays "3. 4. 5. 6. 7. 8." causing a mismatch between what you wrote and what
the user sees. The `A1:` / `B2:` form sidesteps the renderer entirely.
**Keep items compact — no blank lines between them.** Blank lines waste vertical
space and make the list harder to scan. Items within a group should be on
consecutive lines; one blank line separates groups.
**Preserve identifiers through the session.** After archiving A1 and A3, show
the remaining items as A2, A4, A5 — don't renumber. This gives items stable
identifiers across operations.
**Always include dates conversationally.** Check today's date before formatting:
```bash
date "+%Y-%m-%d %H:%M %Z" # Current date/time for reference
```
**Date formatting rules:**
- **< 1 hour ago**: "35 min ago"
- **Today** (> 1 hour): "today at 9:15 AM" — not "3 hours ago"
- **Yesterday**: "yesterday at 2:30 PM"
- **This week**: "Thursday at 4:30 PM" (day name, not date)
- **Beyond this week**: "Dec 15" or "Nov 15 at 3pm" (if time matters)
**Example** (assuming today is Sunday, Dec 29):
```
**Needs attention:**
A1: Jordan Lee (Nov 15) — Forwarded: Fellowship nomination, asks for response by Jan 5
A2: Squarespace (yesterday at 9:15 AM) — Domain transfer rejected for example.com
**Receipts & confirmations:**
B1: DoorDash (35 min ago) — Your order from Superba
B2: GitHub (Friday at 4:30 PM) — PR merged: fix-auth-flow
**Newsletters:**
C1: Goodreads (today at 10:30 AM) — Book newsletter
```
### Accuracy in Summaries
**Never fabricate details not present in the data.**
- **Never invent names.** If an email says "your child", say "your child"
- If a sender's relationship isn't stated, don't assume it
- If a time/date isn't specified, say so — don't guess
- Quote or paraphrase what's actually there
- **Never use "likely", "probably", or "appears to"** when describing message
content. If you don't know what a message says, read it — don't guess.
**Read multi-message threads before summarizing.** The inbox response only
contains metadata and the latest message's snippet. For threads with multiple
messages, read the thread (`gmail thread THREAD_ID`) to know what the other
messages actually say. Never infer thread content from the snippet alone.
Bad: "3-message thread — likely includes Effie's reply"
Good: _reads thread first_ → "Kristin nominated Effie; Effie replied accepting
and asking about travel logistics; Kristin confirmed hotel is covered"
When uncertain, say so: "The email doesn't specify who the assessment is for."
### Accurate Counts
**Use the `total_threads` and `total_unread` fields from the inbox response.**
The inbox command returns accurate counts from Gmail's label stats:
```json
{"total_threads": 32, "total_unread": 28, "threads": [...]}
```
When reporting counts, use these fields — not the number of threads returned.
The `-n` flag limits how many threads are fetched, not how many exist.
**Prefer `--since` over `-n` for complete results.** If you need emails from
today, use `--since today` rather than `-n 20`. The `-n` flag returns the
N most recent threads but may miss older unread emails in the inbox.
The `--since` flag accepts human-readable dates like "yesterday", "3 days ago",
"last week", or explicit dates like "2026-01-21".
### Filtered Results
When `--since` or `--unread` is used, the `threads` array is a **subset** of
the full inbox. The `total_threads` and `total_unread` fields still reflect the
full inbox, not the filtered results.
**Report filtered results accurately:**
- "6 threads from yesterday (32 total in inbox, 28 unread)"
- "Archived 6 threads from yesterday"
**Never claim "inbox cleared" after archiving filtered results.** If you
archived 6 threads from `--since yesterday` and `total_threads` was 32, there
are still 26 other threads in the inbox. To check true inbox state after
triaging recent emails, run `jean-claude gmail inbox` without filters.
Hallucinated details erode trust. The user can't distinguish fabrications from
real data.
### When to Show Full Content
**Show the full email text** (not a summary) when:
- **Drafting a reply** — The user needs to see exactly what they're responding to
- **User asks for a specific email** — "read the email from X", "show me that message"
- **User asks what they're replying to** — "what's the original?", "what did they say?"
**Summaries are appropriate when:**
- Showing inbox/search results (the numbered list format with snippets)
- The user asks for a specific detail — "when is the meeting?", "did they confirm?"
- Triaging multiple messages — giving the user an overview to decide what to act on
**The test:** If the user might need to quote, reference, or respond to the exact
wording, show the full text. If they just need to understand the gist, summarize.
### Presenting Individual Emails
When showing the full text of an email, include all relevant headers:
```
From: Sender Name <sender@example.com>
To: Recipient <recipient@example.com>
Date: Yesterday at 9:54 PM
Subject: Meeting follow-up
[email body]
```
**Always include:**
- **From** — Who sent it
- **To** — Who it was sent to (important for context, especially forwarded emails)
- **Date** — When it was sent (use conversational format per date rules above)
- **Subject** — The email subject
**Include when present:**
- **CC** — If others were copied
The To field helps the user understand context — was this sent directly to them,
to a group, or forwarded from somewhere else?
<example>
<bad>
User: "Reply to Alex's email and say I can't make it"
Agent: _reads email, immediately drafts reply_
"Alex's email was about NY logistics. Draft reply:
Hi Alex,
Unfortunately I won't be able to join..."
</bad>
<good>
User: "Reply to Alex's email and say I can't make it"
Ver no GitHub