Dumplings monitors Windows package releases and submits updated manifests to microsoft/winget-pkgs. Its PowerShell runner manages thousands of package tasks, with static installer analysis, manifest validation, and notifications.
- Runs selected or all package tasks with explicit dependency ordering and configurable concurrency.
- Compares releases with persisted task state and distinguishes new, changed, updated, and rollback states.
- Detects and statically analyzes many Windows installer and bootstrapper formats.
- Reads, updates, formats, and validates multi-file WinGet manifests without invoking
winget validate. - Writes task state, sends queued Telegram or Matrix notifications, and submits guarded pull requests.
- Publishes a task status dashboard to GitHub Pages after each Automation workflow run.
- Keeps GPL installer implementations behind a JSON child-process boundary from the Apache-2.0 PackageModule.
flowchart LR
Core["Core runner"] --> Tasks["Tasks/*"]
Core --> Package["PackageModule (Apache-2.0)"]
Tasks --> Package
Package -->|"JSON child process"| Parsers["InstallerParsers (GPL-2.0/GPL-3.0)"]
Package --> Output["State, manifests, and messages"]
Package --> Winget["winget-pkgs pull requests"]
| Path | Responsibility |
|---|---|
Core |
Task discovery, dependency planning, worker coordination, hooks, timeouts, and synchronization. |
Modules/PackageModule |
Package task model, release helpers, installer analysis, WinGet manifest processing, messaging, and submission. |
Modules/InstallerParsers |
Process-isolated static parsers for formats whose implementations use GPL-compatible licenses. |
Tasks |
One directory per automation task, containing Config.yaml, Script.ps1, and persisted state. |
.agents/skills |
Workflow documentation for installer analysis and WinGet manifest authoring. |
Utilities |
Repository maintenance and GitHub Actions support scripts. |
Core, PackageModule, and InstallerParsers are Git submodules and are also usable as independently versioned projects.
PackageModule's supported standalone entry point is Modules/PackageModule/PackageModule.psd1. Core uses Modules/PackageModule/Index.ps1 to import that manifest and load task model classes.
- Windows
- PowerShell 7.4 or later
- Git with submodule support
- Network access for release checks and installer downloads
- GitHub credentials, and optionally a local
winget-pkgscheckout, only when submission is enabled
The runner installs missing PowerShell modules declared in Preference.yaml. GitHub Actions caches the pinned versions in PowerShellModules.psd1. The optional browser helper restores the Apache-2.0 Patchright runtime pinned by PlaywrightRuntime.psd1. Its large, version-specific driver payload is cached outside Git.
Clone the repository and all submodules:
git clone --recurse-submodules https://github.com/SpecterShell/Dumplings.git
Set-Location .\DumplingsIf the repository was cloned without submodules:
git submodule update --init --recursiveRun one task without enabling state writes, messages, or submissions:
.\Core\Index.ps1 -Name Adobe.WorkfrontProofRun several tasks with four workers:
.\Core\Index.ps1 -Name Adobe.WorkfrontProof, Mozilla.Firefox -ThrottleLimit 4Run every task:
.\Core\Index.ps1Arguments not owned by Core\Index.ps1 override values from Preference.yaml.
# Re-evaluate a task regardless of its persisted state.
.\Core\Index.ps1 -Name Vendor.Package -Force
# Persist State.yaml and a timestamped log after a detected change.
.\Core\Index.ps1 -Name Vendor.Package -EnableWrite
# Exercise manifest generation and submission logic without opening a PR.
.\Core\Index.ps1 -Name Vendor.Package -Force -EnableSubmit -Dry
# Preserve existing installer metadata while still downloading, hashing, validating, and submitting manifests.
.\Core\Index.ps1 -Name Vendor.Package -Force -EnableSubmit -Dry -SkipInstallerAnalysis-EnableMessage and non-dry -EnableSubmit perform external side effects. Enable them only after configuring their credentials and reviewing the selected tasks.
-SkipInstallerAnalysis is a global preference override. A task can opt out with SkipInstallerAnalysis: true in its Config.yaml. Both settings skip static analysis while retaining installer hashing and manifest validation.
Preference.yaml contains non-secret runner and module defaults. Command-line overrides have higher priority.
Secrets are loaded in this order:
- YAML from the
DUMPLINGS_SECRETenvironment variable. - Values from the ignored local
Secret.yamlfile, which override matching environment values.
The runner also reads an ignored .env file without replacing environment variables that already exist. Never commit .env, Secret.yaml, tokens, cookies, or installer credentials.
Common environment variables include:
| Variable | Purpose |
|---|---|
GH_DUMPLINGS_TOKEN, GITHUB_TOKEN |
GitHub API, repository, and submission authentication. |
TG_BOT_TOKEN, TG_CHAT_ID |
Optional Telegram notifications. |
MT_BOT_TOKEN, MT_ROOM_ID |
Optional Matrix notifications. |
DUMPLINGS_SECRET |
Additional task-specific secrets encoded as YAML. |
A task directory is selected only when it contains Config.yaml. A typical package task starts with:
Type: PackageTask
WinGetIdentifier: Vendor.Package
Skip: falseScript.ps1 populates $this.CurrentState, calls $this.Check(), and conditionally uses $this.Print(), $this.Write(), $this.Message(), and $this.Submit(). State.yaml points to the most recent timestamped state log and is read on the next run.
Dependencies must be explicit:
DependsOn:
- '#Vendor'Tasks whose names begin with # commonly populate $Global:DumplingsStorage for dependent package tasks. Core validates declared dependencies, orders them deterministically, and blocks dependents whose providers fail.
Use tasks from the same publisher as references and verify their current behavior.
analyze-winget-installercovers static installer detection, parser routing, Apps & Features evidence, and isolated VM validation.author-winget-manifestcovers official source discovery, manifest fields, localization, automation, validation, and submission.author-dumplings-taskcovers task creation, state comparison, source/feed patterns, manifest-update projection, shared providers, and dry-run validation.use-dumplings-functionscovers shared networking, temporary-file, archive, content, feed, browser, HTML, and YAML helper APIs.
Run the component suites from the repository root:
Invoke-Pester .\Core\Tests
Invoke-Pester .\Modules\PackageModule\Tests
Invoke-Pester .\Modules\InstallerParsers\TestsRun ScriptAnalyzer on a changed module when available:
Invoke-ScriptAnalyzer .\Modules\PackageModule\Libraries\Example.psm1Downloaded fixtures are cached under ../Dumplings-TestFixtures/Installers/<Family>/<PackageIdentifier>/<Version>. Curated builder media and source trees live under Builders and Sources. Keep synthetic fixtures and extraction output in Pester's $TestDrive. Tests must not execute installers.
The offline regression workflow tests Core, PackageModule, and InstallerParsers in separate jobs with pinned module caches. It does not run package tasks, submit manifests, send messages, or download installer fixtures. Run it locally with ./Utilities/Testing/Invoke-Regression.ps1 -Component PackageModule -Offline, selecting other components by name as needed.
Use Core's -MeasurePerformance switch for sanitized per-run stage measurements. The isolated benchmark and AST task-inventory tools are documented in Utilities/Testing, including measured startup costs and the ready scheduler's dependency-heavy results. These switches do not enable state writes or submission.
The root project remains licensed under the MIT License. Core and PackageModule use the Apache License 2.0 and Apache License 2.0, respectively. PackageModule contains documented file-level MIT and third-party exceptions. InstallerParsers has file-specific GPL licensing described in its README.