Skip to content
Hoody.com

Use these endpoints to discover, read, write, organize, and inspect scripts on a Hoody container. Scripts live under /hoody/storage/hoody-exec/scripts inside the container. A path you send in a request is normally relative to the host’s instance namespace (for example, deploy.ts or jobs/clean.ts); the service adds the scope prefix. A path it returns in a response, such as resolvedPath, resolvedFrom, or resolvedTo, is relative to the scripts root, with the scope prefix attached (for example, default/1/deploy.ts). The scope prefix has the form <subdomain>/<execId>, where subdomain is the literal default whenever the request host carries no subdomain.

All script endpoints below live on the same per-container hostname:

https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com

List the exec ids known to this container, with per-id file counts and a breakdown of SDK versus custom ids.

This endpoint takes no parameters.

Terminal window
curl -X GET "https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com/api/v1/exec/list" \
-H "Authorization: Bearer <token>"

Magic comments are the leading @directive value lines at the top of a script that configure execution. The endpoints below let you read the schema, read a single script’s directives, update a single script, and bulk-update every script in a directory.

Read the parsed magic comments from a script. Tokens are redacted.

NameInTypeRequiredDescription
pathquerystringYesPath query parameter
execIdquerystringNoOptional execution scope. When provided, relative paths resolve under default/{execId}/ unless subdomain is also set. Query value takes precedence over body. Lowercase alphanumeric, no hyphens — the -exec- part of a hostname cannot carry one, so a hyphenated execId names a tree no request could route to and is rejected with 400.
exec_idquerystringNoAlias for execId (snake_case). Lowercase alphanumeric, no hyphens — the -exec- part of a hostname cannot carry one, so a hyphenated execId names a tree no request could route to and is rejected with 400.
subdomainquerystringNoOptional subdomain namespace used with execId for path resolution.
Terminal window
curl -X GET "https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com/api/v1/exec/magic-comments/read?path=deploy.ts" \
-H "Authorization: Bearer <token>"

Return the canonical magic-comments schema: categories, fields, and defaults.

This endpoint takes no parameters.

Terminal window
curl -X GET "https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com/api/v1/exec/magic-comments/schema" \
-H "Authorization: Bearer <token>"

Set directives on a single script. Keys that are not directives are ignored. Directives not named are left as they are. A value of null removes the directive.

