Communitygithub.com

dzhng/crm.cli

Gestiona contactos, empresas, negocios y pipeline con crm.cli — un CRM sin interfaz gráfica, basado en línea de comandos y respaldado por SQLite con una interfaz de sistema de archivos virtual.

¿Qué es crm.cli?

crm.cli es un CRM completo, minimalista y sin servidor, diseñado para desarrolladores y agentes de IA. Almacena todos los datos (contactos, empresas, negocios y actividades) en un único archivo SQLite, accesible y modificable directamente desde la terminal, sin necesidad de una interfaz gráfica. Soporta búsqueda exacta con FTS5, búsqueda difusa/semántica, detección de duplicados, informes de pipeline, importación/exportación CSV/JSON, y un sistema de archivos virtual (FUSE en Linux, NFS en macOS) que permite leer y escribir datos como si fueran archivos JSON, facilitando la integración con herramientas Unix como `grep`, `jq` o `vim`. Los agentes de IA pueden montar el CRM y acceder a contactos, empresas y negocios directamente, ejecutar operaciones por lotes con `--format ids`, y aprovechar los informes precalculados para análisis rápidos. Está diseñado para ser rápido, componible y fácil de automatizar, con soporte para hooks personalizados y campos personalizados arbitrarios.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/dzhng/crm.cli/tree/HEAD/skills

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

¿Qué hace crm.cli?

Un CRM sin servidor, minimalista y basado en línea de comandos. Contactos, negocios y pipeline en un único archivo SQLite: consultable desde tu terminal, componible con herramientas Unix y montable como un sistema de archivos virtual.

Instalación

curl -fsSL https://raw.githubusercontent.com/dzhng/crm.cli/main/install.sh | sh

Esto descarga el binario precompilado en ~/.local/bin e instala las dependencias de montaje (FUSE en Linux, Rust toolchain en macOS para NFS).

Después de la instalación, asegúrate de que ~/.local/bin esté en tu PATH:

export PATH="$HOME/.local/bin:$PATH"

Verifica:

crm --version

Configuración

Opcional. Crea crm.toml en la raíz de tu proyecto o en ~/.crm/config.toml:

[database]
path = "~/.crm/crm.db"

[pipeline]
stages = ["lead", "qualified", "proposal", "negotiation", "closed-won", "closed-lost"]
won_stage = "closed-won"
lost_stage = "closed-lost"

[defaults]
format = "table"

[phone]
default_country = "US"
display = "international"

[mount]
default_path = "~/crm"

La configuración se descubre automáticamente recorriendo hacia arriba desde el directorio actual. Sobrescribe con --config <ruta> o la variable de entorno CRM_CONFIG.

Banderas globales

Todos los comandos aceptan:

  • --db <ruta> — Ruta de la base de datos SQLite (por defecto: ~/.crm/crm.db, env: CRM_DB)
  • --format <fmt> — Formato de salida: table, json, csv, tsv, ids
  • --config <ruta> — Ruta del archivo de configuración TOML
  • --no-color — Desactiva la salida coloreada

Contactos

Crear un contacto

crm contact add --name "Juan Pérez" \
  --email [email protected] \
  --phone "+52-55-1234-5678" \
  --linkedin linkedin.com/in/juanperez \
  --company "Empresa SA" \
  --tag cliente-potencial \
  --set cargo=CTO

Todas las banderas son opcionales excepto --name. Los teléfonos se normalizan al formato E.164, las URLs de LinkedIn se extraen a identificadores, y las empresas se crean automáticamente si no existen. Las banderas --email, --phone, --company, --tag y --set se pueden repetir.

Banderas de redes sociales: --linkedin, --x, --bluesky, --telegram. Todas aceptan identificadores o URLs completas.

Listar contactos

crm contact list
crm contact list --tag cliente-potencial --company "Empresa SA"
rm contact list --filter "cargo~=CTO AND company=Empresa" --sort name --limit 20
crm contact list --format json | jq '.[].name'

Operadores de filtro: =, !=, ~= (contiene), >, <. Combínalos con AND / OR.

