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
2.6 KiB
name, description, metadata
| name | description | metadata | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| contacts | Contact management with CardDAV sync. Validates email recipients for calendar invites and himalaya email sending. Prevents hallucinated addresses. |
|
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)
vdirsyncerconfigured with a CardDAV pair for contacts sync- Contacts directory:
~/.openclaw/workspace/contacts/default/
Usage
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 --tocallscontacts.py resolvebefore 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.