NameInTypeRequiredDescription
execIdquerystringNoOptional execution scope. When provided, relative paths resolve under default/{execId}/ unless subdomain is also set. Query value takes precedence over body. Lowercase alphanumeric, no hyphens — the -exec- part of a hostname cannot carry one, so a hyphenated execId names a tree no request could route to and is rejected with 400.
exec_idquerystringNoAlias for execId (snake_case). Lowercase alphanumeric, no hyphens — the -exec- part of a hostname cannot carry one, so a hyphenated execId names a tree no request could route to and is rejected with 400.
subdomainquerystringNoOptional subdomain namespace used with execId for path resolution.
FieldTypeRequiredDefaultDescription
pathstringYesScript to edit, relative to the scripts directory.
commentsobjectYesDirectives to set, keyed by directive name.
comments.enabledbooleanNoEnable or disable script execution.
comments.tokenstring | array<string>NoShared secret token for endpoint authentication. A string sets one token; an array of up to 16 different tokens sets the whole list.
comments.modestringNoExecution model for the script. One of: worker, serverless.
comments.timeoutinteger | stringNoScript timeout. Bare number is milliseconds; suffix (ms, s, m, h, d) honoured.
comments.log-levelstringNoLogging verbosity. One of: none, minimal, standard, full, debug.
comments.debugbooleanNoShortcut to set log level to debug.
comments.log-request-bodyboolean | stringNoInclude request body in logs. Boolean shorthand or full | redacted | off.
comments.log-response-bodyboolean | stringNoInclude response body in logs. Boolean shorthand or full | redacted | off.
comments.log-max-body-sizeinteger | stringNoMaximum body size to retain in logs.
comments.log-exclude-headersarrayNoHeaders to redact from logs.
comments.log-retention-daysintegerNoLog retention window in days (0 to 3650).
comments.debug-instrumentbooleanNoEnable runtime debug instrumentation.
comments.await-promisesbooleanNoNo effect: a returned promise is always awaited and its resolved value is the response. Accepted so existing scripts keep working.
comments.concurrentboolean | integerNoConcurrency policy: true, false, or a max concurrency integer.
comments.corsstringNoCORS origin strategy. none (or null) writes @cors none; empty removes the directive.
comments.cors-credentialsbooleanNoEnable CORS credentials.
comments.cors-methodsstringNoComma-separated CORS allowed methods.
comments.cors-headersstringNoComma-separated CORS allowed headers.
comments.cors-max-ageintegerNoCORS preflight max-age in seconds.
comments.websocketbooleanNoEnable WebSocket mode for the script.
comments.aibooleanNoEnable or disable AI helpers.
comments.ai-modelstringNoOverride default AI model identifier.
comments.ai-temperaturenumberNoAI temperature between 0 and 2. Send 0 or a number from 0.000001 to 2.
comments.ai-max-tokensintegerNoMaximum AI output tokens.
comments.ai-keystringNoOverride AI API key for the script.
comments.descriptionstringNoHuman-readable description for the script.
comments.tagsarrayNoTags used for grouping and filtering.
comments.labelstringNoShort label used for classification or filtering.
comments.schedulestringNoCron expression or Bun nickname. UTC only.
comments.schedule-timeoutinteger | stringNoPer-fire wall-clock timeout.
dry_runbooleanNofalseWhen true, the file is not written.
Terminal window
curl -X PUT "https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com/api/v1/exec/magic-comments/update" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"path": "deploy.ts",
"comments": {
"enabled": true,
"timeout": "90s",
"log-level": "standard"
}
}'

POST /api/v1/exec/magic-comments/bulk-update

Section titled “POST /api/v1/exec/magic-comments/bulk-update”

Set the same directives on every script in a directory. With dry_run: true, the response lists every matching file under would_affect with its current and proposed comments. With dry_run: false, the change is applied to every matching file and the response still succeeds when some fail: check results.failed before assuming every file changed.

FieldTypeRequiredDefaultDescription
directorystringNoDirectory to edit, relative to the scripts directory. Ignored when execId is given.
execIdstringNoEdits default/<execId> (or <subdomain>/<execId> when taken from the Host).
commentsobjectYesDirectives to set, keyed by directive name.
comments.enabledbooleanNoEnable or disable script execution.
comments.tokenstring | array<string>NoShared secret token for endpoint authentication. A string sets one token; an array of up to 16 different tokens sets the whole list.
comments.modestringNoExecution model for the script. One of: worker, serverless.
comments.timeoutinteger | stringNoScript timeout.
comments.log-levelstringNoLogging verbosity. One of: none, minimal, standard, full, debug.
comments.debugbooleanNoShortcut to set log level to debug.
comments.log-request-bodyboolean | stringNoInclude request body in logs.
comments.log-response-bodyboolean | stringNoInclude response body in logs.
comments.log-max-body-sizeinteger | stringNoMaximum body size to retain in logs.
comments.log-exclude-headersarrayNoHeaders to redact from logs.
comments.log-retention-daysintegerNoLog retention window in days (0 to 3650).
comments.debug-instrumentbooleanNoEnable runtime debug instrumentation.
comments.await-promisesbooleanNoNo effect: a returned promise is always awaited and its resolved value is the response. Accepted so existing scripts keep working.
comments.concurrentboolean | integerNoConcurrency policy: true, false, or a max concurrency integer.
comments.corsstringNoCORS origin strategy.
comments.cors-credentialsbooleanNoEnable CORS credentials.
comments.cors-methodsstringNoComma-separated CORS allowed methods.
comments.cors-headersstringNoComma-separated CORS allowed headers.
comments.cors-max-ageintegerNoCORS preflight max-age in seconds.
comments.websocketbooleanNoEnable WebSocket mode for the script.
comments.aibooleanNoEnable or disable AI helpers.
comments.ai-modelstringNoOverride default AI model identifier.
comments.ai-temperaturenumberNoAI temperature between 0 and 2.
comments.ai-max-tokensintegerNoMaximum AI output tokens.
comments.ai-keystringNoOverride AI API key for the script.
comments.descriptionstringNoHuman-readable description for the script.
comments.tagsarrayNoTags used for grouping and filtering.
comments.labelstringNoShort label used for classification or filtering.
comments.schedulestringNoCron expression or Bun nickname. UTC only.
comments.schedule-timeoutinteger | stringNoPer-fire wall-clock timeout.
extensionstringNo".ts"File extension to match.
recursivebooleanNotrueRecurse into subdirectories.
dry_runbooleanNofalseWhen true, no file is written.
Terminal window
curl -X POST "https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com/api/v1/exec/magic-comments/bulk-update" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"execId": "1",
"comments": {
"log-level": "standard",
"timeout": "60s"
},
"dry_run": false
}'

