Oblive Docs

Container Releases

Publish coordinated Oblive images to Amazon ECR Public and deployment bundles to Cloudflare R2.

Oblive publishes three first-party images and one coordinated portable deployment bundle from the manual Publish release GitHub Actions workflow:

ImageRuntime roles
backendBackend API and one-shot migrations
frontendFrontend server
agentsChat, worker, and Codex auth synchronizer

PostgreSQL, Redis, and Garage retain the exact upstream tags in compose.yaml: pgvector/pgvector:0.8.1-pg17, redis:8.2.1-alpine, and dxflrs/garage:v2.3.0.

Configure GitHub

Create these repository secrets:

  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY
  • CLOUDFLARE_ACCOUNT_ID
  • CLOUDFLARE_R2_ACCESS_KEY_ID
  • CLOUDFLARE_R2_SECRET_ACCESS_KEY

Create these repository variables:

VariableValue
ECR_PUBLIC_REGISTRY_ALIASw3z5w3s0
ECR_PUBLIC_REPOSITORYskyfall/oblive
CLOUDFLARE_R2_BUCKEToblive
OBLIVE_DOWNLOAD_BASE_URLhttps://downloads.oblive.dev

The credentials must belong to a dedicated least-privilege IAM principal. Amazon ECR Public authentication runs through us-east-1, while image upload permission is scoped to the existing repository:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "GetAuthorizationToken",
      "Effect": "Allow",
      "Action": ["ecr-public:GetAuthorizationToken", "sts:GetServiceBearerToken"],
      "Resource": "*"
    },
    {
      "Sid": "PublishObliveImages",
      "Effect": "Allow",
      "Action": [
        "ecr-public:BatchCheckLayerAvailability",
        "ecr-public:CompleteLayerUpload",
        "ecr-public:InitiateLayerUpload",
        "ecr-public:PutImage",
        "ecr-public:UploadLayerPart"
      ],
      "Resource": "arn:aws:ecr-public::<aws-account-id>:repository/skyfall/oblive"
    }
  ]
}

Replace <aws-account-id> with the AWS account that owns the public repository. The workflow does not create or configure the repository. The same AWS credentials authenticate image publication and the release smoke test; no second credential pair is required.

Create the Cloudflare credentials under R2 → Overview → Manage R2 API Tokens. Use an account token with Object Read & Write access limited to the oblive bucket, then store its generated Access Key ID and Secret Access Key in the matching GitHub secrets. The existing Cloudflare account ID can be reused; the Pages API token and AWS ECR credentials are separate and must not be reused for R2 S3 uploads. Connect downloads.oblive.dev as the bucket’s public custom domain.

Publish a Release

  1. Open Actions → Publish release → Run workflow.

  2. Select the main branch.

  3. Select the release mode:

    ModeUse when
    fullBackend, frontend, agents, or their image dependencies changed.
    bundle-onlyOnly the CLI, Compose files, schema, or packaged config changed.
  4. Choose a patch, minor, or major bump. The first release must use full with patch, producing v0.0.1.

  5. Optionally add maintainer notes. They appear before GitHub’s generated release notes.

  6. Run the workflow.

The workflow refuses non-main releases, commits without a successful main CI run, and releases with no commits after the latest stable vX.Y.Z tag. CI owns formatting, linting, type checks, unit and integration tests, bundle and installer tests, and the complete source-stack smoke. The release workflow keeps only the checks that depend on newly published semantic artifacts.

The release boundary is deliberately ordered:

  1. In full mode, build AMD64 and ARM64 digests for all three services. In bundle-only mode, resolve and validate the immediately previous stable release’s digests without rebuilding.
  2. Publish and verify immutable semantic image tags.
  3. Build and checksum the deployment bundle.
  4. Authenticate to Public ECR, start the complete semantic deployment with a non-operational API key, and verify backend health plus the frontend HTML, CSS, and JavaScript assets.
  5. Promote all three latest tags to the tested digests.
  6. Publish and publicly verify the versioned bundle in Cloudflare R2, then advance the latest pointer.
  7. Create the matching GitHub tag and Release metadata.

If bundle generation, smoke testing, R2 publication, or public checksum verification fails, the download pointer and GitHub Release are not advanced. The smoke job always removes its containers and volumes.

Use bundle-only only when the existing service images remain valid for the packaged changes. It creates a normal coordinated semantic release: the new service tags point to the reused immutable digests, the complete stack is smoke tested, and only then are the moving tags and download pointer advanced. Reused images retain their original OCI build metadata and provenance. The bundle owns the dependency-bundled stack generator used for configuration and environment generation, so it does not require reused backend images to contain current repository scripts.

Changes limited to the landing page or public install.sh do not require this workflow. Publish those through Publish landing instead. Documentation and landing deployments run only after CI succeeds for the same main commit; unchanged sites are skipped. Manual site deployments are also limited to CI-passing commits on main.

Image Tags

Every release creates a new version-specific semantic tag and updates the moving latest tag for each image. A bundle-only release may point its new tag to the previous release’s immutable image digest, but the workflow never overwrites an earlier semantic tag:

public.ecr.aws/w3z5w3s0/skyfall/oblive:backend-v0.0.1
public.ecr.aws/w3z5w3s0/skyfall/oblive:backend-latest
public.ecr.aws/w3z5w3s0/skyfall/oblive:frontend-v0.0.1
public.ecr.aws/w3z5w3s0/skyfall/oblive:frontend-latest
public.ecr.aws/w3z5w3s0/skyfall/oblive:agents-v0.0.1
public.ecr.aws/w3z5w3s0/skyfall/oblive:agents-latest

The installer never places moving image tags in a deployment. The latest installation channel resolves the R2 releases/latest pointer, then writes the matching <service>-vX.Y.Z references for all three first-party services. oblive update is the only normal boundary that advances that selection.

Deployment Bundle

Every semantic release publishes stable asset names under an immutable version path:

https://downloads.oblive.dev/releases/vX.Y.Z/oblive-deployment.tar.gz
https://downloads.oblive.dev/releases/vX.Y.Z/oblive-deployment.tar.gz.sha256
https://downloads.oblive.dev/releases/latest

The final path contains only the exact current stable version, such as v1.2.3, and is updated after the versioned archive passes checksum verification through the public hostname. GitHub Releases retain the semantic tag and generated release notes; R2 is the public bundle owner.

The archive contains the semantic VERSION, image repository, build-free base and local-auth Compose files, Garage and PostgreSQL initialization files, local-stack JSON Schema, a portable stack runtime bundled with its dependencies, and the standalone oblive CLI. The CLI mounts that runtime into the backend container, which supplies the pinned Bun executable without owning the generator source. The generator runs as the invoking host user so its mode-0600 configuration and environment files remain private without becoming root-owned on Linux.

The Installed CLI Architecture page defines the bundle layout, root resolution, Compose invocation, update transaction, and destructive-command boundaries.

Install the repository dependencies, then build the archive locally for inspection with:

bun install --frozen-lockfile
.github/scripts/release/build-deployment-bundle.sh \
  v1.2.3 public.ecr.aws/w3z5w3s0/skyfall/oblive /tmp/oblive-release
.github/scripts/tests/deployment-bundle.test.sh
.github/scripts/tests/deployment-bundle-container.test.sh
.github/scripts/tests/portable-install.test.sh

The public /install.sh endpoint resolves latest when necessary and downloads the stable assets from the exact R2 semantic-version path. Keep the asset names, bundle layout, semantic tag contract, download pointer, and CLI update logic compatible in one change.