{@render children?.()} t.draftConfig)} on:canceled={() => { draftTriggersModalOpen = false }} on:confirmed={handleDraftTriggersConfirmed} /> {#if !$userStore?.operator} (metadataOpen = false)} aiId="script-builder-settings" aiDescription="Script builder settings" >
{#if customUi?.settingsPanel?.disableMetadata !== true} {/if} {#if customUi?.settingsPanel?.disableRuntime !== true} {/if} {#if customUi?.settingsPanel?.disableGeneratedUi !== true && !isDbt} {#snippet extra()} The arguments are synced with the main signature but you may refine the parts that cannot be inferred from the type directly. {/snippet} {/if} {#if customUi?.settingsPanel?.disableTriggers !== true} {#snippet extra()} Configure how this script will be triggered. {/snippet} {/if} {#snippet content()}
{#snippet action()} {#if customUi?.settingsPanel?.metadata?.disableMute !== true}
{/if} {/snippet}
{#if !customUi?.settingsPanel?.metadata?.languages || customUi?.settingsPanel?.metadata?.languages?.length > 1}
{#snippet action()} {/snippet} {#if lockedLanguage}
As a forked script, the language '{script.language}' cannot be modified.
{/if}
{#each langs as [label, lang] (lang)} {@const isPicked = (lang == script.language && template != 'bunnative' && template != 'docker' && template != 'claudesandbox') || (template == 'bunnative' && lang == 'bunnative') || (template == 'docker' && lang == 'docker') || (template == 'claudesandbox' && lang == 'bun')} {#snippet text()} {label} is only available with an enterprise license {/snippet} {/each}
{/if}
Template
{#if customUi?.settingsPanel?.metadata?.disableScriptKind !== true && !isDbt}
{#snippet header()} Tag this script's purpose within flows such that it is available as the corresponding action. {/snippet} { template = 'script' script.kind = detail initContent(script.language, detail, template) }} > {#snippet children({ item })} {#each scriptKindOptions as { value, title, desc, documentationLink, Icon }} {/each} {/snippet}
{/if} {#if customUi?.settingsPanel?.disableRuntime}
{/if} {#if script.schema && !disableAi && !customUi?.settingsPanel?.metadata?.disableAiFilling}
{/if}
{#snippet header()} The script will be executed on a worker configured to listen to this worker group tag (queue). For instance, you could setup an "highmem", or "gpu" tag. {/snippet}
{#snippet header()} Allowed concurrency within a given timeframe {/snippet} { if (script.concurrent_limit && script.concurrent_limit != undefined) { script.concurrent_limit = undefined script.concurrency_time_window_s = undefined script.concurrency_key = undefined } else { script.concurrent_limit = 1 } }} options={{ right: 'Concurrency limits' }} /> {#if Boolean(script.concurrent_limit)}
{#if Boolean(script.concurrent_limit)} {/if}
{/if}
{#snippet header()} Cache the results for each possible inputs {/snippet}
!!script.cache_ttl, (v) => (script.cache_ttl = v ? 300 : undefined) } options={{ right: 'Cache the results for each possible inputs' }} /> {#if script.cache_ttl}
How long to keep the cache valid
script.cache_ignore_s3_path, (v) => (script.cache_ignore_s3_path = v || undefined) } options={{ right: 'Ignore S3 Object paths for caching purposes', rightTooltip: 'If two S3 objects passed as input have the same content, they will hit the same cache entry, regardless of their path.' }} /> {/if}
{#snippet header()} Add a custom timeout for this script {/snippet}
{ if (script.timeout && script.timeout != undefined) { script.timeout = undefined } else { script.timeout = customUi?.defaultTimeout ?? 300 } }} options={{ right: 'Add a custom timeout for this script' }} /> {#if Boolean(script.timeout)} Timeout duration {#if script.timeout} {:else} {/if} {/if}
{#snippet header()} Debounce Jobs {/snippet}
{#snippet header()} Restart the script upon ending unless cancelled {/snippet}
{ if (script.restart_unless_cancelled) { script.restart_unless_cancelled = undefined } else { script.restart_unless_cancelled = true } }} options={{ right: 'Restart upon ending unless cancelled' }} />
{ if (script.dedicated_worker) { script.dedicated_worker = undefined } else { script.dedicated_worker = true } }} options={{ right: 'Script is run on dedicated workers' }} /> {#if script.dedicated_worker}
A worker group needs to be configured to listen to this script. Select it in the dedicated workers section of the worker group configuration.
{/if} {#snippet header()} In this mode, the script is meant to be run on dedicated workers that run the script at native speed. Can reach >1500rps per dedicated worker. Only available on enterprise edition and for Python3, Deno, Bun and Bunnative. For other languages, the efficiency is already on par with dedicated workers since they do not spawn a full runtime {/snippet}
{#snippet header()} WARNING: This settings ONLY applies to synchronous webhooks or when the script is used within a flow. If used individually, this script must be triggered using a synchronous endpoint to have the desired effect.

The logs, arguments and results of the job will be completely deleted from Windmill after the specified delay once it is complete and the result has been returned. Set to 0 for immediate deletion.

The deletion is irreversible. {#if !$enterpriseLicense}

This option is only available on Windmill Enterprise Edition. {/if}
{/snippet}
{ if (script.delete_after_secs != null) { script.delete_after_secs = undefined } else { script.delete_after_secs = 0 } }} options={{ right: 'Delete logs, arguments and results after completion' }} /> {#if script.delete_after_secs != null} {/if}
{#if !isCloudHosted()}
0} on:change={() => { if (script.priority) { script.priority = undefined } else { script.priority = 100 } }} options={{ right: 'Label as high priority' }} > {#snippet right()} { if (script.priority && script.priority > 100) { script.priority = 100 } else if (script.priority && script.priority < 0) { script.priority = 0 } }} /> {/snippet} {#snippet header()} Jobs from script labeled as high priority take precedence over the other jobs when in the jobs queue. {#if !$enterpriseLicense}This is a feature only available on enterprise edition.{/if} {/snippet}
{/if}
{#snippet header()} When this option is enabled, manual executions of this script are invisible to users other than the user running it, including the owner(s). This setting can be overridden when this script is run manually from the advanced menu. {/snippet}
{ if (script.visible_to_runner_only) { script.visible_to_runner_only = undefined } else { script.visible_to_runner_only = true } }} options={{ right: 'Make runs invisible to others' }} />
{#snippet header()} When this option is enabled, the script will be run with the permissions of {canPreserve ? 'the specified user' : 'the last editor'}. {/snippet}
{ if (script.on_behalf_of_email) { script.on_behalf_of_email = undefined script.on_behalf_of = undefined preserveOnBehalfOf = false onBehalfOfChoice = undefined } else { script.on_behalf_of_email = $userStore?.email script.on_behalf_of = myPermissionedAs } }} options={{ right: `Run on behalf of ${canPreserve ? 'a specified user' : 'last editor'}` }} /> {#if script.on_behalf_of_email && canPreserve} → { onBehalfOfChoice = choice if (choice === 'me') { script.on_behalf_of_email = $userStore?.email script.on_behalf_of = myPermissionedAs customOnBehalfOfEmail = '' preserveOnBehalfOf = false } else if (choice === 'target') { // Keep the saved pair. A script that has no recorded principal yet // sends the email alone and the backend derives one from it. script.on_behalf_of_email = originalOnBehalfOfEmail script.on_behalf_of = originalOnBehalfOfPermissionedAs customOnBehalfOfEmail = '' preserveOnBehalfOf = true } else if (choice === 'custom' && details) { script.on_behalf_of_email = details.email script.on_behalf_of = details.permissionedAs customOnBehalfOfEmail = details.email preserveOnBehalfOf = true } }} kind="script" {canPreserve} customValue={customOnBehalfOfEmail} isDeployment={false} /> {:else if script.on_behalf_of_email && !canPreserve} Currently: {originalOnBehalfOfEmail ?? script.on_behalf_of_email}. Will be set to {$userStore?.email} on deploy (requires admin or wm_deployers group to override) {/if}
{#if !isCloudHosted()}
{#snippet header()} Additional static custom env variables to pass to the script. {/snippet} {#if script.envs && script.envs.length > 0} Static envs variables are not passed in preview but solely on deployed scripts. {/if}
Format is: `{'='}` {#if Array.isArray(script.envs ?? [])} {#each script.envs ?? [] as _v, i}
{#if script.envs} {/if}
{/each} {/if}
{/if}
{#if !isDbt} {/if} { captureTable?.loadCaptures(true) }} currentPath={script.path} {initialPath} {fakeInitialPath} noEditor={true} newItem={initialPath == ''} isFlow={false} {hasPreprocessor} canHavePreprocessor={canHavePreprocessor(script.language)} args={hasPreprocessor && selectedInputTab !== 'preprocessor' ? {} : args} isDeployed={savedScript && savedScript?.no_deployed !== true} schema={script.schema} runnableVersion={script.parent_hash} onDeployTrigger={handleDeployTrigger} />
{/snippet}
{#if customUi?.topBar?.path != false}
onNavigate?.(item)} />
{/if} {#if opWorkspace} {/if} {#if !condensedHeader} {@const canOpenRuntime = customUi?.topBar?.settings != false && customUi?.settingsPanel?.disableRuntime !== true} { selectedTab = 'runtime' metadataOpen = true } : undefined} /> {/if}
{#if $enterpriseLicense && initialPath != '' && !inSessionPane} {/if}
{#snippet settingsButton()} {#if customUi?.topBar?.settings != false} {/if} {/snippet} {#snippet diffButton()} {#if customUi?.topBar?.diff != false} {@const isDraftOnly = savedScript?.no_deployed === true} {@const diffDisabled = !savedScript || !diffDrawer || isDraftOnly} {@const diffTitle = isDraftOnly ? 'Deploy this script once to compare against the deployed version' : 'Diff'}
{/if} {/snippet} {#if compactTopbar} {#snippet buttonReplacement()}
{#if showPipelineHint}
This script can become a data pipeline step: annotate it with -- pipeline and -- materialize to materialize its result, or build it in the pipeline editor. Learn more
{/if} {#if isDbt} saveDraft()} on:saveDraft={() => saveDraft()} bind:editor bind:this={scriptEditor} bind:schema={script.schema} path={script.path} bind:code={script.content} timeout={script.timeout} tag={script.tag} deployedHash={deployedScriptHash} bind:args bind:modules={script.modules} /> {:else} { saveDraft() }} on:saveDraft={() => { saveDraft() }} on:openTriggers={openTriggers} on:applyArgs={applyArgs} on:addPreprocessor={addPreprocessor} bind:editor bind:this={scriptEditor} bind:schema={script.schema} path={script.path} stablePathForCaptures={initialPath || fakeInitialPath} bind:code={script.content} lang={script.language} timeout={script.timeout} kind={script.kind} autoKind={script.auto_kind} {template} tag={script.tag} lastSavedCode={savedScript?.content} lastDeployedCode={savedScript?.content} bind:args bind:hasPreprocessor bind:captureTable bind:assets={script.assets} bind:modules={script.modules} enablePreprocessorSnippet {testPanelCollapsed} /> {/if}
{:else} Script Builder not available to operators {/if}

A dbt script is a whole dbt project: the files are the script's module bundle, the content is a wm_dbt.yaml descriptor, and the models become dbt:// assets in the graph.

Expect rough edges, and expect details to move: the descriptor's fields, what a run returns, and how the graph is stored are all still settling.

Deploying and running work today, and an existing project needs no changes — cp -r it into the script's folder and push. Nothing here is load-bearing for other languages.

Docs · report anything surprising, it is the most useful thing at this stage.