Plugin SDK Release Notes

This page tracks releases of the formae Plugin SDK packages:

  • pkg/plugin - Core SDK for building plugins
  • pkg/plugin-conformance-tests - Conformance test framework
  • formae-plugin-template - Scaffold for new plugins

June 2026

plugin v0.3.0

Released June 2026. Requires formae ≥0.86.0

Breaking behaviour. ExtractSchema now emits every property path, including unannotated ones, with createOnly defaulting to false. The planner uses this complete schema surface to decide between cascade-replace and cascade-update when a parent resource is being replaced. Any field whose value the provider rejects on update must now be annotated @formae.FieldHint { createOnly = true }. Previously the planner could not distinguish "unannotated" from "mutable" and cascade-replaced dependents wholesale; now an unannotated dependent field is treated as mutable and the resolvable re-resolves at apply time, so the dependent absorbs the new parent value through a provider-native Update. Plugins that under-mark immutable fields will see apply-time provider rejections that previously masqueraded as cascade-replaces.

The canonical case this unlocks is an ECS Service consuming a TaskDefinition via the mutable taskDefinition field: previously every revision bump tore down and recreated the Service (2–4 minutes of outage); with taskDefinition correctly unmarked (i.e. mutable), the Service does a rolling deploy.

Migration: audit your schema for fields whose value the provider rejects on update (typical: a resource's name/identifier, region, KMS key ID at create time, networking primitives). Add @formae.FieldHint { createOnly = true } to each. Run your conformance suite; the update phase now exercises the planner's mutability decision end-to-end.

Resolvables follow the same rule. Cross-resource references (fields whose values are Resolvable URIs pointing at other resources) were previously treated as implicitly createOnly. They now follow the same rule as scalar fields: a Resolvable-typed field is treated as immutable only when annotated @formae.FieldHint { createOnly = true }. Plugins where a resolvable-bearing field's value can be safely updated in place by the provider should leave it unannotated; plugins where changing the reference requires a replace should mark it explicitly. The same audit applies: review every Resolvable-typed field and add the annotation where the provider rejects in-place updates.

Feature: Typed EdgeKind on FieldHint replaces the AttachesTo boolean

FieldHint now carries an edgeKind union with three values: default, attachesTo, and the new runtimeDependency. The legacy attachesTo = true boolean is still accepted and derived to edgeKind = "attachesTo" for one release, so existing plugins compiled against v0.2.2 continue to load unchanged. New plugins should write edgeKind directly:

@formae.FieldHint { edgeKind = "runtimeDependency" }
fileSystemId: (String|formae.Resolvable)?

Feature: runtimeDependency edge kind for instance-scoped destroy ordering

runtimeDependency annotates a field whose value points at a specific resource instance that must outlive its containment children during destroy. The planner inserts edges from the annotated consumer to each containment child that points at the same producer instance, so the children are destroyed before their parent.

The motivating case is AWS::EFS::FileSystem + AWS::EFS::MountTarget: an ECS TaskDefinition references a FileSystem via a mutable field, and the FileSystem has MountTargets as containment children. Without this annotation, the engine could delete the FileSystem while MountTargets still held it open, stranding both. Annotating the TaskDefinition's fileSystemId field with edgeKind = "runtimeDependency" pulls those MountTargets into the destroy ordering ahead of their parent FileSystem.

attachesTo (the same semantics as the previous boolean) still flips the destroy edge between two specific resources where the attacher must outlive the host. runtimeDependency is the multi-instance, containment-aware variant.

Feature: ParentRef and Schema.ParentMappings describe parent-instance identity

A new ParentRef PKL class and ResourceHint.parentRefs field let resource types declare which fields identify their parent instance. Schema.Parent and Schema.ParentMappings are now plumbed from PKL through the descriptor extractor and are available to the planner for instance-discriminated child-points-at lookups during destroy. This is what makes runtimeDependency instance-safe rather than type-wide.

Fix: formae plugin init scaffolder: namespace, substitution, and verify-schema glob

Three rough edges surfaced by the atlas plugin scaffold are fixed:

  • Mixed-case namespace input is now normalised to upper-case at input time, with a one-line stderr notice when the input differs from the normalised form. Previously the conversion happened silently at template-generation time and left config.Namespace mixed-case internally.
  • Five additional template-substitution rules cover placeholders that were leaking through scaffolded output: bare module example declarations, PklProject baseUri and packageZipUrl strings, PKL module-qualifier prefixes (example.ExampleResource), the license header year and author (previously hard-coded to 2025), and the new @example/core/example.pkl subdir import path that pairs with the template repo's subdir convention.
  • The testutil ImportsGenerator.pkl glob is changed from import*(@<ns>/**/*.pkl) to the union pattern already used in the sibling generators under internal/schema/pkl/generator and pkg/plugin/descriptors. The single-glob form misses top-level files in PKL's glob model, so make verify-schema was reporting "Total resource types: 0, PASSED" for plugins that placed resources at schema/pkl/<resource>.pkl: a false-success signal that hid real schema problems. The new pattern matches both top-level and nested files.

Docs: Package READMEs

pkg/plugin/README.md and pkg/plugin-conformance-tests/README.md are added so plugin authors who land in those directories directly (via go doc, GitHub's package tree, or as a follow-up to formae plugin init) get a self-contained orientation. The plugin README covers the ResourcePlugin interface, the optional ObservablePlugin and Configurable interfaces, the async ProgressResult flow, the on-disk layout (formae-plugin.pkl manifest plus schema/pkl/PklProject), the sdk.RunWithManifest entry point, and the conventions plugin authors commonly miss (statelessness across operations, mandatory NativeID in every ProgressResult, JSON-typed properties, no pointer sharing across the actor boundary).

Migration from v0.2.2: Bump the dependency and rebuild:

github.com/platform-engineering-labs/formae/pkg/plugin v0.3.0
github.com/platform-engineering-labs/formae/pkg/plugin-conformance-tests v0.2.5
github.com/platform-engineering-labs/formae/pkg/model v0.1.25

Then go mod tidy and make build. Bump minFormaeVersion in formae-plugin.pkl to 0.86.0 if you plan to ship any edgeKind or parentRefs annotations.


conformance-tests v0.2.5

Released June 2026. Requires plugin ≥0.3.0

Feature: Channel-aware formae resolver with dev fallback

The harness now reads minFormaeVersion from your plugin's formae-plugin.pkl manifest and uses it as the floor when picking a formae release to install via orbital. It prefers the highest stable release that meets the floor; otherwise it falls back to the highest qualifying release on the dev channel; otherwise it errors with a message naming the required minimum.

This lets a plugin opt into a not-yet-stable formae release by declaring a higher minimum in its manifest. For example, a plugin adopting the new edgeKind schema needs formae ≥0.86.0; while 0.86.0 is in its dev-channel window, the harness picks the latest qualifying dev build automatically. Plugins whose declared minimum is satisfied by the latest stable release see no behaviour change.

Each channel uses its own orbital tree under the conformance tempdir, and the dev tree is only initialised when stable cannot satisfy the floor. An explicit FORMAE_VERSION (used by nightly and debug-conformance) is still honoured exactly, now searched across stable then dev.

Fix: Empty-value drift no longer flagged in the reverse comparison direction

The forward direction of compareMap and compareProperties skips when the expected value is structurally absent (nil, empty array, or empty map). The reverse direction had no equivalent forgiveness: any actual key absent from expected was flagged as drift unless the schema marked the field as hasProviderDefault. Cloud providers commonly return [] for unset list fields and {} for unset map fields, which is semantically equivalent to the key being omitted, but the harness was flagging it.

This forced plugin authors into a bad trade-off for user-canonical fields. Marking hasProviderDefault on the schema satisfied the harness, but formae core's strip-provider-default pass then dropped the field symmetrically from apply diffs, silently losing user changes. Setting explicit empty literals in testdata lost test-coverage clarity and bloated fixtures.

The reverse loops now mirror the forward loops' empty-skip. Non-empty unexpected values are still flagged, which is the case that matters for both out-of-band changes and missed hasProviderDefault annotations. This unblocks AWS::ECS::TaskDefinition (18 ContainerDefinitions[0].* fields plus Tags), AWS::ECS::TaskSet.Tags, and AWS::SES::EmailIdentity.Tags, among others.

Fix: FORMAE_VERSION is now populated when FORMAE_BINARY is set externally

EnsureFormaeBinary returned early when FORMAE_BINARY was already set in the environment, without extracting the version or populating FORMAE_VERSION. Downstream, ResolvePKLDependencies saw an empty FORMAE_VERSION, logged "skipping PKL dependency resolution", and the test's subsequent pkl eval failed with NoSuchFileException on testdata/PklProject.deps.json. That file is gitignored and only materialises once pkl project resolve has run, so every nightly that built formae from source regressed in lockstep once the per-plugin run-conformance-tests.sh wrapper was retired in favour of letting the SDK manage setup. The externally-set branch now mirrors the orbital path: extract the version, log it, and t.Setenv FORMAE_VERSION before returning.

Migration from v0.2.4: Bump the dependency:

github.com/platform-engineering-labs/formae/pkg/plugin-conformance-tests v0.2.5

Then go mod tidy. No code changes required. If you want to opt your plugin into a dev-channel formae release, raise minFormaeVersion in formae-plugin.pkl.


Full go.mod bump for this cycle

github.com/platform-engineering-labs/formae/pkg/plugin v0.3.0
github.com/platform-engineering-labs/formae/pkg/plugin-conformance-tests v0.2.5
github.com/platform-engineering-labs/formae/pkg/model v0.1.25

Run go mod tidy and make build after updating. Bump minFormaeVersion in formae-plugin.pkl to 0.86.0 if your plugin adopts the new edgeKind or parentRefs annotations; otherwise the existing 0.84.0 floor still works.


May 2026

plugin v0.2.2

Released May 13, 2026. Requires formae ≥0.84.0

Feature: AttachesTo field hint for reachability-based destroy ordering

Plugin authors can now annotate a field that $refs another resource with attachesTo = true to declare that the resource being defined attaches as a backend to the resource it references, and must outlive it during destroy. The destroy DAG inverts the edge: the referenced resource (the host) is deleted first, and the attaching resource waits.

When to use it. Annotate a field with attachesTo when the resource being defined provides a live capability — a serving endpoint, a consumer connection — that depends on the continued existence of the resource it references, and when other resources in the stack consume that live capability during their own tear-down. The canonical example is AWS::ECS::Service.LoadBalancers.targetGroupArn: the ECS service is the live backend for the listener URL. A Grafana target pointing at that listener URL drives CRUD calls through it during destroy; if the service tears down in parallel with the listener, those calls fail and the agent wedges mid-destroy. With attachesTo, the service waits for the listener to be deleted first, keeping the HTTP endpoint reachable throughout the Grafana resources' tear-down.

DAG semantics. This is a destroy-only annotation. Create order is unchanged: the normal construction constraint still applies (the attacher is created after its host). On destroy, instead of the default reverse-construction order (consumer before producer), an attachesTo edge flips direction: the host is destroyed first, then the attacher.

PKL syntax:

@formae.FieldHint { attachesTo = true }
targetGroupArn: (String|formae.Resolvable)?

Compatibility. The AttachesTo field defaults to false on JSON unmarshal of stored resources whose schemas were written before this release. Existing plugins compiled against pkg/plugin@v0.2.1 or earlier continue to load unchanged. Agents older than 0.84.0 silently ignore the annotation (the field round-trips as false).

Migration from v0.2.1: Bump the dependency and rebuild:

github.com/platform-engineering-labs/formae/pkg/plugin v0.2.2
github.com/platform-engineering-labs/formae/pkg/model v0.1.24

Then go mod tidy and make build. Plugins that do not adopt attachesTo need no code changes.


conformance-tests v0.2.4

Released May 13, 2026. Requires plugin ≥0.2.2

Feature: --schema-location local for unpublished plugins

The conformance harness now passes --schema-location local to formae extract during conformance runs. Plugins whose schema has not yet been published to Hub no longer need a Hub entry to run their conformance suite — the agent resolves the schema from the locally loaded plugin binary instead.

Feature: FORMAE_TEST_TESTDATA_DIR override

Set FORMAE_TEST_TESTDATA_DIR to point at an alternate fixture directory at runtime. This lets plugin authors test against different fixture sets (for example, region-specific resources or staged migration fixtures) without modifying test code or Makefile targets.

Migration from v0.2.3: Bump the dependency:

github.com/platform-engineering-labs/formae/pkg/plugin-conformance-tests v0.2.4

Then go mod tidy. No code changes required.


Full go.mod bump for this cycle

github.com/platform-engineering-labs/formae/pkg/plugin v0.2.2
github.com/platform-engineering-labs/formae/pkg/plugin-conformance-tests v0.2.4
github.com/platform-engineering-labs/formae/pkg/model v0.1.24

Run go mod tidy and make build after updating. The Makefile's auto-derivation keeps minFormaeVersion in formae-plugin.pkl at 0.84.0; no behavioural change for plugins that do not adopt attachesTo.


April 2026

conformance-tests v0.2.3

Released April 27, 2026. Requires plugin ≥0.2.1

Feature: Configurable timeouts for the OOB-delete CRUD phase and the OOB plugin RPCs

Two timeouts that previously fired in the middle of healthy long-running operations on slow backends are now configurable, and one of them has a much higher default. Slow managed-Kubernetes resources (AWS::EKS::Cluster, OVH::Kube::Cluster, etc.) were the main motivator — they were failing conformance not because of bugs, but because the harness gave up before the cloud API finished.

Env var Bounds Default Override when
FORMAE_TEST_OOB_TIMEOUT The OOB Create / OOB Delete plugin RPC waits inside retryOnRecoverable (single attempt of waitForOperationProgress). Used by both the discovery test's CreateOOB step and the CRUD test's OOB-delete setup. 30 minutes (raised from a hardcoded 10 minutes) A single Create/Delete RPC to your plugin can legitimately take longer than 30 minutes. Most plugins won't need this.
FORMAE_TEST_OOB_DELETE_TIMEOUT Step 24 of the CRUD test: the post-sync inventory-tombstone wait, after the plugin's Delete RPC has already returned. 2 minutes (unchanged; was previously hardcoded) Sync → tombstone propagation in your agent setup is slow.

Both default to values that match what we currently exercise on AWS / OVH; raise them only if you observe timeouts on a specific resource, with a value in integer minutes (matches the FORMAE_TEST_TIMEOUT and FORMAE_TEST_DISCOVERY_TIMEOUT convention).

The two knobs are independent — they bound different waits in different phases and can be set independently in CI.

Pairs with the AWS plugin fixes in formae-plugin-aws#47, which gets eks-cluster off the timeout list.

Migration from v0.2.2: Bump the dependency:

go get github.com/platform-engineering-labs/formae/pkg/plugin-conformance-tests@v0.2.3
go mod tidy

No code changes required. Existing conformance test suites continue to work unchanged; the raised default for FORMAE_TEST_OOB_TIMEOUT only affects how long the harness is willing to wait for slow-provisioning resources before failing.


plugin v0.2.1

Released April 18, 2026. Requires formae ≥0.84.0

Feature: Plugin compatibility checks

Plugins now verify agent compatibility at startup. If the agent version is older than the SDK's minimum requirement, the plugin exits with a clear error message instead of failing with cryptic wire protocol errors. The agent also checks plugin compatibility during discovery and skips incompatible plugins with actionable warnings.

The SDK exports two constants — MinFormaeVersion and SDKVersion — that plugins can use in build tooling. The make build target in the plugin template now auto-generates minFormaeVersion in the manifest from the SDK constant, removing the need for plugin authors to set it manually.

Feature: Conformance test harness handles binary download

The conformance test harness now downloads the formae binary automatically via the orbital package manager when FORMAE_BINARY is not set. PKL dependency resolution is also handled by the harness. Plugin authors no longer need the scripts/run-conformance-tests.sh shell script — the Makefile conformance targets call go test -tags=conformance directly. Future changes to the download mechanism or PKL resolution will flow through go get without requiring manual script updates.

Migration from v0.2.0: Update your go.mod:

go get github.com/platform-engineering-labs/formae/pkg/plugin@v0.2.1
go get github.com/platform-engineering-labs/formae/pkg/plugin-conformance-tests@v0.2.1
go mod tidy

Optionally update your Makefile to match the template (simplified conformance targets, broadened schema install, auto-generated minFormaeVersion) and delete scripts/run-conformance-tests.sh.


plugin v0.2.0

Released April 16, 2026. Requires formae ≥0.84.0 and Go 1.26+

Breaking change. The wire protocol between the agent and plugins has changed from EDF struct encoding to MessagePack. All plugins must be recompiled against this version. Plugins built against older SDK versions will fail with message decoding errors.

Change: MessagePack serialization replaces EDF

The internal wire protocol between the agent and plugins now uses MessagePack with zstd compression instead of Ergo's native EDF struct encoding. This is a foundational change that enables backwards-compatible schema evolution — adding new fields to SDK types no longer breaks existing plugins. Previously, any field addition to a message type required all plugins to be recompiled simultaneously.

Plugin developers do not need to handle serialization directly — it is transparent. The CompressResource() and CompressJSON() helpers from v0.1.21 are no longer needed and have been removed; compression is now handled at the protocol layer.

Change: Simplified EDF type registration

RegisterSharedEDFTypes() now registers 13 top-level message types instead of the ~40 dependency-ordered types required previously. Nested types are handled by MessagePack, eliminating the registration ordering issues that plugin authors occasionally hit when adding new message types.

Feature: Configurable interface for plugin-specific configuration

Plugins can now receive custom configuration from the user's formae.conf.pkl. Implement the optional Configurable interface to accept plugin-specific settings beyond the standard rate limits and discovery filters:

type Configurable interface {
    Configure(config json.RawMessage) error
}

Define your configuration schema in schema/Config.pkl extending BaseResourcePluginConfig, and users can set plugin-specific fields in the agent.resourcePlugins block of their configuration. See

Change: Configuration types moved to pkg/model

RateLimitConfig, MatchFilter, FilterCondition, and LabelConfig have moved from pkg/plugin to pkg/model. Update your imports accordingly:

// Before
plugin.RateLimitConfig{...}

// After
import pkgmodel "github.com/platform-engineering-labs/formae/pkg/model"
pkgmodel.RateLimitConfig{...}

Feature: Discovery filters and label configuration

Two new methods on the ResourcePlugin interface let plugins declaratively shape discovery behavior:

  • DiscoveryFilters() — return filters to exclude specific resources from discovery (e.g., Kubernetes-owned resources in AWS)
  • LabelConfig() — configure how human-readable labels are extracted from discovered resources using JSONPath queries

Both methods are required. Plugins that don't need filtering or custom labels should return nil and pkgmodel.LabelConfig{} respectively.

Change: Ergo framework upgraded to v3.2.0

The Ergo actor framework has been upgraded from v3.1.0 to v3.2.0. This is handled transparently by the SDK — plugin developers do not need to interact with Ergo directly.

Fix: Ergo banner no longer printed in plugin processes

Plugin processes no longer print the Ergo Framework ASCII banner on startup, keeping plugin logs clean.

Fix: Stack overflow on self-referencing sub-resource types

reverseSubResourceFieldMapping now tracks visited classes and breaks the recursion on self-referencing types (for example, BigQuery's SchemaField). Extract and PKL generation no longer hit a stack overflow when plugins expose sub-resources that recurse into their own type.


conformance-tests v0.2.2

Released April 18, 2026. Requires plugin ≥0.2.1

Fix: Correct orbital hub URL and version extraction

Fixed the hub URL used for downloading formae (was pointing to the old binaries/repo.json endpoint instead of the orbital repository). Also fixed version extraction to parse the formae version from --version output correctly.


conformance-tests v0.2.1

Released April 18, 2026. Requires plugin ≥0.2.1

Feature: Built-in binary download via orbital

The harness now downloads the formae binary automatically when FORMAE_BINARY is not set, using the same orbital package manager that powers formae update. This eliminates the need for scripts/run-conformance-tests.sh. PKL dependency resolution (version pinning + pkl project resolve) is also handled internally.

Improvement: Graceful handling of missing PklProject files

ResolvePKLDependencies now skips directories without a PklProject file instead of failing, supporting minimal plugins that may not have testdata/PklProject.


conformance-tests v0.2.0

Released April 16, 2026. Requires plugin ≥0.2.0 and Go 1.26+

Feature: Per-plugin typed configuration in test harness

The test harness now generates configuration using typed plugin imports (import "plugins:/<Plugin>.pkl") and per-plugin resourcePlugins blocks, matching the new configuration format in formae ≥0.84.0. Plugins must have a schema/Config.pkl extending BaseResourcePluginConfig for the harness to generate correct configuration.

Feature: Configurable discovery resource types via environment variable

The FORMAE_DISCOVERY_TYPES environment variable allows overriding which resource types the harness configures for discovery tests, without modifying test code.

Feature: Step-level result matrix in test output

Conformance test output now includes per-phase outcomes via the new ResultCollector: 8 CRUD phases (Create, Verify, Extract, Sync, Update, Replace, Destroy, OOB Delete) and 4 discovery phases (CreateOOB, Register, Discover, Verify). This makes it easy to see at a glance which phase failed instead of parsing the full test log.

Change: Top-level pluginDir in generated configuration

The test configuration now includes pluginDir at the top level, matching the configuration schema change in formae ≥0.84.0.

Fix: Discovery NativeID matching for charts with multiple resource types

The discovery test previously took the NativeID from the last-created resource and the resource type from the last resource in the PKL output, which could differ when dependency order and PKL output order diverged (for example, a cert-manager chart whose last PKL resource is a Service but last-created resource is a Deployment). The harness now searches backwards through created resources for the one matching the extracted type, so discovery tests for multi-resource charts no longer wait for a non-existent combination.


March 2026

plugin v0.1.21

Released March 28, 2026

Breaking change. The internal message format between the agent and plugins has changed. All plugins must be recompiled against this version. Plugins built against older SDK versions will fail with message decoding errors during synchronization and resource operations.

Change: Compressed plugin messages

Resource fields in all plugin operation messages (ReadResource, CreateResource, UpdateResource, DeleteResource) are now gzip-compressed for transport. This resolves an issue where resources with large schemas (e.g. Kubernetes Pod, AWS ECS TaskDefinition) could exceed internal transport limits, causing silent failures during synchronization and updates.

Plugin developers do not need to handle compression — it is transparent. If you construct ReadResource or DeleteResource directly (e.g. in test utilities), use plugin.CompressResource() for the Resource field and plugin.CompressJSON() for property fields.

Fix: Plugin error messages now included in failure responses

When a plugin's CRUD method returns an error, the error text is now included in the response. Previously the message was empty, making failures difficult to diagnose from the CLI or API.


conformance-tests v0.1.40

Released March 28, 2026

Feature: Out-of-band delete detection test

The CRUD lifecycle now verifies that the agent correctly detects when a resource is deleted outside of formae. After the standard destroy cycle, the test recreates the resource, deletes it directly via the plugin (bypassing formae), triggers a sync, and verifies the resource is removed from inventory.

Feature: Collection-aware hasProviderDefault for Mapping fields

Property comparison now correctly handles hasProviderDefault on Mapping-type fields, preventing false test failures when cloud providers populate extra keys in map fields.


conformance-tests v0.1.25

Released March 17, 2026

Feature: Regex support for test filter

The TEST= parameter now supports /…/ delimited regular expressions for flexible test group selection. For example, TEST='/.*-chart/' selects all chart tests and TEST='/^cluster.*/' selects all cluster-scoped resources. Regex and literal segments can be mixed in a single comma-separated filter (e.g., TEST='/.*-chart/,namespace'). Invalid regex patterns cause immediate failure with a clear error message. See Filtering Tests for details.

Feature: Configurable discovery timeout

The discovery test timeout is now configurable via the FORMAE_TEST_DISCOVERY_TIMEOUT environment variable (in minutes). Previously hardcoded to 2 minutes, this can now be increased for plugins with many resource types or chart-based test cases that need more time for discovery to complete. See Environment Variables for details.


conformance-tests v0.1.24

Released March 12, 2026

Fix: Retry create/delete operations on recoverable errors

The test harness now retries CreateResource and DeleteResource operations when the plugin returns a recoverable error, instead of failing the test immediately. This reduces flaky test failures caused by transient cloud provider errors during conformance runs.


conformance-tests v0.1.23

Released March 10, 2026

Fix: Honor @HasProviderDefault annotation in property comparison

Previously, conformance tests ignored extra fields returned by plugins, which could hide issues where plugins return unexpected data. Tests now validate that extra fields in the actual state are only allowed if marked with @HasProviderDefault in the schema. Unexpected extra fields will now correctly fail the test.


conformance-tests v0.1.22

Released March 9, 2026

Fix: Property comparison for Listing fields containing resolvables

Previously, conformance tests would fail for schemas with Listing fields where elements contained resolvable references (e.g., subjects: Listing<Subject> with a resolvable namespace property inside Subject). The test framework now correctly compares these nested resolvables.


February 2026

plugin v0.1.14

Released February 23, 2026. Requires formae ≥0.82.2

Fix: Transitive pkg/model dependency

Fixed incorrect transitive dependency on pkg/model that caused EDF serialization errors. The pkg/model dependency is now pinned to v0.1.5 across all SDK modules.


conformance-tests v0.1.21

Released February 23, 2026. Requires plugin ≥0.1.14

Fix: Transitive pkg/model dependency

Bumped pkg/model to v0.1.5 to match plugin v0.1.14, fixing EDF serialization errors caused by mismatched transitive dependencies.


plugin-template

Feature: verify-schema CI job

Added a verify-schema CI job to the template that validates PKL schemas can be generated correctly, catching schema errors before they reach plugin releases.


conformance-tests v0.1.20

Released February 23, 2026

Fix: Nested Resolvables in SubResource map comparison

compareProperties() used flat string comparison for non-Resolvable, non-array values. When a SubResource map (e.g., ResourceLifecycleConfig) contained a nested Resolvable reference, the entire map was string-compared — $visibility:Clear from Pkl eval vs $value:arn:... from resolved inventory — causing false test failures.

Added recursive compareMap() that delegates to compareResolvable() for nested Resolvables, compareArrayUnordered() for arrays, and recurses into sub-maps.


plugin v0.1.13

Requires formae ≥0.82.0

Feature: HasProviderDefault field hint

New hasProviderDefault annotation for fields where cloud providers assign default values (e.g., S3 bucket encryption, SQS visibility timeout).

@formae.FieldHint { hasProviderDefault = true }
bucketEncryption: BucketEncryption?

When a field with this hint exists in actual state but is not specified by the user, formae accepts the provider's default instead of generating a "remove" operation. This prevents oscillation during reconcile cycles.

See the schema reference for details.


conformance-tests v0.1.19

Released February 10, 2026

Improvement: Robust property comparison for arrays, resolvables, and string escaping

This release significantly improves how the conformance test framework compares expected vs actual resource properties:

  • Order-independent array comparison — All array properties are now compared as unordered sets. Elements are serialized to JSON and sorted before comparison, eliminating false failures caused by CloudControl returning arrays in a different order than specified in PKL.

  • Resolvable handling inside arrays — Arrays containing resolvable references (e.g., Tags with resolved values) are now matched element-wise using metadata keys ($label, $type, $stack, $property). Resolvables are handled gracefully after extraction, where $value may no longer be present.

  • String escaping normalization — JSON/PKL round-trip differences in backslash escaping no longer cause false mismatches. Extraction comparison now reuses the same comparison logic as inventory comparison, benefiting from all the above improvements.


plugin v0.1.12

Released February 6, 2026

Fix: pkl-go race condition

Fixed a race condition in pkl-go's NewProjectEvaluator where a late message from the pkl subprocess could kill the evaluator manager's listen loop, causing evaluation failures. This primarily affected CI environments under resource pressure.


plugin v0.1.11

Released February 5, 2026

Feature: Plugin telemetry metrics

Plugins now export Ergo actor framework metrics via OpenTelemetry, providing visibility into plugin process health and performance.


conformance-tests v0.1.14

Released February 4, 2026

Feature: Configurable test timeout

Override the default 5-minute timeout for resources that take longer to provision:

make conformance-test TIMEOUT=900

Note: Requires updating your Makefile from the plugin template repository.


Feature: Config directory support

You can now create a config/ directory under testdata/ containing shared Pkl code (such as targets or stacks). Files in this directory are not picked up as test cases by the conformance test framework.


January 2026

conformance-tests v0.1.13

Released January 31, 2026. Requires plugin v0.1.9.

Feature: Parallel test execution with configurable Ergo ports

Run conformance tests in parallel to significantly reduce test execution time:

make conformance-test PARALLEL=10

When running parallel tests, multiple formae agent instances need unique ports for Ergo node communication. This release adds ergoPort configuration to prevent port conflicts.

Note: Requires updating your Makefile from the plugin template repository.


conformance-tests v0.1.12

Released January 30, 2026

Feature: Parallel test execution support

Added infrastructure for running conformance tests in parallel via FORMAE_TEST_PARALLEL environment variable.


conformance-tests v0.1.10

Released January 30, 2026

Conformance test improvements

  • Faster and more reliable discovery tests in CI environments
  • Extract validation step now runs correctly for all extractable resources
  • Improved error messages when validations fail

plugin v0.1.9

Released January 31, 2026

Feature: Configurable Ergo port

Plugins now read FORMAE_ERGO_PORT environment variable to configure Ergo acceptors, enabling parallel test execution.


plugin v0.1.8

Released January 30, 2026

Fix: Plugin log levels now preserved

Plugin logs were incorrectly routed through stderr, causing the formae agent to treat all plugin logs as errors regardless of their actual log level. Logs now route through stdout with correct log levels preserved.