--- url: /nodepit.md description: >- Search, discover, and install KNIME nodes and workflows on the NodePit platform. --- # NodePit NodePit is a platform for the KNIME ecosystem. It started in 2017 as a search engine for KNIME nodes and workflows and has since grown into a broader suite of tools for KNIME users and developers — including a curated catalog of extensions, workflow discovery, and the [NodePit Runner](../runner/) for workflow automation. Visit [nodepit.com](https://nodepit.com) to explore the full platform. ## Node Catalog NodePit indexes and makes searchable every publicly available KNIME node across all extensions and KNIME versions. Search by name, category, or keyword to find the right node for your workflow. Each node page shows the description, ports, configuration options, related workflows, and installation instructions. ## Workflow Search NodePit lets you search for and browse published KNIME workflows. Workflow pages link back to the nodes they use — making it easy to discover new nodes in the context of real examples. ## Nodes & Extensions NodePit develops and maintains a growing portfolio of KNIME extension packages covering popular APIs and services. Extensions are distributed as native KNIME nodes — no Python runtime, no wrapped components. See [Nodes & Extensions](../extensions/) for the full catalog and installation instructions. ## NodePit for KNIME NodePit for KNIME is a plugin that brings the NodePit node catalog directly into your KNIME Analytics Platform. Browse, search, and install nodes without leaving KNIME. Find it on the [NodePit for KNIME product page](https://nodepit.com/product/nodepit). ## NodePit Space NodePit Space is a WebDAV-based storage for KNIME workflows, available to every registered user at `https://nodepit.com/space/`. Connect to it from KNIME Analytics Platform as a remote workflow repository using your NodePit username and password. Each Space has two areas: * **Private** — the root of your Space, readable only by you. Use it to store and sync workflows across machines. * **Public** (`/public` sub-folder) — visible to anyone. Workflows uploaded here are indexed by NodePit and appear in the workflow search results. ## NodePit Runner NodePit Runner is the workflow automation platform that lets you deploy, schedule, and monitor KNIME workflows without KNIME Server. See the [Runner documentation](../runner/) for details. --- --- url: /extensions.md description: >- Browse and install NodePit's portfolio of KNIME extensions for third-party APIs and services. --- # Nodes & Extensions NodePit develops and maintains a portfolio of KNIME extension packages. Each extension provides native KNIME nodes for a specific API or service — ready to use in any workflow without additional runtime dependencies. Available extensions include integrations for OpenAI, DeepL, Spotify, Sentry, and more. Browse the full catalog at [nodepit.com/product](https://nodepit.com/product). ## Installing Extensions All NodePit extensions are distributed via the NodePit update site. You only need to add the update site once; after that, every NodePit extension is available to install through the KNIME extension manager. **Add the NodePit update site:** 1. Open KNIME Analytics Platform. 2. Go to **File → Preferences → Install/Update → Available Software Sites**. 3. Click **Add …** and enter the NodePit update site URL — you can find it on the extension's product page at [nodepit.com](https://nodepit.com). 4. Confirm with **OK**. **Install an extension:** 1. Go to **File → Install KNIME Extensions …** 2. Search for the extension by name. 3. Select it, click **Next →**, and follow the prompts. 4. Restart KNIME when asked. The installed nodes appear in the KNIME node repository under the extension's category immediately after restart. ## Building Your Own Extensions If you need nodes for an API that is not yet covered, see [For Developers](../developers/) — [Node Generator](../developers/node-generator/) can turn any OpenAPI or Swagger specification into a ready-to-distribute KNIME extension in minutes, and [Publishing Extensions](../developers/publishing-extensions.md) covers hosting and listing it on NodePit yourself. --- --- url: /developers.md description: Build KNIME extensions with Node Generator and publish them on NodePit. --- # For Developers Beyond browsing and installing NodePit's own extensions, you can build KNIME extensions of your own and, optionally, distribute them through NodePit. This section covers both halves of that: building, then publishing. ## Build extensions [Node Generator](./node-generator/) converts any OpenAPI or Swagger specification into a complete, native KNIME extension — no coding required. See the [Overview](./node-generator/) to get started, or the [CLI Reference](./node-generator/cli-reference.md) for the full set of options. ## Publish extensions [Publishing Extensions](./publishing-extensions.md) covers hosting your extension's update site and product page on NodePit — whether it was built with Node Generator or by hand. --- --- url: /developers/node-generator.md description: >- Convert an OpenAPI or Swagger specification into a native KNIME extension, no coding required. --- # Node Generator Node Generator converts any [OpenAPI](https://www.openapis.org) or Swagger specification into a set of native KNIME nodes. Feed it a YAML or JSON spec — from a local file or a URL — and it produces a complete Maven project including node dialogs, authentication nodes, response mapping, and a P2 update site ready to install in KNIME. Node Generator is a free command-line tool built and maintained by NodePit. ## Requirements * **Java JDK 17** or higher — [Adoptium Temurin](https://adoptium.net/temurin/releases/?version=17) is recommended. * **Apache Maven** — see the [Maven installation guide](https://maven.apache.org/install.html). ## Quick Start **1. Download the JAR** Download [nodegenerator.jar](https://download.nodepit.com/nodegenerator/nodegenerator.jar) from the NodePit download server, or use curl: ```bash curl -O https://download.nodepit.com/nodegenerator/nodegenerator.jar ``` **2. Run the generator** Pass the location of your OpenAPI or Swagger specification — a local file path or a URL: ```bash java -jar nodegenerator.jar https://petstore.swagger.io/v2/swagger.json ``` Node Generator writes the generated project to a `generated/` directory. Use `--destination` to change the output path. **3. Build the update site** ```bash cd generated mvn clean verify ``` Maven compiles the generated Java code and produces a P2 update site at `generated/p2/target/repository`. **4. Install the nodes in KNIME** 1. Open KNIME Analytics Platform. 2. Go to **File → Preferences → Install/Update → Available Software Sites**. 3. Click **Add …**, then **Local …**, and point to the `p2/target/repository` directory. 4. Go to **File → Install KNIME Extensions …**, find your nodes by name, and install them. 5. Restart KNIME when prompted. ## Distributing via NodePit If you want to distribute your extension through the NodePit catalog, contact . Once set up, use `--nodepit-product ` to configure automated publishing as part of the generated CI pipeline — see [Publishing Extensions](../publishing-extensions.md) for what this uploads and how to do it manually. For a full list of all available options, see the [CLI Reference](./cli-reference.md). --- --- url: /developers/node-generator/cli-reference.md description: >- All command-line options for nodegenerator.jar, grouped by input, output, and authentication. --- # CLI Reference This page documents all command-line options for `nodegenerator.jar`. Run `java -jar nodegenerator.jar` without arguments to print the built-in help, which is always authoritative for the installed version. Options marked *(repeatable)* can be specified multiple times. ## Input | Option | Description | | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `SPEC` | Path or URL to the OpenAPI/Swagger spec. Required. Accepts local file paths and HTTP(S) URLs; URLs may include `username:password` for basic authentication. Specify multiple specs to merge them. | ## Output | Option | Default | Description | | -------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | `--destination ` | `generated` | Directory to write the generated project into. | | `--plugin-folder ` | `plugin` | Sub-folder within the destination for the generated plugin code. | | `--write-ignore ` | — | Gitignore-style glob — matching files are not written. Useful for preserving hand-edited support files such as `feature.xml` or CI config. *(repeatable)* | ## Identity & Versioning | Option | Default | Description | | -------------------------------- | ----------------------- | -------------------------------------------------------------------------------------------- | | `--title ` | From spec | Plugin title shown in KNIME and on the update site. | | `--namespace <namespace>` | Derived from server URL | Java package namespace, e.g. `com.example.nodes`. | | `--plugin-namespace <namespace>` | Same as `--namespace` | Separate namespace for the generated plugin bundle, if different from the API namespace. | | `--plugin-version <version>` | `0.0.1` | Plugin version number (SemVer). | | `--knime-version <version>` | `5.9` | Minimum supported KNIME version. The compatible version ceiling is determined automatically. | ## Node & Category Appearance | Option | Description | | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | `--node-icon <png-file>` | 16×16 px PNG file to use as the icon for all generated operation nodes. | | `--category-name <name>` | Root category name in the KNIME node repository. Defaults to the spec title. | | `--category-icon <png-file>` | 16×16 px PNG file to use as the root category icon. | | `--root-categories <id>=<name>` | One or more category levels to nest the generated nodes under. Syntax: `root-id=Root Category\|parent-id=Sub Category`. | | `--update-site-category-label <label>` | Category label shown in the KNIME update site listing. Defaults to the title. | | `--primary-color <hex>` | Hex color (without `#`) used for node port colouring. Default: `BCC6CC`. | | `--splash-icon-48 <png-file>` | 48×48 px splash screen icon. Required together with `--splash-icon-32` and `--splash-icon-24`. | | `--splash-icon-32 <png-file>` | 32×32 px splash screen icon. | | `--splash-icon-24 <png-file>` | 24×24 px splash screen icon. | | `--product-icon <svg-file>` | SVG icon used on the OAuth authorisation page. | ## Node Name Transformations | Option | Description | | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | | `--trim-names <regex>` | Regex pattern stripped from node and category names before display. Useful for removing common prefixes such as an API name. *(repeatable)* | | `--pretty-name <original>=<pretty>` | Override the generated display name for a specific operation or parameter. *(repeatable)* | | `--disable-grouping` | Place all generated operation nodes directly in the root category rather than grouping them by spec tags. | | `--alphabetically-sorted-nodes` | Sort nodes alphabetically. Enabled by default; pass `--alphabetically-sorted-nodes=false` to preserve spec order. | ## Filtering | Option | Description | | ---------------------------------------- | ------------------------------------------------------------------------ | | `--exclude-operation <operation-id>` | Skip generating a node for the given operation ID. *(repeatable)* | | `--exclude-tag <tag-name>` | Skip all operations that carry the given tag. *(repeatable)* | | `--exclude-parameter <param-name>` | Omit the given parameter from all nodes. *(repeatable)* | | `--exclude-response-type <content-type>` | Omit the given response content type, e.g. `text/html`. *(repeatable)* | | `--exclude-property <property-name>` | Exclude a response property from automatic table mapping. *(repeatable)* | ## Authentication | Option | Default | Description | | ---------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ | | `--oauth-client-id <id>` | — | OAuth 2.0 client ID to embed in the generated auth node. | | `--oauth-client-secret <secret>` | — | OAuth 2.0 client secret. | | `--oauth-redirect-url <url>` | `http://localhost:54321` | OAuth redirect URL including protocol and port. Must not include a path component. | | `--oauth-permanent-scope <scope>` | — | OAuth scope always added to every authorisation request, e.g. `offline_access`. *(repeatable)* | | `--api-key-prefix <name>=<prefix>` | — | Prefix prepended to an API key before it is sent. Syntax: `Authorization=Token` produces the header `Authorization: Token <key>`. *(repeatable)* | ## Table Mapping By default, generated nodes expose the raw JSON response. Enable table mapping to have Node Generator automatically convert JSON responses into KNIME table rows. | Option | Default | Description | | ------------------------------------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------ | | `--enable-default-table-mapping` | Off | Enables automatic response-to-table mapping for all operations. | | `--default-table-mapping-operation-id-pattern <regex>` | `.*` | Applies default table mapping only to operations whose ID matches the pattern, e.g. `^list.*` for list operations. | | `--default-table-mapping-path <path>` | — | JSON property path within the response to use as the table source, e.g. `data`. | For per-operation control, use the `x-nodepit-mapping` extension directly in your spec. ## Networking | Option | Default | Description | | ------------------------------------- | ------- | ------------------------------------------------------------------------- | | `--default-network-timeout <seconds>` | `10` | Default connect, read, and write timeout for all generated HTTP requests. | ## Node UI Style | Option | Default | Description | | -------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------- | | `--target-type <type>` | `classic` | Node UI style. `classic` generates AWT-based nodes compatible with all supported KNIME versions. `modern` generates WebUI nodes (beta). | | `--ignore-ssl-errors-node` | Off | Generate a configuration node that allows ignoring SSL errors. Only available with `--target-type modern`. | ## NodePit Publishing Configure these options to integrate the generated project with the NodePit distribution pipeline via the generated CI scripts. | Option | Description | | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `--nodepit-product <product-id>` | NodePit product identifier. When set, the generated CI pipeline uploads the update site, product page, and changelog to NodePit. Requires CI/CD secrets to be configured. | | `--nodepit-disable-update-site` | Disables update site upload even when `--nodepit-product` is set. | | `--nodepit-disable-documentation` | Disables documentation upload even when `--nodepit-product` is set. | Contact <mail@nodepit.com> to set up a NodePit product listing. ## Licensing Node Generator can embed NodePit Licensing support into the generated plugin. | Option | Description | | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `--license-public-key <gpg-file>` | GPG public key used by the NodePit Licensing Plugin to validate licenses. Enables license enforcement in the generated nodes. | | `--license-icon <png-file>` | 16×16 px PNG icon displayed in the license UI. | | `--license-server-only` | Enforce license checks only on KNIME server environments; local installs can run without a license. | | `--preferences-name <name>` | Label for the generated preferences page. Defaults to the title. Only generated when licensing is enabled. | | `--preferences-icon <png-file>` | 16×16 px PNG icon for the preferences page. | ## Contact Metadata These values are embedded in the generated plugin's `feature.xml` and product metadata. | Option | Default | | ----------------------------- | --------------------- | | `--contact-name <name>` | `NodePit` | | `--contact-address <address>` | `Bienertstraße 33` | | `--contact-zip <zip>` | `01187` | | `--contact-city <city>` | `Dresden` | | `--contact-country <country>` | `Germany` | | `--contact-state <state>` | — | | `--contact-email <email>` | `mail@nodepit.com` | | `--contact-website <url>` | `https://nodepit.com` | ## CI/CD & Project Structure | Option | Default | Description | | ------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------- | | `--source-code-hoster <hoster>` | `gitlab` | CI/CD pipeline to generate. Accepted values: `gitlab`, `github`. Can be specified for both simultaneously. | | `--extra-module <module-name>` | — | Add an extra Maven module to the root `pom.xml` and the CI build paths. *(repeatable)* | | `--extra-gitignore <pattern>` | — | Add an extra entry to the generated `.gitignore`. *(repeatable)* | | `--extra-plugin <plugin-id>` | — | Add an extra OSGi plugin entry to `feature.xml`. *(repeatable)* | ## Advanced | Option | Description | | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------- | | `--test-workflows` | Generate a `testflowrunner/` directory with the structure for automated KNIME test workflows. | | `--test-workflows-preferences <epf-file>` | Preferences file to use during test workflow execution. | | `--node-migrations` | Generate a migration fragment module for evolving node settings across plugin versions. | | `--node-fragment` | Generate a fragment module for implementing custom nodes that extend the generated plugin. | | `--example-default-fallback` | Use the example value from the spec as the default value in node dialogs when no explicit default is defined. | --- --- url: /developers/publishing-extensions.md description: Put a KNIME extension on the NodePit product catalog and host its update site. --- # Publishing Extensions Publishing an extension to NodePit puts it on the [product catalog](https://nodepit.com/product) with its own product page, and hosts its KNIME update site so users can [install it](../extensions/index.md#installing-extensions) directly from KNIME. This applies to any KNIME extension — whether it was built with [Node Generator](./node-generator/) or by hand. ## Quick Start 1. Get your product ID, edit token, and SFTP credentials — see [Prerequisites](#prerequisites). 2. Build your extension's update site and upload it over SFTP — see [Update site](#update-site). 3. Set your product page's name, description, and other content via the REST API — see [Product page](#product-page). 4. Wait for NodePit to crawl and index your update site; your product page goes live once that's done — see [Going live](#going-live). These steps can happen in any order except the last — do them all before waiting on step 4. ## Prerequisites Publishing is set up by NodePit staff, not self-service. Contact <mail@nodepit.com> to get: * **A product registered** — this assigns your extension a product ID, the slug it's addressed by on nodepit.com and in the upload commands below. Your product page will live at `https://nodepit.com/product/<product-id>`, starting out hidden. * **A product edit token** — authenticates updates to your product page's content and metadata. * **SFTP credentials** — a username and password for uploading update site files. Keep the edit token and SFTP password secret — anyone with either can overwrite your product page or update site. ## Product page Your product page (`https://nodepit.com/product/<product-id>`) is the landing page for your extension — it's what users see when they click through from a search result or the catalog, and where they find the update site URL to install it. It also shows up as a card on the [product catalog](https://nodepit.com/product) itself; that card is built from just `icon`, `name`, `description`, and `style.color1`/`color2`, so those four are worth getting right even if you don't touch anything else. Everything on your product page — content and metadata alike — is a field on a single REST endpoint: `PATCH https://nodepit.com/api/products/<product-id>`, authenticated with your product edit token as a bearer token. Send only the fields you're updating in each request. Object fields — currently just `style` — are replaced wholesale rather than merged: if you PATCH `style` with only `color1`, any previously set `backgroundImageUrl` or `badgeColor` is lost. Include every `style` sub-field you want to keep in each request. | Field | Purpose | Format | | -------------------------- | -------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | | `name` | Product title | String | | `description` | Tagline shown in listings and search | String | | `text` | Full product page body | Markdown, see below | | `changelog` | Version history — badge and release feed | Keep a Changelog, see below | | `license` | License terms | Markdown, no required structure | | `faq` | Frequently asked questions | Q\&A, see below | | `contact` | Legal/support contact shown on the page | Object — `name` and `email` required if set at all | | `style.color1` / `color2` | Card and header gradient, top-left to bottom-right | Hex colors | | `style.backgroundImageUrl` | Overrides the gradient with an image | URL, optional — set to `""` to remove | | `style.badgeColor` | Badge color, falls back to `color1` if unset | Hex color, optional — set to `""` to remove | | `instructions` | Extra post-install setup section, beyond the update site | Markdown, optional — set to `""` to remove | | `icon` | Product icon, same as set at registration | SVG markup string (or `iconBase64` for a raster image); the page crops it into a circle, so keep the artwork centered | **`text`** is rendered as-is, with any headings becoming sidebar nav anchors. It supports the `{{NODEPIT_KNIME_VERSION}}` placeholder, substituted with the current KNIME release at render time. **`changelog`** must follow [Keep a Changelog](https://keepachangelog.com) exactly: one `# Title`; one `## [Version] - YYYY-MM-DD` heading per release; `### Added`/`Changed`/`Deprecated`/`Removed`/`Fixed`/`Security`/`Info` sub-headings (others still parse, just render without a badge); changes as `- ` list items. HTML comments are stripped before parsing. **`faq`** treats each `## Question` heading as a question, with the markdown up to the next `##` as its answer. Multi-line fields (`text`, `changelog`, `license`, `faq`, `instructions`) are easiest to update by reading from a local markdown file rather than hand-escaping JSON. On macOS/Linux, `jq` builds the request body for you: ```bash curl -X PATCH "https://nodepit.com/api/products/<product-id>" \ -H "Authorization: Bearer <product-edit-token>" \ -H "Content-Type: application/json" \ --data "$(jq -n --rawfile changelog CHANGELOG.md '{changelog: $changelog}')" ``` On Windows, PowerShell's `ConvertTo-Json` does the same, and `Invoke-RestMethod` replaces `curl`: ```powershell $uri = "https://nodepit.com/api/products/<product-id>" $headers = @{ Authorization = "Bearer <product-edit-token>" } $body = @{ changelog = Get-Content -Raw CHANGELOG.md } | ConvertTo-Json Invoke-RestMethod -Method Patch -Uri $uri -Headers $headers ` -ContentType "application/json" -Body $body ``` Swap `changelog`/`CHANGELOG.md` for the field and file you're updating — e.g. `text`/`PRODUCT.md`, `license`/`LICENSE.md`, `faq`/`FAQ.md`. Short plain-string fields like `name` and `description` don't need this — inline them directly: ```bash curl -X PATCH "https://nodepit.com/api/products/<product-id>" \ -H "Authorization: Bearer <product-edit-token>" \ -H "Content-Type: application/json" \ --data '{"name": "...", "description": "..."}' ``` ## Update site Build your extension's P2 update site — with Node Generator this is `mvn clean verify` from the generated project, producing a zip under `p2/target/` and an unzipped copy at `p2/target/repository`. The update site is hosted over plain SFTP (there is no REST API for this part), so any SFTP client works — on Windows, [WinSCP](https://winscp.net) or the `sftp.exe` that ships with Windows 10 and later are both fine. Connect to `nodepit.com` on **port 2222** with your SFTP username and password, then, under `update-site/`: 1. Upload the zip itself as `update-site/<label>.zip`, overwriting any existing file. 2. Upload the contents of `p2/target/repository` into `update-site/<label>/`, overwriting existing files. `<label>` becomes part of the published update site's URL, symlinked on the server, and is served at `https://download.nodepit.com/<product-id>/<label>` — the URL users add as a KNIME "Available Software Site". NodePit conventionally labels update sites by the KNIME release they target (e.g. `5.9`), since a KNIME extension's compatibility is usually pinned to a KNIME version rather than its own release cadence — but a semantic version (e.g. `1.0.0`) works too if that fits your extension better. ## Example workflows and assets Your SFTP account has folders for images or other static files (`assets/`) and example KNIME workflows (`workflows/`) to reference from your product page. Upload into them the same way you'd upload the [update site](#update-site) — same SFTP connection, different folder. Files show up at `https://download.nodepit.com/workflows/<product-id>/<path>` and `https://download.nodepit.com/assets/<product-id>/<path>` respectively. Link to them directly from your `text`, `faq`, `changelog`, or `instructions` markdown — e.g. `![Example workflow](https://download.nodepit.com/assets/<product-id>/screenshot.png)`. There's no automatic path rewriting, so links must be absolute. ## Automating with Node Generator If your extension is built with Node Generator, pass `--nodepit-product <product-id>` to have it generate a CI pipeline that runs both uploads automatically on release. See the [CLI Reference](./node-generator/cli-reference.md#nodepit-publishing) for the full set of publishing flags and the CI/CD secrets they require. ## Going live Uploading doesn't make your extension appear in the [Node Catalog](../nodepit/#node-catalog) or on your product page right away. NodePit still needs to set up crawling for your update site so its nodes get indexed — this is a manual step done by NodePit staff after your upload. Your product page stays hidden until this indexing has settled, at which point NodePit enables it. It's worth checking your upload actually worked before then: visit `https://nodepit.com/product/<product-id>` to see the (still-hidden but reachable) product page, and `https://download.nodepit.com/<product-id>/<label>` to confirm the update site is being served. A PATCH request to `/api/products/<product-id>` returns HTTP 2xx on success, so a non-2xx response there is worth investigating too. --- --- url: /runner.md description: >- Self-hosted scheduling and monitoring for KNIME workflows, shell scripts, and Docker containers. --- # Introduction NodePit Runner is a self-hosted scheduling and monitoring service for KNIME Analytics Platform workflows, shell scripts, and Docker-containerized workloads. Deploy it inside your own network, schedule your workflows on a cron expression, and inspect every execution — its status, log output, and produced artifacts — in one place. ![NodePit Runner dashboard showing project summary, running schedules, and run history](/runner-dashboard.png) ## What it does * **Schedule workflows** — run any KNIME workflow, shell script, or Docker container on a cron schedule without touching the workflow itself * **Monitor executions** — see the status, duration, and output of every run in one place * **Get notified** — receive email alerts when a run succeeds, fails, or is canceled * **Organise with projects** — group environments, schedules, files, and members into projects ## How it works Runner is deployed as a set of Docker containers. The **API** and **Web** services provide the user interface and REST API. One or more **Executor** containers pick up scheduled runs, build an isolated Docker environment, execute the workflow or script, and report the result back. See [System Overview](./architecture.md) for a detailed breakdown of components, infrastructure requirements, and external network access. ## Next steps * [Installation](./installation) — set up NodePit Runner with Docker Compose * [Quick Start](./quick-start) — create your first scheduled run ## Try NodePit Runner One fixed price covers everything: all features, unlimited users, unlimited schedules, and unlimited runs. Start with a free trial key — no commitment required. --- --- url: /runner/installation.md description: Install NodePit Runner with Docker Compose in under ten minutes. --- # Installation NodePit Runner is distributed as a set of Docker images and runs with Docker Compose. A typical installation takes under ten minutes. ## Prerequisites **System requirements** * 2 CPUs, 8 GB RAM, 50 GB disk (minimum) * Any OS that runs Docker — Linux (Debian/Ubuntu) recommended for production **Software** * [Docker](https://docs.docker.com/engine/install/) * [Docker Compose](https://docs.docker.com/compose/install/) v2 (`docker compose`, not `docker-compose`) ## Step 1 — Download docker-compose.yml The [nodepit/runner](https://github.com/nodepit/runner) repository on GitHub is the single source for all Runner distribution files: the Docker images, the official compose file, and optional extensions for HTTPS, backups, and more. Download the official compose file from GitHub: ```sh curl -O https://raw.githubusercontent.com/nodepit/runner/main/docker-compose.yml ``` Or [download it directly](https://raw.githubusercontent.com/nodepit/runner/main/docker-compose.yml) and save it to an empty directory. ## Step 2 — Start Runner ```sh docker compose up -d ``` Docker pulls the images on first run, which may take a minute or two. Once all containers are healthy, Runner is available at `http://localhost:8080`. ## Step 3 — Create the admin account Open `http://localhost:8080` in your browser. On first launch you will be prompted to set a password and create the initial admin account. Once logged in, go to [Settings](./settings.md) to configure your time zone, SMTP for notifications, and your license key. ## Upgrading Pull the latest images and restart the stack: ```sh docker compose pull docker compose up -d ``` Database migrations run automatically on startup. No manual steps are required. ## Next steps * [Configuration](./configuration.md) — set secrets, configure a public URL, set up a reverse proxy, scale executors * [Quick Start](./quick-start.md) — create your first project and run a workflow --- --- url: /runner/configuration.md description: Configure Runner through environment variables in the Docker Compose file. --- # Configuration Runner is configured through environment variables. The official compose file has working defaults baked in, so it runs out of the box with no changes: ```sh docker compose up -d ``` To change a value — a password, the public URL — place a `.env` file next to `docker-compose.yml`. It’s read automatically, and anything you set there overrides the built-in default, so a value only needs to change in one place. Copy [`.env.example`](https://github.com/nodepit/runner/blob/main/.env.example) to `.env` to get started. ## Core settings The default compose file ships with working defaults for these three settings, mirrored by [`.env.example`](https://github.com/nodepit/runner/blob/main/.env.example), so it runs out of the box for a local evaluation. Change them before exposing Runner to a network. ### MongoDB password Set `MONGO_ROOT_USERNAME` and `MONGO_ROOT_PASSWORD` in `.env`. Both the `api` and `mongodb` services read from the same two variables, so the connection string stays in sync automatically — there’s nothing else to edit. ```sh # .env MONGO_ROOT_USERNAME=root MONGO_ROOT_PASSWORD=your-db-password ``` ::: warning `MONGO_ROOT_PASSWORD` only sets the password when MongoDB initialises a new database. Changing it in `.env` after first run has no effect on an existing database. To rotate the password on a running installation, follow these steps: ::: 1. Stop the API container so no connections are open: ```sh docker compose stop api ``` 2. Open a MongoDB shell and change the password: ```sh docker compose exec mongodb mongosh -u root -p # enter current password when prompted use admin db.changeUserPassword('root', passwordPrompt()) # enter new password when prompted exit ``` 3. Update `MONGO_ROOT_PASSWORD` in `.env` to the new password. 4. Restart the stack: ```sh docker compose up -d ``` ### API key A shared secret between the API and Executor services. Set it once in `.env` — both services read the same variable: ```sh # .env API_KEY=your-api-key ``` ### Public URL Set `WEB_BASE_URL` in `.env` to the hostname or IP address your users will access Runner at. The API uses this to generate links in notification emails and other outbound content — if it’s wrong, those links will be broken. ```sh # .env WEB_BASE_URL=https://runner.example.com ``` ## Executor tuning The following settings aren’t wired to `.env` — add them directly to the `executor` service’s `environment:` block in `docker-compose.yml`. ### Worker resources Each executor spawns a Docker container per workflow run. Without limits, a runaway workflow can starve the host. Set CPU and memory limits to contain the blast radius: ```yaml # Executor service DOCKER_CPU_PERIOD: 100000 DOCKER_CPU_QUOTA: 85000 # 85% of one CPU DOCKER_MEMORY: 1500000000 # 1.5 GB ``` See the [Docker documentation](https://docs.docker.com/config/containers/resource_constraints/) for details on these values. To mount additional host paths into worker containers, use `DOCKER_BINDS`: ```yaml DOCKER_BINDS: /data/shared:/data/shared,/certs:/certs:ro ``` ### Private registry Each executor builds and caches Docker images locally. When running multiple executors, each one rebuilds its own cache independently — wasting time and disk space. A shared private registry solves this: images are pushed after the first build and pulled by all other executors instead of being rebuilt. ```yaml # Executor service DOCKER_REGISTRY_URL: registry.example.com DOCKER_REGISTRY_USER: your-registry-user DOCKER_REGISTRY_PASSWORD: your-registry-password ``` When a registry is configured, built images are automatically removed from the executor after being pushed. Set `DOCKER_REMOVE_IMAGES: false` to keep a local copy as well. To try this locally without standing up your own registry, see the [registry extension](#private-image-registry) below. ### Executor identity Each executor registers itself with the API on startup. You can give it a display name and tags that appear in the Executors list and can be used to route specific projects to specific executors: ```yaml # Executor service INITIAL_DESCRIPTION: Production executor INITIAL_TAGS: prod,eu-west ``` See [Executors](./executors.md) for how to use tags for routing. ## Extensions The [`extensions/`](https://github.com/nodepit/runner/tree/main/extensions) directory has optional add-ons, each a self-contained compose file you layer on top of `docker-compose.yml` with `-f`. These wire in third-party open-source tools rather than software built or maintained by NodePit — see each one’s own project for support and documentation beyond what’s covered here. To avoid repeating `-f` flags on every command, set `COMPOSE_FILE` in `.env` instead: ```sh COMPOSE_FILE=docker-compose.yml:extensions/nginx/docker-compose.yml:extensions/watchtower/docker-compose.yml ``` ### Reverse proxy and HTTPS For a publicly reachable installation, put Runner behind the [nginx extension](https://github.com/nodepit/runner/tree/main/extensions/nginx): an HTTPS reverse proxy with automatic Let’s Encrypt certificates. Set `DOMAIN` and `LETSENCRYPT_EMAIL` in `.env` — Runner refuses to start without them once the extension is layered on — and point a DNS record at the server before starting it, since certificate issuance needs the domain to resolve publicly. Set `WEB_BASE_URL` to `https://<DOMAIN>` too, so links generated by Runner use the public HTTPS URL. ```sh docker compose \ -f docker-compose.yml \ -f extensions/nginx/docker-compose.yml \ up -d ``` ### Automatic updates The [watchtower extension](https://github.com/nodepit/runner/tree/main/extensions/watchtower) pulls and restarts containers whenever new images are released. ```sh docker compose \ -f docker-compose.yml \ -f extensions/watchtower/docker-compose.yml \ up -d ``` ### Backups The [backup extension](https://github.com/nodepit/runner/tree/main/extensions/backup) creates daily database and workflow-data backups, stored locally and optionally shipped to an S3-compatible bucket. Set the `BACKUP_S3_*` variables in `.env` to also ship backups off-site — see `.env.example`. ```sh docker compose \ -f docker-compose.yml \ -f extensions/backup/docker-compose.yml \ up -d ``` ### Docker management UI The [portainer extension](https://github.com/nodepit/runner/tree/main/extensions/portainer) adds a web UI for managing the Docker stack — starting and stopping containers, viewing logs, inspecting resource usage — without the CLI. ```sh docker compose \ -f docker-compose.yml \ -f extensions/portainer/docker-compose.yml \ up -d ``` ### Private image registry The [registry extension](https://github.com/nodepit/runner/tree/main/extensions/registry) adds a [private Docker registry](#private-registry) already wired to the Executor via `DOCKER_REGISTRY_URL`, for trying that feature out without setting up your own registry first. It's unauthenticated and bound to `127.0.0.1` only, so it's meant for a single-host setup — sharing it across multiple executor hosts needs your own authenticated registry instead. ```sh docker compose \ -f docker-compose.yml \ -f extensions/registry/docker-compose.yml \ up -d ``` ## Environment variables The tables below document the container environment variables Runner reads directly. The official compose file already wires `API_KEY`, `WEB_BASE_URL`, `DB_URL`, and the MongoDB credentials to the `.env` variables described above — you only need to set these yourself if you’re running a custom compose setup. ### API | Variable | Required | Default | Description | | -------------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------------- | | `API_KEY` | yes | — | Secret token that authorises Executor connections to the API. Must match the `API_KEY` set on each Executor. | | `DB_URL` | yes | — | MongoDB connection string in the format `mongodb://user:password@host/database?authSource=admin`. | | `WEB_BASE_URL` | yes | — | Publicly reachable URL of the web UI. Used to build absolute links in notification emails and other outbound content. | ### Executor | Variable | Required | Default | Description | | -------------------------- | -------- | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `API_BASE_URL` | yes | — | Base URL of the API service as reachable from the Executor container, e.g. `http://api:3000`. | | `API_KEY` | yes | — | Secret token used to authenticate with the API. Must match the `API_KEY` set on the API. | | `DOCKER_BINDS` | no | — | Comma-separated volume mounts added to every worker container, in `host:container[:options]` format. Useful for sharing certificates, SSH keys, or data directories. | | `DOCKER_CPU_PERIOD` | no | `100000` | CPU scheduling period in microseconds. Used together with `DOCKER_CPU_QUOTA` to set a CPU limit: quota ÷ period = fraction of a CPU allocated per worker container. | | `DOCKER_CPU_QUOTA` | no | — | Microseconds of CPU time allocated per period. Set to `85000` with the default period to allow up to 85% of one CPU per worker container. | | `DOCKER_MEMORY` | no | — | Hard memory limit for worker containers in bytes. Containers that exceed this limit are killed. | | `DOCKER_NETWORK_MODE` | no | `bridge` | Docker network mode for worker containers. Accepts any value supported by Docker: `bridge`, `host`, `none`, or a named network. | | `DOCKER_REGISTRY_PASSWORD` | no | — | Password for authenticating with the registry configured in `DOCKER_REGISTRY_URL`. | | `DOCKER_REGISTRY_URL` | no | — | URL of a private Docker registry. When set, built images are pushed here so other Executor instances can pull them instead of rebuilding. | | `DOCKER_REGISTRY_USER` | no | — | Username for authenticating with the registry configured in `DOCKER_REGISTRY_URL`. | | `DOCKER_REMOVE_IMAGES` | no | `true` when registry is set | When `true`, images are deleted from the local Executor after being pushed to the registry, freeing disk space. Has no effect when no registry is configured. | | `INITIAL_DESCRIPTION` | no | — | Human-readable name for this Executor instance, shown in the Executors list in the UI. Useful when running multiple Executors. | | `INITIAL_TAGS` | no | — | Comma-separated tags assigned to this Executor on startup. Tags are used to route projects to specific Executors. | ### Web | Variable | Required | Default | Description | | ------------------ | -------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `SECURITY_CONTACT` | no | — | Contact address for security researchers, as a `mailto:`, `https://`, or `tel:` URI. Published at `/.well-known/security.txt`. Leave unset to serve no security.txt at all. The web container refuses to start if the value doesn't match one of those schemes. | The web interface also answers the standard `/.well-known/change-password` address by redirecting to your profile page, so password managers can send you straight there — no configuration needed. ### MongoDB | Variable | Required | Default | Description | | ---------------------------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `MONGO_INITDB_ROOT_PASSWORD` | yes | — | Password for the MongoDB root user. Only applied when the database is initialised for the first time — changing it later has no effect on an existing database. | | `MONGO_INITDB_ROOT_USERNAME` | yes | — | Username for the MongoDB root user. Only applied on first initialisation. | ## Troubleshooting ### Runs fail on ARM Mac with "Errors were encountered while processing: ca-certificates" This is a known issue with Rosetta on M2 and M3 processors. In Docker Desktop, go to **Settings → General** and disable **Use Rosetta for x86/amd64 emulation on Apple Silicon**. See the [upstream issue](https://github.com/docker/for-mac/issues/7255) for details. ### Runs fail on ARM Mac with "Failed to restore cached image … not found" This is a known issue with some versions of Docker Desktop. In Docker Desktop, go to **Settings → General** and disable **Use containerd for pulling and storing images**. See the [upstream issue](https://github.com/moby/moby/issues/44578) for details. --- --- url: /runner/quick-start.md description: >- Create a project, set up an environment, and run your first workflow in about five minutes. --- # Quick Start This guide walks through creating a project, setting up an environment, and running your first workflow. It takes about five minutes. If you do not have an account yet, see [Your Account](./account.md) first. ::: tip Press `Cmd+K` (macOS) or `Ctrl+K` (Windows / Linux) at any point to open the command palette for quick navigation and search. ::: ## Step 1 — Create a project Projects are the top-level container for environments, schedules, and runs. Go to **Projects** and click **Add Project**. Give it a name and click **Save**. ## Step 2 — Add an environment An environment defines the KNIME version your workflows run against. Each project can have multiple environments — for example, one per KNIME version you want to test against. Open your project and go to **Environments**. Click **Add Environment**, then: 1. Enter a name. 2. Select **KNIME** as the type. 3. Pick a KNIME version. 4. Click **Save**. ## Step 3 — Add a schedule A schedule pairs a workflow file with an environment and defines when it runs automatically. Go to **Schedules** and click **Add Schedule**, then: 1. Enter a name. 2. Select the environment you just created. 3. Upload your workflow file (`.knwf`). 4. Leave the cron expression as-is — you'll trigger the first run manually. 5. Click **Save**. ## Step 4 — Trigger a run Back in the **Schedules** list, find your schedule and click the **Run** button. Runner queues the workflow immediately without waiting for the cron schedule. ## Step 5 — View the result Clicking **Run** takes you to the Runs list. Click the run to open it — once an executor picks it up, you'll see live log output and a final status: **Passed**, **Failed**, or **Canceled**. ## Next steps * [Environments](./environments.md) — KNIME version management, EPF files, additional dependencies * [Schedules](./schedules.md) — cron expressions, flow variables, credentials, notifications * [Runs](./runs.md) — log output, run history, cleanup --- --- url: /runner/executors.md description: The worker processes that pick up and run scheduled workflows and scripts. --- # Executors Executors are the worker processes that actually run your workflows and scripts. Each executor is a Docker container that continuously polls the Runner API for pending runs, picks them up, executes the workflow or script inside an isolated sub-container, and reports the result back. You can run multiple executors side by side to handle concurrent schedules. All authenticated users can view the executor list. Managing executors — editing, pausing, and deleting — requires the global Admin role. See [Members & Roles](./members.md) for how global roles relate to project access. ## Your executors The executor list shows all registered executors. Each row displays the executor's current status, its description, the CPU architectures it supports, any tags it has, the executor version, how many runs it has executed in total, and when it was last seen. You can sort by description, last seen date, or run count, and search by description. Each executor can be in one of three statuses: | Status | Meaning | | --------- | ------------------------------------------------- | | ready | Online and idle; waiting for a run to be assigned | | executing | Online and currently executing a run | | offline | Has not contacted the API in the last 60 seconds | An executor marked as **paused** will not pick up new runs regardless of its online status. In-flight runs already assigned to it are not affected. Each executor has two actions: * **Pause / Resume** — toggle whether the executor accepts new runs. Requires Admin. * **Delete** — see [Deleting an executor](#deleting-an-executor). ## Adding an executor Executors are not added through the UI directly. Click **Add Executor** to see the instructions, or run the following command on the Runner host to scale the number of executor containers: ```sh docker compose scale executor=2 ``` Replace `2` with the number of executor instances you want. You can scale up or down at any time. A new executor registers itself with the API on startup and appears in the list within a minute. The initial description and tags of a new executor instance can be set via environment variables in `docker-compose.yml` before starting the container: * `INITIAL_DESCRIPTION` — sets the display name, e.g. `INITIAL_DESCRIPTION: GPU Executor` * `INITIAL_TAGS` — sets the initial tags as a comma-separated list, e.g. `INITIAL_TAGS: large,gpu` These values are only applied when the executor first registers. Changing them after the executor is running has no effect — use the edit form instead. ## Editing an executor Click any executor row to open its detail page. Two fields are editable: **Description** — the display name shown in the executor list and on run detail pages. **Tags** — used to route runs to specific executors. See [How runs are dispatched](#how-runs-are-dispatched) for the full matching rules. Use tags to direct resource-intensive runs to larger machines — for example, tag one executor `gpu` and configure the relevant environments to require it. The remaining fields are read-only statistics: **Version** — the version of the executor container. The API and Web versions are shown in [Settings](./settings.md). Keep all three in sync — running mismatched versions is not supported. **Architectures** — the CPU architectures this executor supports, detected automatically at startup (e.g. `x64`, `arm64`). Runs are dispatched to an executor that matches the architecture required by their environment. **Status** — the executor's current status and paused state, as shown in the list. **Created At** — when this executor first registered with Runner. Scaling up or pulling a newer executor image typically creates a new executor entry. **Last Seen At** — when the executor last polled the API. Online executors contact the API approximately once per minute. If this timestamp is stale and the executor shows as offline, check the executor container's logs for errors. **Number of Runs Done** — the total number of runs this executor has executed. Click the link to see all runs from this executor across the projects you have access to. ## How runs are dispatched When a run becomes pending, Runner looks for an executor that satisfies three criteria simultaneously: **Available** — the executor is online and not paused. **Architecture** — the executor supports one of the CPU architectures allowed by the environment's **Executor Architecture** setting, or any environment that leaves the setting empty. KNIME environments always require `x64`. Executors report their supported architectures automatically at startup. See [Environments](./environments.md#advanced) for how to restrict an environment to specific architectures. **Tags** — the run carries a combined set of tags: environment tags and schedule tags are always merged together. If the schedule has no tags, only the environment's tags apply; if neither has tags, the run is tagless. How the executor's own tags determine eligibility: * **Executor has no tags** — it only picks up runs that also have no tags. * **Executor has tags** — it picks up any run where at least one of the run's tags appears in the executor's tag set, plus any tagless runs. This means a `gpu` executor picks up both untagged runs and runs tagged `gpu`, but not runs tagged exclusively `large`. A `gpu,large` executor picks up runs tagged `gpu`, runs tagged `large`, and tagless runs. If no executor satisfies all three criteria, the run stays `pending` until one becomes available — or until the **Cancel Pending Runs After** timeout in [Settings](./settings.md) fires. The executor list is visible to all users, so anyone can check which executors are online and what tags they carry. ## Pausing and resuming Pausing an executor prevents it from picking up any new runs. It remains registered and visible in the list. Use this when you need to take an executor offline for maintenance without removing it entirely — for example, to update the Docker image or perform host maintenance. To pause, click the **Pause** button on the list row or the executor detail page. Click **Resume** to make it available again. Both actions require Admin. ## Deleting an executor An executor can only be deleted when it is offline and has no run records associated with it. An executor with any run history — even completed runs — cannot be deleted. This protects the audit trail: run detail pages link back to the executor that handled them. If you need to remove an executor with run history, stop the container and leave the executor registered. It will appear as offline but its historical data remains intact. Deleting requires Admin. --- --- url: /runner/users.md description: >- Admin-only management of Runner user accounts, global roles, and account confirmation. --- # Users & Roles The Users section is an admin-only area for managing Runner user accounts. Here you can create users, assign global roles, manually confirm accounts, impersonate users for debugging, and remove accounts that are no longer needed. ## Global roles Every Runner user has one of two global roles. **User** — the default role. Users can create projects and access any project they are a member of. They can manage their own account (change their email address) but cannot access admin functions. See [Members & Roles](./members.md) for how project-level access works. **Admin** — full system access. Admins can manage executors, configure global settings, and manage all user accounts, including creating and deleting users, changing roles, and impersonating users. An Admin role does not automatically grant access to all projects — admins still need to be added as project members like anyone else. ## Your users The user list shows all registered accounts. Each row displays the user's Gravatar and email address, when they registered, and when they last logged in. Admins and unconfirmed users are marked with a badge next to their email. You can sort by email, registration date, or last login date, and search by email. Each user has up to three actions in the list: * **Confirm** — manually confirm an unconfirmed account. Only visible when the account has not yet been confirmed. * **Impersonate** — open a session as this user in a new tab. See [Impersonating a user](#impersonating-a-user). * **Delete** — see [Deleting a user](#deleting-a-user). ## Adding a user Click **Add User**, enter an email address, select a role, and click **Save**. No password is set during creation — the user should use the **Forgot Password** flow on the login page to set their password before their first login. New accounts are created in an unconfirmed state. The user becomes fully active once they confirm their email address via the confirmation link sent on registration, or once an admin confirms them manually. ## Editing a user Click any user row to open their detail page. Two fields are editable: **Email Address** — the user's login email and the address used for notifications and avatars. Admins can change any user's email; regular users can change their own. **Role** — the global role assigned to this user. Requires Admin. You cannot change your own role — ask another admin to do it. ## Confirming a user When a user registers, Runner sends a confirmation email with a link to activate their account. Until confirmed, the user has no access to any part of the application. If a user did not receive the confirmation email or needs to be activated immediately, an admin can confirm the account manually by clicking the **Confirm** button on the list row or the user detail page. ## Impersonating a user Impersonation lets an admin open a session that behaves exactly as if they were logged in as another user. This is useful for diagnosing access problems or verifying that a user's project permissions are set up correctly. The impersonated session opens in a new browser tab so your own session is unaffected. Impersonation is only available to Admins and only for confirmed user accounts. You cannot impersonate yourself, and you cannot start an impersonated session while already impersonating someone. ## Deleting a user Deleting a user removes their account and revokes all their access tokens. If SMTP is configured in [Settings](./settings.md), the user receives a notification email when their account is deleted. A user can only be deleted if they have no activity in the system — no projects, environments, files, schedules, runs, or project memberships where they appear as creator, last editor, or member. In practice this means that any user who has actively used Runner cannot be deleted. If you need to revoke access without deleting, remove them from all projects via [Members & Roles](./members.md) instead. You cannot delete your own account. --- --- url: /runner/settings.md description: >- Global, system-wide configuration for a Runner installation, restricted to the Admin role. --- # Settings The Settings page contains the global configuration for your Runner installation. All settings here apply system-wide and require the Admin role to change. ## General **Version** — shows the currently running Web and API versions (`Web: x.x.x, API: x.x.x`). Executor versions are shown separately in the [Executors](./executors.md) page. Keep all three in sync — running mismatched versions is not supported. A banner appears here when a newer version of Runner is available, with links to the [Release Notes](./changelog.md) and update instructions. **License** — paste your full license key here, including the `-----BEGIN LICENSE-----` and `-----END LICENSE-----` lines. Once a valid key is saved, this field shows the licensee name and expiry date instead. An **Invalid License** label appears if the key cannot be validated. Click **Enter …** to replace an existing key. Get a license key at [nodepit.com](https://nodepit.com/product/runner). ## Email Email settings enable Runner to send notifications for run outcomes, user management events, and access token expiry. All outgoing emails use the sender details configured here. **Sender Name** — the display name shown in the From field of outgoing emails, for example `NodePit Runner`. Optional — if left empty, only the sender email address is shown. **Sender Email Address** — the From address for all emails sent by Runner. **SMTP URL** — the connection string for your SMTP server. The format is `smtp://user:password@host:port`. Use `smtps://` for a TLS connection. The field is masked by default; click **Show** to reveal it. Advanced options — such as disabling TLS certificate verification or setting a specific port — can be passed as query parameters following the [Nodemailer SMTP URL format](https://nodemailer.com/smtp/), for example `smtps://user:password@host/?ignoreTLS=true`. **Send Test Email** — sends a test email to your own address to verify the configuration. The button is only available once the sender email address and SMTP URL are both filled in. Any delivery error is shown inline below the button. ## Time Zone **Time Zone** — the time zone used to evaluate all cron expressions. When a schedule is set to run at `0 9 * * 1-5`, it fires at 9:00 am in this time zone. Click **Use Current** to set it to your browser's local time zone. All time zones from the IANA database are available, plus UTC. ::: warning Changing the time zone affects all schedules immediately. Review your cron expressions after changing this setting to make sure runs still fire at the intended local times. ::: ## Cancellations These settings define global timeout defaults for stuck runs. Both can be overridden per schedule in the [Schedules](./schedules.md) settings. **Cancel Pending Runs After** — if a run stays in the `pending` state longer than this threshold, Runner cancels it automatically. A run can get stuck in `pending` when no executor is available or when no executor matches the required tags. Options: never, 15 minutes, 1 hour, 6 hours, 1 day. **Cancel Running Runs After** — if a run stays in the `running` state longer than this threshold, Runner cancels it automatically. Use this as a safety net for workflows that hang or exceed their expected duration. Options: never, 15 minutes, 1 hour, 6 hours, 1 day. ## Experimental Experimental settings are off by default and may change or be removed without notice. **KNIME Download Source** — where KNIME Analytics Platform is downloaded from when building images for KNIME environments. Defaults to KNIME's own servers (`download.knime.org`); switch to the NodePit mirror (`download.nodepit.com`) if KNIME's servers are unreliable or unreachable from your network. Switching invalidates cached image layers for existing KNIME environments, so the next run of each rebuilds its image from the new source. --- --- url: /runner/dashboard.md description: >- The global and per-project overview of running, recent, and upcoming schedules, with historical charts. --- # Dashboard The dashboard is the first thing you see when you open Runner. It gives you a live overview of your installation — what is running right now, what finished recently, and what is scheduled next — alongside historical charts for spotting trends in run outcomes and duration. Runner has two dashboard contexts: the **global dashboard** covers all projects you have access to, and the **project dashboard** shows the same layout scoped to a single project. ## Summary cards A row of cards at the top shows entity counts at a glance — Projects, Executors, Environments, Files, Schedules, Runs, and Members, depending on your role and whether you are in the global or project context. Clicking a card takes you directly to that section. ## Live activity Three columns below the cards refresh every 10 seconds. **Finished** shows the 10 most recent completed runs with their outcome, duration, and queue time. **Running** shows everything currently in progress, with elapsed time counting up live. **Next** lists upcoming scheduled runs with a live countdown — click any row to open the schedule. ## Charts The lower half of the page contains four charts covering the period selected with the **7d / 30d / 90d** buttons. They refresh every 60 seconds. **Runs Over Time** and **Status Breakdown** give you a picture of run volume and outcome distribution — useful for spotting days with unusual failure rates or changes in throughput. **Run Duration** and **Duration Distribution** show how long runs take over time and how times are spread across the selected period. Use these to catch performance regressions or understand whether most runs finish quickly or cluster at longer durations. --- --- url: /runner/projects.md description: >- The top-level container for environments, files, schedules, runs, and members in Runner. --- # Projects A project is the top-level container in Runner. Everything — environments, files, schedules, runs, and members — belongs to a project. Access control is project-scoped: each member has a role that determines what they can do within that project. ## Your projects The project list shows a card for each project you have access to. Each card shows the project name, your role in it, and counts for environments, files, schedules, runs, and members. The counts are clickable and take you directly to that section — useful for jumping straight to the schedules or runs of a project without opening it first. The last updated time and author give you a sense of recent activity without having to open the project. ## Creating a project Click **Add Project**, enter a name, and click **Save**. Runner adds you as the project owner and takes you to the Environments page. The name is the only required field. Choose something that makes the project's purpose clear to other members — it appears in the project list, in email notifications, and in run logs. ## Editing a project Open the project and click **Edit**. The name is the only editable field. To manage who has access, go to [Members & Roles](./members.md). ## Deleting a project A project can only be deleted once it is empty. Remove all environments, files, schedules, and runs first — the **Delete** button is disabled until then. This prevents accidental loss of run history or workflow files that other members may still need. --- --- url: /runner/environments.md description: >- Define the KNIME version, Docker image, or shell runtime that schedules execute in. --- # Environments An environment defines the runtime your workflows or scripts execute in — for example, which KNIME version to use and which extensions are installed, or which Docker image to run. Runner builds a Docker image from these settings the first time a schedule in this environment runs. Subsequent runs reuse the cached image, so startup is fast unless the environment changes. ## Your environments The environment list shows all environments in the current project. The **Latest Run** column is the quickest way to spot trouble: a failed status here means the last run in this environment did not pass, even if you haven't looked at the Runs page yet. Click the status to jump directly to that run. You can filter by type (KNIME, Shell, or Docker) and sort by name or last modified date. Each environment has three actions: * **Clear Cache** — deletes the cached Docker image and forces a full rebuild on the next run. Use this after changing system-level dependencies or when a run fails due to a stale image. * **Copy** — duplicates the environment with all its settings. Useful for testing a new KNIME version alongside an existing one without starting from scratch. * **Delete** — see [Deleting an environment](#deleting-an-environment). ## Creating an environment Click **Add Environment**, fill in the fields below, and click **Save**. The type you select determines which additional sections appear. Creating environments requires the appropriate project role — if you don't have it, the **Add Environment** button is disabled. See [Members & Roles](./members.md) for details. ### General **Name** — Required. Choose a name that describes what the environment does or what it runs on, for example "KNIME 5.3 — Production" or "Data Export". Members see this name when creating schedules. **Notes** — Optional free-text field for documentation about this environment. Supports Markdown. A good place to record why a particular KNIME version was chosen, known issues, or setup steps that aren't obvious from the settings alone. **Type** — Select **KNIME** to run KNIME workflows, **Shell** to run shell scripts, or **Docker** to run any containerized workload — Python, Node.js, or anything else you can package into an image. The type cannot be changed after the environment is saved — if you need a different type, create a new environment or copy an existing one. ### KNIME These settings are only available for KNIME environments. **KNIME Version** — The version of KNIME Analytics Platform to install into this environment's image. New environments default to a recent supported KNIME version, but you can pick any other supported version instead. Runner supports multiple versions simultaneously; each version produces a separate cached image. When a new KNIME version releases, copy an existing environment, change the version, and run a test schedule before switching production schedules over. Entering `nightly` installs the latest KNIME nightly build; nightly environments are never cached and rebuild from scratch on every run, which is slower and not recommended for production. **Preference File** — An optional `.epf` file exported from your local KNIME Analytics Platform via **File → Export Preferences…**. Use this to carry over your local KNIME settings — proxy configuration, credentials storage, database drivers — into Runner's execution environment. The uploaded file is stored in the project's [Files](./files.md). **Preference Entries** — Individual key/value preference overrides, applied on top of the preference file if one is provided. Useful for setting specific preferences without exporting a full EPF file, or for overriding individual values from the file. The key field autocompletes from the uploaded preference file. **JVM Arguments** — By default, Runner configures JVM arguments automatically for the selected KNIME version. Enable **Configure JVM arguments manually** only if you need to override this — for example to increase heap memory with `-Xmx4G`. Use **Apply Version Defaults** to load the recommended arguments for your KNIME version as a starting point, then adjust as needed. Removing required arguments can cause workflows to fail. **Extension Search** — Searches the [NodePit](https://nodepit.com) node catalogue to find KNIME extensions by name or keyword. Selecting an extension automatically adds its update site and feature identifier to the lists below. **Update Sites** — URLs of Eclipse update sites to install extensions from. Most extensions are available from the official KNIME update sites, which the Extension Search handles automatically. Add custom update sites here for third-party or internal extensions — for example, `https://download.nodepit.com/5.12` for NodePit extensions on KNIME 5.12. **Features** — The feature identifiers to install, for example `ws.palladian.nodes.feature.feature.group`. Each feature must be available on one of the configured update sites and must not already be included in the base KNIME installation — installing a pre-installed feature causes the image build to fail. ### Shell Shell environments only use the General and Advanced settings. There are no Shell-specific fields — the shell script itself is uploaded on the schedule, not the environment. ### Docker These settings are only available for Docker environments. Docker environments open Runner up to virtually any containerized workload — not just KNIME workflows and shell scripts, but Python, Node.js, or anything else you can package into an image. Point the environment at an existing image or your own Dockerfile, then tailor each schedule with its own command and environment variables without ever touching the underlying image. **Source** — **Image** to pull an existing image from a registry, or **Dockerfile** to build one from a Dockerfile you upload. Switch to Dockerfile if you need to install additional tools or dependencies on top of a base image. **Image** — Required when Source is Image. The image reference to pull, for example `python:3.12-slim`. Include a registry host for images outside Docker Hub, for example `ghcr.io/acme/my-image:latest`. Pick an image that already provides whatever runtime the schedule's Command needs — `python:3.12-slim` for a Python command, `node:20-alpine` for Node.js, or a minimal `alpine` image for shell commands. See the Command examples in [Schedules](./schedules.md#docker) for each. **Dockerfile** — Required when Source is Dockerfile. Select a `Dockerfile` already uploaded to the project's [Files](./files.md) or upload a new one directly. **Private Registries** — Credentials for pulling images from private registries. Add one entry per registry host, each with a host, username, and password. Add an entry for every private registry your image — or, for a Dockerfile source, any base image referenced with a `FROM` instruction — is hosted on. **Always Pull** — When enabled, Runner checks for a newer version of the image before every run instead of reusing the cached one. Use this for images tagged `latest` or another mutable tag where you want runs to always pick up the newest build. Leave disabled for immutable, version-pinned tags to avoid the extra pull on every run. **Build Arguments** — Only available for a Dockerfile source. Name/value pairs passed as Docker build arguments (`--build-arg`) to the build, for example to parametrize a base image version referenced in the Dockerfile with `ARG`. ### Advanced These settings apply to all environment types. **Additional Files** — Files made available inside the container at `/nodepit/<filename>`. Use this for JDBC drivers, licence files, certificates, or any other file that workflows depend on at runtime but that does not belong in the workflow itself. Files can be selected from the project's [Files](./files.md) or uploaded directly here. For a Docker environment with Source set to Dockerfile, these files are also available to the Dockerfile's own `COPY` and `ADD` instructions during the build — schedule-level additional files are not, since those are only mounted at runtime. **Additional Dockerfile Instructions** — Raw Dockerfile instructions appended at the end of the Dockerfile. Use this to install system packages or configure the environment beyond what the other settings support — for example, installing Python or R for use with KNIME's scripting nodes. For a Docker environment with Source set to Dockerfile, these instructions are appended after your own uploaded Dockerfile, not just a Runner-generated one. **Executor Tags** — Tags that constrain which executors can run schedules using this environment. A run will only be picked up by an executor that has all the required tags set. Leave this empty to allow any executor to run the environment. See [Executors](./executors.md) for how tags are configured on the executor side. **Executor Architecture** — Restricts runs to executors supporting one of the selected CPU architectures (`x64`, `arm64`). Leave empty to allow any architecture. KNIME environments are always fixed to `x64`, since that's the only architecture KNIME supports, and this field is disabled for them. See [How runs are dispatched](./executors.md#how-runs-are-dispatched) for how architecture matching works. ## Editing an environment All fields can be edited after creation, with one exception: **Type** is locked once the environment is saved. If you need to change the type, create a new environment. If your role does not permit editing, the form is shown in read-only mode. Any change to the environment settings — including KNIME version, extensions, or additional files — takes effect on the next run. Runner detects the change and rebuilds the Docker image automatically. If you want to force a rebuild without changing any settings, use **Clear Cache**. ## Deleting an environment An environment can only be deleted if it has no schedules or runs referencing it. Remove or reassign those first — the **Delete** button is disabled until then. --- --- url: /runner/files.md description: >- Shared project storage for uploaded files and run artifacts, referenced by environments and schedules. --- # Files The Files section is a shared storage area for a project. It holds two kinds of files: **uploads** added by project members — workflow files, shell scripts, preference files, JDBC drivers, certificates — and **artifacts** generated by executors as the output of a run. Both types live in the same list and can be referenced by environments and schedules. ## Your files The file list shows all files in the current project. Each file is shown with an icon matching its extension. Use the filter bar at the top to switch between uploaded files and run artifacts, and the search to find files by name. You can also sort by name, size, or last modified date. Each row has two actions: **Download** to save a local copy, and **Delete** — see [Deleting a file](#deleting-a-file). Clicking a file opens its detail view, which shows the name, origin, size, and last modified date. For KNIME workflow files (`.knwf`), Runner renders a zoomable SVG preview of the workflow so you can identify the file at a glance without opening it in KNIME. ## Uploading files Click **Upload Files** or drag one or more files anywhere onto the Files page. Multiple files can be uploaded in a single operation. Uploading requires the appropriate project role — the button is disabled if you don't have it. See [Members & Roles](./members.md) for details. There is no restriction on file type. Files are available for selection across environments and schedules as soon as the upload completes. Files can also be uploaded directly from the environment form — preference files and additional files uploaded there appear here in the same list. See [Environments](./environments.md) for details. ## Replacing a file Open a file and click **Replace …** to upload a new version. The filename stays the same and all environments and schedules that reference this file automatically use the new content — no need to update them manually. Use this to update a workflow or script without changing any of your schedule configuration. Replacing requires the same project role as uploading — the button is disabled if you don't have it. ## Deleting a file Deleting a file requires the appropriate project role. A file can only be deleted if nothing references it. The **Delete** button is disabled if the file is currently used by an environment (as a preference file or additional file), a schedule (as the workflow, script, or additional file), or a run (as an artifact). Remove or update those references first. --- --- url: /runner/schedules.md description: >- Tie a workflow or script to a cron expression and an environment, and manage how runs are recorded. --- # Schedules A schedule ties a workflow or script to a cron expression and an environment. When active, Runner fires the schedule automatically at the specified interval and records every execution as a [Run](./runs.md). You can also trigger a run manually at any time, regardless of whether the schedule is active or the cron expression has fired. ## Your schedules The schedule list shows all schedules in the current project. Each row displays the description and any executor tags, the status of the latest run, the next scheduled run time with the cron expression (or an **Inactive** badge if the schedule is paused), the associated environment and file, and when the schedule was last modified and by whom. You can filter by environment type (KNIME, Shell, or Docker) and search by description or notes. Use the sort control to order by description or by last modified date. Each schedule has three actions: * **Copy** — duplicates the schedule with all its settings. The copy opens in edit mode so you can adjust it before saving. * **Run Now** — triggers an immediate run outside of the normal cron schedule. Requires at least the Operator role. The button is disabled if the installation does not have a valid license. * **Delete** — see [Deleting a schedule](#deleting-a-schedule). ## Creating a schedule Click **Add Schedule**, fill in the fields below, and click **Save**. Creating a schedule requires at least the Maintainer role — if you don't have it, the **Add Schedule** button is disabled. See [Members & Roles](./members.md) for details. ### Schedule These fields apply to all schedule types. **Description** — Required. A short label for this schedule, shown in the list and in run notification emails. **Notes** — Optional free-text field for documentation about this schedule. Supports Markdown. A good place to record what the workflow does, who requested it, or any dependencies that are not obvious from the other settings. **Status** — Controls whether the schedule fires automatically. When **Active**, Runner queues a run at each cron tick. When inactive, the schedule is paused — no automatic runs fire, but you can still trigger a run manually with **Run Now**. **Schedule** — A standard five-field cron expression defining when the schedule fires. Common examples: ``` 0 9 * * 1-5 Weekdays at 9:00 am */30 * * * * Every 30 minutes 0 0 * * * Daily at midnight 0 6 1 * * First of the month at 6:00 am ``` All cron expressions are evaluated in the time zone configured in [Settings](./settings.md). **Environment** — The environment that defines the runtime for this schedule. The type of the selected environment (KNIME, Shell, or Docker) determines which additional fields appear below. See [Environments](./environments.md) for details on creating and managing environments. ### Concurrency **Concurrency** — Controls what happens when the schedule is triggered — by its own cron timing or by clicking **Run Now** — while a run of it is already active (`pending`, `running`, or `canceling`). Choose: * **Allow** — the previous, default behavior. The new run executes in parallel with the active one. * **Skip** — the new trigger is ignored. A run is still recorded with a **Skipped** status, so you always know it was triggered and skipped, and when. * **Queue** — the new run waits until the active run finishes, then starts. * **Cancel & Replace** — the active run is canceled immediately and replaced by the new one. ### KNIME These fields appear when the selected environment is a KNIME environment. **Workflow** — The `.knwf` workflow file to execute. Select a file already uploaded to the project or upload a new one directly. Export your workflow from KNIME Analytics Platform via **File → Export KNIME Workflow…**; make sure all nodes are connected and reset before exporting. Files written to the `/nodepit` directory during execution are collected into the run's artifact archive. **Workflow Variables** — Values to inject into the workflow as flow variables. Each entry requires a name, a type (String, int, or double), and a value. Variables defined here override any flow variables already set inside the workflow. **Credentials** — Workflow credentials to make available during execution. Each entry requires a name, a login, and a password. These override credentials defined inside the workflow. **Reset Workflow Before Execution** — When enabled, Runner resets all nodes before executing the workflow. This ensures all nodes execute from scratch and is the recommended setting for scheduled runs. ### Shell These fields appear when the selected environment is a Shell environment. **Shell Script** — The `.sh` script file to execute. Select a file already uploaded to the project or upload a new one directly. Files written to `/nodepit` during execution appear in the run's artifact archive. **Environment Variables** — Values made available to the script as environment variables when it runs. Each entry requires a name and a value. ### Docker These fields appear when the selected environment is a Docker environment. **Command** — Overrides the image's entrypoint or default command. Leave empty to run the image's own default command. This field accepts a full multi-line script, not just a single line — paste in an entire script you already have, exactly as it exists in a file, rather than reducing it to a one-liner. Useful for retry loops or other logic that doesn't warrant its own file. For example, retrying a request a few times before giving up, using whichever runtime the image already provides — an Alpine-based image with `wget`, or a `python`/`node` image: ::: code-group ```bash [Bash] for i in $(seq 1 3); do wget -q --spider https://example.com && echo "Success on attempt $i" && exit 0 echo "Attempt $i failed" sleep 5 done exit 1 ``` ```python [Python] python3 -c " import urllib.request for attempt in range(1, 4): try: urllib.request.urlopen('https://example.com', timeout=10) print(f'Success on attempt {attempt}') break except Exception as e: print(f'Attempt {attempt} failed: {e}') " ``` ```js [Node.js] node -e " const https = require('https'); function attempt(n) { https.get('https://example.com', res => { console.log(\`Success on attempt \${n}: \${res.statusCode}\`); }).on('error', () => { console.log(\`Attempt \${n} failed\`); if (n < 3) setTimeout(() => attempt(n + 1), 5000); }); } attempt(1); " ``` ::: Or piping between tools, for example backing up a database straight to S3: ``` pg_dump -h $DB_HOST -U $DB_USER $DB_NAME | gzip | aws s3 cp - s3://backups/db-$(date +%F).sql.gz ``` If the command needs a tool the base image doesn't already include, install it via the environment's **Additional Dockerfile Instructions** — see [Environments](./environments.md#advanced). Prefer keeping the script as its own file — for version control, or to reuse it across schedules — rather than pasting it into this field? Upload it as an **Additional File** below instead, and set Command to just call it, for example `python3 /nodepit/report.py`. **Environment Variables** — Values made available inside the container as environment variables when it runs. Each entry requires a name and a value. ### Timeouts **Remove Runs After** — How long to retain runs created by this schedule before deleting them automatically. Options: never, immediately, 1 hour, 1 day, 1 week, 30 days, 1 year. Cleanup runs every 60 seconds. Set to **Never** to retain all runs indefinitely. **Cancel Running Runs After** — If a run stays in the `running` state longer than this threshold, Runner cancels it automatically. Options: 15 minutes, 1 hour, 6 hours, 1 day. Leave unset to fall back to the global default from [Settings](./settings.md). Use this to tighten or loosen the global timeout for a specific schedule. ### Notifications These toggles control which run outcomes send an email notification to you personally. **Notify on successful runs** — Send an email when a run completes with a `passed` status. **Notify on failed runs** — Send an email when a run completes with a `failed` status. **Notify on canceled runs** — Send an email when a run is canceled. Notifications require SMTP to be configured in [Settings](./settings.md). If SMTP is not set up, the toggles are disabled and a warning is shown. See [Notifications](./notifications.md) for details on setting up email and how notification emails are formatted. ### Advanced **Additional Files** — Extra files mounted inside the container at `/nodepit/<filename>` for this schedule only. Use this for files that are specific to this schedule, such as a particular configuration or input file. Files that multiple schedules share belong in the environment's Additional Files instead. **Executor Tags** — Tags that constrain which executors can handle runs of this schedule. Schedule tags are combined with any tags set on the environment — together they determine which executors are eligible. See [Executors](./executors.md#how-runs-are-dispatched) for how tag matching works. ## Editing a schedule All fields can be edited after the schedule is saved. There are no locked fields. If your role does not permit editing (Operator or Reader), the form is shown in read-only mode. Changes take effect immediately: the next automatic run and any manual run triggered after saving will use the updated settings. ## Deleting a schedule Deleting a schedule requires at least the Maintainer role. A schedule cannot be deleted while it has runs in an active state (pending, running, or canceling). Wait for those runs to complete or abort them first, then retry. When a schedule is deleted, all of its associated runs are deleted as well. --- --- url: /runner/runs.md description: 'Inspect the status, timing, logs, and artifacts of every schedule execution.' --- # Runs A run is a single execution of a schedule. Runs are created automatically when a schedule fires on its cron expression, or manually when someone clicks **Run Now** or triggers one via the REST API. Every run is recorded — its status, timing, log output, and any files it produced — so you can inspect what happened and when. ## Run statuses Each run moves through a lifecycle represented by one of seven statuses. | Status | Meaning | | --------- | --------------------------------------------------------------------------------------------------- | | pending | Queued; waiting for an available executor to pick it up | | running | An executor has picked it up and the workflow or script is executing | | canceling | An abort was requested; the executor is stopping the process | | passed | The execution completed successfully | | failed | The execution completed with an error or non-zero exit code | | canceled | The run was aborted before it could complete | | skipped | The schedule was triggered while a run of it was already active and its Concurrency setting is Skip | The statuses `pending`, `running`, and `canceling` are active states — the run detail page polls automatically and updates in real time while a run is in any of these states. A `skipped` run never executes — it is recorded directly in its terminal state so you always know the trigger happened. See [Concurrency](./schedules.md#concurrency) for how the **Skip**, **Queue**, and **Cancel & Replace** strategies affect run creation. ## Your runs The run list shows all runs in the current project, most recent first. Each row shows the run status, the description and any executor tags, the schedule and environment it belongs to (with a warning icon if either, or a file either of them uses — workflow, script, Dockerfile, EPF preferences, or additional file — has changed since the run was created), and when the run was created and by whom. You can filter by status and search by description. The list loads 25 runs at a time and extends automatically as you scroll. Each run has three actions in the list: * **Abort** — cancel an active run. See [Aborting a run](#aborting-a-run). * **Retry** — create a new run from the same schedule. See [Retrying a run](#retrying-a-run). * **Delete** — remove a completed run. See [Deleting a run](#deleting-a-run). ## Run detail Click any run to open its detail page. The page shows a set of summary cards followed by the log output. **Triggered by** — whether the run was started automatically by its cron schedule or manually (via **Run Now** or the API), the user whose action created it, and when. **Executor** — the executor that ran this run, including its tags. If no executor has been assigned yet (a pending run), this shows "No executor assigned yet". **Environment** — the environment used for this run, with a link to the environment page. A warning icon appears if the environment, or a file it uses, has changed since the run was created — relevant if you plan to retry. **Schedule** — the schedule this run belongs to, with a link to the schedule. A warning icon appears if the schedule, or a file it uses, has changed since the run was created. **Tags** — the executor tags that were applied to this run, controlling which executor could pick it up. **Duration** — how long the run spent queued and how long it spent executing. While a run is active, the elapsed time updates live. If Runner has historical data for this schedule, a progress bar shows how far through the expected duration the run is. The bar turns red if the run exceeds the estimated duration. **Status and artifact** — the current run status. If the run produced files in the `/nodepit` directory, a download link for the artifact archive appears here. ### Resource metrics While a run is executing and for any completed run that collected metrics, Runner displays six time-series graphs: * **CPU** — CPU usage as a percentage of the allocated limit * **Memory** — memory usage in bytes * **Network Received / Network Sent** — cumulative bytes received and sent over the network * **Disk Read / Disk Write** — cumulative bytes read from and written to disk These metrics are collected from the executor's Docker container. They are useful for spotting resource bottlenecks, such as a workflow that runs out of memory or a script that reads an unexpectedly large dataset. ### Log Below the summary cards, the log viewer shows the complete output of the run. Lines are colored by log level — errors in red, warnings in orange, notices in blue, debug output in gray, and all other output in the default color. The log can also be organized into collapsible sections, and individual lines can be flagged as errors, warnings, or notices regardless of what their own wording happens to be. Errors and warnings from a KNIME workflow, and a package that fails to install during a Docker build, are detected and highlighted automatically — no action needed on your part. A Shell or Docker schedule's Command or script can do the same for its own output by printing `::group::<title>` to open a section (closed with a matching `::endgroup::`) or prefixing a line with `::error::`, `::warning::`, or `::notice::` to mark it explicitly. Click a section's header, or the chevron beside it, to collapse or expand it; searching or following a link to a specific line automatically expands any section that contains it. The log viewer toolbar provides several controls: * **Search** — opens an inline search bar. Options: **Aa** to match case, **W** to match whole words only, and `.*` to use a regular expression. Use the up and down arrows or Enter / Shift+Enter to jump between matches. * **Collapse All / Expand All** — fold or unfold every section at once. * **Scroll to top / Scroll to bottom** — jump to the first or last line. * **Follow Log** — automatically scrolls to the bottom as new lines arrive. Only available while the run is active; turns off when the run completes. * **Copy Log** — copies the full log text to the clipboard, with section and severity markers unwrapped to plain text. * **Download Log** — downloads the log as a file, with section and severity markers unwrapped the same way. You can also click any line number to anchor a link to that line — the URL updates so you can share a direct link to a specific point in the log. Shift+click extends the selection to a range; Cmd+click (or Ctrl+click) toggles individual lines in and out of the selection. ## Aborting a run Aborting a run sends a cancellation signal to the executor and moves the run to `canceling`, then `canceled` once the process has stopped. Only runs in `pending` or `running` state can be aborted. Owners and Maintainers can abort any run in the project. Operators can only abort runs they triggered themselves. ## Retrying a run Retrying creates a new run using the same schedule and environment. The new run is added to the top of the run list and goes through the normal lifecycle. If the schedule or environment has been updated since the original run was created, Runner shows a confirmation dialog explaining the difference — the retry will use the current versions of both, which may produce different results. Retrying requires at least the Operator role and a valid Runner license. The **Retry** button is disabled if no valid license is installed. ## Deleting a run A run can only be deleted once it has reached a terminal status — `passed`, `failed`, or `canceled`. Active runs must be aborted first. Owners and Maintainers can delete any run in the project. Operators can only delete runs they triggered themselves. --- --- url: /runner/members.md description: Assign project-scoped roles that control what each member can see and do. --- # Members & Roles Members are the users who have access to a project. Each member is assigned a role that determines exactly what they can see and do within that project. Roles are scoped to the project — the same user can be an Owner in one project and a Reader in another. Runner's global Admin role, which governs executors, settings, and user management, does not automatically grant access to any project; admins still need to be added as members like anyone else. ## Project roles Runner has four project roles, ordered from most to least permissive. | Permission | Owner | Maintainer | Operator | Reader | | ---------------------------------------- | :---: | :--------: | :------: | :----: | | View all project resources | ✓ | ✓ | ✓ | ✓ | | Trigger runs (Run Now) | ✓ | ✓ | ✓ | | | Abort and delete own runs | ✓ | ✓ | ✓ | | | Abort and delete any run | ✓ | ✓ | | | | Create, edit, and delete environments | ✓ | ✓ | | | | Create, edit, and delete files | ✓ | ✓ | | | | Create, edit, and delete schedules | ✓ | ✓ | | | | Manage members | ✓ | | | | | Edit project settings and delete project | ✓ | | | | **Owner** — full control over the project. Owners are the only role that can manage who has access and change project-level settings. Every project must have at least one Owner. **Maintainer** — can build and maintain everything inside a project: environments, files, and schedules. Can also trigger, abort, and delete any run. Cannot manage members or change project settings. **Operator** — intended for users who run workflows but should not change how they are configured. Operators can trigger runs and manage the runs they started, but cannot edit environments, files, or schedules. **Reader** — view-only access. Readers can inspect all project resources — environments, files, schedules, runs, and logs — but cannot make any changes or trigger runs. ## Your members The member list shows all users who have access to the current project. Each row shows the member's email address and Gravatar, their role, and when they were added and by whom. You can filter by role and sort by email address, role, or date added. Use the search box to find a member by email. ## Adding a member Adding a member requires the Owner role. Click **Add Member**, enter the user's email address, select a role, and click **Save**. The email field autocompletes from existing Runner user accounts — only users who already have a Runner account can be added as members. If SMTP is configured in [Settings](./settings.md), the new member receives an email notification when they are added. ## Changing a role To change a member's role, click their row in the list and select a new role from the dropdown. Changing a member's role requires the Owner role. Two constraints apply: * **You cannot change your own role.** Ask another Owner to change it for you. * **The role of the sole Owner cannot be changed.** Promote another member to Owner first, then change the original Owner's role. ## Removing a member Removing a member revokes their access to the project immediately. Click the delete button on the member's row or open their detail page and click the delete button there. Removing a member requires the Owner role. The sole Owner of a project cannot be removed. Promote another member to Owner first. If SMTP is configured in [Settings](./settings.md), the removed member receives an email notification. ## Leaving a project Any member can leave a project themselves by opening their own entry in the member list and clicking **Leave Project**. Leaving a project removes your own access immediately. The sole Owner of a project cannot leave. Promote another member to Owner first, then leave. --- --- url: /runner/account.md description: >- Manage sign-in, project access, and notification settings for your personal Runner account. --- # Your Account Your account is your personal identity in Runner. It controls how you sign in, which projects you can access, and where Runner sends notifications. This page covers the full account lifecycle — from registering for the first time to updating your credentials later. ## Registering Open the Runner URL in your browser. If you do not have an account yet, click **Sign up** on the login page. Enter your email address and choose a password. Passwords must be at least eight characters long, include at least one letter, one number, and one special character, and must not contain spaces. Click **Sign Up** to submit. After registering, Runner sends a confirmation email to your address. Your account is inactive until you click the link in that email. If the email does not arrive, ask an Admin to confirm your account manually — see [Users & Roles](./users.md). ::: tip If no user accounts exist yet — for example, on a fresh installation — the sign-up form shows a **Create Admin User** button instead. The first account created this way is automatically assigned the Admin role. ::: ## Signing in Go to the Runner URL and enter your email address and password. Click **Login**. If your credentials are correct, Runner redirects you to the home page. If your account has not been confirmed yet, login is not possible until an Admin confirms it or you click the confirmation link in the email Runner sent when you registered. ## Recovering your password If you have forgotten your password, click **Recover it here** on the login page. Enter your email address and click **Continue**. Runner sends a password reset email to that address if an account exists for it. The response is intentionally vague to avoid leaking whether an email is registered. Click the link in the reset email to open the password reset form. Enter a new password that meets the same requirements as registration. Click **Continue** — Runner logs you in immediately and redirects you to the home page. ## Changing your email address Open your profile by clicking your avatar at the bottom of the left sidebar and selecting **Profile**. In the **Change Email Address** card, enter your new address and confirm with your current password. Click **Send Verification Email**. Runner sends a verification link to the new address. Click the link to confirm the change. For security reasons, all your active sessions are invalidated at that point — you will need to sign in again with your new address. Your new email must be different from your current one. ## Changing your password Open your profile (avatar at the bottom of the left sidebar) and find the **Change Password** card. Enter your current password, then choose a new password. The new password must meet the same requirements as registration and must be different from the current one. Click **Save New Password**. After the change, Runner logs you out of all active sessions. You will be redirected to the login page automatically after a few seconds. --- --- url: /runner/notifications.md description: 'Which account, membership, and run events send email, and how to set up SMTP.' --- # Notifications Runner sends email to your account address for events that affect your account, your project memberships, your access tokens, and the runs you care about. All emails require SMTP to be configured in [Settings](./settings.md) — if email is not set up, nothing is sent. ## Email sender Every email Runner sends uses the sender name and sender email address configured in [Settings](./settings.md). These appear in the **From** field. If no sender name is configured, only the email address is shown. Contact your Admin if you are not receiving emails or want to verify the configured sender. ## Email headers Runner sets custom headers on every notification email. Most mail clients — Gmail, Apple Mail, Thunderbird, and others — support filter rules based on custom headers, even if they are not visible by default. Use these to route Runner notifications into folders or apply labels automatically. | Header | Always present | Value | | -------------------------------------- | :------------: | ----------------------------------------------------------------------------------------------- | | `X-NodePit-Runner-Notification-Reason` | ✓ | The notification type, e.g. `run-status`, `member-added`, `user-access-token-expiring-soon`. | | `X-NodePit-Runner-Project-Id` | | The ID of the related project. Set on run, schedule, environment, and membership notifications. | | `X-NodePit-Runner-Environment-Id` | | The ID of the related environment. Set on run notifications. | | `X-NodePit-Runner-Schedule-Id` | | The ID of the related schedule. Set on run notifications. | | `X-NodePit-Runner-Run-Id` | | The ID of the run. Set on run notifications. | | `X-NodePit-Runner-Run-State` | | The run's outcome: `passed`, `failed`, or `canceled`. Set on run notifications. | A typical setup is a filter that moves all messages where `X-NodePit-Runner-Notification-Reason` is `run-status` to a dedicated folder, or one that separates notifications per project using `X-NodePit-Runner-Project-Id`. ## Run notifications Run notifications are the only emails you can configure yourself. They are set per schedule in the schedule's **Notifications** card — you choose which outcomes trigger an email: passed, failed, or canceled. See [Schedules](./schedules.md) for details. ## Account, membership, and token emails Runner sends automatic notifications for account events (registration, confirmation, password and email address changes), project membership changes (added, role changed, removed), and access token activity (created, deleted, expiring soon, expired). These emails cannot be disabled. They serve as security notices — if you receive one you did not expect, contact your Admin. --- --- url: /runner/access-tokens.md description: >- Authenticate with the Runner API using scoped, expiring personal access tokens instead of a password. --- # Access Tokens Personal access tokens let you authenticate with the Runner API without using your password. They are intended for automated use — CI pipelines, scripts, local development tooling — where interactive login is not possible. Each token is scoped to limit what it can do and expires automatically on a date you choose. Tokens are scoped primarily to project-level resources, plus a handful of account-wide reads: your own account details, basic information about other users, instance-wide search, and usage statistics — and, if you're an Admin, executor management. Even a Full Access token can never modify your profile or account credentials, and can only list or view — never create or revoke — tokens and connected applications; those actions always require signing in. If the consumer supports it, consider [connecting it via OAuth](./connected-applications.md) instead — it avoids handling a raw secret and can be revoked the same way. ## Your tokens Open **Integrations** from the left sidebar (or search for it) and find the **Personal Access Tokens** card. The list shows all your active tokens with their description, scope, expiry date, and when each was last used. A short prefix is shown below the description to help identify which token is which without revealing the full secret. Click a token to open its detail view, showing when it was created, when it was last used and from which IP address, and its total request count. ## Creating a token Click **Add Access Token** on the **Integrations** page. Fill in the following fields: **Description** — a short label identifying where the token will be used, for example `CI pipeline` or `local dev`. This is only for your reference. **Scope** — controls what operations the token permits: * **Full Access** — read and write access to everything the token can reach. * **Read Only** — read-only access to the same resources. Use this when the consumer only needs to fetch data. **Expires At** — the date on which the token stops working. The token becomes invalid on this date. The earliest allowed expiry is tomorrow; the form defaults to one month from today. After clicking **Create**, Runner shows the full token value exactly once in a dialog. Copy it immediately and store it somewhere safe — it cannot be retrieved again. Closing the dialog without copying means you will need to delete the token and create a new one. ## Using a token Pass the token in the `Authorization` header using the `ApiKey` scheme: ``` Authorization: ApiKey <your-token> ``` See the [API Reference](https://api.runner.nodepit.com/docs) for available endpoints. ## Revoking a token Click the delete button on a token row, either in the list or in its detail view. Revocation takes effect immediately — any request using that token will be rejected from that point on. Deleted tokens cannot be restored. Tokens are also automatically revoked when your account is deleted. ## Email notifications If SMTP is configured in [Settings](./settings.md), Runner sends you an email whenever a token is created or deleted on your account. Seven days before a token expires, you receive a reminder to rotate it. When the expiry date arrives and the token is deleted, you receive a final notification. These emails serve as security notices — if you receive one you did not initiate, revoke the token immediately and contact your Admin. --- --- url: /runner/connected-applications.md description: >- Let third-party apps and AI assistants connect to your Runner account via OAuth, without sharing your password. --- # Connected Applications Connected applications let a third-party app — an AI assistant talking to Runner over [MCP](./mcp-server.md), or any other OAuth-capable client — access your account without you sharing your password or copying a token by hand. You approve each connection once; Runner keeps the app signed in and lets you review or revoke access at any time. Like [personal access tokens](./access-tokens.md), even a connection with full access can never change your account or security settings. ## Connecting an application A client that supports OAuth initiates the connection itself — for example, by opening the URL an MCP client gives you, or by clicking a "Connect" button in the client's own settings. Runner opens a consent screen showing the application's name and the access it is requesting. If you are not already signed in, Runner asks for your email and password first. Click **Allow** to approve the connection, or close the window to deny it. Approving redirects you back to the application, which can now act on your behalf. ## Your connected applications Open **Integrations** from the left sidebar (or search for it) and find the **Connected Applications** card. It lists every application you have approved, alongside your personal access tokens. Click an application to open its detail view: **Application** — the name the application identified itself with when it connected. **Client ID** — the identifier the application registered under. Some applications register anew on every connection, leaving several entries that look alike — the client ID is what tells them apart, and what matches the application's own configuration. Only shown when the application reported one. **Redirect URIs** — the URLs the application may be redirected back to after you approve access. An unfamiliar entry here can indicate a hijacked or misconfigured client. **Scope** — **Full Access** (read and write) or **Read Only**, as requested by the application when it connected. **Software** — the application's name and version, when it reported them when connecting. **Contact** — an address for the application's maintainer, when it reported one when connecting. **Created** — when you first approved the connection. **Expires** — when the application's current access token expires. It renews automatically in the background as long as the connection keeps being used. **Refresh Token Expires** — once past this date, the application must ask you to reconnect before it can continue acting on your behalf. This is the date to watch for a connection you expect to stay active unattended, such as an AI assistant or an automated integration. **Last Used** and **Last Used From** — when the connection was last used, and from which IP address. **Request Count** — the total number of requests made through this connection. ## Revoking access Click the delete button on an application row, either in the list or in its detail view. Revocation takes effect immediately and disconnects the application — it will need to go through the consent screen again to reconnect. Revoked connections cannot be restored. ## Email notifications If SMTP is configured in [Settings](./settings.md), Runner sends you an email whenever an application connects or is disconnected. These emails serve as security notices — if you receive one for a connection you did not initiate, revoke it immediately and contact your Admin. --- --- url: /runner/mcp-server.md description: >- Manage projects, environments, schedules, and runs from Claude, ChatGPT, or any other MCP-compatible AI assistant. --- # AI Assistant (MCP Server) Runner exposes itself as an [MCP](https://modelcontextprotocol.io/) server, so an AI assistant can create and manage your projects, environments, schedules, and runs just by describing what you want — no need to click through the UI yourself. MCP (Model Context Protocol) is an open standard for connecting AI assistants to external tools and data; connecting Runner this way gives the assistant the same capabilities as the web UI, scoped to what your account can access. This goes well beyond answering questions. Because the assistant can call the same operations the UI uses, a single prompt can chain several steps together — provision an environment, wire up a schedule, and write the shell command it runs, all without you opening Runner at all. ## Connecting an assistant Open **Integrations** from the left sidebar (or search for it) and find the **Connect an AI Assistant** card. It shows your Runner instance's MCP address: ``` https://<your-runner>/mcp ``` Add this address in your assistant's connector or integration settings. For clients Runner recognizes, the dropdown next to the address gives a one-click **Add to…** link that opens the client's own "add connector" screen pre-filled with this address: * **Claude** — opens claude.ai's connector settings in a new tab. * **Cursor**, **VS Code**, **LM Studio** — opens the respective app directly, if installed. For any other MCP-compatible client, including **ChatGPT**, copy the address with the button next to it and paste it into that client's connector settings manually. The first time an assistant connects, Runner shows the same consent screen used for any [connected application](./connected-applications.md) — approve it to let the assistant act on your behalf. The connection then appears in your **Connected Applications** list, where you can review or revoke it at any time. See [Connecting an AI Assistant](./guides/connecting-an-ai-assistant.md) for a full walkthrough, from adding the connector to your first prompts. ### Self-hosted Runner without internet access Whether this works depends on where the assistant's connector settings actually run: * **claude.ai and ChatGPT** manage connectors from their own cloud — when you add one, their infrastructure calls your Runner instance's address directly. This only works if that address is reachable from the public internet over HTTPS. A Runner instance behind a VPN, firewall, or otherwise internal-only won't be reachable this way, regardless of how it's configured. * **Locally-run clients** — Claude Desktop, Claude Code, Cursor, VS Code, LM Studio — run as a process on your own machine, so they can reach an internal-only Runner instance the same way your browser already does. ::: tip If your Runner instance isn't internet-accessible, connect with a locally-run client instead, or bridge one that only supports remote HTTPS URLs (such as Claude Desktop's built-in connector UI) using [`mcp-remote`](https://www.npmjs.com/package/mcp-remote), which proxies the connection from your machine's network instead of the assistant's cloud. ::: ## What you can do Once connected, the assistant can read and write anything a **Full Access** [connection](./connected-applications.md) is scoped to — the same access a personal access token has: project-level resources, plus a handful of account-wide reads such as your own account details, other users' basic info, and instance-wide search and statistics. It can never modify your profile or account credentials, or create or revoke tokens on your behalf. If you only want the assistant to look things up, approve it with **Read Only** access instead. ### Looking things up * "List my Runner projects." * "Show me the schedules in my \[project name] project." * "Any failed runs recently? Show me the last few for \[project name] and pull up the log for the most recent failure." * "Which of my schedules are currently disabled?" * "How has the nightly-backup schedule been doing over the last month?" * "Search for anything related to 'nightly backup' — schedules, files, runs, whatever matches." * "What's my Runner account email, and what role do I have?" ### Building things This is where it gets interesting. The assistant is not limited to answering questions about existing state — it can design and provision entire environments and schedules from a plain-language description. A **Docker** schedule's [Command field accepts a full multi-line script](./schedules.md#docker), not just a single line, so the assistant typically writes the whole job as one inline command — installing whatever packages it needs at the start, then the actual logic — against a plain base image like `python:3.12-slim` or `node:20-slim`. That covers most requests end to end, without you touching the UI: * "Set up a new Docker environment in \[project name] using the `python:3.12-slim` image, then create a schedule that runs it every night at 2am and dumps our database with `pg_dump`, uploading the result to S3." * "Build a schedule that scrapes \[some URL] every hour with a Python script using `requests` and `beautifulsoup4`, and emails me if the page content changed." * "I need a Node.js job that pulls the latest exchange rates from an API and writes them to a CSV file. Set up the environment, install what it needs, and schedule it for 6am on weekdays." * "My nightly-backup schedule keeps failing — look at the last failed run's log, figure out what's wrong, and fix it." Because the assistant can install dependencies, write the entrypoint, and wire up the schedule in one pass, there is very little it cannot build this way — bash, Python, Node.js, or anything else that runs in a container. See [Building a Schedule From a Prompt](./guides/building-a-schedule-from-a-prompt.md) for a full example, and [Debugging a Failed Run with an AI Assistant](./guides/debugging-a-failed-run-with-an-ai-assistant.md) for using it to fix one that broke. ## Revoking access An AI assistant connects the same way any other [connected application](./connected-applications.md) does. Revoke it from the **Connected Applications** card on the **Integrations** page — revocation takes effect immediately. --- --- url: /runner/api.md description: >- The Runner REST API, published as Swagger UI, covering every operation available in the web UI. --- # API Reference NodePit Runner exposes a REST API that covers every operation available in the UI. Use it to automate workflows, integrate Runner into CI pipelines, or build tooling on top of it. The full API reference is published as a Swagger UI: [Open API Reference →](https://api.runner.nodepit.com/docs) Every running Runner instance also ships its own Swagger UI at `/api/docs` (e.g. `http://localhost:8080/api/docs`), reflecting the exact version you have deployed. The raw OpenAPI specification is available at `/api/docs/json`. Both links, ready to copy, are also on the **API Access** card on the [Integrations](./access-tokens.md) page. ## Authentication The API supports five authentication schemes depending on the use case. **Personal access tokens** — the standard way to authenticate external API calls. Tokens are scoped primarily to project-level resources, plus a handful of account-wide reads — see [Access Tokens](./access-tokens.md) for exactly what's included. They can never modify your profile or account credentials, or create or revoke tokens themselves. Pass the token using the `ApiKey` scheme: ``` Authorization: ApiKey <your-token> ``` See [Access Tokens](./access-tokens.md) for how to create a token and which scopes are available. **OAuth** — the standard way for a third-party application to authenticate on a user's behalf without ever handling their password. Runner runs an OAuth 2.1 authorization server supporting the authorization code flow with PKCE and dynamic client registration; a client discovers the authorization, token, and registration endpoints from: ``` GET /.well-known/oauth-authorization-server ``` Every authorization request shows the user a consent screen before a token is issued. The resulting access token is scoped to **read** or **write**, same as a personal access token, and is passed the same way: ``` Authorization: ApiKey <access-token> ``` Access tokens are short-lived and renew automatically via a refresh token, for as long as the connection keeps being used. See [Connected Applications](./connected-applications.md) for how users review and revoke a connection, and [AI Assistant (MCP Server)](./mcp-server.md) for the concrete flow an MCP client uses to connect this way. **Admin API key** — a static key set via the `API_KEY` environment variable in your [Runner configuration](./configuration.md). It grants access to executor management and run operations, and is primarily used by executors to register, send heartbeats, claim runs, and post logs. Pass it using the same `ApiKey` scheme: ``` Authorization: ApiKey <api-key> ``` **JWT bearer tokens** — used internally by the Runner web UI after login. The `Authorization: Bearer <token>` scheme is accepted but tokens are short-lived (7 days) and not designed for external use. **Download tokens** — a download started by the browser navigating to an address, such as a log, an artifact, or a file, cannot send an `Authorization` header. For these, request a short-lived token with `POST /download-token` and pass it as the `downloadToken` parameter on the download address. The token is valid for 15 seconds, grants no more access than you already have, and is accepted only for downloading. Access tokens and the user to impersonate are no longer accepted as address parameters — send the `Authorization` and `NodePit-Impersonated-UserId` headers instead. ## Further integrations [NodePit Runner for KNIME](./runner-for-knime.md) is a KNIME extension that lets you interact with Runner directly from within KNIME Analytics Platform, both via dedicated nodes and through the KNIME Explorer panel. [AI Assistant (MCP Server)](./mcp-server.md) lets an AI assistant such as Claude or ChatGPT call this API on your behalf through the Model Context Protocol, instead of you writing requests by hand. --- --- url: /runner/guides/connecting-an-ai-assistant.md description: >- Connect Claude to Runner over MCP and run your first prompts against a real project. --- # Connecting an AI Assistant This guide connects Claude to a Runner project over [MCP](../mcp-server.md) and runs a first few prompts against it, so you can see the whole chain — client, OAuth consent, tool call — work end to end before trying anything more ambitious. The same steps apply to any other MCP-compatible assistant, only the client-side setup screen looks different. ## Get the MCP address Open **Integrations** from the left sidebar (or search for it) and find the **Connect an AI Assistant** card. It shows your Runner instance's MCP address, in the form `https://<your-runner>/mcp`. ## Connect Claude Click the dropdown next to the address and choose **Claude** — this opens claude.ai's connector settings in a new tab with the address already filled in. Confirm adding the connector there. If you'd rather add it manually, or you're connecting a different client, copy the address instead and paste it into that client's own connector or integration settings. This only works if your Runner instance is reachable from the public internet over HTTPS — claude.ai's connector settings call that address from Anthropic's own cloud, not from your machine. If your instance is internal-only, see [Self-hosted Runner without internet access](../mcp-server.md#self-hosted-runner-without-internet-access) for how to connect a locally-run client instead. ## Approve the connection The first time Claude actually calls a tool, Runner shows a consent screen: "**Claude** wants to connect to your NodePit Runner account." Sign in if you aren't already, then choose a scope: * **Read Only** — enough for the prompts below, and a safe default while you're still finding your footing. * **Full Access** — needed once you want the assistant to create or change anything, see [Building a Schedule From a Prompt](./building-a-schedule-from-a-prompt.md). Click **Allow**. The connection now shows up under **Connected Applications** on the same **Integrations** page, where you can review or revoke it later. ## Run your first prompts Back in Claude, try: > List my Runner projects. Claude calls the `list-projects` tool and replies with the projects your account can see. Pick one from the reply and continue: > Show me the schedules in \[project name], and tell me if any of them are currently disabled. This chains two tools — listing schedules and reading each one's `active` state — into a single answer. If a schedule recently failed, ask: > Any failed runs in \[project name] in the last week? Show me the log for the most recent one. Once these come back correctly, the connection is working end to end and you're ready for a prompt that actually builds something — see [Building a Schedule From a Prompt](./building-a-schedule-from-a-prompt.md). --- --- url: /runner/guides/building-a-schedule-from-a-prompt.md description: >- Have an AI assistant provision a Docker environment, write the script, and schedule it — from one prompt. --- # Building a Schedule From a Prompt Once an assistant is [connected](./connecting-an-ai-assistant.md) with **Full Access**, it isn't limited to reading state back to you — it can provision an environment, write the entrypoint script, and schedule it, all from a plain description of the job. This guide walks through one example end to end: a daily exchange-rate fetch. ## Describe the job In Claude, describe what you want without specifying any Runner-specific details — the assistant works out the environment type, the image, and the script itself: > In my Finance project, I need a job that fetches the latest USD/EUR exchange rate from an API every morning at 6am, > and writes it to a CSV file. Set it up for me. ## Watch it work The assistant typically works through this in a few tool calls: 1. Lists environments in the Finance project to check whether a suitable one already exists. 2. Creates a **Docker** environment pointed directly at an existing image — usually `python:3.12-slim` or `node:20-slim` — since a plain HTTP call needs nothing installed at the image level. 3. Creates a **Docker** schedule on that environment and writes the whole job into the **Command** field: installing any packages the script needs at the start, then the script itself. There's no separate file to attach — the [Command field takes a full multi-line script](../schedules.md#docker) directly, so the assistant writes the entire thing inline, for example: ```sh pip install --quiet requests python3 -c " import csv import datetime import requests rate = requests.get('https://api.example.com/latest?base=USD&symbols=EUR', timeout=10).json()['rates']['EUR'] with open('/nodepit/rates.csv', 'a', newline='') as f: csv.writer(f).writerow([datetime.date.today().isoformat(), rate]) " ``` 4. Sets the **Schedule** cron expression to `0 6 * * *`. Claude explains each step as it goes and tells you when it's done, including the schedule's name so you can find it. ## Verify in Runner Open the schedule Claude created and check the fields: * **Environment** — the Docker image it picked. * **Command** — the full script it wrote, including anything it decided to install. Read it before trusting it with real credentials. * **Schedule** — the cron expression, and that it matches the time zone configured in [Settings](../settings.md). Click **Run Now** to trigger it immediately instead of waiting for 6am, and check the run's log to confirm it worked. ## Iterate conversationally If something's off, just say so instead of editing it yourself: > The CSV should also include a timestamp column, and email me if the API request fails. Claude rewrites the **Command** field directly — no need to open an editor or touch the Runner UI yourself. This back-and-forth is the real point: describing behavior in plain language and letting the assistant translate it into a working environment and schedule, iterating until it's right. ## A few more starting points The same pattern — a Docker environment plus an inline **Command** — works for almost anything that can run as a script or in a container: * "Build a schedule that scrapes \[some URL] every hour with a Python script using `requests` and `beautifulsoup4`, and emails me if the page content changed." * "Take this Bash script \[paste it] and turn it into a Docker schedule that runs every 15 minutes, with an environment variable for the API key." * "Create a Docker schedule in \[project name] that runs `pg_dump` against our database and uploads the result to S3 — write the command for me." See [AI Assistant (MCP Server)](../mcp-server.md) for the full list of what a connected assistant can do, and [Debugging a Failed Run with an AI Assistant](./debugging-a-failed-run-with-an-ai-assistant.md) for when one of these jobs breaks later. --- --- url: /runner/guides/debugging-a-failed-run-with-an-ai-assistant.md description: >- Have an AI assistant read a failed run's log, diagnose the cause, and fix the script. --- # Debugging a Failed Run with an AI Assistant A schedule you built — or inherited from a colleague — just failed, and you don't want to dig through the log yourself. With an assistant [connected](./connecting-an-ai-assistant.md) over MCP, you can hand it the whole diagnose-and-repair loop: reading the log, finding the cause, and updating the script. ## Point it at the failure > My nightly-backup schedule in the Ops project failed last night. What happened? The assistant lists recent runs for that schedule, finds the failed one, and pulls its log via `get-run` and `get-run-log`. It replies with what actually went wrong — for example, a missing environment variable, an unreachable host, or a dependency that failed to install — rather than just pasting the raw log back at you. ## Ask for a fix If the cause is something the script itself can handle: > Fix the script so it retries the S3 upload up to three times before failing. The assistant rewrites the schedule's **Command** field directly and the fix is live immediately. If the cause is external to the script instead — for example, a secret that expired — it tells you what to change, since it can't act on things outside Runner's reach: > The database password in that script's environment variable looks wrong — you'll need to update it, then I can > re-run the job to confirm. ## Confirm the fix > Run it now and show me whether it passes this time. The assistant triggers the schedule with `run-schedule` and reports back once the new run finishes. If it still fails, it can pull the new log and continue iterating without you switching back to the Runner UI at all. ## When to step in yourself Treat this as a fast first pass, not a substitute for review — especially for schedules that touch production data or credentials. Read what changed in the script before trusting it with real infrastructure, the same way you would review a colleague's fix. See [Building a Schedule From a Prompt](./building-a-schedule-from-a-prompt.md) for how these scripts get created in the first place, and [Runs](../runs.md) for what each run status means. --- --- url: /runner/guides/triggering-runs-from-ci.md description: >- Trigger a Runner schedule from a CI/CD pipeline via the API and fail the pipeline on a bad result. --- # Triggering Runs from CI/CD If a pipeline needs to kick off a Runner schedule and wait for the result — for example, running a KNIME workflow or shell script as part of a deploy — call the API directly instead of scripting the web UI. This guide triggers a schedule, polls until it finishes, and fails the pipeline if the run didn't pass. ## Create a token Create a Personal Access Token with **Full Access** scope — triggering a run is a write operation, so a Read Only token won't work. See [Access Tokens](../access-tokens.md) for how to create one and where to store it as a pipeline secret. ## Find the schedule ID Open the schedule in Runner. The ID is the path segment right after `/schedules/` in the browser's address bar — copy it from there. ## Trigger the run ```sh RUN_ID=$(curl -sf -X PUT "https://runner.example.com/api/schedule/$SCHEDULE_ID/run" \ -H "Authorization: ApiKey $RUNNER_TOKEN" | jq -r '._id') ``` The response is the newly created run, including its `_id` and initial `status` of `pending`. ## Poll until it finishes ```sh while true; do STATUS=$(curl -sf "https://runner.example.com/api/run/$RUN_ID" \ -H "Authorization: ApiKey $RUNNER_TOKEN" | jq -r '.status') case "$STATUS" in passed|failed|canceled) break ;; esac sleep 5 done ``` See [Runs](../runs.md#run-statuses) for what each status means. `pending`, `running`, and `canceling` are active states; `passed`, `failed`, and `canceled` are terminal — the loop above stops as soon as one of those is reached. ## Fail the pipeline on a bad result ```sh if [ "$STATUS" != "passed" ]; then echo "Run $RUN_ID finished with status $STATUS" exit 1 fi ``` Combine the three snippets into a single pipeline step, substituting your Runner host, `$SCHEDULE_ID`, and a `$RUNNER_TOKEN` secret from your CI system's variable store. --- --- url: /runner/guides/routing-to-executors.md description: Use tags to route resource-heavy or reserved schedules to specific executors. --- # Routing Runs to Dedicated Executors By default, any online executor can pick up any run. If you have a resource-heavy workflow — one that needs more memory, a GPU, or specific hardware — or want to reserve a machine for one team's schedules, use tags to route runs to the executor that should handle them. Say you've stood up one bigger executor for a memory-hungry KNIME workflow, while everything else keeps running on your existing shared executors. ## Tag the dedicated executor Set the tag either when the executor first registers, or afterwards on its detail page: * **At registration** — set `INITIAL_TAGS` in `docker-compose.yml` before starting the container, for example `INITIAL_TAGS: large`. This only applies the first time the executor registers. * **After registration** — open [Executors](../executors.md), click the executor, and add `large` to its **Tags** field. Requires Admin. ## Tag the environment or schedule Add `large` as an **Executor Tag** on the environment (if every schedule using it should route to the dedicated executor) or on the schedule (if only that one schedule should). Environment and schedule tags are merged together, so you can tag broadly on the environment and add more specific tags per schedule. ## Understand what tagging does — and doesn't — guarantee Tagging the executor `large` does **not** reserve it exclusively for `large`-tagged runs. Runner's matching rule is: a tagged executor picks up any run sharing one of its tags, **plus any run with no tags at all**. So your new `large` executor will still pick up ordinary, untagged runs from anywhere else in the project whenever it's idle — it isn't dedicated yet, just additionally eligible. To actually reserve it, make sure nothing else is tagless: tag your regular schedules and environments with something like `standard`, and keep the dedicated executor tagged only `large` (not `standard`). Since `standard`-tagged runs no longer share a tag with the `large` executor and are no longer tagless, they won't be dispatched there — leaving it free for the workflow that actually needs it. Your existing shared executors, tagged `standard`, keep handling everything else. ## Verify Open [Executors](../executors.md) to confirm the dedicated executor shows the `large` tag and is online. Trigger the heavy schedule with **Run Now** and check the run's **Executor** card to confirm it landed on the right one. If it stays `pending`, double-check that the tags on the executor and the schedule (or its environment) actually overlap — see [How runs are dispatched](../executors.md#how-runs-are-dispatched) for the full matching rules. --- --- url: /runner/guides/filtering-notification-emails.md description: >- Route run-status notification emails into a dedicated folder using their custom headers. --- # Filtering Notification Emails Every notification Runner sends carries custom headers — `X-NodePit-Runner-Notification-Reason`, `X-NodePit-Runner-Project-Id`, and others listed in [Notifications](../notifications.md#email-headers). Most desktop mail clients can filter on these directly, even though they aren't shown by default. This guide sets up a filter that moves all run-status emails into a dedicated folder, using Thunderbird, Outlook, and Apple Mail as examples. ## Thunderbird 1. Go to **Tools → Message Filters** and click **New**. 2. Under **if the following conditions are met**, open the first dropdown and choose **Customize…**. 3. Add a new header named `X-NodePit-Runner-Notification-Reason` and select it from the condition dropdown. 4. Set the comparison to **contains** and enter `run-status`. 5. Under **Perform these actions**, choose **Move Message to** and pick or create a folder. 6. Save the filter. It applies to new mail from now on — use **Run Filters Now** on an existing folder to apply it retroactively. ## Outlook 1. Go to **Home → Rules → Manage Rules & Alerts** and click **New Rule**. 2. Choose **Apply rule on messages I receive** and click **Next**. 3. Check **with specific words in the message header**, then click the **specific words** link in the description pane. 4. Enter `X-NodePit-Runner-Notification-Reason: run-status` and click **Add**, then **OK**. 5. Choose an action, such as **move it to the specified folder**, and finish the wizard. ## Apple Mail 1. Go to **Mail → Settings… → Rules** and click **Add Rule**. 2. Name the rule, then open the first condition's dropdown and choose **Other Header…**. 3. Enter `X-NodePit-Runner-Notification-Reason` as the header name, set the comparison to **Contains** or **Is equal to**, and enter `run-status` as the value. 4. Under **Perform the following actions**, choose **Move Message** and select a mailbox. 5. Click **OK** to save. ## Going further Combine headers for finer-grained routing — for example, a rule matching `X-NodePit-Runner-Notification-Reason: run-status` together with `X-NodePit-Runner-Project-Id: <your-project-id>` files run notifications per project instead of into one shared folder. Find a project's ID in its URL in the Runner web app. If your mail client isn't listed here, check its documentation for filtering on a "custom header" or "message header" condition — the concept is the same, only the menu names differ. See [Notifications](../notifications.md#email-headers) for the full list of headers and when each is set. --- --- url: /runner/guides/knime-views.md description: >- Fix KNIME Views and JavaScript Views nodes failing with GTK or display errors in Runner. --- # KNIME Views Workflows that use [KNIME Views](https://nodepit.com/iu/org.knime.features.base.views.feature.group) or [KNIME JavaScript Views](https://nodepit.com/iu/org.knime.features.js.views.feature.group) extensions — such as the Line Plot or Bar Chart nodes — may fail in Runner with one of these errors: * `ERROR:elf_dynamic_array_reader.h(64) tag not found` * `Execute failed: No more handles [gtk_init_check() failed]` This is caused by a bug in the Chromium browser embedded in those extensions. The fix is to switch to the bundled legacy Chromium browser and configure two preference entries in your environment. 1. Open the environment and use **Extension Search** to add **KNIME Bundled Chromium Browser (legacy)**. 2. Under **Preference Entries**, add the following two entries: | Key | Value | | ----------------------------------------------------- | -------------------------------------------------------------- | | `/instance/org.knime.js.core/js.core.headlessBrowser` | `org.knime.ext.seleniumdrivers.multios.ChromiumImageGenerator` | | `/instance/org.knime.js.core/js.core.viewBrowser` | `org.knime.ext.seleniumdrivers.multios.ChromiumWizardNodeView` | 3. Save the environment and run your schedule. See [Environments](../environments.md) for the full list of available settings. --- --- url: /runner/guides/r-integration.md description: Install R into a KNIME environment for the R Statistics Integration extension. --- # R Integration If your KNIME workflow uses nodes from the [KNIME Interactive R Statistics Integration](https://nodepit.com/iu/org.knime.features.r.feature.group) extension, you need to install R into your environment. Runner does not include R by default — it must be added via a Dockerfile instruction. ## Installing R 1. Open the environment and go to **Additional Dockerfile Instructions**. 2. Add the following snippet. It installs `r-base` and `Rserve` — the package that lets KNIME communicate with R: ```dockerfile RUN apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get install -yq r-base \ && rm -rf /var/lib/apt/lists/* \ && R -e "install.packages('Rserve',,'http://rforge.net/',type='source')" ``` R will be available at `/usr/lib/R` and is discovered automatically by the KNIME Interactive R Statistics nodes. 3. Save the environment and run your schedule. ## Adding R packages To install additional R packages, extend the `RUN` command: ```dockerfile RUN apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get install -yq r-base \ && rm -rf /var/lib/apt/lists/* \ && R -e "install.packages(c('Rserve', 'ggplot2', 'dplyr'),,'http://rforge.net/',type='source')" ``` See [Environments](../environments.md) for the full list of available settings. --- --- url: /runner/guides/python-scripting.md description: >- Set up KNIME's bundled or a custom Python environment for the Python scripting nodes. --- # Python Scripting Runner supports KNIME's Python scripting nodes. The recommended approach is to use the [new Python nodes](https://nodepit.com/category/scripting/python) (`org.knime.features.python3.scripting.feature.group`), which include a bundled Python environment and require no additional setup beyond installing the extension. The legacy "Python (legacy)" nodes require a manual Python installation and are not officially supported. ## Using the bundled Python environment 1. Open the environment and use **Extension Search** to add **KNIME Python Integration**. Confirm that the feature `org.knime.features.python3.scripting.feature.group` is listed under **Features**. 2. Under **Preference Entries**, add: | Key | Value | | ------------------------------------------------------------------- | --------- | | `/instance/org.knime.python3.scripting.nodes/pythonEnvironmentType` | `bundled` | 3. Save the environment and run your schedule. ## Using a custom Python installation If the bundled environment does not meet your needs — specific Python version, dependencies not available in the bundled distribution — you can install Python manually via a Dockerfile instruction. 1. Open the environment and use **Extension Search** to add **KNIME Python Integration** as above. 2. Under **Additional Dockerfile Instructions**, add a snippet to install Python and your dependencies. The example below installs Python 3.9 with `py4j`, `pyarrow`, `numpy`, and `pandas` — adapt the version and package list to your requirements: ```dockerfile ENV DEBIAN_FRONTEND=noninteractive RUN apt update && apt install -y software-properties-common RUN add-apt-repository ppa:deadsnakes/ppa RUN apt update && apt install -y python3.9 python3.9-distutils python3.9-venv RUN python3.9 -m ensurepip RUN pip3.9 install py4j pyarrow numpy pandas ``` 3. Under **Preference Entries**, add: | Key | Value | | ------------------------------------------------------------------- | ----------- | | `/instance/org.knime.python3.scripting.nodes/pythonEnvironmentType` | `manual` | | `/instance/org.knime.python3.scripting.nodes/python3Path` | `python3.9` | Make sure `python3Path` matches the Python binary name from your Dockerfile snippet. 4. Save the environment and run your schedule. See [Environments](../environments.md) for the full list of available settings. --- --- url: /runner/guides/selenium-nodes.md description: >- Set up headless Chrome and a license for Selenium Nodes web-automation workflows. --- # Selenium Nodes [Selenium Nodes for KNIME](https://seleniumnodes.com) enable web scraping, browser automation, and UI testing from within KNIME workflows. Running them in Runner requires a headless Chrome setup and a valid Selenium Nodes license configured as a preference entry. ## Prerequisites * A valid Selenium Nodes license key * Your workflow must use **Chrome for Testing (bundled)** in the Start WebDriver or WebDriver Factory node — not a system Chrome installation ## Configuring the environment 1. In your workflow, open the **Start WebDriver** or **WebDriver Factory** node and set the browser to **Chrome for Testing (bundled)**. 2. Open the environment and use **Extension Search** to add both: * **Selenium Nodes for KNIME** * **Selenium Nodes for KNIME: Chrome for Testing** 3. Under **Preference Entries**, add your license key. Before pasting it, reformat it onto a single line: replace line breaks with `\n` and escape any `=` characters as `\=`. | Key | Value | | --------------------------------------------------------------------------- | -------------------------------- | | `/instance/com.nodepit.licensing.plugin/ws.palladian.nodes.selenium.plugin` | `<your reformatted license key>` | 4. Under **JVM Arguments**, add the following to the argument list: ``` -Dseleniumnodes.chromium.args='--headless=new --no-sandbox --disable-dev-shm-usage' ``` 5. Save the environment and run your schedule. See [Environments](../environments.md) for the full list of available settings. --- --- url: /runner/guides/jdbc-drivers.md description: >- Register a vendor-provided JDBC driver, such as Oracle's, in a KNIME environment. --- # JDBC Drivers Some databases — OracleDB, for example — are not shipped with a JDBC driver by KNIME. To connect to these databases from a Runner workflow, you need to register a vendor-provided driver in your environment. 1. Download the JDBC driver from your database vendor (typically a `.jar` file, e.g. `ojdbc8.jar`). Register it in your local KNIME Analytics Platform following the [KNIME Database Extension Guide](https://docs.knime.com/latest/db_extension_guide/index.html#register_jdbc) and confirm that your workflow connects successfully before continuing. 2. Once the local connection works, export your KNIME preferences via **File → Export Preferences…**. The exported `.epf` file contains the driver registration entries you will need. 3. Open the environment and go to **Additional Files**. Upload the driver `.jar` file. Runner makes it available inside the container at `/nodepit/<filename>` — for example, `/nodepit/ojdbc8.jar`. 4. Under **Preference Entries** (or **Preference File** if you prefer to use the exported `.epf`), add an entry that points to the driver file in `/nodepit`. Check your exported preferences for the correct key. For a driver named `OracleDB`, the entry looks like this: | Key | Value | | ------------------------------------------------------- | --------------------- | | `/instance/org.knime.database/drivers/OracleDB/paths/0` | `/nodepit/ojdbc8.jar` | The key structure varies by database and driver name — use the exported preferences as your reference. 5. Save the environment and run your schedule. See [Environments](../environments.md) for the full list of available settings. --- --- url: /runner/guides/shell-tooling.md description: >- Install curl, jq, the AWS CLI, or other tools into a Shell environment's minimal Alpine image. --- # Installing Tools for Shell Scripts Shell environments start from a minimal Alpine Linux image — enough to run a `.sh` script, but nothing beyond a basic shell. If your script needs `curl`, `jq`, the AWS CLI, or any other tool, install it via **Additional Dockerfile Instructions**, since Shell environments have no dedicated settings of their own for this. ## Installing packages with apk 1. Open the Shell environment (or create one) and go to **Advanced** → **Additional Dockerfile Instructions**. 2. Add a `RUN` instruction using Alpine's package manager, `apk`. For example, to install `curl` and `jq`: ```dockerfile RUN apk add --no-cache curl jq ``` 3. Save the environment and run your schedule. Search the [Alpine package index](https://pkgs.alpinelinux.org/packages) for the exact package name if you're not sure what to install — Alpine's package names sometimes differ from Debian or Ubuntu's. ## Installing the AWS CLI Alpine doesn't ship the AWS CLI as a single package. Install it into a virtual environment and link the binary onto the `PATH`: ```dockerfile RUN apk add --no-cache python3 py3-pip \ && python3 -m venv /opt/awscli \ && /opt/awscli/bin/pip install --no-cache-dir awscli \ && ln -s /opt/awscli/bin/aws /usr/local/bin/aws ``` ## Installing Python or Node.js If your script shells out to `python3` or `node`, install the corresponding Alpine package: ```dockerfile RUN apk add --no-cache python3 py3-pip ``` ```dockerfile RUN apk add --no-cache nodejs npm ``` Combine multiple `RUN` instructions, or chain them with `&&`, to install everything your script depends on in one environment. See [Environments](../environments.md#advanced) for the full Additional Dockerfile Instructions reference. --- --- url: /runner/guides/migrating-cron-jobs.md description: >- Move an existing server cron job into Runner as a Docker environment and schedule. --- # Migrating a Cron Job If you already run a job as a cron entry on some server — a Python script, a Node.js task, a compiled binary, anything you can package into a container — you can move it into Runner as a **Docker** environment and schedule instead of rebuilding it as a KNIME workflow or shell script. This guide walks through that migration end to end. Say you currently have a crontab entry like this on some server: ``` 0 * * * * /opt/jobs/sync-inventory/run.sh ``` ## Package the job as an image If you don't already have a Docker image for the job, write a minimal Dockerfile around it. For a Python script with a few dependencies: ```dockerfile FROM python:3.12-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY sync_inventory.py . ENTRYPOINT ["python", "sync_inventory.py"] ``` Build and push it to a registry your Runner installation can reach — Docker Hub, a private registry, or one hosted alongside your other CI images: ```sh docker build -t registry.example.com/acme/sync-inventory:1.0 . docker push registry.example.com/acme/sync-inventory:1.0 ``` If you'd rather have Runner build the image itself, skip the push and upload the Dockerfile directly in the next step instead. In that case, also upload `requirements.txt` and `sync_inventory.py` as **Additional Files** on the environment (not the schedule) — Runner makes the environment's Additional Files available to the Dockerfile's `COPY` and `ADD` instructions during the build. Files added on the schedule instead are only mounted into the container at runtime and won't be there yet when the image builds. See [Source](../environments.md#docker) in the Environments reference. ## Create the Docker environment In your project, click **Add Environment**, select **Docker** as the type, and fill in: * **Source** — **Image**, since you already built and pushed one. * **Image** — `registry.example.com/acme/sync-inventory:1.0`. * **Private Registries** — add an entry for `registry.example.com` with the credentials that can pull the image, if the registry isn't public. Save the environment. Runner doesn't build anything yet — the image is only pulled the first time a schedule using this environment runs. ## Create the schedule Click **Add Schedule**, select the environment you just created, and fill in: * **Schedule** — `0 * * * *`, matching the original crontab entry. All cron expressions run in the time zone configured in [Settings](../settings.md), so double-check it matches what the original cron job assumed. * **Command** — leave empty if your image's `ENTRYPOINT` already does the right thing, as in the example above. Otherwise, override it here. * **Environment Variables** — move over anything the script previously read from the shell environment or an `.env` file next to it, for example API keys or a target hostname. If the job reads or writes files — a config file, credentials, an output directory — add them under **Advanced** → **Additional Files** on the schedule (schedule-specific) or the environment (shared across schedules). Files are mounted at `/nodepit/<filename>`; anything the container writes there is collected into the run's artifact archive. See [Schedules](../schedules.md) for the full field reference. ## Verify Save the schedule, then click **Run Now** to trigger it immediately instead of waiting for the next cron tick. Open the run and check the log output — this is your old cron job's stdout/stderr, now searchable and retained according to the schedule's **Remove Runs After** setting instead of scrolling through a log file on the original server. Once you're confident the run behaves the same as the original job, decommission the crontab entry. ## Parametrizing a build If you went the Dockerfile route instead of a pre-built image, use **Build Arguments** to avoid hardcoding values like a base image version into the Dockerfile itself: ```dockerfile ARG PYTHON_VERSION=3.12 FROM python:${PYTHON_VERSION}-slim ``` Add a `PYTHON_VERSION` build argument on the environment to override it without editing the Dockerfile — useful for testing a version bump on a copy of the environment before rolling it out. See [Environments](../environments.md) for the full list of Docker-specific settings. --- --- url: /runner/guides/website-monitoring.md description: >- Check that a website responds and alert Slack when it doesn't, using a Docker schedule. --- # Monitoring a Website Docker environments are a good fit for small monitoring jobs that don't need a full workflow — checking that a site responds, and alerting a Slack channel when it doesn't. This guide walks through setting one up end to end: an environment, a schedule, and a Command that retries before giving up. ## Create the environment 1. Go to **Environments** and click **Add Environment**. 2. Set **Type** to **Docker** and **Source** to **Image**. 3. Set **Image** to `curlimages/curl:latest` — a minimal image that ships `curl` and nothing else, which is all this Command needs. 4. Save the environment. ## Write the schedule 1. Go to **Schedules** and click **Add Schedule**. 2. Set **Environment** to the Docker environment created above. 3. Under **Environment Variables**, add `SLACK_WEBHOOK_URL` with the webhook URL for the Slack channel that should receive the alert. 4. Set **Command** to a retry loop that posts to Slack only once all attempts have failed: ```bash URL="https://example.com" MAX_RETRIES=3 for i in $(seq 1 $MAX_RETRIES); do echo "Attempt $i/$MAX_RETRIES: checking $URL ..." if curl -sf -o /dev/null "$URL"; then echo "Success: $URL is reachable" exit 0 fi echo "Attempt $i failed" sleep 5 done echo "All $MAX_RETRIES attempts failed, notifying Slack" curl -X POST -H 'Content-type: application/json' \ --data "{\"text\":\"$URL is not responding after $MAX_RETRIES attempts\"}" \ "$SLACK_WEBHOOK_URL" exit 1 ``` Exiting non-zero on final failure also marks the run as `failed`, so Runner's own run history and any [Notifications](../schedules.md#notifications) you've enabled reflect the outage too — the Slack post is an additional, faster channel. 5. Set **Schedule** to how often the check should run, for example `*/5 * * * *` for every 5 minutes. 6. Save the schedule and set it to **Active**. ## Adjusting the example * Swap `curlimages/curl` for a `python` or `node` image and rewrite the Command in that language — see the examples in [Schedules](../schedules.md#docker). * If the check needs a tool the image doesn't include, install it via the environment's **Additional Dockerfile Instructions** instead of switching images — see [Environments](../environments.md#advanced). * To alert multiple channels or add email, extend the final `curl` call or enable the schedule's own **Notify on failed runs** toggle instead of maintaining the logic in the Command. --- --- url: /runner/guides/database-backups.md description: >- Dump a PostgreSQL database, compress it, and upload it to S3 on a nightly Docker schedule. --- # Backing Up a Database to S3 A Docker environment is enough to run a nightly database backup without a dedicated backup service — dump the database, compress it, and upload it straight to S3. This guide walks through the setup for a PostgreSQL database, using an environment, a schedule, and a Command that pipes three tools together. ## Create the environment 1. Go to **Environments** and click **Add Environment**. 2. Set **Type** to **Docker** and **Source** to **Image**. 3. Set **Image** to `postgres:16-alpine` — it ships `pg_dump`, but not the AWS CLI, so add that under **Additional Dockerfile Instructions**: ```dockerfile RUN apk add --no-cache aws-cli ``` 4. Save the environment. ## Write the schedule 1. Go to **Schedules** and click **Add Schedule**. 2. Set **Environment** to the Docker environment created above. 3. Under **Environment Variables**, add the database connection details and AWS credentials: | Name | Value | | ----------------------- | ----------------------------------- | | `DB_HOST` | your database host | | `DB_USER` | your database user | | `DB_NAME` | the database to back up | | `PGPASSWORD` | the database user's password | | `AWS_ACCESS_KEY_ID` | AWS access key with S3 write access | | `AWS_SECRET_ACCESS_KEY` | the matching secret key | | `AWS_DEFAULT_REGION` | the S3 bucket's region | `pg_dump` reads `PGPASSWORD` automatically, and the AWS CLI reads the `AWS_*` variables — neither needs to be passed on the command line. 4. Set **Command** to dump, compress, and upload in one pipeline: ```bash pg_dump -h "$DB_HOST" -U "$DB_USER" "$DB_NAME" \ | gzip \ | aws s3 cp - "s3://backups/$DB_NAME-$(date +%F).sql.gz" ``` 5. Set **Schedule** to `0 2 * * *` for a nightly backup at 2am. 6. Save the schedule and set it to **Active**. ## Adjusting the example * For MySQL or MariaDB, use a `mysql:8` or `mariadb:11` image and swap the Command for `mysqldump -h "$DB_HOST" -u "$DB_USER" "$DB_NAME" | gzip | aws s3 cp - ...`. * To upload elsewhere, replace the final `aws s3 cp` with the CLI for your target — for example `az storage blob upload` for Azure Blob Storage, installed the same way via **Additional Dockerfile Instructions**. * Enable **Notify on failed runs** on the schedule so a failed `pg_dump` or upload doesn't go unnoticed — see [Notifications](../schedules.md#notifications). --- --- url: /runner/guides/scheduled-report-email.md description: >- Query an API, format a summary, and email it on a schedule using Python's standard library. --- # Sending a Scheduled Report Email A Docker environment can generate and send a report just as easily as it can back up a database or watch a website — query wherever your data lives, format a summary, and mail it out on a schedule, without a dedicated reporting tool. This guide builds a weekly digest of a GitHub repository's open issues, emailed every Monday morning. The script below is ordinary Python — nothing about it is specific to Runner. If you already have a script like this sitting in a `.py` file somewhere, you don't need to adapt it: paste its full contents straight into the **Command** field as-is, and Runner runs it exactly as written. ## Create the environment 1. Go to **Environments** and click **Add Environment**. 2. Set **Type** to **Docker** and **Source** to **Image**. 3. Set **Image** to `python:3.12-slim` — the report script below only needs the standard library, so no extra dependencies to install. 4. Save the environment. ## Write the schedule 1. Go to **Schedules** and click **Add Schedule**. 2. Set **Environment** to the Docker environment created above. 3. Under **Environment Variables**, add the repository to report on and the SMTP credentials to send with: | Name | Value | | --------------- | ------------------------------------------ | | `GITHUB_REPO` | the repository to report on, `owner/repo` | | `SMTP_HOST` | your SMTP server hostname | | `SMTP_PORT` | usually `587` | | `SMTP_USER` | the sending account's username | | `SMTP_PASSWORD` | the sending account's password | | `REPORT_TO` | the address that should receive the report | ::: tip These are separate from the SMTP server configured in [Settings](../settings.md) — that configuration is only used for Runner's own account and run-status emails, never from within a script. A schedule needs its own credentials to send mail. ::: 4. Set **Command** to the full script below, pasted in as one block: ```bash python3 -c " import json import os import smtplib import urllib.request from email.mime.text import MIMEText repo = os.environ['GITHUB_REPO'] url = f'https://api.github.com/repos/{repo}/issues?state=open' req = urllib.request.Request(url, headers={'Accept': 'application/vnd.github+json'}) with urllib.request.urlopen(req, timeout=10) as resp: issues = [i for i in json.load(resp) if 'pull_request' not in i] lines = [f'{len(issues)} open issue(s) in {repo}:', ''] for issue in issues: number = issue['number'] title = issue['title'] link = issue['html_url'] lines.append(f'- #{number} {title} ({link})') body = '\n'.join(lines) msg = MIMEText(body) msg['Subject'] = f'Weekly issue digest: {repo}' msg['From'] = os.environ['SMTP_USER'] msg['To'] = os.environ['REPORT_TO'] with smtplib.SMTP(os.environ['SMTP_HOST'], int(os.environ['SMTP_PORT'])) as smtp: smtp.starttls() smtp.login(os.environ['SMTP_USER'], os.environ['SMTP_PASSWORD']) smtp.send_message(msg) print('Sent digest with ' + str(len(issues)) + ' issue(s) to ' + os.environ['REPORT_TO']) " ``` 5. Set **Schedule** to `0 8 * * 1` for every Monday at 8am. 6. Save the schedule and set it to **Active**. ## Adjusting the example * Swap the GitHub API call for wherever your report's data actually lives — an internal API, a database query, a CSV export. The shape stays the same: fetch, format, send. * For an HTML-formatted report, build a `MIMEMultipart` message with an `'html'`-subtype `MIMEText` part instead of plain text, and format the summary as a table. * Enable **Notify on failed runs** on the schedule so a broken query or SMTP error doesn't silently mean nobody gets the report — see [Notifications](../schedules.md#notifications). * If the report needs a package beyond the standard library, install it at the start of the Command with `pip install --quiet <package>` rather than switching to a Dockerfile source — see the Command examples in [Schedules](../schedules.md#docker). * If you'd rather maintain the script as its own file — for version control, or to share it across schedules — upload it as an **Additional File** instead of pasting it into Command, and set Command to `python3 /nodepit/report.py`. --- --- url: /runner/architecture.md description: >- How Runner's API, Web, Executor, and database services fit together, and what network access each needs. --- # System Overview NodePit Runner is made up of four services that work together. Understanding how they fit together helps you plan your deployment, troubleshoot problems, and appreciate what happens behind the scenes when a scheduled workflow runs. ## Components ```mermaid graph TD Browser["Browser"] --> Web["Web"] Web --> API["API"] API <--> DB["MongoDB"] Executor["Executor"] --> API Executor --> Worker["Worker Container"] Executor <--> Worker Executor -.-> Registry["Docker Registry\n(optional)"] ``` **Web** serves the browser-based user interface. It talks exclusively to the API — it has no direct access to the database or executor infrastructure. **API** is the central service. It stores all configuration and state in MongoDB, serves the REST API consumed by the Web frontend and by external clients, and coordinates executors. See [API Reference](./api.md) for the available endpoints. **MongoDB** is the persistence layer. All projects, environments, schedules, runs, logs, and user accounts are stored here. **Executor** is the service that actually runs your workflows and scripts. It polls the API for pending runs, builds a Docker image for the run's environment (or pulls a cached one), and starts a short-lived **worker container** to execute the workflow or script in isolation. When the worker finishes, the executor collects logs and output files and reports the result back to the API. You can run multiple executor instances to handle concurrent runs. ## Infrastructure requirements Each executor needs two things on the host: * **Docker socket** (`/var/run/docker.sock`) — required to build images and spawn worker containers. This gives the executor the same privileges as the Docker daemon on the host; treat executor host access accordingly. * **Shared data volume** — mounted at `/opt/data` in the executor container and passed through to each worker. Used to transfer the workflow file and additional files into the worker and collect output files from it. Both are pre-configured in the official `docker-compose.yml` and require no manual setup for a standard deployment. ## External network access Runner makes outbound connections to several external services. Deployments in restricted network environments need to allow these. | Host | Environments | Purpose | | ------------------------------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------- | | `nodepit.com` | All | Extension Search in the UI; update version check shown in Settings | | `registry-1.docker.io` | All | Docker Hub — Ubuntu base image (KNIME) and Alpine base image (Shell) | | `download.nodepit.com` | KNIME | NodePit Batch, used internally to execute KNIME workflows | | `archive.ubuntu.com`, `security.ubuntu.com` | KNIME | Ubuntu apt — system dependencies | | `download.knime.org` | KNIME | KNIME Analytics Platform | | Update sites (as configured) | KNIME | Extension update sites; only required when extensions are installed | | `dl-cdn.alpinelinux.org` | Shell | Alpine apk — system dependencies | | Configured registries (as set on the environment) | Docker | Pulling images or base images from private registries configured in a Docker environment's Private Registries | All external connections are outbound-only downloads. No workflow data, run results, logs, or user information is transmitted to any of these services. ## Scaling and multi-executor deployments In the default configuration, Runner runs one executor on the same host as the API and MongoDB. To handle more concurrent runs, scale up the number of executor containers on the same host: ```sh docker compose scale executor=2 ``` Each executor instance registers independently with the API and can pick up runs in parallel. However, the Docker image build stage — pull, build, and push — is serialized across all executors on the same host using a host-wide lock. Only one executor builds at a time; others wait. This means multiple executors on one host increase run throughput but not build throughput. The recommended approach for higher capacity is **one executor per host**. This gives each executor the full resources of its host, eliminates build lock contention, and provides independent failure domains — if one host goes down, the remaining executors continue processing runs. When running executors on multiple hosts, a [private Docker registry](./configuration.md#private-registry) lets them share built images instead of each rebuilding from scratch on every host. --- --- url: /runner/changelog.md description: Link to the full NodePit Runner release notes on nodepit.com. --- # Release Notes The full release notes for NodePit Runner are published on nodepit.com and list all releases with their notable changes. [View Release Notes →](https://nodepit.com/product/runner/changelog) ## Staying informed **In-app banner** — when a newer version of Runner is available, a banner appears on the [Settings](./settings.md) page with a link to the changelog and upgrade instructions. **RSS feed** — subscribe to [`https://nodepit.com/product/feed.xml`](https://nodepit.com/product/feed.xml) in your feed reader to receive release notifications for all NodePit products, including Runner. ## Upgrading Pull the latest images and restart the stack: ```sh docker compose pull docker compose up -d ``` Database migrations run automatically on startup. No manual steps are required. See [Installation](./installation.md) for the full upgrade procedure. --- --- url: /runner/runner-for-knime.md description: >- The KNIME extension that connects KNIME Analytics Platform to a Runner installation. --- # NodePit Runner for KNIME [NodePit Runner for KNIME](https://nodepit.com/product/runner-knime) is a KNIME extension that connects KNIME Analytics Platform to your Runner installation. It gives you two distinct capabilities: a set of nodes for interacting with the Runner API from within your workflows, and an Explorer integration for browsing and managing Runner content directly from the KNIME workspace panel. ## Installation 1. In KNIME, go to **Preferences → Install/Update → Available Software Sites** and add the update site for your KNIME version: ``` https://download.nodepit.com/5.12 ``` Replace `5.12` with your KNIME version number. 2. Go to **File → Install KNIME Extensions …**, find **NodePit Runner for KNIME**, and follow the installation steps. Alternatively, install directly from [nodepit.com](https://nodepit.com/product/runner-knime). ## Nodes The extension provides nodes covering all major Runner resources — Projects, Environments, Files, Schedules, Runs, Members, Executors, Users, and Access Tokens. Use them to build KNIME workflows that query run history, trigger schedules on demand, upload files, or manage Runner configuration without switching to the Runner UI. Every workflow starts with a **Server** node that configures the URL of your Runner instance. Connect its output to one of the authentication nodes — **Access Token** (recommended for automation; see [Access Tokens](./access-tokens.md)), **Login** (email and password, returns a JWT), or **JWT** (accepts an existing token directly). The authentication node's output port connects to all downstream operation nodes. ## Explorer The extension also integrates with the KNIME Explorer panel. After installing, open **KNIME Preferences → KNIME Explorer** and add a new mount point pointing to your Runner instance URL. Runner projects and their files then appear in the Explorer panel alongside your local workspace and other mount points. You can browse, upload, and download workflows and files directly from KNIME without opening the Runner UI. --- --- url: /about.md description: Who builds NodePit and what this documentation site covers. --- # About ## NodePit NodePit is built by two developers from Dresden, Germany, creating tools for the KNIME ecosystem since 2011 — using it, extending it, and in it for the long run. NodePit launched in 2017 as a search engine for KNIME nodes and has since grown into a full platform covering the KNIME ecosystem, with workflow automation tooling and a portfolio of extensions downloaded tens of thousands of times worldwide. [Learn more about NodePit and the team →](https://nodepit.com/about) ## This Documentation This documentation was written with the assistance of [Claude](https://claude.ai), an AI assistant by Anthropic. All content was directed, reviewed, and verified by the NodePit team against the actual product source code and behaviour. If you find an error or something that is unclear, please reach out at <mail@nodepit.com>.