agentsclimarketplace

Masheev widget

Skill masheev/skills/skills/masheev-widget

Official Agent Skills for integrating Masheev into your applications

Install
npx -y skills add masheev/skills --skill masheev-widget

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use when installing, configuring, or troubleshooting the Masheev chat widget in any web application. Covers adding the chat widget via script tag, npm package (@masheev/embed-sdk), React, Next.js, Vue, and vanilla JavaScript. Handles SSR safety ("window is not defined"), SPA route changes, user identity with HMAC verification, widget positioning, theming (light/dark/auto), CSP headers, GDPR consent gating, embedded mode, prompt-input mode, and common errors. Use this skill whenever someone asks to "add Masheev", "install the chat widget", "embed Masheev", or mentions @masheev/embed-sdk.

The file declares its own license as Apache-2.0. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

10.2 KB, as published. Nobody here has run it

Masheev Widget Integration

Add the Masheev chat widget to any web application. The widget runs in an iframe, communicates via postMessage, and requires only an inboxId to start.

Quick Start

Script Tag (simplest)

<script>
  (function(m,a,s,h,e,v){
    m.MasheevConfig=e;m[e]={inboxId:v};
    s=a.createElement('script');s.async=1;
    s.src='https://cdn.masheev.com/widget.js';
    a.head.appendChild(s);
  })(window,document,0,0,'masheev','YOUR_INBOX_ID');
</script>

npm Package

npm install @masheev/embed-sdk
import { init } from "@masheev/embed-sdk/js";

init({
  inboxId: "YOUR_INBOX_ID",
  mode: "chat-widget",         // "chat-widget" | "prompt-input" | "embedded"
  position: "right",           // "left" | "right"
  colorScheme: "auto",         // "light" | "dark" | "auto"
});

React

import { useMasheev } from "@masheev/embed-sdk/react";

function App() {
  const { open, close, isReady } = useMasheev({
    inboxId: "YOUR_INBOX_ID",
  });

  return <button onClick={open} disabled={!isReady}>Chat with us</button>;
}

Next.js (SSR-safe)

"use client";

import dynamic from "next/dynamic";
import { useMasheev } from "@masheev/embed-sdk/react";

// Option A: Use the hook directly in a client component
function ChatWidget() {
  useMasheev({ inboxId: "YOUR_INBOX_ID" });
  return null;
}

// Option B: Dynamic import if widget has side effects at import time
const ChatWidget = dynamic(
  () => import("../components/chat-widget"),
  { ssr: false }
);

// In your layout:
export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <ChatWidget />
      </body>
    </html>
  );
}

Configuration Reference

OptionTypeDefaultDescription
inboxIdstringrequiredYour inbox ID from the Masheev dashboard
mode"chat-widget" | "prompt-input" | "embedded""chat-widget"Widget display mode
position"left" | "right""right"Launcher position (chat-widget mode only)
colorScheme"light" | "dark" | "auto""light"Theme — "auto" follows the parent page (.dark/.light class or data-theme) then OS preference
sessionMode"persistent" | "ephemeral" | "workflow""persistent"Conversation persistence across page loads
userUserContext-Identify the logged-in user
placeholderstring-Custom input placeholder text
agentNamestring-Override AI agent display name
agentTitlestring-Agent role/title shown in header
questionsstring[]-Suggested conversation starters
privacyUrlstring-Link to your privacy policy
requireConsentbooleanfalseRequire explicit consent before starting chat
hideHeaderbooleanfalseHide chat header (embedded mode only)
toolsClientToolDefinition[]-Client-side tools (see masheev-client-tools skill)
workflowWorkflowConfig-Conversational workflow (see masheev-workflows skill)
debugbooleanfalseLog all postMessage traffic to console

Color Scheme (light / dark)

Two ways to theme the widget. Pick based on whether your app has its own theme state.

Recommended: drive it from your app (deterministic)

If your app already knows its resolved theme, push that value to the widget — no DOM guessing, no coupling to class names. Seed colorScheme at init (avoids a theme flash on first paint) and re-push on every change with updateColorScheme:

// React — one source of truth, synced on initial load AND every toggle
const isDark = useIsDark(); // your app's resolved theme (next-themes, custom, etc.)
const colorScheme = isDark ? "dark" : "light";

const { updateColorScheme } = useMasheev({
  inboxId: "...",
  colorScheme, // read once — seeds the first render
});

useEffect(() => {
  updateColorScheme(colorScheme); // keeps the live widget in sync
}, [colorScheme, updateColorScheme]);
// Vanilla JS
import { init, updateColorScheme } from "@masheev/embed-sdk/js";
init({ inboxId: "...", colorScheme: isDark ? "dark" : "light" });

