morph-embed
v0.3.0
Published
Embed a prompt bar in your product so users can generate the features you haven't built — real-data widgets, layout reshapes, and confirm-gated actions. Declarative-DSL security model; your data never leaves the page.
Maintainers
Readme
morph-embed
Let your users build the features you haven't shipped yet.
Morph Embed adds a prompt bar to your web product. Your users type what they're missing — "add a box showing how much we lost in the last 15 days" — and get a real, working widget computed from your data, rendered safely, saved for them, and reapplied on every visit. No ticket, no sprint, no code deployed.
User types a sentence → a real feature appears → it persistsThree capabilities, in increasing order of integration effort:
| Capability | What users can do | What you provide | |---|---|---| | Reshape | Restyle, rearrange, declutter your UI by prompt | Nothing — works out of the box | | Data widgets | Generate stat boxes and charts over live data ("lost deals this month", "signups per week") | Registered data sources (a fetch function + a field schema) | | Actions | Generated buttons that do things ("add a follow-up task") — always user-clicked, always confirmable | Registered actions (a callback + an argument schema) |
Why it's safe to put in your product
Most teams can't let an LLM touch their UI because model output might execute. Morph is built so it can't:
- The model never returns code. It answers only in a fixed, declarative
JSON DSL (
hide,injectCSS,move,addElement,renderData, …). Every op is validated and sanitized in the browser: HTML is whitelist-sanitized, CSS is neutralized, and there is no execution op to reach for. This is the architecture, not a filter. - Your data never leaves the page. The model only ever sees your source
names and field schemas. When it wants numbers, it emits a query
description; trusted SDK code validates that query against your schema,
runs your fetch function in the browser (under your existing auth),
aggregates client-side, and renders the numbers itself via
createElementNS. Morph's servers never see a record — and the model never emits a number. - Actions are allowlisted by construction. Unknown action names and off-schema arguments are dropped before anything renders. A registered action runs only on a real user click, behind a confirm dialog if you say so. Nothing is scheduled; nothing fires on its own.
- Keys are publishable. Like a Stripe
pk_key, your key appears in page source by design. It's bound to your origins server-side and rate-limited per vendor. It gates cost, not data — there is no data behind it. - Generated features live client-side — in
localStorage, or in your own backend via a three-method storage adapter. Morph stores nothing per-user.
Install
npm:
npm install morph-embedimport { init } from 'morph-embed';Or one script tag (IIFE build, exposes window.Morph):
<script src="https://unpkg.com/morph-embed/dist/morph-embed.js"></script>Integrate
This is the complete integration surface — a CRM registering one data source and one action:
Morph.init({
key: 'pk_...', // your publishable key
sources: {
deals: {
fetch: async (query) => api.deals(), // your API, your auth, your data
schema: { // field name -> string|number|date|boolean
name: 'string',
stage: 'string',
amount: 'number',
closedAt: 'date',
},
description: 'All CRM deals (stage: won|lost|open)',
},
},
actions: {
createTask: {
run: async (args) => api.tasks.create(args), // your callback
argsSchema: { note: 'string' }, // string|number args only
description: 'Create a follow-up task',
confirm: true, // user must approve every run
},
},
// Optional:
storage: { get, set, remove }, // persist users' features in YOUR backend
// (omit for localStorage)
trigger: 'alt+m', // hotkey, or 'none' + call Morph.open()
// from your own button
backend: 'https://...', // override the Morph API endpoint
});Your users click the ✦ launcher (bottom corner, theme it or hide it) or press Alt+M and describe what they want. That's the whole thing.
What your users get (v0.2, research-grounded UX)
- A visible entry point — a small launcher button with an active-edit
badge. It never auto-opens and never talks first; one subtle pulse on first
visit only (none under
prefers-reduced-motion). - Forgiveness by default — every change applies instantly and shows an Undo toast (the Gmail pattern). No confirmation dialogs to click through.
- Full control & history — "Your edits on this page" lists every saved edit in the user's own words, with per-edit on/off toggle, per-edit delete, and a reset. Persistence is disclosed right there ("re-applies every visit").
- A narrated wait — "Reading this page… → Designing your change…" instead of a blank spinner while the model works.
- A hotkey that actually works everywhere — physical-key matching, so macOS Option+M (which types "µ") fires correctly, German AltGr+M (also µ) is never hijacked, and nothing triggers while typing in your app's inputs.
Configure or hide the launcher:
Morph.init({
key: 'pk_…',
launcher: { position: 'bottom-left', accent: '#5b6cff' }, // or launcher: false
trigger: 'alt+m', // or 'none'
});What the model can ask of your sources
The query language is deliberately tiny — enough for "show me X", small enough to audit:
filter— equality or IN over your fieldsdateField+since/until— durations like'15d','24h', or ISO datesgroupBy— one row per groupaggregate—sum|count|avg|min|maxlimit
Every referenced field must exist in your declared schema — a hallucinated field is a hard error, never a silent zero. If a question needs more than this language expresses, expose it as a purpose-built source instead.
Widgets your users can generate
stat (big number + caption), bar, and line charts — all rendered by
trusted code as SVG from the query result. Layout reshapes and added elements
use the same sanitized DSL as the rest of Morph.
Try it
The repository ships a fake CRM with Morph embedded —
sdk/demo-crm/
— seeded with deals data. Its app.js is the reference integration; the golden
path ("add a box showing how much we lost in the last 15 days" → real widget →
survives reload) is documented in its README.
Status & keys
Morph Embed is in early access. Get a publishable key self-serve at usemorph.xyz/dashboard — create an account, add your origins, copy the key (rate limits included). Questions or problems: GitHub issues.
Morph is also a browser extension that reshapes any website the same way — same engine, same security model.
License
MIT © Mandar Wagh — see LICENSE. (The morph-embed package is
MIT-licensed; the Morph backend service and the wider repository are licensed
separately.)
