Table of Contents

zkbuild (zkbuild-action)

One of Zeugwerk’s CI/CD tools for TwinCAT. Manual PLC builds in the IDE don’t scale and aren’t reproducible. zkbuild lets you compile your PLCs and run unit tests in the cloud -no Jenkins or build servers. zkbuild-action is available for all major Git hosts (GitHub, GitLab, Bitbucket) and calls our CI/CD backend. Push code; get reproducible .library artifacts and test results.

Free tier for public repos (30 builds/month). For private repos or higher volume, contact us.

On-premises / self-hosted builds - If you need to build on your own infrastructure (private network, air-gapped, custom CI), use zkmake instead. It provides the same build and test capabilities using a local TwinCAT XAE installation.


Why use it

  • Reproducible builds - Same output every time, independent of your machine.
  • Automated testing - Run TcUnit or Framework unit tests in CI; the build fails if tests fail.
  • No manual builds - Avoid “forgot to rebuild” and “works on my machine” issues.
  • Audit trail - Every build is logged and traceable (useful for compliance).
  • Zero DevOps - No Jenkins or build servers to maintain.

Quick start

  1. Register - Register here. Public repos get 30 free builds/month.
  2. Add a workflow - The example below is for GitHub; zkbuild-action also works with GitLab CI and Bitbucket Pipelines. Create .github/workflows/build.yml in your repo (or the equivalent in your Git host):
name: Build/Test
on:
  push:
    branches: [main, 'release/**']
  pull_request_target:
  workflow_dispatch:
jobs:
  Build:
    name: Build/Test
    runs-on: ubuntu-latest
    steps:
      - name: Build
        uses: Zeugwerk/zkbuild-action@1.0.0
        with:
          username: ${{ secrets.ACTIONS_ZGWK_USERNAME }}
          password: ${{ secrets.ACTIONS_ZGWK_PASSWORD }}
      - name: Upload Artifact
        uses: actions/upload-artifact@v4
        with:
          name: artifact
          path: "**/*.library"
      - name: Publish Unittest
        uses: EnricoMi/publish-unit-test-result-action@v1
        with:
          files: archive/test/TcUnit_xUnit_results.xml
  1. Store credentials - Add ACTIONS_ZGWK_USERNAME and ACTIONS_ZGWK_PASSWORD as GitHub Secrets. Do not commit them.
  2. Configure the build - Add a .Zeugwerk/config.json in your repo (see Configuration). You can generate it with Twinpack.

How it works

Your push triggers the action → the action calls Zeugwerk CI/CD → our server builds the solution, runs unit tests, and returns artifacts (e.g. .library files, test results). The action uploads them to the workflow run. No Jenkins or self-hosted runner required.

Configuration

Inputs

Input Required Default Description
username Yes Zeugwerk account username. Store as a GitHub Actions secret and reference via secrets.ZEUGWERK_USERNAME.
password Yes Zeugwerk account password. Store as a GitHub Actions secret and reference via secrets.ZEUGWERK_PASSWORD.
tcversion No (auto) TwinCAT version for compiling and testing (e.g. TC3.1.4024.22). Must be available on the Zeugwerk CI/CD server. If omitted, an available version is selected automatically.
platform No TwinCAT RT (x64) Target platform for the build. Must match a platform supported by the Zeugwerk CI/CD server.
variant-build No (default) Name of the PLC project variant to build. Useful when the project defines multiple variants for different hardware configurations.
variant-test No (default) Name of the PLC project variant to use when running unit tests. Typically a variant without hardware dependencies so tests can run in simulation.
static-analysis No false Enable TwinCAT static analysis during the build. true runs light analysis for open-source users and full analysis for Zeugwerk customers (full analysis requires a Beckhoff license). Uses the static analysis settings from the .plcproj files.
installer No false When true, generates an installer package that allows the PLC to be deployed to a target system from a Windows PC. See PLC deployment installer.
installer-name No Setup-<REPO> <VERSION>.exe Override the installer file name.
workspace No ./ Path to the directory containing the .Zeugwerk folder. Use this when your project is not at the repository root (e.g. src/MyPlc/).
version No (from latest tag) Override the version number used when naming build artifacts. Accepts 1.2.3.4 or 1.2.3-alpha style strings.
skip-build No false Skip compiling the project and producing build artifacts. Useful when you only want to run unit tests.
skip-test No false Skip compiling and executing unit tests. Useful for faster feedback on draft PRs.
force-checks No false Force a "Check All Objects" pass even for application PLCs. By default this is skipped for applications since "Build Solution" is sufficient.
artifact-name No artifact.zip File name for the downloaded build artifact archive. Override to avoid collisions when multiple build jobs run in the same workflow.

