atris/skills/email-agent/SKILL.md
Gmail integration via AtrisOS API. Read, send, archive emails. Use when user asks about email, inbox, or wants to send/check messages.
npx skillsauth add atrislabs/atris email-agentInstall 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.
Drop this in
~/.claude/skills/email-agent/SKILL.mdand Claude Code becomes your email assistant.
Before any email operation, run this bootstrap to ensure everything is set up:
#!/bin/bash
set -e
# 1. Check if atris CLI is installed
if ! command -v atris &> /dev/null; then
echo "Installing atris CLI..."
npm install -g atris
fi
# 2. Check if logged in to AtrisOS
if [ ! -f ~/.atris/credentials.json ]; then
echo "Not logged in to AtrisOS."
echo ""
echo "Option 1 (interactive): Run 'atris login' and follow prompts"
echo "Option 2 (non-interactive): Get token from https://atris.ai/auth/cli"
echo " Then run: atris login --token YOUR_TOKEN"
echo ""
exit 1
fi
# 3. Extract token (try node first, then python3, then jq)
if command -v node &> /dev/null; then
TOKEN=$(node -e "console.log(require('$HOME/.atris/credentials.json').token)")
elif command -v python3 &> /dev/null; then
TOKEN=$(python3 -c "import json,os; print(json.load(open(os.path.expanduser('~/.atris/credentials.json')))['token'])")
elif command -v jq &> /dev/null; then
TOKEN=$(jq -r '.token' ~/.atris/credentials.json)
else
echo "Error: Need node, python3, or jq to read credentials"
exit 1
fi
# 4. Check Gmail connection status (also validates token)
STATUS=$(curl -s "https://api.atris.ai/api/integrations/gmail/status" \
-H "Authorization: Bearer $TOKEN")
# Check for token expiry
if echo "$STATUS" | grep -q "Token expired\|Not authenticated"; then
echo "Token expired. Please re-authenticate:"
echo " Run: atris login --force"
echo " Or get new token from: https://atris.ai/auth/cli"
exit 1
fi
# Parse connected status
if command -v node &> /dev/null; then
CONNECTED=$(node -e "console.log(JSON.parse('$STATUS').connected || false)")
elif command -v python3 &> /dev/null; then
CONNECTED=$(echo "$STATUS" | python3 -c "import sys,json; print(json.load(sys.stdin).get('connected', False))")
else
CONNECTED=$(echo "$STATUS" | jq -r '.connected // false')
fi
if [ "$CONNECTED" != "true" ] && [ "$CONNECTED" != "True" ]; then
echo "Gmail not connected. Getting authorization URL..."
AUTH=$(curl -s -X POST "https://api.atris.ai/api/integrations/gmail/start" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{}')
if command -v node &> /dev/null; then
URL=$(node -e "console.log(JSON.parse('$AUTH').auth_url || '')")
elif command -v python3 &> /dev/null; then
URL=$(echo "$AUTH" | python3 -c "import sys,json; print(json.load(sys.stdin).get('auth_url', ''))")
else
URL=$(echo "$AUTH" | jq -r '.auth_url // empty')
fi
echo ""
echo "Open this URL to connect your Gmail:"
echo "$URL"
echo ""
echo "After authorizing, run your email command again."
exit 0
fi
echo "Ready. Gmail is connected."
export ATRIS_TOKEN="$TOKEN"
Important: Run this script ONCE before email operations. If it exits with instructions, follow them, then run again.
Base: https://api.atris.ai/api/integrations/gmail
All requests require: -H "Authorization: Bearer $TOKEN"
TOKEN=$(node -e "console.log(require('$HOME/.atris/credentials.json').token)")
curl -s "https://api.atris.ai/api/integrations/gmail/messages?query=in:inbox&max_results=20" \
-H "Authorization: Bearer $TOKEN"
Query syntax (Gmail search):
in:inbox — inbox onlyin:inbox newer_than:1d — today's emailsis:unread — unread onlyfrom:[email protected] — from specific sendersubject:invoice — subject contains wordhas:attachment — emails with attachmentscurl -s "https://api.atris.ai/api/integrations/gmail/messages/{message_id}" \
-H "Authorization: Bearer $TOKEN"
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/send" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": "[email protected]",
"subject": "Subject line",
"body": "Email body text"
}'
With CC/BCC:
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/send" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": "[email protected]",
"cc": "[email protected]",
"bcc": ["[email protected]", "[email protected]"],
"subject": "Subject line",
"body": "Email body text"
}'
Reply in thread (IMPORTANT — use this for all replies):
To reply within an existing email thread, you MUST pass thread_id and reply_to_message_id. Without these, Gmail creates a new thread.
# 1. First, get the message you're replying to (extract thread_id and id)
curl -s "https://api.atris.ai/api/integrations/gmail/messages/{message_id}" \
-H "Authorization: Bearer $TOKEN"
# Response includes: id, thread_id, subject, from, etc.
# 2. Send reply in the same thread
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/send" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": "[email protected]",
"subject": "Re: Original Subject",
"body": "Your reply text here",
"thread_id": "THREAD_ID_FROM_STEP_1",
"reply_to_message_id": "MESSAGE_ID_FROM_STEP_1"
}'
thread_id — The thread ID from the original message. Tells Gmail which thread to add this to.reply_to_message_id — The message ID you're replying to. The backend uses this to set In-Reply-To and References headers so Gmail threads it correctly.subject — Must match the original subject with "Re: " prefix.With attachments:
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/send" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": "[email protected]",
"subject": "With attachment",
"body": "See attached.",
"attachments": [{"filename": "report.txt", "content": "base64-encoded-content", "mime_type": "text/plain"}]
}'
List drafts:
curl -s "https://api.atris.ai/api/integrations/gmail/drafts?max_results=20" \
-H "Authorization: Bearer $TOKEN"
Read a draft:
curl -s "https://api.atris.ai/api/integrations/gmail/drafts/{draft_id}" \
-H "Authorization: Bearer $TOKEN"
Create a draft:
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/drafts" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": "[email protected]",
"subject": "Subject line",
"body": "Draft body text"
}'
Supports same fields as send: cc, bcc, attachments, plus thread_id to attach to an existing thread.
Update a draft:
curl -s -X PUT "https://api.atris.ai/api/integrations/gmail/drafts/{draft_id}" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": "[email protected]",
"subject": "Updated subject",
"body": "Updated body"
}'
Send a draft:
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/drafts/{draft_id}/send" \
-H "Authorization: Bearer $TOKEN"
Delete a draft:
curl -s -X DELETE "https://api.atris.ai/api/integrations/gmail/drafts/{draft_id}" \
-H "Authorization: Bearer $TOKEN"
# Mark as read
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/messages/{message_id}/read" \
-H "Authorization: Bearer $TOKEN"
# Mark as unread
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/messages/{message_id}/unread" \
-H "Authorization: Bearer $TOKEN"
# Single message
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/messages/{message_id}/archive" \
-H "Authorization: Bearer $TOKEN"
# Batch archive
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/messages/batch-archive" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"message_ids": ["id1", "id2", "id3"]}'
# Single message
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/messages/{message_id}/trash" \
-H "Authorization: Bearer $TOKEN"
# Batch trash
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/messages/batch-trash" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"message_ids": ["id1", "id2", "id3"]}'
curl -s "https://api.atris.ai/api/integrations/gmail/status" \
-H "Authorization: Bearer $TOKEN"
curl -s -X DELETE "https://api.atris.ai/api/integrations/gmail" \
-H "Authorization: Bearer $TOKEN"
GET /messages?query=in:inbox%20newer_than:1d&max_results=20POST /send with {to, subject, body}GET /messages/{message_id} — extract id, thread_id, from, subjectPOST /send with {to, subject: "Re: ...", body, thread_id, reply_to_message_id}thread_id matches original thread_id (if it doesn't, something went wrong)GET /messages?query=in:inbox&max_results=50POST /batch-archiveGET /gmail/drafts?max_results=20POST /gmail/drafts with {to, subject, body}GET /gmail/draftsPOST /gmail/drafts/{draft_id}/sendGET /messages?query=from:{sender}Safe to suggest archiving:
noreply@, notifications@, newsletter@, no-reply@NEVER auto-archive (always keep):
Always ask before archiving. Never archive without explicit user approval.
| Error | Meaning | Solution |
|-------|---------|----------|
| Token expired | AtrisOS session expired | Run atris login |
| Gmail not connected | OAuth not completed | Re-run bootstrap, complete OAuth flow |
| 401 Unauthorized | Invalid/expired token | Run atris login |
| 400 Gmail not connected | No Gmail credentials | Complete OAuth via bootstrap |
| 429 Rate limited | Too many requests | Wait 60s, retry |
| Invalid grant | Google revoked access | Re-connect Gmail via bootstrap |
Local token (~/.atris/credentials.json): Your AtrisOS auth token, stored locally with 600 permissions. Same model as AWS CLI, GitHub CLI.
Gmail credentials: Your Gmail refresh token is stored server-side in AtrisOS encrypted vault. Never stored on your local machine.
Access control: AtrisOS API enforces that you can only access your own email. No cross-user access possible.
OAuth scopes: Only requests necessary Gmail permissions (read, send, modify labels).
HTTPS only: All API communication encrypted in transit.
# Setup (one time)
npm install -g atris && atris login
# Get token
TOKEN=$(node -e "console.log(require('$HOME/.atris/credentials.json').token)")
# Check connection
curl -s "https://api.atris.ai/api/integrations/gmail/status" -H "Authorization: Bearer $TOKEN"
# List inbox
curl -s "https://api.atris.ai/api/integrations/gmail/messages?query=in:inbox&max_results=10" -H "Authorization: Bearer $TOKEN"
# Send new email
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/send" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"to":"[email protected]","subject":"Hi","body":"Hello!"}'
# Reply in thread (pass thread_id + reply_to_message_id)
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/send" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"to":"[email protected]","subject":"Re: Original","body":"Reply text","thread_id":"THREAD_ID","reply_to_message_id":"MSG_ID"}'
# List drafts
curl -s "https://api.atris.ai/api/integrations/gmail/drafts" -H "Authorization: Bearer $TOKEN"
# Create draft
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/drafts" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"to":"[email protected]","subject":"Hi","body":"Draft text"}'
# Mark as read
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/messages/{message_id}/read" -H "Authorization: Bearer $TOKEN"
# Trash an email
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/messages/{message_id}/trash" -H "Authorization: Bearer $TOKEN"
# Send a draft
curl -s -X POST "https://api.atris.ai/api/integrations/gmail/drafts/{draft_id}/send" \
-H "Authorization: Bearer $TOKEN"
testing
Detects AI slop and fixes it, especially in memos, docs, READMEs, messages, PRDs, and other written output. Based on Wikipedia's AI Cleanup patterns plus memo-specific anti-slop rules. Triggers on "copy edit", "review writing", "humanize", "deslopper", "ai patterns", "make it sound human", "AI slop", "anti-slop", "memo".
tools
Use when an agent needs to inspect or send local macOS iMessage through Atris CLI. Triggers on iMessage, Messages.app, local text messages, chat.db, or texting someone from the user's Mac.
databases
Submit, list, resolve, close, or delete Atris customer feedback. Use when user types /feedback or asks to triage the feedback queue.
development
Fast research sweep — arxiv, semantic scholar, github, web. Finds papers, scores relevance, extracts actionable insights, stores to wiki. Triggers on: research search, find papers, latest research, arxiv, what's new in, sweep papers, research sweep.