Mostrar un contacto

Búsqueda por ID, correo, teléfono o red social:

crm contact show ct_01J8ZVXB3K...
crm contact show [email protected]
crm contact show "+525512345678"
crm contact show juanperez           # Identificador de LinkedIn

Editar un contacto

crm contact edit [email protected] --name "Juan García"
crm contact edit "+525512345678" --add-email [email protected] --rm-tag etiqueta-vieja
crm contact edit juanperez --add-company "Nueva Corp" --set cargo=CEO --unset source

Banderas de añadir/eliminar: --add-email, --rm-email, --add-phone, --rm-phone, --add-company, --rm-company, --add-tag, --rm-tag. Las redes sociales se asignan directamente: --linkedin, --x, --bluesky, --telegram.

Eliminar un contacto

crm contact rm [email protected]
crm contact rm "+525512345678" --force    # saltar confirmación
crm contact rm juanperez                   # por red social

Fusionar contactos

Fusiona dos contactos en uno. El primer contacto sobrevive, el segundo se absorbe y se elimina. Acepta cualquier tipo de referencia:

crm contact merge ct_01A... ct_01B...
crm contact merge [email protected] [email protected]
crm contact merge "+525512345678" "+525598765432"
crm contact merge juanperez juan-garcia-linkedin

Combina correos, teléfonos, empresas, etiquetas, campos personalizados y reenlaza todos los negocios y actividades.

Empresas

Crear una empresa

crm company add --name "Empresa SA" \
  --website empresa.com \
  --phone "+52-800-555-0000" \
  --tag corporativo \
  --set sector=Saas

Las banderas --website, --phone, --tag, --set se pueden repetir.

Listar / mostrar / editar / eliminar

crm company list --tag corporativo
crm company show empresa.com                        # por sitio web
crm company show "+528005550000"                   # por teléfono
crm company edit empresa.com --name "Empresa Inc" --add-website empresa.io
crm company rm empresa.com --force

Fusionar empresas

crm company merge co_01A... co_01B...
crm company merge empresa.com empresa.io
crm company merge "+528005550000" "+528005550001"

Reenlaza todos los contactos y negocios de la segunda a la primera.

Negocios

Crear un negocio

crm deal add --title "Acme Enterprise" \
  --value 50000 \
  --stage qualified \
  --contact [email protected] \
  --company empresa.com \
  --expected-close 2026-06-15 \
  --probability 60 \
  --tag corporativo

Los contactos y empresas se crean automáticamente si no existen. Las banderas --contact y --tag se pueden repetir.

Listar negocios

crm deal list --stage qualified --min-value 10000
crm deal list --contact [email protected] --sort value --reverse
crm deal list --format ids | wc -l    # contar negocios

Mover un negocio a través del pipeline

crm deal move dl_01... --stage proposal --note "Envié presentación de precios"
crm deal move dl_01... --stage closed-won --note "Firmó contrato por 2 años"

Los cambios de etapa se registran como actividad con marcas de tiempo. Usa deal move, no deal edit --stage.

Editar / eliminar

crm deal edit dl_01... --value 75000 --add-contact [email protected] --probability 80
crm deal rm dl_01... --force

Resumen del pipeline

crm pipeline

Muestra el recuento, el valor total y el valor ponderado por etapa.

Registro de actividades

Registrar una actividad

crm log note "Café con Juan, hablamos sobre la expansión en el Q3" --contact [email protected]
crm log call "Demostración del producto, quiere una propuesta" --contact [email protected] --deal dl_01...
crm log meeting "Revisión trimestral" --company empresa.com --at 2026-04-01
crm log email "Envié seguimiento de precios" --contact [email protected] --set canal=saliente

Tipos: note, call, meeting, email. Los contactos y empresas se crean automáticamente. --contact se puede repetir. --at sobrescribe la marca de tiempo.

Listar actividades

crm activity list --contact [email protected] --since 2026-01-01
crm activity list --type call --limit 10
crm activity list --deal dl_01... --format json

Etiquetas

