Skip to main content
ClaudeWave
Skill1.2k repo starsupdated today

contacts

The contacts skill manages the user's contact database, relationship graph, and access control for external messaging channels like Telegram and phone. Use it to search and merge contacts, view trusted contacts with messaging permissions, and create invite links for granting access to new users. Contact creation requires guardian (administrator) access through the web UI or invite-link flow; the LLM can only list, search, and merge existing contacts.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/vellum-ai/vellum-assistant /tmp/contacts && cp -r /tmp/contacts/assistant/src/config/bundled-skills/contacts ~/.claude/skills/contacts
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

Manage the user's contacts, relationship graph, access control (trusted contacts), and invite links. This skill covers contact CRUD with multi-channel tracking, controlling who can message the assistant through external channels (Telegram, phone), and creating/managing invite links that grant access.

## Contact Management

> **Every contact write goes through the guardian.** You can list, search, and merge contacts on your own. To create, edit, or delete one, run the matching command below: each opens a form in the guardian's app, and the write happens only if they submit it. You are proposing, not writing. Say so: "I'll put that up for you to confirm," not "Done."
>
> Two things a contact record does **not** do: it grants no access (a record has no channels, so nobody can message the assistant through it), and it is not a channel. Use `assistant contacts prompt` to bind an address, or `assistant contacts invites create` to let someone bind their own.
>
> The form needs the guardian's desktop or web app to be open. If a command reports that it timed out, nobody answered: tell the user, and do not retry in a loop.

### Create a contact

```bash
assistant contacts create --name "Alice" --json
```

Opens an add-contact form prefilled with what you pass. The guardian can edit the name and notes before submitting, so treat the result as theirs, not yours: read the command's output rather than assuming the values you proposed were the ones written.

Optional flags:

- `--notes` -- proposed notes, prefilled into the form
- `--label` / `--description` -- what the form says about why you are asking
- `--timeout` -- how long the form stays open, in ms (default 300000)

Use this before creating an invite for someone who is not in the contact graph yet.

### Update a contact

```bash
assistant contacts update "<contact_id>" --name "Alice Chen" --json
assistant contacts update "<contact_id>" --notes "Moved to Berlin" --json
```

Opens an edit form showing the current name next to the proposed change. At least one of `--name` or `--notes` is required. This edits the record only. To revoke or block someone's access, use `assistant contacts channels update-status`.

### Delete a contact

```bash
assistant contacts delete "<contact_id>" --json
```

Opens a confirmation showing the contact and its channels. Deleting a contact deletes its channels too, so anyone reaching the assistant through them loses access. A guardian contact cannot be deleted. When two records are the same person, merge them with the `contact_merge` tool instead: merging keeps the surviving contact's channels.

### Search contacts

Search for contacts by name, channel address, or other criteria.

```bash
assistant contacts list --query "<search_term>" --json
```

Optional flags:

- `--query` -- search by display name (partial match)
- `--channel-address` -- search by channel address (email, phone, handle)
- `--channel-type` -- filter by channel type when searching by address
- `--limit` -- maximum results to return (default 50, max 100)

### Merge contacts

When you discover two contacts are the same person (e.g. same person on email and Slack), merge them to consolidate. Merging:

- Combines all channels from both contacts
- Merges notes from both contacts
- Sums interaction counts
- Deletes the donor contact

```bash
assistant contacts merge <surviving_contact_id> <donor_contact_id> --json
```

## Access Control (Trusted Contacts)

Trusted contacts control who is allowed to send messages to the assistant through external channels like Telegram and voice (phone calls).

### Concepts

- **Contact channel**: A user identity (external user ID or chat ID) on a specific messaging platform, stored as an entry in a contact's `channels` array. Each channel entry has its own `status` and `policy`.
- **Policy**: Controls what the contact channel can do -- `allow` (can message freely) or `deny` (blocked from messaging).
- **Status**: The channel's lifecycle state -- `active` (currently effective), `revoked` (access removed), or `blocked` (explicitly denied).
- **Channel type**: The messaging platform (e.g., `telegram`, `phone`).

### List trusted contacts

Use this to show the user who currently has access, or to look up a specific contact.

```bash
assistant contacts list --json
```

Optional query parameters for filtering:

- `--role <role>` -- filter by role (default: `contact`; use `guardian` to list guardians)
- `--limit <limit>` -- maximum number of contacts to return
- `--query <query>` -- search query to filter contacts

Example:

```bash
assistant contacts list --role contact --json
```

The response contains `{ ok: true, contacts: [...] }` where each contact has:

- `id` -- unique contact ID
- `role` -- the contact's role (`contact`, `guardian`)
- `displayName` -- human-readable name
- `channels` -- array of channel entries, each with:
  - `id` -- channel ID (needed for status/policy changes)
  - `channel` -- the channel type (e.g., `telegram`, `phone`)
  - `externalUserId` -- the user's ID on that channel
  - `externalChatId` -- the chat ID on that channel
  - `displayName` -- channel-specific display name
  - `username` -- channel username (e.g., Telegram @handle)
  - `status` -- current status (`active`, `revoked`, `blocked`, etc.)
  - `policy` -- current policy (`allow`, `deny`)
- `createdAt` -- when the contact was added

**Presenting results**: Format the contact list as a readable table or list. Include display name, role, and per-channel status/policy. If no contacts exist, tell the user their contact list is empty.

### Allow a user (add trusted contact)

Access is granted per channel, not per contact, and it always takes proof that the person holds the address. Creating the contact record is only the first step.

1. **Contact record** -- if they are not in the graph yet, `assistant contacts create --name "<name>"`. The guardian confirms it. This alone grants nothing.
2. **Invite link** -- `assistant contacts invites create