PageSourceSearch

https://www.windmill.dev/assets/js/7e3dceb8.b2bd52c6.js

js windmill.dev collected 2026-09-24 19:08:29 UTC 87,116 bytes, 2 lines download raw bytes

1(self.webpackChunkwindmilldocs=self.webpackChunkwindmilldocs||[]).push([["19109"],{61399(e,s,t){"use strict";t.r(s),t.d(s,{metadata:()=>n,default:()=>u,frontMatter:()=>o,contentTitle:()=>l,toc:()=>c,assets:()=>d});var n=JSON.parse('{"id":"advanced/instance_settings/index","title":"Instance settings","description":"How do I configure Windmill instance settings as a superadmin?","source":"@site/docs/advanced/18_instance_settings/index.mdx","sourceDirName":"advanced/18_instance_settings","slug":"/advanced/instance_settings/","permalink":"/docs/advanced/instance_settings/","draft":false,"unlisted":false,"tags":[],"version":"current","frontMatter":{"description":"How do I configure Windmill instance settings as a superadmin?"},"sidebar":"tutorialSidebar","previous":{"title":"Self-host","permalink":"/docs/advanced/self_host/"},"next":{"title":"Setup OAuth and SSO","permalink":"/docs/advanced/setup_oauth/"}}'),i=t(74848),r=t(28453),a=t(78410);t(50773),t(57250);let o={description:"How do I configure Windmill instance settings as a superadmin?"},l="Instance settings",d={},c=[{value:"Admins workspace",id:"admins-workspace",level:2},{value:"Global users",id:"global-users",level:2},{value:"Guests",id:"guests",level:2},{value:"Core",id:"core",level:2},{value:"Base url",id:"base-url",level:3},{value:"WebSocket base url",id:"websocket-base-url",level:3},{value:"Email domain",id:"email-domain",level:3},{value:"Request size limit in MB",id:"request-size-limit-in-mb",level:3},{value:"Default timeout",id:"default-timeout",level:3},{value:"Max timeout for sync endpoints",id:"max-timeout-for-sync-endpoints",level:3},{value:"Keep job directories for debug",id:"keep-job-directories-for-debug",level:3},{value:"License key",id:"license-key",level:3},{value:"Non-prod instance",id:"non-prod-instance",level:3},{value:"HTTP route default allowed origins",id:"http-route-default-allowed-origins",level:3},{value:"Retention period in secs",id:"retention-period-in-secs",level:3},{value:"Per-workspace retention overrides",id:"per-workspace-retention-overrides",level:3},{value:"Audit log retention (days)",id:"audit-log-retention-days",level:3},{value:"Maximum token expiration (days)",id:"maximum-token-expiration-days",level:3},{value:"Disable token in MCP URLs",id:"disable-token-in-mcp-urls",level:3},{value:"Instance object storage",id:"instance-object-storage",level:3},{value:"S3",id:"s3",level:4},{value:"Azure Blob",id:"azure-blob",level:4},{value:"AWS OIDC",id:"aws-oidc",level:4},{value:"Google Cloud Storage",id:"google-cloud-storage",level:4},{value:"Store audit logs in object storage",id:"store-audit-logs-in-object-storage",level:3},{value:"Auto-build binaries on deployment",id:"auto-build-binaries-on-deployment",level:3},{value:"Private Hub base url",id:"private-hub-base-url",level:3},{value:"Private hub api secret",id:"private-hub-api-secret",level:3},{value:"Disable hub",id:"disable-hub",level:3},{value:"Auth/OAuth",id:"authoauth",level:2},{value:"Single Sign On (SSO)",id:"single-sign-on-sso",level:3},{value:"SSO groups claim",id:"sso-groups-claim",level:4},{value:"OAuth",id:"oauth",level:3},{value:"SCIM/SAML",id:"scimsaml",level:3},{value:"SCIM token",id:"scim-token",level:4},{value:"SAML metadata",id:"saml-metadata",level:4},{value:"Registries",id:"registries",level:2},{value:"UV index url",id:"uv-index-url",level:3},{value:"UV extra index url",id:"uv-extra-index-url",level:3},{value:"Npm config registry",id:"npm-config-registry",level:3},{value:"Bunfig install scopes",id:"bunfig-install-scopes",level:3},{value:"<code>.npmrc</code>",id:"npmrc",level:3},{value:"Maven <code>settings.xml</code>",id:"maven-settingsxml",level:3},{value:"Cargo registries",id:"cargo-registries",level:3},{value:"Nuget config",id:"nuget-config",level:3},{value:"Workspace-specific registry overrides",id:"workspace-specific-registry-overrides",level:3},{value:"Docker registries",id:"docker-registries",level:3},{value:"Alerts",id:"alerts",level:2},{value:"Critical alert channels",id:"critical-alert-channels",level:3},{value:"Mute critical alerts in UI",id:"mute-critical-alerts-in-ui",level:3},{value:"Alert on token expiry",id:"alert-on-token-expiry",level:3},{value:"Mute zombie job restart alerts",id:"mute-zombie-job-restart-alerts",level:3},{value:"Slack",id:"slack",level:3},{value:"SMTP",id:"smtp",level:3},{value:"Set up auto-invites",id:"set-up-auto-invites",level:3},{value:"Webhooks",id:"webhooks",level:2},{value:"Instance events webhook",id:"instance-events-webhook",level:3},{value:"AI",id:"ai",level:2},{value:"AI_HTTP_HEADERS",id:"ai_http_headers",level:3},{value:"Open Telemetry &amp; Prometheus",id:"open-telemetry--prometheus",level:2},{value:"OpenTelemetry (OTEL)",id:"opentelemetry-otel",level:3},{value:"HTTP tracing",id:"http-tracing",level:3}
1,{value:"HTTP request tracing retention in secs",id:"http-request-tracing-retention-in-secs",level:3},{value:"Prometheus",id:"prometheus",level:3},{value:"Indexer",id:"indexer",level:2},{value:"Max index time window",id:"max-index-time-window",level:3},{value:"Index writer memory budget",id:"index-writer-memory-budget",level:3},{value:"Commit max batch size",id:"commit-max-batch-size",level:3},{value:"Refresh index period",id:"refresh-index-period",level:3},{value:"Max indexed job log size",id:"max-indexed-job-log-size",level:3},{value:"Commit max batch size",id:"commit-max-batch-size-1",level:3},{value:"Refresh index period",id:"refresh-index-period-1",level:3},{value:"Telemetry",id:"telemetry",level:2},{value:"Community Edition",id:"community-edition",level:3},{value:"Enterprise Edition",id:"enterprise-edition",level:3},{value:"GitHub App",id:"github-app",level:2},{value:"Webhook base url",id:"webhook-base-url",level:3},{value:"DB Health",id:"db-health",level:2},{value:"Diagnostics",id:"diagnostics",level:3},{value:"Scan limit",id:"scan-limit",level:3}];function h(e){let s={a:"a",admonition:"admonition",blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",img:"img",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,r.R)(),...e.components},{Details:n}=s;return n||function(e,s){throw Error("Expected "+(s?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(s.header,{children:(0,i.jsx)(s.h1,{id:"instance-settings",children:"Instance settings"})}),"\n",(0,i.jsxs)(s.p,{children:["Instance settings are accessible to all ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/roles_and_permissions/#superadmin",children:"superadmins"})," of your Windmill instance. This is where you manage settings and features across all workspaces. One instance can have several workspaces."]}),"\n",(0,i.jsxs)(s.p,{children:["This is from the Instance settings that you can see on which Windmill ",(0,i.jsx)(s.a,{href:"https://github.com/windmill-labs/windmill/releases",children:"version"})," your instance is running."]}),"\n",(0,i.jsx)(s.p,{children:(0,i.jsx)(s.img,{alt:"Instance version",src:t(45119).A+"",title:"Instance version",width:"1224",height:"450"})}),"\n",(0,i.jsx)(s.h2,{id:"admins-workspace",children:"Admins workspace"}),"\n",(0,i.jsxs)(s.p,{children:["The Admins workspace is for ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/roles_and_permissions/#superadmin",children:"superadmins"})," only and contains scripts whose purpose is to manage your Windmill instance, such as ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/resources_and_types/#sync-resource-types-with-windmillhub",children:"keeping resource types up to date"})," or the New User Setup App."]}),"\n",(0,i.jsxs)(s.p,{children:["The ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/resources_and_types/",children:"resources types"})," created from the Admins workspace are shared across all workspaces."]}),"\n",(0,i.jsx)(s.p,{children:"You can access it from the list of workspaces or from Instance settings."}),"\n",(0,i.jsx)(s.p,{children:(0,i.jsx)(s.img,{alt:"Admins workspace",src:t(69201).A+"",title:"Admins workspace",width:"2880",height:"1800"})}),"\n",(0,i.jsx)(s.h2,{id:"global-users",children:"Global users"}),"\n",(0,i.jsx)(s.p,{children:"Global Users are users of the Windmill instance. They are not associated with any workspace and can be assigned to any workspace (from the workspace settings)."}),"\n",(0,i.jsxs)(s.p,{children:["From there you can manually add a user to the instance, giving an email and a password. Users can be set to User, ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/roles_and_permissions/#devops",children:"Devops"})," or Superadmin ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/roles_and_permissions/#superadmin",children:"roles"}),"."]}),"\n",(0,i.jsxs)(s.p,{children:["When a user's role is set by an ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/groups_and_folders/#instance-level-roles",children:"instance group"}),', a "Set by instance group" indicator appears next to the role toggle. You can still upgrade a user to a higher role manually (e.g. from group-assigned devops to superadmin), but demoting to "User" requires removing the user from the instance group. See ',(0,i.jsx)(s.a,{href:"/docs/core_concepts/roles_and_permissions/#instance-level-roles-via-instance-groups",children:"instance-level roles via instance groups"})," for details."]}),"\n",(0,i.jsxs)(s.p,{children:["Automatic username creation derives a stable, instance-wide username from each user's email, shared across workspaces. It is enabled by default and avoids duplicated usernames; only very old legacy instances may still have it disabled. ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/roles_and_permissions/#superadmin",children:"Superadmins"})," acting in workspaces they are not members of are identified by this derived username instead of their email (in job metadata, audit logs, drafts and the UI); their email is still preserved internally."]}),"\n",(0,i.jsxs)(s.p,{children:["A more common way to add users is to use ",(0,i.jsx)(s.a,{href:"#authoauth",children:"SSO/OAuth"}),"."]}),"\n",(0,i.jsxs)(s.p,{children:["For each user, you can see Email, Auth (manually-set password or Auth methods), Name, Kind (",(0,i.jsx)(s.a,{href:"/docs/core_concepts/roles_and_permissions/#developer",children:"Developer"})," or ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/roles_and_permissions/#operator",children:"Operator"})," where an operator at the instance level is an operator in all workspaces they are members of), and Role (User or ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/roles_and_permissions/#superadmin",children:"Superadmin"}),")."]}),"\n",(0,i.jsxs)(s.p,{children:["You can also toggle on 'Recently active only' to only show users who have performed at least one action in the last 30 days. Only those users are counted in our ",(0,i.jsx)(s.a,{href:"/pricing",children:"Pricing"}
1),". When enabled, the table also displays each user's Kind (Developer or Operator), reflecting their highest permission level across all workspaces they belong to."]}),"\n",(0,i.jsx)(s.p,{children:(0,i.jsx)(s.img,{alt:"Global Users",src:t(65591).A+"",title:"Global Users",width:"3020",height:"1674"})}),"\n",(0,i.jsx)(s.h2,{id:"guests",children:"Guests"}),"\n",(0,i.jsxs)(s.p,{children:["The Guests tab, next to Users, lists the ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/roles_and_permissions/#guests",children:"guests"})," of the trailing 30 days: people who opened an app set to Guests without a Windmill account, whether they signed in through the identity provider or came in on a ",(0,i.jsx)(s.a,{href:"/docs/apps/guest_apps/#guest-jwt-for-embedded-apps",children:"guest JWT"}),".\nFor each one you see their email, the workspaces they opened and when they were first and last seen.\nOne email is one guest, however many workspaces they opened."]}),"\n",(0,i.jsx)(s.p,{children:"Above the list, 'Allow guests on this instance' is the superadmin switch every workspace switch sits under.\nTurned off, no guest can sign in anywhere on the instance whatever a workspace or an app says, apps stop offering a guest sign-in, and sessions already issued stop on their next request."}),"\n",(0,i.jsxs)(s.p,{children:["The tab also reports the instance's standing against the guest allowance: the first 100 distinct guest emails over 30 days are free, and past that an instance holding an ",(0,i.jsx)(s.a,{href:"/pricing",children:"Enterprise Edition"})," license meters them at four guests to one seat while an instance without one admits no new guest email until the count drops back under 100."]}),"\n",(0,i.jsx)("div",{className:"grid grid-cols-2 gap-6 mb-4",children:(0,i.jsx)(a.A,{title:"Guest apps",description:"Let people open an app without a Windmill account and without a seat, through a sign-in or a JWT your backend signs.",href:"/docs/apps/guest_apps"})}),"\n",(0,i.jsx)(s.h2,{id:"core",children:"Core"}),"\n",(0,i.jsx)(s.p,{children:(0,i.jsx)(s.img,{alt:"Core settings",src:t(18888).A+"",title:"Core settings",width:"3016",height:"1678"})}),"\n",(0,i.jsx)(s.h3,{id:"base-url",children:"Base url"}),"\n",(0,i.jsx)(s.p,{children:"The base URL is the public base url of the instance."}),"\n",(0,i.jsxs)(s.p,{children:["If the base URL is not set correctly, some server-side generated URLs like resume URLs will be incorrect. Additionally, ",(0,i.jsx)(s.a,{href:"#authoauth",children:"OAuth and SSO"})," functionalities will not work properly."]}),"\n",(0,i.jsx)(s.h3,{id:"websocket-base-url",children:"WebSocket base url"}),"\n",(0,i.jsxs)(s.p,{children:["Optional override for the base URL used by the frontend to open WebSocket connections to the LSP, debugger, and multiplayer services. When empty, WebSocket connections fall back to the current ",(0,i.jsx)(s.code,{children:"window.location"})," (same host as the page)."]}),"\n",(0,i.jsxs)(s.p,{children:["Set this when the browser cannot reach WebSocket services on the same host as the main app \u2014 for example, when WebSocket services are exposed under a dedicated subdomain (e.g. ",(0,i.jsx)(s.code,{children:"wss://ws.example.com"}),"). The value is used as a prefix for all frontend WebSocket connections (LSP, debugger, multiplayer)."]}),"\n",(0,i.jsx)(s.p,{children:'A "Test connectivity" button runs HTTP health and WebSocket ping checks for the three services in parallel and reports per-service results inline.'}),"\n",(0,i.jsx)(s.h3,{id:"email-domain",children:"Email domain"}),"\n",(0,i.jsxs)(s.p,{children:["Domain to display in webhooks for ",(0,i.jsx)(s.a,{href:"/docs/triggers/email_triggers/",children:"email triggers"})," (should match the ",(0,i.jsx)(s.a,{href:"https://www.cloudflare.com/learning/dns/dns-records/dns-mx-record/",children:"MX record"}),")."]}),"\n",(0,i.jsx)(s.h3,{id:"request-size-limit-in-mb",children:"Request size limit in MB"}),"\n",(0,i.jsx)(s.p,{children:"Maximum size of HTTP requests in MB. Cloud only."}),"\n",(0,i.jsx)(s.h3,{id:"default-timeout",children:"Default timeout"}),"\n",(0,i.jsxs)(s.p,{children:["Default timeout for individual ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/jobs/#retention-policy",children:"jobs"}),", in seconds."]}),"\n",(0,i.jsx)(s.p,{children:"You will find a helper to convert days, hours, minutes, and seconds to seconds."}),"\n",(0,i.jsxs)(s.p,{children:["Note that you can set a ",(0,i.jsx)(s.a,{href:"/docs/flows/custom_timeout",children:"custom timeout for flow steps"}),"."]}),"\n",(0,i.jsx)(s.h3,{id:"max-timeout-for-sync-endpoints",children:"Max timeout for sync endpoints"}),"\n",(0,i.jsxs)(s.p,{children:["Maximum amount of time (measured in seconds) that a ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/webhooks/",children:"sync endpoint"})," is allowed to run before it is forcibly stopped or timed out."]}),"\n",(0,i.jsx)(s.p,{children:"You will find a helper to convert days, hours, minutes, and seconds to seconds."}),"\n",(0,i.jsx)(s.h3,{id:"keep-job-directories-for-debug",children:"Keep job directories for debug"}),"\n",(0,i.jsxs)(s.p,{children:["Toggle to keep Job directories after execution at ",(0,i.jsx)(s.code,{children:"/tmp/windmill/<worker>/<job_id>"}),"."]}),"\n",(0,i.jsx)(s.h3,{id:"license-key",children:"License key"}),"\n",(0,i.jsxs)(s.p,{children:["The license key is used to enable ",(0,i.jsx)(s.a,{href:"/pricing",children:"Enterprise Edition"}),". You can get one by starting a free trial from the ",(0,i.jsx)(s.a,{href:"/pricing",children:"pricing page"})," or by contacting us at ",(0,i.jsx)(s.a,{href:"mailto:[email protected]",children:"[email protected]"})]}),"\n",(0,i.jsxs)(s.p,{children:["To see how to upgrade your instance to Enterprise Edition, see the ",(0,i.jsx)(s.a,{href:"/docs/enterprise/plans_details/#self-host",children:"Upgrade to Enterprise Edition"})," docs.\nA same key can also be used for non-prod instances. Just make sure to set the ",(0,i.jsx)(s.a,{href:"#non-prod-instance",children:(0,i.jsx)(s.code,{children:"Non-
1prod instance"})})," to true so that the computation usage is not counted in the billing."]}),"\n",(0,i.jsx)(s.p,{children:"From there you also have two buttons:"}),"\n",(0,i.jsxs)(s.ul,{children:["\n",(0,i.jsxs)(s.li,{children:[(0,i.jsx)(s.code,{children:"Renew key"}),": to renew the license key (as long as you have a valid subscription). Anyway, the key is automatically renewed everyday as long as your subscription is valid."]}),"\n",(0,i.jsxs)(s.li,{children:[(0,i.jsx)(s.code,{children:"Open customer portal"}),": the recommended way to access the ",(0,i.jsx)(s.a,{href:"/docs/enterprise/plans_details/#windmill-customer-portal",children:"Customer portal"})," where you can manage your subscription."]}),"\n"]}),"\n",(0,i.jsx)(s.p,{children:"If your subscription is active, the key is automatically renewed everyday. A key is typically valid for 35 days."}),"\n",(0,i.jsxs)(s.p,{children:["On ",(0,i.jsx)(s.a,{href:"/docs/enterprise/onboarding/#air-gapped-environments",children:"air-gapped"})," instances running an offline license key, this field also shows live usage against the caps embedded in the key (",(0,i.jsx)(s.code,{children:"Seats: x / y"})," and ",(0,i.jsx)(s.code,{children:"CUs: x / y"}),"). Exceeding either cap invalidates the license and halts jobs until usage drops back under cap. See ",(0,i.jsx)(s.a,{href:"/docs/enterprise/onboarding/#air-gapped-environments",children:"air-gapped environments"})," for details."]}),"\n",(0,i.jsx)(s.h3,{id:"non-prod-instance",children:"Non-prod instance"}),"\n",(0,i.jsx)(s.p,{children:"Whether we should consider the reported usage of this instance as non-prod."}),"\n",(0,i.jsxs)(s.p,{children:["Non-prod instances work the same as prod instances in terms of features, but their ",(0,i.jsx)(s.a,{href:"/pricing",children:"computation usage"})," is not counted in the billing. Seats count, however, are across all instances. If all instances using the same key are 'Non-prod', the one using most Compute Units will be counted as Prod."]}),"\n",(0,i.jsxs)(s.p,{children:["Alternatively, you can copy a development license key using the dedicated button from the ",(0,i.jsx)(s.a,{href:"/docs/enterprise/plans_details/#windmill-customer-portal",children:"Customer portal"}),". This provides an alternative to manually turning instances to Non-prod mode."]}),"\n",(0,i.jsxs)(s.p,{children:["This setting is only available on ",(0,i.jsx)(s.a,{href:"/pricing",children:"Enterprise Edition"}),"."]}),"\n",(0,i.jsx)(s.h3,{id:"http-route-default-allowed-origins",children:"HTTP route default allowed origins"}),"\n",(0,i.jsxs)(s.p,{children:["Comma-separated list of origins that ",(0,i.jsx)(s.a,{href:"/docs/triggers/http_routing/#allowed-origins",children:"HTTP routes"})," allow to call them from a browser when the route sets none of its own, stored under ",(0,i.jsx)(s.code,{children:"http_route_default_allowed_origins"})," (the API also accepts a JSON array).\nA route overrides it with its own list and opts out with ",(0,i.jsx)(s.code,{children:"*"}),", so this is a default rather than a ceiling.\nLeave it empty for no default, so every route allows any origin unless it restricts itself.\nChanges apply without a restart."]}),"\n",(0,i.jsxs)(s.p,{children:["This setting is only available on ",(0,i.jsx)(s.a,{href:"/pricing",children:"Enterprise Edition"}),"."]}),"\n",(0,i.jsx)(s.h3,{id:"retention-period-in-secs",children:"Retention period in secs"}),"\n",(0,i.jsxs)(s.p,{children:["How long to keep the jobs data (especially the ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/audit_logs/",children:"audit logs"}),") in the database (max 30 days on ",(0,i.jsx)(s.a,{href:"/pricing",children:"Community Edition"}),")."]}),"\n",(0,i.jsx)(s.p,{children:"You will find a helper to convert days, hours, minutes, and seconds to seconds."}),"\n",(0,i.jsxs)(s.p,{children:["This setting is only available on ",(0,i.jsx)(s.a,{href:"/pricing",children:"Enterprise Edition"}),"."]}),"\n",(0,i.jsx)(s.h3,{id:"per-workspace-retention-overrides",children:"Per-workspace retention overrides"}),"\n",(0,i.jsxs)(s.p,{children:["Override the retention period for specific workspaces, independently of the instance-wide ",(0,i.jsx)(s.a,{href:"#retention-period-in-secs",children:"retention period"}),". A workspace override can be longer or shorter than the global value, and ",(0,i.jsx)(s.code,{children:"0"})," means keep jobs forever for that workspace. Workspaces without an override follow the instance-wide setting."]}),"\n",(0,i.jsxs)(s.p,{children:["The overrides are stored as a JSON map of ",(0,i.jsx)(s.code,{children:"workspace_id"}
1)," to seconds in the ",(0,i.jsx)(s.code,{children:"retention_period_secs_overrides"})," global setting, next to ",(0,i.jsx)(s.code,{children:"retention_period_secs"}),'. Configure them in the instance settings UI under the "Jobs" tab, right below the retention period field, by adding one row per workspace. Up to 10 workspaces can be overridden.']}),"\n",(0,i.jsxs)(s.p,{children:["This is a superadmin-controlled instance setting (not a workspace admin setting) since retention is an operator and cost concern. It is only available on ",(0,i.jsx)(s.a,{href:"/pricing",children:"Enterprise Edition"}),"."]}),"\n",(0,i.jsx)(s.h3,{id:"audit-log-retention-days",children:"Audit log retention (days)"}),"\n",(0,i.jsx)(s.p,{children:"How long to keep audit log entries in the database. Default: 365 days (EE), 14 days (CE). Audit logs are internally partitioned by day for performance - expired partitions are dropped automatically rather than deleted row by row."}),"\n",(0,i.jsxs)(s.p,{children:["If you enable ",(0,i.jsx)(s.a,{href:"#store-audit-logs-in-object-storage",children:"Store audit logs in object storage"}),", the bucket holds the durable long-term history, so you can safely lower this value to only what you need for the in-app ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/audit_logs/",children:"audit log"})," view. Windmill never deletes the exported audit logs from object storage."]}),"\n",(0,i.jsx)(s.h3,{id:"maximum-token-expiration-days",children:"Maximum token expiration (days)"}),"\n",(0,i.jsxs)(s.p,{children:["Furthest ahead, in days, that a user-created API token can expire.\nA token requested with no expiration or a longer one is created with this expiration instead.\n",(0,i.jsx)(s.a,{href:"/docs/core_concepts/roles_and_permissions/#service-accounts",children:"Service account"})," tokens are exempt.\nLeave empty for no limit.\nSee ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/user_tokens/#maximum-token-expiration",children:"Maximum token expiration"})," for what it covers."]}),"\n",(0,i.jsx)(s.h3,{id:"disable-token-in-mcp-urls",children:"Disable token in MCP URLs"}),"\n",(0,i.jsxs)(s.p,{children:["When enabled, the ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/mcp/",children:"MCP"})," endpoints refuse a token passed as a ",(0,i.jsx)(s.code,{children:"?token="})," query parameter, which would otherwise end up in browser history and proxy logs.\nMCP clients then sign in through ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/mcp/#connect-with-oauth",children:"OAuth"})," or send the token in an ",(0,i.jsx)(s.code,{children:"Authorization"})," header.\nIt is off by default, and existing MCP URLs that carry a token stop working once it is enabled."]}),"\n",(0,i.jsx)(s.h3,{id:"instance-object-storage",children:"Instance object storage"}),"\n",(0,i.jsxs)(s.p,{children:[(0,i.jsx)(s.a,{href:"/docs/core_concepts/object_storage_in_windmill/#instance-object-storage",children:"Connect your instance"})," to a S3 bucket to ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/object_storage_in_windmill/#large-job-logs-management",children:"store large logs"})," and ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/object_storage_in_windmill/#instance-object-storage-distributed-cache-for-python-rust-go",children:"global cache for Python and Go"}),"."]}),"\n",(0,i.jsxs)(s.p,{children:["This feature has no overlap with the ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/object_storage_in_windmill/#workspace-object-storage",children:"Workspace object storage"}),"."]}),"\n",(0,i.jsxs)(s.p,{children:["A ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/worker_groups/",children:"worker group"})," can cache its dependencies in its own bucket instead of this one, see ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/worker_groups/#dependency-cache-object-storage",children:"dependency cache object storage"}),".\nEverything else, including logs and job results, always uses the instance object storage."]}),"\n",(0,i.jsx)(s.p,{children:"You can choose to use S3, Azure Blob Storage, AWS OIDC or Google Cloud Storage. For each you will find a button to test settings from a server or from a worker."}),"\n",(0,i.jsx)(s.p,{children:(0,i.jsx)(s.img,{alt:"S3/Azure for Python/Go cache &amp; large logs",src:t(36299).A+"",title:"S3/Azure for Python/Go cache &amp; large logs",width:"2578",height:"1354"})}),"\n",(0,i.jsx)(s.h4,{id:"s3",children:"S3"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Field"}),(0,i.jsx)(s.th,{children:"Description"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Bucket"}),(0,i.jsx)(s.td,{children:"The name of your S3 bucket"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Region"}),(0,i.jsx)(s.td,{children:"If left empty, will be derived automatically from $AWS_REGION"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Access key ID"}),(0,i.jsx)(s.td,{children:"If left empty, will be derived automatically from $AWS_ACCESS_KEY_ID, pod or ec2 profile"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Secret key"}),(0,i.jsx)(s.td,{children:"If left empty, will be derived automatically from $AWS_SECRET_KEY, pod or ec2 profile"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Endpoint"}),(0,i.jsx)(s.td,{children:"Only needed for non AWS S3 providers like R2 or MinIo"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Allow http"}),(0,i.jsx)(s.td,{children:"Disable if using https only policy"})]})]})]}),"\n",(0,i.jsx)(s.h4,{id:"azure-blob",children:"Azure Blob"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Field"}),(0,i.jsx)(s.th,{children:"Description"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Account name"}),(0,i.jsx)(s.td,{children:"The name of your Azure storage account"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Container name"}),(0,i.jsx)(s.td,{children:"The name of your Azure blob container"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Access key"}),(0,i.jsx)(s.td,{children:"Your Azure storage account access key. Leave empty when authenticating with AKS Workload Identity"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Tenant ID"}),(0,i.jsx)(s.td,{children:"(Optional) Your Azure tenant ID"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Client ID"}),(0,i.jsx)(s.td,{children:"(Optional) Your Azure client ID"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Federated token file"}),(0,i.jsxs)(s.td,{children:["(Optional) Path to the projected service account token when using AKS Workload Identity, e.g. ",(0,i.jsx)(s.code,{children:"/var/run/secrets/azure/tokens/azure-identity-token"})]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Endpoint"}),(0,i.jsx)(s.td,{children:"(Optional) Only needed for non Azure Blob providers like Azurite"})]})]})]}),"\n",(0,i.jsxs)(s.p,{children:["When running on AKS with ",(0,i.jsx)(s.a,{href:"https://learn.microsoft.com/en-us
1/azure/aks/workload-identity-overview",children:"Workload Identity"}),", you can authenticate without a storage access key: set the tenant ID, client ID and federated token file (leave the access key empty). Windmill then exchanges the projected service account token for storage credentials directly, without relying on IMDS."]}),"\n",(0,i.jsx)(s.h4,{id:"aws-oidc",children:"AWS OIDC"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Field"}),(0,i.jsx)(s.th,{children:"Description"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Bucket"}),(0,i.jsx)(s.td,{children:"The name of your S3 bucket"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Region"}),(0,i.jsx)(s.td,{children:"The AWS region where your bucket is located"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Role ARN"}),(0,i.jsxs)(s.td,{children:["The ARN of the IAM role to assume (e.g., arn:aws:iam::123456789012",":role","/test)"]})]})]})]}),"\n",(0,i.jsxs)(s.p,{children:["This setting is only available on ",(0,i.jsx)(s.a,{href:"/pricing",children:"Enterprise Edition"}),"."]}),"\n",(0,i.jsx)(s.h4,{id:"google-cloud-storage",children:"Google Cloud Storage"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Field"}),(0,i.jsx)(s.th,{children:"Description"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Bucket"}),(0,i.jsx)(s.td,{children:"The name of your Google Cloud Storage bucket"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Service Account Key"}),(0,i.jsx)(s.td,{children:"The service account key for your Google Cloud Storage bucket in JSON format. Leave empty to use the instance's ambient GCP credentials instead (GKE Workload Identity or the GCP metadata server)"})]})]})]}),"\n",(0,i.jsxs)(s.p,{children:["Leaving the Service Account Key empty is useful when Windmill runs in the same GCP project as the bucket: instead of managing a static key, grant the Kubernetes service account (via ",(0,i.jsx)(s.a,{href:"https://cloud.google.com/kubernetes-engine/docs/concepts/workload-identity",children:"GKE Workload Identity"}),") or the VM's service account access to the bucket, and Windmill will authenticate through the metadata server."]}),"\n",(0,i.jsxs)(s.p,{children:["For security reasons, testing GCS connectivity with an empty Service Account Key requires being a ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/roles_and_permissions/#superadmin",children:"superadmin"}),": since a blank key falls back to the server's own GCP identity, the test buttons would otherwise let non-superadmin users probe arbitrary buckets with the instance's credentials."]}),"\n",(0,i.jsx)(s.h3,{id:"store-audit-logs-in-object-storage",children:"Store audit logs in object storage"}),"\n",(0,i.jsxs)(s.p,{children:["When enabled and ",(0,i.jsx)(s.a,{href:"#instance-object-storage",children:"instance object storage"})," is configured, ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/audit_logs/",children:"audit logs"})," are also exported as newline-delimited JSON (NDJSON) to a dedicated ",(0,i.jsx)(s.code,{children:"logs/audit/"})," folder in the bucket, partitioned by day (",(0,i.jsx)(s.code,{children:"logs/audit/dt=YYYY-MM-DD/"}),"). The export is incremental and runs in the background off the audit log hot path."]}),"\n",(0,i.jsxs)(s.p,{children:["Only audit logs created after the setting is enabled are exported (no historical backfill), and Windmill never deletes the exported files from object storage. This is the recommended setup to forward audit logs to a ",(0,i.jsx)(s.a,{href:"https://en.wikipedia.org/wiki/Security_information_and_event_management",children:"SIEM"})," for long-term security analysis. See ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/audit_logs/#exporting-audit-logs-to-object-storage",children:"exporting audit logs to object storage"})," for details."]}),"\n",(0,i.jsxs)(s.p,{children:["This setting is only available on ",(0,i.jsx)(s.a,{href:"/pricing",children:"Enterprise Edition"}),"."]}),"\n",(0,i.jsx)(s.h3,{id:"auto-build-binaries-on-deployment",children:"Auto-build binaries on deployment"}),"\n",(0,i.jsxs)(s.p,{children:["When enabled and ",(0,i.jsx)(s.a,{href:"#instance-object-storage",children:"instance object storage"}),' is configured, deploying a Rust, Go or C# script queues a job that compiles it and uploads the binary to the bucket, so its first run does not pay the compile. Off by default. The companion "Auto-build worker tag" setting picks the ',(0,i.jsx)(s.a,{href:"/docs/core_concepts/worker_groups/",children:"worker tag"})," those build jobs run on. See ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/
1object_storage_in_windmill/#auto-build-binaries-on-deployment",children:"auto-build binaries on deployment"}),"."]}),"\n",(0,i.jsxs)(s.p,{children:["This setting is only available on ",(0,i.jsx)(s.a,{href:"/pricing",children:"Enterprise Edition"}),"."]}),"\n",(0,i.jsx)(s.h3,{id:"private-hub-base-url",children:"Private Hub base url"}),"\n",(0,i.jsxs)(s.p,{children:["Base url of your ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/private_hub/",children:"Private Hub"})," instance, without trailing slash."]}),"\n",(0,i.jsx)(s.p,{children:"The url above will be used both when accessing the hub from the instance and from the user browser.\nIf end users cannot access the Private Hub with the url above, you can enable the toggle just below the field to set a different url for the Private Hub which is accessible to the users (Private Hub accessible url)."}),"\n",(0,i.jsxs)(s.p,{children:["This setting is only available on ",(0,i.jsx)(s.a,{href:"/pricing",children:"Enterprise Edition"}),"."]}),"\n",(0,i.jsx)(s.h3,{id:"private-hub-api-secret",children:"Private hub api secret"}),"\n",(0,i.jsxs)(s.p,{children:["Private Hub api secret. Only required if access to your ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/private_hub/#restricting-access-to-your-private-hub",children:"Private Hub is restricted"}),"."]}),"\n",(0,i.jsxs)(s.p,{children:["This setting is only available on ",(0,i.jsx)(s.a,{href:"/pricing",children:"Enterprise Edition"}),"."]}),"\n",(0,i.jsx)(s.h3,{id:"disable-hub",children:"Disable hub"}),"\n",(0,i.jsxs)(s.p,{children:["When enabled, Windmill stops making any request to ",(0,i.jsx)(s.code,{children:"hub.windmill.dev"})," (or your ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/private_hub/",children:"Private Hub"}),") and hides the hub pickers in the flow, app, and script editors. This is intended for closed/air-gapped deployments where outbound access to the hub is unavailable."]}),"\n",(0,i.jsx)(s.p,{children:'When the hub is reachable but returns errors, the hub pickers display a persistent warning alert with a direct link back to this setting (instead of a transient error toast), guiding superadmins to toggle "Disable hub" and remove the warning.'}),"\n",(0,i.jsx)(s.h2,{id:"authoauth",children:"Auth/OAuth"}),"\n",(0,i.jsxs)(s.p,{children:["Windmill supports ",(0,i.jsx)(s.a,{href:"/docs/advanced/setup_oauth/",children:"SSO/OAuth"})," for user authentication. You can enable it from the Instance settings."]}),"\n",(0,i.jsx)("div",{className:"grid grid-cols-2 gap-6 mb-4",children:(0,i.jsx)(a.A,{title:"Setup OAuth and SSO",description:"Windmill supports Single Sign-On for Microsoft, Google, GitHub, GitLab, Okta, and domain restriction.",href:"/docs/advanced/setup_oauth"})}),"\n",(0,i.jsx)(s.h3,{id:"single-sign-on-sso",children:"Single Sign On (SSO)"}),"\n",(0,i.jsxs)(s.p,{children:["When at least one of the ",(0,i.jsx)(s.a,{href:"/docs/advanced/setup_oauth/#sso",children:"SSO options"})," is set, users will be able to login to Windmill via their third-party account."]}),"\n",(0,i.jsx)(s.p,{children:"To test SSO, the recommended workflow is to to save the settings and try to login in an incognito window."}),"\n",(0,i.jsx)(s.p,{children:(0,i.jsx)(s.img,{alt:"SSO",src:t(2678).A+"",title:"SSO",width:"3018",height:"1716"})}),"\n",(0,i.jsx)(s.p,{children:"You can add a custom SSO client by providing a client id."}),"\n",(0,i.jsx)(s.p,{children:"Also, from the instance settings you can enable toggle 'Require users to have been added manually to Windmill to sign in through OAuth'."}),"\n",(0,i.jsxs)(s.p,{children:["Without ",(0,i.jsx)(s.a,{href:"/pricing",children:"Enterprise Edition"}),", the number of SSO users is limited to 10."]}),"\n",(0,i.jsx)(s.h4,{id:"sso-groups-claim",children:"SSO groups claim"}),"\n",(0,i.jsxs)(s.p,{children:["Name of the SAML attribute or OIDC userinfo claim carrying the user's identity provider groups.\nWhen set, every SSO login reconciles the user's membership in SCIM-provisioned instance groups against the claim before the session starts, so group changes in the identity provider apply at the next login instead of the next SCIM push.\nLeave empty to disable.\nEnterprise Edition only; see ",(0,i.jsx)(s.a,{href:"/docs/advanced/saml_and_scim/#login-time-group-sync-from-the-idp-groups-claim",children:"login-time group sync"}),"."]}),"\n",(0,i.jsx)(s.h3,{id:"oauth",children:"OAuth"}),"\n",(0,i.jsxs)(s.p,{children:["When one of the ",(0,i.jsx)(s.a,{href:"/docs/advanced/setup_oauth/#oauth",children:"OAuth"})," options is set, you will be able to create a specific ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/resources_and_types/",children:"resource"})," containing a 'token' automatically generated by the third-party provider.\nTo test it after setting an oauth client, go to the Resources menu and create a new one of the type of your oauth client (i.e. a '",(0,i.jsx)(s.a,{href:"https://hub.windmill.dev/?app=github",children:"github"}),"' resource if you set GitHub OAuth)."]}),"\n",(0,i.jsx)(s.p,{children:(0,i.jsx)(s.img,{alt:"OAuth",src:t(29722).A+"",title:"OAuth",width:"3024",height:"1678"})}),"\n",(0,i.jsx)(s.h3,{id:"scimsaml",children:"SCIM/SAML"}),"\n",(0,i.jsxs)(s.p,{children:["Windmill supports ",(0,i.jsx)(s.a,{href:"/docs/advanced/saml_and_scim/",children:"SCIM and SAML"})," for user provisioning and ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/authentication/",children:"authentication"}),"."]}),"\n",(0,i.jsx)(s.p,{children:(0,i.jsx)(s.img,{alt:"SCIM/SAML",src:t(35967).A+"",title:"SCIM/SAML",width:"3020",height:"1678"})}),"\n",(0,i.jsx)(s.p,{children:"You can test settings with button 'Test content/url'."}),"\n",(0,i.jsxs)(s.p,{children:["These settings are only available on ",(0,i.jsx)(s.a,{href:"/pricing",children:"Enterprise Edition"}),"."]}),"\n",(0,i.jsx)("div",{className:"grid grid-cols-2 gap-6 mb-4",children:(0,i.jsx)(a.A,{title:"SAML & SCIM",description:"Configure Okta or Microsoft for both SAML and SCIM.",href:"/docs/advanced/saml_and_scim"})}),"\n",(0,i.jsx)(s.h4,{id:"scim-token",children:"SCIM token"}),"\n",(0,i.jsx)(s.p,{children:"Token used to authenticate requests from the IdP."}),"\n",(0,i.jsx)(s.h4,{id:"saml-metadata",children:"SAML metadata"}),"\n",(0,i.jsx)(s.p,{children:"XML metadata url OR content for the SAML IdP."}),"\n",(0,i.jsxs)(s.p,{children:["By default, metadata URLs that resolve to private or internal network addresses are blocked to protect against SSRF. For self
1-hosted deployments with an internal IdP, set the ",(0,i.jsx)(s.code,{children:"ALLOW_PRIVATE_SAML_METADATA_URLS=true"})," environment variable to allow them. See ",(0,i.jsx)(s.a,{href:"/docs/advanced/saml_and_scim/#private-or-internal-idp-metadata-urls",children:"private or internal IdP metadata URLs"}),"."]}),"\n",(0,i.jsx)(s.h2,{id:"registries",children:"Registries"}),"\n",(0,i.jsxs)(s.p,{children:["Add private registries for ",(0,i.jsx)(s.a,{href:"https://pypi.org/",children:"UV"}),", ",(0,i.jsx)(s.a,{href:"https://bun.sh/",children:"Bun"}),", ",(0,i.jsx)(s.a,{href:"https://www.npmjs.com/",children:"npm"}),", ",(0,i.jsx)(s.a,{href:"https://www.nuget.org/",children:"Nuget"}),", ",(0,i.jsx)(s.a,{href:"https://learn.microsoft.com/en-us/azure/devops/artifacts/tutorials/private-powershell-library",children:"PowerShell"}),", ",(0,i.jsx)(s.a,{href:"/docs/getting_started/scripts_quickstart/java#private-maven-registries",children:"Maven/Java"}),", and ",(0,i.jsx)(s.a,{href:"/docs/getting_started/scripts_quickstart/rust",children:"Cargo/Rust"}),"."]}),"\n",(0,i.jsxs)(s.p,{children:["These settings are only available on ",(0,i.jsx)(s.a,{href:"/pricing",children:"Enterprise Edition"}),"."]}),"\n",(0,i.jsx)(s.p,{children:(0,i.jsx)(s.img,{alt:"Registries",src:t(2706).A+"",title:"Registries",width:"3024",height:"1718"})}),"\n",(0,i.jsxs)("div",{className:"grid grid-cols-2 gap-6 mb-4",children:[(0,i.jsx)(a.A,{title:"Dependency management & imports",description:"Windmill's strength lies in its ability to run scripts without having to manage a requirements.txt directly.",href:"/docs/advanced/imports"}),(0,i.jsx)(a.A,{title:"Dependencies in Python",description:"How to manage dependencies in Python scripts.",href:"/docs/advanced/dependencies_in_python"}),(0,i.jsx)(a.A,{title:"Dependencies in TypeScript",description:"How to manage dependencies in TypeScript scripts.",href:"/docs/advanced/dependencies_in_typescript"})]}),"\n",(0,i.jsx)(s.h3,{id:"uv-index-url",children:"UV index url"}),"\n",(0,i.jsx)(s.p,{children:"Add private registry for python."}),"\n",(0,i.jsx)(s.h3,{id:"uv-extra-index-url",children:"UV extra index url"}),"\n",(0,i.jsx)(s.p,{children:"Add private extra private registry for python."}),"\n",(0,i.jsx)(s.h3,{id:"npm-config-registry",children:"Npm config registry"}),"\n",(0,i.jsx)(s.p,{children:"Add private NPM registry."}),"\n",(0,i.jsx)(s.h3,{id:"bunfig-install-scopes",children:"Bunfig install scopes"}),"\n",(0,i.jsxs)(s.p,{children:["Add private scoped registries for Bun, See: ",(0,i.jsx)(s.a,{href:"https://bun.sh/docs/install/registries",children:"https://bun.sh/docs/install/registries"}),"."]}),"\n",(0,i.jsx)(s.h3,{id:"npmrc",children:(0,i.jsx)(s.code,{children:".npmrc"})}),"\n",(0,i.jsxs)(s.p,{children:["Provide the full content of a standard ",(0,i.jsx)(s.a,{href:"https://docs.npmjs.com/cli/v10/configuring-npm/npmrc",children:(0,i.jsx)(s.code,{children:".npmrc"})})," file. This works natively with Bun (since 1.1.18), Deno (2.x), and the Windmill npm proxy (which parses the default registry and auth token from the ",(0,i.jsx)(s.code,{children:".npmrc"}),"). When configured, the legacy ",(0,i.jsx)(s.code,{children:"Npm config registry"})," and ",(0,i.jsx)(s.code,{children:"Bunfig install scopes"})," fields are hidden for new setups."]}),"\n",(0,i.jsxs)(s.h3,{id:"maven-settingsxml",children:["Maven ",(0,i.jsx)(s.code,{children:"settings.xml"})]}),"\n",(0,i.jsxs)(s.p,{children:["Provide the full content of a Maven ",(0,i.jsx)(s.code,{children:"settings.xml"})," file. Windmill writes it to ",(0,i.jsx)(s.code,{children:"{JAVA_HOME}/.m2/settings.xml"})," so Coursier can use your configured servers, mirrors, and repository URLs when resolving ",(0,i.jsx)(s.a,{href:"/docs/getting_started/scripts_quickstart/java",children:"Java"})," dependencies. Clearing the setting removes the file."]}),"\n",(0,i.jsx)(s.h3,{id:"cargo-registries",children:"Cargo registries"}),"\n",(0,i.jsxs)(s.p,{children:["Provide the content of a Cargo ",(0,i.jsx)(s.code,{children:"config.toml"})," file for configuring private ",(0,i.jsx)(s.a,{href:"/docs/getting_started/scripts_quickstart/rust",children:"Rust"})," crate registries. Written to ",(0,i.jsx)(s.code,{children:"{job_dir}/.cargo/config.toml"})," during job execution."]}),"\n",(0,i.jsx)(s.h3,{id:"nuget-config",children:"Nuget config"}),"\n",(0,i.jsx)(s.p,{children:"Write a nuget.config file to set custom/private package sources and credentials."}),"\n",(0,i.jsx)(s.h3,{id:"workspace-specific-registry-overrides",children:"Worksp
1ace-specific registry overrides"}),"\n",(0,i.jsx)(s.p,{children:'Superadmins can configure per-workspace overrides for package registry settings. This allows different workspaces to use different private registries (e.g. workspace A uses registry-a.example.com while workspace B uses registry-b.example.com). All registry settings except the Python version and uv index strategy can be overridden per workspace. Configure these under the "Workspace Registries" section.'}),"\n",(0,i.jsx)(s.h3,{id:"docker-registries",children:"Docker registries"}),"\n",(0,i.jsxs)(s.p,{children:["Credentials used by ",(0,i.jsx)(s.code,{children:"crane"})," when pulling private container images for ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/ai_sandbox/",children:"sandbox"})," snapshot builds. Provide a JSON array of ",(0,i.jsx)(s.code,{children:"{registry, username, password}"})," objects, for example:"]}),"\n",(0,i.jsx)(s.pre,{children:(0,i.jsx)(s.code,{className:"language-json",children:'[\n  { "registry": "ghcr.io", "username": "my-user", "password": "ghp_xxx" },\n  { "registry": "registry.example.com", "username": "ci", "password": "..." }\n]\n'})}),"\n",(0,i.jsxs)(s.p,{children:["Windmill writes the corresponding Docker ",(0,i.jsx)(s.code,{children:"config.json"})," to ",(0,i.jsx)(s.code,{children:"/tmp/windmill/docker"})," and sets ",(0,i.jsx)(s.code,{children:"DOCKER_CONFIG"})," when invoking ",(0,i.jsx)(s.code,{children:"crane export"}),", so private base images can be resolved without exposing credentials in the snapshot build script. This setting is fully redacted in logs."]}),"\n",(0,i.jsx)(s.h2,{id:"alerts",children:"Alerts"}),"\n",(0,i.jsx)(s.p,{children:(0,i.jsx)(s.img,{alt:"Alerts",src:t(48666).A+"",width:"3022",height:"1682"})}),"\n",(0,i.jsx)(s.h3,{id:"critical-alert-channels",children:"Critical alert channels"}),"\n",(0,i.jsxs)(s.p,{children:["Channels to send ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/critical_alerts/",children:"critical alerts"})," to. ",(0,i.jsx)(s.a,{href:"#smtp",children:"SMTP"})," must be configured for the email channel. A Slack workspace must be connected to the instance for the Slack channel. ",(0,i.jsx)(s.a,{href:"/docs/advanced/setup_oauth/#microsoft-teams",children:"Microsoft Teams"})," must be setup to configure critical alerts to be sent to a Microsoft Teams channel."]}),"\n",(0,i.jsx)(s.p,{children:"You can add multiple channels between Email, Slack, and Microsoft Teams."}),"\n",(0,i.jsx)(s.p,{children:(0,i.jsx)(s.img,{alt:"Critical alerts channels",src:t(33313).A+"",title:"Critical alerts channels",width:"2268",height:"1316"})}),"\n",(0,i.jsxs)(s.p,{children:["Furthermore you can chose to mute ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/critical_alerts/",children:"critical alerts in the UI"}),' using the "Mute critical alerts in UI" toggle.']}),"\n",(0,i.jsxs)(s.p,{children:["This setting is only available on ",(0,i.jsx)(s.a,{href:"/pricing",children:"Enterprise Edition"}),"."]}),"\n",(0,i.jsx)(s.p,{children:(0,i.jsx)(s.img,{alt:"Critical alert example",src:t(68366).A+"",title:"Critical alert example",width:"1038",height:"484"})}),"\n",(0,i.jsx)(s.h3,{id:"mute-critical-alerts-in-ui",children:"Mute critical alerts in UI"}),"\n",(0,i.jsx)(s.p,{children:"Enable to mute critical alerts in the UI."}),"\n",(0,i.jsx)(s.h3,{id:"alert-on-token-expiry",children:"Alert on token expiry"}),"\n",(0,i.jsxs)(s.p,{children:["Enable to send ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/critical_alerts/#token-expiration-notifications",children:"critical alerts"})," when API tokens are about to expire (within 7 days) or have expired. This setting is off by default."]}),"\n",(0,i.jsxs)(s.p,{children:["Email notifications to token owners are always sent regardless of this setting, as long as ",(0,i.jsx)(s.a,{href:"#smtp",children:"SMTP"})," is configured."]}),"\n",(0,i.jsx)(s.h3,{id:"mute-zombie-job-restart-alerts",children:"Mute zombie job restart alerts"}),"\n",(0,i.jsxs)(s.p,{children:["Stop sending ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/critical_alerts/",children:"critical alerts"})," when a zombie job or flow is detected and restarted automatically. This setting is off by default."]}),"\n",(0,i.jsxs)(s.p,{children:["A job whose worker stops pinging for longer than ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/environment_variables/",children:(0,i.jsx)(s.code,{children:"ZOMBIE_JOB_TIMEOUT"})})," is considered a zombie and restarted, up to 3 attempts, and each restart raises a critical alert. On an instance with flaky workers, that means a burst of alerts for a condition Windmill heals on its own."]}),"\n",(0,i.jsx)(s.p,{children:"Muting them leaves the recovery itself untouched, and the terminal alerts still fire: a job that exhausted all its restart attempts and is failed, and a flow cancelled after hanging between two steps."}),"\n",(0,i.jsx)(s.p,{children:"Toggling this setting takes effect immediately, without restarting the instance."}),"\n",(0,i.jsxs)(s.p,{children:["This setting is only available on ",(0,i.jsx)(s.a,{href:"/pricing",children:"Enterprise Edition"}),"."]}),"\n",(0,i.jsx)(s.h3,{id:"slack",children:"Slack"}),"\n",(0,i.jsxs)(s.p,{children:["Connecting your instance to a Slack workspace enables ",(0,i.jsx)(s.a,{href:"#critical-alert-channels",children:"critical alerts"})," to be sent to a Slack channel."]}),"\n",(0,i.jsx)(s.p,{children:"Just click on the 'Connect to Slack' button and follow the instructions from Slack."}),"\n",(0,i.jsxs)(s.p,{children:["This setting is only available on ",(0,i.jsx)(s.a,{href:"/pricing",children:"Enterprise Edition"}),"."]}),"\n",(0,i.jsx)(s.h3,{id:"smtp",children:"SMTP"}),"\n",(0,i.jsxs)(s.p,{children:["Setting SMTP unlocks ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/authentication/",children:"sending emails upon adding new users"})," to the workspace or the instance and ",(0,i.jsx)(s.a,{href:"#critical-alert-channels",children:"sending critical alerts"}),"."]}),"\n",(0,i.jsx)(s.p,{children:"You need to provide the following details:"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Name"}),(0,i.jsx)(s.th,{children:"Type"}),(0,i.jsx)(s.th,{children:"Description"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Host"}),(0,i.jsx)(s.td,{children:"String"}),(0,i.jsx)(s.td,{children:"SMTP server host"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Port"}),(0,i.jsx)(s.td,{children:"Number"}),(0,i.jsx)(s.td,{children:"SMTP server port"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Username"}),(0,i.jsx)(s.td,{children:"String"}),(0,i.jsx)(s.td,{children:"SMTP server user"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Password"}),(0,i.jsx)(s.td,{children:"String"}),(0,i.jsx)(s.td,{children:"SMTP server password"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"From Address"}),(0,i.jsx)(s.td,{children:"String"}),(0,i.jsx)(s.td,{children:"Email address to send emails from"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Implicit TLS"}),(0,i.jsx)(s.td,{children:"Boolean"}),(0,i.jsx)(s.td,{children:"Use implicit TLS (default: false)"})]})]})]}),"\n",(0,i.jsx)(s.p,{children:"You have another field to test the SMTP settings."}),"\n",(0,i.jsx)("iframe",{style:{aspectRatio:"16/9"},src:"https://www.youtube.com/embed/Wyq6d0bkuGo",title:"YouTube video player",frameBorder:"0",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share",allowFullScreen:!0,className:"border-2 rounded-lg object-cover w-full dark:border-gray-800"}),"\n",(0,i.jsx)("br",{}),"\n",(0,i.jsxs)(n,{children:[(0,i.jsxs)("summary",{children:["Set-up SMTP from the ",(0,i.jsx)(s.code,{children:".env"})," file (deprecated) "]}),(0,i.jsx)(s.p,{children:"The relevant environment variables are:"}),(0,i.jsx)(s.pre,{children:(0,i.jsx)(s.code,{children:"[email protected]\nSMTP_HOST=smtp.gmail.com\nSMTP_PORT=587\[email protected]\nSMTP_PASSWORD=app_password\n"})}),(0,i.jsxs)(s.p,{children:["If you used the ",(0,i.jsx)(s.a,{href:"/docs/advanced/self_host/#setup-windmill-on-localhost",children:"Setup Windmill on localhost"})," method, open the ",(0,i.jsx)(s.code,{children:".env"})," file in any text editor. You can use ",(0,i.jsx)(s.code,{children:"nano"}),", ",(0,i.jsx)(s.code,{children:"vim"}),", or any other editor you're comfortable with."]}),(0,i.jsx)(s.pre,{children:(0,i.jsx)(s.code,{className:"language-bash",children:"nano .env\n"})}),(0,i.jsxs)(s.p,{children:["Append the following to the end of your ",(0,i.jsx)(s.code,{children:".env"})," file:"]}),(0,i.jsx)(s.pre,{children:(0,i.jsx)(s.code,{children:"[email protected]\nSMTP_HOST=smtp.gmail.com\nSMTP_PORT=587\[email protected]\nSMTP_PASSWORD=your_app_password\n"})}),(0,i.jsxs)(s.p,{children:["Make sure to replace ",(0,i.jsx)(s.code,{children:"[email protected]"})," with your actual Gmail email address and ",(0,i.jsx)(s.code,{children:"your_app_password"})," with the app password you've generated from Gmail."]})," ",(0,i.jsx)("br",{}),(0,i.jsxs)(s.blockquote,{children:["\n",(0,i.jsxs)(s.p,{children:[(0,i.jsx)(s.strong,{children:"Note"}),": If you're using Gmail, you'll need to ",(0,i.jsx)(s.a,{href:"https://support.google.com/accounts/answer/185833?hl=en",children:"generate an App Password"})," to use as ",(0,i.jsx)(s.code,{children:"SMTP_PASSWORD"}),". This is a unique password that Gmail provides for apps and services that want to connect to your account."]}),"\n"]}),(0,i.jsx)("br",{}),(0,i.jsx)(s.p,{children:"Save and Close the File:"}),(0,i.jsxs)(s.ul,{children:["\n",(0,i.jsxs)(s.li,{children:["If using ",(0,i.jsx)(s.code,{children:"nano"}),", press ",(0,i.jsx)(s.code,{children:"CTRL + O"})," to save and then ",(0,i.jsx)(s.code,{children:"CTRL + X"})," to exit."]}),"\n",(0,i.jsxs)(s.li,{children:["If using ",(0,i.jsx)(s.code,{children:"vim"}),", press ",(0,i.jsx)(s.code,{children:"Esc"}),", then type ",(0,i.jsx)(s.code,{children:":wq"})," and press ",(0,i.jsx)(s.code,{children:"Enter"}),"."]}),"\n"]}),(0,i.jsx)(s.p,{children:"Restart your Windmill application:"}),(0,i.jsxs)(s.ul,{children:["\n",(0,i.jsxs)(s.li,{children:["Since you've made changes to the ",(0,i.jsx)(s.code,{children:".env"})," file, you'll need to restart your Windmill application for the changes to take effect."]}),"\n"]}),(0,i.jsx)(s.pre,{children:(0,i.jsx)(s.code,{className:"language-bash",children:"docker 
1compose down\ndocker compose up -d\n"})}),(0,i.jsx)(s.p,{children:"Now, your Windmill instance should use the SMTP settings you've provided to send invites and email to manually added users. Make sure the SMTP details you've provided are correct and that the Gmail account you're using has allowed less secure apps or generated an App Password."})]}),"\n",(0,i.jsx)(s.h3,{id:"set-up-auto-invites",children:"Set up auto-invites"}),"\n",(0,i.jsx)(s.p,{children:"When creating a workspace, you have the option to invite automatically everyone on the same domain. That's how you make sure that anyone added to the instance is also added to the workspace."}),"\n",(0,i.jsx)("video",{className:"border-2 rounded-lg object-cover w-full h-full",controls:!0,id:"new_workspace",src:"/videos/new_workspace.mp4"}),"\n",(0,i.jsx)(s.h2,{id:"webhooks",children:"Webhooks"}),"\n",(0,i.jsx)(s.h3,{id:"instance-events-webhook",children:"Instance events webhook"}),"\n",(0,i.jsx)(s.p,{children:"URL to receive POST requests for instance events such as user added, OAuth signup, user invited to workspace, or user joined workspace."}),"\n",(0,i.jsxs)(s.p,{children:["Configure it from ",(0,i.jsx)(s.strong,{children:"Instance settings > Monitoring > Webhooks"}),"."]}),"\n",(0,i.jsxs)(s.p,{children:["For workspace-level events (script, flow, app, resource lifecycle) see the ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/webhooks/#workspace-webhook",children:"workspace webhook"}),". For incoming webhooks that trigger scripts and flows, see ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/webhooks/",children:"webhooks"}),"."]}),"\n",(0,i.jsx)(s.h2,{id:"ai",children:"AI"}),"\n",(0,i.jsxs)(s.p,{children:["Configure ",(0,i.jsx)(s.a,{href:"/docs/core_concepts/ai_generation/",children:"Windmill AI"})," providers, models, and prompts once at the instance level so every workspace inherits them. Navigate to ",(0,i.jsx)(s.strong,{children:"Instance settings > AI"}),"."]}),"\n",(0,i.jsx)(s.p,{children:"Resolution order used by AI chat, code generation, and code completion:"}),"\n",(0,i.jsxs)(s.ol,{children:["\n",(0,i.jsxs)(s.li,{children:[(0,i.jsx)(s.strong,{children:"Workspace AI settings"})," when the workspace has any provider configured."]}),"\n",(0,i.jsxs)(s.li,{children:[(0,i.jsx)(s.strong,{children:"Instance AI settings"})," as the fallback when the workspace has no providers configured."]}),"\n"]}),"\n",(0,i.jsxs)(s.p,{children:["The fallback references resources from the ",(0,i.jsx)(s.code,{children:"admins"})," workspace, so any resources used by instance AI settings must exist there. A workspace using the instance fallback shows a read-only summary of the active instance AI config and an ",(0,i.jsx)(s.strong,{children:"Override for this workspace"})," button; clearing the workspace override instantly reverts to instance defaults."]}),"\n",(0,i.jsx)(s.h3,{id:"ai_http_headers",children:"AI_HTTP_HEADERS"}),"\n",(0,i.jsxs)(s.p,{children:["Set the ",(0,i.jsx)(s.code,{children:"AI_HTTP_HEADERS"})," env var on the server and workers to attach custom headers to every outgoing AI request (OpenAI, Anthropic, Azure, Bedrock, Vertex, etc.). Headers are comma-separated:"]}),"\n",(0,i.jsx)(s.pre,{children:(0,i.jsx)(s.code,{className:"language-bash",children:'AI_HTTP_HEADERS="X-Org: acme, X-Env: prod" ./windmill\n'})}),"\n",(0,i.jsxs)(s.p,{children:["Use this when AI traffic must flow through a corporate proxy or gateway that expects fixed auth/routing headers. Per-resource ",(0,i.jsx)(s.code,{children:"headers"})," on the ",(0,i.jsx)(s.code,{children:"customai"})," resource type are applied after this env var and take precedence on conflicting keys."]}),"\n",(0,i.jsx)(s.h2,{id:"open-telemetry--prometheus",children:"Open Telemetry & Prometheus"}),"\n",(0,i.jsx)(s.p,{children:(0,i.jsx)(s.img,{alt:"Open Telemetry &amp; Prometheus",src:t(13106).A+"",width:"1500",height:"1311"})}),"\n",(0,i.jsx)(s.h3,{id:"opentelemetry-otel",children:"OpenTelemetry (OTEL)"}),"\n",(0,i.jsxs)(s.p,{children:["Enable to collect telemetry data and send it to an ",(0,i.jsx)(s.a,{href:"https://opentelemetry.io/",children:"OpenTelemetry"})," collector such as ",(0,i.jsx)(s.a,{href:"https://www.jaegertracing.io/",children:"Jaeger"})," or ",(0,i.jsx)(s.a,{href:"https://www.tempo.io/",children:"Tempo"})," for tracing. OpenTelemetry data sent to the collector consists of traces, logs, and ",(0,i.jsx)(s.a,{href:"/docs/misc/guides/otel/#exporting-windmill-metrics-via-otlp",children:"metrics"}),". You can independently toggle each signal (Tracing, Logs, Metrics) in the instance settings."]}),"\n",(0,i.jsxs)(s.p,{children:["The transport protocol can also be selected from a dropdown: ",(0,i.jsx)(s.strong,{children:"grpc"})," (default, port 4317) or ",(0,i.jsx)(s.strong,{children:"http/protobuf"})," (port 4318, sets ",(0,i.jsx)(s.code,{children:"OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf"}),"). Use ",(0,i.jsx)(s.code,{children:"http/protobuf"})," when your collector or network environment does not support gRPC. Follow this ",(0,i.jsx)(s.a,{href:"/docs/misc/guides/otel/",children:"guide"})," for an example setup."]}),"\n",(0,i.jsx)(s.h3,{id:"http-tracing",children:"HTTP tracing"}),"\n",(0,i.jsx)(s.p,{children:"HTTP tracing captures HTTP/HTTPS requests made by job scripts as observability spans within the job details UI. Traces are stored and correlated with the job, displaying method, URL, status code, and timing information."}),"\n",(0,i.jsxs)(s.p,{children:["If the ",(0,i.jsx)(s.a,{href:"#opentelemetry-otel",children:"OpenTelemetry"}
1)," external collector is enabled, traces are also sent to that collector and seamlessly integrate with existing spans."]}),"\n",(0,i.jsx)(s.p,{children:"The feature works in two modes:"}),"\n",(0,i.jsxs)(s.ul,{children:["\n",(0,i.jsxs)(s.li,{children:[(0,i.jsx)(s.strong,{children:"Auto-instrumentation"})," for Native TypeScript: uses built-in OpenTelemetry instrumentation to automatically capture ",(0,i.jsx)(s.code,{children:"fetch()"})," requests."]}),"\n",(0,i.jsxs)(s.li,{children:[(0,i.jsx)(s.strong,{children:"MITM proxy"})," for other languages (Python, Bun, Deno, Go, Bash, Rust, C#, Nu, Ruby): outgoing HTTP traffic is routed through a tracing proxy that intercepts and records requests."]}),"\n"]}),"\n",(0,i.jsx)(s.p,{children:"You can select which language runtimes should have tracing enabled. Toggling this setting restarts workers."}),"\n",(0,i.jsx)(s.p,{children:(0,i.jsx)(s.img,{alt:"HTTP traces tab",src:t(50370).A+"",width:"1000",height:"1138"})}),"\n",(0,i.jsxs)(s.p,{children:["This setting is only available on ",(0,i.jsx)(s.a,{href:"/pricing",children:"Enterprise Edition"}),"."]}),"\n",(0,i.jsxs)(s.p,{children:["Captured spans are not kept forever: see ",(0,i.jsx)(s.a,{href:"#http-request-tracing-retention-in-secs",children:"HTTP request tracing retention in secs"})," for the retention window and its default."]}),"\n",(0,i.jsx)(s.h3,{id:"http-request-tracing-retention-in-secs",children:"HTTP request tracing retention in secs"}),"\n",(0,i.jsxs)(s.p,{children:["How long a captured ",(0,i.jsx)(s.a,{href:"#http-tracing",children:"HTTP tracing"}),' span is kept, and therefore how far back the job details view can show the HTTP requests a job made.\nDefaults to 7 days, and there is no "keep forever" value.']}),"\n",(0,i.jsx)(s.p,{children:"This window is independent of the job retention period, so a span can outlive its job or be deleted while the job is still listed.\nSpans are usually worth expiring sooner than the jobs themselves: tracing records one per HTTP request made from a job script."}),"\n",(0,i.jsxs)(s.p,{children:["The window can also be set with the ",(0,i.jsx)(s.code,{children:"OTEL_TRACES_RETENTION_SECS"})," env var on the servers, which the instance setting overrides when both are set."]}),"\n",(0,i.jsxs)(s.admonition,{title:"Upgrading to a version that sweeps traces",type:"warning",children:[(0,i.jsx)(s.p,{children:"Traces were never swept before this setting existed, so an instance with HTTP tracing enabled kept every span it had ever captured.\nAfter upgrading, every span older than the retention window is deleted, with no way to recover them."}),(0,i.jsxs)(s.p,{children:["To keep more than 7 days of request traces, set the window before the upgrade rather than after: servers read ",(0,i.jsx)(s.code,{children:"OTEL_TRACES_RETENTION_SECS"})," at startup, so setting it in the same deploy as the upgrade applies from the very first sweep."]})]}),"\n",(0,i.jsxs)(s.p,{children:["Capturing traces requires ",(0,i.jsx)(s.a,{href:"/pricing",children:"Enterprise Edition"}),"."]}),"\n",(0,i.jsx)(s.h3,{id:"prometheus",children:"Prometheus"}),"\n",(0,i.jsxs)(s.p,{children:["Expose ",(0,i.jsx)(s.a,{href:"https://prometheus.io/",children:"Prometheus"})," metrics for workers and servers on port 8001 at /metrics."]}),"\n",(0,i.jsx)(s.h2,{id:"indexer",children:"Indexer"}),"\n",(0,i.jsx)(s.p,{children:(0,i.jsx)(s.img,{alt:"Indexer",src:t(83
1070).A+"",width:"3018",height:"1714"})}),"\n",(0,i.jsx)(s.h3,{id:"max-index-time-window",children:"Max index time window"}),"\n",(0,i.jsxs)(s.p,{children:["Maximum time window (in days) that the indexer looks back when indexing jobs and service logs. Defaults to 7 days. This caps both the initial population of the index and periodic cleanup \u2014 documents older than the window are not indexed and are evicted on the next refresh cycle. Windmill internally uses ",(0,i.jsx)(s.code,{children:"min(max_index_time_window_secs, retention_period_secs)"})," so the window never exceeds the configured ",(0,i.jsx)(s.a,{href:"#retention-period-in-secs",children:"retention period"}),". Setting the value to 0 disables the time window and falls back to the retention period alone."]}),"\n",(0,i.jsxs)(s.p,{children:["This setting can also be controlled via the ",(0,i.jsx)(s.code,{children:"TANTIVY_MAX_INDEX_TIME_WINDOW__S"})," env var."]}),"\n",(0,i.jsx)(s.h3,{id:"index-writer-memory-budget",children:"Index writer memory budget"}),"\n",(0,i.jsx)(s.p,{children:"The allocated memory arena for the indexer. A bigger value means less writing to disk and potentially higher indexing throughput"}),"\n",(0,i.jsx)(s.h3,{id:"commit-max-batch-size",children:"Commit max batch size"}),"\n",(0,i.jsx)(s.p,{children:'The max amount of documents (here jobs) per commit. To optimize indexing throughput, it is best to keep this as high as possible. However, especially when reindexing the whole instance, it can be useful to have a limit on how many jobs can be written without being committed. A commit will make the jobs available for search, constitute a "checkpoint" state in the indexing and will be logged.'}),"\n",(0,i.jsx)(s.h3,{id:"refresh-index-period",children:"Refresh index period"}),"\n",(0,i.jsx)(s.p,{children:"The index will query new jobs periodically and write them on the index. This setting sets that period in seconds."}),"\n",(0,i.jsx)(s.h3,{id:"max-indexed-job-log-size",children:"Max indexed job log size"}),"\n",(0,i.jsx)(s.p,{children:"Job logs are included when indexing, but to avoid the index size growing artificially, the logs will be truncated after that size (in KB) has been reached."}),"\n",(0,i.jsx)(s.h3,{id:"commit-max-batch-size-1",children:"Commit max batch size"}),"\n",(0,i.jsx)(s.p,{children:'The max amount of documents per commit. In this case 1 document is one log file representing all logs during 1 minute for a specific host. To optimize indexing throughput, it is best to keep this as high as possible. However, especially when reindexing the whole instance, it can be useful to have a limit on how many logs can be written without being committed. A commit will make the logs available for search, appear as a log line, and be a "checkpoint" of the indexing progress.'}),"\n",(0,i.jsx)(s.h3,{id:"refresh-index-period-1",children:"Refresh index period"}),"\n",(0,i.jsx)(s.p,{children:"The index will query new service logs periodically and write them on the index. This setting sets that period in seconds."}),"\n",(0,i.jsx)(s.h2,{id:"telemetry",children:"Telemetry"}),"\n",(0,i.jsxs)(s.p,{children:["Anonymous usage data is collected to help improve Windmill. Telemetry data is sent as a HTTPS request to ",(0,i.jsx)(s.a,{href:"https://stats.windmill.dev",children:"https://stats.windmill.dev"})," once a day."]}),"\n",(0,i.jsx)(s.p,{children:(0,i.jsx)(s.img,{alt:"Telemetry",src:t(9218).A+"",title:"Telemetry",width:"3018",height:"1714"})}),"\n",(0,i.jsxs)(s.p,{children:["The data collected differs between Community Edition and ",(0,i.jsx)(s.a,{href:"/pricing",children:"Enterprise Edition"}),":"]}),"\n",(0,i.jsx)(s.h3,{id:"community-edition",children:"Community Edition"}),"\n",(0,i.jsx)(s.p,{children:"The following information is collected:"}),"\n",(0,i.jsxs)(s.ul,{children:["\n",(0,i.jsx)(s.li,{children:"version of your instance"}),"\n",(0,i.jsx)(s.li,{children:"instance base URL"}),"\n",(0,i.jsx)(s.li,{children:"job usage (language, total duration, count)"}),"\n",(0,i.jsx)(s.li,{children:"login type usage (login type, count)"}),"\n",(0,i.jsx)(s.li,{children:"worker usage (worker, worker instance, vCPUs, memory)"}),"\n",(0,i.jsx)(s.li,{children:"user usage (author count, operator count, the distinct guests of the last 30 days, the seats they add past the free allowance, and the workspaces that allow guests)"}),"\n",(0,i.jsx)(s.li,{children:"development instance status"}),"\n"]}),"\n",(0,i.jsx)(s.p,{children:'Telemetry can be fully disabled from the instance settings using the "Disable telemetry" toggle.'}),"\n",(0,i.jsx)(s.h3,{id:"enterprise-edition",children:"Enterprise Edition"}),"\n",(0,i.jsxs)(s.p,{children:["On ",(0,i.jsx)(s.a,{href:"/pricing",children:"Enterprise Edition"}),", telemetry is required for ",(0,i.jsx)(s.a,{href:"/docs/enterprise/onboarding/#billing",children:"license compliance"}),' and cannot be fully disabled. You can toggle "Minimal telemetry" to reduce the data sent to only what is needed for license compliance. If you have fully air-gapped requirements, ',(0,i.jsx)(s.a,{href:"/docs/enterprise/onboarding/#air-gapped-environments",children:"contact us"})," to arrange an alternative."]}),"\n",(0,i.jsx)(s.p,{children:"When minimal telemetry is enabled, the following is sent:"}),"\n",(0,i.jsxs)(s.ul,{children:["\n",(0,i.jsx)(s.li,{children:"version of your instance"}),"\n",(0,i.jsx)(s.li,{children:"instance base URL"}),"\n",(0,i.jsx)(s.li,{children:"login type usage (login type, count)"}),"\n",(0,i.jsx)(s.li,{children:"worker usage (worker, worker instance, vCPUs, memory)"}),"\n",(0,i.jsx)(s.li,{children:"user usage (author count, operator count, the distinct guests of the last 30 days, the seats they add past the free allowance, and the workspaces that allow guests)"}),"\n",(0,i.jsx)(s.li,{children:"superadmin email addresses"}),"\n",(0,i.jsx)(s.li,{children:"development instance status"}),"\n"]}),"\n",(0,i.jsx)(s.p,{children:"When minimal telemetry is disabled, the following is also collected:"}),"\n",(0,i.jsxs)(s.ul,{children:["\n",(0,i.jsx)(s.li,{children:"job usage (language, total duration, count)"}),"\n"]}),"\n",(0,i.jsxs)(s.p,{children:['You can "Send usage" to manually send usage data to Windmill and monitor it from the ',(0,i.jsx)(s.a,{href:"/docs/enterprise/plans_details/#windmill-customer-portal",children:"Customer portal"}),'. You can also "Download usage" to get a signed copy of the telemetry data as a JSON file named ',(0,i.jsx)(s.code,{children:"windmill-telemetry-{date}-{signature}.json"}),". This is useful for air-gapped instances that cannot send telemetry directly: the file can be inspected before being sent manually to Windmill, and the signature lets Windmill verify it has not been tampered with."]}),"\n",(0,i.jsx)(s.h2,{id:"github-app",children:"GitHub App"}),"\n",(0,i.jsxs)(s.p,{children:["Configure a self-managed GitHub App for GitHub.com, GitHub Enterprise Cloud or GitHub Enterprise Server to enable ",(0,i.jsx)(s.a,{href:"/docs/advanced/git_sync/",children:"Git sync"})," without relying on the Windmill-managed GitHub App via ",(0,i.jsx)(s.code,{children:"stats.windmill.dev"}),"."]}),"\n",(0,i.jsxs)(s.p,{children:["This setting is found under ",(0,i.jsx)(s.strong,{children:"Advanced > GitHub App"})," in Instance Settings and is only available on ",(0,i.jsx)(s.a,{href:"/pricing",children:"Enterprise Edition"}),'. Turn on the "Self-managed GitHub App" toggle to enable the fields below.']}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Field"}),(0,i.jsx)(s.th,{children:"Description"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Base URL"}),(0,i.jsxs)(s.td,{children:["The base URL of your GitHub instance (e.g. ",(0,i.jsx)(s.code,{children:"https://github.com"}),", ",(0,i.jsx)(s.code,{children:"https://<subdomain>.ghe.com"})," or your GHES URL)"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"App ID"}),(0,i.jsx)(s.td,{children:"The ID of your registered GitHub App"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"App Slug"}),(0,i.jsx)(s.td,{children:"The slug of your GitHub App"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Client ID"}),(0,i.jsx)(s.td,{children:"The client ID of your GitHub App"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"App owner"}),(0,i.jsxs)(s.td,{children:["The organization or user that owns the GitHub App. Only needed on GitHub Enterprise Cloud data residency hosts (",(0,i.jsx)(s.code,{children:"*.ghe.com"}),"), whose installation URLs carry the owner"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Private Key (PEM)"}),(0,i.jsx)(s.td,{children:"The private key generated for your GitHub App"})]})]})]}),"\n",(0,i.jsxs)(s.p,{children:["Once the app is configured, a ",(0,i.jsx)(s.strong,{children:"Worksp
1ace assignments"})," panel appears below the fields. Click ",(0,i.jsx)(s.strong,{children:"Refresh"})," to list the installations the app can see on your GitHub instance, and assign them to workspaces. This lets a superadmin link installations to workspaces directly, so workspace users do not need GitHub permissions to set up sync. It is also the recovery path for installations that were created without the app's Setup URL configured."]}),"\n",(0,i.jsx)(s.p,{children:'Installations assigned this way are tagged "Provisioned by admin" in the workspace Git sync settings and can only be removed from here, not by workspace admins.'}),"\n",(0,i.jsxs)(s.p,{children:["For setup instructions, see ",(0,i.jsx)(s.a,{href:"/docs/integrations/git_repository#self-managed-github-app",children:"Self-managed GitHub App"}),"."]}),"\n",(0,i.jsx)(s.h3,{id:"webhook-base-url",children:"Webhook base url"}),"\n",(0,i.jsxs)(s.p,{children:["Base url your git host delivers ",(0,i.jsx)(s.a,{href:"/docs/advanced/git_sync/#webhooks",children:"Git sync webhooks"})," to, without trailing slash. When empty, the ",(0,i.jsx)(s.a,{href:"#base-url",children:"base url"})," is used. Set it, for the managed and self-managed GitHub Apps and for ",(0,i.jsx)(s.a,{href:"/docs/integrations/git_repository#gitlab",children:"GitLab"})," alike, when the git host cannot reach your instance on the url your users' browsers use."]}),"\n",(0,i.jsx)(s.p,{children:"Configure it before connecting any repository: changing it later does not move the webhooks the git host already holds, and the setting then lists the workspaces whose Git sync settings must be re-saved to move them."}),"\n",(0,i.jsx)(s.h2,{id:"db-health",children:"DB Health"}),"\n",(0,i.jsxs)(s.p,{children:["The DB Health diagnostic dashboard provides on-demand insights into your Windmill database. It is available under ",(0,i.jsx)(s.strong,{children:"Monitoring > DB Health"})," in Instance Settings and is accessible to superadmins only."]}),"\n",(0,i.jsxs)(s.p,{children:["Click ",(0,i.jsx)(s.strong,{children:"Run Diagnostics"})," to execute a set of lightweight, read-only queries against your database. Results are displayed in collapsible sections with green/yellow/red status indicators."]}),"\n",(0,i.jsx)(s.p,{children:(0,i.jsx)(s.img,{alt:"DB Health",src:t(50100).A+"",title:"DB Health dashboard",width:"1193",height:"1446"})}),"\n",(0,i.jsx)(s.h3,{id:"diagnostics",children:"Diagnostics"}),"\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Section"}),(0,i.jsx)(s.th,{children:"What it shows"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.strong,{children:"Database Size"})}),(0,i.jsx)(s.td,{children:"Total database size and top 15 tables by size"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.strong,{children:"Job Retention"})}),(0,i.jsxs)(s.td,{children:["Oldest completed job age vs configured ",(0,i.jsx)(s.code,{children:"retention_period_secs"}),", total completed job count. Green if cleanup is keeping up, yellow/red if jobs are accumulating beyond the retention window"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.strong,{children:"Large Job Results"})}),(0,i.jsxs)(s.td,{children:["Top 10 largest ",(0,i.jsx)(s.code,{children:"result"})," payloads (by ",(0,i.jsx)(s.code,{children:"pg_column_size"}),") among recently scanned jobs, plus average result size. Only results > 1 KB are listed"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.strong,{children:"Connection Pool"})}),(0,i.jsxs)(s.td,{children:["SQLx pool size, idle connections, max connections, and active PostgreSQL connections from ",(0,i.jsx)(s.code,{children:"pg_stat_activity"}),". Green below 80% utilization, yellow below 95%, red at 95%+"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.strong,{children:"Table Maintenance"})}),(0,i.jsx)(s.td,{children:"Top 15 tables by dead tuples with dead/live ratio, last autovacuum and autoanalyze timestamps. Red when dead tuple ratio exceeds 30%"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.strong,{children:"Slow Queries"})}),(0,i.jsxs)(s.td,{children:["Top 10 queries by mean execution time from ",(0,i.jsx)(s.code,{children:"pg_stat_statements"}),". If the extension is not installed, a message suggests enabling it"]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:(0,i.jsx)(s.strong,{children:"Datatables"})}),(0,i.jsxs)(s.td,{children:["Instance-stored datatables with per-table size and estimated row count from ",(0,i.jsx)(s.code,{children:"pg_class"})]})]})]})]}),"\n",(0,i.jsx)(s.h3,{id:"scan-limit",children:"Scan limit"}),"\n",(0,i.jsxs)(s.p,{children:["Use the ",(0,i.jsx)(s.strong,{children:"Scan last N jobs"}
1)," dropdown to control how many recent completed jobs are scanned for the large results analysis. The default is 10,000. Higher values give more complete results but take longer on large databases. The allowed range is 1,000 to 1,000,000."]})]})}function u(e={}){let{wrapper:s}={...(0,r.R)(),...e.components};return s?(0,i.jsx)(s,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},69201(e,s,t){"use strict";t.d(s,{A:()=>n});let n=t.p+"assets/images/admins_workspace-c2d010f0187d17a0ecb72a520b5426e9.png"},48666(e,s,t){"use strict";t.d(s,{A:()=>n});let n=t.p+"assets/images/alerts-d357e6d4233d63906332b12cfac12e15.png"},18888(e,s,t){"use strict";t.d(s,{A:()=>n});let n=t.p+"assets/images/core_settings-522740f5a562e86451e573f852f634f4.png"},33313(e,s,t){"use strict";t.d(s,{A:()=>n});let n=t.p+"assets/images/critical_alerts_channels-7be9a19c7e770636ec0cf9021943f2c5.png"},50100(e,s,t){"use strict";t.d(s,{A:()=>n});let n=t.p+"assets/images/db_health-86bd3546b38a589d2fb00fadca4316d0.png"},65591(e,s,t){"use strict";t.d(s,{A:()=>n});let n=t.p+"assets/images/global_users-428be23a7e81821c48832bef64f0d2c9.png"},50370(e,s,t){"use strict";t.d(s,{A:()=>n});let n=t.p+"assets/images/http_traces_tab-975918c02a9b122a97587b80a736a938.png"},83070(e,s,t){"use strict";t.d(s,{A:()=>n});let n=t.p+"assets/images/indexer-0448fcafce7c494a132234f3ce35c56a.png"},45119(e,s,t){"use strict";t.d(s,{A:()=>n});let n=t.p+"assets/images/instance_version-bc4ece6887729d3da3b102984cbaacf9.png"},29722(e,s,t){"use strict";t.d(s,{A:()=>n});let n=t.p+"assets/images/oauth-92c8891d1b205ca56ef4f7a33d1d2b5b.png"},13106(e,s,t){"use strict";t.d(s,{A:()=>n});let n=t.p+"assets/images/otel_prometheus-da550f3fa6dad7be963ded758b643f8b.png"},2706(e,s,t){"use strict";t.d(s,{A:()=>n});let n=t.p+"assets/images/registries-d37be1d10300d696a1026d6ab23bfd43.png"},35967(e,s,t){"use strict";t.d(s,{A:()=>n});let n=t.p+"assets/images/scim_saml-818992600accded1879edd7c5e5839e8.png"},2678(e,s,t){"use strict";t.d(s,{A:()=>n});let n=t.p+"assets/images/sso-c8878b14ca838413640c0c84dde344a2.png"},68366(e,s,t){"use strict";t.d(s,{A:()=>n});let n=t.p+"assets/images/teams_critical_alert-d2cdd998d3e273bfc51dfba5488cc3c3.png"},9218(e,s,t){"use strict";t.d(s,{A:()=>n});let n=t.p+"assets/images/telemetry-8123f159b1b471502f9f2f27f3f3fd8a.png"},36299(e,s,t){"use strict";t.d(s,{A:()=>n});let n=t.p+"assets/images/s3_azure_cache-c7b2a9669d5891f6e522f31ad2d8de7d.png"},57250(e,s,t){"use strict";t.d(s,{A:()=>o});var n=t(74848);t(96540);var i=t(34164),r=t(57663);function a({children:e,className:s,hidden:t}){return(0,n.jsx)("div",{role:"tabpanel",className:(0,i.A)("tabItem_Ymn6",s),hidden:t,children:e})}function o({children:e,className:s,value:t}){let{selectedValue:i,lazy:l}=(0,r.uc)(),d=t===i;return!d&&l?null:(0,n.jsx)(a,{className:s,hidden:!d,children:e})}},50773(e,s,t){"use strict";t.d(s,{A:()=>u});var n=t(74848);t(96540);var i=t(34164),r=t(88287),a=t(57663),o=t(28584),l=t(19863);function d({className:e}){let{selectedValue:s,selectValue:t,tabValues:r,block:l}=(0,a.uc)(),c=[],{blockElementScrollPositionUntilNextRender:h}=(0,o.a_)(),u=e=>{let n=e.currentTarget,i=r[c.indexOf(n)].value;i!==s&&(h(n),t(i))},p=e=>{let s=null;switch(e.key){case"Enter":u(e);break;case"ArrowRight":{let t=c.indexOf(e.currentTarget)+1;s=c[t]??c[0];break}case"ArrowLeft":{let t=c.indexOf(e.currentTarget)-1;s=c[t]??c[c.length-1]}}s?.focus()};return(0,n.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,i.A)("tabs",{"tabs--block":l},e),children:r.map(({value:e,label:t,attributes:r})=>(0,n.jsx)("li",{role:"tab",tabIndex:s===e?0:-1,"aria-selected":s===e,ref:e=>{c.push(e)},onKeyDown:p,onClick:u,...r,className:(0,i.A)("tabs__item","tabItem_LNqP",r?.className,{"tabs__item--active":s===e}),children:t??e},e))})}function c({children:e}){return(0,n.jsx)("div",{className:"margin-top--md",children:e})}function h({className:e,children:s}){return(0,n.jsxs)("div",{className:(0,i.A)(r.G.tabs.container,"tabs-container","tabList__CuJ"),children:[(0,n.jsx)(d,{className:e}),(0,n.jsx)(c,{children:s})]})}function u(e){let s=(0,l.A)(),t=(0,a.OC)(e);return(0,n.jsx)(a.O_,{value:t,children:(0,n.jsx)(h,{className:e.className,children:(0,a.vT)(e.children)})},String(s))}},57663(e,s,t){"use strict";t.d(s,{OC:()=>u,O_:()=>x,uc:()=>g,vT:()=>c});var n=t(74848),i=t(96540),r=t(56347),a=t(99989),o=t(96629),l=t(80618),d=t(41367);function c(e){return i.Children.toArray(e).filter(e=>"\n"!==e)}function h({value:e,tabValues:s}){return s.some(s=>s.value===e)}function u(e){let s,{defaultValue:t,queryString:n=!1,groupId:c}=e,u=function(e){let{values:s,children:t}=e;return(0,i.useMemo)(()=>{let e=s??i.Children.toArray(t).flatMap(e=>{if(!e)return[];if((0,i.isValidElement)(e)&&function(e){let{props:s}=e;return!!s&&"object"==typeof s&&"value"in s}(e))return[e];
1let s="string"==typeof e.type?e.type:e.type.name;throw Error(`Docusaurus error: Bad <Tabs> child <${s}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.
2If you do not want to pass on a "value" prop to the direct children of <Tabs>, you can also pass an explicit <Tabs values={...}> prop.`)}).map(({props:{value:e,label:s,attributes:t,default:n}})=>({value:e,label:s,attributes:t,default:n})),n=(0,l.XI)(e,(e,s)=>e.value===s.value);if(n.length>0)throw Error(`Docusaurus error: Duplicate values "${n.map(e=>`'${e.value}'`).join(", ")}" found in <Tabs>. Every value needs to be unique.`);return e},[s,t])}(e),[p,g]=(0,i.useState)(()=>(function({defaultValue:e,tabValues:s}){if(0===s.length)throw Error("Docusaurus error: the <Tabs> component requires at least one <TabItem> children component");if(e){if(!h({value:e,tabValues:s}))throw Error(`Docusaurus error: The <Tabs> has a defaultValue "${e}" but none of its children has the corresponding value. Available values are: ${s.map(e=>e.value).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return e}let t=s.find(e=>e.default)??s[0];if(!t)throw Error("Unexpected error: 0 tabValues");return t.value})({defaultValue:t,tabValues:u})),[x,m]=function({queryString:e=!1,groupId:s}){let t=(0,r.W6)(),n=function({queryString:e=!1,groupId:s}){if("string"==typeof e)return e;if(!1===e)return null;if(!0===e&&!s)throw Error('Docusaurus error: The <Tabs> component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return s??null}({queryString:e,groupId:s});return[(0,o.aZ)(n),(0,i.useCallback)(e=>{if(!n)return;let s=new URLSearchParams(t.location.search);s.set(n,e),t.replace({...t.location,search:s.toString()})},[n,t])]}({queryString:n,groupId:c}),[j,f]=function({groupId:e}){let s=e?`docusaurus.tab.${e}`:null,[t,n]=(0,d.Dv)(s);return[t,(0,i.useCallback)(e=>{s&&n.set(e)},[s,n])]}({groupId:c}),b=h({value:s=x??j,tabValues:u})?s:null;return(0,a.A)(()=>{b&&g(b)},[b]),{selectedValue:p,selectValue:(0,i.useCallback)(e=>{if(!h({value:e,tabValues:u}))throw Error(`Can't select invalid tab value=${e}`);g(e),m(e),f(e)},[m,f,u]),tabValues:u,lazy:e.lazy??!1,block:e.block??!1}}let p=(0,i.createContext)(null);function g(){let e=i.useContext(p);if(!e)throw Error("useTabsContext() must be used within a Tabs component");return e}function x(e){return(0,n.jsx)(p.Provider,{value:e.value,children:e.children})}},78410(e,s,t){"use strict";t.d(s,{A:()=>a});var n=t(74848),i=t(46942),r=t.n(i);function a({title:e,description:s,href:t,Icon:i,color:o="blue",target:l}){return(0,n.jsxs)("a",{href:t,className:r()("rounded-md p-8 border border-gray-100 dark:border-gray-800 shadow-sm transition-all cursor-pointer flex flex-col gap-2 !no-underline overflow-hidden",{blue:"hover:bg-blue-100 hover:dark:bg-blue-900/50 hover:border-blue-500 dark:hover:border-blue-600 ",teal:"hover:bg-teal-100 hover:dark:bg-teal-900/50 hover:border-teal-500 dark:hover:border-teal-600 ",orange:"hover:bg-orange-100 hover:dark:bg-orange-900/50 hover:border-orange-500 dark:hover:border-orange-600 "}[o]),target:l,children:[(0,n.jsxs)("div",{className:"flex flex-row gap-4 items-center",children:[void 0!==i&&(0,n.jsx)(i,{size:32,className:r()("rounded-md p-2",{blue:"bg-blue-100 text-blue-600 dark:bg-blue-500 dark:text-blue-100",teal:"bg-teal-100 text-teal-600 dark:bg-teal-600 dark:text-teal-100",orange:"bg-orange-200 text-orange-600 dark:bg-orange-600 dark:text-orange-100"}[o])}),(0,n.jsx)("div",{className:"text-lg font-semibold text-gray-800 dark:text-gray-100",children:e})]}),(0,n.jsx)("div",{className:"text-sm text-gray-500 dark:text-gray-200",children:s})]})}t(96540)},46942(e){!function(){"use strict";var s={}.hasOwnProperty;function t(){for(var e="",i=0;i<arguments.length;i++){var r=arguments[i];r&&(e=n(e,function(e){if("string"==typeof e||"number"==typeof e)return e;if("object"!=typeof e)return"";if(Array.isArray(e))return t.apply(null,e);if(e.toString!==Object.prototype.toString&&!e.toString.toString().includes("[native code]"))return e.toString();var i="";for(var r in e)s.call(e,r)&&e[r]&&(i=n(i,r));return i}(r)))}return e}
2function n(e,s){return s?e?e+" "+s:e+s:e}e.exports?(t.default=t,e.exports=t):"function"==typeof define&&"object"==typeof define.amd&&define.amd?define("classnames",[],function(){return t}):window.classNames=t}()},28453(e,s,t){"use strict";t.d(s,{R:()=>a,x:()=>o});var n=t(96540);let i={},r=n.createContext(i);function a(e){let s=n.useContext(r);return n.useMemo(function(){return"function"==typeof e?e(s):{...s,...e}},[s,e])}function o(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),n.createElement(r.Provider,{value:s},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.