leynier/portifact

Publique e compartilhe artefatos estáticos (sites HTML, Markdown e texto simples) com a Portifact, controlando quem pode vê-los e coletando anotações dos revisores. Use quando o usuário quiser compartilhar um plano, relatório, protótipo ou documento como um link, ou mencionar Portifact, a CLI portifact ou o servidor MCP Portifact.

O que é portifact?

Portifact é uma ferramenta e serviço para publicar artefatos estáticos (sites HTML, documentos Markdown e texto simples) com URLs únicas, controle de acesso, expiração e restauração, além de anotações opcionais de revisores autenticados. Agentes de IA podem usar a CLI `portifact` (um único executável sem dependências Node ou Bun) ou um servidor MCP remoto em `https://app.portifact.com/mcp` para listar, publicar e gerenciar documentos, controlar versões, baixar, reverter, gerenciar anotações e relatar uso e logs de acesso. A ferramenta é útil para desenvolvedores que desejam compartilhar protótipos, relatórios ou planos com acesso controlado, coletar feedback por meio de anotações e garantir que os artefatos expirem após um período definido. Ela suporta autenticação via OAuth, upload de arquivos grandes em partes, anexo de fontes privadas (com suporte a git e LFS), e filtros de segurança para evitar vazamento de segredos, sendo adequada para ambientes de desenvolvimento, revisão de código e colaboração em equipe. A Portifact está em desenvolvimento inicial, então novos comandos e recursos são adicionados a cada versão; a CLI sempre mostra os comandos suportados via `--help`, e o agente deve verificar isso antes de usar qualquer comando.

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

Installed? Explore more Programação e Desenvolvimento skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

O que portifact faz?

A Portifact publica artefatos estáticos com seu próprio URL, controle de acesso, expiração e restauração, e anotações opcionais de revisores autenticados. Os agentes a utilizam através da CLI portifact ou do servidor MCP remoto.

Verifique quais versões suportam

A Portifact está em desenvolvimento inicial e ganha comandos a cada versão. Antes de usar qualquer comando:

  1. Execute portifact --version para confirmar que a CLI está instalada.
  2. Execute portifact --help para ver os comandos que esta versão suporta.
  3. Use apenas comandos e flags que --help lista. Nunca adivinhe um comando. Se o usuário pedir algo que a versão instalada não pode fazer, diga isso e sugira a atualização.

