- pkg/plugin - Core SDK for building plugins
- pkg/plugin-conformance-tests - Conformance test framework
- formae-plugin-template - Scaffold for new plugins
July 2026
formae schema 0.88.0
Released July 2026. Requires formae ≥0.88.0. Feature:formae.SecretValue for secret fields
Mark a resource field as a secret by typing it (String | formae.SecretValue) (nullable and union variants included). formae derives the field’s opaque hint from the type, so the agent stores the value hashed at rest and keeps it out of logs. This is independent of writeOnly, which controls read-back and drift; a secret the provider never returns is typically both.
plugin v0.4.1
Released July 2026. Requires formae ≥0.87.1 forPriorProperties to be populated.
Feature: PriorProperties on ReadRequest
ReadRequest now carries an optional PriorProperties field holding the caller’s last-known model for the resource (the stored row). A plugin’s Read can consult it to report the projection the caller actually manages. For example, it can embed a child collection only when the prior model declares it inline, so a caller that manages those children as standalone resources is not shown phantom drift or driven to destroy them on a reconcile.
The field is optional and additive: a plugin that ignores it behaves exactly as before, and no migration is required. It is empty when the caller has no prior state, such as a create/status read-back or discovery, so treat empty as “unknown” and fall back to your default behaviour. The agent populates it starting formae 0.87.1; on older agents it is always empty.
PriorProperties is a json.RawMessage; unmarshal it to inspect the caller’s model. A read still reports actual cloud state. This hint only disambiguates a resource’s boundary where the provider conflates it with its children.
June 2026
plugin v0.4.0
Released June 2026. Requires formae ≥0.87.0 Breaking behaviour. ThewriteOnly field hint no longer implies “re-send on every update.” writeOnly now means only that the provider never returns the value on read, so it is stripped from read-back state and never produces drift. The “the provider drops this value unless it is included in every update” semantics that writeOnly previously bundled in now live in a separate hint, requiredOnUpdate.
Migration. Audit every field marked @formae.FieldHint { writeOnly = true }. If the provider requires the value to be present on every update (typical of rotating secrets and write-only configuration blocks the API replaces wholesale), add requiredOnUpdate, or the value silently stops being sent and the next update drops it:
writeOnly = true and is no longer needlessly re-sent when an unrelated field on the same resource changes. Run your conformance suite’s update phase: a field the provider drops will surface as a post-update diff, which is the signal it needs requiredOnUpdate.
Feature: format on FieldHint for serialized-content String fields
A String field can now declare the structured format of its content with @formae.FieldHint { format = "json" }. When set, the agent compares the field by its canonical content rather than its raw byte serialization: differences that are purely cosmetic (object key ordering and insignificant whitespace) no longer register as a change, so they neither surface as drift on sync nor produce a no-op update on apply.
read("dashboard.json"). The provider stores the JSON in its own canonical (often minified, key-reordered) form, so on the next read the bytes differ from the source even though the document is identical. With format = "json" the two are compared as equal JSON documents and the spurious diff disappears.
format defaults to "", which leaves the field an opaque String compared byte-for-byte (unchanged behaviour). "json" is the only format recognised today; an unknown value is rejected when the plugin registers rather than silently ignored, and a JSON document with duplicate object keys is rejected.
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:
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.Namespacemixed-case internally. - Five additional template-substitution rules cover placeholders that were leaking through scaffolded output: bare
module exampledeclarations, PklProjectbaseUriandpackageZipUrlstrings, PKL module-qualifier prefixes (example.ExampleResource), the license header year and author (previously hard-coded to 2025), and the new@example/core/example.pklsubdir import path that pairs with the template repo’s subdir convention. - The
testutilImportsGenerator.pklglob is changed fromimport*(@<ns>/**/*.pkl)to the union pattern already used in the sibling generators underinternal/schema/pkl/generatorandpkg/plugin/descriptors. The single-glob form misses top-level files in PKL’s glob model, somake verify-schemawas reporting “Total resource types: 0, PASSED” for plugins that placed resources atschema/pkl/<resource>.pkl: a false-success signal that hid real schema problems. The new pattern matches both top-level and nested files.
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:
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 readsminFormaeVersion 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:
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
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:
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:
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:
go mod tidy. No code changes required.
Full go.mod bump for this cycle
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.
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:
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:
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. TheCompressResource() 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:
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:
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
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 oldbinaries/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 whenFORMAE_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-awarehasProviderDefault 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 TheTEST= 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 retriesCreateResource 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 withListing 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: Transitivepkg/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: Transitivepkg/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 comparisoncompareProperties() 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 NewhasProviderDefault annotation for fields where cloud providers assign
default values (e.g., S3 bucket encryption, SQS visibility timeout).
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$valuemay 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’sNewProjectEvaluator 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: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: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 viaFORMAE_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 readFORMAE_ERGO_PORT environment variable to configure Ergo
acceptors, enabling parallel test execution.

