
open-artifacts
Open-source, self-hosted Claude Code Artifacts on Cloudflare — publish, password-protect, and auto-update shareable HTML/Markdown pages from any coding agent.
Install with your AI
Paste into Claude Code, Cursor, or any agent — it reads the repo and wires the tool into your project.
Install and set up open-artifacts (git-clone project) into my current project. Found on https://claudeers.com/open-artifacts Repo: https://github.com/coda0HQ/open-artifacts Homepage/docs: — Detected install method: git-clone → git clone https://github.com/coda0HQ/open-artifacts Category: skills. Platforms: cli, api, web, mobile. Read the repo's README for exact setup and env vars, then install it and wire it into my project. Claudeers Health Verdict: active; community-verified: false. Confirm the source before running anything.
git clone https://github.com/coda0HQ/open-artifacts
// compatibility
| Platforms | cli, api, web, mobile |
|---|---|
| Operating systems | — |
| AI compatibility | claude |
| License | MIT |
| Pricing | open-source |
| Language | TypeScript |
Open Artifacts
English | 简体中文
Open-source, self-hosted Claude Code Artifacts: let any coding agent publish self-contained HTML/Markdown pages to shareable URLs, protect them with passwords (zero-knowledge, client-side encryption), and keep them updated as the project they describe evolves. Runs entirely on Cloudflare (Workers + D1 + R2), fits in the free tier, no accounts anywhere.
Hosted or self-hosted. coda0.com is the official managed instance, run by the project — point your agent at it for zero-setup publishing. Or self-host the engine on your own Cloudflare account (see below); it's the same MIT-licensed code either way.
flowchart LR
you["you"] -- "share the app's interaction flows as a page" --> agent["your agent"]
agent -- "POST /api/artifacts" --> worker["your Worker"]
worker -- "https://<instance>/a/3fKx9mQp2Wvb" --> url["shareable URL"]
later["later: the flows change"] --> status["agent runs<br/>artifact.mjs status"]
status -- "stale" --> regen["regenerates page"]
regen -- "PUT (same id)" --> worker2["your Worker"]
worker2 -- "same URL, v2" --> url
Give your agent the skill
npx skills add coda0HQ/open-artifacts -s using-open-artifacts # project scope (.claude/skills/)
npx skills add coda0HQ/open-artifacts -s using-open-artifacts -g # or user scope
Works with Claude Code and any agent supporting the Agent Skills standard. Then point it at an instance — the hosted one, or your own:
export OPEN_ARTIFACTS_URL=https://coda0.com # hosted; or your self-hosted URL
No instance yet? references/deployment.md (bundled with the skill) lists
three ways to get one: use the public shared instance with zero setup,
self-host on your own Cloudflare account, or share a team instance, with a
trust-model table for picking based on content sensitivity.
The bundled SKILL.md and references/design.md teach the agent the design
philosophy: an expert-designer workflow (understand, explore, plan, build,
verify), an explicit anti-AI-slop list, modern CSS power moves, and a
5-direction library (Editorial / Modern minimal / Human / Tech utility /
Brutalist) with ready-to-paste OKLch palettes and font stacks for when no
brand is specified. references/tokens.css is the shared token contract the
Recipe builder injects into every HTML artifact before its theme fragment.
Adapted from
open-design,
Claude's artifact-design skill,
impeccable by Paul Bakaus
(Apache-2.0, interaction-state and anti-pattern rules),
Emil Kowalski (easing, frequency, and duration rules), and
Apple WWDC 2018 Designing Fluid Interfaces (canvas gesture physics).
Retargeted to this project's strict no-external-requests CSP.
Ask your agent to "publish this as an artifact" — it runs the bundled CLI:
node .claude/skills/using-open-artifacts/scripts/artifact.mjs validate \
artifacts/app-interactions.recipe.json
node .claude/skills/using-open-artifacts/scripts/artifact.mjs create \
artifacts/app-interactions.recipe.json
Every artifact is generated from a versioned JSON Recipe plus ordered
fragments. The Recipe owns title, favicon, format, scope, watch globs, channel,
level, Canvas mode, locality, and encryption policy. create and update
compose and validate in memory, then send exactly one final publish request.
Deploy your own instance
git clone https://github.com/coda0HQ/open-artifacts && cd open-artifacts
pnpm install
npx wrangler d1 create open-artifacts # put database_id into wrangler.jsonc
npx wrangler r2 bucket create open-artifacts-content
pnpm run deploy
The schema applies itself on first request — no migration step. To restrict who can create artifacts on your instance (updates are always restricted by per-artifact write tokens):
npx wrangler secret put CREATE_TOKEN # then set OPEN_ARTIFACTS_TOKEN client-side
Local development: pnpm dev (state persists in .wrangler/state).
How it works
| Concern | Design |
|---|---|
| Identity | No accounts. Artifact ids are 12-char crypto-random (unguessable, unlisted). Creation returns a one-time writeToken; only its SHA-256 is stored. |
| Deterministic sources | A strict Recipe plus ordered fragments generates every Artifact. The builder injects tokens and, for Canvas, the vendored runtime and controls. Manifest v2 records Recipe/input/output hashes; direct HTML/Markdown CLI publishing is rejected. |
| Channels | artifact.channel binds an artifact to a stable URL. The CLI keeps a per-channel token (ch_) in .artifacts/credentials.json; presenting it on a later create updates the bound artifact (new version, same link) instead of minting a new one. Only the channel hash is stored server-side. |
| Local mode | artifact.local: true places private sources under gitignored .artifacts/recipes.local/ and .artifacts/fragments.local/, with state in manifest.local.json. Shared Recipes/fragments may be committed. Encrypted Recipes are always private. |
| Storage | D1 for metadata/tokens/version index, R2 for content bodies (content/<id>/<version>). Both strongly consistent — updates are visible immediately. |
| Versions | Every publish is an immutable version with an optional label and its own title, description, favicon, format, and encryption state, so history reflects what each version actually looked like. ?v=N views history; PUT accepts baseVersion and returns 409 on conflicts (override with force). |
| Serving | The Worker wraps stored content in a skeleton (CSS reset, emoji favicon, viewport, light/dark theme with a data-theme toggle) and serves it with Content-Security-Policy: sandbox allow-scripts ...; default-src 'none' — artifact scripts run in an opaque origin and cannot make any external request. |
| Link previews | Every page emits OpenGraph + Twitter tags (title, description, image). GET /og/:id returns a 1200x630 PNG card rasterized on the edge with @resvg/resvg-wasm from an embedded Inter subset — a real raster crawlers render (they ignore SVG), self-contained with no external requests. |
| Passwords | The CLI encrypts locally: PBKDF2-HMAC-SHA256 (600k iterations) + AES-256-GCM. The server stores only {salt, iv, ciphertext}. The viewer serves an unlock shell that decrypts in the browser and renders the result inside a sandboxed iframe. The password never leaves the client. |
| Auto-update | The Recipe records scope, watch, and autoUpdate; Manifest v2 keeps the publication snapshot. artifact.mjs status reports stale watched artifacts, while the optional Stop-hook path only surfaces opted-in entries. Agents update Recipe fragments or ack reviewed drift. |
| Markdown | Rendered client-side (vendored marked, inlined — no CDN), so encrypted Markdown works without the server ever seeing plaintext. |
API
POST /api/artifacts { content, favicon, title?, description?, format?, label?, encrypted?, channel? }
→ 201 { id, url, writeToken, version, channel? }
PUT /api/artifacts/:id same fields + baseVersion?/force? (Bearer writeToken or channel token)
GET /api/artifacts/:id metadata + version history
GET /api/artifacts/:id/raw stored content (?v=N)
DELETE /api/artifacts/:id (Bearer writeToken)
GET /a/:id rendered page (?v=N)
encrypted is { salt, iv, iterations } (all base64/int) with base64
ciphertext as content. channel is a channel token (ch_...) that targets
the artifact already bound to that channel, or binds a new one on first use.
Max content size 4 MiB.
Security model
- Serving untrusted HTML on your own origin is the classic stored-XSS trap;
every user-content response here carries the CSP
sandboxdirective (opaque origin — no cookies, no storage, no same-origin API calls) plusdefault-src 'none',connect-src 'none',X-Content-Type-Options: nosniffandReferrer-Policy: no-referrer. *.workers.devis on the Public Suffix List, isolating your instance from other sites.- Anyone with the URL of an unprotected artifact can read it (like an unlisted
gist). Use
--passwordfor anything sensitive; title/favicon metadata stays plaintext. - An open instance (no
CREATE_TOKEN) lets anyone with the URL create pages. Set the secret for anything public-facing.
Development
pnpm test # Worker integration tests (vitest + workerd)
pnpm test:cli # skill CLI tests
pnpm typecheck
pnpm check # biome lint + format
BDD scenarios live in tests/features/; the architecture decision record in
docs/architecture.md.
MIT licensed.
// faq
What is open-artifacts?
Open-source, self-hosted Claude Code Artifacts on Cloudflare — publish, password-protect, and auto-update shareable HTML/Markdown pages from any coding agent.. It is open-source on GitHub.
Is open-artifacts free to use?
open-artifacts is open-source under the MIT license, so it is free to use.
What category does open-artifacts belong to?
open-artifacts is listed under skills in the Claudeers registry of Claude-compatible tools.
// embed badge
[](https://claudeers.com/open-artifacts)
// retro hit counter
[](https://claudeers.com/open-artifacts)
// reviews
// guestbook
// related in Claude Skills
An agentic skills framework & software development methodology that works.
💫 Toolkit to help you get started with Spec-Driven Development
AI coding assistant skill (Claude Code, Codex, OpenCode, Cursor, Gemini CLI, and more). Turn any folder of code, SQL schemas, R scripts, shell scripts, docs,…