Versões cujo --help lista login podem fazer login, logout e mostrar a conta conectada. Versões cujo --help também lista publish podem publicar arquivos e pastas e gerenciar artefatos e seu acesso, e versões cujo --help lista versions, rollback e pull podem listar versões, reverter e baixar, e versões cujo --help lista annotations podem gerenciar threads de comentários, conforme descrito abaixo. Versões onde portifact publish --help lista --source, --ref e --assets publicam arquivos ZIP, anexam fontes privadas e publicam assets Markdown; versões onde portifact pull --help lista --git constroem um histórico Git das fontes privadas; versões cujo --help lista usage mostram as cotas da conta; versões cujo --help lista logs mostram quem abriu um artefato; e versões cujo --help lista licenses imprimem as licenças do software de código aberto no binário (portifact licenses; também em https://portifact.com/third-party-notices). O servidor MCP em https://app.portifact.com/mcp pode listar, publicar e gerenciar documentos pequenos, listar, baixar e reverter versões, ler, escrever, moderar e exportar anotações, e reportar uso e logs de acesso; veja abaixo.

Instalar ou atualizar a CLI

A CLI é um único executável e não precisa de Node ou Bun. Pergunte antes de instalar software na máquina do usuário.

curl -fsSL https://portifact.com/install | bash
irm https://portifact.com/install.ps1 | iex
  • No Alpine Linux, instale o runtime C++ primeiro: apk add libstdc++ libgcc.
  • Execute o mesmo comando novamente para atualizar.
  • Defina PORTIFACT_VERSION=0.2.0 para instalar uma versão específica.
  • Em ambientes não interativos ou isolados, defina PORTIFACT_NO_MODIFY_PATH=1 e chame ~/.portifact/bin/portifact diretamente em vez de editar perfis de shell.
  • O instalador verifica o download com os checksums de lançamento e para em caso de incompatibilidade. Não ignore uma verificação falha.

Fazer login

Verifique primeiro com portifact whoami --json. Código de saída 0 imprime {"server","userId","clientId","scopes"}; código de saída 3 significa que este dispositivo não está conectado ou a sessão expirou.

Para fazer login, execute portifact login (adicione --json para um resultado parseável). Ele usa o fluxo de dispositivo OAuth:

  1. A CLI imprime uma página (https://app.portifact.com/device) e um código de 8 caracteres no stderr, e abre o navegador quando uma pessoa está no terminal. Passe --no-browser para pular a abertura.
  2. Mostre ao usuário a página e o código exatamente como impressos, e peça para ele fazer login lá, verificar se a página mostra o mesmo código e aprová-lo. Nunca aprove por ele e nunca peça para ele colar nada dessa página de volta para você. A página de login pede ao usuário para confirmar que tem 18 anos ou mais e aceitar os termos (https://portifact.com/terms); essa escolha é dele, então nunca a aceite por ele. Se a página disser que não pode enviar um código de e-mail para o endereço dele (e-mail anterior foi devolvido ou denunciado como spam) ou que os códigos de e-mail estão pausados para o mês, diga ao usuário para fazer login com Google ou GitHub.
  3. O comando aguarda até que o usuário aprove ou negue, ou o código expire (10 minutos), então execute-o onde o usuário possa ver seu stderr e deixe-o terminar.

As credenciais vão para o armazenamento de credenciais do sistema operacional. Quando não houver nenhum (por exemplo, um servidor Linux sem um Secret Service), elas vão para credentials.json no diretório de configuração do usuário (~/.config/portifact no Linux, ~/Library/Application Support/portifact no macOS, %APPDATA%\portifact no Windows) com permissões apenas para o usuário, e a CLI imprime um aviso. Nunca leia, imprima, copie ou faça upload desse arquivo ou dos tokens armazenados; a CLI os atualiza sozinha.

portifact logout revoga os tokens deste dispositivo no servidor e depois os remove. Ele revoga tokens, então confirme com o usuário primeiro. Se o servidor não puder ser alcançado, ele mantém as credenciais e sai com código 1; execute novamente mais tarde.

PORTIFACT_APP_ORIGIN aponta a CLI para outro servidor e existe para testes e staging. Não o defina a menos que o usuário peça.

Publicar

Apenas em versões cujo --help lista publish.

  1. Visualize primeiro: portifact publish <caminho> --dry-run --json constrói o manifesto sem fazer login ou enviar. Retorna {"dryRun","type","name","entrypoint","totalBytes","files":[{"path","size","sha256","contentType"}],"excluded":[{"path","reason"}]}, além de "sources":{"chosenBy","totalBytes","files","excluded","origin","lfsPointers"} com --source. Mostre ao usuário os arquivos, as fontes e o que foi deixado de fora, e pare se algo parecer privado.
  2. Publique: portifact publish <caminho> --json. O resultado é {"artifactId","versionId","versionNumber","url","expiresAt","uploadId","files","totalBytes","sourceFiles","sourceBytes","sourceOrigin","uploadedFiles","uploadedBytes"}. O progresso e o manifesto vão para o stderr.
  • O tipo é inferido a partir do caminho: uma pasta, um arquivo .zip ou .html é um site, .md é markdown e .txt é text. Passe --type site|markdown|text para outros arquivos. Pastas e arquivos ZIP só podem ser sites.
  • Um único arquivo HTML é publicado como o index.html do site. Uma pasta precisa de um index.html, ou --entry <caminho> com a página para abrir primeiro.
  • --name define o nome mostrado na lista de artefatos; o padrão é o nome do arquivo ou pasta.
  • --artifact <id> publica uma nova versão de um artefato existente, mantendo seu nome, tipo e acesso, a menos que --name mude o nome. Se alguém publicou no meio tempo, falha com version_conflict (saída 6); verifique o artefato e publique novamente.
  • Pastas sempre excluem .git, node_modules, caches, arquivos do sistema e arquivos que podem conter segredos (.env e .env.* exceto exemplos, .dev.vars, .npmrc, .netrc, chaves SSH, *.pem, *.key, *.p12, estado do Terraform e similares). Nomear tal arquivo diretamente é recusado. O filtro é uma rede de segurança, não uma revisão: ainda verifique o manifesto.
  • Links simbólicos e arquivos especiais são recusados, nunca seguidos.
  • Arquivos que a conta já armazena não são enviados novamente. Uploads interrompidos são repetidos, e se a publicação falhar após o upload ter começado, a CLI o cancela para que nada seja publicado pela metade.
  • Versões cujo progresso mostra Uploaded part <n> of <m> of <caminho> enviam arquivos com mais de 64 MiB em partes de 16 MiB, transmitidos do disco, para que um arquivo grande nunca precise caber na memória e uma parte falha seja enviada novamente por conta própria. Uma versão contém no máximo 250 MB de arquivos publicados, independentemente do tamanho da parte.
  • Um arquivo ZIP é expandido na máquina do usuário antes de qualquer upload ser feito. Quando todos os arquivos dentro dele estão em uma pasta, essa pasta se torna a raiz. Links, arquivos especiais, entradas criptografadas, caminhos que saem do arquivo, nomes conflitantes, entradas sobrepostas, arquivos que se expandem além do tamanho declarado ou mais de 200 vezes, mais de 10.000 entradas e qualquer coisa acima dos limites de tamanho são recusados (invalid_input, saída 2, ou quota_exceeded, saída 7). As exclusões padrão e o filtro de segredos também se aplicam às suas entradas.
  • --source <caminho> anexa fontes privadas à versão: apenas o proprietário pode vê-las e baixá-las (pull --source), elas contam para o armazenamento, mas não para o tamanho publicado, e os arquivos publicados e de fonte juntos têm no máximo 1.000. O caminho pode ser uma pasta, um único arquivo ou um arquivo ZIP. Em uma pasta dentro de um repositório git, o git escolhe os arquivos: o que ele versiona mais novos arquivos que não ignora, sem submódulos ou repositórios aninhados. --ref <commit> anexa exatamente a árvore desse commit (um branch, tag ou ID de commit; nunca inclui alterações não commitadas). A CLI então registra o commit, o branch, o remoto sem credenciais e se houve alterações não commitadas como o sourceOrigin da versão. Fora de um repositório, ou sem git instalado, a pasta é percorrida com as exclusões padrão. Arquivos que podem conter segredos nunca são anexados, independentemente do que o git disser. Um aviso no stderr lista os ponteiros Git LFS, que são anexados como ponteiros, não como conteúdo; sugira git lfs pull primeiro.
  • --assets <dir> publica uma pasta de imagens e outros arquivos com um documento Markdown, em seu caminho relativo ao documento, para que seus links relativos funcionem. A pasta deve estar dentro da pasta do documento, e as exclusões padrão se aplicam.
  • A Portifact renderiza um artefato markdown ou text por conta própria: seu URL abre uma página renderizada a partir do documento, onde HTML bruto em Markdown é mostrado como texto e nada é executado. O arquivo original é baixado de seu próprio caminho sob o URL do artefato (por exemplo <url>plan.md, ou <url>index.md para publish_document), com o mesmo acesso da página. Um documento tem no máximo 5 MB de texto UTF-8, e um artefato text é um único arquivo.

Gerenciar artefatos

Apenas em versões cujo --help lista esses comandos. Todo comando aceita --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] retorna {"items":[...],"nextCursor"}; passe nextCursor como --cursor, com os mesmos filtros, para a próxima página. Cada item é o que portifact info retorna mais "activity":{"versions","currentBytes","openThreads","lastAnnotationAt"}: as versões retidas (a atual incluída), os bytes da versão atual (arquivos publicados e fontes, null sem uma versão), os tópicos abertos na versão atual e quando um tópico em qualquer versão mudou pela última vez (null sem tópicos). O tráfego é contado por conta, não por artefato, portanto está apenas em portifact usage. --search corresponde a uma parte do nome (letras em qualquer maiúscula/minúscula) ou do ID, e cada filtro fornecido deve ser verdadeiro, então use-os para encontrar um artefato em vez de percorrer tudo. portifact info <id> retorna um item: {"id","name","type","state","accessMode","annotations","currentVersionId","url","expiresAt","archivedAt","purgeAt","createdAt","updatedAt"}, mais "suspension":{"reason"} enquanto o artefato estiver suspenso.
  • portifact renew <id>, archive <id> e restore <id> retornam {"artifactId","state","expiresAt","purgeAt"}. Pergunte antes de arquivar.
  • portifact delete <id> exclui permanentemente. Ele pede que a pessoa no terminal digite o ID do artefato; sem um terminal, requer --yes e, caso contrário, falha com saída 2. Só passe --yes depois que o usuário confirmar esse artefato exato.

Controlar acesso

Apenas em versões cujo --help lista access. Todo comando aceita --json e imprime {"artifactId","mode","readers","indexable","embeddable","policyGeneration"}.

  • portifact access <id> mostra a política atual. Use-o para relatar o modo de acesso após a publicação.
  • portifact access set <id> restricted|authenticated|public: restricted é o proprietário mais leitores listados, authenticated é qualquer pessoa conectada à Portifact, public é qualquer pessoa com o link. Contas nos primeiros 7 dias não podem tornar um artefato público (account_too_new_for_public, saída 7).
  • portifact access add <id> <email>... e access remove <id> <email>... alteram a lista de leitores (no máximo 100 endereços por vez). Os leitores só importam enquanto o modo é restricted.

Versões, reversão e download

Apenas em versões cujo --help lista esses comandos. Todo comando aceita --json.

Um artefato mantém sua versão atual mais as versões que a substituíram durante os últimos sete dias. A reversão e o download funcionam apenas nessas versões retidas.

  • portifact versions <id> lista-as, da mais recente para a mais antiga. --json imprime {"artifactId","items":[{"id","number","current","entrypoint","publishedBytes","sourceBytes","publishedFiles","sourceFiles","rendererVersion","committedAt","expiresAt","sourceOrigin"}]}; expiresAt é quando uma versão anterior para de ser retida e é null para a atual, e sourceOrigin é {"commit","branch","remote","dirty"} quando as fontes vieram do git, caso contrário, null. A origem é o que o editor declarou; a Portifact não pode verificá-la.
  • portifact rollback <id> <versão-id> torna uma versão retida atual novamente. Ela é publicada como uma nova versão com os mesmos arquivos, reinicia os 30 dias e não altera o acesso: leitores removidos desde essa versão permanecem removidos. Pergunte ao usuário antes de reverter. Retorna {"artifactId","versionId","versionNumber","url","expiresAt","fromVersionId","fromVersionNumber"}. Se alguém publicou no meio tempo, falha com version_conflict (saída 6); verifique versions novamente e pergunte ao usuário. Em versões cujo portifact rollback --help diz "version ID or number", <versão-id> também pode ser o número da versão (3 ou v3), e pull --version aceita um também; um número que não é retido falha com not_found (saída 5).
  • portifact pull <id> --out <dir> baixa os arquivos publicados da versão atual em <dir>/published. Adicione --source para as fontes privadas (em <dir>/source, apenas proprietário), --published --source para ambos, e --version <versão-id> para uma versão anterior. <dir> não deve existir ainda; o pull nunca escreve fora dele, recusa caminhos dentro de uma pasta .git, verifica o SHA-256 de cada arquivo e remove a pasta se algo falhar (download_failed, saída 1). Retorna {"artifactId","versionId","versionNumber","out","files":[{"kind","path","size","sha256"}],"totalBytes"}. Se um artefato é compartilhado com alguém, o total de bytes inclui tudo; você pode baixar apenas os arquivos publicados ou apenas as fontes. O diretório de saída é criado com permissões seguras.

Anotações

Apenas em versões cujo --help lista annotations. Todo comando aceita --json.

Um artefato pode ter anotações em qualquer estado de acesso. O estado de anotações de um artefato é off, open ou locked, e portifact access set não o altera; veja portifact annotations.

  • portifact annotations on|off|lock <id> define o estado de anotações do artefato. off remove anotações existentes, open permite novas, locked mantém as existentes, mas impede novas; pergunte ao usuário antes de mudar para off.
  • portifact annotations list <id> lista tópicos de anotação na versão atual, cada um com seu threadId e contagem de comentários. Passe --all-versions para listar tópicos no artefato, e --open apenas para tópicos abertos.
  • portifact annotations export <id> [--format json|xlsx|md|csv] [--no-comments] exporta anotações do artefato. O formato padrão é json; passe - no lugar de <id> para exportar da entrada padrão.
  • portifact annotations threads <id> add <texto> cria um tópico de anotação na versão atual. Ele tenta incluir citações no contexto de seleção do usuário; anotações sem contexto são colocadas no início do documento.
  • portifact annotations threads <id> reply <thread-id> <texto> e resolve|reopen gerenciam um tópico. resolve usa padrão "Resolvido"; cubra outros padrões com "resolvido". Sempre anexe um comentário ao resolver; nunca resolva sem ele.

Uso e logs

Apenas em versões cujo --help lista usage ou logs.

  • portifact usage --json retorna a cota de armazenamento da conta (storageLimit, storageUsed), a cota de anotações (annotationLimit, annotationsUsed), a cota de tráfego (trafficLimit, trafficUsed), data de reinício do tráfego (trafficResetsAt) e se o artefato é público (publicAllowed).
  • portifact logs <id> [--limit N] [--cursor C] [--geocode] retorna quem abriu este artefato (items: [{requestId, artifactId, ip, userAgent, method, path, status, bytes, durationMs, createdAt}]). O tráfego não anônimo é o único tráfego registrado e é mantido por 30 dias. Passe --geocode para incluir cidade/país aproximados a partir do IP; a própria Portifact geocodifica e nunca compartilha IPs brutos. Os itens são por solicitação; várias visualizações da mesma pessoa na mesma página, com ou sem autenticação, aparecem separadamente. Um item com status 402 é uma solicitação de visualização de um documento que foi bloqueada porque uma das cotas foi excedida.

Licenças

Apenas em versões cujo --help lista licenses. portifact licenses imprime as licenças de código aberto do binário. O mesmo conteúdo está em https://portifact.com/third-party-notices. Esse arquivo também é empacotado com o binário e está disponível sem uma conta.

Configuração

PORTIFACT_APP_ORIGIN (string de URL) aponta a CLI para um servidor Portifact não padrão. Existe para testes e staging; não defina a menos que o usuário peça.

PORTIFACT_MCP_ALLOW_TOOLS (string de ferramentas separadas por vírgula) restringe quais ferramentas MCP este servidor pode expor. O valor padrão permite todas.

Servidor MCP

A Portifact também expõe um servidor MCP em https://app.portifact.com/mcp que agentes compatíveis com MCP podem usar para ler, escrever e moderar artefatos. A lista exata de ferramentas muda à medida que o servidor evolui; consulte seu ponto final de lista de ferramentas e nunca invente uma. As ferramentas disponíveis incluem:

  • Listar artefatos – Busca artefatos por nome, tipo, estado, modo de acesso e estado de anotações.
  • Obter informações do artefato – Detalhes de um artefato pelo seu ID.
  • Publicar artefato (documento) – Publica um documento Markdown ou texto com metadados (nome, tipo, modo de acesso, lista de leitores). Usa texto simples (não caminhos de arquivo); documentos pequenos apenas (5 MB de texto).
  • Listar versões – Versões retidas de um artefato.
  • Baixar versão – O texto do documento atual ou de uma versão anterior.
  • Reverter versão – Torna uma versão anterior a atual.
  • Ler anotações – Tópicos de anotação de um artefato.
  • Escrever anotação – Adiciona um novo tópico de anotação a um artefato.
  • Responder a anotação – Adiciona um comentário a um tópico existente.
  • Moderar anotações – Resolve ou reabre um tópico de anotação.
  • Exportar anotações – Todas as anotações de um artefato em JSON, XLSX, Markdown ou CSV.
  • Obter uso – Cotas e uso da conta.
  • Obter logs de acesso – Quem abriu um artefato.

Para usar com o Claude Code, adicione ao seu ~/.claude.json5:

{
  mcpServers: {
    portifact: {
      command: "npx",
      args: ["-y", "@portifact/mcp-server"]
    }
  }
}

A ferramenta publish_document retorna detalhes do artefato publicado; a ferramenta list_artifacts retorna um cursor para paginação.

Habilidades Relacionadas