diff --git a/playbooks/charm/lp-recipe-sync.yaml b/playbooks/charm/lp-recipe-sync.yaml
new file mode 100644
index 0000000..a3f8c8d
--- /dev/null
+++ b/playbooks/charm/lp-recipe-sync.yaml
@@ -0,0 +1,3 @@
+- hosts: all
+  roles:
+    - charm-lp-recipe-sync
diff --git a/roles/charm-lp-recipe-sync/defaults/main.yaml b/roles/charm-lp-recipe-sync/defaults/main.yaml
new file mode 100644
index 0000000..0057f2a
--- /dev/null
+++ b/roles/charm-lp-recipe-sync/defaults/main.yaml
@@ -0,0 +1,3 @@
+# allow repos to use a different source to facilitate testing of new features
+# in zosci-tools branches.
+zosci_tools_pkg: "git+https://github.com/freyes/zosci-tools.git#egg=zosci-tools"
diff --git a/roles/charm-lp-recipe-sync/tasks/main.yaml b/roles/charm-lp-recipe-sync/tasks/main.yaml
new file mode 100644
index 0000000..c6f615a
--- /dev/null
+++ b/roles/charm-lp-recipe-sync/tasks/main.yaml
@@ -0,0 +1,20 @@
+- name: Sync LP charm recipe definition
+  environment:
+    LP_CREDENTIALS: "{{ launchpad_token.value }}"
+  block:
+    - name: Install zosci-tools
+      become: true
+      ansible.builtin.pip:
+        name: "{{ zosci_tools_pkg }}"
+      register: result
+      until: result is not failed
+      retries: 10
+      delay: 10
+    - name: Run zosci-lp-recipe sync
+      args:
+        executable: /bin/bash
+        chdir: "{{ zuul.project.src_dir }}"
+      shell: |
+        export LP_CREDENTIALS_FILE=$(mktemp)
+        echo "{{ LP_CREDENTIALS }}" | base64 -d > $LP_CREDENTIALS_FILE
+        zosci-lp-recipe sync --i-really-mean-it
diff --git a/zuul.d/jobs.yaml b/zuul.d/jobs.yaml
index 8ff78a8..5a87468 100644
--- a/zuul.d/jobs.yaml
+++ b/zuul.d/jobs.yaml
@@ -781,6 +781,7 @@
       nodes:
         - name: focal-medium
           label: focal-medium
+
 - job:
     name: sqa-integration
     description: Sets up a sqalab connection for this test environment
@@ -789,3 +790,20 @@
     abstract: true
     secrets:
       - sqalab_environment
+
+- job:
+    name: charm-lp-recipe-sync
+    description: |
+      Run `zosci-lp-recipe sync` to update the recipe's definition on
+      Launchpad.
+    timeout: 3600
+    parent: tox
+    provides: charm
+    post-review: true
+    run: playbooks/charm/lp-recipe-sync.yaml
+    nodeset:
+      nodes:
+        - name: focal-medium
+          label: focal-medium
+    secrets:
+      - launchpad_token
diff --git a/zuul.d/project-templates.yaml b/zuul.d/project-templates.yaml
index 3309d9e..195a865 100644
--- a/zuul.d/project-templates.yaml
+++ b/zuul.d/project-templates.yaml
@@ -253,6 +253,9 @@
         # NOTE(icey) BUT REALLY, DO NOT ENABLE THE FOLLOWING UNTIL YOU KNOW WE CAN
         # RUN A 3.10 JOB ON ZOSCI.
         #- tox-py310
+    promote:
+      jobs:
+        - charm-lp-recipe-sync
 - project-template:
     name: charm-publish-jobs
     description: |
diff --git a/zuul.d/secrets.yaml b/zuul.d/secrets.yaml
index 8b01474..ba2d046 100644
--- a/zuul.d/secrets.yaml
+++ b/zuul.d/secrets.yaml
@@ -191,3 +191,18 @@
         username: ZuulBot
         uuid: 0c00c563-7e9e-40ab-8db6-738d81aa1ce5
         weebl_url: http://10.131.231.53:8080
+
+- secret:
+    name: launchpad_token
+    data:
+      value: !encrypted/pkcs1-oaep
+        - b7n/+cqF8DjRe0jWaNGUDmo2kFJWiHgBqKkwdVHyxzi5CJWhIPKGcK8tK5l7MGXGnrzzT
+          3H8b2SdyM9jDihjbnRDEDP9u3hmd3DTYkabv1R2eERVkNZisUoI6/9XZ3V2hWShaqa4cc
+          Bq2nq0fCnByY3c8VZUIk7gScYz88xQlmpj9xU8u2AVm6NmFrrkaHn0uCFDAMdAKGwDBvs
+          nP2UVq8ObmnIsuAPWReK04oqHu5UhVyt1Ts3OvbkPatk840Azgo0GOO35t67fy2wiZHy2
+          0w643dDfvpgYbV7f0xE+5Nuq1jneCQ7ax4E/2dZxuNMnunOAGAeK+kKIwIeZtdTIMU0WO
+          n/eI5IHu/h1JIH+UnN66wccxaezC/hZmVGwoWlCiyAU/s891CUINtK8uqVtsDftSgeDKe
+          7QMYFyeo2yloOpKZlZ8khJUOePonLMGr/AiX5NU/etg7RFTnRFeLg+CfmBV2ZgQ2da/mg
+          5rIe0o95jc054HfMT7z54rd/OB0SDig+WheJP9s/KFJb/h5T2Lmrie5YB/7ZQHQAt9S+z
+          RbsZ2vi+pUuQDEE8j6M9bTlhtnDcTHYz/JOwq33Lyso3vCMS/icGVHZH10Pp4edACRtcK
+          GGosoONbOzXtrRvFHatJVIJuv0tQhzL+r3awoCLN+JqOU3hjuNCy7pVdW7/sCQ=