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
68 lines
2.6 KiB
Markdown
68 lines
2.6 KiB
Markdown
---
|
|
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`.
|