Read, write, move, delete, list, and traverse scripts. Every path on this section follows the path conventions in the page introduction: the path a caller sends is instance-relative; paths returned in responses are scripts-root-relative with the scope prefix attached.

List scripts and directories under a directory. Supports optional filters and recursion.

NameInTypeRequiredDescription
dirquerystringNoDirectory to list, relative to the scripts directory.
filterquerystringNoSubstring filter on file names.
metadataquerystringNoMetadata filter.
labelquerystringNoLabel filter.
tagsquerystringNoTag filter.
modequerystringNoMode filter.
enabledquerystringNoEnabled filter.
websocketquerystringNoWebSocket filter.
remotequerystringNoKeep only scripts by their remote operations: any (at least one of @remote-messages, @remote-call, @remote-eval is on), none (all off), or messages / call / eval (that one is on). Lists recursively and adds each script’s magicComments and remote summary, like the other filters. Any other value is refused with 400.
recursivequerystringNoRecurse into subdirectories.
include_commentsquerystringNoInclude magic comments in the response.
exhaustivequerybooleanNoWhen true, list every entry below dir recursively with its type (file, directory, symlink, fifo, socket, block-device, character-device, unknown), in entries instead of scripts. Nothing is hidden (dot-files, node_modules, .git, .hoody-cache, _sdk, _hoody) and no symlink is followed. Combine only with dir, execId and subdomain (other options are refused with 400). The answer is complete or an error, never partial: more than 10000 entries is 422 with details.code TOO_MANY_ENTRIES; a name or link target that is not valid UTF-8 is 422 with details.code NAME_NOT_UTF8 (details.parent, and the raw name as details.nameHex); an entry or directory that disappears or is replaced during the scan, or a directory whose dev, inode, mtime or ctime changed after it was read (checked once the scan is done), restarts it, and a tree still changing after 3 restarts is 409 with details.code TREE_CHANGED. This is best effort, for a tree nobody mutates concurrently: a change undone within one timestamp tick, or on a filesystem without fine timestamps, can go unseen.
execIdquerystringNoOptional execution scope. When provided, relative paths resolve under default/{execId}/ unless subdomain is also set.
exec_idquerystringNoAlias for execId (snake_case).
subdomainquerystringNoOptional subdomain namespace used with execId for path resolution.
Terminal window
curl -X GET "https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com/api/v1/exec/scripts/list?dir=&recursive=true" \
-H "Authorization: Bearer <token>"

Read the contents of a script along with its magic comments and filesystem metadata.

NameInTypeRequiredDescription
pathquerystringYesScript to read, instance-relative.
execIdquerystringNoOptional execution scope. When provided, relative paths resolve under default/{execId}/ unless subdomain is also set.
exec_idquerystringNoAlias for execId (snake_case).
subdomainquerystringNoOptional subdomain namespace used with execId for path resolution.
Terminal window
curl -X GET "https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com/api/v1/exec/scripts/read?path=deploy.ts" \
-H "Authorization: Bearer <token>"

