Claude-skill-registry canvas-code-execution
Develops Canvas code execution features with Pyodide/iframe sandboxing. Use when working on Python/JS execution, package management, or sandbox security.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/canvas-code-execution" ~/.claude/skills/majiayu000-claude-skill-registry-canvas-code-execution && rm -rf "$T"
manifest:
skills/data/canvas-code-execution/SKILL.mdsource content
Canvas Code Execution Skill
When to Use
Use this skill when:
- Implementing Python execution via Pyodide
- Adding JavaScript execution via iframe sandbox
- Working with package management (micropip)
- Handling execution errors and timeouts
- Adding new supported languages
Architecture Overview
lib/canvas/ ├── execution-errors.ts # Typed error handling with user-friendly messages ├── import-detector.ts # Python import parsing and package detection ├── package-manager.ts # Pyodide singleton + micropip integration ├── package-security.ts # Allowlist/blocklist for packages ├── monaco-loader.ts # Monaco editor with CDN fallback └── types.ts # Canvas types and language support components/canvas/ ├── canvas-preview.tsx # Execution preview with Pyodide/iframe ├── canvas-editor.tsx # Monaco editor wrapper └── canvas-panel.tsx # Full Canvas panel with split view
Security Model (NEVER VIOLATE)
1. Package Allowlist Only
// ✅ CORRECT: Check allowlist before loading import { isPackageAllowed, isPackageBlocked } from '@/lib/canvas/package-security'; if (!isPackageAllowed(packageName)) { throw new CanvasExecutionError({ code: CanvasErrorCode.PACKAGE_NOT_ALLOWED, context: { packageName } }); }
2. Block Dynamic Imports
// DANGEROUS_PATTERNS in import-detector.ts blocks: // - __import__() // - importlib.import_module() // - exec() // - eval() // - compile() with 'exec' // - getattr(__import__) // - builtins.__import__
3. Iframe Sandbox Restrictions
// For JavaScript execution - minimal permissions const sandbox = [ 'allow-scripts', // NO allow-same-origin // NO allow-forms // NO allow-popups ].join(' ');
4. Execution Timeouts
// Always enforce timeouts const EXECUTION_TIMEOUT = 30_000; // 30s for code const PYODIDE_LOAD_TIMEOUT = 60_000; // 60s for Pyodide init const PACKAGE_INSTALL_TIMEOUT = 120_000; // 2min for packages
Error Handling Pattern
CanvasExecutionError Class
import { CanvasExecutionError, CanvasErrorCode } from '@/lib/canvas/execution-errors'; // Creating errors throw new CanvasExecutionError({ code: CanvasErrorCode.EXECUTION_SYNTAX_ERROR, context: { lineNumber: 5, traceback: pythonTraceback, }, }); // Factory methods CanvasExecutionError.fromPythonError(traceback, duration); CanvasExecutionError.timeout(duration, 'execution'); CanvasExecutionError.packageError(packageName, 'not_allowed'); // For UI display (user-friendly) const display = error.toUserDisplay(); // { title, message, recovery[], severity, showRefresh }
Error Severity Levels
| Severity | Meaning | Action |
|---|---|---|
| Code error (syntax, runtime) | Show fix suggestions |
| Timeout, network | Retry button |
| Memory exceeded, crash | Refresh button |
| CDN unreachable, sandbox violation | Feature unavailable |
Import Detection
Analyzing Code for Packages
import { analyzeImports, validateImports } from '@/lib/canvas/import-detector'; const analysis = analyzeImports(pythonCode); // analysis.packagesToLoad: string[] - External packages needed // analysis.blockedPackages: {...}[] - Blocked with reasons // analysis.stdlibPackages: string[] - Python stdlib (no action) // analysis.unknownPackages: string[] - Unknown (may work) // analysis.canExecute: boolean - Safe to run // analysis.warnings: string[] - User warnings // analysis.estimatedDownloadKB: number - Total download size
Quick Validation
const { valid, errors, warnings } = validateImports(code); if (!valid) { // Show errors to user }
Package Manager Usage
Singleton Pattern
import { PyodidePackageManager, getPackageManager } from '@/lib/canvas/package-manager'; const manager = getPackageManager({ verbose: process.env.NODE_ENV === 'development', onProgress: (progress) => { // Update UI with progress.message, progress.packagesLoaded, etc. }, }); // Initialize once per page await manager.initialize(); // Execute with automatic package loading const result = await manager.executeWithPackages(code); // { success, output, error, returnValue, durationMs }
Progress Callbacks
interface PackageLoadProgress { status: 'analyzing' | 'downloading' | 'installing' | 'complete' | 'error'; currentPackage: string | null; packagesTotal: number; packagesLoaded: number; estimatedSizeKB: number; downloadedKB: number; message: string; }
Adding New Packages
1. Add to Allowlist
// In package-security.ts ALLOWED_PACKAGES newpackage: { name: "newpackage", displayName: "New Package", description: "Short student-friendly description", tier: PackageTier.STANDARD, // or DATA_SCIENCE, PURE_PYTHON category: PackageCategory.DATA, // or MATH, VISUALIZATION, etc. sizeKB: 2000, // Download size memoryKB: 15_000, // RAM when loaded isPurePython: true, // Or false for C extensions aliases: ["np"], // Import aliases dependencies: ["numpy"], // Auto-installed warnSlowLoad: false, warnMemory: false, },
2. Update Blocklist If Needed
// In BLOCKED_PACKAGES dangerouspackage: { reason: "Security reason visible to students", alternatives: ["safe-alternative"], },
Monaco Editor Integration
Loading with Fallback
import { initializeMonaco, isMonacoReady, resetMonacoLoader } from '@/lib/canvas/monaco-loader'; // CDN fallback chain: // 1. jsdelivr (primary) // 2. unpkg // 3. cdnjs // Handle AMD conflicts with Pyodide // - Monaco and Pyodide both use AMD loaders // - package-manager.ts sets __pyodideLoadingAMD flag // - monaco-loader.ts waits for this flag before loading
Reset on Error
try { await initializeMonaco(); } catch (error) { resetMonacoLoader(); // Retry or show error }
Language Support
Execution Matrix
// From types.ts export const EXECUTION_SUPPORT: Record<string, 'pyodide' | 'iframe' | 'none'> = { python: 'pyodide', javascript: 'iframe', typescript: 'iframe', // Transpiled html: 'iframe', react: 'iframe', css: 'iframe', sql: 'none', java: 'none', // etc. };
Adding New Language
- Add to
tiers inSUPPORTED_LANGUAGEStypes.ts - Set execution support in
EXECUTION_SUPPORT - Add Monaco language ID mapping in
getMonacoLanguage() - Add file extension in
getFileExtension()
Component Integration
Canvas Preview
// In canvas-preview.tsx <CanvasPreview content={code} language="python" onExecutionResult={(result) => { // Handle output, errors }} onExecutionStart={() => { // Show loading }} />
Error Display
import { CanvasExecutionError } from '@/lib/canvas/execution-errors'; function ExecutionErrorDisplay({ error }: { error: CanvasExecutionError }) { const display = error.toUserDisplay(); return ( <div className={cn('p-4 rounded-lg', severityStyles[display.severity])}> <h4 className="font-medium">{display.title}</h4> <p className="text-sm mt-1">{display.message}</p> {display.recovery.length > 0 && ( <ul className="text-xs mt-2 space-y-1"> {display.recovery.map((r, i) => ( <li key={i}>• {r}</li> ))} </ul> )} {display.showRefresh && ( <Button onClick={() => window.location.reload()} size="sm"> Refresh Page </Button> )} </div> ); }
Testing Checklist
- Python execution with imports works
- Package loading shows progress
- Blocked packages show helpful alternatives
- Timeouts trigger with recovery options
- Mobile memory warnings appear
- Monaco loads (check AMD conflicts)
- Iframe sandbox restrictions enforced
- Error messages are student-friendly
- Dynamic import patterns are blocked