Hoody Exec
Section titled “Hoody Exec”The recommended way to run scripts on Hoody. Write a TypeScript/JavaScript function in a file. That’s it. You now have an HTTP endpoint — complete with automatic routing, JSON serialization, dependency installation, and production-grade execution. No Express. No Fastify. No webserver configuration. No package.json. Just write code in files, and they become URLs.
This is what “everything is HTTP” means in practice. Your code IS the API.
Two Execution Modes
Section titled “Two Execution Modes”Everything in Hoody Exec revolves around choosing the right execution mode. This one decision changes everything about how your code runs.
| Feature | Worker Mode | Serverless Mode |
|---|---|---|
| State | Persistent shared object | None (fresh each time) |
| WebSocket | Supported | Not available |
| Concurrency | Unlimited (handle in code) | Configurable via @concurrent |
| Startup | Once (fast subsequent requests) | Per request (slight overhead) |
| Memory | Higher (persistent VM) | Lower (ephemeral) |
| Use Case | Real-time, stateful APIs | Webhooks, isolated tasks |
Worker Mode (// @mode worker) — Think: long-running Node.js server that never restarts. Persistent VM, shared state across requests, WebSocket support, zero cold start.
Serverless Mode (// @mode serverless or omit) — Think: AWS Lambda, Vercel Functions. Fresh VM per request, complete isolation, configurable concurrency.
See Execution Modes for the complete deep dive with real-world examples.
What You Can Do
Section titled “What You Can Do”- File = API — Create file → instant HTTP endpoint (no server config)
- Two Modes — Worker (persistent) or Serverless (isolated)
- Magic Comments — Configure with
// @mode worker,// @cors *,// @timeout 5000 - File-Based Routing —
api/users/[id].ts→/api/users/123with dynamic parameters - Powered by Bun — Modern JavaScript runtime (faster than Node.js)
- AI Code Generation — Write
// @ai true→ get AI helpers injected automatically - Auto-Install Dependencies — Use
require('axios')→ automatically installed (no package.json) - Templates — Scaffold from built-in or custom templates
- Code Validation — TypeScript checking, syntax validation, dependency analysis
- Shared State — In-memory KV store across requests (worker mode only)
- WebSocket Support — Real-time bidirectional communication (worker mode only)
- Monitoring — Performance metrics, log streaming, cache stats
Quick Example
Section titled “Quick Example”Create scripts/1/api/hello.ts:
// @mode serverless// @cors reflective// @timeout 5000
return { message: 'Hello from Hoody Exec!', timestamp: new Date().toISOString(), method: metadata.method, ip: metadata.clientIp};That’s it. It’s now live at:
https://PROJECT_ID-CONTAINER_ID-exec-1.SERVER.containers.hoody.icu/api/helloNo imports. No exports. No configuration. The parameters (metadata, req, res, shared) are automatically injected.
URL Structure
Section titled “URL Structure”Every Hoody Exec instance is accessible via a unique hostname:
{projectId}-{containerId}-exec-{execId}.{server}.containers.hoody.icu| Component | Description | Example |
|---|---|---|
projectId | Your project ID | abc123 |
containerId | Container ID | def456 |
execId | Exec instance identifier | 1, 2, test |
server | Server location | us1, eu2 |
The exec ID determines which script directory is used:
exec-1serves scripts fromscripts/1/exec-2serves scripts fromscripts/2/exec-testserves scripts fromscripts/test/
You can run multiple exec instances on a single container, each with its own scripts, routing, and shared state. Subdomains resolve automatically — create a new exec ID and it’s immediately routable.
Discovering Available Exec IDs
Section titled “Discovering Available Exec IDs”Use the exec list endpoint to see which exec instances are available:
# List all exec instance IDshoody exec namespaces listconst containerClient = await client.withContainer({ id: CONTAINER_ID, project_id: PROJECT_ID, server: SERVER});const result = await containerClient.exec.ids.list();console.log(result.execIds); // [{ id: "1", type: "custom", files: 4 }, ...]curl "https://PROJECT-CONTAINER-exec-1.SERVER.containers.hoody.icu/api/v1/exec/list"Example response:
{ "execIds": [ { "id": "1", "type": "custom", "files": 4 }, { "id": "2", "type": "custom", "files": 1 } ], "total": 2, "summary": { "sdk": 0, "custom": 2 }}To list scripts for a specific exec instance:
# List all scripts in the current exec instancehoody exec scripts list-userconst scripts = await containerClient.exec.scripts.list();console.log(scripts.data);curl "https://PROJECT-CONTAINER-exec-1.SERVER.containers.hoody.icu/api/v1/exec/scripts/list"Calling Scripts from Scripts
Section titled “Calling Scripts from Scripts”Since every script is an HTTP endpoint, you can call any script from any other script using fetch():
// @mode serverless
// Call other exec scripts by their URL pathconst news = await fetch("/api/hackernews");const weather = await fetch("/api/weather");
const [newsData, weatherData] = await Promise.all([ news.json(), weather.json()]);
return { news: newsData, weather: weatherData };Relative paths like /api/hackernews resolve to the same exec instance. To call scripts on a different instance or container, use the full hostname:
// Call a script on exec instance 2const res = await fetch("https://PROJECT-CONTAINER-exec-2.SERVER.containers.hoody.icu/api/users");
// Call a script on a different containerconst res2 = await fetch("https://PROJECT-OTHER_CONTAINER-exec-1.SERVER.containers.hoody.icu/reports/daily");Getting Started
Section titled “Getting Started”Get your first script running in three steps:
1. Write — Create a script file:
// @mode serverlessreturn { message: 'Hello, world!', time: Date.now() };Or create it programmatically:
# Write a script to the exec instancehoody exec scripts write --path "hello.js" \ --content "// @mode serverless\nreturn { message: 'Hello, world!' };" \ --create-dirsconst containerClient = await client.withContainer({ id: CONTAINER_ID, project_id: PROJECT_ID, server: SERVER});await containerClient.exec.scripts.write({ path: 'hello.js', content: '// @mode serverless\nreturn { message: "Hello, world!" };', createDirs: true});curl -X POST "https://PROJECT-CONTAINER-exec-1.SERVER.containers.hoody.icu/api/v1/exec/scripts/write" \ -H "Content-Type: application/json" \ -d '{"path": "hello.js", "content": "// @mode serverless\nreturn { message: \"Hello, world!\" };", "createDirs": true}'2. Execute — Access your script via its URL:
curl "https://PROJECT-CONTAINER-exec-1.SERVER.containers.hoody.icu/hello"3. Verify — Check the response and logs:
{ "message": "Hello, world!", "time": 1708700000000 }Stream logs in real time to debug:
# Stream logs from the exec instancehoody exec logs stream --file "api/hello.ts"// Logs are streamed via SSE — use the HTTP endpoint directlyconst res = await fetch( `https://${PROJECT}-${CONTAINER}-exec-1.${SERVER}.containers.hoody.icu/api/v1/exec/logs/stream?file=access.log`);curl "https://PROJECT-CONTAINER-exec-1.SERVER.containers.hoody.icu/api/v1/exec/logs/stream?file=access.log"API Endpoints Summary
Section titled “API Endpoints Summary”All endpoints accessed relative to your Exec instance:
https://PROJECT_ID-CONTAINER_ID-exec-1.SERVER.containers.hoody.icuCore Execution:
GET/POST /{path}— Execute scripts via file-based routes
Script Management:
GET /api/v1/exec/scripts/list— List all scriptsGET /api/v1/exec/scripts/read— Read script contentPOST /api/v1/exec/scripts/write— Create/update scriptsDELETE /api/v1/exec/scripts/delete— Delete a scriptPOST /api/v1/exec/scripts/move— Move/rename a scriptPOST /api/v1/exec/scripts/tree— Get directory tree
Templates:
GET /api/v1/exec/templates/list— List templatesGET /api/v1/exec/templates/preview— Preview templatePOST /api/v1/exec/templates/generate— Create from template
Validation:
POST /api/v1/exec/validate/script— Comprehensive validationPOST /api/v1/exec/validate/typescript— TypeScript checkingPOST /api/v1/exec/validate/syntax— Syntax validationPOST /api/v1/exec/validate/dependencies— Dependency validationPOST /api/v1/exec/validate/return-type— Return type validationPOST /api/v1/exec/validate/magic-comments— Parse magic comments
Dependencies:
POST /api/v1/exec/dependencies/check— Check missing packagesPOST /api/v1/exec/dependencies/install— Install NPM modules
Routing:
POST /api/v1/exec/route/resolve— Resolve which script a URL maps toPOST /api/v1/exec/route/discover— Discover all routesPOST /api/v1/exec/route/test— Test route matching
Package Management:
GET /api/v1/exec/package/read— Read package.jsonPOST /api/v1/exec/package/update— Update package.jsonPOST /api/v1/exec/package/install— Install packagesPOST /api/v1/exec/package/compare— Compare packagesPOST /api/v1/exec/package/pin— Pin versionsPOST /api/v1/exec/package/init— Init package.json
Magic Comments API:
GET /api/v1/exec/magic-comments/schema— Get magic comments schemaGET /api/v1/exec/magic-comments/read— Read script magic commentsPUT /api/v1/exec/magic-comments/update— Update magic commentsPOST /api/v1/exec/magic-comments/bulk-update— Bulk update magic comments
State & Cache:
POST /api/v1/exec/shared-state/get— Read shared statePOST /api/v1/exec/shared-state/set— Write shared statePOST /api/v1/exec/shared-state/clear— Clear shared statePOST /api/v1/exec/cache/clear— Clear execution cache
Logs:
GET /api/v1/exec/logs/list— List logsPOST /api/v1/exec/logs/read— Read logGET /api/v1/exec/logs/stream— Stream logs (SSE)POST /api/v1/exec/logs/search— Search logsDELETE /api/v1/exec/logs/clear— Clear logs
Monitoring:
GET /api/v1/exec/monitor/stats— Performance metricsGET /api/v1/exec/monitor/active-requests— Active requestsPOST /api/v1/exec/monitor/script-performance— Script performanceGET /api/v1/exec/health— Health check
System:
POST /api/v1/exec/system/restart— Restart serverGET /api/v1/exec/system/restart-status— Get restart status
User OpenAPI:
POST /api/v1/exec/user-openapi/generate— Generate OpenAPI spec from user scriptsGET /api/v1/exec/user-openapi/list— List user scripts for OpenAPI generationPOST /api/v1/exec/user-openapi/validate— Validate user schemaGET /api/v1/exec/user-openapi/schema— Serve schema fileGET /api/v1/exec/user-openapi/spec— Serve generated OpenAPI specPOST /api/v1/exec/user-openapi/merge— Merge OpenAPI specs
SDK Management:
POST /api/v1/exec/sdk/import— Import SDKGET /api/v1/exec/sdk/list— List imported SDKsGET /api/v1/exec/sdk/:id— Get SDK detailsDELETE /api/v1/exec/sdk/:id— Delete imported SDK
Custom Templates:
POST /api/v1/exec/templates/create-custom— Create custom templatePUT /api/v1/exec/templates/update-custom/:name— Update custom templateDELETE /api/v1/exec/templates/delete-custom/:name— Delete custom template
Bundled Dependencies:
GET /api/v1/exec/dependencies/bundled— List pre-bundled dependencies
Use Cases
Section titled “Use Cases”Instant APIs (Either Mode)
Section titled “Instant APIs (Either Mode)”Skip Express/Fastify setup — write functions in files, they’re instantly HTTP endpoints. Worker mode for performance, serverless for isolation.
Real-Time Services (Worker Mode)
Section titled “Real-Time Services (Worker Mode)”WebSocket chat servers, live dashboards, SSE streams, collaborative tools — worker mode’s persistent VM handles connections efficiently with shared state.
Webhook Receivers (Serverless Mode)
Section titled “Webhook Receivers (Serverless Mode)”Stripe, GitHub, Slack webhooks — serverless isolation prevents cross-contamination, @concurrent false ensures serial processing for consistency.
Hoody AI Interception (Worker Mode)
Section titled “Hoody AI Interception (Worker Mode)”Intercept and control AI requests via MITM proxy. Add safety checks, modify prompts, track usage. See Hoody AI Intercept & Control.
Proxy Hooks (Worker Mode)
Section titled “Proxy Hooks (Worker Mode)”Register hoody-exec scripts as MITM handlers for any container service (terminal, files, curl, …) directly in your proxy permissions document. The Hoody Proxy dispatches matching traffic through your hook with the real client IP preserved. See Proxy Hooks.
Internal Tools (Either Mode)
Section titled “Internal Tools (Either Mode)”Admin dashboards, data migration scripts, reporting endpoints — choose worker for speed with caching or serverless for isolation and safety.
Session Management (Worker Mode)
Section titled “Session Management (Worker Mode)”Track user sessions, implement rate limiting, maintain connection pools — shared state persists across requests with zero overhead.
Development & Prototyping (Either Mode)
Section titled “Development & Prototyping (Either Mode)”Rapid iteration with magic comments, test ideas without deployment complexity, AI-generate boilerplate instantly — from idea to API in seconds.
Best Practices
Section titled “Best Practices”Choose the Right Mode
Section titled “Choose the Right Mode”Worker mode when you need state, WebSocket, or handle high request volume with caching. Serverless mode when you need isolation, process webhooks, or have sporadic traffic.
Magic Comment Strategy
Section titled “Magic Comment Strategy”Always declare @mode first, set reasonable timeouts to prevent hangs, use @cors reflective for development, enable appropriate logging level for debugging. See Magic Comments Reference.
Security Considerations
Section titled “Security Considerations”Never run untrusted code in worker mode (shared state contamination risk), deploy behind authentication for sensitive operations, use container firewall for production, validate all user input.
State Management (Worker Mode)
Section titled “State Management (Worker Mode)”Use shared object for in-memory cache only, clean up old state periodically to prevent memory leaks, understand state lost on restart, use SQLite for data that must survive restarts.
Concurrency Control (Serverless Mode)
Section titled “Concurrency Control (Serverless Mode)”Use @concurrent 5 to limit parallel executions and prevent overload, set @concurrent false for serial processing (webhooks), monitor queue depth via stats API.
Dependency Strategy
Section titled “Dependency Strategy”Let auto-install handle common packages (zero config), pin versions in production for stability via package.json if needed, test dependencies before deploying, monitor node_modules size growth.
Performance Optimization
Section titled “Performance Optimization”Use worker mode for frequently-called endpoints (zero cold start), monitor cache hit rates (should be >95%), keep scripts small and focused (under 200 lines), implement timeout limits to prevent hangs.
Useful Questions
Section titled “Useful Questions”Q: When should I use worker vs serverless mode? Use worker for WebSocket, stateful apps, high-traffic APIs, session management, rate limiting. Use serverless for webhooks, isolated tasks, untrusted code, sporadic traffic, stateless operations. See Execution Modes for the full comparison.
Q: Can serverless mode use WebSocket? No — WebSocket requires persistent connection handling in a persistent VM. Only worker mode supports WebSocket.
Q: What happens to shared state on restart?
Lost completely. shared is in-memory only. Use SQLite (hoody-sqlite service) or external database for data that must survive restarts.
Q: How does concurrency work in worker mode?
Unlimited — your code handles all concurrent requests in the same VM. Manage concurrency yourself via semaphores or queues if needed. Serverless mode uses @concurrent to limit.
Q: Can I mix worker and serverless scripts?
Yes — each script declares its own mode independently. Worker scripts at /api/ws.ts can coexist with serverless scripts at /webhooks/stripe.ts.
Q: How do magic comments work? Parsed at script load time. Configure script behavior without code changes. Validated via validation API. Take precedence over defaults. Change comment, behavior changes. See Magic Comments.
Q: Can I use TypeScript?
Yes — .ts files automatically transpiled by Bun. Full TypeScript validation available via validation endpoints. Zero config needed.
Q: How does auto-install work?
Detects require() calls, checks if module installed, runs npm install automatically, caches install status, uses latest versions (or pin in package.json).
Q: Do I need to manage a web server? No — that’s the point. You write functions in files, Hoody Exec IS the web server. No Express, no Koa, no configuration. The file system IS your routing configuration.
Troubleshooting
Section titled “Troubleshooting”Script Returns 404
Section titled “Script Returns 404”Cause: No script file matches URL path.
Solution: Check file exists at /hoody/storage/hoody-exec/scripts/1/path/to/script.ts, verify filename matches route exactly, use route validation API to test.
Magic Comments Not Working
Section titled “Magic Comments Not Working”Cause: Comments not at top of file or syntax error.
Solution: Place magic comments before ANY code (even before imports), use validation endpoint to parse comments, check exact syntax (space after //), verify comment name spelling. See Magic Comments.
Shared State Not Persisting
Section titled “Shared State Not Persisting”Cause: Using serverless mode or server restarted.
Solution: Must use // @mode worker for shared state. State is in-memory only (lost on restart). Use SQLite service for persistence. See Execution Modes.
WebSocket Connection Fails
Section titled “WebSocket Connection Fails”Cause: Missing magic comments or wrong mode.
Solution: Must have both // @mode worker AND // @websocket. Worker mode required — serverless cannot do WebSocket.
CORS Errors in Browser
Section titled “CORS Errors in Browser”Cause: Missing CORS magic comments.
Solution: Add // @cors reflective for development, // @cors * for testing, specific origin for production (// @cors https://app.com).
Script Timeout
Section titled “Script Timeout”Cause: Long-running operation exceeds timeout.
Solution: Add // @timeout 60000 to increase limit, use // @timeout 0 for unlimited (risky), optimize slow operations, consider async patterns.
Concurrent Request Limit Hit (Serverless)
Section titled “Concurrent Request Limit Hit (Serverless)”Cause: @concurrent limit reached, requests queuing.
Solution: Increase limit (// @concurrent 10), optimize script performance, consider worker mode for high traffic, monitor queue depth.
Module Not Found After Auto-Install
Section titled “Module Not Found After Auto-Install”Cause: Installation failed or network issue. Solution: Check network connectivity, verify module exists on npm, check logs for install errors, manually install if needed, check module name spelling.