by kgoedecke
The open-source alternative to Paper.design. A multiplayer design canvas where humans and AI agents design together, live. MCP built in.
# Add to your Claude Code skills
git clone https://github.com/kgoedecke/doopdoop is an open-source ai agents skill for AI coding assistants such as Claude Code, Codex CLI, and ChatGPT, built by kgoedecke. The open-source alternative to Paper.design. A multiplayer design canvas where humans and AI agents design together, live. MCP built in. It has 139 GitHub stars.
doop's catalog security scan is still queued. You can run an instant dependency and prompt-injection check now with the "Scan for vulnerabilities" button above.
Clone the repository with "git clone https://github.com/kgoedecke/doop" and add it to your Claude Code skills directory (see the Installation section above).
doop is primarily written in TypeScript. It is open-source under kgoedecke on GitHub, so you can review or fork the full source.
Yes. SkillsLLM lists many other AI Agents skills you can browse and compare side by side. Open the AI Agents category from the badge at the top of this page, or use the Related Skills and comparison links further down to weigh doop against similar tools.
No comments yet. Be the first to share your thoughts!
Unlocks once the catalog security scan passes (runs nightly).
⚠️ Third-Party Software Notice
This skill is third-party open-source software developed and hosted independently on GitHub. SkillsLLM is an informational directory and does not control or maintain the underlying repository.
Any security checks, ratings, or warnings displayed by SkillsLLM are automated and limited in scope. They do not constitute a security certification or guarantee that the software is safe, error-free, or free from malicious code, vulnerabilities, compromised dependencies, or prompt-injection risks.
Review the source code, permissions, dependencies, and configuration before installing or running any third-party skill. Use is at your own risk. To the maximum extent permitted by applicable law, SkillsLLM is not liable for losses arising from third-party software.
The deep catalog scan for this skill is still queued. Run an instant dependency check now instead.
Doop is the open-source alternative to Paper.design — a multiplayer
design canvas for humans and AI agents. Every design lives on a shareable Canvas
(/c/<id>) holding Frames — artboards that render real HTML in sandboxed iframes. People edit
in the browser; AI agents edit through the built-in MCP server, streaming their designs in
live. Everyone sees everything as it happens: cursors, presence, frame edits, agent status, and an
activity feed.
docker compose up, or npm run dev with zero configuration
(embedded Postgres, no external services required).git clone https://github.com/kgoedecke/doop && cd doop
npm install
npm run dev
/api, /ws, /mcp to it)Everything works with no configuration: data persists to an embedded Postgres (PGlite) in data/pg,
and every optional integration (SMTP, Anthropic, stock photos, object storage, analytics) degrades
gracefully until its variable in .env.example is set.
Or self-host the production build with Docker:
BETTER_AUTH_SECRET=$(openssl rand -hex 32) docker compose up -d # app + Postgres on :4400
Production build without Docker: npm run build && npm start (single server on :4400 serving
everything). Set DATABASE_URL to use a real Postgres — same code path as PGlite.
Prefer not to run anything? doop.design is the hosted version.
One command connects Claude Code (or any MCP client) to your canvas:
claude mcp add --transport http doop http://localhost:4300/mcp
That triggers the standard MCP OAuth flow — a browser window opens, you approve, and from then on
the agent works as you. Ask it to design something on your canvas id and watch it happen live.
Everything in this shot is the real flow: Claude Code announced itself with set_status, created a
frame, and is streaming the pricing section in — presence avatar, "for Kai Moreno" attribution,
the frame chip, the working strip, and the task in the Agents panel.
The first canvas after signup comes with a performance: the resident Doop agent streams a welcome design in while you watch — status in the working strip, a task in the panel, a pulsing border on the frame it's building.
The web app requires an account (better-auth, email/password — open signup). Your account name is your identity everywhere: cursors, presence, the activity feed, and feedback attribution are all server-authoritative from the session, and the WebSocket rejects unauthenticated joins. Canvases are private by default, Figma-style: only the owner and people they invite (Share → invite by email, existing doop accounts) can open one. The Share modal can also turn on link sharing per canvas ("anyone with the link can edit"), which restores drop-a-link collaboration for that canvas. Your home screen lists your own canvases plus ones shared with you (plus unowned legacy ones, claimable there). Agents connected over MCP act under the account that approved them and get exactly that user's access.
With SMTP configured (SMTP_HOST etc. — see .env.example), signups require email
verification and "forgot password" sends real reset links. Without it, signup stays open and every
email is printed to the server log, links included — the flows still work in development.
Env: BETTER_AUTH_SECRET (required in production), TRUSTED_ORIGINS (comma-separated,
defaults to the localhost dev origins).
The /mcp endpoint requires OAuth. Adding the server in Claude Code / Codex triggers
the standard MCP OAuth flow: a browser window opens, you sign in to Doop and approve,
and the client stores a bearer token. Every tool call then carries your identity —
agent tasks show "for ⟨you⟩" in the Tasks panel, and presence tooltips name the owner.
Unauthenticated calls get a 401 with WWW-Authenticate discovery pointers
(/.well-known/oauth-authorization-server + oauth-protected-resource), which is what
kicks off the flow. Dynamic client registration is enabled, so no manual client setup.
In production also set BETTER_AUTH_URL to the public origin — OAuth URLs are built on it.
The repo ships a production Dockerfile (client build + Chromium for frame screenshots).
Any container host works; Railway/Fly are the least friction:
DATABASE_URL. Don't skip this in real deployments —
the PGlite fallback is embedded/single-process and only suits a single instance with a
persistent volume mounted at /app/data.BETTER_AUTH_SECRET (long random string) and BETTER_AUTH_URL (the public origin,
e.g. https://doop.example.com). Extra allowed origins: TRUSTED_ORIGINS (comma-separated).GET /healthz. The server trusts one proxy hop (trust proxy), so
TLS termination at the platform edge works out of the box.Local sanity check of the exact production image:
docker build -t doop .
docker run -p 4400:4400 -e BETTER_AUTH_URL=http://localhost:4400 -e BETTER_AUTH_SECRET=dev-only doop
The MCP endpoint (streamable HTTP, stateless) is at:
http://localhost:4300/mcp
Claude Code:
claude mcp add --transport http doop http://localhost:4300/mcp
Generic MCP config:
{ "mcpServers": { "doop": { "type": "http", "url": "http://localhost:4300/mcp" } } }
Then tell the agent something like:
Work on canvas
<canvas-id>(shown in the top bar). Callget_canvasto see the existing frames. To design, create a frame withcreate_frame, then stream the design into it withappend_frame_htmlin ~300–500 character chunks (start=trueon the first,done=trueon the last) so people watch it build up live. Complete HTML with inline CSS. After finishing, callget_frame_screenshotto see it, fix what looks wrong, and re-check. Pick anagent_nameand reuse it on every call.
Screenshots render in your system Chrome/Chromium via puppeteer-core (set CHROME_PATH if it isn't
auto-detected). Humans can hit the same renderer at GET /api/frames/:id/screenshot.png?scale=2.
Agent HTML lands in the store immediately, but viewers see it through a typewriter reveal: the server
broadcasts the accumulated HTML at a steady rate (~500 chars/s, accelerating to clear backlogs in ~8s),
so even an agent that sends few large chunks — or a one-shot set_frame_html / create_frame with
full HTML — plays back as a smooth live stream. Mid-reveal HTML is healed before broadcast: a trailing
half-written tag is dropped, an unclosed <script> is cut (never run half-written JS), and an unclosed
<style> is closed so content paints instead of blanking. Human edits from the inspector bypass the
reveal (and a human html edit cancels any open reveal — the human takes over).
While a stream/reveal is open the frame gets a pulsing dashed border and a "✦ is designing…"
chip; "finished designing" logs when the reveal completes. A stale stream auto-closes after 30s.
There is also a REST equivalent: POST /api/frames/:id/append with { html_chunk, start?, done?, actor? }.
Steering happens at three layers (the same architecture paper.design uses, plus result nudges):
instructions at MCP initialize