canvas-code-execution

Canvas Code Execution Skill

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "canvas-code-execution" with this command: npx skills add omerakben/omer-akben/omerakben-omer-akben-canvas-code-execution

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 } }); }

  1. Block Dynamic Imports

// DANGEROUS_PATTERNS in import-detector.ts blocks: // - import() // - importlib.import_module() // - exec() // - eval() // - compile() with 'exec' // - getattr(import) // - builtins.import

  1. Iframe Sandbox Restrictions

// For JavaScript execution - minimal permissions const sandbox = [ 'allow-scripts', // NO allow-same-origin // NO allow-forms // NO allow-popups ].join(' ');

  1. 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

user

Code error (syntax, runtime) Show fix suggestions

recoverable

Timeout, network Retry button

reload_required

Memory exceeded, crash Refresh button

fatal

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, },

  1. 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 SUPPORTED_LANGUAGES tiers in types.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

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

bundle-optimization

No summary provided by upstream source.

Repository SourceNeeds Review
General

brightness-system

No summary provided by upstream source.

Repository SourceNeeds Review
General

doc-coauthoring

No summary provided by upstream source.

Repository SourceNeeds Review