crm tag [email protected] cliente-potencial corporativo       # añadir etiquetas
crm untag [email protected] etiqueta-vieja                     # eliminar etiquetas
crm tag list                                                    # todas las etiquetas con recuento
crm tag list --type contact                                     # solo etiquetas de contacto

Las etiquetas funcionan en contactos, empresas y negocios.

Búsqueda

Búsqueda exacta por palabra clave (FTS5)

crm search "empresa CTO"
crm search "juan" --type contact

Búsqueda difusa / semántica

crm find "fintech startup Madrid"
crm find "ese CTO que conocí en la conferencia" --limit 5 --threshold 0.3

Reconstruir el índice de búsqueda

crm index rebuild
crm index status

El índice se actualiza automáticamente al escribir. Solo se necesita reconstrucción manual después de una corrupción.

Detección de duplicados

crm dupes
crm dupes --type contact --threshold 0.5
crm dupes --type company --limit 20

Usa similitud combinada de Levenshtein + Dice coefficient. Detecta: nombres similares, correos compartidos, teléfonos compartidos, sitios web compartidos, redes sociales compartidas. Revisa y luego fusiona:

crm dupes --type contact
# → Juan Pérez ↔ J. Pérez: nombre similar, correo compartido
crm contact merge ct_01A... ct_01B...

Informes

crm report pipeline                                  # recuentos y valores por etapa
crm report activity --period 30d --by type           # volumen de actividad
crm report stale --days 14 --type contact            # sin actividad reciente
crm report conversion --since 2026-01-01             # tasas de etapa a etapa
crm report velocity --won-only                       # tiempo por etapa
crm report forecast --period 2026-Q2                 # pronóstico ponderado
crm report won --period 90d                          # resumen de cerrados-ganados
crm report lost --period 90d                         # resumen de cerrados-perdidos

Importar / Exportar

Importar desde CSV o JSON

crm import contacts clientes.csv
crm import contacts clientes.json --update     # actualizar existentes por coincidencia de correo
crm import companies empresas.csv --dry-run
crm import deals negocios.csv --skip-errors
cat data.json | crm import contacts -            # importar desde stdin

Encabezados CSV: name, email/emails, phone/phones, company/companies, tags, linkedin, x, bluesky, telegram. Las columnas no reconocidas se convierten en campos personalizados.

Exportar

crm export contacts --format csv > contactos.csv
crm export companies --format json > empresas.json
crm export deals --format tsv
crm export all --format json > respaldo-completo.json

Sistema de archivos virtual (montaje)

Monta el CRM como un sistema de archivos vivo de lectura/escritura. Cualquier herramienta que lea archivos obtiene acceso completo al CRM: agentes de IA, grep, jq, vim, scripts.

Montar

crm mount ~/crm
crm mount ~/crm --readonly

En Linux usa FUSE. En macOS usa un servidor NFS v3 (sin necesidad de extensiones de kernel).

Estructura del sistema de archivos

~/crm/
├── llm.txt                           # Instrucciones para agentes de IA
├── contacts/
│   ├── ct_01...juan-perez.json        # Archivos JSON de contacto
│   ├── _by-email/                     # Búsqueda por correo
│   ├── _by-phone/                     # Búsqueda por teléfono E.164
│   ├── _by-linkedin/                  # Búsqueda por identificador de LinkedIn
│   ├── _by-x/                         # Búsqueda por identificador de X
│   ├── _by-company/                   # Agrupado por empresa
│   └── _by-tag/                       # Agrupado por etiqueta
├── companies/
│   ├── co_01...empresa-sa.json
│   ├── _by-website/
│   ├── _by-phone/
│   └── _by-tag/
├── deals/
│   ├── dl_01...acme-enterprise.json
│   ├── _by-stage/
│   ├── _by-company/
│   └── _by-tag/
├── activities/
│   ├── _by-contact/
│   ├── _by-company/
│   ├── _by-deal/
│   └── _by-type/
├── reports/                          # Análisis precalculados
│   ├── pipeline.json
│   ├── forecast.json
│   ├── stale.json
│   ├── conversion.json
│   ├── velocity.json
│   ├── won.json
│   └── lost.json
├── pipeline.json                     # Resumen rápido del pipeline
├── tags.json                         # Todas las etiquetas con recuento
└── search/                           # Búsqueda leyendo archivos
    └── <consulta>.json               # cat search/"empresa CTO".json