Outputs

Artifact Location
.library file(s) archive/<repo>/<tcversion>/<plc>_<version>.library
Test results (JUnit) archive/test/TcUnit_xUnit_results.xml (embedded / tests/) · archive/tests/<TestProjectFolder>/TcUnit_xUnit_results.xml (in-solution)
Installer (.exe) archive/<installer-name> (when installer: true)
Build logs GitHub Actions run summary

Config file

zkbuild-action reads .Zeugwerk/config.json from the repository root (or from the directory set by workspace). Use Twinpack to generate and maintain it. For the full schema including packages, references, modules, and patches: config.json reference.

Unit tests

zkbuild-action discovers and runs unit tests automatically. Three layouts are supported: embedded test FBs (ZCore.IUnittest / Testbench.IUnittest, Option A), a standalone project under tests/ (Option B), or an in-solution UnitTestApplication in the main config.json (Option C, native TcUnit). Results are written as JUnit XML under archive/test/ or archive/tests/<TestProjectFolder>/ depending on the layout.

For setup, folder layout, in-solution configuration, and CI reporting examples: Unit tests.

Input examples

Pin a TwinCAT version

- uses: Zeugwerk/zkbuild-action@1.0.0
  with:
    username: ${{ secrets.ZEUGWERK_USERNAME }}
    password: ${{ secrets.ZEUGWERK_PASSWORD }}
    tcversion: TC3.1.4024.56

Build and test different variants

Use variant-build for the release build and variant-test for a simulation variant that runs without real hardware:

- uses: Zeugwerk/zkbuild-action@1.0.0
  with:
    username: ${{ secrets.ZEUGWERK_USERNAME }}
    password: ${{ secrets.ZEUGWERK_PASSWORD }}
    variant-build: Release
    variant-test: Simulation

Enable static analysis

- uses: Zeugwerk/zkbuild-action@1.0.0
  with:
    username: ${{ secrets.ZEUGWERK_USERNAME }}
    password: ${{ secrets.ZEUGWERK_PASSWORD }}
    static-analysis: true

Generate an installer package

- uses: Zeugwerk/zkbuild-action@1.0.0
  with:
    username: ${{ secrets.ZEUGWERK_USERNAME }}
    password: ${{ secrets.ZEUGWERK_PASSWORD }}
    installer: true
    installer-name: Setup-MyPLC ${{ github.ref_name }}.exe

Project not at repository root

Use workspace when .Zeugwerk/config.json is in a subdirectory:

- uses: Zeugwerk/zkbuild-action@1.0.0
  with:
    username: ${{ secrets.ZEUGWERK_USERNAME }}
    password: ${{ secrets.ZEUGWERK_PASSWORD }}
    workspace: src/MyPlc/

Run tests only (skip build artifacts)

Useful on pull requests where you want fast feedback without producing .library files:

- uses: Zeugwerk/zkbuild-action@1.0.0
  with:
    username: ${{ secrets.ZEUGWERK_USERNAME }}
    password: ${{ secrets.ZEUGWERK_PASSWORD }}
    skip-build: true

PLC deployment installer

When installer: true, zkbuild-action produces a Windows .exe (by default Setup-<REPO> <VERSION>.exe in archive/). Download it from your build artifacts and run it on a Windows engineering or service PC to deploy the compiled PLC boot project to a TwinCAT target.

