Recent changes to this wiki:

link
diff --git a/doc/no_llm_code.mdwn b/doc/no_llm_code.mdwn
index 1cc0fdd426..66d9ce7a62 100644
--- a/doc/no_llm_code.mdwn
+++ b/doc/no_llm_code.mdwn
@@ -1,6 +1,7 @@
-LLM generated code in free software is a potential landmine. The copyright
-of such code is an open question, and any current answer to that question
-risks changing at some point in the future.
+[LLM](https://en.wikipedia.org/wiki/Large_language_model) generated code in
+free software is a potential landmine. The copyright of such code is an
+open question, and any current answer to that question risks changing at
+some point in the future.
 
 This is a particular problem for git-annex since [[future proofing]] is an
 important aspect of its design.

typo
diff --git a/doc/no_llm_code.mdwn b/doc/no_llm_code.mdwn
index 2d3d53caea..1cc0fdd426 100644
--- a/doc/no_llm_code.mdwn
+++ b/doc/no_llm_code.mdwn
@@ -13,7 +13,7 @@ guarantees. Although it would be very much appreciated if they did.
 
 git-annex currently supports being built with versions of
 dependencies that pre-date any introduction of LLM generated code.
-To do do, turn on the `NoLLMDependencies` build flag.
+To do so, turn on the `NoLLMDependencies` build flag.
 When building with stack, use `stack-NoLLMDependencies.yaml`.
 (It is not currently built that way by default, but such builds are welcome.)
 

Added stack-NoLLMDependencies.yaml
diff --git a/CHANGELOG b/CHANGELOG
index c3e93c2e0a..70b97f13d3 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -5,6 +5,7 @@ git-annex (10.20260625) UNRELEASED; urgency=medium
     that predate the addition of any LLM generated code.
     See https://git-annex.branchable.com/no_llm_code/
   * git-annex.cabal: Added NoLLMDependencies build flag.
+  * Added stack-NoLLMDependencies.yaml
   * Fix build with time-1.15.
 
  -- Joey Hess <id@joeyh.name>  Wed, 01 Jul 2026 14:12:59 -0400
diff --git a/doc/no_llm_code.mdwn b/doc/no_llm_code.mdwn
index 31bf0fff9a..2d3d53caea 100644
--- a/doc/no_llm_code.mdwn
+++ b/doc/no_llm_code.mdwn
@@ -14,6 +14,7 @@ guarantees. Although it would be very much appreciated if they did.
 git-annex currently supports being built with versions of
 dependencies that pre-date any introduction of LLM generated code.
 To do do, turn on the `NoLLMDependencies` build flag.
+When building with stack, use `stack-NoLLMDependencies.yaml`.
 (It is not currently built that way by default, but such builds are welcome.)
 
 Unfortunately, it's not possible to guarantee that will continue to work
diff --git a/git-annex.cabal b/git-annex.cabal
index 1a010768e1..6a920de2e0 100644
--- a/git-annex.cabal
+++ b/git-annex.cabal
@@ -36,6 +36,7 @@ Description:
 Extra-Source-Files:
   stack.yaml
   stack-botan.yaml
+  stack-NoLLMDependencies.yaml
   README
   CHANGELOG
   NEWS
diff --git a/stack-NoLLMDependencies.yaml b/stack-NoLLMDependencies.yaml
new file mode 100644
index 0000000000..3fcb296182
--- /dev/null
+++ b/stack-NoLLMDependencies.yaml
@@ -0,0 +1,30 @@
+flags:
+  git-annex:
+    NoLLMDependencies: true
+    production: true
+    parallelbuild: true
+    assistant: true
+    torrentparser: true
+    magicmime: false
+    dbus: false
+    debuglocks: false
+    benchmark: true
+    ospath: true
+    botan: false
+    blake3: true
+    xxh3: true
+  file-io:
+    os-string: true
+  xxhash-ffi:
+    pkg-config: false
+packages:
+- '.'
+resolver: lts-24.26
+extra-deps:
+- aws-0.25.2
+- file-io-0.2.0
+- blake3-0.3
+- xxhash-ffi-0.3.1
+- ram-0.20.1
+- persistent-2.14.6.3
+- persistent-sqlite-2.13.3.0

update
diff --git a/doc/no_llm_code.mdwn b/doc/no_llm_code.mdwn
index b3b0717e41..31bf0fff9a 100644
--- a/doc/no_llm_code.mdwn
+++ b/doc/no_llm_code.mdwn
@@ -18,11 +18,13 @@ To do do, turn on the `NoLLMDependencies` build flag.
 
 Unfortunately, it's not possible to guarantee that will continue to work
 in new versions of git-annex. That's the goal, but it may become
-untenable. It's already the case that building git-annex with the older
-versions of dependencies leaves at least one security hole in a dependency
-open. See below for details about this and other possible future problems
+untenable. See below for details about possible future problems
 with specific dependencies.
 
+Note that if a security hole is only fixed by a newer version of a
+dependency, the `NoLLMDependencies` build flag will still build with the
+older, insecure version.
+
 Additional work needs to be done on an ongoing basis to review
 git-annex's dependencies to detect the addition of LLM generated code.
 

correction
diff --git a/doc/no_llm_code.mdwn b/doc/no_llm_code.mdwn
index e0ed75f24e..b3b0717e41 100644
--- a/doc/no_llm_code.mdwn
+++ b/doc/no_llm_code.mdwn
@@ -56,9 +56,7 @@ with apparently broken (how?) changes in 0.21.0 being reverted in
 0.21.1.
 
 Rather than use ram, git-annex continues to use the unmaintained
-[memory](//hackage.haskell.org/package/memory). 
-Since git-annex's use of this package is fairly incidental, this
-dependency could be removed if it becomes a problem.
+[memory](//hackage.haskell.org/package/memory) that ram was forked from.
 
 But ram is an dependency of other dependencies, and these in particular
 depend on 0.21.0 or newer:

simplify NoLLMDependencies by depending on older version of ram
That prevents cabal from picking dependencies that need a newer version
of ram which contains LLM generated code.
Note that git-annex still depends on memory. And so all imports from
memory need to be PackageImports qualified now.
It would be easier if git-annex could use the old version of ram.
The problem is that it needs the ByteArrayAccess instance for Digest.
When crypton switched to ram, it depended immediately on the newer
version. So there is no available instance for git-annex to use.
diff --git a/Annex/Balanced.hs b/Annex/Balanced.hs
index 394cb56e00..9005440ad6 100644
--- a/Annex/Balanced.hs
+++ b/Annex/Balanced.hs
@@ -5,6 +5,8 @@
  - Licensed under the GNU AGPL version 3 or higher.
  -}
 
+{-# LANGUAGE PackageImports #-}
+
 module Annex.Balanced where
 
 import Key
@@ -15,7 +17,7 @@ import Data.Maybe
 import qualified Data.List as L
 import Data.Bits (shiftL)
 import qualified Data.Set as S
-import qualified Data.ByteArray as BA
+import qualified "memory" Data.ByteArray as BA
 
 -- The Int is how many UUIDs to pick.
 type BalancedPicker = S.Set UUID -> Key -> Int -> [UUID]
diff --git a/Annex/DirHashes.hs b/Annex/DirHashes.hs
index 21756dea37..e2fb08d5e8 100644
--- a/Annex/DirHashes.hs
+++ b/Annex/DirHashes.hs
@@ -5,6 +5,8 @@
  - Licensed under the GNU AGPL version 3 or higher.
  -}
 
+{-# LANGUAGE PackageImports #-}
+
 module Annex.DirHashes (
 	Hasher,
 	HashLevels(..),
@@ -20,7 +22,7 @@ module Annex.DirHashes (
 import Data.Default
 import Data.Bits
 import qualified Data.List.NonEmpty as NE
-import qualified Data.ByteArray as BA
+import qualified "memory" Data.ByteArray as BA
 import qualified Data.ByteString as S
 
 import Common
diff --git a/Annex/Import.hs b/Annex/Import.hs
index 67b845ddd5..170bf4aeeb 100644
--- a/Annex/Import.hs
+++ b/Annex/Import.hs
@@ -6,6 +6,7 @@
  -}
 
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE PackageImports #-}
 {-# LANGUAGE CPP #-}
 
 module Annex.Import (
@@ -71,7 +72,7 @@ import Backend.Utilities
 import Control.Concurrent.STM
 import qualified Data.Map.Strict as M
 import qualified Data.Set as S
-import qualified Data.ByteArray.Encoding as BA
+import qualified "memory" Data.ByteArray.Encoding as BA
 #ifdef mingw32_HOST_OS
 import qualified System.FilePath.Posix as Posix
 #endif
diff --git a/Utility/AuthToken.hs b/Utility/AuthToken.hs
index 4f94c984a1..46a7c4a7b6 100644
--- a/Utility/AuthToken.hs
+++ b/Utility/AuthToken.hs
@@ -25,7 +25,7 @@ import Utility.Exception
 
 import Data.Maybe
 import Data.Char
-import qualified Data.ByteArray as BA
+import qualified "memory" Data.ByteArray as BA
 import qualified Data.Text as T
 import qualified Data.Text.Encoding as TE
 import qualified Data.ByteString.Lazy as L
diff --git a/Utility/Hash/Crypton.hs b/Utility/Hash/Crypton.hs
index bb49a7a2bc..4d290d0150 100644
--- a/Utility/Hash/Crypton.hs
+++ b/Utility/Hash/Crypton.hs
@@ -69,7 +69,7 @@ module Utility.Hash.Crypton (
 import qualified Data.ByteString as S
 import qualified Data.ByteString.Lazy as L
 import Data.IORef
-import qualified Data.ByteArray as BA
+import qualified "memory" Data.ByteArray as BA
 import "crypton" Crypto.Hash
 
 import Utility.Hash.Types
diff --git a/Utility/Hash/Types.hs b/Utility/Hash/Types.hs
index acc3ef97e7..9705876013 100644
--- a/Utility/Hash/Types.hs
+++ b/Utility/Hash/Types.hs
@@ -6,12 +6,13 @@
  -}
 
 {-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE PackageImports #-}
 
 module Utility.Hash.Types where
 
 import qualified Data.ByteString as S
-import Data.ByteArray
-import qualified Data.ByteArray.Encoding as BAE
+import "memory" Data.ByteArray
+import qualified "memory" Data.ByteArray.Encoding as BAE
 import Data.String
 import Control.DeepSeq
 import GHC.Generics
diff --git a/Utility/IPAddress.hs b/Utility/IPAddress.hs
index e19cecac1d..cde446b642 100644
--- a/Utility/IPAddress.hs
+++ b/Utility/IPAddress.hs
@@ -6,6 +6,7 @@
  -}
 
 {-# LANGUAGE BinaryLiterals #-}
+{-# LANGUAGE PackageImports #-}
 
 -- Note that some extensions are necessary for reasons outlined in
 -- my July 2021 blog post. -- JEH
@@ -21,7 +22,7 @@ import Utility.Exception
 
 import Network.Socket
 import Data.Word
-import Data.Memory.Endian
+import "memory" Data.Memory.Endian
 import Data.List
 import Text.Printf
 
diff --git a/doc/no_llm_code.mdwn b/doc/no_llm_code.mdwn
index 258b1d0337..e0ed75f24e 100644
--- a/doc/no_llm_code.mdwn
+++ b/doc/no_llm_code.mdwn
@@ -55,23 +55,22 @@ Note particularly [large LLM generated code churn](https://github.com/jappeace/r
 with apparently broken (how?) changes in 0.21.0 being reverted in
 0.21.1.
 
-Rather than depend on ram, git-annex continues to depend on the unmaintained
+Rather than use ram, git-annex continues to use the unmaintained
 [memory](//hackage.haskell.org/package/memory). 
 Since git-annex's use of this package is fairly incidental, this
 dependency could be removed if it becomes a problem.
 
-But ram is an dependency of other dependencies:
+But ram is an dependency of other dependencies, and these in particular
+depend on 0.21.0 or newer:
 
 * crypton since 1.1.0
-* crypton-x509-validation since 1.9.0. Note that 1.9.1 fixes a security
-  hole, [CVE-2026-9648](https://www.cve.org/CVERecord?id=CVE-2026-9648).
-  This security hole is not expected to affect many git-annex users.
-* aws since 0.25.3 (needed to get the CVE-2026-9648 fix)
-* tls since 2.3.0
-* blake3 since 0.3.1 (optional git-annex dependency)
+* tls since 2.3.1
 
 [Reverse dependencies of ram](https://packdeps.haskellers.com/reverse/ram)
 
+The `NoLLMDependencies` build flag depends on an older version of ram
+in order to prevent such dependencies using the newer version.
+
 ### persistent
 
 [persistent](https://hackage.haskell.org/package/persistent) since 2.15.0.0
diff --git a/git-annex.cabal b/git-annex.cabal
index d627e0f14c..1a010768e1 100644
--- a/git-annex.cabal
+++ b/git-annex.cabal
@@ -292,8 +292,11 @@ Executable git-annex
    servant-client-core,
    warp (>= 3.2.8),
    warp-tls (>= 3.2.2),
+   crypton,
    crypton-connection (>= 0.4.3),
-   crypton-x509-store
+   crypton-x509-store,
+   tls,
+   aws (>= 0.24.1)
   CC-Options: -Wall
   GHC-Options: -Wall -fno-warn-tabs  -Wincomplete-uni-patterns
   Default-Language: Haskell2010
@@ -305,17 +308,11 @@ Executable git-annex
   if flag(NoLLMDependencies)
     Build-Depends:
      base (>= 4.18.2.1 && < 4.23),
-     crypton (< 1.1.0),
-     crypton-x509-validation (< 1.9.0),
-     aws (>= 0.24.1) && (< 2.25.3),
-     tls (< 2.3.0),
+     ram (< 0.21.0),
      persistent (>= 2.13.3) && (< 2.15.0.0)
   else
     Build-Depends:
      base (>= 4.18.2.1 && < 5),
-     crypton,
-     aws (>= 0.24.1),
-     tls,

(Diff truncated)
update
diff --git a/doc/no_llm_code.mdwn b/doc/no_llm_code.mdwn
index a11f18e350..258b1d0337 100644
--- a/doc/no_llm_code.mdwn
+++ b/doc/no_llm_code.mdwn
@@ -20,11 +20,11 @@ Unfortunately, it's not possible to guarantee that will continue to work
 in new versions of git-annex. That's the goal, but it may become
 untenable. It's already the case that building git-annex with the older
 versions of dependencies leaves at least one security hole in a dependency
-open.
+open. See below for details about this and other possible future problems
+with specific dependencies.
 
-This means that additional work needs to be done to review git-annex's
-dependencies on an ongoing basis to detect the addition of LLM generated
-code.
+Additional work needs to be done on an ongoing basis to review
+git-annex's dependencies to detect the addition of LLM generated code.
 
 Help with finding these is welcome. Please edit this page and/or file
 bug reports on git-annex if it cannot be built without LLM generated code.
@@ -63,8 +63,9 @@ dependency could be removed if it becomes a problem.
 But ram is an dependency of other dependencies:
 
 * crypton since 1.1.0
-* crypton-x509-validation since 1.9.0. Note that 1.9.1 fixes 
-  [CVE-2026-9648](https://www.cve.org/CVERecord?id=CVE-2026-9648).
+* crypton-x509-validation since 1.9.0. Note that 1.9.1 fixes a security
+  hole, [CVE-2026-9648](https://www.cve.org/CVERecord?id=CVE-2026-9648).
+  This security hole is not expected to affect many git-annex users.
 * aws since 0.25.3 (needed to get the CVE-2026-9648 fix)
 * tls since 2.3.0
 * blake3 since 0.3.1 (optional git-annex dependency)

git-annex.cabal: Added NoLLMDependencies build flag
diff --git a/CHANGELOG b/CHANGELOG
index 2f70663abc..c3e93c2e0a 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -4,6 +4,7 @@ git-annex (10.20260625) UNRELEASED; urgency=medium
     and will attempt to remain buildable with versions of dependencies
     that predate the addition of any LLM generated code.
     See https://git-annex.branchable.com/no_llm_code/
+  * git-annex.cabal: Added NoLLMDependencies build flag.
   * Fix build with time-1.15.
 
  -- Joey Hess <id@joeyh.name>  Wed, 01 Jul 2026 14:12:59 -0400
diff --git a/doc/no_llm_code.mdwn b/doc/no_llm_code.mdwn
index a8aa82ec71..a11f18e350 100644
--- a/doc/no_llm_code.mdwn
+++ b/doc/no_llm_code.mdwn
@@ -13,14 +13,18 @@ guarantees. Although it would be very much appreciated if they did.
 
 git-annex currently supports being built with versions of
 dependencies that pre-date any introduction of LLM generated code.
-(It is not currently built that way by default but such builds are welcome.)
-Unfortunately, it's not possible to guarantee that will continue to be the
-case in new versions of git-annex. That's the goal, but it may become
-untenable.
-
-Unfortunately, this means that additional work needs to be done to review
-git-annex's dependencies on an ongoing basis to detect the addition of LLM
-generated code.
+To do do, turn on the `NoLLMDependencies` build flag.
+(It is not currently built that way by default, but such builds are welcome.)
+
+Unfortunately, it's not possible to guarantee that will continue to work
+in new versions of git-annex. That's the goal, but it may become
+untenable. It's already the case that building git-annex with the older
+versions of dependencies leaves at least one security hole in a dependency
+open.
+
+This means that additional work needs to be done to review git-annex's
+dependencies on an ongoing basis to detect the addition of LLM generated
+code.
 
 Help with finding these is welcome. Please edit this page and/or file
 bug reports on git-annex if it cannot be built without LLM generated code.
diff --git a/git-annex.cabal b/git-annex.cabal
index 2fef9ae934..d627e0f14c 100644
--- a/git-annex.cabal
+++ b/git-annex.cabal
@@ -146,6 +146,12 @@ Extra-Source-Files:
   templates/notifications/longpolling.julius
   Utility/libkqueue.h
 
+Flag NoLLMDependencies
+  Description: Avoid building with versions of dependencies that contain 
+    LLM generated code <https://git-annex.branchable.com/no_llm_code/>
+  Default: False
+  Manual: True
+
 Flag Assistant
   Description: Enable git-annex assistant, webapp, and watch command
   Default: True
@@ -213,7 +219,6 @@ custom-setup
 Executable git-annex
   Main-Is: git-annex.hs
   Build-Depends:
-   base (>= 4.18.2.1 && < 5),
    network-uri (>= 2.6),
    optparse-applicative (>= 0.14.2),
    containers (>= 0.5.8),
@@ -252,7 +257,6 @@ Executable git-annex
    conduit,
    time (>= 1.9.1),
    persistent-sqlite (>= 2.13.3),
-   persistent (>= 2.13.3),
    persistent-template (>= 2.8.0),
    unliftio-core,
    microlens,
@@ -277,22 +281,19 @@ Executable git-annex
    tasty-quickcheck,
    tasty-rerun,
    ansi-terminal >= 0.9,
-   aws (>= 0.24.1),
    DAV (>= 1.0),
    network (>= 3.0.0.0),
    network-bsd,
    git-lfs (>= 1.2.0),
    clock (>= 0.3.0),
-   crypton,
-   crypton-connection (>= 0.4.3),
-   crypton-x509-store,
-   tls,
    servant,
    servant-server,
    servant-client,
    servant-client-core,
    warp (>= 3.2.8),
-   warp-tls (>= 3.2.2)
+   warp-tls (>= 3.2.2),
+   crypton-connection (>= 0.4.3),
+   crypton-x509-store
   CC-Options: -Wall
   GHC-Options: -Wall -fno-warn-tabs  -Wincomplete-uni-patterns
   Default-Language: Haskell2010
@@ -300,6 +301,22 @@ Executable git-annex
   Other-Extensions: TemplateHaskell
   -- Some things don't work with the non-threaded RTS.
   GHC-Options: -threaded
+   
+  if flag(NoLLMDependencies)
+    Build-Depends:
+     base (>= 4.18.2.1 && < 4.23),
+     crypton (< 1.1.0),
+     crypton-x509-validation (< 1.9.0),
+     aws (>= 0.24.1) && (< 2.25.3),
+     tls (< 2.3.0),
+     persistent (>= 2.13.3) && (< 2.15.0.0)
+  else
+    Build-Depends:
+     base (>= 4.18.2.1 && < 5),
+     crypton,
+     aws (>= 0.24.1),
+     tls,
+     persistent (>= 2.13.3)
 
   -- Fully optimize for production.
   if flag(Production)
@@ -340,7 +357,10 @@ Executable git-annex
   -- Disabled on arm until this issue is resolved:
   -- https://github.com/k0001/hs-blake3/issues/8
   if flag(Blake3) && (! arch(aarch64) && ! arch(arm))
-    Build-Depends: blake3 (>= 0.3)
+    if flag(NoLLMDependencies)
+      Build-Depends: blake3 (>= 0.3) && (< 0.3.1)
+    else
+      Build-Depends: blake3 (>= 0.3)
     CPP-Options: -DWITH_BLAKE3
     Other-Modules:
       Utility.Hash.Blake3
@@ -366,10 +386,6 @@ Executable git-annex
     CPP-Options: -DWITH_ASSISTANT -DWITH_WEBAPP
     Build-Depends:
       mountpoints,
-      yesod (>= 1.4.3), 
-      yesod-static (>= 1.5.1),
-      yesod-form (>= 1.4.8),
-      yesod-core (>= 1.6.0),
       path-pieces (>= 0.2.1),
       wai,
       wai-extra,
@@ -377,6 +393,18 @@ Executable git-annex
       clientsession,
       template-haskell,
       shakespeare (>= 2.0.11)
+    if flag(NoLLMDependencies)
+      Build-Depends:
+        yesod (>= 1.4.3) && (< 1.7.0.0), 
+        yesod-static (>= 1.5.1) && (<1.6.1.3),
+        yesod-form (>= 1.4.8) && (< 1.7.9.3),
+        yesod-core (>= 1.6.0) && (< 1.7.0.0)
+    else
+      Build-Depends:
+        yesod (>= 1.4.3), 
+        yesod-static (>= 1.5.1),
+        yesod-form (>= 1.4.8),
+        yesod-core (>= 1.6.0)
     Other-Modules:
       Assistant
       Assistant.Alert
diff --git a/stack-botan.yaml b/stack-botan.yaml
index d3e6d2987a..dfa29f07b1 100644
--- a/stack-botan.yaml
+++ b/stack-botan.yaml
@@ -1,5 +1,6 @@
 flags:
   git-annex:
+    NoLLMDependencies: false
     production: true
     parallelbuild: true
     assistant: true
diff --git a/stack.yaml b/stack.yaml
index 6399b77762..323e2aa300 100644
--- a/stack.yaml
+++ b/stack.yaml
@@ -1,5 +1,6 @@
 flags:
   git-annex:
+    NoLLMDependencies: false
     production: true
     parallelbuild: true
     assistant: true

toc
diff --git a/doc/no_llm_code.mdwn b/doc/no_llm_code.mdwn
index 6da9209c58..a8aa82ec71 100644
--- a/doc/no_llm_code.mdwn
+++ b/doc/no_llm_code.mdwn
@@ -27,7 +27,9 @@ bug reports on git-annex if it cannot be built without LLM generated code.
 
 ## known dependencies that contain LLM generated code
 
-## ghc
+[[!toc startlevel=3]]
+
+### ghc
 
 [This commit](https://github.com/ghc/ghc/commit/a5ec467ee3d4e77c026437a545981269acde3434)
 is probably the first, and will be released in the upcoming ghc 9.15.
@@ -65,7 +67,7 @@ But ram is an dependency of other dependencies:
 
 [Reverse dependencies of ram](https://packdeps.haskellers.com/reverse/ram)
 
-## persistent
+### persistent
 
 [persistent](https://hackage.haskell.org/package/persistent) since 2.15.0.0
 
@@ -73,7 +75,7 @@ But ram is an dependency of other dependencies:
 
 git-annex supports being built with older versions.
 
-## yesod
+### yesod
 
 [yesod](https://hackage.haskell.org/package/yesod-core) since 1.7.0.0
 
@@ -84,7 +86,7 @@ and 10,000+ lines of changes.
 
 (See [[todo/ditch_yesod]])
 
-## Cabal
+### Cabal
 
 [First LLM generated code](https://github.com/haskell/cabal/commit/da8b314563feb15a3df7bc1baeef4b7aa08f7578)
 

cabal
diff --git a/doc/no_llm_code.mdwn b/doc/no_llm_code.mdwn
index 586d2fb285..6da9209c58 100644
--- a/doc/no_llm_code.mdwn
+++ b/doc/no_llm_code.mdwn
@@ -83,3 +83,11 @@ git-annex supports being built with older versions.
 and 10,000+ lines of changes.
 
 (See [[todo/ditch_yesod]])
+
+## Cabal
+
+[First LLM generated code](https://github.com/haskell/cabal/commit/da8b314563feb15a3df7bc1baeef4b7aa08f7578)
+
+Cabal is needed to build git-annex, but is not linked into it.
+There is a risk that a new version of Cabal could need changes to
+git-annex.cabal that prevent an old version building it.

yesod-core version
diff --git a/doc/no_llm_code.mdwn b/doc/no_llm_code.mdwn
index cffabf62ef..586d2fb285 100644
--- a/doc/no_llm_code.mdwn
+++ b/doc/no_llm_code.mdwn
@@ -75,7 +75,7 @@ git-annex supports being built with older versions.
 
 ## yesod
 
-[yesod](https://hackage.haskell.org/package/yesod), not yet in a released version
+[yesod](https://hackage.haskell.org/package/yesod-core) since 1.7.0.0
 
 [First LLM generated code](https://github.com/yesodweb/yesod/commit/1b033c741ce81d01070de993b285a17e71178156)
 

yesod
diff --git a/doc/no_llm_code.mdwn b/doc/no_llm_code.mdwn
index 1fc22aff29..cffabf62ef 100644
--- a/doc/no_llm_code.mdwn
+++ b/doc/no_llm_code.mdwn
@@ -27,6 +27,20 @@ bug reports on git-annex if it cannot be built without LLM generated code.
 
 ## known dependencies that contain LLM generated code
 
+## ghc
+
+[This commit](https://github.com/ghc/ghc/commit/a5ec467ee3d4e77c026437a545981269acde3434)
+is probably the first, and will be released in the upcoming ghc 9.15.
+
+git-annex remains buildable with older versions of ghc back to 9.6.6.
+
+This will probably prevent git-annex from taking advantage of 
+most new improvements to the Haskell language going forward. 
+That is deeply unfortunate. This is the main reason why git-annex is not
+guaranteed to never change to depend on LLM generated code, because cutting
+it off from all future Haskell language improvements may be worse than the
+alternative.
+
 ### ram and its reverse dependencies
 
 [ram](https://hackage.haskell.org/package/ram) since 0.21.0.
@@ -59,16 +73,13 @@ But ram is an dependency of other dependencies:
 
 git-annex supports being built with older versions.
 
-## ghc
+## yesod
 
-[This commit](https://github.com/ghc/ghc/commit/a5ec467ee3d4e77c026437a545981269acde3434)
-is probably the first, and will be released in the upcoming ghc 9.15.
+[yesod](https://hackage.haskell.org/package/yesod), not yet in a released version
 
-git-annex remains buildable with older versions of ghc back to 9.6.6.
+[First LLM generated code](https://github.com/yesodweb/yesod/commit/1b033c741ce81d01070de993b285a17e71178156)
 
-This will probably prevent git-annex from taking advantage of 
-most new improvements to the Haskell language going forward. 
-That is deeply unfortunate. This is the main reason why git-annex is not
-guaranteed to never change to depend on LLM generated code, because cutting
-it off from all future Haskell language improvements may be worse than the
-alternative.
+[LLM generated commit with a 1489 line commit message](https://github.com/yesodweb/yesod/commit/1ee25122d82f8f94136bf1496a825c6c00b74fcf)
+and 10,000+ lines of changes.
+
+(See [[todo/ditch_yesod]])
diff --git a/doc/todo/ditch_yesod.mdwn b/doc/todo/ditch_yesod.mdwn
index d8ef722ae5..e6c4a4d6e2 100644
--- a/doc/todo/ditch_yesod.mdwn
+++ b/doc/todo/ditch_yesod.mdwn
@@ -14,6 +14,8 @@ reasons:
 * I find that Hamlet does not lend itself to being refactored, everything
   is essentially an IO action with side effects of generating html, so
   can't really bring proper FP tools to bear.
+* Its current maintainer is on the good LLM drugs.
+  <https://github.com/yesodweb/yesod/commit/1ee25122d82f8f94136bf1496a825c6c00b74fcf>
 
 At the moment, servant seems like the nicest place to end up. Just as type
 safe as yesod afaik, and very lightweight and simple and rather awesome.

weaken
diff --git a/doc/no_llm_code.mdwn b/doc/no_llm_code.mdwn
index 5848705677..1fc22aff29 100644
--- a/doc/no_llm_code.mdwn
+++ b/doc/no_llm_code.mdwn
@@ -11,9 +11,12 @@ will never do so.
 However, libraries that git-annex depends on do not generally have such
 guarantees. Although it would be very much appreciated if they did.
 
-So git-annex is also guaranteed to support being built with versions of
+git-annex currently supports being built with versions of
 dependencies that pre-date any introduction of LLM generated code.
 (It is not currently built that way by default but such builds are welcome.)
+Unfortunately, it's not possible to guarantee that will continue to be the
+case in new versions of git-annex. That's the goal, but it may become
+untenable.
 
 Unfortunately, this means that additional work needs to be done to review
 git-annex's dependencies on an ongoing basis to detect the addition of LLM
@@ -65,4 +68,7 @@ git-annex remains buildable with older versions of ghc back to 9.6.6.
 
 This will probably prevent git-annex from taking advantage of 
 most new improvements to the Haskell language going forward. 
-That is deeply unfortunate.
+That is deeply unfortunate. This is the main reason why git-annex is not
+guaranteed to never change to depend on LLM generated code, because cutting
+it off from all future Haskell language improvements may be worse than the
+alternative.

reword
diff --git a/doc/no_llm_code.mdwn b/doc/no_llm_code.mdwn
index c41fd6e185..5848705677 100644
--- a/doc/no_llm_code.mdwn
+++ b/doc/no_llm_code.mdwn
@@ -63,5 +63,6 @@ is probably the first, and will be released in the upcoming ghc 9.15.
 
 git-annex remains buildable with older versions of ghc back to 9.6.6.
 
-It's deeply unfortunate that git-annex will not be able to take advantage
-of any new improvements to the Haskell language going forward.
+This will probably prevent git-annex from taking advantage of 
+most new improvements to the Haskell language going forward. 
+That is deeply unfortunate.

sadness
diff --git a/doc/no_llm_code.mdwn b/doc/no_llm_code.mdwn
index fbc54586cf..c41fd6e185 100644
--- a/doc/no_llm_code.mdwn
+++ b/doc/no_llm_code.mdwn
@@ -62,3 +62,6 @@ git-annex supports being built with older versions.
 is probably the first, and will be released in the upcoming ghc 9.15.
 
 git-annex remains buildable with older versions of ghc back to 9.6.6.
+
+It's deeply unfortunate that git-annex will not be able to take advantage
+of any new improvements to the Haskell language going forward.

ghc 9.15
diff --git a/doc/no_llm_code.mdwn b/doc/no_llm_code.mdwn
index da50b14a47..fbc54586cf 100644
--- a/doc/no_llm_code.mdwn
+++ b/doc/no_llm_code.mdwn
@@ -58,5 +58,7 @@ git-annex supports being built with older versions.
 
 ## ghc
 
-Need to look up the version, but in any case git-annex remains buildable
-with older versions of ghc back to 9.6.6.
+[This commit](https://github.com/ghc/ghc/commit/a5ec467ee3d4e77c026437a545981269acde3434)
+is probably the first, and will be released in the upcoming ghc 9.15.
+
+git-annex remains buildable with older versions of ghc back to 9.6.6.

LLM dependency tracking
diff --git a/CHANGELOG b/CHANGELOG
index b85b0ba223..24f2187984 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,9 @@
 git-annex (10.20260625) UNRELEASED; urgency=medium
 
+  * git-annex is guaranteed to not contain LLM generated code,
+    and to remain buildable with versions of dependencies that
+    predate the addition of any LLM generated code.
+    See https://git-annex.branchable.com/no_llm_code/
   * Fix build with time-1.15.
 
  -- Joey Hess <id@joeyh.name>  Wed, 01 Jul 2026 14:12:59 -0400
diff --git a/doc/future_proofing.mdwn b/doc/future_proofing.mdwn
index 84883d060f..8be7197eb4 100644
--- a/doc/future_proofing.mdwn
+++ b/doc/future_proofing.mdwn
@@ -51,3 +51,5 @@ problem:
   a remote, as long as you have access to the encryption keys (which
   for some types of encryption are stored in the git-annex branch of
   the repository, sometimes encrypted with your gpg key).
+
+* [[No LLM code]]
diff --git a/doc/no_llm_code.mdwn b/doc/no_llm_code.mdwn
new file mode 100644
index 0000000000..da50b14a47
--- /dev/null
+++ b/doc/no_llm_code.mdwn
@@ -0,0 +1,62 @@
+LLM generated code in free software is a potential landmine. The copyright
+of such code is an open question, and any current answer to that question
+risks changing at some point in the future.
+
+This is a particular problem for git-annex since [[future proofing]] is an
+important aspect of its design.
+
+So, git-annex does not contain code generated by LLMs and guarantees it
+will never do so.
+
+However, libraries that git-annex depends on do not generally have such
+guarantees. Although it would be very much appreciated if they did.
+
+So git-annex is also guaranteed to support being built with versions of
+dependencies that pre-date any introduction of LLM generated code.
+(It is not currently built that way by default but such builds are welcome.)
+
+Unfortunately, this means that additional work needs to be done to review
+git-annex's dependencies on an ongoing basis to detect the addition of LLM
+generated code.
+
+Help with finding these is welcome. Please edit this page and/or file
+bug reports on git-annex if it cannot be built without LLM generated code.
+
+## known dependencies that contain LLM generated code
+
+### ram and its reverse dependencies
+
+[ram](https://hackage.haskell.org/package/ram) since 0.21.0.
+  
+Note particularly [large LLM generated code churn](https://github.com/jappeace/ram/commit/3a0c034648f1cb7e60e96a681fd74066ff5944fe)
+with apparently broken (how?) changes in 0.21.0 being reverted in
+0.21.1.
+
+Rather than depend on ram, git-annex continues to depend on the unmaintained
+[memory](//hackage.haskell.org/package/memory). 
+Since git-annex's use of this package is fairly incidental, this
+dependency could be removed if it becomes a problem.
+
+But ram is an dependency of other dependencies:
+
+* crypton since 1.1.0
+* crypton-x509-validation since 1.9.0. Note that 1.9.1 fixes 
+  [CVE-2026-9648](https://www.cve.org/CVERecord?id=CVE-2026-9648).
+* aws since 0.25.3 (needed to get the CVE-2026-9648 fix)
+* tls since 2.3.0
+* blake3 since 0.3.1 (optional git-annex dependency)
+
+[Reverse dependencies of ram](https://packdeps.haskellers.com/reverse/ram)
+
+## persistent
+
+[persistent](https://hackage.haskell.org/package/persistent) since 2.15.0.0
+
+[First LLM generated code](https://github.com/yesodweb/persistent/commit/ac0a8698f38ae3b07acdacf0ce236d7fc73bb077)
+
+git-annex supports being built with older versions.
+
+## ghc
+
+Need to look up the version, but in any case git-annex remains buildable
+with older versions of ghc back to 9.6.6.

comment
diff --git a/doc/bugs/auth/comment_10_5cfac94f32b17336a81deabe2508c129._comment b/doc/bugs/auth/comment_10_5cfac94f32b17336a81deabe2508c129._comment
new file mode 100644
index 0000000000..50c81dfbb9
--- /dev/null
+++ b/doc/bugs/auth/comment_10_5cfac94f32b17336a81deabe2508c129._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 10"""
+ date="2026-07-01T20:12:11Z"
+ content="""
+`git-annex push` won't always trigger this problem because often it has
+things to `git push` to the server before sending content. A more reliable
+way is to use `git-annex copy --to`.
+"""]]

comment
diff --git a/doc/bugs/auth.mdwn b/doc/bugs/auth.mdwn
index 170aa3be31..c45cea90ba 100644
--- a/doc/bugs/auth.mdwn
+++ b/doc/bugs/auth.mdwn
@@ -1,3 +1,6 @@
+[[!meta title="git-credential-oauth does not work with git-annex push to
+git-annex p2phttp behind forgejo-aneksajo unless git push primes the credential cache first"]]
+
 ### Please describe the problem.
 
 `git annex push` does not trigger git credential retrieval reliably, but forces manual credential entry.
diff --git a/doc/bugs/auth/comment_9_c5b7872812b6aa29224f45b266a7e87e._comment b/doc/bugs/auth/comment_9_c5b7872812b6aa29224f45b266a7e87e._comment
new file mode 100644
index 0000000000..08738e4aa6
--- /dev/null
+++ b/doc/bugs/auth/comment_9_c5b7872812b6aa29224f45b266a7e87e._comment
@@ -0,0 +1,15 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 9"""
+ date="2026-07-01T20:00:36Z"
+ content="""
+`git-annex push` is talking to `git-annex p2phttp` which is on a
+`Forgejo-aneksajo` server.
+
+In this case, the server responds with HTTP 401, and I have verified that
+response does *not* include the `www-authenticate` header.
+
+So, git-annex's code to send that header on to `git-credential` seems fine,
+and this needs to be fixed in either p2phttp or Forgejo-aneksajo to make
+the header be sent. I suspect it will need to be done in Forgejo-aneksajo.
+"""]]

comment
diff --git a/doc/bugs/auth/comment_8_d6b94d6eef80a8711899f008bb31609b._comment b/doc/bugs/auth/comment_8_d6b94d6eef80a8711899f008bb31609b._comment
new file mode 100644
index 0000000000..e56517d8ac
--- /dev/null
+++ b/doc/bugs/auth/comment_8_d6b94d6eef80a8711899f008bb31609b._comment
@@ -0,0 +1,15 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 8"""
+ date="2026-07-01T19:40:42Z"
+ content="""
+The wwwauth field is the relevant one.
+
+There was a past bug about a very similar problem:
+<https://git-annex.branchable.com/bugs/__96__git_annex_push__96___does_not_use_git-credential-oauth/>
+
+[[!commit 32fac0b103db1982b748f15def825e1490d34f50]] was supposed to fix
+that, by passing the www-authenticate http header in to git credential.
+
+This bug must be a case where that doesn't happen.
+"""]]

comment
diff --git a/doc/bugs/auth/comment_7_fcb6f9dacdae34ee522d0efd53038eed._comment b/doc/bugs/auth/comment_7_fcb6f9dacdae34ee522d0efd53038eed._comment
new file mode 100644
index 0000000000..54f2b67f4e
--- /dev/null
+++ b/doc/bugs/auth/comment_7_fcb6f9dacdae34ee522d0efd53038eed._comment
@@ -0,0 +1,22 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 7"""
+ date="2026-07-01T19:34:30Z"
+ content="""
+@mih told me the url privately. (There is only 1.)
+
+It is indeed a host which when passed to `git-credential-oauth get`
+it decides not to do anything.
+
+But, `git push` to the same url uses `git-credential-oauth get` and it
+*does* do oauth.
+
+Dumping what git sends to it, there are additional fields beyond what
+git-annex sends:
+
+	capability[]=authtype
+	capability[]=state
+	protocol=https
+	host=<obscured>
+	wwwauth[]=Basic realm="Gitea"
+"""]]

Fix build with time-1.15
It added a Seconds pattern, so rename Seconds to SecondsDelay to avoid
conflict. Also renamed Microseconds to MicrosecondsDelay; although time
does not have Microseconds, it has Picoseconds, so might add Microseconds
later..
diff --git a/Annex/Init.hs b/Annex/Init.hs
index e610fbce00..7966ce7595 100644
--- a/Annex/Init.hs
+++ b/Annex/Init.hs
@@ -428,7 +428,7 @@ probeLockSupport = withEventuallyCleanedOtherTmp $ \tmp -> do
 		return ok
 	
 	warnstall annexrunner = do
-		threadDelaySeconds (Seconds 10)
+		threadDelaySeconds (SecondsDelay 10)
 		annexrunner $ do
 			warning "Probing the filesystem for POSIX fcntl lock support is taking a long time."
 			warning "(Setting annex.pidlock will avoid this probe.)"
diff --git a/Annex/StallDetection.hs b/Annex/StallDetection.hs
index 9b885c2ecf..9e6f67ba76 100644
--- a/Annex/StallDetection.hs
+++ b/Annex/StallDetection.hs
@@ -55,7 +55,7 @@ detectStalls (Just (StallDetection bwrate@(BwRate _minsz duration))) metervar on
 	let BwRate scaledminsz scaledduration = upscale bwrate timepassed
 	detectStalls' scaledminsz scaledduration metervar onstall v
   where
-	minwaitsecs = Seconds $
+	minwaitsecs = SecondsDelay $
 		min 60 (fromIntegral (durationSeconds duration))
 	waitforfirstupdate startval = do
 		liftIO $ threadDelaySeconds minwaitsecs
@@ -75,7 +75,7 @@ detectStalls (Just ProbeStallDetection) metervar onstall = do
   where
 	duration = Duration 60
 
-	delay = Seconds (fromIntegral (durationSeconds duration) `div` 2)
+	delay = SecondsDelay (fromIntegral (durationSeconds duration) `div` 2)
 	
 	waitforfirstupdate startval = do
 		liftIO $ threadDelaySeconds delay
@@ -115,7 +115,7 @@ detectStalls' minsz duration metervar onstall st = do
 			| sofar - prev < minsz -> onstall
 			| otherwise -> cont
   where
-	delay = Seconds (fromIntegral (durationSeconds duration))
+	delay = SecondsDelay (fromIntegral (durationSeconds duration))
 
 readMeterVar
 	:: MonadIO m
diff --git a/Annex/Transfer.hs b/Annex/Transfer.hs
index 7ec629e442..191c7061fa 100644
--- a/Annex/Transfer.hs
+++ b/Annex/Transfer.hs
@@ -360,19 +360,19 @@ forwardRetry numretries old new
  - by git configuration. -}
 configuredRetry :: RetryDecider
 configuredRetry numretries _old new = do
-	(maxretries, Seconds initretrydelay) <- getcfg $ 
+	(maxretries, SecondsDelay initretrydelay) <- getcfg $ 
 		Remote.gitconfig <$> transferRemote new
 	if numretries < maxretries
 		then do
-			let retrydelay = Seconds (initretrydelay * 2^(numretries-1))
-			showSideAction $ UnquotedString $ "Delaying " ++ show (fromSeconds retrydelay) ++ "s before retrying."
+			let retrydelay = SecondsDelay (initretrydelay * 2^(numretries-1))
+			showSideAction $ UnquotedString $ "Delaying " ++ show (fromSecondsDelay retrydelay) ++ "s before retrying."
 			liftIO $ threadDelaySeconds retrydelay
 			return True
 		else return False
   where
 	globalretrycfg = fromMaybe 0 . annexRetry
 		<$> Annex.getGitConfig
-	globalretrydelaycfg = fromMaybe (Seconds 1) . annexRetryDelay
+	globalretrydelaycfg = fromMaybe (SecondsDelay 1) . annexRetryDelay
 		<$> Annex.getGitConfig
 	getcfg Nothing = (,) <$> globalretrycfg <*> globalretrydelaycfg
 	getcfg (Just gc) = (,)
diff --git a/Assistant/CredPairCache.hs b/Assistant/CredPairCache.hs
index eba3d2b779..a645840b15 100644
--- a/Assistant/CredPairCache.hs
+++ b/Assistant/CredPairCache.hs
@@ -27,7 +27,7 @@ import Control.Concurrent
  - Note that repeatedly caching the same CredPair
  - does not reset its expiry time.
  -}
-cacheCred :: CredPair -> Seconds -> Assistant ()
+cacheCred :: CredPair -> SecondsDelay -> Assistant ()
 cacheCred (login, password) expireafter = do
 	cache <- getAssistant credPairCache
 	liftIO $ do
diff --git a/Assistant/Repair.hs b/Assistant/Repair.hs
index caa02138e2..978d59b080 100644
--- a/Assistant/Repair.hs
+++ b/Assistant/Repair.hs
@@ -149,7 +149,7 @@ repairStaleLocks lockfiles = go =<< getsizes
 	go [] = return ()
 	go l = whenM (liftIO $ null <$> Lsof.query ("--" : map (fromOsPath . fst) l)) $ do
 		debug ["Waiting for 60 seconds to check stale git lock file"]
-		liftIO $ threadDelaySeconds $ Seconds 60
+		liftIO $ threadDelaySeconds $ SecondsDelay 60
 		l' <- getsizes
 		if l' == l
 			then liftIO $ mapM_ (removeWhenExistsWith removeFile . fst) l
diff --git a/Assistant/Restart.hs b/Assistant/Restart.hs
index 58a17c12a2..5a3f03b943 100644
--- a/Assistant/Restart.hs
+++ b/Assistant/Restart.hs
@@ -52,7 +52,7 @@ postRestart url = do
 	modifyDaemonStatus_ $ \status -> status { globalRedirUrl = Just url }
 	liftIO . sendNotification . globalRedirNotifier =<< getDaemonStatus
 	void $ liftIO $ forkIO $ do
-		threadDelaySeconds (Seconds 120)
+		threadDelaySeconds (SecondsDelay 120)
 		terminateSelf
 
 terminateSelf :: IO ()
diff --git a/Assistant/Threads/Committer.hs b/Assistant/Threads/Committer.hs
index 7c11ecc05c..210f096a21 100644
--- a/Assistant/Threads/Committer.hs
+++ b/Assistant/Threads/Committer.hs
@@ -59,7 +59,7 @@ commitThread :: NamedThread
 commitThread = namedThread "Committer" $ do
 	havelsof <- liftIO $ inSearchPath "lsof"
 	delayadd <- liftAnnex $
-		fmap Seconds . annexDelayAdd <$> Annex.getGitConfig
+		fmap SecondsDelay . annexDelayAdd <$> Annex.getGitConfig
 	largefilematcher <- liftAnnex largeFilesMatcher
 	annexdotfiles <- liftAnnex $ getGitConfigVal annexDotFiles
 	addunlockedmatcher <- liftAnnex $
@@ -111,7 +111,7 @@ waitChangeTime a = waitchanges 0
   where
 	waitchanges lastcommitsize = do
 		-- Wait one one second as a simple rate limiter.
-		liftIO $ threadDelaySeconds (Seconds 1)
+		liftIO $ threadDelaySeconds (SecondsDelay 1)
 		-- Now, wait until at least one change is available for
 		-- processing.
 		cs <- getChanges
@@ -193,7 +193,7 @@ waitChangeTime a = waitchanges 0
 		loop 0 = continue oldchanges
 		loop n = do
 			liftAnnex noop -- ensure Annex state is free
-			liftIO $ threadDelaySeconds (Seconds 1)
+			liftIO $ threadDelaySeconds (SecondsDelay 1)
 			changes <- getAnyChanges
 			if null changes
 				then loop (n - 1)
@@ -280,7 +280,7 @@ commitStaged msg = do
  - Any pending adds that are not ready yet are put back into the ChangeChan,
  - where they will be retried later.
  -}
-handleAdds :: OsPath -> Bool -> GetFileMatcher -> Bool -> Maybe AddUnlockedMatcher -> Maybe Seconds -> [Change] -> Assistant [Change]
+handleAdds :: OsPath -> Bool -> GetFileMatcher -> Bool -> Maybe AddUnlockedMatcher -> Maybe SecondsDelay -> [Change] -> Assistant [Change]
 handleAdds lockdowndir havelsof largefilematcher annexdotfiles addunlockedmatcher delayadd cs = returnWhen (null incomplete) $ do
 	let (pending, inprocess) = partition isPendingAddChange incomplete
 	let lockdownconfig = LockDownConfig
@@ -467,7 +467,7 @@ handleAdds lockdowndir havelsof largefilematcher annexdotfiles addunlockedmatche
  -
  - Check by running lsof on the repository.
  -}
-safeToAdd :: OsPath -> LockDownConfig -> Bool -> Maybe Seconds -> [Change] -> [Change] -> Assistant [Either Change Change]
+safeToAdd :: OsPath -> LockDownConfig -> Bool -> Maybe SecondsDelay -> [Change] -> [Change] -> Assistant [Either Change Change]
 safeToAdd _ _ _ _ [] [] = return []
 safeToAdd lockdowndir lockdownconfig havelsof delayadd pending inprocess = do
 	maybe noop (liftIO . threadDelaySeconds) delayadd
diff --git a/Assistant/Threads/ConfigMonitor.hs b/Assistant/Threads/ConfigMonitor.hs
index 97cd4af8bb..9a251616c5 100644
--- a/Assistant/Threads/ConfigMonitor.hs
+++ b/Assistant/Threads/ConfigMonitor.hs
@@ -50,7 +50,7 @@ configMonitorThread = namedThread "ConfigMonitor" $ loop =<< getConfigs
 			{- Record a commit to get this config
 			 - change pushed out to remotes. -}
 			recordCommit
-		liftIO $ threadDelaySeconds (Seconds 60)
+		liftIO $ threadDelaySeconds (SecondsDelay 60)
 		loop new
 
 {- Config files, and their checksums. -}
diff --git a/Assistant/Threads/Cronner.hs b/Assistant/Threads/Cronner.hs
index 9b063b5882..21282e0291 100644
--- a/Assistant/Threads/Cronner.hs
+++ b/Assistant/Threads/Cronner.hs
@@ -116,8 +116,8 @@ sleepingActivityThread urlrenderer activity lasttime = go lasttime =<< getnextti
 	desc = fromScheduledActivity activity
 	schedule = getSchedule activity
 	waitrun l t mmaxt = do
-		seconds <- liftIO $ secondsUntilLocalTime t
-		when (seconds > Seconds 0) $ do
+		seconds <- liftIO $ secondsDelayUntilLocalTime t
+		when (seconds > SecondsDelay 0) $ do
 			debug ["waiting", show seconds, "for next scheduled", desc]
 			liftIO $ threadDelaySeconds seconds
 		now <- liftIO getCurrentTime
@@ -161,14 +161,14 @@ remoteActivityThread urlrenderer mvar activity lasttime = do
 	go _ = noop -- running at exact time not handled here
 	loop = remoteActivityThread urlrenderer mvar activity
 
-secondsUntilLocalTime :: LocalTime -> IO Seconds
-secondsUntilLocalTime t = do
+secondsDelayUntilLocalTime :: LocalTime -> IO SecondsDelay
+secondsDelayUntilLocalTime t = do
 	now <- getCurrentTime
 	tz <- getTimeZone now
 	let secs = truncate $ diffUTCTime (localTimeToUTC tz t) now
 	return $ if secs > 0

(Diff truncated)
formatting
diff --git a/doc/bugs/auth/comment_6_896c29667ae2774d65caafd2a4472e60._comment b/doc/bugs/auth/comment_6_896c29667ae2774d65caafd2a4472e60._comment
index b6eabb917d..1aaf96e8de 100644
--- a/doc/bugs/auth/comment_6_896c29667ae2774d65caafd2a4472e60._comment
+++ b/doc/bugs/auth/comment_6_896c29667ae2774d65caafd2a4472e60._comment
@@ -4,8 +4,8 @@
  date="2026-07-01T17:00:06Z"
  content="""
 In your bug report I noticed that the password prompt is for
-"https://oauth2@<host>" but when you git push it's to
-"https://<host>/<repo>.git". I'm not clear on if these were
+`"https://oauth2@<host>"` but when you git push it's to
+`"https://<host>/<repo>.git"`. I'm not clear on if these were
 really different urls or if it was a mistake in your sanitization.
 
 If there are different urls, `git-credential-oauth` could have acted

comment
diff --git a/doc/bugs/auth/comment_6_896c29667ae2774d65caafd2a4472e60._comment b/doc/bugs/auth/comment_6_896c29667ae2774d65caafd2a4472e60._comment
new file mode 100644
index 0000000000..b6eabb917d
--- /dev/null
+++ b/doc/bugs/auth/comment_6_896c29667ae2774d65caafd2a4472e60._comment
@@ -0,0 +1,30 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 6"""
+ date="2026-07-01T17:00:06Z"
+ content="""
+In your bug report I noticed that the password prompt is for
+"https://oauth2@<host>" but when you git push it's to
+"https://<host>/<repo>.git". I'm not clear on if these were
+really different urls or if it was a mistake in your sanitization.
+
+If there are different urls, `git-credential-oauth` could have acted
+on one and not on the other. Although I don't understand why running
+`git pull` would then cache a credential that would be used on a different url.
+
+Assuming you're using `git-credential-oauth` from eg the Debian package of
+that name, here's an example of it not acting on an url:
+
+	joey@darkstar:~/tmp/x>(echo 'protocol=https'; echo 'host=example.com'; echo 'username=oauth2') | git-credential-oauth get
+	joey@darkstar:~/tmp/x>
+
+Running it the same way with github.com doesn't behave that way:
+
+	joey@darkstar:~/tmp/x>(echo 'protocol=https'; echo 'host=github.com'; echo 'username=oauth2') | git-credential-oauth get
+	Please complete authentication in your browser...
+
+This behavior is not network dependent. In fact, `git-credential-oauth` has a
+pile of special casing for different hosts and different servers, including a
+looksLikeForgejo case. If it does not recognize the server name, it doesn't do
+anything without further configuration.
+"""]]

comment
diff --git a/doc/bugs/auth/comment_5_d8f1045d7fe42f74e10766d791bcbfd4._comment b/doc/bugs/auth/comment_5_d8f1045d7fe42f74e10766d791bcbfd4._comment
new file mode 100644
index 0000000000..9298a5fbf1
--- /dev/null
+++ b/doc/bugs/auth/comment_5_d8f1045d7fe42f74e10766d791bcbfd4._comment
@@ -0,0 +1,36 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 5"""
+ date="2026-07-01T15:52:14Z"
+ content="""
+The "Password for" prompt comes from git-credential, not git-annex.
+
+I was able to reproduce that behavior using a `git-credential-foo`
+"helper" which just exits successfully but does not output any credentials.
+With the git config adjusted to use that (as well as cache), git runs
+it but then falls back to the password prompt:
+
+	joey@darkstar:~/tmp/a1>GIT_TRACE=2 git push foo
+	12:08:19.869469 git.c:502               trace: built-in: git push foo
+	12:08:19.869942 run-command.c:673       trace: run_command: GIT_DIR=.git git remote-https foo https://github.com/joeyh/gitannexbuilder
+	12:08:19.869965 run-command.c:765       trace: start_command: /usr/lib/git-core/git remote-https foo https://github.com/joeyh/gitannexbuilder
+	12:08:19.873067 git.c:808               trace: exec: git-remote-https foo https://github.com/joeyh/gitannexbuilder
+	12:08:19.873107 run-command.c:673       trace: run_command: git-remote-https foo https://github.com/joeyh/gitannexbuilder
+	12:08:19.873121 run-command.c:765       trace: start_command: /usr/lib/git-core/git-remote-https foo https://github.com/joeyh/gitannexbuilder
+	12:08:20.549858 run-command.c:673       trace: run_command: 'git credential-cache get'
+	12:08:20.549927 run-command.c:765       trace: start_command: /bin/sh -c 'git credential-cache get' 'git credential-cache get'
+	12:08:20.555753 git.c:502               trace: built-in: git credential-cache get
+	12:08:20.556612 run-command.c:673       trace: run_command: 'git credential-foo get'
+	12:08:20.556635 run-command.c:765       trace: start_command: /bin/sh -c 'git credential-foo get' 'git credential-foo get'
+	12:08:20.561465 git.c:808               trace: exec: git-credential-foo get
+	12:08:20.561506 run-command.c:673       trace: run_command: git-credential-foo get
+	12:08:20.561530 run-command.c:765       trace: start_command: /home/joey/bin/git-credential-foo get
+	Username for 'https://github.com':
+
+So it seems likely that `git-credential-oauth` is just choosing not to do
+anything when git-annex runs it, and then git is falling back like that.
+
+Why it would choose to do that I don't know, but I suppose it could be a
+difference in that is sent to it on stdin when called by git-annex vs
+by git.
+"""]]

comment
diff --git a/doc/bugs/auth/comment_4_d62d27ba12c59f1f0b49a2140276b5b4._comment b/doc/bugs/auth/comment_4_d62d27ba12c59f1f0b49a2140276b5b4._comment
new file mode 100644
index 0000000000..74b0b13458
--- /dev/null
+++ b/doc/bugs/auth/comment_4_d62d27ba12c59f1f0b49a2140276b5b4._comment
@@ -0,0 +1,13 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 4"""
+ date="2026-07-01T15:43:12Z"
+ content="""
+At the risk of introducing a second red herring, this seems similar to
+[[bugs/git_annex_checkpresentkey_removes_git_credentials]]. But I don't
+think the same, because here `git-annex push` works after `git push` has
+cached a credential, so git-annex is apparently not removing the cached
+credential.
+
+Could you link to the forgejo-aneksajo issue that is/was being dealt with?
+"""]]

diff --git a/doc/bugs/time_1.15__58___Ambiguous_occurrence___8216__Seconds__8217__.mdwn b/doc/bugs/time_1.15__58___Ambiguous_occurrence___8216__Seconds__8217__.mdwn
index de5c58ee7c..4812411c79 100644
--- a/doc/bugs/time_1.15__58___Ambiguous_occurrence___8216__Seconds__8217__.mdwn
+++ b/doc/bugs/time_1.15__58___Ambiguous_occurrence___8216__Seconds__8217__.mdwn
@@ -1,6 +1,13 @@
 ## Please describe the problem.
 
-Building git-annex with GHC 9.14/time 1.15 fails with error "Ambiguous occurrence ‘Seconds’." in Annex/StallDetection.hs
+Building git-annex with GHC 9.14/time 1.15 fails with error "Ambiguous occurrence ‘Seconds’." in 
+
+- Annex/StallDetection.hs, 
+- Assistant/Threads/Committer.hs, 
+- Assistant/Threads/Cronner.hs, 
+- Assistant/Threads/Exporter.hs
+- Assistant/Threads/Watcher.hs 
+- Command/FuzzTest.hs
 
 time 1.15 adds "Seconds" to Data.Time.Clock, leading to ambiguity. Easiest fix would probably be to hide the export, alternatively use qualified import.
 

diff --git a/doc/bugs/time_1.15__58___Ambiguous_occurrence___8216__Seconds__8217__.mdwn b/doc/bugs/time_1.15__58___Ambiguous_occurrence___8216__Seconds__8217__.mdwn
index fe1ad87cf9..de5c58ee7c 100644
--- a/doc/bugs/time_1.15__58___Ambiguous_occurrence___8216__Seconds__8217__.mdwn
+++ b/doc/bugs/time_1.15__58___Ambiguous_occurrence___8216__Seconds__8217__.mdwn
@@ -10,9 +10,9 @@ Build git-annex with GHC 9.14
 
 ## What version of git-annex are you using? On what operating system?
 
-OS: Arch Linux\
-Kernel: 7.0.13-arch1-1\
-GHC: 9.14\
+OS: Arch Linux  
+Kernel: 7.0.13-arch1-1  
+GHC: 9.14  
 git-annex: 10.20251215, newer versions are also affected afaict, including the recently released 10.20260624
 
 ## Please provide any additional information below.

diff --git a/doc/bugs/time_1.15__58___Ambiguous_occurrence___8216__Seconds__8217__.mdwn b/doc/bugs/time_1.15__58___Ambiguous_occurrence___8216__Seconds__8217__.mdwn
new file mode 100644
index 0000000000..fe1ad87cf9
--- /dev/null
+++ b/doc/bugs/time_1.15__58___Ambiguous_occurrence___8216__Seconds__8217__.mdwn
@@ -0,0 +1,69 @@
+## Please describe the problem.
+
+Building git-annex with GHC 9.14/time 1.15 fails with error "Ambiguous occurrence ‘Seconds’." in Annex/StallDetection.hs
+
+time 1.15 adds "Seconds" to Data.Time.Clock, leading to ambiguity. Easiest fix would probably be to hide the export, alternatively use qualified import.
+
+## What steps will reproduce the problem?
+
+Build git-annex with GHC 9.14
+
+## What version of git-annex are you using? On what operating system?
+
+OS: Arch Linux\
+Kernel: 7.0.13-arch1-1\
+GHC: 9.14\
+git-annex: 10.20251215, newer versions are also affected afaict, including the recently released 10.20260624
+
+## Please provide any additional information below.
+
+[[!format sh """
+# If you can, paste a complete transcript of the problem occurring here.
+# If the problem is with the git-annex assistant, paste in .git/annex/daemon.log
+
+[332 of 760] Compiling Annex.StallDetection ( Annex/StallDetection.hs, dist/build/git-annex/git-annex-tmp/Annex/StallDetection.dyn_o )
+Annex/StallDetection.hs:58:23: error: [GHC-87543]
+    Ambiguous occurrence ‘Seconds’.
+    It could refer to
+       either ‘Utility.ThreadScheduler.Seconds’,
+              imported from ‘Utility.ThreadScheduler’ at Annex/StallDetection.hs:21:1-30
+              (and originally defined at Utility/ThreadScheduler.hs:32:19-48),
+           or ‘Data.Time.Clock.Seconds’,
+              imported from ‘Data.Time.Clock’ at Annex/StallDetection.hs:25:1-22
+              (and originally defined in ‘time-1.15:Data.Time.Clock.Internal.DiffTime’).
+   |
+58 |         minwaitsecs = Seconds $
+   |                       ^^^^^^^
+
+Annex/StallDetection.hs:78:17: error: [GHC-87543]
+    Ambiguous occurrence ‘Seconds’.
+    It could refer to
+       either ‘Utility.ThreadScheduler.Seconds’,
+              imported from ‘Utility.ThreadScheduler’ at Annex/StallDetection.hs:21:1-30
+              (and originally defined at Utility/ThreadScheduler.hs:32:19-48),
+           or ‘Data.Time.Clock.Seconds’,
+              imported from ‘Data.Time.Clock’ at Annex/StallDetection.hs:25:1-22
+              (and originally defined in ‘time-1.15:Data.Time.Clock.Internal.DiffTime’).
+   |
+78 |         delay = Seconds (fromIntegral (durationSeconds duration) `div` 2)
+   |                 ^^^^^^^
+
+Annex/StallDetection.hs:118:17: error: [GHC-87543]
+    Ambiguous occurrence ‘Seconds’.
+    It could refer to
+       either ‘Utility.ThreadScheduler.Seconds’,
+              imported from ‘Utility.ThreadScheduler’ at Annex/StallDetection.hs:21:1-30
+              (and originally defined at Utility/ThreadScheduler.hs:32:19-48),
+           or ‘Data.Time.Clock.Seconds’,
+              imported from ‘Data.Time.Clock’ at Annex/StallDetection.hs:25:1-22
+              (and originally defined in ‘time-1.15:Data.Time.Clock.Internal.DiffTime’).
+    |
+118 |         delay = Seconds (fromIntegral (durationSeconds duration))
+    |                 ^^^^^^^
+
+# End of transcript or log.
+"""]]
+
+### Have you had any luck using git-annex before? (Sometimes we get tired of reading bug reports all day and a lil' positive end note does wonders)
+
+

update
diff --git a/doc/thanks/contributor-list b/doc/thanks/contributor-list
index ed4fd05472..00d0418c93 100644
--- a/doc/thanks/contributor-list
+++ b/doc/thanks/contributor-list
@@ -74,3 +74,4 @@ Gergely Risko,
 Yaroslav Halchenko,
 Oleg Tolmatcev,
 Greg Steuck,
+edef,

add news item for git-annex 10.20260624
diff --git a/doc/news/version_10.20260316.mdwn b/doc/news/version_10.20260316.mdwn
deleted file mode 100644
index 7ca6f4e414..0000000000
--- a/doc/news/version_10.20260316.mdwn
+++ /dev/null
@@ -1,17 +0,0 @@
-git-annex 10.20260316 released with [[!toggle text="these changes"]]
-[[!toggleable text="""  * Added CHECKPRESENT-URL extension to the external special remote protocol.
-  * Fix reversion in previous version that caused auto-initializing of
-    local git remotes that have annex-ignore set.
-  * Fix bug that caused git credential to be rejected when a http request
-    failed for some reason other than 401.
-  * Importing from the directory special remote will no longer add sizes
-    to keys, which overrode backends that generate unsized keys.
-  * Fix retrival from http git remotes of keys with '%' in their names.
-  * Fix behavior when initremote is used with --sameas=
-    combined with --private.
-  * web, S3, git: Fix bugs in checking if content is present on a remote
-    when configuration does not allow accessing it.
-  * httpalso: Fix bugs in handling content not being present on the remote.
-  * adb: Avoid deleting contents of a non-empty directory when
-    removing the last exported file from the directory.
-  * Improve display of http exceptions."""]]
\ No newline at end of file
diff --git a/doc/news/version_10.20260624.mdwn b/doc/news/version_10.20260624.mdwn
new file mode 100644
index 0000000000..7ee7c9425f
--- /dev/null
+++ b/doc/news/version_10.20260624.mdwn
@@ -0,0 +1,24 @@
+git-annex 10.20260624 released with [[!toggle text="these changes"]]
+[[!toggleable text="""  * Added Botan build flag, which speeds up checksumming significantly
+    for most existing hash backends.
+  * Added Blake3 build flag, which is the fastest available
+    cryptographically secure hash.
+    Thanks to edef for implementing this.
+  * When b3sum is in PATH, use it for faster blake3 hashing.
+  * Added XXH3 build flag, which is the fastest available
+    non-cryptographically secure hash, and is a smaller hash
+    than MD5 or SHA1.
+  * Improve handling of synced/master and similar branches, by
+    only creating such branches when necessary to push to a non-bare
+    remote, and by removing the local synced branch once its changes
+    are merged.
+  * put: New command.
+  * move: Fix bug where an interrupted command other than move could
+    be treated as an interrupted move, resulting in dropping content
+    when not allowed by numcopies.
+  * Fix build with http-types-0.12.5
+  * merge, post-receive: Fix bug that prevented merging any synced/
+    branches into the current branch.
+    (Reversion introduced in 10.20260601)
+  * git-annex.cabal: Remove unused dependency on old-locale.
+  * Remove dependencies on securemem and byteable."""]]
\ No newline at end of file

done
diff --git a/doc/todo/BLAKE3_multithreading.mdwn b/doc/todo/BLAKE3_multithreading.mdwn
index e096343e74..75d1ce79ea 100644
--- a/doc/todo/BLAKE3_multithreading.mdwn
+++ b/doc/todo/BLAKE3_multithreading.mdwn
@@ -36,3 +36,5 @@ Supporting BLAKE3 multithreading would not be trivial. It needs mmaped file acce
 and the C++ library oneTBB, which would need to be somehow linked into the haskell library.
 
 Calling out to b3sum when in PATH would be easier.. --[[Joey]]
+
+> [[done]]

When b3sum is in PATH, use it for faster blake3 hashing
b3sum is so much faster that it's worth the pain.
The pain could be avoided if this is implemented:
https://github.com/k0001/hs-blake3/issues/9
There is no progress display possible when using b3sum. But it's so much
faster that it's still worth using.
Disabled incremental verification for blake3. b3sum is not able to use
multithreading when reading from stdin. And piping to it would surely be
slower.
The ugly use of unsafePerformIO in b3sumAvailable is the second place where
a Backend needs to use it. This suggests that there should be a constuctor
in IO for Backend.
Note that incremetal verification is disabled even when b3sum is not in
PATH. It would be possible to check b3sumAvailable, but again that needs
a constructor in IO for Backend. Anyway, probably users of this backend
will install b3sum.
Sponsored-by: Brock Spratlen
diff --git a/Backend/Hash.hs b/Backend/Hash.hs
index 6834229f15..f159b4d2be 100644
--- a/Backend/Hash.hs
+++ b/Backend/Hash.hs
@@ -179,7 +179,7 @@ sameCheckSum key hash
 	backslash = fromIntegral (ord '\\')
 
 checkKeyChecksumIncremental :: HashType -> Maybe (Key -> Annex IncrementalVerifier)
-checkKeyChecksumIncremental hash = case snd (hasher hash) of
+checkKeyChecksumIncremental hash = case hashIncremental (hasher hash) of
 	Just iv -> Just (liftIO . iv)
 	Nothing -> Nothing
 
@@ -238,15 +238,25 @@ trivialMigrate' oldkey newbackend afile maxextlen maxexts
 	newvariety = backendVariety newbackend
 
 hashFile :: HashType -> OsPath -> MeterUpdate -> Annex Hash
-hashFile hash file meterupdate = 
-	liftIO $ withMeteredFile file meterupdate $ \b -> do
-		let h = (fst $ hasher hash) b
+hashFile hashtype file meterupdate = case hashFileFast o of
+	Nothing -> liftIO hashpure
+	Just a -> liftIO $ a file >>= \case
+		Just h -> return h
+		Nothing -> hashpure
+  where
+	o = hasher hashtype
+	hashpure = withMeteredFile file meterupdate $ \b -> do
+		let h = (hashPure o) b
 		-- Force full evaluation of hash so whole file is read
 		-- before returning.
 		evaluate (rnf h)
 		return h
 
-type Hasher = (L.ByteString -> Hash, Maybe (Key -> IO IncrementalVerifier))
+data Hasher = Hasher
+	{ hashPure :: L.ByteString -> Hash
+	, hashFileFast :: Maybe (OsPath -> IO (Maybe Hash))
+	, hashIncremental :: Maybe (Key -> IO IncrementalVerifier)
+	}
 
 hasher :: HashType -> Hasher
 hasher MD5Hash = md5Hasher
@@ -266,10 +276,12 @@ hasher XXH3Hash = xxh3Hasher
 #endif
 
 mkHasher :: (L.ByteString -> HashDigest) -> IO IncrementalHasher -> Hasher
-mkHasher h i = 
-	( digestToHash . h
-	, Just $ mkIncrementalVerifier i descChecksum . sameCheckSum
-	)
+mkHasher h i = Hasher
+	{ hashPure = digestToHash . h
+	, hashFileFast = Nothing
+	, hashIncremental = Just $
+		mkIncrementalVerifier i descChecksum . sameCheckSum
+	}
 
 sha2Hasher :: HashSize -> Hasher
 sha2Hasher (HashSize hashsize)
@@ -322,12 +334,22 @@ blake2spHasher (HashSize hashsize)
 
 #ifdef WITH_BLAKE3
 blake3Hasher :: Hasher
-blake3Hasher = (blake3, Just $ blake3IncrementalVerifier descChecksum . sameCheckSum)
+blake3Hasher = Hasher
+	{ hashPure = blake3
+	, hashFileFast = Just blake3File
+	-- No incremental verification for blake3 because
+	-- blake3File is much faster.
+	, hashIncremental = Nothing
+	}
 #endif
 
 #ifdef WITH_XXH3
 xxh3Hasher :: Hasher
-xxh3Hasher = (digestToHash . xxh3, xxh3Incremental)
+xxh3Hasher = Hasher
+	{ hashPure = digestToHash . xxh3
+	, hashFileFast = Nothing
+	, hashIncremental = xxh3Incremental
+	}
 #endif
 
 sha1Hasher :: Hasher
@@ -367,6 +389,6 @@ testKeyHash = SHA2Hash (HashSize 256)
 genTestKey :: L.ByteString -> Key
 genTestKey content = addTestE $ mkKey $ \kd -> kd
 	{ keyName = S.toShort $ hashByteString $
-		(fst $ hasher testKeyHash) content
+		(hashPure $ hasher testKeyHash) content
 	, keyVariety = backendVariety testKeyBackend
 	}
diff --git a/CHANGELOG b/CHANGELOG
index ebb6c708ac..d54f23e8b0 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -5,6 +5,7 @@ git-annex (10.20260602) UNRELEASED; urgency=medium
   * Added Blake3 build flag, which is the fastest available
     cryptographically secure hash.
     Thanks to edef for implementing this.
+  * When b3sum is in PATH, use it for faster blake3 hashing.
   * Added XXH3 build flag, which is the fastest available
     non-cryptographically secure hash, and is a smaller hash
     than MD5 or SHA1.
diff --git a/Utility/Hash/Blake3.hs b/Utility/Hash/Blake3.hs
index 99eb510cd9..5b6c6659d5 100644
--- a/Utility/Hash/Blake3.hs
+++ b/Utility/Hash/Blake3.hs
@@ -1,4 +1,4 @@
-{- Blake3 convenience wrapper.
+{- Blake3 convenience wrapper with b3hash support.
  -
  - Copyright 2026 Joey Hess <id@joeyh.name>
  - Copyright 2022 edef <edef@edef.eu>
@@ -12,16 +12,25 @@
 module Utility.Hash.Blake3 (
 	blake3,
 	blake3IncrementalVerifier,
+	blake3File,
 ) where
 
 import Utility.Hash.Types
 import Utility.Hash.Incremental
 import Utility.FileSystemEncoding
+import Utility.OsPath
+import Utility.Path
+import Utility.FileSize
+import Utility.Process
+import Utility.Exception
+import Utility.Monad
 
 import qualified BLAKE3
 import qualified Data.ByteString as S
 import qualified Data.ByteString.Lazy as L
 import Data.IORef
+import Control.Concurrent.MVar
+import GHC.IO (unsafePerformIO)
 
 finalize :: BLAKE3.Hasher -> BLAKE3.Digest BLAKE3.DEFAULT_DIGEST_LEN
 finalize = BLAKE3.finalize
@@ -46,3 +55,49 @@ blake3IncrementalVerifier desc samechecksum = do
 		, positionIncrementalVerifier = fmap snd <$> readIORef v
 		, descIncrementalVerifier = desc
 		}
+
+{- When b3sum is in the path, this uses it to hash a file. For large
+ - files, that is much faster due to supporting parallelism.
+ -
+ - This returns Nothing when b3sum is not in the path, or exits nonzero, 
+ - or when the file is too small to be worth running it.
+ -}
+blake3File :: OsPath -> IO (Maybe Hash)
+blake3File file = takeMVar b3sumAvailable >>= \case
+	Just True -> do
+		putMVar b3sumAvailable (Just True)
+		runb3sum
+	Just False -> do
+		putMVar b3sumAvailable (Just False)
+		return Nothing
+	Nothing -> ifM (inSearchPath "b3sum")
+		( do
+			putMVar b3sumAvailable (Just True)
+			runb3sum
+		, do
+			putMVar b3sumAvailable (Just False)
+			return Nothing
+		)
+  where
+	runb3sum = ifM filelargeenough
+		( tryNonAsync runb3sum' >>= return . \case
+			Right output -> case lines output of
+				(hash:[]) | length hash == 64 ->
+					Just $ Hash $ encodeBS hash
+				_ -> Nothing
+			Left _ ->  Nothing
+		, return Nothing
+		)
+	runb3sum' = readProcess "b3sum" ["--no-names", "--", fromOsPath file]
+	
+	-- A file needs to be about 3mb in size before the overhead of
+	-- starting a b3sum process is worthwhile.
+	filelargeenough = tryNonAsync (getFileSize file) >>= return . \case
+		Right sz -> sz > 3000000
+		Left _ -> False
+
+{- Used to avoid needing to check the PATH for b3sum each time
+ - blake3File is called. -}
+{-# NOINLINE b3sumAvailable #-}
+b3sumAvailable :: MVar (Maybe Bool)
+b3sumAvailable = unsafePerformIO $ newMVar Nothing
diff --git a/debian/control b/debian/control
index 321eb45783..e368394333 100644
--- a/debian/control
+++ b/debian/control
@@ -121,6 +121,7 @@ Recommends:
 	git-remote-gcrypt (>= 0.20130908-6),
 	nocache,
 	aria2,
+	b3sum,

(Diff truncated)
update
diff --git a/doc/todo/BLAKE3_multithreading.mdwn b/doc/todo/BLAKE3_multithreading.mdwn
index de60122a4f..e096343e74 100644
--- a/doc/todo/BLAKE3_multithreading.mdwn
+++ b/doc/todo/BLAKE3_multithreading.mdwn
@@ -29,6 +29,9 @@ file with SHA256SUM, git-annex fsck:
 	11.18user 2.11system 0:13.41elapsed 99%CPU (0avgtext+0avgdata 53792maxresident)k
 	7816912inputs+288outputs (2major+8615minor)pagefaults 0swaps
 
+Using -J with enough concurrent files might approach b3sum's speed,
+but often a user wants to add or fsck 1 file as fast as possible.
+
 Supporting BLAKE3 multithreading would not be trivial. It needs mmaped file access,
 and the C++ library oneTBB, which would need to be somehow linked into the haskell library.
 

todo
diff --git a/doc/todo/BLAKE3_multithreading.mdwn b/doc/todo/BLAKE3_multithreading.mdwn
new file mode 100644
index 0000000000..de60122a4f
--- /dev/null
+++ b/doc/todo/BLAKE3_multithreading.mdwn
@@ -0,0 +1,35 @@
+git-annex using BLAKE3 is significantly slower than b3sum.
+The latter uses BLAKE3's multithreading, which is not available in the
+haskell library.
+
+<https://github.com/k0001/hs-blake3/issues/9>
+
+On a 4 gb file:
+
+git-annex fsck:
+
+	1.25user 2.36system 0:07.81elapsed 46%CPU (0avgtext+0avgdata 57676maxresident)k
+	5539480inputs+208outputs (2major+9161minor)pagefaults 0swaps
+
+b3sum:
+
+	1.60user 3.03system 0:02.98elapsed 155%CPU (0avgtext+0avgdata 3158216maxresident)k
+	7013984inputs+0outputs (15345major+57763minor)pagefaults 0swaps
+
+b3sum --num-threads 1:
+
+	1.24user 1.62system 0:07.31elapsed 39%CPU (0avgtext+0avgdata 2326392maxresident)k
+	5902456inputs+0outputs (3262major+43283minor)pagefaults 0swaps
+
+A massive amount of performance is being left on the table.
+
+Although even so, BLAKE3 is still signficantly faster than SHA2, eg on the same
+file with SHA256SUM, git-annex fsck:
+
+	11.18user 2.11system 0:13.41elapsed 99%CPU (0avgtext+0avgdata 53792maxresident)k
+	7816912inputs+288outputs (2major+8615minor)pagefaults 0swaps
+
+Supporting BLAKE3 multithreading would not be trivial. It needs mmaped file access,
+and the C++ library oneTBB, which would need to be somehow linked into the haskell library.
+
+Calling out to b3sum when in PATH would be easier.. --[[Joey]]

done
diff --git a/doc/todo/add_xxHash_backend.mdwn b/doc/todo/add_xxHash_backend.mdwn
index cf9143ea09..065d41ade1 100644
--- a/doc/todo/add_xxHash_backend.mdwn
+++ b/doc/todo/add_xxHash_backend.mdwn
@@ -1 +1,3 @@
 From https://cyan4973.github.io/xxHash/ , xxHash seems much faster than md5 with comparable quality.  There's a Haskell implementation.
+
+> [[done]] (XX3) --[[Joey]]

XXH3
This is the fastest available non-cryptographically secure hash,
and is a smaller hash than MD5 or SHA1.
Had to work around a number of issues with the haskell library.
And it is not available on 32 bit systems until one of those issues is
fixed.
Sponsored-by: Jack Hill
diff --git a/Backend/Hash.hs b/Backend/Hash.hs
index 80b223f838..50eadc1bb2 100644
--- a/Backend/Hash.hs
+++ b/Backend/Hash.hs
@@ -41,6 +41,13 @@ import Control.Exception (evaluate)
 import Data.IORef
 import qualified BLAKE3
 #endif
+#ifdef WITH_XXH3
+import qualified Data.Digest.XXHash.FFI as XXH3
+import qualified Data.Hashable as Hashable
+import Data.Word
+import Data.Bits
+import Data.ByteString.Builder
+#endif
 
 data HashType
 	= MD5Hash
@@ -55,6 +62,9 @@ data HashType
 #ifdef WITH_BLAKE3
 	| Blake3Hash
 #endif
+#ifdef WITH_XXH3
+	| XXH3Hash
+#endif
 
 cryptographicallySecure :: HashType -> Bool
 cryptographicallySecure (SHA2Hash _) = True
@@ -67,6 +77,9 @@ cryptographicallySecure (Blake2spHash _) = True
 #ifdef WITH_BLAKE3
 cryptographicallySecure Blake3Hash = True
 #endif
+#ifdef WITH_XXH3
+cryptographicallySecure XXH3Hash = False
+#endif
 cryptographicallySecure SHA1Hash = False
 cryptographicallySecure MD5Hash = False
 
@@ -85,6 +98,11 @@ hashes = concat
 	, map (Blake2spHash . HashSize) [256, 224]
 #ifdef WITH_BLAKE3
 	, [Blake3Hash]
+#endif
+#ifdef WITH_XXH3
+	, if xxH3Supported
+		then [XXH3Hash]
+		else []
 #endif
 	, [SHA1Hash]
 	, [MD5Hash]
@@ -99,7 +117,7 @@ genBackend hash = Backend
 	{ backendVariety = hashKeyVariety hash (HasExt False)
 	, genKey = Just (keyValue hash)
 	, verifyKeyContent = Just $ checkKeyChecksum sameCheckSum hash
-	, verifyKeyContentIncrementally = Just $ checkKeyChecksumIncremental hash
+	, verifyKeyContentIncrementally = checkKeyChecksumIncremental hash
 	, canUpgradeKey = Just needsUpgrade
 	, fastMigrate = Just trivialMigrate
 	, isStableKey = const True
@@ -127,6 +145,9 @@ hashKeyVariety (Blake2spHash size) he = Blake2spKey size he
 #ifdef WITH_BLAKE3
 hashKeyVariety Blake3Hash he = Blake3Key he
 #endif
+#ifdef WITH_XXH3
+hashKeyVariety XXH3Hash he = XXH3Key he
+#endif
 
 {- A key is a hash of its contents. -}
 keyValue :: HashType -> KeySource -> MeterUpdate -> Annex Key
@@ -169,8 +190,10 @@ sameCheckSum key hash
 	expected = keyHash key
 	backslash = fromIntegral (ord '\\')
 
-checkKeyChecksumIncremental :: HashType -> Key -> Annex IncrementalVerifier
-checkKeyChecksumIncremental hash key = liftIO $ (snd $ hasher hash) key
+checkKeyChecksumIncremental :: HashType -> Maybe (Key -> Annex IncrementalVerifier)
+checkKeyChecksumIncremental hash = case snd (hasher hash) of
+	Just iv -> Just (liftIO . iv)
+	Nothing -> Nothing
 
 keyHash :: Key -> S.ByteString
 keyHash = fst . splitKeyNameExtension
@@ -235,7 +258,7 @@ hashFile hash file meterupdate =
 		evaluate (rnf h)
 		return h
 
-type Hasher = (L.ByteString -> Hash, Key -> IO IncrementalVerifier)
+type Hasher = (L.ByteString -> Hash, Maybe (Key -> IO IncrementalVerifier))
 
 hasher :: HashType -> Hasher
 hasher MD5Hash = md5Hasher
@@ -250,9 +273,15 @@ hasher (Blake2spHash hashsize) = blake2spHasher hashsize
 #ifdef WITH_BLAKE3
 hasher Blake3Hash = blake3Hasher
 #endif
+#ifdef WITH_XXH3
+hasher XXH3Hash = xxh3Hasher
+#endif
 
 mkHasher :: (L.ByteString -> HashDigest) -> IO IncrementalHasher -> Hasher
-mkHasher h i = (digestToHash . h, mkIncrementalVerifier i descChecksum . sameCheckSum)
+mkHasher h i = 
+	( digestToHash . h
+	, Just $ mkIncrementalVerifier i descChecksum . sameCheckSum
+	)
 
 sha2Hasher :: HashSize -> Hasher
 sha2Hasher (HashSize hashsize)
@@ -305,7 +334,7 @@ blake2spHasher (HashSize hashsize)
 
 #ifdef WITH_BLAKE3
 blake3Hasher :: Hasher
-blake3Hasher = (hash, incremental) where
+blake3Hasher = (hash, Just incremental) where
 	finalize :: BLAKE3.Hasher -> BLAKE3.Digest BLAKE3.DEFAULT_DIGEST_LEN
 	finalize = BLAKE3.finalize
 
@@ -331,6 +360,31 @@ blake3Hasher = (hash, incremental) where
 			}
 #endif
 
+#ifdef WITH_XXH3
+xxh3Hasher :: Hasher
+xxh3Hasher = (hash, incremental) where
+	hash = convcanonical . Hashable.hashWithSalt 0 . XXH3.XXH3
+	-- The haskell library does not support incremental verification
+	-- (without going too low-level to be appropriate here).
+	-- https://github.com/haskell-haskey/xxhash-ffi/issues/7
+	incremental = Nothing
+	-- Convert to XXH3 canonical representation.
+	-- This is unfortunately not exposed by xxhash-ffi so has to
+	-- be re-implemented here.
+	-- See https://github.com/haskell-haskey/xxhash-ffi/issues/8
+	convcanonical = digestToHash . HashDigest 
+		. L.toStrict . toLazyByteString 
+		. word64BE . fromint
+	fromint :: Int -> Word64
+	fromint = fromIntegral
+
+-- Due to use of Int, the xxhash-ffi library is currently only suitable
+-- for use on 64 bit (or higher) systems. 
+-- https://github.com/haskell-haskey/xxhash-ffi/issues/6
+xxH3Supported :: Bool
+xxH3Supported = finiteBitSize (0 :: Int) >= 64
+#endif
+
 sha1Hasher :: Hasher
 sha1Hasher = mkHasher sha1 sha1_hasher
 
diff --git a/BuildFlags.hs b/BuildFlags.hs
index e8f8361b7c..e618492b95 100644
--- a/BuildFlags.hs
+++ b/BuildFlags.hs
@@ -74,6 +74,11 @@ buildFlags = filter (not . null)
 	, "Blake3"
 #else
 #warning Building without Blake3 support.
+#endif
+#ifdef WITH_XXH3
+	, "XXH3"
+#else
+#warning Building without XXH3 support.
 #endif
 	]
 
diff --git a/CHANGELOG b/CHANGELOG
index 731f9b615b..a5da5c0f25 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,9 +2,12 @@ git-annex (10.20260602) UNRELEASED; urgency=medium
 
   * Added Botan build flag, which speeds up checksumming significantly
     for most existing hash backends.
-  * Added Blake3 build flag, which is the fastest available hash in
-    git-annex now.
+  * Added Blake3 build flag, which is the fastest available
+    cryptographically secure hash.
     Thanks to edef for their patches.
+  * Added XXH3 build flag, which is the fastest available
+    non-cryptographically secure hash, and is a smaller hash
+    than MD5 or SHA1.
   * Improve handling of synced/master and similar branches, by
     only creating such branches when necessary to push to a non-bare
     remote, and by removing the local synced branch once its changes
diff --git a/Types/Key.hs b/Types/Key.hs
index f7e9bc5a04..06396415a2 100644
--- a/Types/Key.hs
+++ b/Types/Key.hs
@@ -216,6 +216,9 @@ data KeyVariety
 	| Blake2spKey HashSize HasExt
 #ifdef WITH_BLAKE3
 	| Blake3Key HasExt
+#endif
+#ifdef WITH_XXH3
+	| XXH3Key HasExt
 #endif
 	| SHA1Key HasExt
 	| MD5Key HasExt
@@ -256,6 +259,9 @@ hasExt (Blake2spKey _ (HasExt b)) = b
 #ifdef WITH_BLAKE3

(Diff truncated)
comment
diff --git a/doc/todo/add_xxHash_backend/comment_7_d8b95d234c09d58be8b60bd0f6b4d767._comment b/doc/todo/add_xxHash_backend/comment_7_d8b95d234c09d58be8b60bd0f6b4d767._comment
new file mode 100644
index 0000000000..77894032ea
--- /dev/null
+++ b/doc/todo/add_xxHash_backend/comment_7_d8b95d234c09d58be8b60bd0f6b4d767._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 7"""
+ date="2026-06-22T15:22:32Z"
+ content="""
+This would still be worth doing despite git-annex supporting BLAKE3 now.
+XXHASH is even faster, due to not needing to do the work to be
+cryptographically secure.
+"""]]

comment
diff --git a/doc/backends/comment_36_d903eb4b0207b848a1d92010f7868bb1._comment b/doc/backends/comment_36_d903eb4b0207b848a1d92010f7868bb1._comment
new file mode 100644
index 0000000000..33d4d91de2
--- /dev/null
+++ b/doc/backends/comment_36_d903eb4b0207b848a1d92010f7868bb1._comment
@@ -0,0 +1,16 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""Re: combine worm with partial hash"""
+ date="2026-06-22T15:17:46Z"
+ content="""
+It lowers the probability to only files that happen to start with the same
+prefix. There are many cases where 2 versions of a file start with the same
+data and diverge later, think eg a filesystem image where one file has been
+changed. 
+
+So I think this would give a false sense of protection, kind of like wearing
+a steel toed boot but with a gun still pointed at your foot.
+
+It's better to just not use WORM. Modern computers can hash really fast,
+especially if you use BLAKE3.
+"""]]

mention annex.securehashesonly
diff --git a/doc/backends.mdwn b/doc/backends.mdwn
index 6fb6cc9638..9ff00f12be 100644
--- a/doc/backends.mdwn
+++ b/doc/backends.mdwn
@@ -76,7 +76,8 @@ in `.gitattributes`:
 ## non-cryptograpgically secure backends
 
 The backends below do not guarantee cryptographically that the
-content of an annexed file remains unchanged.
+content of an annexed file remains unchanged. git-annex can be configured
+to not allow these, by the `annex.securehashesonly` git-config setting.
 
 * `SHA1`, `SHA1E`, `MD5`, `MD5E` -- Smaller hashes than `SHA256`
    for those who want a checksum but are not concerned about security.

comment
diff --git a/doc/bugs/blake3_hash_support/comment_11_59b43eddd3f187440824ba36ee75ff57._comment b/doc/bugs/blake3_hash_support/comment_11_59b43eddd3f187440824ba36ee75ff57._comment
new file mode 100644
index 0000000000..b0c5a7d67c
--- /dev/null
+++ b/doc/bugs/blake3_hash_support/comment_11_59b43eddd3f187440824ba36ee75ff57._comment
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 11"""
+ date="2026-06-22T14:56:37Z"
+ content="""
+It would be possible to add other blake3 hash lengths, but I have not
+investigated if there is any benefit (eg performance or security) in
+using anything other than `BLAKE3_256`. Will wait to see if anyone comes up
+with a use case for them.
+
+I don't think it will be a problem to adapt the existing code to use them.
+"""]]

fix
diff --git a/doc/bugs/blake3_hash_support/comment_9_585f9d6f330c22a954b005cae0428e58._comment b/doc/bugs/blake3_hash_support/comment_9_585f9d6f330c22a954b005cae0428e58._comment
index c5727fe205..8d730f85fe 100644
--- a/doc/bugs/blake3_hash_support/comment_9_585f9d6f330c22a954b005cae0428e58._comment
+++ b/doc/bugs/blake3_hash_support/comment_9_585f9d6f330c22a954b005cae0428e58._comment
@@ -3,7 +3,7 @@
  subject="""comment 9"""
  date="2026-06-22T14:25:51Z"
  content="""
-Updated to blake3 and it is indeed even faster: 6.80s
+Updated to blake3-0.3 and it is indeed even faster: 6.80s
 
 Impressive, that's twice as fast as botan's sha256.
 """]]

blake3 merged
diff --git a/doc/bugs/blake3_hash_support.mdwn b/doc/bugs/blake3_hash_support.mdwn
index 1485e79ac3..f5db2b9384 100644
--- a/doc/bugs/blake3_hash_support.mdwn
+++ b/doc/bugs/blake3_hash_support.mdwn
@@ -375,3 +375,5 @@ index 30614e156..0778948fb 100644
      Build-Depends: network-multicast, network-info
      CPP-Options: -DWITH_PAIRING
 """]]
+
+> [[merged|done]] --[[Joey]]
diff --git a/doc/bugs/blake3_hash_support/comment_10_5c3e349536dbb0c76d3df02e92a60c78._comment b/doc/bugs/blake3_hash_support/comment_10_5c3e349536dbb0c76d3df02e92a60c78._comment
new file mode 100644
index 0000000000..eb58ec2361
--- /dev/null
+++ b/doc/bugs/blake3_hash_support/comment_10_5c3e349536dbb0c76d3df02e92a60c78._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 10"""
+ date="2026-06-22T14:49:17Z"
+ content="""
+The above patches *did* have a memory leak.
+
+I've fixed that, and merged to master.
+"""]]

comment
diff --git a/doc/bugs/blake3_hash_support/comment_9_585f9d6f330c22a954b005cae0428e58._comment b/doc/bugs/blake3_hash_support/comment_9_585f9d6f330c22a954b005cae0428e58._comment
new file mode 100644
index 0000000000..c5727fe205
--- /dev/null
+++ b/doc/bugs/blake3_hash_support/comment_9_585f9d6f330c22a954b005cae0428e58._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 9"""
+ date="2026-06-22T14:25:51Z"
+ content="""
+Updated to blake3 and it is indeed even faster: 6.80s
+
+Impressive, that's twice as fast as botan's sha256.
+"""]]

note about build flag
diff --git a/doc/backends.mdwn b/doc/backends.mdwn
index 767f1f7eb2..6fb6cc9638 100644
--- a/doc/backends.mdwn
+++ b/doc/backends.mdwn
@@ -62,7 +62,9 @@ in `.gitattributes`:
 * `BLAKE3_256`, `BLAKE3_256E`
   -- Very fast [Blake3 hash](https://github.com/BLAKE3-team/BLAKE3).
   Unlike the Blake2 family, Blake3 is a single variant optimised for many platforms.
-  It is still faster than Blake2 in most cases.
+  It is still faster than Blake2 in most cases.  
+  This is only supported when git-annex is built with the Blake3 build
+  flag.
 
 ### Other
 

update for blake3
Thanks to annexuser64623
diff --git a/doc/backends.mdwn b/doc/backends.mdwn
index 2d1328590b..767f1f7eb2 100644
--- a/doc/backends.mdwn
+++ b/doc/backends.mdwn
@@ -24,6 +24,8 @@ in `.gitattributes`:
 
 ## recommended backends to use
 
+### SHA-2 and SHA-3
+
 * `SHA256E` -- The default backend for new files, combines a 256 bit SHA-2
   hash of the file's content with the file's extension. This allows
   verifying that the file content is right, and can avoid duplicates of
@@ -39,6 +41,9 @@ in `.gitattributes`:
 * `SKEIN512`, `SKEIN512E`, `SKEIN256`, `SKEIN256E`
   -- [Skein hash](http://en.wikipedia.org/wiki/Skein_hash),
   a well-regarded SHA3 hash competition finalist.
+
+### Blake2 and Blake3
+
 * `BLAKE2B160`, `BLAKE2B224`, `BLAKE2B256`, `BLAKE2B384`, `BLAKE2B512`
   `BLAKE2B160E`, `BLAKE2B224E`, `BLAKE2B256E`, `BLAKE2B384E`, `BLAKE2B512E`
   -- Fast [Blake2 hash](https://blake2.net/) variants optimised for 64 bit
@@ -54,6 +59,13 @@ in `.gitattributes`:
   `BLAKE2SP224E`, `BLAKE2SP256E`
   -- Fast [Blake2 hash](https://blake2.net/) variants optimised for 
   8-way CPUs.
+* `BLAKE3_256`, `BLAKE3_256E`
+  -- Very fast [Blake3 hash](https://github.com/BLAKE3-team/BLAKE3).
+  Unlike the Blake2 family, Blake3 is a single variant optimised for many platforms.
+  It is still faster than Blake2 in most cases.
+
+### Other
+
 * `VURL` -- This is like an `URL` (see below) but the content can
   be verified with a cryptographically secure checksum that is
   recorded in the git-annex branch. It's generated when using 

comment
diff --git a/doc/bugs/blake3_hash_support/comment_8_9bc97dc175da01478fb6c39a6fdff538._comment b/doc/bugs/blake3_hash_support/comment_8_9bc97dc175da01478fb6c39a6fdff538._comment
new file mode 100644
index 0000000000..2ae60679cf
--- /dev/null
+++ b/doc/bugs/blake3_hash_support/comment_8_9bc97dc175da01478fb6c39a6fdff538._comment
@@ -0,0 +1,18 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 8"""
+ date="2026-06-22T14:05:49Z"
+ content="""
+blake3 does outperform botan's sha256. I benchmarked it at
+8.30s vs 0:14.36s adding a 4 gb file. That's with blake3-0.2. 
+Newer versions of the blake3 library may be faster yet.
+
+Since the above patches no longer cleanly apply, I have committed
+my update of them to the `blake3` branch. My above review items are not
+addressed yet in that branch. I did add Blake3 to BuildFlags.hs though,
+which was a problem I missed in my earlier review.
+
+Also, the haskell blake3 library has gotten a 0.3 release, which
+the code needs to be updated to build with. (I see no need to retain
+support for 0.2.)
+"""]]

Added a comment
diff --git a/doc/bugs/blake3_hash_support/comment_7_443a5e7eb16d1a859cad9b0d5506c7b1._comment b/doc/bugs/blake3_hash_support/comment_7_443a5e7eb16d1a859cad9b0d5506c7b1._comment
new file mode 100644
index 0000000000..1384caec3c
--- /dev/null
+++ b/doc/bugs/blake3_hash_support/comment_7_443a5e7eb16d1a859cad9b0d5506c7b1._comment
@@ -0,0 +1,48 @@
+[[!comment format=mdwn
+ username="annexuser64623"
+ avatar="http://cdn.libravatar.org/avatar/f2247695660ba216740a81d573e6a3cd"
+ subject="comment 7"
+ date="2026-06-19T10:18:02Z"
+ content="""
+Thanks for your work on Blake3.
+I am looking forward to use Blake3-256 as well since it's much faster than sha2-256 on my machine.
+
+Regarding support via Botan:
+I could not find any recent activity concerning Blake3 Support.
+Links:
+[Botan Discussion on Blake3](https://github.com/randombit/botan/discussions/4755)
+and
+[Botan Issue on Blake3](https://github.com/randombit/botan/issues/3054)
+
+Unfortunately, I'm unfamiliar with Haskell and cannot help with the suggested/requested implementation changes.
+Thus, I created a patch for updating the docs:
+
+```
+diff --git a/doc/backends.mdwn b/doc/backends.mdwn
+index 2d1328590b..fbcc9c87d6 100644
+--- a/doc/backends.mdwn
++++ b/doc/backends.mdwn
+@@ -26,2 +26,4 @@ in `.gitattributes`:
+
++### SHA-2 and SHA-3
++
+ * `SHA256E` -- The default backend for new files, combines a 256 bit SHA-2
+@@ -41,2 +43,5 @@ in `.gitattributes`:
+   a well-regarded SHA3 hash competition finalist.
++
++### Blake2 and Blake3
++
+ * `BLAKE2B160`, `BLAKE2B224`, `BLAKE2B256`, `BLAKE2B384`, `BLAKE2B512`
+@@ -56,2 +61,9 @@ in `.gitattributes`:
+   8-way CPUs.
++* `BLAKE3_256`, `BLAKE3_256E`
++  -- Very fast [Blake3 hash](https://github.com/BLAKE3-team/BLAKE3).
++  Unlike the Blake2 family, Blake3 is a single variant optimised for many platforms.
++  It is still faster than Blake2 in most cases.
++
++### Other
++
+ * `VURL` -- This is like an `URL` (see below) but the content can
+```
+
+"""]]

comment
diff --git a/doc/bugs/migrate_removes_associated_URLs_with_custom_scheme/comment_4_49ad0811cab9f1565528b202c6b0d953._comment b/doc/bugs/migrate_removes_associated_URLs_with_custom_scheme/comment_4_49ad0811cab9f1565528b202c6b0d953._comment
new file mode 100644
index 0000000000..b97a49c0ab
--- /dev/null
+++ b/doc/bugs/migrate_removes_associated_URLs_with_custom_scheme/comment_4_49ad0811cab9f1565528b202c6b0d953._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""Re: annex-security-allow-unverified-downloads"""
+ date="2026-06-12T15:16:21Z"
+ content="""
+The reason downloading from the web special remote with just an URL key is
+allowed is because it avoids the specific security holes that
+annex-security-allow-unverified-downloads was added to deal with.
+"""]]

comment
diff --git a/doc/bugs/migrate_removes_associated_URLs_with_custom_scheme/comment_3_cd276dcc85b3793e3b0bc2367e6081cf._comment b/doc/bugs/migrate_removes_associated_URLs_with_custom_scheme/comment_3_cd276dcc85b3793e3b0bc2367e6081cf._comment
new file mode 100644
index 0000000000..285ed740a3
--- /dev/null
+++ b/doc/bugs/migrate_removes_associated_URLs_with_custom_scheme/comment_3_cd276dcc85b3793e3b0bc2367e6081cf._comment
@@ -0,0 +1,24 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 3"""
+ date="2026-06-12T15:01:37Z"
+ content="""
+The urls are actually being copied to the new key. But `whereis` only displays
+an url when it's located in a remote that contains a key. After the migration,
+git-annex does not think that your special remote contains the new key,
+so it does not display urls that are claimed by that special remote.
+
+For the web, there is a special case that handles this, recording that the
+new key is present in the web special remote. (setUrlPresent does it)
+
+I don't think it makes sense to make that be done for other types of
+special remotes generally. Consider that `git-annex get`
+would request the special remote get the new key. If the special remote
+is a key/value store, the new key is not located on it, so the get would
+fail. Similarly, `git-annex fsck --from specialremote` would detect a
+problem.
+
+Maybe there are other special remotes that are also url based in a way that
+it would make sense to update the location log when migrating a key.
+The bittorrent special remote comes to mind.
+"""]]

fixed earlier
diff --git a/doc/bugs/p2phttp_key_endpoints_stuck_after_2_head_requests.mdwn b/doc/bugs/p2phttp_key_endpoints_stuck_after_2_head_requests.mdwn
index ec02c06846..041623ecbb 100644
--- a/doc/bugs/p2phttp_key_endpoints_stuck_after_2_head_requests.mdwn
+++ b/doc/bugs/p2phttp_key_endpoints_stuck_after_2_head_requests.mdwn
@@ -83,3 +83,5 @@ icg149@icg1911:~/Playground/c1$ curl --head http://localhost:54321/git-annex/df5
 
 
 [[!tag projects/INM7]]
+
+> [[done]] --[[Joey]]

close old polls
being botspammed
diff --git a/doc/design/assistant/polls/goals_for_April.mdwn b/doc/design/assistant/polls/goals_for_April.mdwn
index 53132dd441..dc0e6a3d7a 100644
--- a/doc/design/assistant/polls/goals_for_April.mdwn
+++ b/doc/design/assistant/polls/goals_for_April.mdwn
@@ -3,7 +3,7 @@ features done in a month if I'm lucky. I have only 3 more funded months,
 and parts of one will be spent working on porting to Windows, so choose wisely!
 --[[Joey]]
 
-[[!poll open=yes expandable=yes 4 "upload and download rate limiting" 15 "get webapp working on Android" 5 "deltas: speed up syncing modified versions of existing files" 8 "encrypted git remotes using git-remote-gcrypt" 0 "add support for more cloud storage remotes" 19 "don't work on features, work on making it easier to install and use" 2 "Handle duplicate files" 6 "direct mode (aka real files instead of symlinks) [already done --joey]" 3 "start windows port now"]]
+[[!poll open=no expandable=yes 4 "upload and download rate limiting" 15 "get webapp working on Android" 5 "deltas: speed up syncing modified versions of existing files" 8 "encrypted git remotes using git-remote-gcrypt" 0 "add support for more cloud storage remotes" 19 "don't work on features, work on making it easier to install and use" 2 "Handle duplicate files" 6 "direct mode (aka real files instead of symlinks) [already done --joey]" 3 "start windows port now"]]
 
 References:
 
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 91fcb1e274..34ae925bee 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=no 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

close
diff --git a/doc/bugs/git-annex_is_slow_at_reading_file_content.mdwn b/doc/bugs/git-annex_is_slow_at_reading_file_content.mdwn
index f87496718d..2884e49447 100644
--- a/doc/bugs/git-annex_is_slow_at_reading_file_content.mdwn
+++ b/doc/bugs/git-annex_is_slow_at_reading_file_content.mdwn
@@ -53,3 +53,9 @@ NixOS 21.11
 
 
 [[!meta title="cryptonite does not use SHA instructions for sha256"]]
+
+> git-annex can now be built with the Botan build flag, which accellerates
+> SHA3 and also some other hashing. It will take a while for all builds
+> to have it, since the C++ library needs to be installed separately
+> from other dependencies. There is a build warning when building without
+> botab. [[done]] --[[Joey]]

correction
diff --git a/doc/bugs/blake3_hash_support/comment_6_86c121634d68400fffccd630dbce0b76._comment b/doc/bugs/blake3_hash_support/comment_6_86c121634d68400fffccd630dbce0b76._comment
index bfdc2c44d9..e7f1f8b7d6 100644
--- a/doc/bugs/blake3_hash_support/comment_6_86c121634d68400fffccd630dbce0b76._comment
+++ b/doc/bugs/blake3_hash_support/comment_6_86c121634d68400fffccd630dbce0b76._comment
@@ -3,7 +3,8 @@
  subject="""comment 6"""
  date="2026-06-09T19:44:56Z"
  content="""
-Another route might be to use botan, which supports blake3.
+Another route might be to use botan, once it supports blake3.
+
 There is some work toward using botan in
 [[git-annex_is_slow_at_reading_file_content]]
 and once it's used, adding blake3 would just be adding another hash.
diff --git a/doc/bugs/git-annex_is_slow_at_reading_file_content/comment_15_6b7596c7a54c9d6d014998ec31478840._comment b/doc/bugs/git-annex_is_slow_at_reading_file_content/comment_15_6b7596c7a54c9d6d014998ec31478840._comment
index f1e206356c..9b7493afb9 100644
--- a/doc/bugs/git-annex_is_slow_at_reading_file_content/comment_15_6b7596c7a54c9d6d014998ec31478840._comment
+++ b/doc/bugs/git-annex_is_slow_at_reading_file_content/comment_15_6b7596c7a54c9d6d014998ec31478840._comment
@@ -3,6 +3,6 @@
  subject="""comment 15"""
  date="2026-06-09T19:46:55Z"
  content="""
-botan includes the blake3 hash, so [[blake3_hash_support]] could happen
+Once botan includes the blake3 hash, [[blake3_hash_support]] could happen
 more or less for free..
 """]]

comment
diff --git a/doc/bugs/git-annex_is_slow_at_reading_file_content/comment_15_6b7596c7a54c9d6d014998ec31478840._comment b/doc/bugs/git-annex_is_slow_at_reading_file_content/comment_15_6b7596c7a54c9d6d014998ec31478840._comment
new file mode 100644
index 0000000000..f1e206356c
--- /dev/null
+++ b/doc/bugs/git-annex_is_slow_at_reading_file_content/comment_15_6b7596c7a54c9d6d014998ec31478840._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 15"""
+ date="2026-06-09T19:46:55Z"
+ content="""
+botan includes the blake3 hash, so [[blake3_hash_support]] could happen
+more or less for free..
+"""]]

botan
diff --git a/doc/bugs/blake3_hash_support/comment_6_86c121634d68400fffccd630dbce0b76._comment b/doc/bugs/blake3_hash_support/comment_6_86c121634d68400fffccd630dbce0b76._comment
new file mode 100644
index 0000000000..bfdc2c44d9
--- /dev/null
+++ b/doc/bugs/blake3_hash_support/comment_6_86c121634d68400fffccd630dbce0b76._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 6"""
+ date="2026-06-09T19:44:56Z"
+ content="""
+Another route might be to use botan, which supports blake3.
+There is some work toward using botan in
+[[git-annex_is_slow_at_reading_file_content]]
+and once it's used, adding blake3 would just be adding another hash.
+"""]]

comment
diff --git a/doc/bugs/git-annex_is_slow_at_reading_file_content/comment_14_badb9dcd455bf56a43c0035894084631._comment b/doc/bugs/git-annex_is_slow_at_reading_file_content/comment_14_badb9dcd455bf56a43c0035894084631._comment
new file mode 100644
index 0000000000..e5e6cf0d3b
--- /dev/null
+++ b/doc/bugs/git-annex_is_slow_at_reading_file_content/comment_14_badb9dcd455bf56a43c0035894084631._comment
@@ -0,0 +1,22 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 14"""
+ date="2026-06-09T19:34:42Z"
+ content="""
+Botan3 can also accellerate sha1 and sha3 (on machines with AVX-512).
+<https://botan.randombit.net/handbook/hardware_acceleration.html>
+
+I think it would make sense at this point to have a botan build flag
+that uses botan for all hashing. It may be that it's faster at other
+hashes than crypton too.
+
+The build flag would need to not be default, since it needs the C++ library
+to be installed. They seem to be moving toward vendoring the C++ library
+in the haskell package:
+<https://github.com/haskell-cryptography/botan/issues/98>
+At which point the build flag could become the default.
+
+I have some early work toward this in the `botan` branch. A proof of
+concept implementation for SHA256 keys benchmarked roughly  
+twice as fast on my laptop.
+"""]]

done
diff --git a/doc/todo/avoid_uncessary_synced_branches.mdwn b/doc/todo/avoid_uncessary_synced_branches.mdwn
index 9158ee8a9b..c0060a170f 100644
--- a/doc/todo/avoid_uncessary_synced_branches.mdwn
+++ b/doc/todo/avoid_uncessary_synced_branches.mdwn
@@ -14,3 +14,7 @@ distributed mode. Once those are merged, it should be deleted.
 And a bare repository should never have a synced/master branch.
 
 (synced/git-annex is another matter, and is fine as it is) --[[Joey]]
+
+> [[done]] --[[Joey]]
+
+[[!tag projects/INM7]]

reduce synced/ branch clutter in centralized git repo workflow
Avoid pushing synced/master branch when a remote accepts a push of
master.
Avoid creating a local synced/master branch when git-annex sync (or
related commands) is run.
Some code that assumed the existance of the local synced/master branch
had to be fixed.
This is to simplify workflows with centralized git repos, where a branch
might get rebased or rewound and force pushed. The existence of
synced/master (etc) branches complicates that because the user has to
clean them up.
This will mean that a decentralized situation, where pushes are to
non-bare git repos that don't allow updating their master, will
need a different workflow for such forced pushes. But, in a
decentralized situation, it's harder to rewrite history anyway.
So a difference in workflow is ok.
synced/git-annex is not affected.
diff --git a/CHANGELOG b/CHANGELOG
index 98636bc58e..d67b0b8930 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,9 @@
 git-annex (10.20260602) UNRELEASED; urgency=medium
 
+  * Improve handling of synced/master and similar branches, by
+    only creating such branches when necessary to push to a non-bare
+    remote, and by removing the local synced branch once its changes
+    are merged.
   * put: New command.
   * move: Fix bug where an interrupted command other than move could
     be treated as an interrupted move, resulting in dropping content
diff --git a/Command/Sync.hs b/Command/Sync.hs
index b7332bcf16..b545c8cdd0 100644
--- a/Command/Sync.hs
+++ b/Command/Sync.hs
@@ -518,9 +518,6 @@ updateBranches forpull forpush (Just branch, madj) = do
 				when forpull $
 					updateadjustedbranch adj
 			Nothing -> noop
-	
-	-- Update the sync branch to match the new state of the branch
-	inRepo $ updateBranch (syncBranch branch) (fromViewBranch branch)
   where
 	-- The adjusted branch may need to be updated, if the adjustment
 	-- is not stable, and the usual configuration does not update it.
@@ -635,7 +632,7 @@ pullThirdPartyPopulated o remote
 	
 	wantpull = remoteAnnexPull (Remote.gitconfig remote)
 
-{- The remote probably has both a master and a synced/master branch.
+{- The remote often has both a master and a synced/master branch.
  - Which to merge from? Well, the master has whatever latest changes
  - were committed (or pushed changes, if this is a bare remote),
  - while the synced/master may have changes that some
@@ -646,20 +643,22 @@ mergeRemote remote currbranch mergeconfig o = ifM isBareRepo
 	, case currbranch of
 		(Nothing, _) -> do
 			branch <- inRepo Git.Branch.currentUnsafe
-			mergelisted (pure (branchlist branch))
-		(Just branch, _) -> do
-			inRepo $ updateBranch (syncBranch branch) branch
-			mergelisted (tomerge (branchlist (Just branch)))
+			domerge =<< branchlist branch
+		(Just branch, _) ->
+			domerge
+				=<< changedfrom branch
+				=<< branchlist (Just branch)
 	)
   where
-	mergelisted getlist =
-		merge currbranch mergeconfig o Git.Branch.ManualCommit
-			=<< map (remoteBranch remote) <$> getlist
-	tomerge = filterM (changed remote)
-	branchlist Nothing = []
+	domerge = merge currbranch mergeconfig o Git.Branch.ManualCommit
+	changedfrom branch = filterM (inRepo . Git.Branch.changed branch)
+	branchlist Nothing = pure []
 	branchlist (Just branch)
-		| is_branchView branch = []
-		| otherwise = [origBranch branch, syncBranch branch]
+		| is_branchView branch = pure []
+		| otherwise = filterM (inRepo . Git.Ref.exists)
+			[ remoteBranch remote (origBranch branch)
+			, remoteBranch remote (syncBranch branch)
+			]
 
 pushRemote :: SyncOptions -> Remote -> CurrBranch -> CommandStart
 pushRemote _o _remote (Nothing, _) = stop
@@ -685,9 +684,14 @@ pushRemote o remote (Just branch, _) = do
 	needpush mainbranch
 		| remoteAnnexReadOnly gc = return False
 		| not (remoteAnnexPush gc) = return False
-		| otherwise = anyM (newer remote) $ catMaybes
-			[ syncBranch <$> mainbranch
-			, Just (Annex.Branch.name)
+		| otherwise = anyM id $ concat
+			[ case mainbranch of
+				Just b ->
+					[ newer remote b b True
+					, newer remote (syncBranch b) b False
+					]
+				Nothing -> []
+			, [ newer remote Annex.Branch.name Annex.Branch.name True ]
 			]
 	-- Older remotes on crippled filesystems may not have a
 	-- post-receive hook set up, so when updateInstead emulation
@@ -716,7 +720,7 @@ pushRemote o remote (Just branch, _) = do
  - branch directly to it, so that cloning/pulling will get it.
  - On the other hand, if it's not bare, pushing to the checked out branch
  - will generally fail (except with receive.denyCurrentBranch=updateInstead),
- - and this is why we push to its syncBranch.
+ - and this is when it's useful to push to its syncBranch.
  -
  - Git offers no way to tell if a remote is bare or not, so both methods
  - are tried.
@@ -725,8 +729,9 @@ pushRemote o remote (Just branch, _) = do
  - github may treat the first branch pushed to a new repository as the
  - default branch for that repository.
  -
- - The sync push first sends the synced/master branch,
- - and then forces the update of the remote synced/git-annex branch.
+ - The sync push first sends the synced/master branch
+ - (when the direct push failed), and then forces the update of 
+ - the remote synced/git-annex branch.
  -
  - The forcing is necessary if a transition has rewritten the git-annex branch.
  - Normally any changes to the git-annex branch get pulled and merged before
@@ -755,16 +760,18 @@ pushBranch remote mbranch ms g = do
 				pushparams True
 					[ Git.fromRef $ Git.Ref.base $ origBranch branch ]
 			let p' = p { std_err = CreatePipe }
-			bracket (createProcess p') cleanupProcess $ \h -> do
+			exitcode <- bracket (createProcess p') cleanupProcess $ \h -> do
 				filterstderr [] (stderrHandle h) (processHandle h)
-				void $ waitForProcess (processHandle h)
-			return True
-		Nothing -> return False
-				
-	syncpush directpushed =  do
+				waitForProcess (processHandle h)
+			return (True, exitcode == ExitSuccess)
+		Nothing -> return (False, False)
+	
+	syncpush (directpushed, directbranchupdated) =  do
 		let p = flip Git.Command.gitCreateProcess g $
 			pushparams (not directpushed) $ catMaybes
-				[ (syncrefspec . origBranch) <$> mbranch
+				[ if not directbranchupdated
+					then (syncrefspec . origBranch) <$> mbranch
+					else Nothing
 				, Just $ Git.Branch.forcePush $ syncrefspec Annex.Branch.name
 				]
 		-- stderr is relayed through a pipe so that the push
@@ -832,20 +839,12 @@ mergeAnnex = do
 	void Annex.Branch.forceUpdate
 	stop
 
-changed :: Remote -> Git.Ref -> Annex Bool
-changed remote b = do
-	let r = remoteBranch remote b
-	ifM (inRepo $ Git.Ref.exists r)
-		( inRepo $ Git.Branch.changed b r
-		, return False
-		)
-
-newer :: Remote -> Git.Ref -> Annex Bool
-newer remote b = do
-	let r = remoteBranch remote b
+newer :: Remote -> Git.Ref -> Git.Ref -> Bool -> Annex Bool
+newer remote rb b dne = do
+	let r = remoteBranch remote rb
 	ifM (inRepo $ Git.Ref.exists r)
 		( inRepo $ Git.Branch.changed r b
-		, return True
+		, return dne
 		)
 
 {- Without --all, only looks at files in the work tree.
diff --git a/doc/git-annex-push.mdwn b/doc/git-annex-push.mdwn
index 6a1509a86e..886cf4ae6a 100644
--- a/doc/git-annex-push.mdwn
+++ b/doc/git-annex-push.mdwn
@@ -20,10 +20,8 @@ it's helpful to add remotes for nearby machines that you want
 to access the same annexed content. Pushing to a non-bare remote will
 not normally update the remote's current branch with changes from the local
 repository. (Unless the remote is configured with
-receive.denyCurrentBranch=updateInstead.)
-
-To make working with such non-bare remotes easier, this command pushes not
-only local `master` to remote `master`, but also to remote `synced/master`
+receive.denyCurrentBranch=updateInstead.) Instead, when it detects
+such a remote, this command pushes to the remote's `synced/master`
 (and similar with other branches). When `git-annex pull` (or `git-annex
 sync`) is later run on the remote, it will merge the `synced/` branches
 that were pushed to it.
@@ -118,14 +116,6 @@ See [[git-annex-preferred-content]](1).
   and pushed by `git-annex push` or `git-annex sync`. This option
   prevents all other activities.
 
-  This can come in handy when you've pushed a change to remotes and now
-  want to reset your master branch back before that change. So you
-  run `git reset` and force-push the master branch to remotes, only
-  to find that the next `git annex merge` or `git annex pull` brings the
-  changes back. Why? Because the `synced/master` branch is hanging
-  around and still has the change in it. Cleaning up the `synced/` branches
-  prevents that problem.
-
 * Also the [[git-annex-common-options]](1) can be used.
 
 # SEE ALSO
diff --git a/doc/sync.mdwn b/doc/sync.mdwn
index 2caae47c43..7b17ab5edf 100644
--- a/doc/sync.mdwn
+++ b/doc/sync.mdwn
@@ -20,8 +20,10 @@ When you run `git annex sync`, it merges the `synced/master` branch
 into `master`, receiving anything that's been pushed to it. (If there is a
 conflict in this merge, [[automatic_conflict_resolution]] is used to

(Diff truncated)
todo
diff --git a/doc/todo/avoid_uncessary_synced_branches.mdwn b/doc/todo/avoid_uncessary_synced_branches.mdwn
new file mode 100644
index 0000000000..9158ee8a9b
--- /dev/null
+++ b/doc/todo/avoid_uncessary_synced_branches.mdwn
@@ -0,0 +1,16 @@
+Sending synced/master to a bare git remote is unnecessary because master
+can be pushed directly to it.
+
+This would be good to avoid, because the existence of synced branches
+can complicate situations such as a force push of master that
+discards commits from the tip of the branch. In that case, the user needs
+to worry about cleaning up the synced/master branches, on remote and the
+remote tracking branches, and the local synced/master branch, 
+to avoid them getting merged back in.
+
+Ideally the local synced/master branch should only exist when there are
+un-merged changes that have been pushed from another repository in
+distributed mode. Once those are merged, it should be deleted.
+And a bare repository should never have a synced/master branch.
+
+(synced/git-annex is another matter, and is fine as it is) --[[Joey]]

remove out of date para about --content
diff --git a/doc/sync.mdwn b/doc/sync.mdwn
index eb86133f46..2caae47c43 100644
--- a/doc/sync.mdwn
+++ b/doc/sync.mdwn
@@ -40,10 +40,4 @@ The workflow for using `git annex sync` is simple:
 * Next time you're working on a different clone of that repository,
   run `git annex sync` to update it.
 
-Note that by default, `git annex sync` only synchronises the git
-repositories, but does not transfer the content of annexed files. If you
-want to fully synchronise two repositories content,
-you can use `git annex sync --content`. You can also configure
-[[preferred_content]] settings to make only some content be synced.
-
 See [[git-annex-sync]] for the command's man page.

document --force
diff --git a/doc/git-annex-adjust.mdwn b/doc/git-annex-adjust.mdwn
index bd2964779d..eccdf843cf 100644
--- a/doc/git-annex-adjust.mdwn
+++ b/doc/git-annex-adjust.mdwn
@@ -119,6 +119,16 @@ and will also propagate commits back to the original branch.
   set the `annex.adjustedbranchrefresh` config. Or use `git-annex sync
   --content`, which updates the branch after transferring content.
 
+* `--force`
+
+  Allow overwriting an existing adjusted branch with a new version.
+
+  For example, suppose you started with branch foo checked out
+  and used  `git-annex adjust --unlock`. But then foo was rebased,
+  and you checked out that new version of foo. Running `git-annex adjust
+  --unlock` again would fail because of the existing adjusted branch.
+  Using `--force` would overwrite that adjusted branch.
+
 * Also the [[git-annex-common-options]](1) can be used.
 
 # SEE ALSO

poll vote (My phone (or MP3 player))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 1e5b6c172f..91fcb1e274 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

add
diff --git a/doc/security/p2phttp_denial_of_service.mdwn b/doc/security/p2phttp_denial_of_service.mdwn
new file mode 100644
index 0000000000..b8720a46bd
--- /dev/null
+++ b/doc/security/p2phttp_denial_of_service.mdwn
@@ -0,0 +1,9 @@
+The `git-annex p2phttp` server could be caused to hang by a simple HEAD
+request to it. This denial of service attack was fixed in version
+10.20260525.
+
+Before version 10.20251114, `p2phttp` had several other bugs that could
+cause it to stall. That version also fixed a file descriptor leak.
+
+Since p2phttp is still somewhat new, and the impact is only a DOS,
+no CVEs were assigned for these.

update
diff --git a/doc/thanks/list b/doc/thanks/list
index 0e8eb59c97..22e43a3de4 100644
--- a/doc/thanks/list
+++ b/doc/thanks/list
@@ -130,3 +130,4 @@ joshingly,
 Melody Tolly, 
 username, 
 Steffen Vogel, 
+Jan, 

Revert "update"
This reverts commit 2afeeebc41d447ad6f51d662ec9b3662f21c5c95.
script broken
diff --git a/doc/thanks/list b/doc/thanks/list
index 50f233b5ca..0e8eb59c97 100644
--- a/doc/thanks/list
+++ b/doc/thanks/list
@@ -130,101 +130,3 @@ joshingly,
 Melody Tolly, 
 username, 
 Steffen Vogel, 
-AlexS, 
-Amitai Schleier, 
-Andrew, 
-anon, 
-Anthony DeRobertis, 
-Anton Grensjö, 
-Anton Y, 
-Art S, 
-Arthur Lutz, 
-Ben, 
-Boyd Stephen Smith, 
-Bruno BEAUFILS, 
-Caleb Allen, 
-Calvin Beck, 
-Chris Lamb, 
-Christian Diller, 
-Christopher Baines, 
-Christopher Goes, 
-Dave Pifke, 
-don haraway, 
-DuncanConstruction, 
-encryptio, 
-Eric Drechsel, 
-ers35, 
-Evgeni Ku, 
-Farran, 
-Fernando Jimenez, 
-fiatjaf, 
-Francois Marier, 
-Gabriel Lee, 
-Greg Grossmeier, 
-HeartBreak KB Official, 
-Ignacio, 
-Ilya Baryshnikov, 
-James (purpleidea), 
-James Valleroy, 
-Jan, 
-Jason Woofenden, 
-Jeff Goeke-Smith, 
-Jim, 
-Jo, 
-Johannes Schlatow, 
-John Peloquin, 
-Jon D, 
-jose_d, 
-Josh Taylor, 
-Josh Tilles, 
-Lacnic, 
-Land Reaver, 
-Lee Hinman, 
-Lee-kai Wang, 
-Lukas Scheel-Platz, 
-Lukas Waymann, 
-Madison McGaffin, 
-Maggie Hess, 
-Matthew Willcockson, 
-Matthias Urlichs, 
-Matthieu, 
-Mattias J, 
-Mica, 
-Michal Politowski, 
-Mika Pflüger, 
-mo, 
-Mohit Munjani, 
-Nahum Shalman, 
-NinjaTrappeur, 
-Ole-Morten Duesund, 
-Paul Tötterman, 
-Pedro Luz, 
-Pig Monkey, 
-Renaud Casenave-Péré, 
-rjbl, 
-Ryan Newton, 
-Rémi Vanicat, 
-Sergey Karpukhin, 
-Shane-o, 
-Shawn Butts, 
-Stan Yamane, 
-Stephan Burkhardt, 
-Stephan Meister, 
-SvenDowideit, 
-sww, 
-Teremu HAMBLIN, 
-Thom May, 
-Thomas Ferris Nicolaisen, 
-Thomas Hochstein, 
-Thomas Schwinge, 
-Tim Howes, 
-tj, 
-Trent Lloyd, 
-Tyler Cipriani, 
-Valeria_, 
-Walltime, 
-wawatcz, 
-Will Hughes, 
-Willard Korfhage, 
-wzhd, 
-Zoé Cassiopée Gauthier, 

update
diff --git a/doc/thanks/list b/doc/thanks/list
index 0e8eb59c97..50f233b5ca 100644
--- a/doc/thanks/list
+++ b/doc/thanks/list
@@ -130,3 +130,101 @@ joshingly,
 Melody Tolly, 
 username, 
 Steffen Vogel, 
+AlexS, 
+Amitai Schleier, 
+Andrew, 
+anon, 
+Anthony DeRobertis, 
+Anton Grensjö, 
+Anton Y, 
+Art S, 
+Arthur Lutz, 
+Ben, 
+Boyd Stephen Smith, 
+Bruno BEAUFILS, 
+Caleb Allen, 
+Calvin Beck, 
+Chris Lamb, 
+Christian Diller, 
+Christopher Baines, 
+Christopher Goes, 
+Dave Pifke, 
+don haraway, 
+DuncanConstruction, 
+encryptio, 
+Eric Drechsel, 
+ers35, 
+Evgeni Ku, 
+Farran, 
+Fernando Jimenez, 
+fiatjaf, 
+Francois Marier, 
+Gabriel Lee, 
+Greg Grossmeier, 
+HeartBreak KB Official, 
+Ignacio, 
+Ilya Baryshnikov, 
+James (purpleidea), 
+James Valleroy, 
+Jan, 
+Jason Woofenden, 
+Jeff Goeke-Smith, 
+Jim, 
+Jo, 
+Johannes Schlatow, 
+John Peloquin, 
+Jon D, 
+jose_d, 
+Josh Taylor, 
+Josh Tilles, 
+Lacnic, 
+Land Reaver, 
+Lee Hinman, 
+Lee-kai Wang, 
+Lukas Scheel-Platz, 
+Lukas Waymann, 
+Madison McGaffin, 
+Maggie Hess, 
+Matthew Willcockson, 
+Matthias Urlichs, 
+Matthieu, 
+Mattias J, 
+Mica, 
+Michal Politowski, 
+Mika Pflüger, 
+mo, 
+Mohit Munjani, 
+Nahum Shalman, 
+NinjaTrappeur, 
+Ole-Morten Duesund, 
+Paul Tötterman, 
+Pedro Luz, 
+Pig Monkey, 
+Renaud Casenave-Péré, 
+rjbl, 
+Ryan Newton, 
+Rémi Vanicat, 
+Sergey Karpukhin, 
+Shane-o, 
+Shawn Butts, 
+Stan Yamane, 
+Stephan Burkhardt, 
+Stephan Meister, 
+SvenDowideit, 
+sww, 
+Teremu HAMBLIN, 
+Thom May, 
+Thomas Ferris Nicolaisen, 
+Thomas Hochstein, 
+Thomas Schwinge, 
+Tim Howes, 
+tj, 
+Trent Lloyd, 
+Tyler Cipriani, 
+Valeria_, 
+Walltime, 
+wawatcz, 
+Will Hughes, 
+Willard Korfhage, 
+wzhd, 
+Zoé Cassiopée Gauthier, 

close
diff --git a/doc/todo/add_--json-progress_support_in_push_and_pull.mdwn b/doc/todo/add_--json-progress_support_in_push_and_pull.mdwn
index 4e18897297..ed8c677093 100644
--- a/doc/todo/add_--json-progress_support_in_push_and_pull.mdwn
+++ b/doc/todo/add_--json-progress_support_in_push_and_pull.mdwn
@@ -1,3 +1,6 @@
 The pull and push commands do not have --json-progress support.  Please add.
 
 [[!tag projects/INM7]]
+
+> [[wontfix|done]] but see my comment at the end for alternatives.
+> --[[Joey]]

update my comment
diff --git a/doc/todo/add_--json-progress_support_in_push_and_pull/comment_10_71fa338205298e0c929d16e470684e02._comment b/doc/todo/add_--json-progress_support_in_push_and_pull/comment_10_71fa338205298e0c929d16e470684e02._comment
index 2bdeacf1cb..a19ac50449 100644
--- a/doc/todo/add_--json-progress_support_in_push_and_pull/comment_10_71fa338205298e0c929d16e470684e02._comment
+++ b/doc/todo/add_--json-progress_support_in_push_and_pull/comment_10_71fa338205298e0c929d16e470684e02._comment
@@ -1,46 +1,53 @@
 [[!comment format=mdwn
  username="joey"
  subject="""comment 10"""
- date="2026-05-29T13:59:25Z"
+ date="2026-06-04T13:59:25Z"
  content="""
-Summarizing the current status of this todo, if someone wants 
-the equivilant of `git-annex pull --json $someremote`, they can run:
+I have done some work adjacent to this todo, implmenting a `--wanted`
+option and `git-annex put` command.
+
+Now, if someone wants  the equivilant of `git-annex pull --json
+$someremote`, they can run:
 
 	git-annex pull --no-content $someremote
-	git-annex get --auto --json --from $someremote
-	git-annex drop --auto --json
+	git-annex get --wanted --json --from $someremote
+	git-annex drop --wanted --json
 
-The first command above does not have json output, but outputs the
+The `git-annex pull` above does not have json output, but outputs the
 usual `git pull` messages for the user to deal with as they see fit.
 
 And, if someone wants the equivilant of `git-annex push --json
 $someremote`, they can run:
 
-	git-annex copy --auto --json --to $someremote
-	git-annex drop --auto --json --from $someremote
+	git-annex copy --wanted --json --to $someremote
+	git-annex drop --wanted --json --from $someremote
 	git-annex push --no-content $someremote
 
-The last command above does not have json output, but outputs the
+The `git-annex push` above does not have json output, but outputs the
 usual `git push` messages for the user to deal with as they see fit.
 
-The argument for adding --json to pull/push now seems to be reduced.
-But not gone entirely I suppose. 
-
-For example, `git-annex push` without
-a remote pushes content to all remotes that want it. That needs
-multiple runs of `git-annex copy`, one per remote. Notice that
-in the `git-annex pull` case, it can be made to operate on all remotes:
+Similarly, the equivilant of `git-annex pull --json` with no remote
+specified:
 
 	git-annex pull --no-content
-	git-annex get --auto --json
-	git-annex drop --auto --json
+	git-annex get --wanted --json
+	git-annex drop --wanted --json
+
+And, the equivilant of `git-annex push` without a remote specified:
+
+	git-annex put --wanted --json
+	git-annex drop --wanted --json
+	git-annex push --no-content
+
+So, the argument for adding --json to pull/push now seems to be reduced.
+Here are all the arguments I can think of for still doing that:
 
-This seems like an argument for adding a `git-annex put`
-command that copies to all remotes that want content. Which is nicely
-symmetric with `git-annex get`.
+* These command sequences won't behave completely identically to pull/push
+  in all configurations, eg they don't look at `remote.<name>.annex-pull`
+  and `remote.<name>.annex-push` configs.
 
-Another difference is that a single `git-annex push` or `pull`
-(or `sync`) does less work than several git-annex commands.
-In the scripts above, git-annex has to traverse the tree twice.
-That is a pretty small difference in overhead.
+* A single `git-annex push` or `pull` (or `sync`) does less work than several
+  git-annex commands. In the command sequences above, git-annex has to
+  traverse the tree twice. That is a pretty small difference in overhead
+  though most of the time.
 """]]
diff --git a/doc/todo/add_--json-progress_support_in_push_and_pull/comment_11_ee87ba949945446dc324981bdf92329f._comment b/doc/todo/add_--json-progress_support_in_push_and_pull/comment_11_ee87ba949945446dc324981bdf92329f._comment
deleted file mode 100644
index 727dd711d3..0000000000
--- a/doc/todo/add_--json-progress_support_in_push_and_pull/comment_11_ee87ba949945446dc324981bdf92329f._comment
+++ /dev/null
@@ -1,17 +0,0 @@
-[[!comment format=mdwn
- username="joey"
- subject="""comment 11"""
- date="2026-05-29T15:09:31Z"
- content="""
-Hmm, `git-annex get --auto` and `git-annex copy --auto` don't just check
-preferred content, they will also make a copy if numcopies is not satisfied
-for the file.
-
-That's something that `git-annex pull` and `git-annex push` don't do.
-
-I think it would be a good idea to add a `--wanted` option to commands
-that support `--auto`. It would only operate on preferred content, avoiding
-making copies only to work toward satisfying numcopies.
-
-Update: Added `--wanted`
-"""]]

decided this is not actually a bug
diff --git a/doc/bugs/push_and_put_-J_OnlyActionOn_problem.mdwn b/doc/bugs/push_and_put_-J_OnlyActionOn_problem.mdwn
index 6458160415..e4da8e7d3f 100644
--- a/doc/bugs/push_and_put_-J_OnlyActionOn_problem.mdwn
+++ b/doc/bugs/push_and_put_-J_OnlyActionOn_problem.mdwn
@@ -1,4 +1,29 @@
 `git-annex put -J2` with the same file needing to go to 2 remotes only runs
-1 transfer at a time. Same with `git-annex push -J2`.
+1 transfer at a time. Same with `git-annex push -J2` and `git-annex copy
+-J2`.
 
 This is because of the use of OnlyActionOn. --[[Joey]]
+
+> That is the thing that prevents it, but there is a good reason for it to
+> be prevented in some cases. Consider `git-annex copy -J2 --auto`, where
+> there are 2 archive remotes. It should only send to 1 of them, not
+> to both. And if the first one it tries to send to fails, it ought to
+> send to the other one. So the second thread needs to block waiting on the
+> first thread and check again if the action ought to be run. Which is what
+> OnlyActionOn does.
+> 
+> So this seems to only make sense to do if preferred content is not being
+> checked, or if the remote does not have a preferred content expression,
+> or if the preferred content expression does not use "copies=" or
+> similar.
+> 
+> Also, this doesn't fully serialize eg `put -J2`, as long as there are
+> several files to put. The 1st file will be sent to the 1st remote
+> and concurrently the 2nd file to the 2nd remote, and once those transfers
+> complete it will move on to sending the 1st file to the 2nd remote and
+> the 2nd file to the 1st remote.
+> 
+> Is it worth supporting this where it can be supported? It might seem
+> like inconsistent behavior.
+> 
+> I think not. [[done]] --[[Joey]]

typo
diff --git a/doc/git-annex-put.mdwn b/doc/git-annex-put.mdwn
index 831fa146b1..13eb06515c 100644
--- a/doc/git-annex-put.mdwn
+++ b/doc/git-annex-put.mdwn
@@ -25,7 +25,7 @@ Paths of files or directories to operate on can be specified.
 * `--auto`
 
   Only send files to remotes that want them, or when there are not
-  yet have the desired number of copies.
+  yet the desired number of copies.
 
 * `--fast`
 

this is a bug
diff --git a/doc/todo/push_and_put_-J_OnlyActionOn_problem.mdwn b/doc/bugs/push_and_put_-J_OnlyActionOn_problem.mdwn
similarity index 100%
rename from doc/todo/push_and_put_-J_OnlyActionOn_problem.mdwn
rename to doc/bugs/push_and_put_-J_OnlyActionOn_problem.mdwn

fix todo
diff --git a/doc/todo/push_and_put_-J_OnlyActionOn_problem.mdwn b/doc/todo/push_and_put_-J_OnlyActionOn_problem.mdwn
new file mode 100644
index 0000000000..6458160415
--- /dev/null
+++ b/doc/todo/push_and_put_-J_OnlyActionOn_problem.mdwn
@@ -0,0 +1,4 @@
+`git-annex put -J2` with the same file needing to go to 2 remotes only runs
+1 transfer at a time. Same with `git-annex push -J2`.
+
+This is because of the use of OnlyActionOn. --[[Joey]]
diff --git a/doc/todo/put_--json_lacks_uuid.mdwn b/doc/todo/put_--json_lacks_uuid.mdwn
index 387a780f6f..f60e04fac1 100644
--- a/doc/todo/put_--json_lacks_uuid.mdwn
+++ b/doc/todo/put_--json_lacks_uuid.mdwn
@@ -1,2 +1,4 @@
 `git annex put --json` does not include the uuid of the remote that content
 is sent to. It ought to, since it can send to multiple remotes. --[[Joey]]
+
+> [[fixed|done]] --[[Joey]]
diff --git a/doc/todo/put_-J_OnlyActionOn_problem.mdwn b/doc/todo/put_-J_OnlyActionOn_problem.mdwn
deleted file mode 100644
index b4f189c485..0000000000
--- a/doc/todo/put_-J_OnlyActionOn_problem.mdwn
+++ /dev/null
@@ -1,5 +0,0 @@
-`git-annex put -J2` with the same file needing to go to 2 remotes only runs
-1 transfer at a time. This is because of the use of OnlyActionOn in
-Command.Move. --[[Joey]]
-
-[[fixed|done]] --[[Joey]] 

include uuid in put --json
diff --git a/Command/Copy.hs b/Command/Copy.hs
index bbc08fda04..247584327b 100644
--- a/Command/Copy.hs
+++ b/Command/Copy.hs
@@ -64,16 +64,16 @@ seek' o fto = startConcurrency (Command.Move.stages fto) $ do
 	case batchOption o of
 		NoBatch -> withKeyOptions
 			(keyOptions o) (autoMode o || wantedMode o) seeker
-			(commandAction . startKey o fto)
+			(commandAction . startKey o fto id)
 			(withFilesInGitAnnex ww seeker)
 			=<< workTreeItems ww (copyFiles o)
 		Batch fmt -> batchOnly (keyOptions o) (copyFiles o) $
-			batchAnnexed fmt seeker (startKey o fto)
+			batchAnnexed fmt seeker (startKey o fto id)
   where
 	ww = WarnUnmatchLsFiles "copy"
 	
 	seeker = AnnexedFileSeeker
-		{ startAction = startSingle $ const $ start o fto
+		{ startAction = startSingle $ const $ start o fto id
 		, checkContentPresent = case fto of
 			FromOrToRemote (FromRemote _) -> Just False
 			FromOrToRemote (ToRemote _) -> Just True
@@ -86,8 +86,15 @@ seek' o fto = startConcurrency (Command.Move.stages fto) $ do
 {- A copy is just a move that does not delete the source file.
  - However, auto mode avoids unnecessary copies, and avoids getting or
  - sending non-preferred content. -}
-start :: CopyOptions -> FromToHereOptions -> SeekInput -> OsPath -> Key -> CommandStart
-start o fto si file key = do
+start
+	:: CopyOptions
+	-> FromToHereOptions
+	-> (ActionItem -> ActionItem)
+	-> SeekInput
+	-> OsPath
+	-> Key
+	-> CommandStart
+start o fto fai si file key = do
 	ru <- case fto of
 		FromOrToRemote (ToRemote dest) -> getru dest
 		FromOrToRemote (FromRemote _) -> pure Nothing
@@ -95,13 +102,26 @@ start o fto si file key = do
 		FromRemoteToRemote _ dest -> getru dest
 		FromAnywhereToRemote dest -> getru dest
 	lu <- prepareLiveUpdate ru key AddingKey
-	start' lu o fto si file key
+
+	start' lu o fto afile si file key ai
   where
 	getru dest = Just . Remote.uuid <$> getParsed dest
+	
+	afile = AssociatedFile (Just file)
+	ai = fai $ mkActionItem (key, afile)
 
-start' :: LiveUpdate -> CopyOptions -> FromToHereOptions -> SeekInput -> OsPath -> Key -> CommandStart
-start' lu o fto si file key = stopUnless shouldCopy $ 
-	Command.Move.start lu fto (moveAction o) si file key
+start'
+	:: LiveUpdate
+	-> CopyOptions
+	-> FromToHereOptions
+	-> AssociatedFile
+	-> SeekInput
+	-> OsPath
+	-> Key
+	-> ActionItem
+	-> CommandStart
+start' lu o fto afile si file key ai = stopUnless shouldCopy $ 
+	Command.Move.start' lu fto (moveAction o) afile si key ai
   where
 	shouldCopy
 		| autoMode o = want <||> numCopiesCheck file key (<)
@@ -119,5 +139,11 @@ start' lu o fto si file key = stopUnless shouldCopy $
 			wantGetBy lu False (Just key) (AssociatedFile (Just file))
 	checkwantget = wantGet lu False (Just key) (AssociatedFile (Just file))
 
-startKey :: CopyOptions -> FromToHereOptions -> (SeekInput, Key, ActionItem) -> CommandStart
-startKey o fto = Command.Move.startKey NoLiveUpdate fto (moveAction o)
+startKey
+	:: CopyOptions
+	-> FromToHereOptions
+	-> (ActionItem -> ActionItem)
+	-> (SeekInput, Key, ActionItem)
+	-> CommandStart
+startKey o fto fai (si, k, ai) = 
+	Command.Move.startKey NoLiveUpdate fto (moveAction o) (si, k, fai ai)
diff --git a/Command/Put.hs b/Command/Put.hs
index ed4b70d256..d32e9b9245 100644
--- a/Command/Put.hs
+++ b/Command/Put.hs
@@ -46,13 +46,13 @@ seek o = startConcurrency commandStages $ do
 	let seeker = AnnexedFileSeeker
 		{ startAction = \_ si p k ->
 			return $ flip map contentremotes $ \r ->
-				Command.Copy.start co (to r) si p k
+				Command.Copy.start co (to r) (fai r) si p k
 		, checkContentPresent = Just True
 		, usesLocationLog = True
 		}
 	let keyaction v = 
 		return $ flip map contentremotes $ \r ->
-			Command.Copy.startKey co (to r) v
+			Command.Copy.startKey co (to r) (fai r) v
 	case batchOption o of
 		NoBatch -> withKeyOptions
 			(keyOptions o) (autoMode o || wantedMode o) seeker
@@ -75,3 +75,9 @@ seek o = startConcurrency commandStages $ do
 		}
 	
 	to = FromOrToRemote . ToRemote . ReadyParse
+
+	-- Since put can send to remotes of its choosing, suppliment the
+	-- ActionItem with the uuid. This makes the json include the remote
+	-- uuid.
+	fai r ai = ActionItemForUUID (Remote.uuid r) ai
+
diff --git a/Types/ActionItem.hs b/Types/ActionItem.hs
index 53e7822a74..84e26b8e2f 100644
--- a/Types/ActionItem.hs
+++ b/Types/ActionItem.hs
@@ -1,6 +1,6 @@
 {- items that a command can act on
  -
- - Copyright 2016-2023 Joey Hess <id@joeyh.name>
+ - Copyright 2016-2026 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU AGPL version 3 or higher.
  -}
@@ -29,6 +29,7 @@ data ActionItem
 	| ActionItemUUID UUID StringContainingQuotedPath
 	-- ^ UUID with a description or name of the repository
 	| ActionItemOther (Maybe StringContainingQuotedPath)
+	| ActionItemForUUID UUID ActionItem
 	| OnlyActionOn Key ActionItem
 	-- ^ Use to avoid more than one thread concurrently processing the
 	-- same Key.
@@ -85,6 +86,7 @@ actionItemDesc (ActionItemTreeFile f) = QuotedPath f
 actionItemDesc (ActionItemUUID _ desc) = desc
 actionItemDesc (ActionItemOther Nothing) = mempty
 actionItemDesc (ActionItemOther (Just v)) = v
+actionItemDesc (ActionItemForUUID _ ai) = actionItemDesc ai
 actionItemDesc (OnlyActionOn _ ai) = actionItemDesc ai
 
 actionItemKey :: ActionItem -> Maybe Key
@@ -95,21 +97,26 @@ actionItemKey (ActionItemFailedTransfer t _) = Just (transferKey t)
 actionItemKey (ActionItemTreeFile _) = Nothing
 actionItemKey (ActionItemUUID _ _) = Nothing
 actionItemKey (ActionItemOther _) = Nothing
+actionItemKey (ActionItemForUUID _ ai) = actionItemKey ai
 actionItemKey (OnlyActionOn _ ai) = actionItemKey ai
 
 actionItemFile :: ActionItem -> Maybe OsPath
 actionItemFile (ActionItemAssociatedFile (AssociatedFile af) _) = af
 actionItemFile (ActionItemTreeFile f) = Just f
 actionItemFile (ActionItemUUID _ _) = Nothing
+actionItemFile (ActionItemForUUID _ ai) = actionItemFile ai
 actionItemFile (OnlyActionOn _ ai) = actionItemFile ai
 actionItemFile _ = Nothing
 
 actionItemUUID :: ActionItem -> Maybe UUID
 actionItemUUID (ActionItemUUID uuid _) = Just uuid
+actionItemUUID (ActionItemForUUID uuid _) = Just uuid
+actionItemUUID (OnlyActionOn _ ai) = actionItemUUID ai
 actionItemUUID _ = Nothing
 
 actionItemTransferDirection :: ActionItem -> Maybe Direction
 actionItemTransferDirection (ActionItemFailedTransfer t _) = Just $
 	transferDirection t
+actionItemTransferDirection (ActionItemForUUID _ ai) = actionItemTransferDirection ai
 actionItemTransferDirection (OnlyActionOn _ ai) = actionItemTransferDirection ai
 actionItemTransferDirection _ = Nothing
diff --git a/doc/todo/put_-J_OnlyActionOn_problem.mdwn b/doc/todo/put_-J_OnlyActionOn_problem.mdwn
index 88cb783723..b4f189c485 100644
--- a/doc/todo/put_-J_OnlyActionOn_problem.mdwn
+++ b/doc/todo/put_-J_OnlyActionOn_problem.mdwn
@@ -1,3 +1,5 @@
 `git-annex put -J2` with the same file needing to go to 2 remotes only runs
 1 transfer at a time. This is because of the use of OnlyActionOn in
 Command.Move. --[[Joey]]
+
+[[fixed|done]] --[[Joey]] 

poll vote (Amazon S3 (done))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index a92964f743..1e5b6c172f 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 38 "Google Drive"]]
+[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Google Drive)
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index d1bdb81324..a92964f743 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 20 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 38 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (OpenStack SWIFT)
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index be9e779b44..d1bdb81324 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 30 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 20 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Tahoe-LAFS)
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 05feed7d11..be9e779b44 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 30 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (My phone (or MP3 player))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 0090d9b91d..05feed7d11 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 11 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Box.com (done))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 859324f795..0090d9b91d 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 14 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 11 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Amazon Glacier (done))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 1e5b6c172f..859324f795 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 14 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Amazon S3 (done))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index a92964f743..1e5b6c172f 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 38 "Google Drive"]]
+[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Google Drive)
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index d1bdb81324..a92964f743 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 20 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 38 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (OpenStack SWIFT)
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index be9e779b44..d1bdb81324 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 30 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 20 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Tahoe-LAFS)
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 05feed7d11..be9e779b44 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 30 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (My phone (or MP3 player))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 0090d9b91d..05feed7d11 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 11 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Box.com (done))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 859324f795..0090d9b91d 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 14 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 11 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Amazon Glacier (done))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 1e5b6c172f..859324f795 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 14 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Amazon S3 (done))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 05feed7d11..1e5b6c172f 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (My phone (or MP3 player))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 1e5b6c172f..05feed7d11 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Amazon S3 (done))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index a92964f743..1e5b6c172f 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 38 "Google Drive"]]
+[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Google Drive)
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index d1bdb81324..a92964f743 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 20 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 38 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (OpenStack SWIFT)
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index be9e779b44..d1bdb81324 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 30 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 20 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Tahoe-LAFS)
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index d1bdb81324..be9e779b44 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 20 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 30 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (OpenStack SWIFT)
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 05feed7d11..d1bdb81324 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 20 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (My phone (or MP3 player))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 0090d9b91d..05feed7d11 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 11 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they