diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 004cb068..7f4ae559 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -1,3 +1,4 @@
+# BEGIN boilerplate-managed
 version: 2
 updates:
   - package-ecosystem: "docker"
@@ -5,10 +6,16 @@ updates:
     labels:
       - "area/dependency"
       - "ok-to-test"
+      - "lgtm"
+      - "approved"
     schedule:
       interval: "weekly"
+      day: "monday"
+      time: "03:00"
+      timezone: "UTC"
     ignore:
-      - dependency-name: "app-sre/boilerplate"
+      - dependency-name: "redhat-services-prod/openshift/boilerplate"
         # don't upgrade boilerplate via these means
-      - dependency-name: "openshift4/ose-operator-registry"
+      - dependency-name: "openshift4/ose-operator-registry*"
         # don't upgrade ose-operator-registry via these means
+# END boilerplate-managed
diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES
index 7fddbfa2..12676f65 100644
--- a/OWNERS_ALIASES
+++ b/OWNERS_ALIASES
@@ -81,7 +81,6 @@ aliases:
     - ravitri
   srep-team-leads:
     - rafael-azevedo
-    - iamkirkbater
     - dustman9000
     - bmeng
     - typeid
diff --git a/boilerplate/_data/last-boilerplate-commit b/boilerplate/_data/last-boilerplate-commit
index e1285a81..038ba7d0 100644
--- a/boilerplate/_data/last-boilerplate-commit
+++ b/boilerplate/_data/last-boilerplate-commit
@@ -1 +1 @@
-1cb129aed5a91f2098f70c0e141561e00b1e16fc
+806a6cb87c742643c0e66fbffffc4b5fc3559007
diff --git a/boilerplate/_lib/container-make b/boilerplate/_lib/container-make
index 77834586..8da20031 100755
--- a/boilerplate/_lib/container-make
+++ b/boilerplate/_lib/container-make
@@ -29,12 +29,14 @@ if [[ "${CONTAINER_ENGINE##*/}" == "podman" ]] && [[ $OSTYPE == *"linux"* ]]; th
 else
     CE_OPTS="${CE_OPTS} -v $REPO_ROOT:$CONTAINER_MOUNT"
 fi
-container_id=$($CONTAINER_ENGINE run -d ${CE_OPTS} $IMAGE_PULL_PATH sleep infinity)
+container_id=$($CONTAINER_ENGINE run --rm -d ${CE_OPTS} $IMAGE_PULL_PATH sleep infinity)
 
 if [[ $? -ne 0 ]] || [[ -z "$container_id" ]]; then
   err "Couldn't start detached container"
 fi
 
+trap "$CONTAINER_ENGINE stop $container_id >/dev/null 2>&1" EXIT
+
 # Now run our `make` command in it with the right UID and working directory
 args="exec -it -u $(id -u):0 -w $CONTAINER_MOUNT $container_id"
 banner "Running: make $@"
@@ -52,6 +54,9 @@ if [[ $rc -ne 0 ]]; then
   fi
 fi
 
+# Disarm the interrupt trap -- normal cleanup handles it from here
+trap - EXIT
+
 # Finally, remove the container
 banner "Cleaning up the container"
 $CONTAINER_ENGINE rm -f $container_id >/dev/null
diff --git a/boilerplate/_lib/subscriber-propose-update b/boilerplate/_lib/subscriber-propose-update
index f3b06ef2..4ac51256 100755
--- a/boilerplate/_lib/subscriber-propose-update
+++ b/boilerplate/_lib/subscriber-propose-update
@@ -25,7 +25,7 @@ Quirks and Limitations:
 - Is still slightly interactive, because 'gh pr create' likes to ask
   questions about your origin and upstream.
 EOF
-    exit -1
+    exit 1
 }
 
 source $REPO_ROOT/boilerplate/_lib/subscriber.sh
