# Artifacts > One private site for every HTML artifact your AI coding tools produce. > Claude Code, Codex, Gemini CLI and Cursor can all publish to it through one > CLI. Private by default; share a link when you choose, with an optional > expiry and passphrase. Every artifact is encrypted end to end: the site > stores ciphertext it cannot read. Free and open source (MIT). Site: https://artifacts.pallason.com Sign up: https://artifacts.pallason.com/signup Sign in: https://artifacts.pallason.com/signin npm package: https://www.npmjs.com/package/personal-artifact (v2.1.0) Source: https://github.com/nafey7/personal-artifacts ## Install and connect npm install -g personal-artifact personal-artifact The second command opens the browser to sign in, approves this machine, saves a token in ~/.artifact-publish.json and installs a "personal-artifact" skill into every coding tool it finds on the machine. ## Publish artifact-publish ./page.html "Title" artifact-publish ./page.html "Title" --project "Client Work" artifact-publish ./page.html "Title" --public --expires 7d Each call prints the artifact's URL. A public artifact's URL ends in #k=; pass on the whole link, since the part after # is the key and the browser never sends it to the site. ## Encryption, exactly Encrypted: every page (AES-256-GCM under a key made on the publisher's machine, stored wrapped under an account key the site never holds). Not encrypted: the owner's email, the title, the project, the size, dates, visibility, and which addresses opened which link. Artifacts from before encryption stay in the clear until their owner encrypts them. Limit: the decrypting script is served by the site, pinned by an integrity hash and generated from the CLI package on npm, where it can be read. The CLI itself has no such limit. Recovery: a twelve-word phrase shown once. Lose it and the password and the encrypted artifacts are gone; the site cannot help. ## HTTP API (Authorization: Bearer , tokens are issued at /settings) - POST /api/upload body { title, enc: 1, html, iv, artKeyWrapped, project?, createProject?, visibility?, slug?, expiresIn?, passphrase?, artKeyByPassphrase? } html is base64url ciphertext; a plain body is refused (the CLI encrypts for you) - GET /api/artifacts list, newest first; ?project=, ?q=, ?limit=, ?trashed=1; rows carry encrypted - GET /api/artifacts/[id-or-slug] one artifact with its html (ciphertext plus enc, iv, artKeyWrapped when encrypted); ?format=html for the html alone (409 on an encrypted one) - PATCH /api/artifacts/[id] edit title, html, project, visibility, expiry, passphrase; encrypted html needs enc, iv, artKeyWrapped - GET /api/auth/keys the account's wrapped keys, for unlocking with the password or recovery phrase - GET|POST /api/projects list or create projects - GET /api/me the token's owner Artifacts are served whole at /a/, inside a sandboxed iframe: write a complete HTML document, keep it under 2MB, and keep state in memory (browser storage throws inside the sandbox).