document.querySelector("#dark-toggle").addEventListener("click", () => {
  updateColorScheme(nowDark ? "dark" : "light");
});

Zero-config: colorScheme: "auto"

For pages where you can't add sync code, "auto" makes the widget follow the parent page automatically. It resolves the scheme in priority order:

  1. An explicit .dark / .light class on <html>
  2. A data-theme="dark" | "light" attribute on <html>
  3. The OS prefers-color-scheme media query

It observes the <html> class + data-theme attributes and the media query, so common toggles (Tailwind .dark, next-themes, etc.) work without extra wiring.

const { updateColorScheme } = useMasheev({ inboxId: "...", colorScheme: "auto" });
ValueBehavior
"light"Force light theme (default)
"dark"Force dark theme
"auto"Follow parent page: explicit .dark/.light class or data-theme, else OS prefers-color-scheme

Prefer the explicit approach when you control the app. "auto" has to infer the theme from the DOM, which couples the widget to your class naming and can miss non-standard toggles. If your toggle sets an explicit .light class while the OS is in dark mode, you need @masheev/embed-sdk ≥ the version that resolves .light/data-theme (older builds fell back to the OS query and stayed dark).

The widget also sets CSS custom properties (--masheev-primary, --masheev-bg, --masheev-text, etc.) on the iframe's document root for advanced styling.

User Identity (HMAC Verification)

Pass authenticated user data to link conversations to your users. Use userHash to prevent spoofing:

// Server-side: generate HMAC hash
import crypto from "node:crypto";

const userHash = crypto
  .createHmac("sha256", process.env.MASHEEV_INBOX_SECRET)
  .update(userId)
  .digest("hex");

// Client-side: pass to widget
init({
  inboxId: "YOUR_INBOX_ID",
  user: {
    userId: "user_123",
    userHash: userHash,  // computed server-side
    name: "Jane Doe",
    email: "[email protected]",
    company: "Acme Inc",
    customAttributes: {
      plan: "pro",
      signupDate: "2026-01-15",
    },
  },
});

SDK Methods

MethodSignatureDescription
open()() => voidOpen the widget
close()() => voidClose the widget
toggle()() => voidToggle open/closed
hide()() => voidHide from DOM (display: none)
show()() => voidShow in DOM
sendMessage(text: string) => voidSend a message programmatically
setInputValue(text: string, opts?: { append?: boolean }) => voidPre-fill the input field
updateContext(ctx: Partial<UserContext>) => voidUpdate user identity mid-session
updateContact(fields: { name?, email?, phone?, company? }) => voidUpdate contact (persists server-side)
setQuestions(questions: string[]) => voidUpdate suggested questions
setListening(listening: boolean) => voidEnable/disable speech input
updateTools(tools: ClientToolDefinition[]) => voidAdd/replace client tools
updateWorkflow(updates: { context?, name? }) => voidUpdate workflow context or name
resetConversation() => voidStart a new conversation
destroy()() => voidRemove widget and clean up
on(event, cb)Returns unsubscribe () => voidSubscribe to widget events
off(event, cb)voidUnsubscribe from event

Events

EventPayloadWhen
ready-Widget iframe loaded and initialized
open-Widget opened
close-Widget closed
message{ role: "user" | "ai", content: string }New message sent or received
error{ message: string, code?: string }Error occurred
resolved{ conversationId, reason? }Conversation marked resolved
newConversation{ previousConversationId? }Fresh conversation started
unreadCount{ count: number }Unread message count changed
action:invoke{ invocationId, toolName, args }AI requests client tool execution
workflow:stepComplete{ workflowId, stepId, data? }Workflow step completed
workflow:complete{ workflowId, outcome, data? }Entire workflow completed

Widget Modes

chat-widget (default)

Floating chat bubble in bottom corner. Opens to full chat panel. Best for most sites.

prompt-input

Persistent input bar (no floating bubble). Good for AI-first interfaces.

embedded

Mount inside a specific DOM element. No floating UI. Full control over layout.

// React embedded mode
function SupportPage() {
  const { containerRef, isReady } = useMasheev({
    inboxId: "YOUR_INBOX_ID",
    mode: "embedded",
    hideHeader: true,
  });

  return <div ref={containerRef} style={{ height: "500px", width: "100%" }} />;
}
// Vanilla JS embedded mode
init({
  inboxId: "YOUR_INBOX_ID",
  mode: "embedded",
  containerId: "masheev-container", // DOM element ID
  hideHeader: true,
});

Troubleshooting

See references/troubleshooting.md for:

  • "window is not defined" in SSR
  • Widget not appearing after SPA navigation
  • CSP header configuration
  • z-index conflicts with other UI elements
  • Cross-origin cookie issues
  • GDPR-compliant deferred loading

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.