@cotctl/cli
v0.12.0
Published
CLI para la plataforma Cotalker
Readme
cotctl
CLI para la plataforma Cotalker
Features
- Gestión declarativa de recursos — crea, actualiza y exporta doce tipos de recursos (formularios, roles, tipos de propiedad, propiedades, workflows, usuarios, cargos, bots, SLAs, schedules, webhooks y rutinas) a partir de archivos YAML, al estilo de kubectl
- Validación local de los archivos YAML antes de aplicar cualquier cambio, con validación remota opcional contra el entorno
- Vista previa con
--dry-run— muestra el diff contra el estado del servidor y advierte sobre los cambios destructivos antes de enviarlos - Autenticación multi-perfil — un ApiToken por entorno, guardado localmente
- Claude Code Skills — instala herramientas y conocimiento de Cotalker directamente en tu editor
- MCP Server — conecta Claude Code con la documentación técnica actualizada de Cotalker
Requisitos
- Node.js >= 18. Hace falta para instalar el paquete y también en cada
ejecución: lo que
npmdeja en el PATH es un lanzador de Node que ubica el binario de tu plataforma y lo ejecuta. El binario en sí es autónomo, pero se llega a él a través de ese lanzador, así que sin Nodecotctlno arranca. - Plataformas soportadas: macOS (arm64, x64), Linux (arm64, x64) y Windows (x64).
Instalación
npm install -g @cotctl/cliVerificar instalación
cotctl --versionQuick Start
# 1. Autenticarse contra un entorno (abre el navegador)
cotctl login --url web.micompania.cotalker.com --subdomain micompania
# 2. Ver los perfiles guardados
cotctl profile list
# 3. Listar los formularios de un perfil.
# Todo comando que consulta la API necesita -c <perfil>: no hay perfil por
# defecto. La excepción es una credencial de entorno (ver Autenticación).
# El perfil se llama igual que el subdominio, salvo que se use --profile al hacer login.
cotctl surveys list -c micompania
# 4. Exportar un formulario por su code (también acepta su ID)
cotctl surveys export solicitud_compra -c micompania -o ./formulario.yaml
# 5. Validar un archivo local (no necesita perfil: se ejecuta sin conexión)
cotctl validate -f ./formulario.yaml
# 6. Previsualizar el cambio y recién después aplicarlo. La vista previa que
# detalla los cambios destructivos es la del comando por entidad
# (surveys apply); el apply genérico no imprime ese bloque.
cotctl surveys apply -f ./formulario.yaml -c micompania --dry-run
cotctl apply -f ./formulario.yaml -c micompaniaNovedades de la 0.12.0
⚠ Cambios incompatibles
Cinco, y el de mayor radio es el primero porque puede poner en rojo un pipeline que hoy pasa en verde.
validate --dirahora falla ante dos cosas que antes dejaba pasar. Un directorio que hoy sale0puede pasar a salir1, por cualquiera de las dos. La primera son los errores semánticos de un formulario: nada nuevo está mal en esos archivos, el error ya estaba y solo no afloraba hasta elapply. La segunda es una referenciafile://que no resuelve, en cualquier kind — no solo en formularios: un PropertyType coneditable.src: "file://missing.js"pasaba como string válido en la0.11.0y ahora hace fallar la corrida. La migración es arreglar lo que el validador ahora reporta, o la misma falla aterriza en el próximoapply.conditionalDisplayycommanddentro de una columna de+tablese rechazan. Un YAML que hoy valida y aplica deja de hacerlo. El rechazo es una falla de esquema, así que sale con el código de falla de validación de cada comando:1envalidate, enapplyy ensurveys applypor igual. No es el2del punto siguiente, que corresponde asurveys export. La migración es subir la condición a la preguntatable, que es el nivel que realmente se evalúa; sobre una pregunta de primer nivel no cambia nada.surveys exportsale con2y no1cuando el transformador simplificado rechaza el formulario. Es el contrato que ya seguía todo el resto (0ok,1falla en ejecución,2entrada inválida). Una falla de transporte o de autenticación sigue saliendo1. Solo afecta a quien pruebe== 1.surveys exportdeja de emitirconditionalDisplayycommanddentro de una columna. Ninguna de las dos claves se evalúa a ese nivel, así que el viaje de ida y vuelta cargaba un campo que no hacía nada. Lo que pasaba al aplicar difería por clave:conditionalDisplayse descartaba, pero elcommandde una columna sí viajaba en elPUT. Como el cuerpo reemplazachatentero, dejar de exportarlo hace que una vuelta completa en formato crudo lo borre del backend en vez de reescribirlo. El valor es inerte, así que no cambia nada observable, pero el borrado es real.workflows apply --dry-runreporta hasta dos campospreservedmás por máquina de estados. No cambia nada del apply; crece el número que encabeza el reporte, así que un script que lo parsee ve un cambio sin cambio detrás.
Autenticación sin terminal
cotctl ya puede correr en un pipeline sin perfil y sin escribir nada en disco:
COTCTL_TOKEN más COTCTL_API_URL en el entorno, o login --token para pegar
un ApiToken desde un archivo o por stdin. Hasta ahora un pipeline tenía que
escribir ~/.cotctl/config.json a mano, reproduciendo un formato interno — y la
receta publicada para hacerlo omitía la clave version, así que producía un
config que el propio cotctl rechazaba como corrupto. Los detalles están en
Autenticación.
workflows apply deja de borrar configuración que el YAML no menciona
Dos ajustes de una máquina de estados —dynamicPropertyTypes y la lista de
extensiones permitidas— se perdían en cada aplicación si el YAML no los
declaraba. Ahora se preservan, y al preservarse también se reportan: de ahí el
cambio incompatible en el conteo del --dry-run.
En la misma línea, el YAML gana dos ajustes que antes no podía expresar —
defaultSelectedTaskTab, la pestaña con la que abre una tarea, y cardLabels,
las etiquetas que muestra su tarjeta— y allowedExtensions pasa a declararse
desde el YAML. Omitir la clave sigue preservando la lista del servidor: una clave
ausente y allowedExtensions: [] son instrucciones distintas.
El CLI reporta lo que realmente pasó
apply descartaba todas las advertencias semánticas antes de mostrarlas, y
schedules logs se comía el error que el backend ya estaba mandando. Los dos
ahora lo dicen. Se suman advertencias nuevas donde había silencio —una pregunta
que declara dependsOn, showWhen, resetOnHide o resetIdentifiers en su
raíz, y una etapa preload u onDisplay que declara src sin context— y dos
flags para graduar la salida: -q, --quiet en apply y -v, --verbose en
schedules logs.
La primera de las dos es del formato simplificado: en el crudo esas claves no
son parte de la pregunta, así que se descartan al parsear y no se emite nada. La
segunda se acota a esas dos etapas porque son las únicas que no se registran sin
context; en el resto es recomendable, no obligatorio, y nada avisa.
Comandos
Generales
| Comando | Descripción |
|---------|-------------|
| cotctl login | Autenticarse y guardar un perfil (requiere --url y --subdomain) |
| cotctl logout [profile] | Revocar el ApiToken en el servidor y eliminar el perfil local |
| cotctl profile | list · delete <name> — gestionar los perfiles guardados |
| cotctl apply | Crear o actualizar recursos desde un archivo YAML (-f) o un directorio (-d) |
| cotctl validate | Validar archivos YAML localmente; --remote contrasta los identificadores contra la API y -w corre la checklist de Marcha Blanca de un workflow |
| cotctl skills | list · install [name] · uninstall [name] — gestionar las Claude Code Skills |
| cotctl mcp | install · list · remove [name] · indices — gestionar las conexiones MCP |
Recursos
Doce de los trece recursos tienen además su propio apply; bot-types es la
excepción, porque solo consulta el catálogo. No todos aceptan el mismo YAML.
El genérico cotctl apply -f cubre siete kinds — Survey, AccessRole,
PropertyType, Property, JobTitle, Workflow y User —; un archivo de
Bot, Sla, Schedule, Webhook o Routine se rechaza con Unknown kind y
hay que aplicarlo con el apply de su propio recurso, o con cotctl apply
--dir, que sí despacha los doce.
| Comando | Subcomandos | Recurso |
|---------|-------------|---------|
| cotctl surveys | list · get · export · apply · deactivate | Formularios |
| cotctl roles | list · get · permissions · export · apply · deactivate | Roles de acceso y permisos |
| cotctl property-types | list · get · export · apply · deactivate | Tipos de propiedad |
| cotctl properties | list · get · export · apply · deactivate | Propiedades |
| cotctl workflows | list · get · export · apply · deactivate · scaffold | Workflows y máquinas de estado |
| cotctl users | list · get · export · apply · deactivate | Usuarios |
| cotctl jobtitles | list · get · export · apply · deactivate | Cargos |
| cotctl bots | list · get · export · apply | Bots de administración (slash-commands) |
| cotctl bot-types | list · versions <BotType> | Catálogo de tipos de ParametrizedBot |
| cotctl slas | list · get · export · apply | SLAs asociados a máquinas de estado |
| cotctl schedules | list · get · export · apply · activate · deactivate · logs | Schedules cron y de disparo único |
| cotctl webhooks | list · get · export · apply · logs · test | Webhooks (suscripciones a eventos) |
| cotctl routines | list · get · export · apply · test | Rutinas (PBScripts) |
cotctl bots versions <BotType> sigue funcionando como alias obsoleto de
cotctl bot-types versions; se elimina en la 1.0.0.
Flags de opt-in — las que cotctl nombra al negarse
Estas flags no se activan solas. cotctl las nombra en su propio mensaje cuando
se detiene ante una operación sensible, cuando no pudo verificar algo, o cuando
deja recursos a medio crear. Esa es también la frontera de la tabla: no es el
índice completo de flags que cambian el comportamiento. Una que altera cómo se
aplica un recurso sin que cotctl se detenga —--legacy-replace-workflows, por
ejemplo— vive en la documentación extendida del repositorio, no acá.
-y / --yes no reemplaza a ninguna: esa flag responde una confirmación, no
levanta una restricción.
| Flag | La declaran | Sin la flag |
|------|-------------|-------------|
| --allow-script-bots | apply · workflows apply · bots apply · slas apply · schedules apply · routines apply | Un YAML que declara un bot PBScript, CCJS o ESMCode —los que ejecutan JavaScript arbitrario— se rechaza y no se envía nada |
| --allow-reactivate | apply · users apply · jobtitles apply | Un YAML con isActive: true sobre un usuario o un cargo que hoy está inactivo se rechaza; cotctl no reactiva por descarte |
| --lax-code | apply · jobtitles apply | Un YAML cuyo code no cumple el patrón exigido se rechaza, tanto al crear como al actualizar. Con la flag, al actualizar un cargo cuyo code guardado tampoco lo cumplía, la validación baja a advertencia; al crear nunca, y tampoco si el code guardado sí cumplía (sería una regresión). Para actualizar un cargo de code heredado hay que conservar ese mismo code en el YAML: si el YAML trae id, cambiar el code se rechaza por inmutabilidad; si no lo trae —el caso por defecto, porque la exportación escribe el id comentado— cotctl no reconoce el registro y crea uno nuevo |
| --skip-remote-validation | apply · surveys apply (solo formularios) | Si el catálogo remoto de permisos no responde, el apply se detiene en vez de seguir a ciegas: sin ese catálogo los permisos podrían perderse en silencio. Con la flag, la validación remota de identificadores no se ejecuta |
| --rollback | apply · workflows apply | Si un apply de workflow falla a mitad de camino, los recursos que la corrida alcanzó a crear quedan en el servidor y cotctl solo avisa. Con la flag, los desactiva en orden inverso; es best-effort, no una transacción: un paso de desactivación que falla se registra y no detiene a los demás |
Para la ayuda detallada de cualquier comando:
cotctl <command> --helpAutenticación
cotctl login obtiene un ApiToken del entorno y lo guarda en un perfil local.
Siempre requiere dos datos: la URL del webclient y el subdominio de la compañía.
cotctl login --url web.micompania.cotalker.com --subdomain micompaniaEl modo por defecto abre el navegador para completar la sesión. Hay dos alternativas:
# Sin navegador: pide email y contraseña en la terminal
cotctl login --url web.micompania.cotalker.com --subdomain micompania --no-browser
# Pegar un ApiToken ya emitido, para quien no tiene permiso de crearlos
# (un administrador lo emite desde el panel del webclient)
cotctl login --url web.micompania.cotalker.com --subdomain micompania --paste-tokenPara un pipeline, o cualquier corrida sin terminal, hay dos formas que no piden nada por consola:
# Un ApiToken ya emitido, desde un archivo o por stdin
cotctl login --url web.micompania.cotalker.com --subdomain micompania --token @token.jwt# Sin perfil y sin escribir nada en disco: la credencial vive en el entorno
export COTCTL_TOKEN="$CI_COTCTL_TOKEN"
export COTCTL_API_URL="https://www.cotalker.com"
cotctl apply -f survey.yaml --yesCon una credencial de entorno se omite -c/--company: la compañía se lee del
claim company del propio token, así que no puede contradecirlo, y el
vencimiento sale de su exp. -c sigue ganando cuando está presente, de modo
que ninguna invocación existente cambia de significado porque COTCTL_TOKEN esté
exportado. COTCTL_COMPANY_ID es opcional y afirma contra qué compañía espera
correr el job: un token de otra detiene la corrida.
La credencial de entorno no se renueva sola. Ante un 401, o pasado el
vencimiento del token, cotctl se detiene nombrando COTCTL_TOKEN en lugar de
caer al prompt de contraseña. Tampoco la escribe en un perfil.
Si la URL no trae esquema, se asume https:// y el comando imprime la URL que
resolvió. Cuando la API no se sirve desde el mismo host que el webclient,
login prueba también el host hermano (www. ↔ web.) e informa cuál
respondió.
Verificación de compañía
El flujo por navegador se autentica contra la sesión que el navegador ya tenga,
y el --subdomain nunca llega a esa página. Por eso, antes de guardar nada,
login lee la compañía a la que pertenece el token recién emitido y la compara
con el --subdomain pedido. Si no coinciden, falla y nombra ambas.
Si la compañía no se puede leer, la verificación no concluye: en una terminal
interactiva login avisa y pregunta si guardar igual; sin terminal se detiene, y
--allow-unverified-company es la forma de continuar.
Lo que queda guardado es el ApiToken, no la sesión del navegador: la sesión web no se invalida cuando cotctl renueva su token.
Multi-perfil
cotctl admite varios perfiles para trabajar con distintos entornos. No hay
perfil por defecto ni perfil activo: -c / --company elige contra qué
perfil corre el comando, y el comando falla si lo necesita y no lo recibe.
El perfil se llama igual que el subdominio, salvo que cotctl login reciba
--profile <nombre>. Esa misma flag es la salida cuando el perfil ya existe y
no hay terminal donde confirmar la sobrescritura: --yes lo sobrescribe,
--profile lo guarda aparte.
La regla es más corta de verificar enunciada al revés. Esta es la lista
completa de comandos que funcionan sin -c; todos los demás lo exigen:
| Comando | Por qué no lo necesita |
|---------|------------------------|
| cotctl login | Es el que crea el perfil |
| cotctl logout [perfil] | Recibe el perfil como argumento posicional; -c es la alternativa |
| cotctl profile list · delete | Solo lee y escribe el archivo local de perfiles |
| cotctl skills | Instala las skills en la máquina local |
| cotctl mcp | Configura la conexión MCP en la máquina local |
| cotctl validate | Valida sin conexión — salvo con --remote o -w, que sí piden -c |
| cotctl workflows scaffold | Genera archivos locales, no consulta la API |
# Elegir contra qué perfil corre el comando
cotctl surveys list --company staging
# Ver todos los perfiles guardados
cotctl profile listLos perfiles se guardan en ~/.cotctl/config.json. Si el archivo queda con
permisos abiertos a otros usuarios, cotctl lo advierte e indica cómo corregirlo.
Claude Code Skills
cotctl incluye Skills para Claude Code que instalan herramientas y conocimiento especializado de Cotalker directamente en tu editor.
Skills disponibles
| Skill | Descripción |
|-------|-------------|
| cotctl-surveys | Crear y modificar YAMLs de formularios vía cotctl |
| cotctl-apply | Aplicar recursos YAML a entornos Cotalker |
| cotctl-export | Exportar y consultar recursos desde Cotalker |
| cotctl-properties | Generar tipos de propiedades y propiedades para Cotalker |
| cotctl-workflows | Crear y gestionar workflows, máquinas de estado y tareas |
| cotctl-roles | Crear y gestionar roles de acceso y permisos en Cotalker |
| cotctl-users | Crear, gestionar, exportar y aplicar YAMLs de usuarios |
| cotctl-jobtitles | Crear, gestionar, exportar y aplicar YAMLs de cargos |
| cotctl-routines | Crear, editar, listar, exportar y aplicar rutinas (PBScripts) |
| cotctl-bots | Crear, gestionar, exportar y aplicar YAMLs de bots de administración |
| cotctl-webhooks | Crear, editar, listar, exportar, probar y desactivar webhooks |
| cotalker-docs | Conocimiento general de la plataforma Cotalker |
Gestión de skills
# Listar las skills disponibles
cotctl skills list
# Instalar (selector interactivo)
cotctl skills install
# Instalar una específica de forma global
cotctl skills install cotctl-surveys --global
# Instalar todas en el proyecto actual
cotctl skills install --all --local
# Desinstalar
cotctl skills uninstall cotctl-surveys --globalMCP Server
cotctl puede configurar la conexión con el servidor MCP de Cotalker RAG, que le permite a Claude Code acceder a la documentación técnica actualizada de la plataforma.
La conexión MCP se configura automáticamente al instalar una skill, a menos que
uses --no-mcp.
Agrega a ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"cotalker-rag": {
"type": "http",
"url": "https://llm.cotalker.com/mcp"
}
}
}Agrega a .mcp.json en la raíz de tu proyecto (scope local) o
~/.claude/settings.json (scope global):
{
"mcpServers": {
"cotalker-rag": {
"type": "http",
"url": "https://llm.cotalker.com/mcp"
}
}
}O usa cotctl directamente:
# Scope global
cotctl mcp install --scope global
# Scope local (proyecto actual)
cotctl mcp install --scope local
# Ver las conexiones configuradas
cotctl mcp listDocumentación
Para la documentación detallada de cada comando:
cotctl <command> --helpPara instalar skills con documentación integrada para Claude Code:
cotctl skills install