Skip to content

Release Manifests

A release manifest is the immutable contract between a ThinkWork release and a customer deployment job. It lets the CLI and the customer AWS control plane deploy without cloning the ThinkWork source repository.

The manifest includes:

  • manifest schema version
  • release version
  • compatibility bounds
  • artifact metadata and SHA-256 hashes
  • artifact bundle metadata for machine-consumed platform payloads
  • Terraform module or bundle references
  • deployment runner/build image reference
  • deployment runner script path, SHA-256, and size metadata
  • managed-app descriptors for Cognee, Twenty, and Plane
  • smoke contracts
  • deployment profile schema version
  • key id and detached signature metadata when the release is signed
  1. Resolve the controller trust policy for the selected environment.
  2. For customer-safe runs, require a detached signature and verify it with a pinned trusted ThinkWork public key.
  3. For dogfood canary runs, unsigned manifests are allowed only when the controller policy is explicitly allow_unsigned_canary; evidence must mark the manifest as an unsigned canary.
  4. Reject expired or revoked signing keys.
  5. Verify compatibility bounds for the CLI and runner.
  6. Resolve releases by explicit version/tag plus manifest digest. Do not use GitHub’s Latest badge as deployment authority for canary validation.
  7. Download artifact bundles only after the manifest is trusted.
  8. Verify the platform bundle SHA-256, extract it with traversal/link checks, and verify every contained artifact SHA-256 before Terraform, static assets, or runtime bundles consume it.
  9. Record the raw manifest digest, canonical manifest digest, trust decision, bundle digest, and staged artifact digests on deployment jobs and smoke evidence.

Human-facing GitHub Releases should stay small. For deployable platform releases, the expected machine-consumed assets are:

  • thinkwork-release.json
  • thinkwork-release.sig.json when release signing is enabled
  • platform-artifacts.tar.gz

The platform bundle contains backend Lambda zips, static-site archives, and the deployment runner script under runner/thinkwork-runner.py. Individual artifact URLs in the manifest are a compatibility path; new deployment controller runs should consume the bundle and verify every contained artifact against the manifest before staging it.

components.deploymentRunner.script records the staged runner script’s relativePath, optional direct url, SHA-256, and size. Settings release preflight uses that metadata to compare a customer’s frozen S3 runner with the selected release. Runner refresh remediation must copy the trusted selected release script only after the manifest and platform bundle have been verified, and evidence should record both the previous runner object and the target script digest.

The manifest asset is also the publish finalization marker. Release automation removes any existing thinkwork-release.json before refreshing deployable assets, uploads the platform bundle and signature first, and uploads the final manifest last. If a refresh fails midway, the release should be temporarily non-deployable instead of presenting an old manifest digest with newer assets.

Managed-app descriptors and runtime images are one contract. If a release manifest advertises a managed app with requiredImages, every required image name must appear in runtimeImages as an immutable @sha256: URI. The release publisher builds the ThinkWork-owned Cognee image and reads pinned Twenty and Plane image URIs from repository variables so the controller can fail before Terraform when an optional app cannot be deployed from the selected release.

The default release manifest currently advertises:

Managed appRequired runtime imageSmoke contract
Cogneecogneeplugins/company-brain/smoke/cognee-managed-app-smoke.mjs
Twenty CRMtwentyplugins/twenty/smoke/twenty-managed-app-smoke.mjs
Planeplaneplugins/plane/smoke/plane-managed-app-smoke.mjs

Plane’s release descriptor is only deploy-ready when the selected manifest contains a digest-pinned Plane runtime image. The image URI must use @sha256: rather than a mutable tag because the deployment runner passes the selected manifest image directly into Terraform.

Desktop assets may be published by a separate workflow, but operators should see one coordinated release version. The human-facing release should contain desktop installers, updater metadata, thinkwork-release.json, and platform-artifacts.tar.gz before the release is treated as a deployable environment update.

Unsigned canaries are for ThinkWork dogfood and TEI proving runs only while the signing key rollout is in progress. Production and customer-safe controllers should set release_manifest_trust_policy = "require_signature" and configure trusted public keys before accepting a release.

The TEI proving environment accepted v0.1.0-canary.149 under the explicit allow_unsigned_canary trust policy. Evidence records both the raw manifest SHA-256 f25c6a05d42578acd6f4696d678b19af831c6e19a23e227e07a6db9559f47532 and the platform bundle SHA-256 b463b44094d60e94ee068881343deab53bb65d6d081b69757dcc04afb181aad8.

Release upgrade evidence should record:

  • previous release version and manifest digest
  • target release version and manifest digest
  • target deployment runner script digest and path
  • platform bundle digest and staged artifact digests
  • Step Functions execution ARN
  • CodeBuild build ARN/id
  • Terraform plan and apply artifact keys
  • post-upgrade foundation smoke result
  • managed-app smoke results for enabled apps, including Plane when it is provisioned or parked

The Settings release workflow consumes the release manifest before dispatching the customer deployment controller. The preflight job must verify and persist:

  • target manifest URL and SHA-256
  • manifest signed/unsigned state and trust policy
  • selected release Terraform module or bundle version
  • selected release runner script path, SHA-256, and size
  • deployed frozen S3 runner compatibility
  • preserved customer configuration summary
  • known IAM drift checks required by the selected release class
  • evidence bucket/prefix and final status pointer

Dispatch must use the release-update job id created by preflight. It must not restart the old direct path that sends only release version, manifest URL, and manifest SHA-256 to the controller.

The preflight summary is intentionally operator-facing. It should make customer domain, delegated/legacy-retired flags, SES sender settings, platform operator emails, identity/OAuth posture, and optional app flags visible before the operator can start the controller.

FailureMeaning
Missing signatureThe controller requires a trusted signature and no detached signature was available.
Unsigned non-canary manifestThe selected release is not a canary and cannot run under allow_unsigned_canary.
Invalid signatureThe manifest cannot be trusted. Stop and fetch a known-good manifest.
Unknown keyThe runner does not trust the signing key. Update trusted keys only through a reviewed release.
Revoked or expired keyDo not deploy. Use a release signed by an active key.
Artifact hash mismatchThe artifact does not match the manifest. Stop before Terraform or runtime update.
Compatibility mismatchUpgrade the CLI/runner or choose a compatible release.
Missing managed-app smoke metadataThe release is not usable for managed-app deployment.
Missing managed-app runtime imageThe release advertises an app that cannot be deployed from its manifest.
Runner mismatchRefresh the S3 runner from the selected trusted release before dispatch.
IAM driftBlock dispatch until the live CodeBuild role can satisfy the selected release class.

ThinkWork can continue to publish release assets from the ThinkWork-owned GitHub project. Customer deployments consume signed release artifacts from the release manifest; they do not need a customer source repo or customer GitHub Actions.

See docs/runbooks/settings-release-upgrades.md for the operator runbook and docs/verification/settings-release-upgrade-safety.md for the regression checklist.