diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 0266391e294a0882097c0b6b41ab83a43b3d3c81..7ec1bda62c29d878e8ebdbfc4c808950fbcbf845 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -8,9 +8,10 @@ include:
   - "https://git.autistici.org/pipelines/images/test/golang/raw/master/ci.yml"
   - "https://git.autistici.org/pipelines/images/test/golangci-lint/raw/main/ci.yml"
 
-#variables:
-#  GO_TEST_PACKAGES: "npm protobuf-compiler protoc-gen-go protoc-gen-go-grpc brotli xxd"
-#  GO_TEST_GENERATE: "true"
+variables:
+  PACKAGE_VERSION: "$CI_COMMIT_TAG"
+  PACKAGE_REGISTRY_BASE_URL: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/idp/${CI_COMMIT_TAG}"
+  PACKAGE_ARCHIVE_AMD64: "smol-idp-$CI_COMMIT_TAG-linux-amd64.tar.gz"
 
 gen_code:
   stage: gen
@@ -74,6 +75,45 @@ build:
       when: never
     - when: always
 
+build_rel_amd64:
+  stage: build
+  needs:
+    - job: gen_code
+    - job: gen_ui
+    - job: go_test
+      artifacts: false
+  image: golang:1.23
+  tags: [amd64]
+  variables:
+    DIST_DIR: "dist/smol-idp-$PACKAGE_VERSION"
+  script:
+    - mkdir -p $DIST_DIR
+    - go build -o $DIST_DIR/smol-idp ./cmd/smol-idp
+    - cp README.md LICENSE $DIST_DIR/
+    - tar -czvf $PACKAGE_ARCHIVE_AMD64 -C dist smol-idp-$PACKAGE_VERSION
+    - "curl --header \"JOB-TOKEN: ${CI_JOB_TOKEN}\" --upload-file ${PACKAGE_ARCHIVE_AMD64} ${PACKAGE_REGISTRY_BASE_URL}/${PACKAGE_ARCHIVE_AMD64}"
+  rules:
+    - if: $CI_COMMIT_TAG
+
+release:
+  stage: build
+  needs:
+    - job: build_rel_amd64
+      artifacts: false
+  image: registry.gitlab.com/gitlab-org/release-cli:latest
+  rules:
+    - if: $CI_COMMIT_TAG
+  script:
+    - echo "running release job"
+  release:
+    name: "$PACKAGE_VERSION"
+    tag_name: "$CI_COMMIT_TAG"
+    description: "$PACKAGE_VERSION"
+    assets:
+      links:
+        - name: "$PACKAGE_ARCHIVE_AMD64"
+          url: "$PACKAGE_REGISTRY_BASE_URL/$PACKAGE_ARCHIVE_AMD64"
+
 # Avoid duplicate pipelines by being explicit about when to run them.
 workflow:
   rules: