The activity manifest
What velophex/activity-manifest.json contains, where each field comes from, the icon limits, and why a package must never change after it is packed.
velophex/activity-manifest.json describes everything in your package: its identity, the engine versions it supports, its activities and their arguments, its icons, and a hash of every file. Studio, the workflow executor and the Robot read it to learn what the package holds; none of them scans your code to find activities. The build generates the manifest every time you run dotnet pack, from your compiled assembly and the staged package files. Never write or edit it by hand, and never check it in. The design document, velophex/activity-design.json, is generated beside it from the same attributes. Package members# Member Comes from Used for format, manifestVersion The build: velophex.activity-manifest, version 2 Reader compatibility packageId, packageVersion The package project's PackageId and version Must equal the package's own NuGet identity description, publisher Description and Authors Studio's Package Manager engineVersionRange VelophexEngineVersionRange in VeloPhex.Versions.props An engine outside the range refuses the package. See Engine compatibility. capabilities The union of every activity's [ActivityCapabilities] The consent prompt in Studio, and the runtime capability gate runtimeAssemblies Every .dll under lib/ What the executor loads activities[] One entry per class with [ActivityType] The toolbox, the designer and the workflow compiler packageIcon, icons icons/package.svg and the map from icon key to icons/<key>.svg Package Manager, toolbox and cards localizations resources/<culture>.json files Translations files[] Path, size and SHA-512 of every file in the package Integrity: see Every file is hashed Activity members# Each entry of activities[] carries: Member Comes from typeId [ActivityType] implementationType, assembly The class and its assembly displayName, category, description, icon, keywords, helpUri, version [ActivityInfo]. category is Category › Subcategory, or Activities when unset. version defaults to the assembly version. recoveryBehavior [ActivityRecovery]: ReplaySafe, ProbeThenReplay or NonReplayable (the default) isolation Required when [ActivityCharacteristics(RequiresIsolation = true)], otherwise Auto idempotent, retrySafe, risk [ActivityCharacteristics]. risk is left out when you do not declare it, and readers treat that as unknown. deterministic, privileged, sessionAffinity, persistable [ActivityCharacteristics]; written only when they differ from the default capabilities The activity's own [ActivityCapabilities] scope [ScopeProvider] (scope.provides) and [RequiresScope] (scope.requires) arguments[] One per argument: name, type, direction, required, and the [ArgumentInfo] members (displayName, description, editorHint, defaultValue, sensitive, order, group, isAdvanced, visibleWhen, choices, placeholder) An excerpt of a generated manifest: velophex/activity-manifest.json (excerpt)JSONCopy{ "format": "velophex.activity-manifest", "manifestVersion": 2, "packageId": "Contoso.Invoices.Activities", "packageVersion": "1.0.0-preview.1", "publisher": "Contoso", "engineVersionRange": "[0.7.0-rc.43, 1.0.0)", "capabilities": ["Network", "Credentials"], "runtimeAssemblies": ["lib/net10.0/Contoso.Invoices.Activities.dll"], "activities": [ { "typeId": "contoso.invoices.getInvoiceStatus", "implementationType": "Contoso.Invoices.Activities.GetInvoiceStatusActivity", "assembly": "Contoso.Invoices.Activities", "displayName": "Get Invoice Status", "category": "Invoices", "icon": "InvoiceStatus", "recoveryBehavior": "NonReplayable", "isolation": "Auto", "idempotent": true, "retrySafe": true, "risk": "None", "capabilities": ["Network", "Credentials"], "arguments": [ { "name": "ApiKey", "type": "System.Security.SecureString", "direction": "In", "required": true, "displayName": "API key", "editorHint": "password", "sensitive": true, "order": 2, "isAdvanced": false } ] } ], "packageIcon": "icons/package.svg", "icons": { "InvoiceStatus": "icons/InvoiceStatus.svg" }, "files": [ { "path": "lib/net10.0/Contoso.Invoices.Activities.dll", "size": 28160, "sha512": "…" } ] } Every file is hashed# files[] lists every file in the package with its size and SHA-512. Studio and the Robot verify it before they use the package: A file whose size or hash does not match is refused (VXPKG023). A file that the manifest does not list is refused (VXPKG024). A listed file that is missing is refused (VXPKG022). So never add, remove or change a file after dotnet pack: re-run the pack instead. The only thing that may be added afterwards is a detached signature, velophex/signature.json, which the manifest does not list. The licence file must be packed and listed too; the build does this for you when PackageLicenseFile and VeloPhexLicenseSource are set (VXMAN011). Icon limits# The manifest's icons and packageIcon must point at files in the package, and the engine enforces: Rule Code Icons are .svg only VXPKG044 (VXMAN004 at pack time) At most 16 KiB per icon VXPKG045 (VXMAN005 at pack time) At most 256 KiB for all icons together VXPKG046 (VXMAN006 at pack time) Studio applies its own stricter rules to the SVG content. See Icons. Why the engine range matters# The engine's manifest reader refuses members it does not know. A manifest written for a newer engine can therefore not be read by an older one: the package installs and then shows nothing. That is why every package declares the oldest engine it works with in engineVersionRange, and why that floor is the engine version of the SDK you built against. See Engine compatibility. Look inside a package# A .nupkg is a ZIP file. To read the manifest of a package you built: PowerShellCopyAdd-Type -AssemblyName System.IO.Compression.FileSystem $zip = [System.IO.Compression.ZipFile]::OpenRead("$PWD\out\Contoso.Invoices.Activities.1.0.0-preview.1.nupkg") $entry = $zip.GetEntry('velophex/activity-manifest.json') $reader = New-Object System.IO.StreamReader($entry.Open()) $reader.ReadToEnd() | ConvertFrom-Json | Select-Object packageId, packageVersion, engineVersionRange, capabilities $reader.Dispose(); $zip.Dispose() To check it automatically on every build, see Package tests. Next steps# Test activities Package, version and sign
Package members
Activity members
Every file is hashed
Icon limits
Why the engine range matters
Look inside a package
Next steps