Que fait portifact ?
Portifact publie des artefacts statiques avec leur propre URL, un contrôle d'accès, une expiration et une restauration, ainsi que des annotations optionnelles de la part de réviseurs authentifiés. Les agents l'utilisent via l'interface CLI portifact ou le serveur MCP distant.
Vérifier ce que la version installée prend en charge
Portifact est en développement précoce et gagne des commandes au fil des versions. Avant d'utiliser une commande :
- Exécutez
portifact --versionpour confirmer que l'interface CLI est installée. - Exécutez
portifact --helppour voir les commandes que cette version prend en charge. - Utilisez uniquement les commandes et les options listées par
--help. Ne devinez jamais une commande. Si l'utilisateur demande quelque chose que la version installée ne peut pas faire, dites-le et suggérez une mise à jour.
Les versions dont --help liste login peuvent se connecter, se déconnecter et afficher le compte connecté. Les versions dont --help liste également publish peuvent publier des fichiers et dossiers et gérer les artefacts et leur accès. Les versions dont --help liste versions, rollback et pull peuvent lister les versions, effectuer des rollbacks et télécharger. Les versions dont --help liste annotations peuvent gérer les fils de commentaires, comme décrit ci-dessous. Les versions dont portifact publish --help liste --source, --ref et --assets publient des fichiers ZIP, attachent des sources privées et publient des ressources Markdown. Les versions dont portifact pull --help liste --git construisent un historique Git des sources privées. Les versions dont --help liste usage affichent les quotas du compte. Les versions dont --help liste logs montrent qui a ouvert un artefact. Les versions dont --help liste licenses impriment les licences des logiciels open source dans le binaire (portifact licenses ; également sur https://portifact.com/third-party-notices). Le serveur MCP sur https://app.portifact.com/mcp peut lister, publier et gérer de petits documents, lister, télécharger et effectuer des rollbacks de versions, lire, écrire, modérer et exporter des annotations, et rapporter les logs d'utilisation et d'accès ; voir ci-dessous.
Installer ou mettre à jour l'interface CLI
L'interface CLI est un exécutable unique et ne nécessite ni Node ni Bun. Demandez avant d'installer un logiciel sur la machine de l'utilisateur.
curl -fsSL https://portifact.com/install | bash
irm https://portifact.com/install.ps1 | iex
- Sur Alpine Linux, installez d'abord l'environnement d'exécution C++ :
apk add libstdc++ libgcc. - Réexécutez la même commande pour mettre à jour.
- Définissez
PORTIFACT_VERSION=0.2.0pour installer une version spécifique. - Dans les environnements non interactifs ou sandboxés, définissez
PORTIFACT_NO_MODIFY_PATH=1et appelez directement~/.portifact/bin/portifactau lieu de modifier les profils shell. - Le programme d'installation vérifie le téléchargement par rapport aux sommes de contrôle de la version et s'arrête en cas de non-concordance. Ne contournez pas une vérification échouée.
Se connecter
Vérifiez d'abord avec portifact whoami --json. Le code de sortie 0 imprime {"server","userId","clientId","scopes"} ; le code de sortie 3 signifie que cet appareil n'est pas connecté ou que la session a expiré.
Pour se connecter, exécutez portifact login (ajoutez --json pour un résultat analysable). Il utilise le flux OAuth de périphérique :
- L'interface CLI imprime une page (
https://app.portifact.com/device) et un code à 8 caractères sur stderr, et ouvre le navigateur lorsqu'une personne est au terminal. Passez--no-browserpour ignorer l'ouverture. - Montrez à l'utilisateur la page et le code exactement comme imprimés, et demandez-lui de s'y connecter, de vérifier que la page affiche le même code et de l'approuver. Ne l'approuvez jamais à sa place et ne lui demandez jamais de coller quoi que ce soit de cette page vers vous. La page de connexion demande à l'utilisateur de confirmer qu'il a 18 ans ou plus et d'accepter les conditions (
https://portifact.com/terms) ; ce choix lui appartient, donc ne l'acceptez jamais à sa place. Si la page indique qu'elle ne peut pas envoyer un code par e-mail à son adresse (un e-mail précédent a été rejeté ou signalé comme spam) ou que les codes e-mail sont en pause pour le mois, dites à l'utilisateur de se connecter avec Google ou GitHub à la place. - La commande attend que l'utilisateur approuve ou refuse, ou que le code expire (10 minutes), alors exécutez-la là où l'utilisateur peut voir son stderr et laissez-la se terminer.
Les informations d'identification vont dans le magasin d'identifiants du système d'exploitation. Lorsqu'il n'y en a pas (par exemple, un serveur Linux sans Secret Service), elles vont dans credentials.json dans le répertoire de configuration de l'utilisateur (~/.config/portifact sur Linux, ~/Library/Application Support/portifact sur macOS, %APPDATA%\portifact sur Windows) avec des autorisations pour l'utilisateur uniquement, et l'interface CLI imprime un avertissement. Ne lisez, n'imprimez, ne copiez et ne téléchargez jamais ce fichier ou les jetons stockés ; l'interface CLI les rafraîchit toute seule.
portifact logout révoque les jetons de cet appareil sur le serveur, puis les supprime. Il révoque les jetons, alors confirmez d'abord avec l'utilisateur. Si le serveur est inaccessible, il conserve les informations d'identification et se termine avec le code 1 ; réexécutez-le plus tard.
PORTIFACT_APP_ORIGIN pointe l'interface CLI vers un autre serveur et existe pour les tests et les environnements de staging. Ne le définissez pas sauf si l'utilisateur le demande.
Publier
Uniquement dans les versions dont --help liste publish.
- Prévisualisez d'abord :
portifact publish <chemin> --dry-run --jsonconstruit le manifeste sans se connecter ni télécharger. Il renvoie{"dryRun","type","name","entrypoint","totalBytes","files":[{"path","size","sha256","contentType"}],"excluded":[{"path","reason"}]}, plus"sources":{"chosenBy","totalBytes","files","excluded","origin","lfsPointers"}avec--source. Montrez à l'utilisateur les fichiers, les sources et ce qui a été exclu, et arrêtez-vous si quelque chose semble privé. - Publiez :
portifact publish <chemin> --json. Le résultat est{"artifactId","versionId","versionNumber","url","expiresAt","uploadId","files","totalBytes","sourceFiles","sourceBytes","sourceOrigin","uploadedFiles","uploadedBytes"}. La progression et le manifeste vont sur stderr.
- Le type est déduit du chemin : un dossier, un fichier
.zipou.htmlest unsite,.mdestmarkdownet.txtesttext. Passez--type site|markdown|textpour d'autres fichiers. Les dossiers et les fichiers ZIP ne peuvent être que des sites. - Un fichier HTML unique est publié en tant que
index.htmldu site. Un dossier a besoin d'unindex.html, ou--entry <chemin>avec la page à ouvrir en premier. --namedéfinit le nom affiché dans la liste des artefacts ; il prend par défaut le nom du fichier ou du dossier.--artifact <id>publie une nouvelle version d'un artefact existant, en conservant son nom, son type et son accès, sauf si--namechange le nom. Si quelqu'un d'autre a publié entre-temps, il échoue avecversion_conflict(code de sortie 6) ; vérifiez l'artefact et publiez à nouveau.- Les dossiers excluent toujours
.git,node_modules, les caches, les fichiers OS et les fichiers pouvant contenir des secrets (.envet.env.*sauf les exemples,.dev.vars,.npmrc,.netrc, les clés SSH,*.pem,*.key,*.p12, l'état Terraform et similaires). Nommer directement un tel fichier est refusé. Le filtre est un filet de sécurité, pas une revue : vérifiez toujours le manifeste. - Les liens symboliques et les fichiers spéciaux sont refusés, jamais suivis.
- Les fichiers que le compte stocke déjà ne sont pas téléchargés à nouveau. Les téléchargements interrompus sont relancés, et si la publication échoue après le début du téléchargement, l'interface CLI l'annule afin que rien ne soit à moitié publié.
- Les versions dont la progression affiche
Uploaded part <n> of <m> of <chemin>téléchargent les fichiers de plus de 64 Mo en parties de 16 Mo, diffusées depuis le disque, de sorte qu'un fichier volumineux n'a jamais à tenir en mémoire et qu'une partie échouée est renvoyée seule. Une version ne contient au maximum que 250 Mo de fichiers publiés, quelle que soit la taille des parties. - Un fichier ZIP est développé sur la machine de l'utilisateur avant que quoi que ce soit ne soit téléchargé. Lorsque tous les fichiers qu'il contient se trouvent dans un seul dossier, ce dossier devient la racine. Les liens, les fichiers spéciaux, les entrées cryptées, les chemins qui quittent l'archive, les noms en conflit, les entrées qui se chevauchent, les fichiers qui se développent au-delà de leur taille déclarée ou plus de 200 fois, plus de 10 000 entrées et tout ce qui dépasse les limites de taille sont refusés (
invalid_input, code de sortie 2, ouquota_exceeded, code de sortie 7). Les exclusions par défaut et le filtre de secrets s'appliquent également à ses entrées. --source <chemin>attache des sources privées à la version : seul le propriétaire peut les voir et les télécharger (pull --source), elles comptent pour le stockage mais pas pour la taille publiée, et les fichiers publiés et sources ensemble font au maximum 1 000. Le chemin peut être un dossier, un seul fichier ou un fichier ZIP. Dans un dossier à l'intérieur d'un dépôt git, git choisit les fichiers : ce qu'il versionne plus les nouveaux fichiers qu'il n'ignore pas, sans sous-modules ni dépôts imbriqués.--ref <commit>attache exactement l'arbre de ce commit à la place (une branche, une étiquette ou un ID de commit ; il n'inclut jamais les modifications non validées). L'interface CLI enregistre ensuite le commit, la branche, le remote sans informations d'identification et s'il y avait des modifications non validées commesourceOriginde la version. En dehors d'un dépôt, ou sansgitinstallé, le dossier est parcouru avec les exclusions par défaut. Les fichiers pouvant contenir des secrets ne sont jamais attachés, quoi que dise git. Un avertissement sur stderr liste les pointeurs Git LFS, qui sont attachés en tant que pointeurs, pas en tant que contenu ; suggérezgit lfs pulld'abord.--assets <rép>publie un dossier d'images et d'autres fichiers avec un document Markdown, à leur chemin relatif par rapport au document, afin que ses liens relatifs fonctionnent. Le dossier doit se trouver à l'intérieur du dossier du document, et les exclusions par défaut s'appliquent.- Portifact rend lui-même un artefact
markdownoutext: son URL ouvre une page rendue à partir du document, où le HTML brut dans Markdown s'affiche sous forme de texte et rien ne s'exécute. Le fichier original se télécharge depuis son propre chemin sous l'URL de l'artefact (par exemple<url>plan.md, ou<url>index.mdpourpublish_document), avec le même accès que la page. Un document fait au maximum 5 Mo de texte UTF-8, et un artefacttextest un seul fichier.
Gérer les artefacts
Uniquement dans les versions dont --help liste ces commandes. Chaque commande prend --json.
portifact list [--limit N] [--cursor C] [--search TEXTE] [--state active|archived|suspended|purging] [--type site|markdown|text] [--access public|authenticated|restricted] [--annotations off|open|locked]renvoie{"items":[...],"nextCursor"}; passeznextCursorcomme--cursor, avec les mêmes filtres, pour la page suivante. Chaque élément est ce queportifact inforenvoie plus"activity":{"versions","currentBytes","openThreads","lastAnnotationAt"}: les versions conservées (la version actuelle incluse), les octets de la version actuelle (fichiers publiés et sources,nullsans version), les fils ouverts sur la version actuelle et quand un fil sur une version a changé pour la dernière fois (nullsans fils). Le trafic est compté par compte, pas par artefact, donc il est uniquement dansportifact usage.--searchcorrespond à une partie du nom (lettres dans n'importe quel cas) ou de l'ID, et chaque filtre donné doit être vrai, alors utilisez-les pour trouver un artefact au lieu de parcourir les pages de tout.portifact info <id>renvoie un élément :{"id","name","type","state","accessMode","annotations","currentVersionId","url","expiresAt","archivedAt","purgeAt","createdAt","updatedAt"}, plus"suspension":{"reason"}pendant que l'artefact est suspendu.portifact renew <id>,archive <id>etrestore <id>renvoient{"artifactId","state","expiresAt","purgeAt"}. Demandez avant d'archiver.portifact delete <id>supprime définitivement. Il demande à la personne au terminal de taper l'ID de l'artefact ; sans terminal, il nécessite--yeset échoue sinon avec le code de sortie 2. Ne passez--yesqu'après que l'utilisateur a confirmé cet artefact exact.
Contrôler l'accès
Uniquement dans les versions dont --help liste access. Chaque commande prend --json et imprime {"artifactId","mode","readers","indexable","embeddable","policyGeneration"}.
portifact access <id>montre la politique actuelle. Utilisez-la pour signaler le mode d'accès après la publication.portifact access set <id> restricted|authenticated|public:restrictedest le propriétaire plus les lecteurs listés,authenticatedest toute personne connectée à Portifact,publicest toute personne ayant le lien. Les comptes dans leurs 7 premiers jours ne peuvent pas rendre un artefact public (account_too_new_for_public, code de sortie 7).portifact access add <id> <email>...etaccess remove <id> <email>...modifient la liste des lecteurs (au maximum 100 adresses à la fois). Les lecteurs ne sont importants que lorsque le mode estrestricted.
Versions, rollback et téléchargement
Uniquement dans les versions dont --help liste ces commandes. Chaque commande prend --json.
Un artefact conserve sa version actuelle plus les versions qu'il a remplacées au cours des sept derniers jours. Le rollback et le téléchargement ne fonctionnent que sur ces versions conservées.
portifact versions <id>les liste, de la plus récente à la plus ancienne.--jsonimprime{"artifactId","items":[{"id","number","current","entrypoint","publishedBytes","sourceBytes","publishedFiles","sourceFiles","rendererVersion","committedAt","expiresAt","sourceOrigin"}]};expiresAtest le moment où une version précédente cesse d'être conservée et estnullpour la version actuelle, etsourceOriginest{"commit","branch","remote","dirty"}lorsque les sources proviennent de git, sinonnull. L'origine est ce que l'éditeur a déclaré ; Portifact ne peut pas la vérifier.portifact rollback <id> <version-id>rend une version conservée à nouveau actuelle. Elle est publiée comme une nouvelle version avec les mêmes fichiers, redémarre les 30 jours et ne change pas l'accès : les lecteurs supprimés depuis cette version restent supprimés. Demandez à l'utilisateur avant d'effectuer un rollback. Elle renvoie{"artifactId","versionId","versionNumber","url","expiresAt","fromVersionId","fromVersionNumber"}. Si quelqu'un a publié entre-temps, elle échoue avecversion_conflict(code de sortie 6) ; vérifiezversionsà nouveau et demandez à l'utilisateur. Dans les versions dontportifact rollback --helpindique "version ID or number",<version-id>peut également être le numéro de version (3ouv3), etpull --versionen accepte un aussi ; un nombre qui n'est pas conservé échoue avecnot_found(code de sortie 5).portifact pull <id> --out <rép>télécharge les fichiers publiés de la version actuelle dans<rép>/published. Ajoutez--sourcepour les sources privées (dans<rép>/source, propriétaire uniquement),--published --sourcepour les deux, et--version <version-id>pour une version précédente.<rép>ne doit pas encore exister ; pull n'écrit jamais en dehors, refuse les chemins à l'intérieur d'un dossier.git, vérifie le SHA-256 de chaque fichier et supprime le dossier si quelque chose échoue (download_failed, code de sortie 1). Elle renvoie{"artifactId","versionId","versionNumber","out","files":[{"kind","path","size","sha256"}],"totalBytes"}. Lorsqu'un artefact est partagé avec quelqu'un, il peut aussi être téléchargé, mais il aura besoin que ses sources aient été attachées pour être disponibles. Une version dont les sources étaient dans un dépôt git a sonsourceOriginenregistré, et "git" (--git) peut alors être utilisé pour l'historique Git.
Annotations (fils de commentaires)
Uniquement dans les versions dont --help liste annotations. Chaque commande prend --json. L'interface CLI travaille sur la version actuelle ; l'API de l'interface utilisateur (et le serveur MCP) peut travailler sur n'importe quelle version.
portifact annotations list <id>récupère les fils de commentaires de la version actuelle de l'artefact, renvoyant{"artifactId","items":[{"id","parentId","resolved","createdAt","updatedAt","initialAnnotation":{"text","authorId","authorName","position","createdAt"},"annotations":[...],"annotationCount":N}]}, oùparentIdestnullpour les fils racine dontannotationsn'inclut que la réponse la plus récente (utilisez l'API directe pour les autres).portifact annotations list <id> --all-versionsliste les fils sur toutes les versions conservées, avec"versionId"et"versionNumber"sur chaque fil.
Chaque initialAnnotation a éventuellement un "position" avec "anchor" (un sélecteur CSS dans une page rendue, une ligne dans le Markdown brut), "offset" et "length" (octets UTF-16 dans le texte rendu). annotationCount est le nombre total d'annotations dans le fil.
portifact annotations show <id> <thread-id> renvoie {"id","parentId","resolved","createdAt","updatedAt","annotations":[...]}, où annotations inclut toutes les annotations. Récupérez-la lorsque plus d'une annotation est attendue.
Les annotations sont destinées aux réviseurs, donc un agent ne devrait pas en ajouter automatiquement (par exemple, pour marquer un artefact comme terminé) à moins que l'utilisateur ne le demande explicitement.
portifact annotations add <id> <thread-id> --text "<texte du commentaire>" ajoute une annotation (réponse) à un fil. Elle renvoie le fil mis à jour (comme show). Pour démarrer un nouveau fil, omettez <thread-id> : portifact annotations add <id> --text "<texte du commentaire>" [--position.anchor <sélecteur>] [--position.offset N] [--position.length N]. Elle renvoie le nouveau fil. Les positions anchor peuvent être données sans offset/length pour créer une annotation sans plage de sélection.
portifact annotations resolve <id> <thread-id> marque le fil comme résolu ; portifact annotations reopen <id> <thread-id> le rouvre. Les deux renvoient le fil mis à jour.
portifact annotations export exporte toutes les annotations de tous les artefacts du compte sous forme d'un fichier JSON, utile pour les audits ou l'importation dans un autre système. Gardez la sortie là où l'utilisateur peut la voir.
Quotas, logs et licences
Uniquement dans les versions dont --help liste ces commandes. Chaque commande prend --json.
portifact usagerenvoie{"totalPublishedBytes","totalPublishedFiles","totalRetainedVersions","totalVersionCount","publishedBytesLimit","publishedFilesLimit","retainedVersionsLimit","versionCountLimit","totalArtifactCount","artifactCountLimit","openThreads","openThreadsLimit","publishesThisMonth","publishesMonthlyAllowance","publishedBytesUploadedThisMonth","publishedBytesMonthlyAllowance","sourceBytesStored","sourceBytesLimit","sourceFilesStored","sourceFilesLimit","sourceArtifacts","sourceArtifactsLimit","signedInUsers","signedInUsersLimit","openSessions","openSessionsLimit","logEvents","logEventsLimit"}.totalPublishedBytes,totalPublishedFiles,totalRetainedVersionsettotalVersionCountincluent toutes les versions (non supprimées). Les autres sont le nombre actuel, pas un total cumulé.portifact logs [--limit N] [--cursor C] [--artifact <id>] [--version <id>] [--action opened|rolled_back|deleted|expired|archived|restored|renewed|rotated|annotated|access_changed] [--user <id>] [--since <ISO>] [--until <ISO>]renvoie{"cursor","items":[{"id","artifactId","artifactName","action","userId","userName","ip","path","ipGeo","userAgent","createdAt"}]}. Principalement destiné aux audits. Les artefacts supprimés et leurs logs sont supprimés définitivement.portifact licensesimprime les licences des logiciels open source inclus dans le binaire.
Serveur MCP
Le serveur MCP à https://app.portifact.com/mcp expose les outils de cette section. Il a get_artifact_annotations, create_annotation_thread, reply_to_annotation_thread, set_thread_resolved, set_thread_open, comment_on_artifact (démarre un nouveau fil), export_annotations, get_artifacts, get_artifact_info, publish_small_document (jusqu'à 50 Ko de texte, sans téléchargement), publish_document (fichier jusqu'à 5 Mo), rollback_version, get_versions, download_version et get_usage_and_logs (pour les artefacts visités uniquement). Pour une explication complète de chaque outil, consultez le portifact --help étendu ou la documentation du serveur MCP.
Le serveur MCP peut également être utilisé pour automatiser les workflows de révision : par exemple, demander à l'agent de créer un fil sur un artefact avec "J'ai examiné cela et c'est bon" en tant que commentaire initial, puis de le marquer comme résolu. L'agent ne devrait le faire que si l'utilisateur le demande explicitement.
Workflow recommandé pour les agents
- Vérifier la prise en charge : exécutez
portifact --versionetportifact --help. Si la commande n'est pas trouvée, installez ou mettez à jour comme ci-dessus. - Se connecter : exécutez
portifact whoami --jsonpour vérifier ; si ce n'est pas le cas, exécutezportifact loginet montrez le code à l'utilisateur. - Prévisualiser et publier : exécutez
portifact publish <chemin> --dry-run --json. Après confirmation, exécutezportifact publish <chemin> --json. - Rendre public ou restreint : lisez
portifact access <id>et ajustez avecportifact access set. Ajoutez des lecteurs avecportifact access add. - Partager l'URL : imprimez l'URL de l'artefact. Ceci termine la publication ; l'utilisateur peut partager le lien comme il le souhaite.
Rappelez-vous : ne faites jamais de suppositions, ne contournez jamais les vérifications d'intégrité des fichiers, ne manipulez jamais les informations d'identification pour le compte de l'utilisateur et ne prenez jamais de décisions d'accès à sa place.