DevScribe Plugin Development & AI Context Specification AI Prompt Directive : Use this document as the authoritative context specification when instructing AI coding assistants (e.g. Gemini, Claude, Cursor, ChatGPT) to build, refactor, or generate custom plugins for the DevScribe developer workspace.
1. AI System Prompt / Directive Copy and paste the following prompt block when starting a new plugin project with an AI assistant:
You are an expert full-stack developer building a plugin for DevScribe (an Electron-based developer application).
DevScribe plugins run inside an Electron Webview and communicate with the main application strictly through `window.pluginAPI`.
Core Architectural Rules:
1. All interactions with DevScribe (storage, file operations, code execution, database queries, terminal, notifications, API client) MUST use `window.pluginAPI`.
2. Do NOT use Node.js `require` or Electron direct modules in the webview bundle; use `window.pluginAPI`.
3. Listen for theme updates via `window.addEventListener("theme-changed", ...)` or read `window.pluginAPI.context.theme`.
4. Persist document state using `window.pluginAPI.updateDocument(window.pluginAPI.context.fileId, data)` or `window.pluginAPI.saveData(data)`.
5. Strictly adhere to the method signatures in the DevScribe Plugin API reference below.2. Quickstart: Commands to Initialize a Plugin Repository Run these commands to set up a new DevScribe plugin repository using Vite + React (recommended) or Vanilla JavaScript :
Option A: React + Vite (Recommended) # 1. Create a new React plugin repository
npx -y create-vite@latest devscribe-plugin-mytool --template react
cd devscribe-plugin-mytool
# 2. Install dependencies
npm install
# 3. Add Remix Icons for visual consistency with DevScribe
npm install remixicon
# 4. Start local development server
npm run devOption B: Vanilla JavaScript mkdir devscribe-plugin-mytool && cd devscribe-plugin-mytool
npm init -y3. Plugin Manifest Specification (manifest.json) Every plugin repository MUST include a manifest.json at its root directory:
{
"id": "my-custom-plugin",
"name": "My Custom Plugin",
"version": "1.0.0",
"description": "A custom developer tool plugin for the DevScribe workspace.",
"author": "Developer Name",
"entry": "index.html",
"icon": "ri-code-s-slash-line",
"fileTypes": ["code-editor", "custom-tool"],
"permissions": [
"file-system",
"code-execution",
"terminal",
"database"
]
}4. Complete Reference of Allowed window.pluginAPI Methods A. Context & Theme Properties Property Type Description window.pluginAPI.context.pluginIdstringID of the active running plugin window.pluginAPI.context.fileIdstringID of the current active document file window.pluginAPI.context.theme"light" | "dark"Synchronously synced DevScribe theme
Theme Listener Pattern: window.addEventListener("theme-changed", (event) => {
const currentTheme = event.detail.theme; // "light" | "dark"
console.log("DevScribe Theme updated:", currentTheme);
});B. Document & File Management Method Signatures / Parameters Return Type Description updateDocument(fileId: string, content: any)Promise<void>Primary Save : Persists block/JSON document data for active filegetDocumentsByParentFile(fileId: string)Promise<any[]>Loads saved document block array for specified file ID saveData(data: any)Promise<void>Legacy Save : Saves raw state object for (pluginId, fileId)loadData()Promise<any>Legacy Load : Retrieves raw state object for (pluginId, fileId)getFileDetailsById(fileId: string)Promise<{ title, lastEdited, folderId, fileType }>Loads file metadata updateFileName(newName: string)Promise<void>Renames the current file createFile(fileData: object)Promise<object>Creates a new file in workspace openFileInTab(fileId: string, fileType: string, title: string)Promise<void>Opens file tab in DevScribe workspace getNestedPath(params?: { fileId?: string, folderId?: string })Promise<{ folders: Array, file: object }>Resolves full breadcrumb ancestor folder hierarchy getAllFiles()Promise<any[]>Lists all files in the active workspace getPlugins()Promise<any[]>Lists all installed workspace plugins getCorePlugins()Promise<any[]>Lists core system plugins
C. Native Code Execution Engine Method Parameters Return Type Description runJsCode(code: string)Promise<any>Executes JavaScript code natively in main process runTsCode(code: string)Promise<any>Executes TypeScript code runJavaCode(code: string, config?: object)Promise<any>Compiles & runs Java code runShellCommand(command: string)Promise<any>Executes terminal shell command in main process runSqliteCommand(query: string)Promise<any>Executes SQLite query on local workspace database runSqlCommand(queryOrParams: any, configId: string)Promise<any>Executes SQL query on configured remote DB runDockerCompose(code: string, action?: string, fileName?: string, fileId?: string)Promise<any>Executes Docker Compose action (up -d, stop, down)
D. Data-Bridge (Database Operations) Method Parameters Return Type Description getConnections()Promise<any[]>Returns all configured database connections saveConnection(data: object)Promise<any>Saves database connection configuration testConnection(data: object)Promise<boolean>Tests database connection parameters deleteConnection(id: string)Promise<void>Removes a database connection getDatabases(connectionId: string)Promise<string[]>Lists databases for a connection getDatabaseTables(connectionId: string, database: string)Promise<string[]>Lists tables in a database executeQuery(connectionId: string, query: string, database: string)Promise<any>Executes SQL query on specified connection
E. Integrated PTY Terminal (window.pluginAPI.terminal) Method Parameters Return Type Description terminal.create(id: string)voidInitializes a PTY terminal instance terminal.input(id: string, data: string)voidSends keystrokes/data to terminal terminal.resize(id: string, cols: number, rows: number)voidResizes terminal grid dimensions terminal.dispose(id: string)voidDestroys PTY terminal instance terminal.onData(id: string, callback: (data: string) => void)() => voidSubscribes to terminal output; returns unsubscribe fn
F. Native API Client & Environments (window.pluginAPI.api) Method Parameters Return Type Description api.executeApiRequest{ url: string, method: string, headers: object, body?: string, filePath?: string, formData?: any[] }Promise<Response>Native HTTP request (bypasses browser CORS) api.executeCurl(command: string)Promise<Response>Executes cURL command string api.fetchAllEnvs()Promise<Array<{ id, name }>>Fetches environment scopes api.fetchEnvByScopeId(scopeId: string)Promise<Array<{ id, key, value }>>Fetches key-value environment variables api.createEnv(name: string)Promise<object>Creates a new environment scope api.saveEnvVariable{ key, value, scopeType, scopeId }Promise<void>Creates/saves env variable api.updateEnvVariable{ id: number, key: string, value: string }Promise<void>Updates existing variable api.deleteEnvVariable(id: number)Promise<void>Deletes an environment variable
G. Messaging & System Utilities Method Parameters Return Type Description notify(message: string, type?: 'info' | 'success' | 'warning' | 'error')voidTriggers DevScribe desktop toast notification openExternal(url: string)voidOpens URL in system default browser messaging.invoke(channel: string, ...args: any)Promise<any>Sends custom IPC invocation to Main process messaging.on(channel: string, callback: (data: any) => void)() => voidSubscribes to main process push events messaging.removeAllListeners(channel: string)voidRemoves IPC event listeners for channel
5. Standard Component Architecture Example (React) Below is a production boilerplate for a DevScribe plugin component demonstrating theme synchronization, auto-saving, and code execution:
import React, { useState, useEffect } from 'react';
export default function App() {
const [code, setCode] = useState('');
const [output, setOutput] = useState('');
const [theme, setTheme] = useState(window.pluginAPI?.context?.theme || 'light');
const [loading, setLoading] = useState(false);
const fileId = window.pluginAPI?.context?.fileId;
// 1. Initialize Document Content & Theme Listener
useEffect(() => {
async function loadContent() {
if (!fileId || !window.pluginAPI) return;
try {
const docs = await window.pluginAPI.getDocumentsByParentFile(fileId);
if (docs && docs.length > 0 && docs[0].content) {
const docData = docs[0].content;
const initialCode = Array.isArray(docData) ? docData[0]?.data?.code : docData.code;
if (initialCode) setCode(initialCode);
}
} catch (err) {
console.error("Failed to load initial document data:", err);
}
}
loadContent();
const handleThemeChange = (e) => setTheme(e.detail.theme);
window.addEventListener('theme-changed', handleThemeChange);
return () => window.removeEventListener('theme-changed', handleThemeChange);
}, [fileId]);
// 2. Persist Document Content to DevScribe
const handleCodeChange = async (newCode) => {
setCode(newCode);
if (!fileId || !window.pluginAPI) return;
try {
await window.pluginAPI.updateDocument(fileId, [
{
type: "code-editor",
data: { code: newCode, updatedAt: Date.now() }
}
]);
} catch (err) {
console.error("Auto-save failed:", err);
}
};
// 3. Run Code Action
const handleExecute = async () => {
setLoading(true);
try {
const result = await window.pluginAPI.runJsCode(code);
setOutput(typeof result === 'object' ? JSON.stringify(result, null, 2) : String(result));
window.pluginAPI.notify("Code executed successfully!", "success");
} catch (err) {
setOutput("Error: " + err.message);
window.pluginAPI.notify("Execution failed", "error");
} finally {
setLoading(false);
}
};
return (
<div style={{
padding: '16px',
backgroundColor: theme === 'dark' ? '#1E1E1E' : '#FFFFFF',
color: theme === 'dark' ? '#F3F4F6' : '#111827',
minHeight: '100vh',
fontFamily: 'Inter, sans-serif'
}}>
<header style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '12px' }}>
<h3>DevScribe Plugin Tool</h3>
<button
onClick={handleExecute}
disabled={loading}
style={{
padding: '6px 14px',
backgroundColor: '#2563EB',
color: '#FFFFFF',
border: 'none',
borderRadius: '4px',
cursor: 'pointer'
}}
>
{loading ? 'Executing...' : 'Run Code'}
</button>
</header>
<textarea
value={code}
onChange={(e) => handleCodeChange(e.target.value)}
placeholder="// Write your code or document content here..."
style={{
width: '100%',
height: '240px',
fontFamily: 'monospace',
fontSize: '13px',
padding: '10px',
borderRadius: '6px',
border: '1px solid #D1D5DB',
backgroundColor: theme === 'dark' ? '#2D2D2D' : '#FAFAFA',
color: theme === 'dark' ? '#F9FAFB' : '#111827'
}}
/>
{output && (
<div style={{ marginTop: '16px' }}>
<h4>Console Output:</h4>
<pre style={{
padding: '12px',
borderRadius: '6px',
backgroundColor: theme === 'dark' ? '#111827' : '#F3F4F6',
overflowX: 'auto'
}}>
{output}
</pre>
</div>
)}
</div>
);
}