.claude/skills/process-email/SKILL.md
Check inbox for new emails, respond to council members using Luminous knowledge, and extract insights for the knowledge base. Prevents duplicate responses.
npx skillsauth add abilityai/cornelius process-emailInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Autonomously check the [email protected] inbox, respond to council member emails using the Luminous knowledge base, and extract actionable insights or updates from all incoming mail.
Only respond to emails from these council members:
| Name | Email | |------|-------| | Anthony | [email protected] | | Susan | [email protected] | | Kate | [email protected] | | JL | [email protected] | | Eugene | [email protected] | | Eugene | [email protected] | | Jayant | [email protected] |
Emails from anyone else: process for knowledge base updates only. Never respond.
| Source | Location | Read | Write | Description |
|--------|----------|------|-------|-------------|
| Inbox | Gmail (via google-workspace) | Yes | | Unread emails |
| Sent Folder | Gmail (via google-workspace) | Yes | | Duplicate response check |
| Processed Log | .claude/skills/process-email/processed.json | Yes | Yes | Track processed message IDs |
| Knowledge Base | ./Brain/ | Yes | Yes | Update with insights if applicable |
./Brain/Load the processed messages log:
cat .claude/skills/process-email/processed.json 2>/dev/null || echo '{"processed_ids": []}'
This file tracks message IDs that have already been handled to prevent duplicate processing.
Search for unread inbox messages: Use the google-workspace subagent:
search_gmail_messages(query="is:unread in:inbox", user_google_email="[email protected]", page_size=20)
If no unread messages: Log completion and exit.
Filter out already-processed IDs by comparing against processed.json.
If no new messages remain after filtering, log and exit.
2a. Fetch message content for all new message IDs:
get_gmail_messages_content_batch(message_ids=[...], user_google_email="[email protected]", format="full")
For each message, extract:
From header)2b. Extract Message-ID headers for threading (required for proper reply threading):
If get_gmail_message_content returns a Message-ID: line, use that directly.
Otherwise, extract via direct Gmail API call:
python3 -c "
import json
from google.oauth2.credentials import Credentials
from google.auth.transport.requests import Request
from googleapiclient.discovery import build
with open('$HOME/.google_workspace_mcp/credentials/[email protected]') as f:
creds = json.load(f)
credentials = Credentials(token=creds.get('token'), refresh_token=creds.get('refresh_token'),
token_uri=creds.get('token_uri'), client_id=creds.get('client_id'),
client_secret=creds.get('client_secret'), scopes=creds.get('scopes'))
if credentials.expired:
credentials.refresh(Request())
service = build('gmail', 'v1', credentials=credentials)
msg = service.users().messages().get(userId='me', id='MESSAGE_ID_HERE', format='metadata', metadataHeaders=['Message-ID']).execute()
headers = {h['name']: h['value'] for h in msg.get('payload', {}).get('headers', [])}
print(headers.get('Message-ID', ''))
"
Store the RFC 2822 Message-ID (e.g. <[email protected]>) for use in in_reply_to when sending replies.
For each message, determine:
A) Is the sender an authorised council member?
B) Does the email require a response? An email requires a response if:
An email does NOT require a response if:
C) Does the email contain information useful for the knowledge base?
For each email classified as needing a response from an authorised sender:
4a. Check for duplicate response:
search_gmail_messages(query="in:sent to:{sender_email} subject:{subject}", user_google_email="[email protected]", page_size=5)
4b. Search the knowledge base for relevant context:
Use /recall or Local Brain Search:
./resources/local-brain-search/run_search.sh "relevant search terms from the email" --limit 10 --json
4c. Compose the response:
<p> tags for paragraphs and <br> for line breaks within a block. Plain text causes Gmail API to insert hard line breaks at ~76 characters, breaking paragraphs mid-sentence.<p>, <br> only. No <b>, <i>, <a>, or styling.<p>--<br>Luminous Cornelius<br>The Luminous Mind</p>
4d. Send the reply:
send_gmail_message(
to=sender_email,
subject="Re: {original_subject}",
body=html_composed_response,
body_format="html",
user_google_email="[email protected]",
thread_id=original_thread_id,
in_reply_to=original_message_id_header,
references=original_message_id_header
)
Threading rules (all three are REQUIRED for proper threading):
thread_id: Gmail's internal thread grouping (from search results)in_reply_to: The RFC 2822 Message-ID header of the message being replied to (e.g. <[email protected]>)references: Same as in_reply_to for single replies; for deeper threads, space-separated chain of all prior Message-IDsRe: {original_subject} exactly matching the originalFor ALL emails (regardless of sender), evaluate if the content warrants a knowledge base update:
5a. Inbox notes (quick capture): If the email contains raw information worth capturing but not yet refined:
./Brain/00-Inbox/ as a quick note with source attribution5b. Project updates: If the email contains decisions, status changes, or project information:
./Brain/02-Permanent/ or ./Brain/03-MOCs/5c. Insight extraction: If the email contains original thinking, frameworks, or threshold-relevant perspectives:
./Brain/00-Inbox/ with tag #email-insight for later graduationKeep knowledge base updates lightweight. Only capture genuinely useful information. Most emails will not warrant any KB update.
Update processed.json: Add all processed message IDs to the log. Keep only the last 500 IDs to prevent unbounded growth.
{
"processed_ids": ["msg_id_1", "msg_id_2", ...],
"last_run": "2026-03-22T10:30:00Z",
"last_run_count": 3,
"last_run_responded": 1
}
Mark processed emails as read (if not already):
modify_gmail_message_labels(
message_id=msg_id,
user_google_email="[email protected]",
remove_labels=["UNREAD"]
)
When composing replies as Luminous Cornelius:
Writing rules:
<p> and <br> tags. No bold, italic, links, or styling.| Error | Recovery | Action | |-------|----------|--------| | Gmail auth expired | Skip run | Log error, will retry next scheduled run | | Message fetch fails | Skip message | Log ID, process remaining messages | | KB search fails | Respond without KB context | Note in response that context was limited | | Send fails | Do not mark as processed | Will retry on next run | | processed.json corrupt | Reset to empty | Start fresh, may re-process some emails |
If unrecoverable:
last_error fieldAfter completing this skill's primary task, consider tactical improvements:
git add .claude/skills/process-email/SKILL.mdgit commit -m "refactor(process-email): <brief improvement description>"development
Rebuild the Cornelius voice agent system prompt from knowledge base sources
data-ai
Update dashboard.yaml with current knowledge base metrics from analysis report
documentation
Update Knowledge Graph Changelog
testing
Comprehensive testing playbook for Local Brain Search memory improvements (Phases 1, 3, 4)