@@ -34,47 +34,101 @@ source $REPO_ROOT/boilerplate/_lib/subscriber.sh
 [[ $# -eq 0 ]] && usage
 
 TMPD=$(mktemp -d)
+echo $TMPD;
 trap "rm -fr $TMPD" EXIT
 
+run_step() {
+    local title=$1
+    local log_file="$TMPD/$title.log"
+    log_file=$(tr '[:upper:]' '[:lower:]' <<< "$log_file")
+    log_file=$(tr ' ' '-' <<< "$log_file")
+    shift
+
+    if [[ $1 != "--" ]]; then
+        echo "ERR: expected '--' but got '$1'"
+        exit 1
+    fi
+    shift
+    echo -n "$title...  "
+
+    if ! "$@" > "$log_file" 2>&1; then
+        echo " FAILED"
+        echo "!!!"
+        echo "!!! Boilerplate update failed for $subscriber"
+        echo "!!!"
+        echo ""
+        cat "$log_file"
+        exit 1
+    fi
+    echo " DONE"
+}
+
+sync_main() {
+    local main_branch=$1
+    shift
+
+    git pull upstream $main_branch
+    git push origin $main_branch
+}
+
+git_clean_and_push() {
+    local branch=$1
+    shift
+
+    git push --delete origin $branch || true
+    git push -u origin $branch
+}
+
 propose_update() {
     local subscriber=$1
     local proj=${subscriber#*/}
 
-    if [[ -z "$DRY_RUN" ]]; then
-        echo "DRY RUN: Would propose update for $subscriber"
-        return 0
-    fi
-
     (
         # Clone my fork of the subscriber repo
         cd $TMPD
         # This
         # - uses the existing fork if one exists
         # - sets 'origin' and 'upstream' remotes
-        gh repo fork $subscriber --clone=true --remote=true
+        # only clones the default branch to save disk space and time
+
+        run_step "Creating fork" -- gh repo fork $subscriber --clone=true --default-branch-only
         cd $proj
 
-        # Current branch is 'master' or 'main'
-        cur_branch=$(current_branch .)
-        # Make sure our origin is synced with upstream, so our update
-        # commit is based off of the latest code.
-        # WARNING: This changes your fork!
-        git pull upstream $cur_branch
-        git push origin $cur_branch
-
-        # Create the update commit
-        make boilerplate-update
-        make boilerplate-commit
-
-        # And create the PR
-        # TODO: This is interactive. How do we tell gh "Yes, please use
-        # upstream as upstream and origin as origin?"
-        gh pr create -f
+        # Current branch is 'master' or 'main' or 'trunk'
+        main_branch=$(current_branch .)
+        run_step "Syncing Fork" -- sync_main $main_branch
+        # run_step "Pushing fork" -- git push origin $main_branch
+
+        # Create the update commit - only cat logs if something goes wrong.
+        run_step "Updating boilerplate" -- make boilerplate-update
+        run_step "Committing boilerplate update" -- make boilerplate-commit
+
+        boilerplate_branch=$(git rev-parse --abbrev-ref HEAD)
+        # By pushing to the origin boilerplate branch explicitly before opening a PR,
+        # we make don't get prompted for the branch to push to.
+        # If we still find that it's giving us an interactive prompt, we can otherwise
+        # use `gh api` to create the PR programmatically.
+        if [[ "$boilerplate_branch" == "$main_branch" ]]; then
+            echo "CRITICAL ERROR: boilerplate branch '$boilerplate_branch' is the same as main branch '$main_branch'"
+            echo "If you see this, something has gone terribly wrong"
+            echo "Skipping"
+            exit 20
+        fi
+        run_step "pushing update" -- git_clean_and_push $boilerplate_branch
+
+        gh pr create --repo $subscriber -f $DRY_RUN_FLAG
     )
 }
 
 bp_master=$(git rev-parse master)
 
+DRY_RUN_FLAG=""
+if [[ -z "$DRY_RUN" ]]; then
+    echo "DRY RUN: ENABLED"
+    DRY_RUN_FLAG="--dry-run"
+fi
+
+
 for subscriber in $(subscriber_args "$@"); do
 
     # Does this one need an update?
@@ -89,14 +143,45 @@ for subscriber in $(subscriber_args "$@"); do
         continue
     fi
 
-    # Is there already a PR proposed for this level?
-    existing_pr=$(gh pr list --repo $subscriber | grep -P ":boilerplate-\S+-$bp_master\s")
+    # Is there already a PR proposed for this commit?
+    pr_list=$(gh pr list --repo $subscriber --json headRefName,url,number | jq -r '. | map(select(.headRefName | startswith("boilerplate-update--")))')
+    existing_pr=$(jq -r ".[] | select(.headRefName == \"boilerplate-update--$bp_master\")" <<< "$pr_list")
     if [[ -n "$existing_pr" ]]; then
-        echo "Subscriber '$subscriber' already has an open PR:"
-        echo "https://github.com/$subscriber/pull/$existing_pr"
+        echo "Subscriber '$subscriber' already has an open PR for this boilerplate commit:"
+        jq -r .url <<< "$existing_pr"
         continue
     fi
 
     # Pull the trigger
-    propose_update "$subscriber"
+    if ! propose_update "$subscriber"; then
+        echo "Error: failed to propose update for '$subscriber'"
+        continue
+    fi
+
+    new_pr="XXXX"
+    # Get the new PR URL
+    # only run if not dry-run - otherwise the new_pr var will be empty
+    if [[ -n $DRY_RUN ]]; then
+        new_pr=$(gh pr list --repo $subscriber --json headRefName,number | jq -r ".[] | select(.headRefName == \"boilerplate-update--$bp_master\") | .number")
+        if [[ -z "$new_pr" ]]; then
+            echo "error: unable to find new PR for boilerplate update '$bp_master' on subscriber '$subscriber'"
+            continue
+        fi
+    fi
+
+    # Add comments to existing PRs to say they're superseded by this new one
+    if [[ -n "$pr_list" ]]; then
+        prs=$(jq -r '. | map(.number) | @tsv' <<< "$pr_list")
+        echo "Closing old PRs: $prs"
+        for pr in $prs; do
+            if [[ -z $DRY_RUN ]]; then
+                echo "Dry run - would close $pr with comment:"
+                echo "  \"Superseded by #$new_pr.\""
+                continue
+            fi
+
+            gh pr close --repo $subscriber --comment "Superseded by #$new_pr." $pr
+        done
+    fi
+
 done
diff --git a/boilerplate/openshift/golang-osd-operator/OWNERS_ALIASES b/boilerplate/openshift/golang-osd-operator/OWNERS_ALIASES
index 7fddbfa2..12676f65 100644
--- a/boilerplate/openshift/golang-osd-operator/OWNERS_ALIASES
+++ b/boilerplate/openshift/golang-osd-operator/OWNERS_ALIASES
@@ -81,7 +81,6 @@ aliases:
     - ravitri
   srep-team-leads:
     - rafael-azevedo
-    - iamkirkbater
     - dustman9000
     - bmeng
     - typeid
diff --git a/boilerplate/openshift/golang-osd-operator/dependabot.yml b/boilerplate/openshift/golang-osd-operator/dependabot.yml
index 45e5fe35..eae3de41 100644
--- a/boilerplate/openshift/golang-osd-operator/dependabot.yml
+++ b/boilerplate/openshift/golang-osd-operator/dependabot.yml
@@ -5,8 +5,13 @@ updates:
     labels:
       - "area/dependency"
       - "ok-to-test"
+      - "lgtm"
+      - "approved"
     schedule:
       interval: "weekly"
+      day: "monday"
+      time: "03:00"
+      timezone: "UTC"
     ignore:
       - dependency-name: "redhat-services-prod/openshift/boilerplate"
         # don't upgrade boilerplate via these means