Leer a través del sistema de archivos

ls ~/crm/contacts/
cat ~/crm/contacts/ct_01...juan-perez.json | jq .
cat ~/crm/contacts/_by-email/[email protected]
cat ~/crm/deals/_by-stage/qualified/
cat ~/crm/reports/forecast.json
cat ~/crm/search/"negocios empresariales".json

Escribir a través del sistema de archivos

# Crear un contacto
echo '{"name":"Roberto López","emails":["[email protected]"]}' > ~/crm/contacts/new.json

# Actualizar (leer → modificar → escribir de nuevo)
cat ~/crm/contacts/ct_01...juan-perez.json | jq '.tags += ["vip"]' > ~/crm/contacts/ct_01...juan-perez.json

# Eliminar
rm ~/crm/contacts/ct_01...juan-perez.json

Desmontar

crm unmount ~/crm

Exportación estática (sin necesidad de montaje)

crm export-fs ./crm-snapshot

Exporta la misma estructura de directorios como una copia estática, útil en contenedores o entornos aislados donde FUSE no está disponible.

Operaciones por lotes

Usa --format ids para canalizar a otros comandos:

# Etiquetar todos los contactos de Acme como corporativos
crm contact list --company "Acme Corp" --format ids | xargs -I{} crm tag {} enterprise

# Mover todos los negocios calificados de más de $50k a propuesta
crm deal list --stage qualified --min-value 50000 --format ids | \
  xargs -I{} crm deal move {} --stage proposal

# Eliminar todos los contactos inactivos
crm report stale --days 90 --type contact --format ids | xargs -I{} crm contact rm {} --force

Campos personalizados

Todas las entidades admiten campos arbitrarios clave-valor:

crm contact add --name "Juan" --set cargo=CTO --set fuente=conferencia
crm contact edit [email protected] --set "json:puntaje=85" --set "json:verificado=true"
crm contact edit [email protected] --unset fuente
crm contact list --filter "cargo~=CTO"

Prefijo con json: para valores tipados (números, booleanos, arreglos).

Hooks

Configura hooks de shell en crm.toml que se ejecutan en mutaciones:

[hooks]
post-contact-add = "~/.crm/hooks/notificar-slack.sh"
post-deal-stage-change = "~/.crm/hooks/negocio-movido.sh"
pre-contact-rm = "~/.crm/hooks/confirmar-eliminar.sh"

Los datos de la entidad se pasan como JSON en stdin. Los pre-hooks abortan con un código de salida distinto de cero.

Hooks disponibles: {pre,post}-{contact,company,deal}-{add,edit,rm}, {pre,post}-deal-stage-change, {pre,post}-activity-add.

Consejos para agentes de IA

  • Monta primero: crm mount ~/crm te da acceso al sistema de archivos — lee archivos JSON directamente en lugar de ejecutar comandos CLI
  • Lee llm.txt: El punto de montaje contiene llm.txt con documentación de estructura y consejos
  • Usa directorios _by-* para búsquedas rápidas: _by-email, _by-phone, _by-linkedin, _by-tag, _by-stage
  • Usa --format json para toda la salida CLI al procesar programáticamente
  • Usa --format ids + xargs para operaciones por lotes
  • Lee reports/ para análisis precalculados — no recalcules desde datos brutos
  • Busca a través del sistema de archivos: cat ~/crm/search/"tu consulta".json
  • Escribe a través del sistema de archivos: Crea/actualiza entidades escribiendo archivos JSON
  • Todos los archivos JSON son autocontenidos — no necesitas unir entre archivos
  • Los números de teléfono aceptan cualquier formato de entrada; se almacenan internamente como E.164
  • Las redes sociales aceptan URLs completas; se almacenan como identificadores limpios

Skills relacionados