Create or replace a script. By default, parent directories are created and the script is validated before it is written.

NameInTypeRequiredDescription
execIdquerystringNoOptional execution scope. When provided, relative paths resolve under default/{execId}/ unless subdomain is also set.
exec_idquerystringNoAlias for execId (snake_case).
subdomainquerystringNoOptional subdomain namespace used with execId for path resolution.
FieldTypeRequiredDefaultDescription
pathstringYesPath of the script to write.
contentstringYesScript contents.
createDirsbooleanNotrueCreate parent directories if they do not exist.
validatebooleanNotrueValidate the script before writing.
ifNotExistsbooleanNofalseCreate only. When true, do not replace an existing file. With the name already taken the answer is 409 and nothing is written; otherwise the new file is created as one atomic step.
typecheckbooleanNofalseWhen true, also type-check the script with the TypeScript compiler against the hoody-sdk declarations. A type error refuses the write with 400.
execIdstringNoOptional execution scope in request body. Query execId/exec_id takes precedence when both are provided.
exec_idstringNoAlias for execId (snake_case).
subdomainstringNoOptional subdomain namespace used with execId for path resolution.
Terminal window
curl -X POST "https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com/api/v1/exec/scripts/write" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"path": "jobs/clean.ts",
"content": "// @enabled true\nexport default async function() { return { ok: true }; }\n"
}'

Move a script to a new path. By default, the move fails with 409 when the destination already exists; pass overwrite: true to replace it. The 409 status is also returned when the source is missing under some conditions; the 404 status covers a missing source in the general case.

NameInTypeRequiredDescription
execIdquerystringNoOptional execution scope. When provided, relative paths resolve under default/{execId}/ unless subdomain is also set.
exec_idquerystringNoAlias for execId (snake_case).
subdomainquerystringNoOptional subdomain namespace used with execId for path resolution.
FieldTypeRequiredDefaultDescription
fromstringYesSource path.
tostringYesDestination path.
overwritebooleanNofalseReplace the destination if it already exists.
execIdstringNoOptional execution scope in request body.
exec_idstringNoAlias for execId (snake_case).
subdomainstringNoOptional subdomain namespace used with execId for path resolution.
Terminal window
curl -X POST "https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com/api/v1/exec/scripts/move" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"from": "deploy.ts",
"to": "jobs/deploy.ts",
"overwrite": false
}'

Delete a script. A safety confirmation is required.

NameInTypeRequiredDescription
pathquerystringYesScript to delete.
confirmquerystringYesSafety confirmation. Must be the literal true.
execIdquerystringNoOptional execution scope.
exec_idquerystringNoAlias for execId (snake_case).
subdomainquerystringNoOptional subdomain namespace used with execId for path resolution.
Terminal window
curl -X DELETE "https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com/api/v1/exec/scripts/delete?path=jobs%2Fclean.ts&confirm=true" \
-H "Authorization: Bearer <token>"

Return a directory tree rooted at a base directory. Use includeMetadata to enrich each node with file metadata.

NameInTypeRequiredDescription
execIdquerystringNoOptional execution scope. When provided, relative paths resolve under default/{execId}/ unless subdomain is also set.
exec_idquerystringNoAlias for execId (snake_case).
subdomainquerystringNoOptional subdomain namespace used with execId for path resolution.
FieldTypeRequiredDefaultDescription
baseDirstringNo""Directory to use as the tree root, relative to the scripts directory.
maxDepthintegerNo10Maximum depth to traverse.
includeMetadatabooleanNofalseInclude file metadata on each node.
execIdstringNoOptional execution scope in request body.
exec_idstringNoAlias for execId (snake_case).
subdomainstringNoOptional subdomain namespace used with execId for path resolution.
Terminal window
curl -X POST "https://{projectId}-{containerId}-exec-1.{server}.containers.hoody.com/api/v1/exec/scripts/tree" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"baseDir": "",
"maxDepth": 5,
"includeMetadata": false
}'