CommunityProgramación y desarrollogithub.com

leynier/portifact

Publica y comparte artefactos estáticos (sitios HTML, Markdown y texto plano) con Portifact, controla quién puede verlos y recopila anotaciones de revisores. Úsalo cuando el usuario quiera compartir un plan, informe, prototipo o documento como enlace, o mencione Portifact, la CLI de Portifact o el servidor MCP de Portifact.

¿Qué es portifact?

Portifact es una herramienta diseñada para que agentes de IA (como Claude Code, Cursor, Codex) publiquen y compartan artefactos estáticos — sitios HTML, documentos Markdown y archivos de texto — con control de acceso, fechas de expiración y capacidad de restauración. Es útil cuando un agente necesita proporcionar un enlace a un plan, informe, prototipo o cualquier documento, permitiendo al usuario verlo en un navegador con políticas de seguridad configurables. La herramienta se utiliza a través de la CLI `portifact` o su servidor MCP remoto. Soporta publicación incremental, subida de archivos grandes por partes, control de acceso (restringido, autenticado o público), anotaciones de revisores autenticados, versionado y rollback, y descarga de fuentes privadas. Está diseñada para entornos de desarrollo y despliegue continuo, con énfasis en la seguridad, la integridad de los datos y la experiencia del desarrollador.

Compatible con✓Claude Code✓Codex CLI✓Cursor
npx skills add https://github.com/leynier/portifact/tree/HEAD/skills/portifact

Installed? Explore more Programación y desarrollo skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Preguntar en tu IA favorita

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

Documentación

¿Qué hace portifact?

Portifact publica artefactos estáticos con su propia URL, control de acceso, caducidad y restauración, y anotaciones opcionales de revisores autenticados. Los agentes lo usan a través de la CLI portifact o el servidor MCP remoto.

Verificar qué versiones de los comandos están soportadas

Portifact está en desarrollo temprano y gana comandos versión a versión. Antes de usar cualquier comando:

  1. Ejecuta portifact --version para confirmar que la CLI esté instalada.
  2. Ejecuta portifact --help para ver los comandos que soporta esta versión.
  3. Usa solo los comandos y banderas que enumera --help. Nunca adivines un comando. Si el usuario pide algo que la versión instalada no puede hacer, dilo y sugiere actualizar.

