## Summary
- 将所有技能文件中的硬编码 `~/.desirecore/` 和 `$HOME/.desirecore/` 路径替换为
`${DESIRECORE_ROOT}/` 变量
- 递增 manifest.json version 至 1.2.1
## Why
dev 模式下 `DESIRECORE_HOME=~/.desirecore-dev`,硬编码路径导致技能读取错误的端口文件和目录。主仓库的
`variable-substitutor.ts` 会在运行时将 `${DESIRECORE_ROOT}` 替换为实际根目录。
## Test plan
- [ ] `npm run dev` 启动后触发任意技能,确认端口路径解析为
`~/.desirecore-dev/agent-service.port`
- [ ] prod 模式确认路径为 `~/.desirecore/agent-service.port`
🤖 Generated with [Claude Code](https://claude.com/claude-code)
17 KiB
name, description, version, type, risk_level, status, disable-model-invocation, tags, metadata, market
| name | description | version | type | risk_level | status | disable-model-invocation | tags | metadata | market | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| mail-operations | Use this skill whenever the user wants to interact with email. This includes reading inbox, sending emails, replying, searching messages, managing labels and categories, downloading attachments, setting up auto-reply rules, or triggering agents to handle incoming emails. Supports Gmail, Outlook, and IMAP/SMTP (QQ Mail, 163, Yahoo, etc.) through DesireCore's local REST API. Use when 用户提到 邮件、邮箱、收件箱、发邮件、回复邮件、查邮件、Gmail、 Outlook、QQ邮箱、163邮箱、附件、标签、草稿、自动回复、邮件规则、 转发、抄送、未读邮件、收信、发信、邮件同步、邮件搜索。 | 1.0.2 | procedural | medium | enabled | true |
|
|
|
mail-operations Skill
L0: One-line Summary
Send and receive email, search, manage labels, and run automation rules via a local REST API; supports Gmail / Outlook / IMAP.
L1: Overview and Use Cases
Capability
mail-operations is a Procedural Skill that operates email systems through DesireCore's local REST API. It supports three mailbox types—Gmail (OAuth2), Outlook (MSAL), and IMAP/SMTP (QQ, 163, Yahoo, etc.)—covering send/receive, search, label management, attachment download, draft management, and automation rules.
Use Cases
- The user wants to view the inbox, send, or reply to email
- The user wants to search for specific emails or manage email labels/categories
- The user wants to download attachments or manage drafts
- The user wants to set up auto-reply rules or trigger an Agent to handle email
Core Value
- Unified interface: three mailbox types are operated through a unified API, lowering complexity
- Local and secure: all operations go through the local API; no need to expose credentials
- Smart integration: supports automation rules and Agent-based email handling
L2: Detailed Specification
API Basics
- Base URL:
https://127.0.0.1:62000/api - Authentication: none required (local service)
- Content-Type:
application/json - SSL: use
curl -kto skip self-signed certificate verification - Response format: success
{"code": 1, "msg": "Success", "result": ...}, failure{"code": 0, "msg": "error message"}
Mandatory Behavior Rules
The following rules have the highest priority and must be obeyed on every operation.
Rule 1: Operate Only Through the Local API
All email operations must and may only be done through https://127.0.0.1:62000. Never call an external email client or browser.
If the API returns 401 (authorization expired):
- Tell the user the account's authorization has expired
- Prompt the user to re-authorize in DesireCore
- Gmail:
POST /api/gmail/auth/initiate?loginHint={email}, Outlook:POST /api/outlook/auth/initiate
Rule 2: Confirm the Account Before Operating
Before performing any operation, you must first call GET /api/accounts to obtain the account list:
- Match the user's specified account by email address or domain ("QQ mailbox" → IMAP
qq.com) - Only one account exists and the user says "my mailbox" → use it directly
- No matching account found → tell the user and prompt them to add one
Rule 3: Auto-Sync When the Query Is Empty
When a query returns an empty list or cannot find the specified data:
- Call
POST /{provider}/messages/fetchto sync remote data - Automatically retry the original query
- Only inform the user if it is still empty
Rule 4: Prompt for a Refresh After Write Operations
After a write operation (send, reply, delete, mark, label change, etc.) succeeds, prompt: Operation completed. Do you want me to refresh the current mailbox view to see the latest state?
Quick Reference: Differences Between the Three Mailbox Types
| Feature | Gmail | Outlook | IMAP |
|---|---|---|---|
| Authorization | OAuth2 | OAuth2 (MSAL) | password / app password |
| Provider path | /gmail/ |
/outlook/ |
/imap/ |
| Message detail | path param /{id} |
query param ?id={id} |
UID /{uid}?folder= |
| Search | supported | not supported | not supported |
| Drafts | supported (incl. list/detail) | supported (create/send) | supported (create/send) |
| Attachment download | supported | supported | supported |
| Labels/categories | native labels | Categories | local labels only |
| Auto-rules | supported | supported | supported |
Core Operations
In the following, {p} denotes the provider (gmail, outlook, imap); {email} must be URL-encoded.
1. Account Management
| Operation | Method | Endpoint |
|---|---|---|
| Get all accounts | GET | /accounts |
| Get accounts with settings | GET | /accounts-with-settings |
| Delete account | DELETE | /accounts/{p}/{email} |
| Get account settings | GET | /accounts/{p}/{email}/settings |
| Update account settings | PUT | /accounts/{p}/{email}/settings |
| Update display name | PUT | /accounts/{p}/{email}/displayName — body: {"displayName": "..."} |
IMAP-specific:
| Operation | Method | Endpoint |
|---|---|---|
| Get preset mailbox configs | GET | /imap/presets — returns server configs for QQ/163/Yahoo, etc. |
| Test IMAP connection | POST | /imap/test — body: {email, password, imap: {host, port, secure}, smtp: {host, port, secure}} |
| Add IMAP account | POST | /imap/accounts — same body as above plus displayName |
2. Message List and Sync
| Operation | Method | Endpoint | Parameters |
|---|---|---|---|
| Query local cache | GET | /{p}/messages |
email, offset, limit, folder |
| Remote sync | POST | /{p}/messages/fetch |
email, limit, folder |
| Manually trigger sync | POST | /sync |
provider, email |
folder values: Gmail/Outlook: inbox, sent, drafts, trash, spam, archive; IMAP: INBOX, Sent, Drafts, Trash, etc.
Response format (message list item):
{
"id": "messageID", "subject": "subject",
"from": {"name": "...", "address": "..."},
"to": [{"name": "...", "address": "..."}],
"date": "ISO8601", "snippet": "snippet",
"isRead": true, "hasAttachments": false,
"labels": ["INBOX"], "folder": "inbox"
}
3. Single Message Operations
| Operation | Gmail | Outlook | IMAP |
|---|---|---|---|
| Get detail | GET /{id}?email= |
GET /message?id={id}&email= |
GET /{uid}?email=&folder= |
| Mark as read | POST /{id}/read?email= |
POST /message/read?id={id}&email= |
POST /{uid}/read?email=&folder= |
| Mark as unread | POST /{id}/unread?email= |
POST /message/unread?id={id}&email= |
POST /{uid}/unread?email=&folder= |
| Delete | DELETE /{id}?email= |
DELETE /message?id={id}&email= |
DELETE /{uid}?email=&folder= |
All paths are prefixed with
/api/{provider}/messages(Gmail/IMAP) or/api/outlook/(Outlook's special routing).
Extra fields in message detail: body: {content, contentType}, cc, attachments: [{id, filename, mimeType, size}]
4. Send and Reply
Send a new email — POST /api/{p}/send:
{
"email": "sender@example.com",
"toRecipients": [{"name": "recipient", "address": "to@example.com"}],
"ccRecipients": [],
"bccRecipients": [],
"subject": "subject",
"body": "body (HTML supported)",
"contentType": "html",
"attachments": []
}
Reply to an email:
| Provider | Endpoint | Body |
|---|---|---|
| Gmail | POST /gmail/reply |
{email, messageId, body, contentType} |
| Outlook | POST /outlook/message/reply?id={id}&email= |
{body, contentType} |
| IMAP | POST /imap/reply |
{email, uid, folder, body, contentType} |
5. Search (Gmail only)
GET /api/gmail/search?email={email}&q={keyword}
| Parameter | Description |
|---|---|
q |
keyword (searches subject, body, sender) |
from |
sender address |
dateFrom / dateTo |
date range YYYY-MM-DD |
hasAttachment |
true/false |
isUnread |
true/false |
offset / limit |
pagination |
6. Attachment Download
| Provider | Method | Endpoint | Body |
|---|---|---|---|
| Gmail | POST | /gmail/messages/{messageId}/attachment |
{email, attachmentId} |
| Outlook | POST | /outlook/attachment |
{email, messageId, attachmentId} |
| IMAP | POST | /imap/attachment |
{email, uid, folder, partId} |
The response result.data is base64-encoded; decode it and save to a file.
Gmail uses POST because the attachmentId may exceed URL length limits.
7. Draft Management
Gmail:
| Operation | Method | Endpoint |
|---|---|---|
| List drafts | GET | /gmail/drafts?email=&limit= |
| Get draft detail | GET | /gmail/drafts/{draftId}?email= |
| Create draft | POST | /gmail/drafts — body: {email, to, cc, subject, body, contentType} |
| Update draft | PUT | /gmail/drafts/{draftId} — same body as create |
| Delete draft | DELETE | /gmail/drafts/{draftId}?email= |
Outlook:
| Operation | Method | Endpoint |
|---|---|---|
| Create draft | POST | /outlook/drafts — body: {email, toRecipients, subject, body, contentType} |
| Update draft | PUT | /outlook/drafts?id={draftId}&email= — same body as create |
| Delete draft | DELETE | /outlook/drafts?id={draftId}&email= |
| Send draft | POST | /outlook/drafts/send?id={draftId}&email= |
IMAP:
| Operation | Method | Endpoint |
|---|---|---|
| Create draft | POST | /imap/drafts — body: {email, toRecipients, subject, body, contentType} |
| Update draft | PUT | /imap/drafts/{uid} — body: {email, folder, toRecipients, subject, body, contentType} |
| Delete draft | DELETE | /imap/drafts/{uid}?email=&folder= |
| Send draft | POST | /imap/drafts/{uid}/send — body: {email, folder} |
8. Label Management (Unified Interface)
| Operation | Method | Endpoint |
|---|---|---|
| List labels | GET | /labels?provider=&email= |
| Get a single label | GET | /labels/{labelId} |
| Create label | POST | /labels — body: {name, color, provider, email, visible} |
| Update label | PUT | /labels/{labelId} — body: {name, color, order, visible} |
| Delete label | DELETE | /labels/{labelId} |
| Get email's labels | GET | /mails/{p}/{email}/labels?mailId= |
| Add label to email | POST | /mails/{p}/{email}/labels?mailId= — body: {"labelId": "..."} |
| Bulk set labels | PUT | /mails/{p}/{email}/labels?mailId= — body: {"labelIds": [...]} |
| Remove label from email | DELETE | /mails/{p}/{email}/labels?mailId=&labelId= |
| Get emails under a label | GET | /labels/{labelId}/mails?provider=&email=&limit=&offset= |
Gmail native labels:
- List labels:
GET /api/gmail/labels?email= - Modify message labels:
POST /api/gmail/messages/{id}/labels— body:{email, addLabelIds, removeLabelIds} - Sync remote labels:
POST /api/gmail/labels/sync?email=
9. Outlook Categories
Outlook uses Categories instead of Labels.
| Operation | Method | Endpoint |
|---|---|---|
| Get categories | GET | /outlook/categories?email= |
| Sync categories | POST | /outlook/categories/sync?email= |
| Create category | POST | /outlook/categories/create?email= — body: {displayName, color} |
| Update category | PUT | /outlook/categories/update?email=&categoryId= — body: {displayName, color} |
| Delete category | DELETE | /outlook/categories/delete?email=&categoryId= |
| Modify message categories | POST | /outlook/message/categories?id=&email= — body: {addCategories, removeCategories} |
coloruses Outlook preset valuespreset0~preset24.
10. Automation Rules
| Operation | Method | Endpoint |
|---|---|---|
| List all rules | GET | /rules?provider=&email= |
| Get a single rule | GET | /rules/{ruleId} |
| Create rule | POST | /rules |
| Update rule | PUT | /rules/{ruleId} |
| Delete rule | DELETE | /rules/{ruleId} |
| Enable/disable | POST | /rules/{ruleId}/toggle |
| Run rule on a message | POST | /rules/execute — body: {provider, email, mailId} |
| Test rule match | POST | /rules/{ruleId}/test — same body as above |
Create rule body:
{
"name": "rule name",
"description": "description",
"provider": "gmail",
"email": "xxx@gmail.com",
"enabled": true,
"conditions": [
{"field": "from|to|subject|body|has_attachment", "operator": "contains|equals|regex|...", "value": "..."}
],
"conditionLogic": "and",
"actions": [
{"type": "add_label|remove_label|mark_as_read|mark_as_unread|archive|delete|auto_reply|agent_handle", "value": "..."}
],
"priority": 1,
"stopOnMatch": false
}
Action types:
| type | value | Description |
|---|---|---|
add_label |
label ID | add a label |
remove_label |
label ID | remove a label |
mark_as_read |
omit | mark as read |
mark_as_unread |
omit | mark as unread |
archive |
omit | archive |
delete |
omit | delete |
auto_reply |
reply text | auto-reply with fixed content |
agent_handle |
Agent ID | trigger an Agent to handle the email |
Rules are executed automatically when the polling engine detects a new email; no manual call is required.
auto_replyandagent_handlesupport all three mailbox types.
11. Authorization Management
| Operation | Method | Endpoint |
|---|---|---|
| Gmail OAuth | POST | /gmail/auth/initiate?loginHint={email} — opens browser for authorization |
| Gmail status | GET | /gmail/auth/status?email= |
| Outlook OAuth | POST | /outlook/auth/initiate — opens browser for authorization |
| Outlook status | GET | /outlook/auth/status?email= |
12. Folders
| Operation | Method | Endpoint |
|---|---|---|
| IMAP folder list | GET | /imap/folders?email= |
| Outlook folder list | GET | /outlook/folders?email= |
Gmail folders are fixed: inbox, sent, drafts, trash, spam, archive.
Data Sync Mechanism
The email system uses local cache + periodic polling:
- Write operations (send, mark, delete, label): update local and remote simultaneously, no delay
- Read operations (query, search): return the local cache; may be delayed (default 30-second polling)
- Remote changes (the user operates from the official web UI): wait for the next polling cycle to sync
Storage path: ${DESIRECORE_ROOT}/mail/{provider}/{email}/ (index.json, messages/, sync.json)
Error Handling
| Status code | Reason | Handling |
|---|---|---|
| 400 | parameter error | check the request parameters |
| 401 | authorization expired | handle per Rule 1; do not try other channels |
| 404 | resource not found | sync first and retry (Rule 3) |
| 500 | internal error | tell the user to retry later |
IMAP note: domestic Chinese mailboxes (QQ, 163) require an "app password" instead of the login password. Use /imap/test to validate the configuration in advance.