contacts: extract into standalone skill, add himalaya wrapper for all email sends
Refactors the contacts system from being embedded in cal_tool.py into a standalone contacts skill that serves as the single source of truth for recipient validation across all outbound email paths. - New skills/contacts/ skill: list, add, delete, resolve commands - New skills/himalaya/scripts/himalaya.sh wrapper: validates To/Cc/Bcc recipients against contacts for message send, template send, and message write commands; passes everything else through unchanged - cal_tool.py now delegates to contacts.py resolve instead of inline logic - TOOLS.md updated: agent should use himalaya wrapper, not raw himalaya
This commit is contained in:
67
skills/contacts/SKILL.md
Normal file
67
skills/contacts/SKILL.md
Normal file
@@ -0,0 +1,67 @@
|
||||
---
|
||||
name: contacts
|
||||
description: "Contact management with CardDAV sync. Validates email recipients for calendar invites and himalaya email sending. Prevents hallucinated addresses."
|
||||
metadata: {"clawdbot":{"emoji":"📇","requires":{"bins":["python3","vdirsyncer"]}}}
|
||||
---
|
||||
|
||||
# Contacts
|
||||
|
||||
Manage a local vCard contact list synced to Migadu CardDAV via vdirsyncer. Used by the calendar tool and himalaya wrapper to validate recipient addresses before sending.
|
||||
|
||||
## Why This Exists
|
||||
|
||||
LLMs can hallucinate email addresses — inventing plausible-looking addresses from context instead of looking up the correct one. This contact list serves as a **tool-level allowlist**: outbound emails can only go to addresses that exist in the contacts.
|
||||
|
||||
**Adding contacts and sending emails are separate operations.** Never add a contact and send to it in the same request.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Python 3 (no external dependencies)
|
||||
- `vdirsyncer` configured with a CardDAV pair for contacts sync
|
||||
- Contacts directory: `~/.openclaw/workspace/contacts/default/`
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
SKILL_DIR=~/.openclaw/workspace/skills/contacts
|
||||
|
||||
# List all contacts
|
||||
$SKILL_DIR/scripts/contacts.sh list
|
||||
|
||||
# Add a contact (single email)
|
||||
$SKILL_DIR/scripts/contacts.sh add --name "小鹿" --email "mail@luyx.org"
|
||||
|
||||
# Add with email type and nickname
|
||||
$SKILL_DIR/scripts/contacts.sh add --name "小橘子" --email "Erica.Jiang@anderson.ucla.edu" --type work --nickname "小橘子"
|
||||
|
||||
# Add a second email to an existing contact
|
||||
$SKILL_DIR/scripts/contacts.sh add --name "小橘子" --email "xueweijiang0313@gmail.com" --type home
|
||||
|
||||
# Resolve a name to email address (used by other tools)
|
||||
$SKILL_DIR/scripts/contacts.sh resolve "小橘子:work"
|
||||
# Output: Erica.Jiang@anderson.ucla.edu
|
||||
|
||||
# Delete a contact
|
||||
$SKILL_DIR/scripts/contacts.sh delete --name "小橘子"
|
||||
```
|
||||
|
||||
## Resolve Formats
|
||||
|
||||
The `resolve` command accepts three formats:
|
||||
|
||||
| Format | Example | Behavior |
|
||||
|--------|---------|----------|
|
||||
| Name | `小橘子` | Match by FN or NICKNAME. Error if multiple emails (use type). |
|
||||
| Name:type | `小橘子:work` | Match by name, select email by type. |
|
||||
| Raw email | `user@example.com` | Accept only if the email exists in contacts. |
|
||||
|
||||
Unknown addresses are **rejected** with the available contacts list shown.
|
||||
|
||||
## Integration
|
||||
|
||||
- **Calendar tool** (`cal_tool.py`): `send --to` calls `contacts.py resolve` before sending invites
|
||||
- **Himalaya wrapper** (`himalaya.sh`): validates To/Cc/Bcc headers before passing to himalaya for email delivery
|
||||
|
||||
## Data
|
||||
|
||||
Contacts are stored as vCard 3.0 `.vcf` files in `~/.openclaw/workspace/contacts/default/`, synced to Migadu CardDAV via vdirsyncer. Filenames are `{uid}.vcf`.
|
||||
Reference in New Issue
Block a user