Las versiones cuyo --help enumera login pueden iniciar sesión, cerrar sesión y mostrar la cuenta conectada. Las versiones cuyo --help también enumera publish pueden publicar archivos y carpetas y gestionar artefactos y su acceso, y las versiones cuyo --help enumera versions, rollback y pull pueden listar versiones, revertir y descargar, y las versiones cuyo --help enumera annotations pueden gestionar hilos de comentarios, como se describe a continuación. Las versiones cuyo portifact publish --help enumera --source, --ref y --assets publican archivos ZIP, adjuntan fuentes privadas y publican activos Markdown; las versiones cuyo portifact pull --help enumera --git construyen un historial Git de las fuentes privadas; las versiones cuyo --help enumera usage muestran las cuotas de la cuenta; las versiones cuyo --help enumera logs muestran quién abrió un artefacto; y las versiones cuyo --help enumera licenses imprimen las licencias del software de código abierto en el binario (portifact licenses; también en https://portifact.com/third-party-notices). El servidor MCP en https://app.portifact.com/mcp puede listar, publicar y gestionar documentos pequeños; listar, descargar y revertir versiones; leer, escribir, moderar y exportar anotaciones; e informar sobre el uso y los registros de acceso; ver más abajo.

Instalar o actualizar la CLI

La CLI es un solo ejecutable y no necesita Node ni Bun. Pregunta antes de instalar software en la máquina del usuario.

curl -fsSL https://portifact.com/install | bash
irm https://portifact.com/install.ps1 | iex
  • En Alpine Linux, instala primero el runtime de C++: apk add libstdc++ libgcc.
  • Vuelve a ejecutar el mismo comando para actualizar.
  • Establece PORTIFACT_VERSION=0.2.0 para instalar una versión específica.
  • En entornos no interactivos o aislados, establece PORTIFACT_NO_MODIFY_PATH=1 y llama directamente a ~/.portifact/bin/portifact en lugar de editar los perfiles de shell.
  • El instalador verifica la descarga con las sumas de verificación de la versión y se detiene si hay una discrepancia. No eludas una verificación fallida.

Iniciar sesión

Comprueba primero con portifact whoami --json. El código de salida 0 imprime {"server","userId","clientId","scopes"}; el código de salida 3 significa que este dispositivo no ha iniciado sesión o la sesión ha terminado.

Para iniciar sesión, ejecuta portifact login (añade --json para un resultado analizable). Utiliza el flujo de dispositivo OAuth:

  1. La CLI imprime una página (https://app.portifact.com/device) y un código de 8 caracteres en stderr, y abre el navegador cuando hay una persona en la terminal. Pasa --no-browser para omitir la apertura.
  2. Muestra al usuario la página y el código exactamente como se imprimieron, y pídele que inicie sesión allí, que verifique que la página muestre el mismo código y que lo apruebe. Nunca lo apruebes por él, y nunca le pidas que pegue nada de esa página de vuelta. La página de inicio de sesión pide al usuario que confirme que es mayor de 18 años y que acepte los términos (https://portifact.com/terms); esa elección es suya, así que nunca la aceptes por él. Si la página dice que no puede enviar un código por correo electrónico a su dirección (correo anterior rebotado o reportado como spam) o que los códigos por correo electrónico están pausados para el mes, dile al usuario que inicie sesión con Google o GitHub.
  3. El comando espera hasta que el usuario apruebe o deniegue, o hasta que el código expire (10 minutos), así que ejecútalo donde el usuario pueda ver su stderr y déjalo terminar.

Las credenciales van al almacén de credenciales del sistema operativo. Cuando no hay ninguno (por ejemplo, un servidor Linux sin un Secret Service), van a credentials.json en el directorio de configuración del usuario (~/.config/portifact en Linux, ~/Library/Application Support/portifact en macOS, %APPDATA%\portifact en Windows) con permisos solo para el usuario, y la CLI imprime una advertencia. Nunca leas, imprimas, copies o subas ese archivo o los tokens almacenados; la CLI los renueva por sí sola.

portifact logout revoca los tokens de este dispositivo en el servidor y luego los elimina. Revoca tokens, así que confírmalo primero con el usuario. Si no se puede contactar al servidor, mantiene las credenciales y sale con código 1; ejecútalo de nuevo más tarde.

PORTIFACT_APP_ORIGIN apunta la CLI a otro servidor y existe para pruebas y staging. No lo establezcas a menos que el usuario lo pida.

Publicar

Solo en versiones cuyo --help enumere publish.

  1. Vista previa primero: portifact publish <ruta> --dry-run --json construye el manifiesto sin iniciar sesión ni subir nada. Devuelve {"dryRun","type","name","entrypoint","totalBytes","files":[{"path","size","sha256","contentType"}],"excluded":[{"path","reason"}]}, más "sources":{"chosenBy","totalBytes","files","excluded","origin","lfsPointers"} con --source. Muestra al usuario los archivos, las fuentes y lo que se omitió, y detente si algo parece privado.
  2. Publicar: portifact publish <ruta> --json. El resultado es {"artifactId","versionId","versionNumber","url","expiresAt","uploadId","files","totalBytes","sourceFiles","sourceBytes","sourceOrigin","uploadedFiles","uploadedBytes"}. El progreso y el manifiesto van a stderr.
  • El tipo se deduce de la ruta: una carpeta, un .zip o un archivo .html es un site, .md es markdown y .txt es text. Pasa --type site|markdown|text para otros archivos. Las carpetas y los archivos ZIP solo pueden ser sitios.
  • Un solo archivo HTML se publica como el index.html del sitio. Una carpeta necesita un index.html, o --entry <ruta> con la página que se abrirá primero.
  • --name establece el nombre que se muestra en la lista de artefactos; por defecto es el nombre del archivo o carpeta.
  • --artifact <id> publica una nueva versión de un artefacto existente, manteniendo su nombre, tipo y acceso a menos que --name cambie el nombre. Si alguien más publicó mientras tanto, falla con version_conflict (código de salida 6); comprueba el artefacto y publica de nuevo.
  • Las carpetas siempre omiten .git, node_modules, cachés, archivos del sistema y archivos que pueden contener secretos (.env y .env.* excepto ejemplos, .dev.vars, .npmrc, .netrc, claves SSH, *.pem, *.key, *.p12, estado de Terraform y similares). Nombrar un archivo de este tipo directamente es rechazado. El filtro es una red de seguridad, no una revisión: aún así verifica el manifiesto.
  • Los enlaces simbólicos y los archivos especiales son rechazados, nunca se siguen.
  • Los archivos que la cuenta ya almacena no se vuelven a subir. Las subidas interrumpidas se reintentan, y si la publicación falla después de que comenzó la subida, la CLI la cancela para que no quede medio publicado.
  • Las versiones cuyo progreso muestra Uploaded part <n> of <m> of <ruta> suben archivos de más de 64 MiB en partes de 16 MiB, transmitidas desde el disco, por lo que un archivo grande nunca tiene que caber en la memoria y una parte fallida se envía de nuevo por sí sola. Una versión tiene como máximo 250 MB de archivos publicados, sea cual sea el tamaño de las partes.
  • Un archivo ZIP se expande en la máquina del usuario antes de que se suba nada. Cuando todos los archivos dentro están dentro de una carpeta, esa carpeta se convierte en la raíz. Los enlaces, archivos especiales, entradas cifradas, rutas que salen del archivo, nombres que colisionan, entradas superpuestas, archivos que se expanden más allá de su tamaño declarado o más de 200 veces, más de 10,000 entradas y cualquier cosa por encima de los límites de tamaño son rechazados (invalid_input, código de salida 2, o quota_exceeded, código de salida 7). Las exclusiones predeterminadas y el filtro de secretos también se aplican a sus entradas.
  • --source <ruta> adjunta fuentes privadas a la versión: solo el propietario puede verlas y descargarlas (pull --source), cuentan para el almacenamiento pero no para el tamaño publicado, y los archivos publicados y las fuentes juntos son como máximo 1,000. La ruta puede ser una carpeta, un solo archivo o un archivo ZIP. En una carpeta dentro de un repositorio git, git elige los archivos: lo que versiona más los archivos nuevos que no ignora, sin submódulos ni repositorios anidados. --ref <commit> adjunta exactamente el árbol de ese commit en su lugar (una rama, etiqueta o ID de commit; nunca incluye cambios no confirmados). La CLI luego registra el commit, la rama, el remoto sin credenciales y si había cambios no confirmados como el sourceOrigin de la versión. Fuera de un repositorio, o sin git instalado, la carpeta se recorre con las exclusiones predeterminadas. Los archivos que pueden contener secretos nunca se adjuntan, diga lo que diga git. Una advertencia en stderr enumera los punteros de Git LFS, que se adjuntan como punteros, no como contenido; sugiere git lfs pull primero.
  • --assets <dir> publica una carpeta de imágenes y otros archivos junto con un documento Markdown, en su ruta relativa al documento, para que sus enlaces relativos funcionen. La carpeta debe estar dentro de la carpeta del documento, y se aplican las exclusiones predeterminadas.
  • Portifact renderiza un artefacto markdown o text por sí mismo: su URL abre una página renderizada a partir del documento, donde el HTML sin procesar en Markdown se muestra como texto y nada se ejecuta. El archivo original se descarga desde su propia ruta bajo la URL del artefacto (por ejemplo <url>plan.md, o <url>index.md para publish_document), con el mismo acceso que la página. Un documento tiene como máximo 5 MB de texto UTF-8, y un artefacto text es un solo archivo.

Gestionar artefactos

Solo en versiones cuyo --help enumere estos comandos. Cada comando acepta --json.

  • portifact list [--limit N] [--cursor C] [--search TEXTO] [--state active|archived|suspended|purging] [--type site|markdown|text] [--access public|authenticated|restricted] [--annotations off|open|locked] devuelve {"items":[...],"nextCursor"}; pasa nextCursor como --cursor, con los mismos filtros, para la página siguiente. Cada elemento es lo que devuelve portifact info más "activity":{"versions","currentBytes","openThreads","lastAnnotationAt"}: las versiones retenidas (incluida la actual), los bytes de la versión actual (archivos publicados y fuentes, null sin una versión), los hilos abiertos en la versión actual y cuándo cambió por última vez un hilo en cualquier versión (null sin hilos). El tráfico se cuenta por cuenta, no por artefacto, por lo que solo está en portifact usage. --search coincide con una parte del nombre (letras en cualquier caso) o del ID, y cada filtro dado debe cumplirse, así que úsalos para encontrar un artefacto en lugar de paginar por todo. portifact info <id> devuelve un elemento: {"id","name","type","state","accessMode","annotations","currentVersionId","url","expiresAt","archivedAt","purgeAt","createdAt","updatedAt"}, más "suspension":{"reason"} mientras el artefacto esté suspendido.
  • portifact renew <id>, archive <id> y restore <id> devuelven {"artifactId","state","expiresAt","purgeAt"}. Pregunta antes de archivar.
  • portifact delete <id> elimina permanentemente. Pide a la persona en la terminal que escriba el ID del artefacto; sin terminal requiere --yes y de lo contrario falla con código de salida 2. Solo pasa --yes después de que el usuario haya confirmado ese artefacto exacto.

Controlar el acceso

Solo en versiones cuyo --help enumere access. Cada comando acepta --json e imprime {"artifactId","mode","readers","indexable","embeddable","policyGeneration"}.

  • portifact access <id> muestra la política actual. Úsalo para informar el modo de acceso después de publicar.
  • portifact access set <id> restricted|authenticated|public: restricted es el propietario más los lectores listados, authenticated es cualquiera que haya iniciado sesión en Portifact, public es cualquiera con el enlace. Las cuentas en sus primeros 7 días no pueden hacer un artefacto público (account_too_new_for_public, código de salida 7).
  • portifact access add <id> <correo>... y access remove <id> <correo>... cambian la lista de lectores (como máximo 100 direcciones a la vez). Los lectores solo importan mientras el modo sea restricted.

Versiones, reversión y descarga

Solo en versiones cuyo --help enumere estos comandos. Cada comando acepta --json.

Un artefacto mantiene su versión actual más las versiones que reemplazó durante los últimos siete días. La reversión y la descarga funcionan solo en esas versiones retenidas.

  • portifact versions <id> las lista, primero las más recientes. --json imprime {"artifactId","items":[{"id","number","current","entrypoint","publishedBytes","sourceBytes","publishedFiles","sourceFiles","rendererVersion","committedAt","expiresAt","sourceOrigin"}]}; expiresAt es cuándo una versión anterior deja de retenerse y es null para la actual, y sourceOrigin es {"commit","branch","remote","dirty"} cuando las fuentes provienen de git, de lo contrario null. El origen es lo que declaró el publicador; Portifact no puede verificarlo.
  • portifact rollback <id> <id-de-versión> hace que una versión retenida vuelva a ser la actual. Se publica como una nueva versión con los mismos archivos, reinicia los 30 días y no cambia el acceso: los lectores eliminados desde esa versión permanecen eliminados. Pregunta al usuario antes de revertir. Devuelve {"artifactId","versionId","versionNumber","url","expiresAt","fromVersionId","fromVersionNumber"}. Si alguien publicó mientras tanto, falla con version_conflict (código de salida 6); comprueba versions de nuevo y pregunta al usuario. En versiones cuyo portifact rollback --help dice "version ID or number", <id-de-versión> también puede ser el número de versión (3 o v3), y pull --version también acepta uno; un número que no se retiene falla con not_found (código de salida 5).
  • portifact pull <id> --out <dir> descarga los archivos publicados de la versión actual en <dir>/published. Añade --source para las fuentes privadas (en <dir>/source, solo propietario), --published --source para ambas, y --version <id-de-versión> para una versión anterior. <dir> no debe existir aún; pull nunca escribe fuera de él, rechaza rutas dentro de una carpeta .git, verifica el SHA-256 de cada archivo y elimina la carpeta si algo falla (download_failed, código de salida 1). Devuelve {"artifactId","versionId","versionNumber","out","files":[{"kind","path","size","sha256"}],"totalBytes"}.

Anotaciones

Solo en versiones cuyo --help enumere annotations. Cada comando acepta --json. Las anotaciones son comentarios de revisores autenticados que están en la lista de lectores del artefacto, y el autor del artefacto. El servidor MCP también puede moderar y exportar.

  • portifact annotations status <id> devuelve {"artifactId","annotationsMode","autoCloseDays"}.
  • portifact annotations set <id> off|open|locked [--auto-close N] cambia el modo.
  • portifact annotations threads <id> [--cursor C] [--limit N] lista los hilos. Cada hilo: {"id","path","location","attributes","status","comments":[{"id","author","authorId","body","resolved","resolvedAt","createdAt"}],"createdAt","updatedAt"}; "path" es la ruta del archivo y "location" su ubicación (rango de líneas o fragmento). "attributes" lleva las etiquetas personalizadas del artefacto.
  • portifact annotations add <id> --message <texto> y --reply <id-de-hilo> --message <texto> crean hilos y comentarios.
  • portifact annotations resolve <id> <id-de-comentario> y unresolve <id> <id-de-comentario>.
  • portifact annotations export <id> [--out <archivo>] [--format csv|json] exporta las anotaciones.

Uso y registros

Solo en versiones cuyo --help enumere estos comandos. Cada comando acepta --json.

  • portifact usage devuelve {"artifacts","versions","publishedBytes","sourceBytes","annotations","trafficBytes"}. Los bytes son los totales de todos los artefactos; el tráfico es la suma de las descargas de páginas, fuentes y archivos en los últimos 30 días, actualizada cada pocas horas.
  • portifact logs <id> [--cursor C] [--limit N] devuelve {"items":[{"artifact","version","kind":"open|download","readers":[],"ip","country","userAgent","time"}],"nextCursor"}. Cada elemento muestra la versión abierta o descargada, los primeros lectores que coinciden con la política de acceso del artefacto en ese momento, y la IP y el agente de usuario. El artefacto debe ser tuyo.

Solución de problemas

  • La CLI usa el código de salida 0 en éxito, 1 en error desconocido o fallo de descarga, 2 en entrada inválida, 3 cuando no ha iniciado sesión, 4 en error del servidor, 5 en recurso no encontrado, 6 en conflicto de versión, 7 en cuota excedida, 8 cuando el artefacto está suspendido y 9 cuando la versión de la CLI es demasiado antigua. Los errores van a stderr.
  • Si dice "artifact suspension in effect", el artefacto está suspendido por el administrador. Dile al usuario que se ponga en contacto con el soporte.
  • Si dice "version storage limit reached", la versión es demasiado grande. Reduce el tamaño o las fuentes.
  • Si dice "creator cannot be a reader" al añadir un lector, el propietario ya es lector automáticamente.
  • Si dice "account over quota", la cuenta superó sus límites de almacenamiento. Actualiza el plan o elimina algunos artefactos.

Notas sobre el flujo de agente

  • Siempre previsualiza primero. El modo seco muestra lo que se subirá, destaca las rutas de fuentes privadas y enumera las omisiones. Si el usuario pide publicar, primero ejecuta la vista previa y muestra el resultado concisamente.
  • Siempre comprueba el estado de inicio de sesión. Si portifact whoami falla, no continúes con el flujo de publicación hasta que el usuario haya iniciado sesión.
  • No eludas la verificación de 18+ y los términos. La página de inicio de sesión se los muestra al usuario; cualquier decisión es exclusivamente suya.
  • Usa --json para analizar los resultados. La CLI imprime la salida legible y la JSON en diferentes flujos. Siempre captura la salida JSON para el siguiente paso del agente.
  • Manejo de errores. Cuando un comando falla, el código de salida y el mensaje de error en stderr te dicen por qué. Nunca asumas el motivo.
  • Límites. La versión actual soporta hasta 250 MB de archivos publicados, 1000 archivos totales (publicados + fuentes) y 100 direcciones de correo por operación de lista de acceso.

Skills relacionados