Skip to content
Back to skills

Contacts

ASecurity

Gerencia contatos do sistema Ravi. Use quando o usuário quiser: - Listar, adicionar, aprovar ou bloquear contatos - Ver contatos pendentes de aprovação - Garantir captura automática de contatos a partir de DMs/chats - Rodar backfill de contatos canônicos a partir do ledger de chats - Configurar agent ou modo de resposta por contato - Adicionar/remover tags ou buscar por tags - Ver detalhes de um contato específico

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 20, 2026
ai-agentsgobashdebugging

Works with

  • cli

Security analysis

A100/100

Scanned October 20, 2026

npx -y skills add filipexyz/ravi --skill contacts --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Contacts?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Contacts
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/filipexyz-contacts/badge)](https://www.skillsdirectory.com/skills/filipexyz-contacts)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: contacts-manager
description: |
  Gerencia contatos do sistema Ravi. Use quando o usuário quiser:
  - Listar, adicionar, aprovar ou bloquear contatos
  - Ver contatos pendentes de aprovação
  - Garantir captura automática de contatos a partir de DMs/chats
  - Rodar backfill de contatos canônicos a partir do ledger de chats
  - Configurar agent ou modo de resposta por contato
  - Adicionar/remover tags ou buscar por tags
  - Ver detalhes de um contato específico
---

# Contacts Manager

> Verbos: CAPTAR (identidade) · GUARDAR (local). Compõe com: crm, bases (`ref`).
> Solução com mais de uma peça? `ravi skills show solucoes` primeiro.

Você gerencia os contatos canônicos do Ravi. Contato é pessoa ou organização; grupo, chat, thread e sessão não são contato.

Use esta skill para operar identidade, policy e intake de contatos. Não use contacts para guardar análise IA de atendimento: análises, facts, oportunidades e tarefas pertencem ao CRM/observers.

## Contrato Do CLI

Rode com `--json` sempre que for decidir programaticamente. Com `--json`, falha sai em envelope `{success:false, op, error:{code, message, retryable, suggestedAction, suggestions?|acceptedFlags?}}`.

Taxonomia de saída:

- `0` sucesso.
- `1` erro de execução (ex.: `CONTACT_NOT_FOUND`). O envelope traz `suggestions` com contatos reais parecidos — apenas contatos visíveis no seu escopo (`contactScope`); consulte antes de concluir "não existe".
- `2` erro de uso (flag/argumento inválido). O envelope traz `acceptedFlags`: corrija a chamada, não insista na mesma sintaxe.
- `3` freio de escrita — não é erro. Nada foi gravado; o envelope traz `dryRun:true` e `plan` com exatamente o que seria feito. Revise o plano e repita com `--execute`.

Onde o freio existe hoje: `contacts remove` e `contacts merge` são dry-run por default e exigem `--execute`. `contacts backfill` já tem freio próprio equivalente: sem `--apply` é sempre preview (a flag histórica é `--apply`, não `--execute`). Todas as demais escritas gravam na hora, sem dry-run: `add`, `allow`, `approve`, `block`, `set`, `tag`, `untag`, `link`, `unlink`, `note`, `metadata set`, `metadata remove`. Nessas o freio é você: confira o alvo antes de rodar.

Compact mode: `contacts list` e `contacts find` aceitam `--fields a,b,c` (ex.: `--fields id,name,status`) — use em varredura para não arrastar o objeto inteiro de cada contato.

Help por operação: `ravi contacts <op> --help` (idem no grupo `contacts metadata`) é enxuto; prefira-o ao help do domínio inteiro.

Checklist antes de responder sobre contatos:

- Tratei exit 3 como freio (revisei o `plan`) e não como falha?
- Consultei `suggestions` do envelope (ou `ravi contacts list`) antes de declarar not-found?

## Modelo Atual

- `contacts`: ficha canônica de pessoa/org.
- `contact_policies`: status operacional e roteamento do contato.
- `platform_identities`: vínculo canal/instância/id técnico para contato ou agent.
- `contact_events`: timeline auditável e append-only.
- `chats`, `chat_messages`, `chat_participants`: ledger bruto de conversas no router DB.
- `chat_reading_lists`: filas de leitura independentes para observers/agentes.

Fluxo P0:

```text
DM chega -> chat/message ledger salva tudo -> contact intake cria/linka contato -> platform identity vincula -> mensagens/participantes apontam para o contato
```

CRM estrito começa depois disso. Observers leem listas de leitura e escrevem facts/oportunidades/tarefas no CRM.

## Status de Contatos

| Status | Descrição |
|--------|-----------|
| `allowed` | Pode interagir normalmente |
| `pending` | Aguardando aprovação |
| `blocked` | Bloqueado, mensagens ignoradas |
| `discovered` | Descoberto mas não aprovado |

## Inspeção Operacional

Quando precisar diagnosticar o estado do CRM, NUNCA olhe um plano isolado. Sempre rode esta sequência em paralelo para ter a foto completa:

```bash
# Plano 1: identidade/policy
ravi contacts list --limit 5 --json
ravi contacts pending --json

# Plano 2: ledger bruto de conversas (independente de contato canônico)
ravi chats list --limit 5 --json
ravi chats lists list --json

# Plano 3: configuração de captura por canal
ravi instances list --json

# Plano 4: classificação automática
ravi tag-rules list --json

# Plano 5: ação automatizada
ravi observers rules list --json
```

⚠️ **Por que cobrir ledger e contatos juntos**: é possível ter centenas de chats no `ravi.db` ledger e poucos contatos canônicos em `chat.db`. Essa divergência indica que intake estava `off`, ou que dados antigos precisam de backfill, ou que os senders eram grupos (não viram contato). Sem comparar os dois planos, o diagnóstico fica incompleto.

⚠️ **Reading lists zeradas + chats ativos** = pipeline desligado. Sempre reporte os dois números.

Apresente o resultado consolidado nesta estrutura:

```
📋 Identidade
   🔹 X contatos canônicos (Y allowed / Z discovered / W pending / K blocked)
   🔹 N pendentes de aprovação

📋 Conversas no ledger
   🔹 C chats (D DMs / G grupos)
   🔹 M mensagens trocadas

📋 Configuração por instância
   🔹 Lista de instâncias com intake mode + default tags

📋 Automação
   🔹 R tag rules carregadas
   🔹 O observer rules ativas
   🔹 L reading lists (com membros / vazias)
```

Se houver divergência entre planos (ex: 300 chats, 5 contatos), explicite ANTES de sugerir próximo passo.

## Comandos Disponíveis

### Listar contatos
```bash
ravi contacts list
```

### Ver pendentes
```bash
ravi contacts pending
```

### Backfill de contatos a partir de chats
Use para retroativamente transformar DMs já capturadas em contatos canônicos e vincular mensagens/participantes ao contato.

Sempre rode dry-run antes de aplicar:

```bash
ravi contacts backfill --instance <instance-name-or-id> --mode discovered --dry-run --json
ravi contacts backfill --instance <instance-name-or-id> --mode discovered --create-list crm-analysis-pending --apply --json
```

Opções principais:
- `--instance <name-or-id>` filtra uma instância/conta. Aceita nome lógico (`main`, `sde`) ou UUID técnico do Omni; o backfill resolve ambos e consulta o ledger nos dois formatos.
- `--channel <channel>` filtra canal, normalmente `whatsapp`.
- `--mode discovered|pending` define status para contatos novos. Use o mesmo modo de `contactIntakeMode` da instância.
- `--limit <n>` limita candidatos.
- `--create-list <name>` adiciona chats vinculados a uma reading list para análise posterior.
- `--list-owner <type:id>` escopa a lista, default `agent:ravi-crm`.
- Sem `--apply`, o comando é apenas preview.

Regras de segurança do backfill:
- Não cria contato para grupo/chat/thread.
- Não toma posse de identidade já pertencente a agent.
- Não rebaixa `allowed`, `blocked` ou opt-out.
- Não aprova conversa nem cria rota de atendimento; só cria/linka identidade e contato.
- Preserva histórico bruto; só adiciona links canônicos e eventos auditáveis.

### Adicionar contato
```bash
ravi contacts add <phone> [nome]
```

### Aprovar pendente
```bash
ravi contacts approve <phone> [agent] [mode]
```
- `agent` - Agent ID para rotear (opcional)
- `mode` - `auto` (responde sempre) ou `mention` (só quando mencionado)

### Bloquear/Permitir
```bash
ravi contacts block <phone>             # bloqueia imediatamente
ravi contacts allow <phone>
```

### Remover
```bash
ravi contacts remove <phone> --execute  # sem --execute é dry-run (exit 3): mostra o plano e não grava
```

### Mesclar duplicados
```bash
ravi contacts merge <source-id> <target-id> --execute  # sem --execute é dry-run (exit 3); move identidades e apaga o source
```

### Ver detalhes
```bash
ravi contacts check <phone>
```

### Configurar propriedades
```bash
ravi contacts set <phone> <key> <value>
```

Keys disponíveis:
- `agent` - Agent ID para rotear
- `mode` - `auto` ou `mention`
- `email` - Email do contato
- `name` - Nome do contato
- `tags` - Array JSON: `'["lead","vip"]'`
- `notes` - Objeto JSON: `'{"empresa":"Acme"}'`
- `opt-out` - `true` ou `false`

## Tags

### Adicionar tag
```bash
ravi contacts tag <phone> <tag>
```

### Remover tag
```bash
ravi contacts untag <phone> <tag>
```

### Buscar por tag
```bash
ravi contacts find <tag> --tag
```

### Buscar por texto
```bash
ravi contacts find <query>
```

## Exemplos

Aprovar contato e rotear para agent específico:
```bash
ravi contacts approve 5511999999999 vendas auto
```

Adicionar tags a um contato:
```bash
ravi contacts tag 5511999999999 lead
ravi contacts tag 5511999999999 interessado
```

Configurar notas com contexto:
```bash
ravi contacts set 5511999999999 notes '{"empresa":"TechCorp","cargo":"CTO"}'
```

## Relação com Routes

Contacts e Routes trabalham juntos no roteamento:

- **Contacts** podem ter `agent_id` direto — isso tem prioridade sobre routes
- **Routes** definem regras por padrão (prefixo, grupo, catch-all) como fallback
- `ravi contacts list` mostra o agent e modo de resposta de cada contato
- Para gerenciar rotas: use a skill `ravi-system:routes`
- Ordem de resolução: contact.agent_id > route match > accountId > default agent

## Relação com Instâncias

Auto intake é configuração por instância:

```bash
ravi instances show <instance> --json
ravi instances set <instance> contactIntakeMode discovered
```

Modos:
- `off`: não cria/linka contato automaticamente.
- `discovered`: cria/linka contato sem colocar como pendente de ação operacional.
- `pending`: cria/linka contato como pendente.

Para a base já existente, use `ravi contacts backfill`. Para novas mensagens, configure `contactIntakeMode`.

## Relação com Observers e CRM

Contacts deve parar na identidade/policy/vínculo com chat. Depois:

- Reading lists organizam quais chats serão lidos.
- Observers analisam deltas de mensagens.
- CRM recebe conclusões: facts, opportunities, activities, tasks e next actions.

Não adicione campos de análise IA em contacts se a informação puder ser produzida por observer e gravada como CRM fact/event.

## Auto Tags por Instância

Cada instância pode declarar tags default que vão automaticamente para qualquer contato canônico criado pelo intake (runtime ou backfill).

Regras:
- Aplica somente quando o contato é criado pela primeira vez (`createdContact=true`). Contato já existente não recebe tag default.
- Tags entram via `attachCanonicalContactTag` e ficam refletidas em `contact_policies.tags_json`.
- Cada aplicação emite um evento `profile.tag_added` em `contact_events` com `reason: instance_default_contact_tags`, preservando proveniência por instância.
- Backfill respeita a mesma regra: só aplica em chats que viram `create_contact`; `link_existing` e `already_linked` não tocam tags.

Configurar:

```bash
ravi instances set <instance> defaultContactTags new-contact
ravi instances set <instance> defaultContactTags '["new-contact","needs-triage"]'
ravi instances set <instance> defaultContactTags -
```

Aceita CSV ou JSON array. `-` ou `null` limpa.

Inspecionar:

```bash
ravi instances show <instance>
# ou via JSON:
ravi instances show <instance> --json | jq .instance.defaultContactTags
```

## Playbook: Tag → Observer por Contato

Fluxo end-to-end para uma instância tratar cada novo contato como um lead vivo, com observers trocando de tag para coordenar etapas.

### 1. Configurar instância

```bash
ravi instances set <instance> contactIntakeMode discovered
ravi instances set <instance> defaultContactTags new-contact
```

Resultado: todo DM novo cria contato canônico e ganha a tag `new-contact`. Contatos antigos não recebem tag retroativa — use `ravi contacts tag <id> new-contact` se quiser equiparar.

### 2. (Opcional) Definir tag formalmente

Tags slugificam automaticamente, mas definir traz label e descrição auditável:

```bash
ravi tags define new-contact --label "New Contact" --description "Contato recém-capturado pelo intake"
```

### 3. Criar observer rule por tag de contato

```bash
ravi observers rules set new-contact-watch <observer-agent> \
  --scope tag \
  --tag new-contact \
  --tag-target contact \
  --observer-role new-contact-watch \
  --observer-mode summarize \
  --profile default
```

A sessão fonte é resolvida automaticamente via `session_participants`: se a sessão tem participante contato com a tag, o rule dispara e cria binding observer.

### 4. Observer trabalha o lead e troca a tag para encadear

Dentro do prompt do observer, ele tem permissão pra ler conversa e propor próximos passos. Para entregar o lead à próxima etapa, troca a tag do contato:

```bash
ravi contacts untag <contactId> new-contact
ravi contacts tag <contactId> lead-qualified
```

Outro observer rule pode estar bound a `--tag lead-qualified --tag-target contact`. Na próxima evaluation (quando uma nova mensagem chega ou outra rebind ocorre), o novo observer entra em ação.

### 5. Auditoria e debugging

```bash
ravi observers rules explain --session <session>
ravi contacts events <phone>
ravi observers list --source-session <session>
```

`explain` mostra `source.contactIds` e quais tags de contato estão sendo coletadas no descriptor.

### Limitações conhecidas

- Bindings antigos não são removidos automaticamente quando a tag muda. O observer antigo continua bound até intervenção manual (`ravi observers unbind` ou expiração natural).
- Para sessões DM-per-peer (1 contato por sessão), o fluxo é determinístico. Em sessões `main` ou de grupo, vários contatos podem coexistir e cada um carrega suas tags.
- `defaultContactTags` aplica só na criação. Se você precisa retaguear contatos existentes para inseri-los no fluxo, faça via `ravi contacts tag <id> <tag>` em lote.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.