Extensibility & Partnerships — Design Document
ARCHIVE — This document is historical reference only. It may contain outdated information. See docs/status.md for current project state.
Created: February 13, 2026 Status: Planned Phase: 3l (Extensibility & Partnerships)
Overview
Enable Morphee to be extended via third-party JavaScript libraries, embedded in external websites via browser extensions, and integrated by website owners via SDK. Create a partnership framework for commercial integrations.
Key capabilities:
- JS Library System — Load third-party libraries into Spaces with ACL-controlled permissions
- Browser Extension — Embed Morphee.app capabilities (chat, memory, tasks) into any website
- Embedding SDK — JavaScript SDK for website owners to integrate Morphee natively
- Partnership Framework — Commercial integration platform for B2B partnerships
Motivation
Problem: Morphee is a standalone app. Users can't:
- Extend functionality with custom libraries (e.g., specialized calculators, domain-specific tools)
- Use Morphee features while browsing other websites
- Website owners can't integrate Morphee's AI capabilities into their platforms
- No structured way for B2B partners to build on top of Morphee
Solution: Make Morphee extensible and embeddable:
- JS Library System — Developers package features as ACL-aware libraries loaded into Spaces
- Browser Extension — Floating Morphee widget available on any webpage (context-aware)
- Embedding SDK —
@morphee/sdknpm package for website integration - Partnership API — Authenticated API for B2B integrations with white-labeling
Use Cases
| Persona | Scenario |
|---|---|
| Teacher (Emma) | Loads "Math Tutor" library into Homework Space → students get interactive geometry tools in chat |
| Developer | Creates custom data visualization library → publishes to Morphee Extension Store → users install with permission grants |
| Parent (Sophie) | Uses browser extension while shopping online → "Add this to family grocery list" from any website |
| SaaS Founder | Integrates @morphee/sdk into customer portal → users get AI assistant with their product data context |
| Enterprise Partner | White-labels Morphee API → offers "AI Workspace powered by Morphee" to their customers |
Architecture
1. JS Library System (Space Plugins)
Goal: Third-party JavaScript libraries loaded into Spaces with sandboxed execution and ACL permissions.
Library Structure
// morphee-math-tutor/index.ts
import { MorpheePlugin, PluginContext } from '@morphee/plugin-api';
export default class MathTutorPlugin implements MorpheePlugin {
name = 'math-tutor';
version = '1.0.0';
permissions = ['frontend.render', 'memory.search']; // Requested permissions
async initialize(ctx: PluginContext) {
// Register custom tools with AI
ctx.registerTool({
name: 'plot_function',
description: 'Plot a mathematical function',
parameters: {
type: 'object',
properties: {
expression: { type: 'string' },
range: { type: 'object' },
},
},
handler: async (params) => {
// Render graph using D3.js
return ctx.renderComponent({
type: 'custom_graph',
props: { expression: params.expression },
});
},
});
}
}
Backend: ExtensionsIntegration
Location: backend/interfaces/integrations/extensions.py
class ExtensionsIntegration(BaseInterface):
async def install_extension(self, ctx: ExecutionContext, extension_id: str, space_id: UUID) -> ActionResult
async def uninstall_extension(self, ctx: ExecutionContext, extension_id: str, space_id: UUID) -> ActionResult
async def list_installed(self, ctx: ExecutionContext, space_id: UUID) -> ActionResult
async def grant_permission(self, ctx: ExecutionContext, extension_id: str, permission: str) -> ActionResult
async def revoke_permission(self, ctx: ExecutionContext, extension_id: str, permission: str) -> ActionResult
async def execute_extension_action(self, ctx: ExecutionContext, extension_id: str, action: str, params: dict) -> ActionResult
Database: Extensions Tables
CREATE TABLE extensions (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name VARCHAR(100) NOT NULL UNIQUE,
display_name VARCHAR(200) NOT NULL,
description TEXT,
version VARCHAR(50) NOT NULL,
author VARCHAR(200),
icon_url TEXT,
manifest_url TEXT NOT NULL, -- HTTPS URL to extension manifest (JSON)
verified BOOLEAN DEFAULT false, -- Morphee-verified extensions
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE space_extensions (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
space_id UUID NOT NULL REFERENCES spaces(id) ON DELETE CASCADE,
extension_id UUID NOT NULL REFERENCES extensions(id) ON DELETE CASCADE,
installed_by UUID NOT NULL REFERENCES users(id),
installed_at TIMESTAMPTZ DEFAULT NOW(),
enabled BOOLEAN DEFAULT true,
config JSONB DEFAULT '{}', -- Extension-specific config
UNIQUE(space_id, extension_id)
);
CREATE TABLE extension_permissions (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
space_extension_id UUID NOT NULL REFERENCES space_extensions(id) ON DELETE CASCADE,
permission VARCHAR(100) NOT NULL, -- "frontend.render", "memory.search", "tasks.create"
granted_by UUID NOT NULL REFERENCES users(id),
granted_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(space_extension_id, permission)
);
Frontend: Extension Loader
Location: frontend/src/lib/extensions/loader.ts
export class ExtensionLoader {
private loaded: Map<string, MorpheePlugin> = new Map();
async loadExtension(extensionId: string, spaceId: string): Promise<void> {
// Fetch extension manifest
const manifest = await api.get(`/api/extensions/${extensionId}/manifest`);
// Load JS bundle (sandboxed iframe or Web Worker)
const plugin = await this.loadBundle(manifest.bundle_url);
// Validate permissions
const grantedPerms = await api.get(`/api/spaces/${spaceId}/extensions/${extensionId}/permissions`);
const ctx = new PluginContext(extensionId, spaceId, grantedPerms);
// Initialize plugin
await plugin.initialize(ctx);
this.loaded.set(extensionId, plugin);
}
private async loadBundle(url: string): Promise<MorpheePlugin> {
// Option 1: Sandboxed iframe with postMessage API
// Option 2: Web Worker with structured clone
// Option 3: Dynamic import with Proxy wrapper for permission checks
// For security: CORS, Content-Security-Policy, Subresource Integrity
const response = await fetch(url, {
integrity: manifest.integrity, // SRI hash
});
const code = await response.text();
// Execute in isolated context
const worker = new Worker(URL.createObjectURL(new Blob([code], { type: 'application/javascript' })));
return new WorkerPluginWrapper(worker);
}
}
Permission Model
Extension permissions map to Integration actions:
| Permission | Integration | Action | Description |
|---|---|---|---|
frontend.render | FrontendIntegration | show_* | Render custom components |
memory.search | MemoryIntegration | search | Search group memory |
memory.store | MemoryIntegration | store | Store memories |
tasks.create | TasksIntegration | create_task | Create tasks |
tasks.list | TasksIntegration | list_tasks | List tasks |
spaces.list | SpacesIntegration | list_spaces | List spaces |
llm.chat | LLMIntegration | chat | Call LLM (token limit enforced) |
network.fetch | (new) NetworkIntegration | fetch | HTTP requests (whitelist enforced) |
ACL enforcement:
async def execute_extension_action(self, ctx: ExecutionContext, extension_id: str, action: str, params: dict):
# Check if extension has permission
perms = await self.get_extension_permissions(ctx.space_id, extension_id)
required = f"{action.split('__')[0]}.{action.split('__')[1]}" # e.g., "tasks.create"
if required not in perms:
return ActionResult(success=False, error=f"Extension missing permission: {required}")
# Check user's role allows this action in this space
user_role = await self.get_user_role(ctx.user_id, ctx.space_id)
if not self.can_execute_action(user_role, action):
return ActionResult(success=False, error="User lacks permission for this action")
# Execute action via InterfaceManager
return await self.interface_manager.execute_action(action, params, ctx)
2. Browser Extension
Goal: Floating Morphee widget on any webpage, context-aware (can read page content with permission).
Architecture
┌─────────────────────────────────────────┐
│ Any Webpage (e.g., Amazon) │
│ ┌───────────── ──────────────────────┐ │
│ │ Content Script (injected) │ │
│ │ - Detect page context │ │
│ │ - Show floating widget │ │
│ │ - Extract selected text │ │
│ └───────────┬───────────────────────┘ │
└──────────────┼──────────────────────────┘
│ postMessage
▼
┌──────────────────────────────────────────┐
│ Background Service Worker │
│ - Authenticate with Morphee API │
│ - Manage WebSocket connection │
│ - Handle cross-origin requests │
└──────────────┬───────────────────────────┘
│ chrome.runtime.sendMessage
▼
┌──────────────────────────────────────────┐
│ Popup / Sidebar (React) │
│ - Chat interface │
│ - Task quick-add │
│ - Memory search │
└──────────────────────────────────────────┘
Manifest V3 Structure
{
"manifest_version": 3,
"name": "Morphee Assistant",
"version": "1.0.0",
"permissions": [
"storage",
"activeTab",
"contextMenus"
],
"host_permissions": [
"https://api.morphee.app/*"
],
"background": {
"service_worker": "background.js"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"],
"css": ["widget.css"]
}
],
"action": {
"default_popup": "popup.html",
"default_icon": "icon.png"
}
}
Content Script (Injected into Pages)
Location: browser-extension/src/content.ts
// Detect page context
const pageContext = {
url: window.location.href,
title: document.title,
selectedText: window.getSelection()?.toString(),
pageType: detectPageType(), // "product", "article", "video", etc.
};
// Show floating widget
const widget = document.createElement('div');
widget.id = 'morphee-widget';
widget.innerHTML = `
<button id="morphee-trigger">
<img src="${chrome.runtime.getURL('icon.png')}" />
</button>
<div id="morphee-chat" style="display: none;">
<iframe src="${chrome.runtime.getURL('chat.html')}"></iframe>
</div>
`;
document.body.appendChild(widget);
// Listen for user clicks
document.getElementById('morphee-trigger')?.addEventListener('click', () => {
const chat = document.getElementById('morphee-chat');
chat.style.display = chat.style.display === 'none' ? 'block' : 'none';
// Send page context to chat iframe
chrome.runtime.sendMessage({
type: 'PAGE_CONTEXT',
context: pageContext,
});
});
// Context menu integration
chrome.runtime.onMessage.addListener((message) => {
if (message.type === 'ADD_TO_TASKS') {
// Selected text → create task
chrome.runtime.sendMessage({
type: 'CREATE_TASK',
title: window.getSelection()?.toString(),
url: window.location.href,
});
}
});
Background Service Worker
Location: browser-extension/src/background.ts
let wsConnection: WebSocket | null = null;
// Authenticate on extension install
chrome.runtime.onInstalled.addListener(async () => {
// Open auth flow
const authUrl = 'https://api.morphee.app/auth/extension';
const redirectUrl = chrome.identity.getRedirectURL();
chrome.identity.launchWebAuthFlow({
url: `${authUrl}?redirect_uri=${redirectUrl}`,
interactive: true,
}, (responseUrl) => {
const token = new URL(responseUrl).searchParams.get('token');
chrome.storage.local.set({ authToken: token });
});
});
// Maintain WebSocket connection
chrome.runtime.onStartup.addListener(async () => {
const { authToken } = await chrome.storage.local.get('authToken');
wsConnection = new WebSocket(`wss://api.morphee.app/ws?token=${authToken}`);
wsConnection.onmessage = (event) => {
// Broadcast to all open popups/sidebars
chrome.runtime.sendMessage({ type: 'WS_EVENT', data: JSON.parse(event.data) });
};
});
// Handle messages from content scripts
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === 'CREATE_TASK') {
fetch('https://api.morphee.app/api/tasks', {
method: 'POST',
headers: {
'Authorization': `Bearer ${authToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
title: message.title,
metadata: { source: 'browser_extension', url: message.url },
}),
}).then(() => sendResponse({ success: true }));
return true; // Async response
}
});
// Context menu
chrome.contextMenus.create({
id: 'morphee-add-task',
title: 'Add to Morphee Tasks',
contexts: ['selection'],
});
chrome.contextMenus.onClicked.addListener((info, tab) => {
if (info.menuItemId === 'morphee-add-task') {
chrome.tabs.sendMessage(tab.id, { type: 'ADD_TO_TASKS' });
}
});
Chat Popup (React)
Location: browser-extension/src/popup/App.tsx
export function App() {
const [messages, setMessages] = useState<Message[]>([]);
const [pageContext, setPageContext] = useState<PageContext | null>(null);
useEffect(() => {
// Listen for page context
chrome.runtime.onMessage.addListener((message) => {
if (message.type === 'PAGE_CONTEXT') {
setPageContext(message.context);
}
});
}, []);
const sendMessage = async (text: string) => {
// Include page context in AI request
const enrichedPrompt = pageContext
? `Context: I'm on ${pageContext.title} (${pageContext.url}). ${text}`
: text;
const response = await fetch('https://api.morphee.app/api/chat', {
method: 'POST',
headers: {
'Authorization': `Bearer ${authToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
conversation_id: currentConversationId,
message: enrichedPrompt,
}),
});
// Handle SSE stream
const reader = response.body.getReader();
// ... (same SSE logic as web app)
};
return (
<div className="morphee-extension-popup">
<ChatBubble messages={messages} />
<ChatInput onSend={sendMessage} />
{pageContext && (
<div className="context-badge">
📄 {pageContext.title}
</div>
)}
</div>
);
}
3. Embedding SDK (@morphee/sdk)
Goal: npm package for website owners to integrate Morphee chat/tasks/memory into their apps.
Installation
npm install @morphee/sdk
Usage
import { MorpheeClient } from '@morphee/sdk';
const morphee = new MorpheeClient({
apiKey: 'mk_your_api_key', // Partner API key
groupId: 'user_group_id', // User's Morphee group
});
// Chat widget
await morphee.chat.render({
container: '#chat-widget',
theme: 'light',
initialMessage: 'Hello! How can I help you today?',
});
// Task quick-add
await morphee.tasks.create({
title: 'Follow up on customer inquiry',
spaceId: 'customer-support-space',
metadata: {
customerId: '12345',
source: 'partner_app',
},
});
// Memory search (RAG)
const results = await morphee.memory.search({
query: 'customer preferences for shipping',
spaceId: 'customer-support-space',
limit: 5,
});
// Listen to events
morphee.on('task_created', (task) => {
console.log('New task:', task);
});
SDK Architecture
// packages/sdk/src/MorpheeClient.ts
export class MorpheeClient {
private apiKey: string;
private baseUrl: string;
private ws: WebSocket | null = null;
constructor(config: MorpheeConfig) {
this.apiKey = config.apiKey;
this.baseUrl = config.baseUrl || 'https://api.morphee.app';
this.groupId = config.groupId;
}
// Chat API
chat = {
render: async (options: ChatRenderOptions) => {
const container = document.querySelector(options.container);
const iframe = document.createElement('iframe');
iframe.src = `${this.baseUrl}/embed/chat?apiKey=${this.apiKey}&theme=${options.theme}`;
container.appendChild(iframe);
// postMessage bridge for events
window.addEventListener('message', (event) => {
if (event.origin === this.baseUrl) {
this.emit(event.data.type, event.data.payload);
}
});
},
send: async (message: string, conversationId?: string) => {
return this.request('POST', '/api/chat', {
conversation_id: conversationId,
message,
});
},
};
// Tasks API
tasks = {
create: async (task: CreateTaskInput) => {
return this.request('POST', '/api/tasks', task);
},
list: async (filters?: TaskFilters) => {
return this.request('GET', '/api/tasks', filters);
},
};
// Memory API
memory = {
search: async (query: string, spaceId: string, limit = 10) => {
return this.request('POST', '/api/memory/search', {
query,
space_id: spaceId,
limit,
});
},
};
private async request(method: string, path: string, body?: any) {
const response = await fetch(`${this.baseUrl}${path}`, {
method,
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
},
body: body ? JSON.stringify(body) : undefined,
});
if (!response.ok) {
throw new MorpheeError(response.status, await response.text());
}
return response.json();
}
}
Backend: Partner API Keys
New table:
CREATE TABLE partner_api_keys (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
key_hash VARCHAR(64) NOT NULL UNIQUE, -- bcrypt hash of "mk_..."
partner_name VARCHAR(200) NOT NULL,
group_id UUID NOT NULL REFERENCES groups(id) ON DELETE CASCADE,
scopes TEXT[] NOT NULL DEFAULT '{}', -- ["chat", "tasks", "memory"]
rate_limit_per_hour INT DEFAULT 1000,
created_by UUID NOT NULL REFERENCES users(id),
created_at TIMESTAMPTZ DEFAULT NOW(),
revoked BOOLEAN DEFAULT false
);
CREATE INDEX idx_partner_keys_hash ON partner_api_keys(key_hash) WHERE NOT revoked;
Middleware for API key auth:
# backend/auth/partner_keys.py
async def validate_partner_api_key(api_key: str) -> tuple[UUID, list[str]]:
"""Returns (group_id, scopes) if valid."""
if not api_key.startswith('mk_'):
raise ValueError("Invalid API key format")
key_hash = hash_api_key(api_key)
result = await db.fetchrow("""
SELECT group_id, scopes, rate_limit_per_hour
FROM partner_api_keys
WHERE key_hash = $1 AND NOT revoked
""", key_hash)
if not result:
raise ValueError("Invalid or revoked API key")
# Check rate limit (Redis)
usage = await redis.get(f"partner_key_usage:{key_hash}")
if usage and int(usage) >= result['rate_limit_per_hour']:
raise ValueError("Rate limit exceeded")
await redis.incr(f"partner_key_usage:{key_hash}", ex=3600)
return result['group_id'], result['scopes']
4. Partnership Framework
Goal: White-label API, revenue sharing, co-marketing platform for B2B integrations.
Partnership Tiers
| Tier | Features | Revenue Share | Support |
|---|---|---|---|
| Developer | Free API access (1k req/month), public extension store listing | 70/30 (dev/Morphee) | Community |
| Startup | 100k req/month, white-label embedding SDK, co-marketing | 60/40 | |
| Enterprise | Unlimited, custom SLA, dedicated account manager, on-prem option | Custom | Priority |
Partner Portal
Location: https://partners.morphee.app
Features:
- API key management (create, revoke, rotate)
- Usage analytics (requests/day, errors, latency)
- Revenue dashboard (extension sales, usage-based billing)
- Documentation (API reference, SDK guides, code samples)
- Support tickets
White-Label Embedding
Partners can customize:
const morphee = new MorpheeClient({
apiKey: 'mk_partner_key',
branding: {
logo: 'https://partner.com/logo.png',
primaryColor: '#FF5722',
fontFamily: 'Inter',
name: 'Acme AI Assistant', // Replaces "Morphee" in UI
},
});
Backend stores branding in partner_api_keys.branding JSONB column.
Revenue Sharing (Extensions)
When user installs paid extension:
- User pays $9.99/month via Stripe
- Morphee takes 30% ($3.00) for hosting, API, payment processing
- Developer gets 70% ($6.99) deposited monthly via Stripe Connect
Database:
CREATE TABLE extension_subscriptions (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
extension_id UUID NOT NULL REFERENCES extensions(id) ON DELETE CASCADE,
stripe_subscription_id VARCHAR(100) NOT NULL UNIQUE,
price_monthly_cents INT NOT NULL,
revenue_share_percent INT NOT NULL DEFAULT 70, -- Developer's share
status VARCHAR(20) NOT NULL DEFAULT 'active', -- active, canceled, past_due
current_period_start TIMESTAMPTZ NOT NULL,
current_period_end TIMESTAMPTZ NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(user_id, extension_id)
);
API Endpoints
Extensions API
| Endpoint | Method | Description |
|---|---|---|
/api/extensions | GET | List available extensions (marketplace) |
/api/extensions/{id} | GET | Get extension details |
/api/extensions/{id}/manifest | GET | Get extension manifest (JSON) |
/api/spaces/{id}/extensions | POST | Install extension in space |
/api/spaces/{id}/extensions/{ext_id} | DELETE | Uninstall extension |
/api/spaces/{id}/extensions/{ext_id}/permissions | GET | List granted permissions |
/api/spaces/{id}/extensions/{ext_id}/permissions | POST | Grant permission |
/api/extensions/{id}/execute | POST | Execute extension action |
Partner API
| Endpoint | Method | Description |
|---|---|---|
/api/partners/keys | POST | Create API key (parent role only) |
/api/partners/keys/{id} | DELETE | Revoke API key |
/api/partners/usage | GET | Get usage stats |
/api/partners/revenue | GET | Get revenue dashboard data |
Embedding Endpoints (for SDK)
| Endpoint | Method | Description |
|---|---|---|
/embed/chat | GET | Chat widget iframe (auth via API key) |
/embed/tasks | GET | Task widget iframe |
/api/embed/chat | POST | Send chat message (API key auth) |
/api/embed/tasks | POST | Create task (API key auth) |
/api/embed/memory/search | POST | Search memory (API key auth) |
Effort Estimation
| Task | Size | Notes |
|---|---|---|
| Backend: ExtensionsIntegration | M | 6 actions + ACL enforcement |
| Backend: Extension tables + migrations | S | 3 tables (extensions, space_extensions, extension_permissions) |
| Backend: Partner API keys + middleware | M | Auth, rate limiting, scoping |
| Backend: Revenue sharing (Stripe Connect) | M | Webhook handlers, payouts |
| Frontend: Extension loader + sandbox | L | Secure iframe/Worker execution, permission UI |
| Frontend: Extension marketplace | M | Browse, install, configure extensions |
| Browser Extension: Chrome/Firefox | L | Manifest V3, content scripts, popup, auth flow |
| SDK: @morphee/sdk (npm package) | M | TypeScript SDK, docs, examples |
| Partner Portal: Dashboard | L | React app with analytics, revenue, docs |
| Documentation: Developer docs + guides | M | API reference, SDK tutorials, extension authoring |
| Tests: Backend + Frontend + SDK | L | 80+ tests total |
Total: X-Large (6-8 weeks)
Risks & Mitigations
| Risk | Mitigation |
|---|---|
| Extension security (XSS, data exfiltration) | Sandboxed execution (iframe/Worker), CSP headers, permission model, code review for verified extensions |
| Browser extension approval delays | Submit early to Chrome/Firefox stores, have fallback (direct install) |
| Partner API abuse (scraping, DDOS) | Rate limiting, API key scoping, Cloudflare WAF |
| Revenue sharing disputes | Clear ToS, automated payouts, dispute resolution process |
| Extension conflicts (two extensions modify same UI) | Extension priority system, conflict detection UI |
Future Enhancements
Core Features
- Extension Marketplace — Browse, search, install extensions with ratings/reviews
- Extension Analytics — Track usage, errors, performance for developers
- Extension Versioning — Semantic versioning, auto-updates, rollback
- Extension SDK v2 — React hooks (
useMemory,useTasks), Web Components - Mobile SDKs — iOS (Swift), Android (Kotlin) native SDKs
- CLI for Extensions —
morphee-cli create my-extension, local dev server - Extension Templates — Starter templates (React component, data viz, API integration)
- Extension Store Revenue — Premium extensions, in-app purchases
ACL & Permission Enhancements
Extension Permissions (Advanced):
interface ExtensionACL {
extension_id: string;
space_id: string;
permissions: Array<{
action: string; // "memory.search", "tasks.create"
granted_by: string; // User ID who granted
granted_at: Date;
expires_at?: Date; // Temporary permission grants
constraints?: {
rate_limit?: number; // Max calls per hour
data_scope?: string[]; // Limit to specific spaces/tags
requires_approval?: boolean; // Each call requires user approval
};
}>;
blocked_actions: string[]; // Explicitly denied permissions
sandbox_level: 'strict' | 'normal' | 'trusted';
}
Use cases:
-
Classroom Extension Permissions:
- Teacher installs "Plagiarism Checker" extension
- Extension can read student submissions (
memory.searchscoped tohomeworkspace) - Cannot modify submissions (
memory.storeblocked) - Student submissions are anonymized before passing to extension
-
Family Shopping Extension:
- Extension can create tasks in "Shopping" space only
- Rate limit: 10 tasks/hour (prevent spam)
- Requires parent approval for purchases >$50
-
Enterprise Partner White-Label:
- Partner's extension runs in "trusted" sandbox (full API access)
- All actions logged for compliance audit
- Data export restricted by GDPR consent
Permission Approval Workflow:
- Extension requests permission → User sees: "Math Tutor wants to: Search your Homework memories, Render custom graphs — Approve?"
- Temporary grants: "Allow for 1 hour", "Allow once", "Allow always"
- Revoke anytime: Settings → Extensions → Permissions → Revoke
Extension Isolation:
- Each extension runs in isolated context (separate iframe/Worker)
- Extensions cannot access each other's data
- Shared state via PluginContext only (permission-checked)
Audit Trail:
CREATE TABLE extension_action_logs (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
extension_id UUID NOT NULL REFERENCES extensions(id),
space_id UUID NOT NULL REFERENCES spaces(id),
user_id UUID NOT NULL REFERENCES users(id),
action VARCHAR(100) NOT NULL,
params JSONB,
result_success BOOLEAN,
error_message TEXT,
timestamp TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_extension_logs_user ON extension_action_logs(user_id, timestamp DESC);
- All extension actions logged with full attribution
- User can view: "Show all actions by 'Math Tutor' extension this week"
- Admin dashboard: aggregate extension usage across group
Advanced Extension Features
Extension Communication:
- Extensions can communicate via message passing (permission-checked)
- Example: "Calendar extension" sends event to "Email extension" → creates draft email
Extension Lifecycle Hooks:
class MyPlugin implements MorpheePlugin {
async onInstall() { /* One-time setup */ }
async onUninstall() { /* Cleanup */ }
async onUpgrade(oldVersion: string) { /* Migration */ }
async onSpaceEnter(spaceId: string) { /* Context switch */ }
async onSpaceLeave(spaceId: string) { /* Cleanup */ }
}
Extension Configuration UI:
- Extensions define config schema (JSON Schema)
- Auto-generated settings UI in Morphee app
- Example: "OpenAI API Key", "Preferred units (metric/imperial)"
Extension Data Storage:
# Backend: ExtensionsIntegration
async def get_extension_data(self, ctx: ExecutionContext, extension_id: str, key: str) -> ActionResult
async def set_extension_data(self, ctx: ExecutionContext, extension_id: str, key: str, value: Any) -> ActionResult
- Per-extension KV store (scoped to space)
- Encrypted at rest (VaultProvider)
- Quota enforced (10MB per extension per space)
Browser Extension Enhancements
Context-Aware Features:
- Detect page type (e-commerce, article, video) → suggest relevant actions
- Example: On Amazon product page → "Add to family wishlist", "Compare prices with saved products"
- Example: On YouTube video → "Save to 'Watch Later' space", "Summarize video transcript"
Offline Mode:
- Browser extension works offline using IndexedDB cache
- Queue actions (create task, save memory) → sync when online
Multi-Account Support:
- Switch between Morphee accounts (work, personal, family)
- Separate auth tokens, different group contexts
Privacy Controls:
- User can whitelist/blacklist domains for context extraction
- Example: "Never read banking websites", "Only extract context from work domains"
Keyboard Shortcuts:
Cmd+Shift+M→ Open Morphee chatCmd+Shift+T→ Quick-add task from selectionCmd+Shift+S→ Save page to memory
Embedding SDK Enhancements
Framework-Specific SDKs:
// React
import { MorpheeProvider, useChat, useTasks } from '@morphee/react';
function App() {
return (
<MorpheeProvider apiKey="mk_...">
<ChatWidget />
</MorpheeProvider>
);
}
function ChatWidget() {
const { messages, send } = useChat();
return <div>{/* ... */}</div>;
}
// Vue, Angular, Svelte versions
Customizable Components:
await morphee.chat.render({
container: '#chat',
components: {
// Replace default components with custom ones
MessageBubble: MyCustomBubble,
TaskCard: MyCustomTaskCard,
},
css: `
.morphee-chat { border-radius: 16px; }
.morphee-message { font-family: 'Comic Sans MS'; }
`,
});
Webhooks:
- Partner app receives real-time events via webhooks
- Example:
POST https://partner.com/webhooks/morpheewhen task created - Signed with HMAC for security
Partnership Enhancements
Co-Marketing Platform:
- Joint blog posts, webinars, case studies
- Partner directory: "Morphee Works With" (logos, links)
- Referral program: Partner refers customer → 10% recurring commission
White-Label On-Prem:
- Enterprise partners can deploy Morphee on their infrastructure
- Docker Compose + Kubernetes manifests
- Single-tenant isolation, custom domain
API Versioning:
- Semantic versioning:
v1,v2, etc. - Deprecated endpoints supported for 12 months
- Migration guides for partners
Partner Success Metrics:
- Dashboard: MAU, API success rate, avg latency, revenue
- Alerts: "API error rate >5%", "Usage spike detected"
Compliance & Certifications:
- SOC 2 Type II (for enterprise partners)
- GDPR compliance (data processing agreements)
- HIPAA support (for healthcare partners)
Integration with Existing Systems
Extension + Skills Integration (Phase 3b.1):
- Extensions can define skills: "Math Tutor extension provides 'Solve Equation' skill"
- Skills can call extension actions
- Dynamic skill registration via extension manifest
Extension + Memory Integration (Phase 2):
- Extensions can embed custom data types in LanceDB
- Example: "Code Snippet extension" embeds code with syntax-aware search
- Per-extension memory namespace isolation
Extension + Frontend Integration (Phase 3b.2):
- Extensions can register custom ComponentSpec renderers
- Example: "Chart extension" renders
{ type: 'custom_chart', props: {...} }
Extension + Notifications (Phase 3a):
- Extensions can send notifications:
ctx.notify({ title, body }) - User can configure: "Mute notifications from 'Weather' extension"
Privacy & Security
Extension Code Review:
- All extensions submitted to marketplace undergo security review
- Static analysis: detect API calls, data exfiltration attempts
- Manual review for verified extensions
Extension Sandboxing (Advanced):
- Extensions run in separate process (Tauri sidecar)
- Memory isolation, no shared state except via IPC
- CPU/memory quotas enforced
Extension Permissions (Runtime Checks):
// In extension code
await ctx.memory.search(query); // ❌ Throws if "memory.search" not granted
// Graceful degradation
if (ctx.hasPermission('memory.search')) {
const results = await ctx.memory.search(query);
} else {
showMessage('This extension needs memory search permission');
}
User Data Privacy:
- Extensions cannot access other extensions' data
- User can export all data stored by extensions (GDPR)
- User can delete all extension data on uninstall
Partner API Security:
- API keys rotated every 90 days (automated email reminder)
- IP whitelisting for enterprise partners
- Anomaly detection: unusual usage patterns trigger alerts
Last Updated: February 13, 2026