The installer packages the boot project from your CI build. On the target PC it asks for deployment settings, then deploys to the PLC identified by its AMS NetID. Deployment can take several minutes.

Prerequisites

  • Windows PC with network access to the TwinCAT target
  • AMS NetID of the target PLC (for example 127.0.0.1.1.1 for a local runtime)
  • Administrator rights recommended when running silently in automated scripts

Interactive installation

  1. Download the .exe from your CI build artifacts.
  2. Run the installer and follow the wizard.
  3. On TwinCAT Deployment Options, enter the AMS NetID of the target PLC. The default for a local runtime is 127.0.0.1.1.1.
  4. On TwinCAT Restart Option, choose whether TwinCAT should be restarted after deployment.
    • Restarting may cause mechanical crashes or damage if the machine is still running. Only enable this when the system is in a safe state.
  5. Complete the wizard. The installer runs until deployment has finished.

Silent installation

For unattended deployment (scripts, MDM, remote maintenance), run the installer directly from an elevated command prompt. The process blocks until setup exits.

"Setup-MyPLC 1.0.0.0.exe" /SILENT /NETID=127.0.0.1.1.1
"Setup-MyPLC 1.0.0.0.exe" /VERYSILENT /NETID=192.168.0.1.1.1 /RESTART=1

Parameters

Parameter Required in silent mode Description
/SILENT Runs without the wizard. No user interaction is required when /NETID is supplied.
/VERYSILENT Same as /SILENT, but also suppresses the standard setup progress window.
/NETID=<ams net id> Yes AMS NetID of the target PLC (same value as in the wizard). Example: /NETID=127.0.0.1.1.1
/RESTART No Restart the TwinCAT runtime after deployment. Equivalent to checking the restart option in the wizard.
/RESTART=1, /RESTART=true, /RESTART=yes No Same as /RESTART.
Warning

In silent mode there is no confirmation dialog for /RESTART. Use it only when the machine is in a safe state.


Pricing

  • Free - 30 builds/month for public repositories.
  • Commercial - Custom pricing for private repos and higher volume. contact us.

Examples

struckig, DeviceInfo, Demo-Twincat-Application-CI, rplc. See the Actions tab in any of these repos for build results.

Troubleshooting

Symptom Likely cause Fix
Credentials not found Secrets not configured Ensure ZEUGWERK_USERNAME and ZEUGWERK_PASSWORD are set in GitHub Secrets.
TwinCAT version mismatch Requested version not available on CI server Set tcversion explicitly, e.g. tcversion: TC3.1.4024.56.
Tests not running Test FBs / config not detected Use embedded FBs, a tests/ project, or UnitTestApplication in config.json. See Unit tests.
Build skipped unexpectedly skip-build: true set Check your workflow inputs; remove skip-build if you need artifacts.
Variant build failing Variant name mismatch Verify the variant name in variant-build exactly matches what is defined in the TwinCAT project.
Installer not produced installer not set Add installer: true to the action inputs.
Wrong artifact picked up Multiple builds in same run Set a unique artifact-name per job to avoid collisions.
Project not found Monorepo with non-root project Set workspace to the subdirectory containing .Zeugwerk/config.json.

Advanced: config with dependencies

For declaring packages and references in .Zeugwerk/config.json, see the config.json reference.

Advanced: patches

zkbuild-action supports platform patches (applied automatically per TwinCAT version) and argument patches (applied when you pass the patch input). For the full patch configuration format, see the config.json reference - Patches.

Note

Argument patches are not available on the free zkbuild tier. Open an issue if you need them for an open source project.


Comparison: zkbuild-action vs. zkmake

zkbuild-action (cloud) zkmake (on-premises)
Infrastructure Zeugwerk CI/CD (no setup) Your Windows build server
TwinCAT XAE required No Yes (on the build machine)
Pipeline support GitHub, GitLab, Bitbucket Any CI that runs Windows .exe
Private repos Commercial plan License required
Free tier 30 builds/month (public repos) -
Config format .Zeugwerk/config.json .Zeugwerk/config.json