diff --git a/scripts/create-tagged-release.sh b/scripts/create-tagged-release.sh
new file mode 100755
index 0000000..6a2c794
--- /dev/null
+++ b/scripts/create-tagged-release.sh
@@ -0,0 +1,101 @@
+#!/usr/bin/env bash
+# Copyright 2022 Mycroft AI Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+# -----------------------------------------------------------------------------
+#
+# Creates a Github release by tag name and uploads assets.
+#
+# Assumes curl and jq are installed.
+#
+set -eo pipefail
+
+owner="$1"
+repo="$2"
+tag="$3"
+token="$4"
+
+if [ -z "${token}" ]; then
+ echo 'Usage: create-tagged-release.sh [asset] [content-type] [asset] [content-type] ...';
+ exit 1;
+fi
+
+shift 4
+
+temp_dir="$(mktemp -d)"
+function finish {
+ rm -rf "${temp_dir}"
+}
+
+trap finish EXIT
+
+# -----------------------------------------------------------------------------
+
+function create_release {
+ # Creates a new tagged release and saves response JSON
+ curl \
+ --silent \
+ --show-error \
+ -X POST \
+ -H 'Accept: application/vnd.github.v3+json' \
+ -H "Authorization: token ${token}" \
+ -d "{\"tag_name\":\"${tag}\",\"target_commitish\":\"master\",\"name\":\"${tag}\",\"body\":\"\",\"draft\":false,\"prerelease\":false,\"generate_release_notes\":false}" \
+ --output "${temp_dir}/response.json" \
+ "https://api.github.com/repos/${owner}/${repo}/releases"
+
+ echo "${temp_dir}/response.json"
+}
+
+function upload_asset {
+ # Uploads an asset to a tagged release
+ upload_url="$1"
+ asset_path="$2"
+ asset_content_type="$3"
+ asset_name="$(basename "${asset_path}")"
+
+ curl \
+ --silent \
+ --show-error \
+ -X POST \
+ -H 'Accept: application/vnd.github.v3+json' \
+ -H "Authorization: token ${token}" \
+ -H "Content-Type: ${asset_content_type}" \
+ --output /dev/null \
+ --data-binary "@${asset_path}" \
+ "${upload_url}?name=${asset_name}"
+}
+
+export create_release
+export upload_asset
+
+response_json="$(create_release)"
+
+release_id="$(jq --raw-output '.id' < "${response_json}")"
+echo "Created ${release_id}"
+
+# Remove {?name.label} from upload URL
+upload_url="$(jq --raw-output '.upload_url' < "${response_json}" | sed -e 's/{[^}]\+}//g')"
+
+# Upload assets
+while [ -n "$2" ]; do
+ asset_path="$1"
+ asset_content_type="$2"
+ upload_asset "${upload_url}" "${asset_path}" "${asset_content_type}"
+
+ echo "Uploaded ${asset_path}"
+ shift 2
+done
+
+echo 'OK'
diff --git a/scripts/delete-tagged-release.sh b/scripts/delete-tagged-release.sh
new file mode 100755
index 0000000..9c0b8b9
--- /dev/null
+++ b/scripts/delete-tagged-release.sh
@@ -0,0 +1,69 @@
+#!/usr/bin/env bash
+# Copyright 2022 Mycroft AI Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+# -----------------------------------------------------------------------------
+#
+# Deletes a Github release by tag name, if it exists.
+#
+# Assumes curl and jq are installed.
+#
+set -eo pipefail
+
+owner="$1"
+repo="$2"
+tag="$3"
+token="$4"
+
+if [ -z "${token}" ]; then
+ echo 'Usage: delete-tagged-release.sh ';
+ exit 1;
+fi
+
+# -----------------------------------------------------------------------------
+
+function get_release_id {
+ curl \
+ --silent \
+ --show-error \
+ -H "Authorization: token ${token}" \
+ -H 'Accept: application/vnd.github.v3+json' \
+ --output - \
+ "https://api.github.com/repos/${owner}/${repo}/releases/tags/${tag}" | \
+ jq --raw-output '.id'
+}
+
+function delete_release {
+ release_id="$1"
+
+ curl \
+ --silent \
+ --show-error \
+ -X DELETE \
+ -H 'Accept: application/vnd.github.v3+json' \
+ -H "Authorization: token ${token}" \
+ "https://api.github.com/repos/${owner}/${repo}/releases/${release_id}"
+}
+
+export get_release_id
+
+release_id="$(get_release_id)"
+
+if [ -n "${release_id}" ]; then
+ delete_release "${release_id}"
+ echo "Deleted: ${release_id}"
+fi
+
+echo 'OK'