diff --git a/playbooks/tox-docs/publish.yaml b/playbooks/tox-docs/publish.yaml
new file mode 100644
index 0000000..9493a50
--- /dev/null
+++ b/playbooks/tox-docs/publish.yaml
@@ -0,0 +1,26 @@
+- hosts: localhost
+  tasks:
+    - name: Write branch marker text
+      copy:
+        dest: "{{ zuul.executor.log_root }}/docs/.root-marker"
+        content: "Project: {{ zuul.project.name }} Branch: {{ zuul.branch }} Build: {{ zuul.build }} Revision: {{ zuul.ref }}"
+    - name: Set publication directory to tag
+      when: "zuul.tag is defined"
+      set_fact:
+        publication_dir: "{{ zuul.tag }}"
+    - name: Get an AFS token
+      include_role:
+        name: create-afs-token
+    - name: Create publication directory
+      file:
+        path: "/afs/.openstack.org/project/opendev.org/docs/{{ zuul.project.name }}/"
+        state: directory
+    - name: Upload to AFS
+      include_role:
+        name: upload-afs
+      vars:
+        afs_source: "{{ zuul.executor.log_root }}/docs/"
+        afs_target: "/afs/.openstack.org/project/opendev.org/docs/{{ zuul.project.name }}/{{ publication_dir }}"
+    - name: Destroy AFS token
+      include_role:
+        name: destroy-afs-token
diff --git a/zuul.yaml b/zuul.yaml
index 8914f41..0e4d0bc 100644
--- a/zuul.yaml
+++ b/zuul.yaml
@@ -253,10 +253,26 @@
     post-run: playbooks/tox-docs/post.yaml
     success-url: docs/
 
+- job:
+    name: opendev-publish-tox-docs
+    parent: opendev-tox-docs
+    description: |
+      Publish a ref-based documentation build.
+
+      Use this in the tag or release pipelines to publish a build
+      based on a newly-created tag.
+    post-run: playbooks/tox-docs/publish.yaml
+    secrets:
+      - secret: opendev-zuul-docs
+        name: afs
+
 - job:
     name: opendev-promote-docs
     description: |
-      Publish a previously built documentation tarball.
+      Publish a previously built branch-tip documentation tarball.
+
+      Use this in the promote pipeline to publish a branch tip tarball
+      built in the gate pipeline.
     run: playbooks/docs/promote.yaml
     nodeset:
       nodes: []