Recent changes to this wiki:

Added a comment: Credential is rejected!
diff --git a/doc/bugs/auth/comment_2_8179e7dc00caf4fea5e47f515f940820._comment b/doc/bugs/auth/comment_2_8179e7dc00caf4fea5e47f515f940820._comment
new file mode 100644
index 0000000000..4516085fb6
--- /dev/null
+++ b/doc/bugs/auth/comment_2_8179e7dc00caf4fea5e47f515f940820._comment
@@ -0,0 +1,81 @@
+[[!comment format=mdwn
+ username="mih"
+ avatar="http://cdn.libravatar.org/avatar/f881df265a423e4f24eff27c623148fd"
+ subject="Credential is rejected!"
+ date="2026-05-16T10:09:34Z"
+ content="""
+I wanted to investigate further and added a credential \"helper\" that documents what was queried
+
+```
+cat << EOT > /usr/local/bin/git-credential-echo
+#!/usr/bin/env bash
+exec cat >&2
+EOT
+chmod +x /usr/local/bin/git-credential-echo
+git config --global --add credential.helper echo
+```
+
+I also switched from `annex push` to `annex copy` (because this is the aspect that failed). I now see (what I could have seen in the log above already). The issue is not that the credential isn't retrieved properly. It is actually rejected, and the superficial/original error is the result of prompting for another valid credential. Here is the log of a copy call:
+
+```
+git annex --debug copy -t origin .
+[2026-05-16 10:01:43.073507233] (Utility.Process) process [639] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"show-ref\",\"git-annex\"]
+[2026-05-16 10:01:43.075431464] (Utility.Process) process [639] done ExitSuccess
+[2026-05-16 10:01:43.075932187] (Utility.Process) process [640] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"show-ref\",\"--hash\",\"refs/heads/git-annex\"]
+[2026-05-16 10:01:43.077917969] (Utility.Process) process [640] done ExitSuccess
+[2026-05-16 10:01:43.078259638] (Annex.Branch) read remote.log
+[2026-05-16 10:01:43.079214293] (Utility.Process) process [641] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"cat-file\",\"--batch\"]
+[2026-05-16 10:01:43.081261767] (Annex.Branch) read proxy.log
+[2026-05-16 10:01:43.082419578] (Utility.Process) process [642] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"ls-files\",\"--stage\",\"-z\",\"--error-unmatch\",\"--\",\".\"]
+[2026-05-16 10:01:43.082798858] (Utility.Process) process [643] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"cat-file\",\"--batch-check=%(objectname) %(objecttype) %(objectsize)\",\"--buffer\"]
+[2026-05-16 10:01:43.083296281] (Utility.Process) process [644] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"cat-file\",\"--batch=%(objectname) %(objecttype) %(objectsize)\",\"--buffer\"]
+[2026-05-16 10:01:43.083778403] (Utility.Process) process [641] done ExitSuccess
+[2026-05-16 10:01:43.086359241] (Utility.Process) process [645] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"cat-file\",\"--batch=%(objectname) %(objecttype) %(objectsize)\",\"--buffer\"]
+copy static/graph.json (to origin...) [2026-05-16 10:01:43.210382475] (Utility.Process) process [647] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"-c\",\"filter.annex.smudge=\",\"-c\",\"filter.annex.clean=\",\"-c\",\"filter.annex.process=\",\"write-tree\"]
+[2026-05-16 10:01:43.214071033] (Utility.Process) process [647] done ExitSuccess
+[2026-05-16 10:01:43.214666158] (Utility.Process) process [648] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"show-ref\",\"--hash\",\"refs/annex/last-index\"]
+[2026-05-16 10:01:43.218272853] (Utility.Process) process [648] done ExitSuccess
+[2026-05-16 10:01:43.218310804] (Database.Keys) reconcileStaged start
+[2026-05-16 10:01:43.218806637] (Utility.Process) process [649] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"cat-file\",\"--batch-check=%(objectname) %(objecttype) %(objectsize)\",\"--buffer\"]
+[2026-05-16 10:01:43.219327951] (Utility.Process) process [650] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"cat-file\",\"--batch=%(objectname) %(objecttype) %(objectsize)\",\"--buffer\"]
+[2026-05-16 10:01:43.219921627] (Utility.Process) process [651] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"-c\",\"filter.annex.smudge=\",\"-c\",\"filter.annex.clean=\",\"-c\",\"filter.annex.process=\",\"-c\",\"diff.external=\",\"diff\",\"ee47aafecb91c163b0eb9e7ef1a35b07d5b1e0b9\",\"8ea4ce9a4065396e07306bc2f30bcf295837ad6f\",\"--raw\",\"-z\",\"--no-abbrev\",\"-G/annex/objects/\",\"--no-renames\",\"--ignore-submodules=all\",\"--no-textconv\",\"--no-ext-diff\"]
+[2026-05-16 10:01:43.223295855] (Utility.Process) process [651] done ExitSuccess
+[2026-05-16 10:01:43.225251807] (Database.Handle) commitDb start
+[2026-05-16 10:01:43.225610276] (Database.Handle) commitDb done
+[2026-05-16 10:01:43.225676608] (Utility.Process) process [650] done ExitSuccess
+[2026-05-16 10:01:43.2257297] (Utility.Process) process [649] done ExitSuccess
+[2026-05-16 10:01:43.226178161] (Utility.Process) process [652] call: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"update-ref\",\"refs/annex/last-index\",\"8ea4ce9a4065396e07306bc2f30bcf295837ad6f\"]
+[2026-05-16 10:01:43.228765129] (Utility.Process) process [652] done ExitSuccess
+[2026-05-16 10:01:43.22880699] (Database.Keys) reconcileStaged end
+[2026-05-16 10:01:43.246406143] (Utility.Process) process [653] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"credential\",\"fill\"]
+[2026-05-16 10:01:43.253477499] (Utility.Process) process [653] done ExitSuccess
+[2026-05-16 10:01:43.274667127] (Utility.Process) process [656] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"credential\",\"reject\"]
+protocol=https
+host=hub.psychoinformatics.de
+username=myuser
+password=***
+[2026-05-16 10:01:43.2873155] (Utility.Process) process [656] done ExitSuccess
+25%   31.98 KiB        70 MiB/s 0s
+100%  126.9 KiB       179 MiB/s 0s[2026-05-16 10:01:43.330200019] (Utility.Process) process [662] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"credential\",\"fill\"]
+protocol=https
+host=hub.psychoinformatics.de
+fatal: could not read Username for 'https://hub.psychoinformatics.de': No such device or address
+[2026-05-16 10:01:43.341958838] (Utility.Process) process [662] done ExitFailure 128
+                                  
+  user error (git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"credential\",\"fill\"] exited 128)
+[2026-05-16 10:01:43.357710043] (Utility.Process) process [668] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"credential\",\"fill\"]
+protocol=https
+host=hub.psychoinformatics.de
+fatal: could not read Username for 'https://hub.psychoinformatics.de': No such device or address
+[2026-05-16 10:01:43.369272597] (Utility.Process) process [668] done ExitFailure 128
+                                  
+  user error (git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"credential\",\"fill\"] exited 128)
+                                  
+failed
+[2026-05-16 10:01:43.371334491] (Utility.Process) process [645] done ExitSuccess
+[2026-05-16 10:01:43.371445144] (Utility.Process) process [644] done ExitSuccess
+[2026-05-16 10:01:43.371533016] (Utility.Process) process [643] done ExitSuccess
+[2026-05-16 10:01:43.371599238] (Utility.Process) process [642] done ExitSuccess
+copy: 1 failed
+```
+"""]]

diff --git a/doc/bugs/auth.mdwn b/doc/bugs/auth.mdwn
index 187c59fb10..170aa3be31 100644
--- a/doc/bugs/auth.mdwn
+++ b/doc/bugs/auth.mdwn
@@ -64,3 +64,5 @@ My expectation would be that a git-annex push would be able to trigger the oauth
 ### What version of git-annex are you using? On what operating system?
 
 `git-annex version: 10.20260316-gf01ba218ffb36e8607516d9895dfaeaeaf101a05` on Debian forky/sid
+
+[[!tag projects/INM7]]

Added a comment: Appears to be unrelated to oauth credential helper
diff --git a/doc/bugs/auth/comment_1_b807003c8b2a120354a490a92821ca03._comment b/doc/bugs/auth/comment_1_b807003c8b2a120354a490a92821ca03._comment
new file mode 100644
index 0000000000..9e69489453
--- /dev/null
+++ b/doc/bugs/auth/comment_1_b807003c8b2a120354a490a92821ca03._comment
@@ -0,0 +1,139 @@
+[[!comment format=mdwn
+ username="mih"
+ avatar="http://cdn.libravatar.org/avatar/f881df265a423e4f24eff27c623148fd"
+ subject="Appears to be unrelated to oauth credential helper"
+ date="2026-05-16T09:33:09Z"
+ content="""
+I am now seeing the \"same\" problem in a different context, where no 3rd-party credential helper is involved.
+
+Concretely, I have a Forgejo actions workflow that manually pre-fills a credential via
+
+```
+git config --global credential.helper cache
+git credential approve <<EOF
+protocol=https
+host=hub.psychoinformatics.de
+username=${{ forgejo.actor }}
+password=${{ forgejo.token }}
+EOF
+```
+
+This appears to be working, as confirmed by
+
+```
+git credential fill
+protocol=https
+host=hub.psychoinformatics.de
+```
+
+which returns
+
+```
+username=myuser
+password=***
+```
+
+However, running `git annex push` immediately afterwards has the git-push parts working, but the internal `credential fill` fail with `fatal: could not read Username for 'https://hub.psychoinformatics.de': No such device or address` (full log below).
+
+```
++ git annex --debug push
+[2026-05-16 09:19:30.185331705] (Utility.Process) process [597] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"show-ref\",\"git-annex\"]
+[2026-05-16 09:19:30.189155934] (Utility.Process) process [597] done ExitSuccess
+[2026-05-16 09:19:30.189885413] (Utility.Process) process [598] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"show-ref\",\"--hash\",\"refs/heads/git-annex\"]
+[2026-05-16 09:19:30.192024278] (Utility.Process) process [598] done ExitSuccess
+[2026-05-16 09:19:30.192633434] (Annex.Branch) read config.log
+[2026-05-16 09:19:30.193750572] (Utility.Process) process [599] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"cat-file\",\"--batch\"]
+[2026-05-16 09:19:30.195842697] (Utility.Process) process [600] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"symbolic-ref\",\"-q\",\"HEAD\"]
+[2026-05-16 09:19:30.197578872] (Utility.Process) process [600] done ExitSuccess
+[2026-05-16 09:19:30.198023783] (Utility.Process) process [601] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"show-ref\",\"refs/heads/main\"]
+[2026-05-16 09:19:30.19984727] (Utility.Process) process [601] done ExitSuccess
+[2026-05-16 09:19:30.200553359] (Utility.Process) process [602] call: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"show-ref\",\"--verify\",\"-q\",\"refs/heads/synced/main\"]
+[2026-05-16 09:19:30.20216315] (Utility.Process) process [602] done ExitFailure 1
+[2026-05-16 09:19:30.202230582] (Annex.Branch) read remote.log
+[2026-05-16 09:19:30.202912609] (Annex.Branch) read proxy.log
+[2026-05-16 09:19:30.20410367] (Utility.Process) process [603] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"show-ref\",\"git-annex\"]
+[2026-05-16 09:19:30.20603299] (Utility.Process) process [603] done ExitSuccess
+[2026-05-16 09:19:30.206394769] (Utility.Process) process [604] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"show-ref\",\"--hash\",\"refs/heads/git-annex\"]
+[2026-05-16 09:19:30.208407081] (Utility.Process) process [604] done ExitSuccess
+[2026-05-16 09:19:30.209282774] (Utility.Process) process [605] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"show-ref\",\"--hash\",\"refs/heads/git-annex\"]
+[2026-05-16 09:19:30.211913422] (Utility.Process) process [605] done ExitSuccess
+[2026-05-16 09:19:30.212857467] (Utility.Process) process [606] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"log\",\"-z\",\"--pretty=format:%H %ct\",\"--raw\",\"--no-abbrev\",\"--no-renames\",\"--reverse\",\"--follow\",\"668c5aa16d4e9ee0af8fc63f4fbb3e7cfb4b93d4\",\"--\",\"migrate.tree\"]
+[2026-05-16 09:19:30.215528925] (Utility.Process) process [606] done ExitSuccess
+[2026-05-16 09:19:30.216522001] (Utility.Process) process [607] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"ls-files\",\"--stage\",\"-z\",\"--error-unmatch\",\"--\"]
+[2026-05-16 09:19:30.217095856] (Utility.Process) process [608] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"cat-file\",\"--batch-check=%(objectname) %(objecttype) %(objectsize)\",\"--buffer\"]
+[2026-05-16 09:19:30.217808254] (Utility.Process) process [609] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"cat-file\",\"--batch=%(objectname) %(objecttype) %(objectsize)\",\"--buffer\"]
+[2026-05-16 09:19:30.218346408] (Utility.Process) process [599] done ExitSuccess
+[2026-05-16 09:19:30.222153637] (Utility.Process) process [610] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"cat-file\",\"--batch=%(objectname) %(objecttype) %(objectsize)\",\"--buffer\"]
+[2026-05-16 09:19:30.228726336] (Annex.Branch) read trust.log
+[2026-05-16 09:19:30.229328452] (Utility.Process) process [611] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"cat-file\",\"--batch\"]
+[2026-05-16 09:19:30.230981234] (Annex.Branch) read cluster.log
+[2026-05-16 09:19:30.237149214] (Utility.Process) process [614] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"-c\",\"filter.annex.smudge=\",\"-c\",\"filter.annex.clean=\",\"-c\",\"filter.annex.process=\",\"write-tree\"]
+[2026-05-16 09:19:30.239369771] (Utility.Process) process [614] done ExitSuccess
+[2026-05-16 09:19:30.239845993] (Utility.Process) process [615] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"show-ref\",\"--hash\",\"refs/annex/last-index\"]
+[2026-05-16 09:19:30.241848385] (Utility.Process) process [615] done ExitSuccess
+[2026-05-16 09:19:30.242685967] (Utility.Process) process [616] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"check-attr\",\"-z\",\"--stdin\",\"annex.backend\",\"annex.largefiles\",\"annex.numcopies\",\"annex.mincopies\",\"--\"]
+[2026-05-16 09:19:30.244064203] (Annex.Branch) read numcopies.log
+[2026-05-16 09:19:30.244322359] (Annex.Branch) read mincopies.log
+[2026-05-16 09:19:30.257332835] (Annex.Branch) read group.log
+[2026-05-16 09:19:30.25750822] (Annex.Branch) read group-preferred-content.log
+[2026-05-16 09:19:30.257716505] (Annex.Branch) read preferred-content.log
+[2026-05-16 09:19:30.257939851] (Annex.Branch) read required-content.log
+[2026-05-16 09:19:30.258732681] (Annex.Branch) read 455/e88/MD5E-s129943--06caaa82dc6cfdd358085974adbbe8d3.json.log
+copy static/graph.json (to origin...) [2026-05-16 09:19:30.378214958] (Utility.Process) process [617] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"credential\",\"fill\"]
+[2026-05-16 09:19:30.383551986] (Utility.Process) process [617] done ExitSuccess
+[2026-05-16 09:19:30.404495517] (Utility.Process) process [620] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"credential\",\"reject\"]
+[2026-05-16 09:19:30.40926853] (Utility.Process) process [620] done ExitSuccess
+25%   31.98 KiB        68 MiB/s 0s
+100%  126.9 KiB       177 MiB/s 0s[2026-05-16 09:19:30.450818263] (Utility.Process) process [623] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"credential\",\"fill\"]
+fatal: could not read Username for 'https://hub.psychoinformatics.de': No such device or address
+[2026-05-16 09:19:30.455457733] (Utility.Process) process [623] done ExitFailure 128
+                                  
+  user error (git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"credential\",\"fill\"] exited 128)
+[2026-05-16 09:19:30.473680804] (Utility.Process) process [626] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"credential\",\"fill\"]
+fatal: could not read Username for 'https://hub.psychoinformatics.de': No such device or address
+[2026-05-16 09:19:30.47933976] (Utility.Process) process [626] done ExitFailure 128
+                                  
+  user error (git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"credential\",\"fill\"] exited 128)
+                                  
+failed
+[2026-05-16 09:19:30.481071965] (Utility.Process) process [610] done ExitSuccess
+[2026-05-16 09:19:30.481128386] (Utility.Process) process [609] done ExitSuccess
+[2026-05-16 09:19:30.481169867] (Utility.Process) process [608] done ExitSuccess
+[2026-05-16 09:19:30.481201948] (Utility.Process) process [607] done ExitSuccess
+[2026-05-16 09:19:30.481629439] (Utility.Process) process [629] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"symbolic-ref\",\"-q\",\"HEAD\"]
+[2026-05-16 09:19:30.483084607] (Utility.Process) process [629] done ExitSuccess
+[2026-05-16 09:19:30.483620051] (Utility.Process) process [630] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"show-ref\",\"refs/heads/main\"]
+[2026-05-16 09:19:30.486919556] (Utility.Process) process [630] done ExitSuccess
+[2026-05-16 09:19:30.487433589] (Utility.Process) process [631] call: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"branch\",\"-f\",\"synced/main\",\"refs/heads/main\"]
+[2026-05-16 09:19:30.490124219] (Utility.Process) process [631] done ExitSuccess
+[2026-05-16 09:19:30.490606621] (Utility.Process) process [632] call: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"show-ref\",\"--verify\",\"-q\",\"refs/remotes/origin/synced/main\"]
+[2026-05-16 09:19:30.493191278] (Utility.Process) process [632] done ExitFailure 1
+                                  
+push origin 
+                                  
+[2026-05-16 09:19:30.493862885] (Utility.Process) process [633] call: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"push\",\"origin\",\"main\"]
+Everything up-to-date
+[2026-05-16 09:19:30.622077877] (Utility.Process) process [633] done ExitSuccess
+[2026-05-16 09:19:30.622889428] (Utility.Process) process [637] call: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"push\",\"origin\",\"main:synced/main\",\"+git-annex:synced/git-annex\"]
+remote: 
+remote: Create a new pull request for 'synced/main':        
+remote:   https://hub.psychoinformatics.de/www/www-from-model/compare/main...synced/main        
+remote: 
+remote: 
+remote: Create a new pull request for 'synced/git-annex':        
+remote:   https://hub.psychoinformatics.de/www/www-from-model/compare/main...synced/git-annex        
+remote: 
+To https://hub.psychoinformatics.de/www/www-from-model
+ * [new branch]      main -> synced/main
+ * [new branch]      git-annex -> synced/git-annex
+[2026-05-16 09:19:31.549596008] (Utility.Process) process [637] done ExitSuccess
+[2026-05-16 09:19:31.55045735] (Utility.Process) process [644] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"push\",\"origin\",\"git-annex\"]
+[2026-05-16 09:19:31.662607017] (Utility.Process) process [644] done ExitSuccess
+                                  
+ok
+[2026-05-16 09:19:31.663427958] (Utility.Process) process [611] done ExitSuccess
+[2026-05-16 09:19:31.663999003] (Utility.Process) process [616] done ExitSuccess
+push: 1 failed
+⚙️ [runner]: exitcode '1': failure
+```
+"""]]

daily
diff --git a/doc/install/OSX.mdwn b/doc/install/OSX.mdwn
index 853af761fb..6f87155477 100644
--- a/doc/install/OSX.mdwn
+++ b/doc/install/OSX.mdwn
@@ -18,7 +18,7 @@ several more. Handy if you don't otherwise have git installed.
 
 ## autobuilds
 
-An hourly autobuild is also available, run by [[Joey]]:
+A daily autobuild is also available, run by [[Joey]]:
 
 * [git-annex.dmg](https://downloads.kitenet.net/git-annex/autobuild/x86_64-apple-catalina/git-annex.dmg)
   ([build logs](https://github.com/joeyh/gitannexbuilder/actions/workflows/build-macos.yaml?query=Build+git-annex+on+macOS))
diff --git a/doc/install/Windows.mdwn b/doc/install/Windows.mdwn
index 87ab7d0492..4dcab5c598 100644
--- a/doc/install/Windows.mdwn
+++ b/doc/install/Windows.mdwn
@@ -13,7 +13,7 @@ current status.
 
 ## autobuilds
 
-An hourly autobuild is also available, run by [[Joey]]:
+A daily autobuild is also available, run by [[Joey]]:
 
 * Windows 10 [download](https://downloads.kitenet.net/git-annex/autobuild/windows/git-annex-installer.exe)
   ([build logs](https://github.com/joeyh/gitannexbuilder/actions?query=workflow%3A%22Build+git-annex+on+Windows%22))

fix badge link
diff --git a/doc/builds.mdwn b/doc/builds.mdwn
index 89aece78e2..13947e0ffd 100644
--- a/doc/builds.mdwn
+++ b/doc/builds.mdwn
@@ -45,7 +45,7 @@
 </iframe>
 <h2>OSX</h2>
 <a href="https://github.com/joeyh/gitannexbuilder/actions?query=workflow%3A%22Build+git-annex+on+macOS%22">
-<img src="https://github.com/joeyh/gitannexbuilder/actions/workflows/build-macos.yaml/badge.svg">
+<img src="https://github.com/joeyh/gitannexbuilder/actions/workflows/build-macos-intel.yaml/badge.svg">
 </a>
 <h2>Windows</h2>
 <a href="https://github.com/joeyh/gitannexbuilder/actions?query=workflow%3A%22Build+git-annex+on+Windows%22">

OSX and Windows autobuilds now fully automated (I hope)
diff --git a/doc/install/OSX.mdwn b/doc/install/OSX.mdwn
index 846d602e6c..853af761fb 100644
--- a/doc/install/OSX.mdwn
+++ b/doc/install/OSX.mdwn
@@ -18,9 +18,7 @@ several more. Handy if you don't otherwise have git installed.
 
 ## autobuilds
 
-There is a [stopgap autobuilder](https://github.com/joeyh/gitannexbuilder) 
-run by Joey Hess. However, it is currently manually triggered and will 
-usually only be run shortly before a release.
+An hourly autobuild is also available, run by [[Joey]]:
 
 * [git-annex.dmg](https://downloads.kitenet.net/git-annex/autobuild/x86_64-apple-catalina/git-annex.dmg)
   ([build logs](https://github.com/joeyh/gitannexbuilder/actions/workflows/build-macos.yaml?query=Build+git-annex+on+macOS))
diff --git a/doc/install/Windows.mdwn b/doc/install/Windows.mdwn
index 391f8620b0..87ab7d0492 100644
--- a/doc/install/Windows.mdwn
+++ b/doc/install/Windows.mdwn
@@ -13,9 +13,7 @@ current status.
 
 ## autobuilds
 
-There is a [stopgap autobuilder](https://github.com/joeyh/gitannexbuilder) 
-run by Joey Hess. However, it is currently manually triggered and will 
-usually only be run shortly before a release.
+An hourly autobuild is also available, run by [[Joey]]:
 
 * Windows 10 [download](https://downloads.kitenet.net/git-annex/autobuild/windows/git-annex-installer.exe)
   ([build logs](https://github.com/joeyh/gitannexbuilder/actions?query=workflow%3A%22Build+git-annex+on+Windows%22))
diff --git a/doc/todo/new_windows_and_OSX_build_hosts_needed.mdwn b/doc/todo/new_windows_and_OSX_build_hosts_needed.mdwn
index b83d65c375..c8cdff95db 100644
--- a/doc/todo/new_windows_and_OSX_build_hosts_needed.mdwn
+++ b/doc/todo/new_windows_and_OSX_build_hosts_needed.mdwn
@@ -17,3 +17,5 @@ perhaps be blessed as the official builds. mih assures me those builds
 will contiue to be from git-annex master.
 
 --[[Joey]]
+
+> Set up <https://github.com/joeyh/gitannexbuilder> [[done]] --[[Joey]] 

stopgap OSX builds now available
diff --git a/doc/install/OSX.mdwn b/doc/install/OSX.mdwn
index 32ee0e856e..846d602e6c 100644
--- a/doc/install/OSX.mdwn
+++ b/doc/install/OSX.mdwn
@@ -18,8 +18,12 @@ several more. Handy if you don't otherwise have git installed.
 
 ## autobuilds
 
-No autobuilds are currently available, however there is a Appveyor CI
-[here](https://ci.appveyor.com/project/mih/git-annex).
+There is a [stopgap autobuilder](https://github.com/joeyh/gitannexbuilder) 
+run by Joey Hess. However, it is currently manually triggered and will 
+usually only be run shortly before a release.
+
+* [git-annex.dmg](https://downloads.kitenet.net/git-annex/autobuild/x86_64-apple-catalina/git-annex.dmg)
+  ([build logs](https://github.com/joeyh/gitannexbuilder/actions/workflows/build-macos.yaml?query=Build+git-annex+on+macOS))
 
 ## download security
 

Revert "remove OSX and Windows from sidebar"
This reverts commit 2728f1c0dd7a8493d74c33e3e3d643059e97cc22.
diff --git a/doc/builds.mdwn b/doc/builds.mdwn
index 9717923965..89aece78e2 100644
--- a/doc/builds.mdwn
+++ b/doc/builds.mdwn
@@ -18,6 +18,12 @@
 <h2>Linux arm64-ancient</h2>
 <iframe width=1024 height=40em scrolling=no frameborder=0 marginheight=0 marginwidth=0 src="https://downloads.kitenet.net/git-annex/autobuild/arm64-ancient/build-version">
 </iframe>
+<h2>OSX</h2>
+<iframe width=1024 height=40em scrolling=no frameborder=0 marginheight=0 marginwidth=0 src="https://downloads.kitenet.net/git-annex/autobuild/x86_64-apple-catalina/build-version">
+</iframe>
+<h2>Windows</h2>
+<iframe width=1024 height=40em scrolling=no frameborder=0 marginheight=0 marginwidth=0 src="https://downloads.kitenet.net/git-annex/autobuild/windows/build-version">
+</iframe>
 """]]
 
 # build logs

add stopgap Windows and OSX builds
diff --git a/doc/builds.mdwn b/doc/builds.mdwn
index 5a0f03134d..9717923965 100644
--- a/doc/builds.mdwn
+++ b/doc/builds.mdwn
@@ -37,5 +37,13 @@
 <h2>Linux arm64-ancient</h2>
 <iframe width=1024 scrolling=no frameborder=0 marginheight=0 marginwidth=0 src="https://downloads.kitenet.net/git-annex/autobuild/arm64-ancient/">
 </iframe>
+<h2>OSX</h2>
+<a href="https://github.com/joeyh/gitannexbuilder/actions?query=workflow%3A%22Build+git-annex+on+macOS%22">
+<img src="https://github.com/joeyh/gitannexbuilder/actions/workflows/build-macos.yaml/badge.svg">
+</a>
+<h2>Windows</h2>
+<a href="https://github.com/joeyh/gitannexbuilder/actions?query=workflow%3A%22Build+git-annex+on+Windows%22">
+<img src="https://github.com/joeyh/gitannexbuilder/actions/workflows/build-windows.yaml/badge.svg">
+</a>
 <h2>Appveyor</h2>
 <a href="https://ci.appveyor.com/project/mih/git-annex">here</a>

p2phttp: send User-Agent
Send git-annex (or other configured) User-Agent when connecting to
annex+http remotes.
diff --git a/CHANGELOG b/CHANGELOG
index dcd6f589f9..18521b8255 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -9,6 +9,8 @@ git-annex (10.20260422) UNRELEASED; urgency=medium
     from the remote.
   * push: When pushing to a bare git repository, display git push
     progress before the display of pushed branches.
+  * Send git-annex (or other configured) User-Agent when connecting to
+    annex+http remotes.
   * Support GIT_SSL_CAINFO, GIT_SSL_CAPATH, http.sslCAPath, and http.sslCAPath
     when connecting to https servers.
   * Linux standalone builds now bundle CA certs. They are used only when
diff --git a/P2P/Http/Client.hs b/P2P/Http/Client.hs
index 1588728850..6e9dc7c797 100644
--- a/P2P/Http/Client.hs
+++ b/P2P/Http/Client.hs
@@ -94,14 +94,19 @@ p2pHttpClientVersions' allowedversion rmt rmtrepo fallback clientaction =
 	case p2pHttpBaseUrl <$> remoteAnnexP2PHttpUrl (gitconfig rmt) of
 		Nothing -> error "internal"
 		Just baseurl -> do
-			mgr <- httpManager <$> getUrlOptions Nothing
-			let clientenv = mkClientEnv mgr baseurl
+			uo <- getUrlOptions (Just (gitconfig rmt))
+			let clientenv = mkClientEnv (httpManager uo) baseurl
+			let clientenv' = clientenv
+				{ makeClientRequest = \u r -> 
+					applyRequest uo
+						<$> makeClientRequest clientenv u r
+				}
 			ccv <- Annex.getRead Annex.gitcredentialcache
 			Git.CredentialCache cc <- liftIO $ atomically $
 				readTMVar ccv
 			case M.lookup (Git.CredentialBaseURL credentialbaseurl) cc of
-				Nothing -> go clientenv Nothing False Nothing versions
-				Just cred -> go clientenv (Just cred) True (credauth cred) versions
+				Nothing -> go clientenv' Nothing False Nothing versions
+				Just cred -> go clientenv' (Just cred) True (credauth cred) versions
   where
 	versions = filter allowedversion allProtocolVersions
 	go clientenv mcred credcached mauth (v:vs) = do
diff --git a/doc/bugs/p2phttp_requests_do_not_set_user-agent.mdwn b/doc/bugs/p2phttp_requests_do_not_set_user-agent.mdwn
index c07377d56e..16e0af6b2b 100644
--- a/doc/bugs/p2phttp_requests_do_not_set_user-agent.mdwn
+++ b/doc/bugs/p2phttp_requests_do_not_set_user-agent.mdwn
@@ -55,3 +55,4 @@ upgrade supported from repository versions: 0 1 2 3 4 5 6 7 8 9 10
 ### 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)
 
 
+> [[fixed|done]] --[[Joey]] 

stopgap windows autobuilder now available
diff --git a/doc/install/Windows.mdwn b/doc/install/Windows.mdwn
index b795d2919f..391f8620b0 100644
--- a/doc/install/Windows.mdwn
+++ b/doc/install/Windows.mdwn
@@ -13,8 +13,12 @@ current status.
 
 ## autobuilds
 
-No autobuilds are currently available, however there is a Appveyor CI
-[here](https://ci.appveyor.com/project/mih/git-annex).
+There is a [stopgap autobuilder](https://github.com/joeyh/gitannexbuilder) 
+run by Joey Hess. However, it is currently manually triggered and will 
+usually only be run shortly before a release.
+
+* Windows 10 [download](https://downloads.kitenet.net/git-annex/autobuild/windows/git-annex-installer.exe)
+  ([build logs](https://github.com/joeyh/gitannexbuilder/actions?query=workflow%3A%22Build+git-annex+on+Windows%22))
 
 ## download security
 

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
new file mode 100644
index 0000000000..ec02c06846
--- /dev/null
+++ b/doc/bugs/p2phttp_key_endpoints_stuck_after_2_head_requests.mdwn
@@ -0,0 +1,85 @@
+### Please describe the problem.
+
+Doing a HEAD request against the /git-annex/$uuid/key/$key endpoint and also any of the versioned key endpoints works the first time, but after that the p2phttp process stops answering any requests.
+
+This is independent of the values for `--jobs` and `--cpus`, so does not seem to be another case of blocked worker processes.
+
+
+### What steps will reproduce the problem?
+
+1. Serve a repository with p2phttp: `git -C . annex p2phttp --jobs 200 --cpus 4 --bind 127.0.0.1 --wideopen --port 54321 --debug`
+2. Do a HEAD request: `curl --head http://localhost:54321/git-annex/df5642e3-3777-42ac-8c40-f9c1c7264e66/key/MD5E-s5--2b00042f7481c7b056c4b410d28f33cf` (substitute uuid and key for valid values)
+3. Do the same HEAD request again, observe it getting stuck
+
+
+### What version of git-annex are you using? On what operating system?
+
+```
+git-annex version: 10.20260421-gd789e57311eca6bbf4949a6f22b44dd46aabb9b1
+build flags: Assistant Webapp Inotify TorrentParser MagicMime Benchmark Feeds Testsuite S3 WebDAV Servant OsPath
+dependency versions: aws-0.25.2 bloomfilter-2.0.1.3 crypton-1.0.4 DAV-1.3.4 feed-1.3.2.1 ghc-9.10.3 http-client-0.7.19 torrent-10000.1.3 uuid-1.3.16 yesod-1.6.2.1
+key/value backends: SHA256E SHA256 SHA512E SHA512 SHA224E SHA224 SHA384E SHA384 SHA3_256E SHA3_256 SHA3_512E SHA3_512 SHA3_224E SHA3_224 SHA3_384E SHA3_384 SKEIN256E SKEIN256 SKEIN512E SKEIN512 BLAKE2B256E BLAKE2B256 BLAKE2B512E BLAKE2B512 BLAKE2B160E BLAKE2B160 BLAKE2B224E BLAKE2B224 BLAKE2B384E BLAKE2B384 BLAKE2BP512E BLAKE2BP512 BLAKE2S256E BLAKE2S256 BLAKE2S160E BLAKE2S160 BLAKE2S224E BLAKE2S224 BLAKE2SP256E BLAKE2SP256 BLAKE2SP224E BLAKE2SP224 SHA1E SHA1 MD5E MD5 WORM URL GITBUNDLE GITMANIFEST VURL X*
+remote types: git gcrypt p2p S3 bup directory rsync web bittorrent webdav adb tahoe glacier ddar git-lfs httpalso borg rclone hook external compute mask
+operating system: linux x86_64
+supported repository versions: 8 9 10
+upgrade supported from repository versions: 0 1 2 3 4 5 6 7 8 9 10
+local repository version: 10
+```
+
+
+### Please provide any additional information below.
+
+p2phttp output:
+
+[[!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
+
+$ git -C . annex p2phttp --jobs 200 --cpus 4 --bind 127.0.0.1 --wideopen --port 54321 --debug
+[2026-05-15 11:20:23.895756881] (Utility.Process) process [652639] read: git ["--git-dir=.git","--work-tree=.","--literal-pathspecs","-c","annex.debug=true","show-ref","git-annex"]
+[2026-05-15 11:20:23.896781487] (Utility.Process) process [652639] done ExitSuccess
+[2026-05-15 11:20:23.896998219] (Utility.Process) process [652640] read: git ["--git-dir=.git","--work-tree=.","--literal-pathspecs","-c","annex.debug=true","show-ref","--hash","refs/heads/git-annex"]
+[2026-05-15 11:20:23.897894537] (Utility.Process) process [652640] done ExitSuccess
+[2026-05-15 11:20:23.89863384] (Utility.Process) process [652641] chat: git ["--git-dir=.git","--work-tree=.","--literal-pathspecs","-c","annex.debug=true","cat-file","--batch"]
+[2026-05-15 11:20:23.900090498] (Utility.Process) process [652642] read: git ["-c","safe.directory=*","-c","safe.bareRepository=all","config","--null","--list"] in "./../a1-bare"
+[2026-05-15 11:20:23.901180123] (Git.Config) git config read: [("",[""]),("alias.gone",["! git fetch -p && git for-each-ref --format '%(refname:short) %(upstream:track)' | awk '$2 == \"[gone]\" {print $1}' | xargs -r git branch -D"]),("alias.lol",["log --graph --decorate --pretty=oneline --abbrev-commit"]),("alias.lola",["log --graph --decorate --pretty=oneline --abbrev-commit --all"]),("alias.wdiff",["diff --color-words=."]),("annex.url",["annex+http://localhost:54321"]),("annex.uuid",["184144b2-f69b-46a2-80e2-58bfb149e11d"]),("annex.version",["10"]),("branch.sort",["-committerdate"]),("color.branch",["auto"]),("color.diff",["auto"]),("color.interactive",["auto"]),("color.status",["auto"]),("column.ui",["auto"]),("commit.verbose",["true"]),("core.bare",["true"]),("core.filemode",["true"]),("core.repositoryformatversion",["0"]),("credential.helper",["oauth -verbose","cache --timeout 21600"]),("credential.https://jugit.fz-juelich.de.oauthclientid",["9d539aa7c067a768bfea62e27daf6da2cd8c0242063f068508222404b94896e2"]),("datalad.create-sibling-ghlike.extra-remote-settings.atris.fz-juelich.de.annex-ignore",["false"]),("datalad.credential.demo.dataverse.org.last-used",["2025-02-27T10:03:48.565458"]),("datalad.credential.demo.dataverse.org.realm",["https://demo.dataverse.org/dataverse"]),("datalad.credential.demo.dataverse.org.type",["token"]),("diff.annextextdiff.command",["git annex diffdriver --text"]),("diff.colormoved",["true"]),("diff.wordregex",["."]),("filter.lfs.clean",["git-lfs clean -- %f"]),("filter.lfs.process",["git-lfs filter-process"]),("filter.lfs.required",["true"]),("filter.lfs.smudge",["git-lfs smudge -- %f"]),("http.sslcainfo",["/home/icg149/.pixi/envs/git/ssl/cacert.pem"]),("http.sslcapath",["/home/icg149/.pixi/envs/git/ssl/cacert.pem"]),("http.sslverify",["true"]),("init.defaultbranch",["main"]),("merge.conflictstyle",["diff3"]),("merge.mergiraf.driver",["mergiraf merge --git %O %A %B -s %S -x %X -y %Y -p %P -l %L"]),("merge.mergiraf.name",["mergiraf"]),("rebase.autosquash",["true"]),("rebase.autostash",["true"]),("rebase.updaterefs",["true"]),("rerere.autoupdate",["true"]),("rerere.enabled",["true"]),("safe.barerepository",["all"]),("safe.directory",["*"]),("tag.sort",["version:refname"]),("user.email",["m.risse@fz-juelich.de"]),("user.name",["Matthias Ri\223e"])]
+[2026-05-15 11:20:23.901462068] (Utility.Process) process [652642] done ExitSuccess
+[2026-05-15 11:20:23.901933159] (Annex.Branch) read proxy.log
+[2026-05-15 11:20:37.787308378] (P2P.IO) [http client] [ThreadId 20] P2P > GET 0  MD5E-s5--2b00042f7481c7b056c4b410d28f33cf
+[2026-05-15 11:20:37.787517924] (P2P.IO) [http server] [ThreadId 19] P2P < GET 0  MD5E-s5--2b00042f7481c7b056c4b410d28f33cf
+[2026-05-15 11:20:37.788184946] (Utility.Process) process [652703] read: git ["--git-dir=.git","--work-tree=.","--literal-pathspecs","-c","annex.debug=true","-c","filter.annex.smudge=","-c","filter.annex.clean=","-c","filter.annex.process=","write-tree"]
+[2026-05-15 11:20:37.790260868] (Utility.Process) process [652703] done ExitSuccess
+[2026-05-15 11:20:37.790588597] (Utility.Process) process [652704] read: git ["--git-dir=.git","--work-tree=.","--literal-pathspecs","-c","annex.debug=true","show-ref","--hash","refs/annex/last-index"]
+[2026-05-15 11:20:37.791806257] (Utility.Process) process [652704] done ExitSuccess
+[2026-05-15 11:20:37.792481433] (P2P.IO) [http server] [ThreadId 19] P2P > DATA 5
+[2026-05-15 11:20:37.792564378] (P2P.IO) [http client] [ThreadId 20] P2P < DATA 5
+
+
+# End of transcript or log.
+"""]]
+
+curl requests:
+
+[[!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
+
+$ curl --head http://localhost:54321/git-annex/df5642e3-3777-42ac-8c40-f9c1c7264e66/key/MD5E-s5--2b00042f7481c7b056c4b410d28f33cf
+HTTP/1.1 200 OK
+Date: Fri, 15 May 2026 09:20:37 GMT
+Server: Warp/3.4.9
+Content-Type: application/octet-stream
+X-git-annex-data-length: 5
+
+icg149@icg1911:~/Playground/c1$ curl --head http://localhost:54321/git-annex/df5642e3-3777-42ac-8c40-f9c1c7264e66/key/MD5E-s5--2b00042f7481c7b056c4b410d28f33cf
+[stuck]
+
+
+# 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)
+
+
+
+[[!tag projects/INM7]]

update
diff --git a/doc/todo/finish_sync_content_transition.mdwn b/doc/todo/finish_sync_content_transition.mdwn
index f7a552e939..f6369be5ff 100644
--- a/doc/todo/finish_sync_content_transition.mdwn
+++ b/doc/todo/finish_sync_content_transition.mdwn
@@ -16,3 +16,19 @@ transition.
 > Using the August 2025 debian stable release that included the warning as the
 > start point, I suggest September 2026 as the transition end date.
 > --[[Joey]]
+> 
+> > Now thinking I can avoid waiting that long, especially since the
+> > pending release has some pull/push drop behavior changes that would be
+> > well bundled with this change.
+> >
+> > Users who upgraded to Debian stable last September will have gotten 8
+> > months of warnings. And they will mostly not be upgrading to a new
+> > version of Debian until the next stable release, which will be in
+> > 2027. While some may choose to upgrade git-annex, there is not
+> > currently a backport so they would have to install eg linuxstandalone.
+> > 
+> > (Users of other distributions are on other schedules, but I generally
+> > take Debian stable as a benchmark of fairly slow updating users. And
+> > the timing of the warning being added right after the previous Debian
+> > stable release makes debian stable pretty much worst case for the
+> > timing of this.) --[[Joey]]

diff --git a/doc/bugs/p2phttp_requests_do_not_set_user-agent.mdwn b/doc/bugs/p2phttp_requests_do_not_set_user-agent.mdwn
index 591d997535..c07377d56e 100644
--- a/doc/bugs/p2phttp_requests_do_not_set_user-agent.mdwn
+++ b/doc/bugs/p2phttp_requests_do_not_set_user-agent.mdwn
@@ -13,6 +13,7 @@ Inspect the p2phttp traffic for the User-Agent header.
 ### What version of git-annex are you using? On what operating system?
 
 Client side:
+
 ```
 $ git annex version
 git-annex version: 10.20260420-g74cffe2f348afd81711fa9f69e165e04e11f1ef0
@@ -27,6 +28,7 @@ local repository version: 10
 ```
 
 Server side:
+
 ```
 # git annex version
 git-annex version: 10.20260316

diff --git a/doc/bugs/p2phttp_requests_do_not_set_user-agent.mdwn b/doc/bugs/p2phttp_requests_do_not_set_user-agent.mdwn
new file mode 100644
index 0000000000..591d997535
--- /dev/null
+++ b/doc/bugs/p2phttp_requests_do_not_set_user-agent.mdwn
@@ -0,0 +1,55 @@
+### Please describe the problem.
+
+<https://atris.fz-juelich.de> uses <https://iocaine.madhouse-project.org/> to protect against being overloaded by scrapers. I've whitelisted the `git-annex/` user agent to keep git-annex functional. Unfortunately it seems like git-annex isn't actually sending a user agent for p2phttp related requests (the user agent field as logged by iocaine is an empty string), and therefore my iocaine configuration broke git-annex operations via p2phttp.
+
+For now I've implemented a path-based workaround allowing all requests to the p2phttp endpoints under `https://atris.fz-juelich.de/git-annex-p2phttp/` irrespective of user agent, so everything is working, but it still looks like a bug.
+
+
+### What steps will reproduce the problem?
+
+Inspect the p2phttp traffic for the User-Agent header. 
+
+
+### What version of git-annex are you using? On what operating system?
+
+Client side:
+```
+$ git annex version
+git-annex version: 10.20260420-g74cffe2f348afd81711fa9f69e165e04e11f1ef0
+build flags: Assistant Webapp Inotify DBus DesktopNotify TorrentParser MagicMime Benchmark Feeds Testsuite S3 WebDAV Servant OsPath
+dependency versions: aws-0.24.4 bloomfilter-2.0.1.3 crypton-1.0.4 DAV-1.3.4 feed-1.3.2.1 ghc-9.10.3 http-client-0.7.19 torrent-10000.1.3 uuid-1.3.16 yesod-1.6.2.1
+key/value backends: SHA256E SHA256 SHA512E SHA512 SHA224E SHA224 SHA384E SHA384 SHA3_256E SHA3_256 SHA3_512E SHA3_512 SHA3_224E SHA3_224 SHA3_384E SHA3_384 SKEIN256E SKEIN256 SKEIN512E SKEIN512 BLAKE2B256E BLAKE2B256 BLAKE2B512E BLAKE2B512 BLAKE2B160E BLAKE2B160 BLAKE2B224E BLAKE2B224 BLAKE2B384E BLAKE2B384 BLAKE2BP512E BLAKE2BP512 BLAKE2S256E BLAKE2S256 BLAKE2S160E BLAKE2S160 BLAKE2S224E BLAKE2S224 BLAKE2SP256E BLAKE2SP256 BLAKE2SP224E BLAKE2SP224 SHA1E SHA1 MD5E MD5 WORM URL GITBUNDLE GITMANIFEST VURL X*
+remote types: git gcrypt p2p S3 bup directory rsync web bittorrent webdav adb tahoe glacier ddar git-lfs httpalso borg rclone hook external compute mask
+operating system: linux x86_64
+supported repository versions: 8 9 10
+upgrade supported from repository versions: 0 1 2 3 4 5 6 7 8 9 10
+local repository version: 10
+```
+
+Server side:
+```
+# git annex version
+git-annex version: 10.20260316
+build flags: Assistant Webapp Inotify DBus DesktopNotify TorrentParser MagicMime Benchmark Feeds Testsuite S3 WebDAV Servant OsPath
+dependency versions: aws-0.25.2 bloomfilter-2.0.1.3 crypton-1.0.6 DAV-1.3.4 feed-1.3.2.1 ghc-9.8.2 http-client-0.7.19 torrent-10000.1.3 uuid-1.3.16 yesod-1.6.2.1
+key/value backends: SHA256E SHA256 SHA512E SHA512 SHA224E SHA224 SHA384E SHA384 SHA3_256E SHA3_256 SHA3_512E SHA3_512 SHA3_224E SHA3_224 SHA3_384E SHA3_384 SKEIN256E SKEIN256 SKEIN512E SKEIN512 BLAKE2B256E BLAKE2B256 BLAKE2B512E BLAKE2B512 BLAKE2B160E BLAKE2B160 BLAKE2B224E BLAKE2B224 BLAKE2B384E BLAKE2B384 BLAKE2BP512E BLAKE2BP512 BLAKE2S256E BLAKE2S256 BLAKE2S160E BLAKE2S160 BLAKE2S224E BLAKE2S224 BLAKE2SP256E BLAKE2SP256 BLAKE2SP224E BLAKE2SP224 SHA1E SHA1 MD5E MD5 WORM URL GITBUNDLE GITMANIFEST VURL X*
+remote types: git gcrypt p2p S3 bup directory rsync web bittorrent webdav adb tahoe glacier ddar git-lfs httpalso borg rclone hook external compute mask
+operating system: linux x86_64
+supported repository versions: 8 9 10
+upgrade supported from repository versions: 0 1 2 3 4 5 6 7 8 9 10
+```
+
+
+### 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
+
+
+# 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)
+
+

linux standalone CA certs
* Linux standalone builds now bundle CA certs. They are used only when
the system does not have its own CA cert store.
* Linux standalone build supports using Fedora's CA cert store location.
installSSLCaCertBundle assumes it's running on a Debian system.
It could also support the Fedora/Rocky location of the CA bundle,
but I didn't want to have a second place where I will need to maintain
a list of locations of the bundle. One is bad enough.
Note that git-annex will read /etc/ssl/certs/*.pem, even on systems without
a /etc/ssl/certs/ca-certificates.crt. On a system with only loose pem files,
runshell does use the standalone cert bundle. This would be a behavior
change on such a system. But it turns out that git only reads the loose pem
files on such a system after it's successfully read
/etc/ssl/certs/ca-certificates.crt. So the standalone build had a broken
git before this on such a system, and I think it's ok for the system loose
pem files to also be ignored by git-annex, for consistency.
diff --git a/Build/Standalone.hs b/Build/Standalone.hs
index b98fcaaf66..fb3092a390 100644
--- a/Build/Standalone.hs
+++ b/Build/Standalone.hs
@@ -160,6 +160,14 @@ installLocales topdir =
 	cp (literalOsPath "/usr/share/i18n") (topdir </> "i18n")
 #endif
 
+installSSLCaCertBundle :: OsPath -> IO ()
+#ifdef darwin_HOST_OS
+installSSLCaCertBundle _ = return ()
+#else
+installSSLCaCertBundle topdir =
+	cp (literalOsPath "/etc/ssl/certs/ca-certificates.crt") (topdir </> "ca-certificates.crt")
+#endif
+
 installSkel :: OsPath -> OsPath -> IO ()
 #ifdef darwin_HOST_OS
 installSkel _topdir basedir = do
@@ -238,6 +246,7 @@ main = getArgs >>= go . map toOsPath
 		installGitLibs topdir
 		installMagic topdir
 		installLocales topdir
+		installSSLCaCertBundle topdir
 		hwcaplibs <- mklibs topdir installedbins
 		installSkelRest topdir basedir hwcaplibs
 	go _ = error "specify topdir and basedir"
diff --git a/CHANGELOG b/CHANGELOG
index 3d194c6847..dcd6f589f9 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -11,6 +11,9 @@ git-annex (10.20260422) UNRELEASED; urgency=medium
     progress before the display of pushed branches.
   * Support GIT_SSL_CAINFO, GIT_SSL_CAPATH, http.sslCAPath, and http.sslCAPath
     when connecting to https servers.
+  * Linux standalone builds now bundle CA certs. They are used only when
+    the system does not have its own CA cert store.
+  * Linux standalone build supports using Fedora's CA cert store location.
 
  -- Joey Hess <id@joeyh.name>  Mon, 27 Apr 2026 11:41:49 -0400
 
diff --git a/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9.mdwn b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9.mdwn
index 0656deb131..a303d6eee8 100644
--- a/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9.mdwn
+++ b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9.mdwn
@@ -62,3 +62,5 @@ on Rocky Linux 9, reproduced in a podman container as mentioned above.
 
 
 [[!tag projects/ICE4]]
+
+> [[fixed|done]] --[[Joey]]
diff --git a/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_11_2399bdce7854d9ad36cf58679814c86e._comment b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_11_2399bdce7854d9ad36cf58679814c86e._comment
new file mode 100644
index 0000000000..5b62c73de0
--- /dev/null
+++ b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_11_2399bdce7854d9ad36cf58679814c86e._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 11"""
+ date="2026-05-13T14:05:37Z"
+ content="""
+Implemented both using the Fedora location (which also works on Rocky),
+and falling back to a bundled copy of the CA cert store.
+"""]]
diff --git a/standalone/linux/skel/runshell b/standalone/linux/skel/runshell
index 63cc1ab9ea..e5347e5d7b 100755
--- a/standalone/linux/skel/runshell
+++ b/standalone/linux/skel/runshell
@@ -240,6 +240,23 @@ case "$os" in
 		# when running non-bundled programs.
 		GIT_ANNEX_STANDLONE_ENV="PATH GCONV_PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR MANPATH LOCPATH"
 		export GIT_ANNEX_STANDLONE_ENV
+
+		# Use system's SSL CA certs if present; fall back to
+		# bundled certs. This is the same list of locations
+		# as in crypton-x509-system System.X509.Unix,
+		# limited to only the Linux ones.
+		if [ -z "$GIT_SSL_CAINFO" ] && [ -z "$GIT_SSL_CAPATH" ]; then
+			if [ -e /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem ]; then
+				GIT_SSL_CAINFO=/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
+				export GIT_SSL_CAINFO
+			else
+				if [ ! -e /etc/ssl/certs/ca-certificates.crt ]; then
+					GIT_SSL_CAINFO="$base/ca-certificates.crt"
+					export GIT_SSL_CAINFO
+				fi
+			fi
+		fi
+
 		;;
 esac
 

meh
diff --git a/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_10_0154c0cbddc6080415e9565df102278b._comment b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_10_0154c0cbddc6080415e9565df102278b._comment
index acfb220d42..37b43db0d7 100644
--- a/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_10_0154c0cbddc6080415e9565df102278b._comment
+++ b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_10_0154c0cbddc6080415e9565df102278b._comment
@@ -3,12 +3,29 @@
  subject="""comment 10"""
  date="2026-05-13T13:03:59Z"
  content="""
-It seems more valuable to make the standalone build not depend on the
-system having /etc/ssl/certs/ than it does to work around one bug in one
-distribution.
-
-I'm leaning toward including a copy of the certs, and only using it when
-/etc/ssl/certs/ca-certificates.crt is not present. This limits the security
-exposure of stale certs to linux systems where https would otherwise not work
-without the bundled certs.
+Fedora has no /etc/ssl/certs/ca-certificates.crt.
+Unlike Rocky, it also has no README saying it should have that file.
+
+On Fedora, both git and git-annex from the standalone bundle fail to
+find any certs.
+
+(While crypton-x509-system does use the Fedora location, Debian has too
+old a version for that, and the standalone build inherits that old
+version.)
+
+So, this is affecting multiple distributions. I would like to find a
+solution that avoids needing to worry about this class of problems with
+the standalone build not being sufficiently standalone.
+
+It seems that the best fix would be for the standalone build to use the
+system CA cert store if one is installed, but fall back to one bundled with
+it if not. This limits the security exposure of stale certs in the bundle 
+to linux systems where https would otherwise not work without the bundled
+certs.
+
+I guess this means that the standalone bundle will need to maintain its
+own list of system cert store locations. Ugh.
+
+Pity that linux does not have some kind of filesystem hierarchy standard.
+;-/
 """]]

comment
diff --git a/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_10_0154c0cbddc6080415e9565df102278b._comment b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_10_0154c0cbddc6080415e9565df102278b._comment
new file mode 100644
index 0000000000..acfb220d42
--- /dev/null
+++ b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_10_0154c0cbddc6080415e9565df102278b._comment
@@ -0,0 +1,14 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 10"""
+ date="2026-05-13T13:03:59Z"
+ content="""
+It seems more valuable to make the standalone build not depend on the
+system having /etc/ssl/certs/ than it does to work around one bug in one
+distribution.
+
+I'm leaning toward including a copy of the certs, and only using it when
+/etc/ssl/certs/ca-certificates.crt is not present. This limits the security
+exposure of stale certs to linux systems where https would otherwise not work
+without the bundled certs.
+"""]]

comment
diff --git a/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_9_63ea6d090bca2ed1627d44372a3ea133._comment b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_9_63ea6d090bca2ed1627d44372a3ea133._comment
new file mode 100644
index 0000000000..7dd8ca1917
--- /dev/null
+++ b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_9_63ea6d090bca2ed1627d44372a3ea133._comment
@@ -0,0 +1,17 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 9"""
+ date="2026-05-12T18:38:08Z"
+ content="""
+> But now I've read this in the Changelog, and I could swear it wasn't there 2 days ago
+
+> > Remove /etc/pki/tls/certs/ca-certificates.crt symlink which was included by mistake
+
+That is not /etc/ssl/certs/ca-certificates.crt so not relevant.
+
+Looking at /etc/ssl/README on Rocky 10, it documents that /etc/ssl/certs
+is supposed to a) match Debian and b) include ca-certificates.crt.
+
+So Rocky unquestionably has a bug, either a bug in its documentation, or an
+omission of a file.
+"""]]

comment
diff --git a/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_8_4d6351cc26dd6caf7d326a41cb86721c._comment b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_8_4d6351cc26dd6caf7d326a41cb86721c._comment
new file mode 100644
index 0000000000..7b113d23c9
--- /dev/null
+++ b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_8_4d6351cc26dd6caf7d326a41cb86721c._comment
@@ -0,0 +1,14 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 8"""
+ date="2026-05-12T17:21:47Z"
+ content="""
+It seems like a good idea for git-annex to support the same configuration
+as git does for the CA cert locations. So I've made git-annex support
+`GIT_SSL_CAINFO` (etc) for its own https connections.
+
+That doesn't address the bug, but it does mean that generally, if the linux
+standalone build is having problems with finding system CA certs,
+setting one environment variable is enough to tell both git and git-annex
+where to look.
+"""]]

emulate git's SSL cert path overrides
Support GIT_SSL_CAINFO, GIT_SSL_CAPATH, http.sslCAPath, and http.sslCAPath
when connecting to https servers.
This is by no means a perfect emulation of how git treats these settings.
It only points crypton-connection at the same path. That's good enough for
supplying some CA certificates when there are not system wide ones, or
when the system wide ones are in an unusual place.
diff --git a/Annex/Url.hs b/Annex/Url.hs
index faa051f051..6f58537d57 100644
--- a/Annex/Url.hs
+++ b/Annex/Url.hs
@@ -39,20 +39,24 @@ import qualified Utility.Url.Parse as U
 import Annex.Hook
 import Utility.Hash (IncrementalVerifier)
 import Utility.IPAddress
-import Network.HTTP.Client.Restricted
 import Utility.Metered
+import Utility.Env
 import Git.Credential
 import qualified BuildInfo
 
 import Network.Socket
 import Network.HTTP.Client
 import Network.HTTP.Client.TLS
+import Network.HTTP.Client.Restricted
+import Network.Connection
 import Text.Read
 import qualified Data.Set as S
 #if MIN_VERSION_tls(2,0,0)
 import qualified Network.Connection as NC
 import qualified Network.TLS as TLS
 #endif
+import Network.Connection.Internal (ConnectionContext(..))
+import Data.X509.CertificateStore
 
 defaultUserAgent :: U.UserAgent
 defaultUserAgent = "git-annex/" ++ BuildInfo.packageversion
@@ -100,8 +104,9 @@ getUrlOptions mgc = Annex.getState Annex.urloptions >>= \case
 				then U.DownloadWithConduit $
 					U.DownloadWithCurlRestricted mempty
 				else U.DownloadWithCurl curlopts
+			ctx <- mkconnectioncontext 
 			manager <- liftIO $ U.newManager $ 
-				avoidtimeout managersettings
+				avoidtimeout $ managersettings ctx
 			return (urldownloader, manager)
 		allowedaddrsports -> do
 			addrmatcher <- liftIO $ 
@@ -122,8 +127,9 @@ getUrlOptions mgc = Annex.getState Annex.urloptions >>= \case
 				if isallowed (addrAddress addr)
 					then Nothing
 					else Just (connectionrestricted addr)
-			(settings, pr) <- liftIO $ 
-				mkRestrictedManagerSettings r Nothing tlssettings
+			ctx <- mkconnectioncontext
+			(settings, pr) <- liftIO $
+				mkRestrictedManagerSettings r (Just ctx) tlssettings
 			case pr of
 				Nothing -> return ()
 				Just ProxyRestricted -> toplevelWarning True
@@ -146,10 +152,26 @@ getUrlOptions mgc = Annex.getState Annex.urloptions >>= \case
 				def { TLS.supportedExtendedMainSecret = TLS.AllowEMS }
 #endif
 			| otherwise = Nothing
-		managersettings = case tlssettings of
-			Nothing -> tlsManagerSettings
-			Just v -> mkManagerSettings v Nothing
 	
+		managersettings ctx = case tlssettings of
+			Nothing -> mkManagerSettingsContext (Just ctx) def Nothing
+			Just v -> mkManagerSettingsContext (Just ctx) v Nothing
+		
+		mkconnectioncontext =
+			getCAPath >>= \case
+				Just p -> liftIO $ mkconnectioncontext' p
+				Nothing -> liftIO $ initConnectionContext
+		mkconnectioncontext' p = 
+			ConnectionContext . fromMaybe mempty
+				<$> readCertificateStore p
+
+		getCAPath = getM id
+			[ liftIO (getEnv "GIT_SSL_CAINFO")
+			, liftIO (getEnv "GIT_SSL_CAPATH")
+			, httpSslCAInfo <$> Annex.getGitConfig
+			, httpSslCAPath <$> Annex.getGitConfig
+			]
+
 	-- http-client defailts to timing out a request after 30 seconds
 	-- or so, but some web servers are slower and git-annex has its own
 	-- separate timeout controls, so disable that.
diff --git a/CHANGELOG b/CHANGELOG
index 9bed759351..3d194c6847 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -9,6 +9,8 @@ git-annex (10.20260422) UNRELEASED; urgency=medium
     from the remote.
   * push: When pushing to a bare git repository, display git push
     progress before the display of pushed branches.
+  * Support GIT_SSL_CAINFO, GIT_SSL_CAPATH, http.sslCAPath, and http.sslCAPath
+    when connecting to https servers.
 
  -- Joey Hess <id@joeyh.name>  Mon, 27 Apr 2026 11:41:49 -0400
 
diff --git a/Types/GitConfig.hs b/Types/GitConfig.hs
index 962cb732ae..6ee328e36b 100644
--- a/Types/GitConfig.hs
+++ b/Types/GitConfig.hs
@@ -165,6 +165,8 @@ data GitConfig = GitConfig
 	, coreSharedRepository :: SharedRepository
 	, coreQuotePath :: QuotePath
 	, receiveDenyCurrentBranch :: DenyCurrentBranch
+	, httpSslCAInfo :: Maybe String
+	, httpSslCAPath :: Maybe String
 	, gcryptId :: Maybe String
 	, gpgCmd :: GpgCmd
 	, mergeDirectoryRenames :: Maybe String
@@ -296,6 +298,8 @@ extractGitConfig configsource r = GitConfig
 	, coreSharedRepository = getSharedRepository r
 	, coreQuotePath = QuotePath (getbool "core.quotepath" True)
 	, receiveDenyCurrentBranch = getDenyCurrentBranch r
+	, httpSslCAInfo = getmaybe "http.sslcainfo"
+	, httpSslCAPath = getmaybe "http.sslcapath"
 	, gcryptId = getmaybe "core.gcrypt-id"
 	, gpgCmd = mkGpgCmd (getmaybe "gpg.program")
 	, mergeDirectoryRenames = getmaybe "directoryrenames"
diff --git a/doc/git-annex.mdwn b/doc/git-annex.mdwn
index 9ac9dbe3a8..3cb7e4f6d8 100644
--- a/doc/git-annex.mdwn
+++ b/doc/git-annex.mdwn
@@ -2433,6 +2433,14 @@ These environment variables are used by git-annex when set:
   Usually it's better to configure any desired options through your
   ~/.ssh/config file, or by setting `annex.ssh-options`.
 
+* `GIT_SSL_CAINFO`, `GIT_SSL_CAPATH`
+
+  Similarly to git, when set to a file or directory, this overrides
+  the default SSL certificates used to verify HTTPS connections.
+
+  (The `http.sslCAInfo` and `http.sslCAPath` git configs have the same
+  effect.)
+
 * `GIT_ANNEX_VECTOR_CLOCK`
 
   Normally git-annex timestamps lines in the log files committed to the
diff --git a/git-annex.cabal b/git-annex.cabal
index 5b1042b9c0..5df1efbcd4 100644
--- a/git-annex.cabal
+++ b/git-annex.cabal
@@ -232,7 +232,7 @@ Executable git-annex
    edit-distance,
    resourcet,
    http-client (>= 0.5.3),
-   http-client-tls,
+   http-client-tls (>= 0.3.2),
    http-types (>= 0.7),
    http-conduit (>= 2.3.0),
    http-client-restricted (>= 0.0.2),
@@ -274,7 +274,8 @@ Executable git-annex
    git-lfs (>= 1.2.0),
    clock (>= 0.3.0),
    crypton,
-   crypton-connection,
+   crypton-connection (>= 0.4.3),
+   crypton-x509-store,
    tls,
    servant,
    servant-server,

Added a comment
diff --git a/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_7_5762b9fc59b32faf3dbad5fc336c5160._comment b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_7_5762b9fc59b32faf3dbad5fc336c5160._comment
new file mode 100644
index 0000000000..18e06c9d9c
--- /dev/null
+++ b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_7_5762b9fc59b32faf3dbad5fc336c5160._comment
@@ -0,0 +1,16 @@
+[[!comment format=mdwn
+ username="matrss"
+ avatar="http://cdn.libravatar.org/avatar/cd1c0b3be1af288012e49197918395f0"
+ subject="comment 7"
+ date="2026-05-12T08:46:43Z"
+ content="""
+> Are you sure the image you checked has a new enough version of the package?
+
+Yes. I've used a freshly pulled docker.io/rockylinux/rockylinux:9 and docker.io/rockylinux/rockylinux:10 respectively and then ran `dnf update` too. dnf lists the installed version as `2025.2.80_v9.0.305-102.el10`. I've even checked AlmaLinux (docker.io/library/almalinux:10) too now, and it is the same thing there.
+
+But now I've read this in the Changelog, and I could swear it wasn't there 2 days ago: <https://rockylinux.pkgs.org/10/rockylinux-baseos-x86_64/ca-certificates-2025.2.80_v9.0.305-102.el10.noarch.rpm.html#:~:text=%2D%20Remove%20%2Fetc%2Fpki%2Ftls%2Fcerts%2Fca%2Dcertificates%2Ecrt%20symlink%20which%20was%20included%20by%20mistake>. So it seems the file is not intended to be there.
+
+> That happens to read every cert file in /etc/ssl/certs/ (amoung some other places for other OS's, including /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem for fedora), which would include /etc/ssl/certs/ca-bundle.crt.
+
+That's good to know! Then I think it should be enough to set `GIT_SSL_CAINFO` to get things working. Maybe git-annex-standalone's runshell could try to discover the certificate location and set `GIT_SSL_CAINFO` if necessary? I.e. if `GIT_SSL_CAINFO` is unset check that `/etc/ssl/certs/ca-certificates.crt` exists, if it doesn't check for ca-bundle.crt, if that does exist set `GIT_SSL_CAINFO=/etc/ssl/certs/ca-bundle.crt`, otherwise log a warning.
+"""]]

comments
diff --git a/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_5_27cf2a97e2771beca8ab743e6b0660ba._comment b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_5_27cf2a97e2771beca8ab743e6b0660ba._comment
new file mode 100644
index 0000000000..78893d22c5
--- /dev/null
+++ b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_5_27cf2a97e2771beca8ab743e6b0660ba._comment
@@ -0,0 +1,15 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 5"""
+ date="2026-05-11T13:37:32Z"
+ content="""
+	2025-08-18 - Frantisek Krenzelok <fkrenzel@redhat.com> - 2024.2.69_v8.0.303-102.5
+	- Bring back openssl trusted format bundle as well (Resolves: RHEL-109484)
+	- Restored the following symlinks:
+	* /etc/pki/tls/cert.pem
+	* /etc/pki/tls/certs/ca-certificates.crt
+
+That certainly reads as if the package is intended to contain the file, and is buggy.
+
+Are you sure the image you checked has a new enough version of the package?
+"""]]
diff --git a/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_6_0e9d430bb9d13a136b9091a234a2000b._comment b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_6_0e9d430bb9d13a136b9091a234a2000b._comment
new file mode 100644
index 0000000000..d0098b59f8
--- /dev/null
+++ b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_6_0e9d430bb9d13a136b9091a234a2000b._comment
@@ -0,0 +1,13 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 6"""
+ date="2026-05-11T13:43:15Z"
+ content="""
+git-annex's own SSL cert checking comes via http-client and 
+crypton-connection, which uses crypton-x509-system. 
+
+That happens to read every cert file
+in `/etc/ssl/certs/` (amoung some other places for other OS's, including
+`/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem` for fedora), 
+which would include `/etc/ssl/certs/ca-bundle.crt`.
+"""]]

diff --git a/doc/bugs/Better_p2phttp_error_on_full_remote_disk.mdwn b/doc/bugs/Better_p2phttp_error_on_full_remote_disk.mdwn
new file mode 100644
index 0000000000..63c281bcca
--- /dev/null
+++ b/doc/bugs/Better_p2phttp_error_on_full_remote_disk.mdwn
@@ -0,0 +1,76 @@
+### Please describe the problem.
+
+Copying a file to a remote repository when the remote does not have enough space for it gives a reasonably informative error message when using ssh:
+
+```
+$ git annex copy --to origin-ssh
+copy qwer ok
+copy test.bin (to origin-ssh...) 
+0%    31.98 KiB         5 MiB/s 34m17s  not enough free space, need 1.05 GB more (use --force to override this check or adjust annex.diskreserve)
+git-annex: transfer already in progress, or unable to take transfer lock
+p2pstdio: 1 failed
+Forgejo: Failed to execute git command
+
+[ble: exit 141]
+```
+
+But copying via p2phttp fails without any explanation:
+
+```
+$ git annex copy --to origin
+copy qwer ok
+copy test.bin (to origin...) 
+0%    31.98 KiB       130 MiB/s 1m18s[ble: EOF] 
+```
+
+Now of course the disk being full coincided with mih upgrading Forgejo-aneksajo, which lead to some debugging until we found this simple culprit. I think it would be useful if p2phttp operations showed a more informative error in-line with how the ssh transport does it.
+
+### What steps will reproduce the problem?
+
+1. Create a remote repository on an almost full disk
+2. Try to copy a file to it that does not fit
+
+### What version of git-annex are you using? On what operating system?
+
+Server-side:
+
+```
+$ git annex version
+git-annex version: 10.20260316
+build flags: Assistant Webapp Inotify DBus DesktopNotify TorrentParser MagicMime Benchmark Feeds Testsuite S3 WebDAV Servant OsPath
+dependency versions: aws-0.25.2 bloomfilter-2.0.1.3 crypton-1.0.6 DAV-1.3.4 feed-1.3.2.1 ghc-9.8.2 http-client-0.7.19 torrent-10000.1.3 uuid-1.3.16 yesod-1.6.2.1
+key/value backends: SHA256E SHA256 SHA512E SHA512 SHA224E SHA224 SHA384E SHA384 SHA3_256E SHA3_256 SHA3_512E SHA3_512 SHA3_224E SHA3_224 SHA3_384E SHA3_384 SKEIN256E SKEIN256 SKEIN512E SKEIN512 BLAKE2B256E BLAKE2B256 BLAKE2B512E BLAKE2B512 BLAKE2B160E BLAKE2B160 BLAKE2B224E BLAKE2B224 BLAKE2B384E BLAKE2B384 BLAKE2BP512E BLAKE2BP512 BLAKE2S256E BLAKE2S256 BLAKE2S160E BLAKE2S160 BLAKE2S224E BLAKE2S224 BLAKE2SP256E BLAKE2SP256 BLAKE2SP224E BLAKE2SP224 SHA1E SHA1 MD5E MD5 WORM URL GITBUNDLE GITMANIFEST VURL X*
+remote types: git gcrypt p2p S3 bup directory rsync web bittorrent webdav adb tahoe glacier ddar git-lfs httpalso borg rclone hook external compute mask
+operating system: linux x86_64
+supported repository versions: 8 9 10
+upgrade supported from repository versions: 0 1 2 3 4 5 6 7 8 9 10
+```
+
+Client-side:
+
+```
+$ git annex version
+git-annex version: 10.20260420-g74cffe2f348afd81711fa9f69e165e04e11f1ef0
+build flags: Assistant Webapp Inotify DBus DesktopNotify TorrentParser MagicMime Benchmark Feeds Testsuite S3 WebDAV Servant OsPath
+dependency versions: aws-0.24.4 bloomfilter-2.0.1.3 crypton-1.0.4 DAV-1.3.4 feed-1.3.2.1 ghc-9.10.3 http-client-0.7.19 torrent-10000.1.3 uuid-1.3.16 yesod-1.6.2.1
+key/value backends: SHA256E SHA256 SHA512E SHA512 SHA224E SHA224 SHA384E SHA384 SHA3_256E SHA3_256 SHA3_512E SHA3_512 SHA3_224E SHA3_224 SHA3_384E SHA3_384 SKEIN256E SKEIN256 SKEIN512E SKEIN512 BLAKE2B256E BLAKE2B256 BLAKE2B512E BLAKE2B512 BLAKE2B160E BLAKE2B160 BLAKE2B224E BLAKE2B224 BLAKE2B384E BLAKE2B384 BLAKE2BP512E BLAKE2BP512 BLAKE2S256E BLAKE2S256 BLAKE2S160E BLAKE2S160 BLAKE2S224E BLAKE2S224 BLAKE2SP256E BLAKE2SP256 BLAKE2SP224E BLAKE2SP224 SHA1E SHA1 MD5E MD5 WORM URL GITBUNDLE GITMANIFEST VURL X*
+remote types: git gcrypt p2p S3 bup directory rsync web bittorrent webdav adb tahoe glacier ddar git-lfs httpalso borg rclone hook external compute mask
+operating system: linux x86_64
+supported repository versions: 8 9 10
+upgrade supported from repository versions: 0 1 2 3 4 5 6 7 8 9 10
+```
+
+### 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
+
+
+# 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)
+
+
+[[!tag projects/ICE4]]

Added a comment
diff --git a/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_4_e4110055b858f5bbf770127f373a42e3._comment b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_4_e4110055b858f5bbf770127f373a42e3._comment
new file mode 100644
index 0000000000..3e0b68a73e
--- /dev/null
+++ b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_4_e4110055b858f5bbf770127f373a42e3._comment
@@ -0,0 +1,18 @@
+[[!comment format=mdwn
+ username="matrss"
+ avatar="http://cdn.libravatar.org/avatar/cd1c0b3be1af288012e49197918395f0"
+ subject="comment 4"
+ date="2026-05-09T23:37:03Z"
+ content="""
+> Rocky does have an equivilant ca-certificates package, which seems likely to provide certificates in a place that will work.
+
+Unfortunately that is not the case. The ca-certificates package on Rocky Linux 9 does not provide /etc/ssl/certs/ca-certificates.crt, only /etc/ssl/certs/ca-bundle.crt and /etc/ssl/ca-bundle.trust.crt. /etc/ssl/certs/ca-bundle.crt seems to be Rocky's equivalent to /etc/ssl/certs/ca-certificates.crt, but it is not picked up by the git-annex-standalone package.
+
+I can confirm that symlinking (`ln -s /etc/ssl/certs/ca-bundle.crt /etc/ssl/certs/ca-certificates.crt`) fixes the issue, but I am not sure if I will be able to convince the HPC sysadmins to do so everywhere.
+
+While the changelog for the Rocky Linux **10** ca-certificates package says that the /etc/ssl/certs/ca-certificates.crt symlink has been restored (<https://rockylinux.pkgs.org/10/rockylinux-baseos-x86_64/ca-certificates-2025.2.80_v9.0.305-102.el10.noarch.rpm.html#:~:text=%2A%20%2Fetc%2Fssl%2Fcerts%2Fca%2Dcertificates%2Ecrt>) this doesn't actually seem to be the case, at least I can't find it in the docker.io/rockylinux/rockylinux:10 image.
+
+> I don't think there is any way to override the location with an environment variable.
+
+At least for GnuTLS it seems to be not implemented: <https://gitlab.com/gnutls/gnutls/-/work_items/1279>. But some applications make it overwritable, and this gave me another idea: setting `export GIT_SSL_CAINFO=/etc/ssl/certs/ca-bundle.crt` eliminates the error I was seeing (which seemed to originate from git after all). But I am not sure if there won't be other issues due to the missing /etc/ssl/certs/ca-certificates.crt file and that path being hardcoded in GnuTLS. At least `git annex get` via p2phttp seems to be working fine, but now I am wondering which CAs it is actually using to validate the remote...
+"""]]

comment
diff --git a/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_3_b9822a537e1efde3d1cf55de52de22e5._comment b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_3_b9822a537e1efde3d1cf55de52de22e5._comment
new file mode 100644
index 0000000000..f1b4f5f1e7
--- /dev/null
+++ b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_3_b9822a537e1efde3d1cf55de52de22e5._comment
@@ -0,0 +1,26 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 3"""
+ date="2026-05-08T14:27:02Z"
+ content="""
+The standalone build is made on Debian and inherits
+where it expects to find SSL certs from there. On Debian, the 
+ca-certificates package provides the certificates, and derives from
+those shipped with Mozilla.
+
+Rocky does have an equivilant ca-certificates package, which seems likely to
+provide certificates in a place that will work.
+
+There may be an argument for the standalone build bundling its own copy
+of certificates. Of course, it then would need a security update every time
+there is a removal. But, Debian allows the admin to configure which
+certificate authorities they trust and only populates the file with those.
+If the standalone build overrode that, it would be at least surprising.
+It might be a good compromise for it to ship its own copy, but only
+use it if the file is not present in /etc/.
+
+As well as the 2 C libraries, git-annex links to a haskell library that
+reads the certificates too. Each of these would need to be patched,
+probably, I don't think there is any way to override the location 
+with an environment variable.
+"""]]

Report issue triggering oauth-based authentication against forgejo-aneksajo
diff --git a/doc/bugs/auth.mdwn b/doc/bugs/auth.mdwn
new file mode 100644
index 0000000000..187c59fb10
--- /dev/null
+++ b/doc/bugs/auth.mdwn
@@ -0,0 +1,66 @@
+### Please describe the problem.
+
+`git annex push` does not trigger git credential retrieval reliably, but forces manual credential entry.
+
+### What steps will reproduce the problem?
+
+I have the following git-credential setup
+
+```
+[credential]
+        helper = cache --timeout 21600
+        helper = oauth
+```
+
+Most of my remotes are on some forgejo-aneksajo site. This setup makes git perform an oauth2 workflow against forgejo, and then use the cached credential for a couple of hours. I find this convenient.
+
+git-annex usage also benefits from this setup, as it appears to be able to use a cached credential fine.
+
+But when a credential is not yet cached, the oauth workflow is not triggered when git-annex needs a credential. Instead, it causes a prompt:
+
+```
+❯ git annex push
+copy vid/trr379-metadata-website-update.mp4 (to origin...) Password for 'https://oauth2@<host>':
+```
+
+When I ctrl-c that and immediately afterwards run git-push, this is happening:
+
+```
+❯ git push
+Please complete authentication in your browser...
+https://<host>/login/oauth/authorize?client_id=a4792ccc-...&code_challenge=mHvQCJU...&code_challenge_method=S256&redirect_uri=http%3A%2F%2F127.0.0.1%3A43407&response_type=code&state=QTFf...
+...
+To https://<host>/<repo>.git
+   0ee8c89..4977dac  main -> main
+```
+
+Afterwards, git-annex-push runs fine too.
+
+```
+❯ git annex push
+copy vid/trr379-metadata-website-update.mp4 (to origin...) 
+ok                                
+(recording state in git...)
+push origin 
+Everything up-to-date
+...
+remote: 
+remote: Create a new pull request for 'synced/git-annex':
+remote:   https://<host>/<repo>/compare/main...synced/git-annex
+remote: 
+remote: 
+remote: Create a new pull request for 'synced/main':
+remote:   https://<host>/<repo>/compare/main...synced/main
+remote: 
+To https://<host>/<repo>.git
+   aec36a7..18aa9ab  git-annex -> synced/git-annex
+   0ee8c89..4977dac  main -> synced/main
+ok
+
+```
+
+My expectation would be that a git-annex push would be able to trigger the oauth workflow in the same way that Git does.
+ 
+### What version of git-annex are you using? On what operating system?
+
+`git-annex version: 10.20260316-gf01ba218ffb36e8607516d9895dfaeaeaf101a05` on Debian forky/sid

let directpush display git push progress
When pushing to a bare git repository, it used to display
first the master -> master branch update, but without any of the usual
git push progress messages, followed by the git push progress and branch
update list for the push of the synced branches. That meant that, if
a lot of data needed to be pushed for the master branch push, there was no
indication of progress.
And if anything wanted to parse the output in order to parse the git push
progress and do something with it, it would need to handle this out of
order situation in this special case. Note that datalad push is probably
going to do that.
The fix is to display the git push progress for directpush. But then,
avoid displaying the git push progress for the synced branches.
This does mean that, if the git-annex branch is significantly ahead,
the progress of sending it doesn't get displayed. But that is less likely
to be the case I think, and anyway, it's no worse than not displaying the
progress of the master -> master push.
A better fix might be to integrate the directpush with the syncpush into a
single push. I wanted to avoid making changes that could break things
though, and all of this is pretty fragile.
When pushing to a non-bare repository, there is no change.
diff --git a/CHANGELOG b/CHANGELOG
index 445b34ba47..9bed759351 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -7,6 +7,8 @@ git-annex (10.20260422) UNRELEASED; urgency=medium
     both the remote and the local repository, now pull only drops unwanted
     files from the local repository, and push only drops unwanted files
     from the remote.
+  * push: When pushing to a bare git repository, display git push
+    progress before the display of pushed branches.
 
  -- Joey Hess <id@joeyh.name>  Mon, 27 Apr 2026 11:41:49 -0400
 
diff --git a/Command/Sync.hs b/Command/Sync.hs
index 54fcf48e0c..9fda21b21c 100644
--- a/Command/Sync.hs
+++ b/Command/Sync.hs
@@ -736,25 +736,36 @@ pushRemote o remote (Just branch, _) = do
  -}
 pushBranch :: Remote -> Maybe Git.Branch -> MessageState -> Git.Repo -> IO Bool
 pushBranch remote mbranch ms g = do
-	directpush
-	annexpush `after` syncpush
+	directpushed <- directpush
+	annexpush `after` syncpush directpushed
   where
 	directpush = case mbranch of
 		Just branch -> do
-			let p = flip Git.Command.gitCreateProcess g $ pushparams
-				[ Git.fromRef $ Git.Ref.base $ origBranch branch ]
+			let p = flip Git.Command.gitCreateProcess g $
+				pushparams True
+					[ Git.fromRef $ Git.Ref.base $ origBranch branch ]
 			let p' = p { std_err = CreatePipe }
 			bracket (createProcess p') cleanupProcess $ \h -> do
 				filterstderr [] (stderrHandle h) (processHandle h)
 				void $ waitForProcess (processHandle h)
-		Nothing -> noop
+			return True
+		Nothing -> return False
 				
-	syncpush = flip Git.Command.runBool g $ pushparams $ catMaybes
-		[ (syncrefspec . origBranch) <$> mbranch
-		, Just $ Git.Branch.forcePush $ syncrefspec Annex.Branch.name
-		]
+	syncpush directpushed =  do
+		let p = flip Git.Command.gitCreateProcess g $
+			pushparams (not directpushed) $ catMaybes
+				[ (syncrefspec . origBranch) <$> mbranch
+				, Just $ Git.Branch.forcePush $ syncrefspec Annex.Branch.name
+				]
+		-- stderr is relayed through a pipe so that the push
+		-- progress is not displayed a second time when the
+		-- directpush already displayed push progress.
+		let p' = p { std_err = CreatePipe }
+		bracket (createProcess p') cleanupProcess $ \h -> do
+			relaystderr (stderrHandle h) (processHandle h)
+			checkSuccessProcess (processHandle h)
 	
-	annexpush = void $ tryIO $ flip Git.Command.runQuiet g $ pushparams
+	annexpush = void $ tryIO $ flip Git.Command.runQuiet g $ pushparams False
 		[ Git.fromRef $ Git.Ref.base $ Annex.Branch.name ]
 	
 	-- In the default configuration of receive.denyCurrentBranch,
@@ -779,11 +790,19 @@ pushBranch remote mbranch ms g = do
 			unless (any ("receive.denyCurrentBranch" `isInfixOf`) buf) $
 				mapM_ (hPutStrLn stderr) (reverse buf)
 	
-	pushparams branches = catMaybes
+	relaystderr herr pid = hGetLineUntilExitOrEOF pid herr >>= \case
+		Just l -> do
+			hPutStrLn stderr l
+			relaystderr herr pid
+		Nothing -> return ()
+
+	pushparams forceprogress branches = catMaybes
 		[ Just $ Param "push"
 		, if commandProgressDisabled' ms
 			then Just $ Param "--quiet"
-			else Nothing
+			else if forceprogress
+				then Just $ Param "--progress"
+				else Nothing
 		, Just $ Param $ Remote.name remote
 		] ++ map Param branches
 	
diff --git a/doc/todo/add_--json-progress_support_in_push_and_pull/comment_8_6a552ff9c4d3b8c314938ed44d3da62f._comment b/doc/todo/add_--json-progress_support_in_push_and_pull/comment_8_6a552ff9c4d3b8c314938ed44d3da62f._comment
new file mode 100644
index 0000000000..4ff9d04abd
--- /dev/null
+++ b/doc/todo/add_--json-progress_support_in_push_and_pull/comment_8_6a552ff9c4d3b8c314938ed44d3da62f._comment
@@ -0,0 +1,26 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 8"""
+ date="2026-05-06T13:12:21Z"
+ content="""
+`datalad push` wants to use the same `git push` operations as
+`git-annex push` does, which is nontrivial to reimplement,
+especially in its handling of the git-annex branch.
+See the long comment on pushBranch explaining the order of operations.
+
+This is one place where `git-annex push` *can't* be emulated using other
+`git-annex` commands that *do* support --json.
+
+But, `git-annex push --no-content` doesn't do much besides run pushBranch.
+So `datalad push` could use it when run in a git-annex repository. 
+There's no need for it to support --json either, the regular `git push`
+output goes to stderr, so it can parse the `git push` progress out of
+stderr as before.
+
+It may want to pass `--quiet` to avoid the usual git-annex output to
+stdout. AFAICS, `git push` does not itself output to stdout.
+
+The only other thing that command does besides `pushBranch` is
+`updateBranches`, which updates view branches and adjusted branches when
+run in one. 
+"""]]

comments
diff --git a/doc/todo/add_--json-progress_support_in_push_and_pull/comment_6_97cf6e37c6b87f7b256797b3a72c8801._comment b/doc/todo/add_--json-progress_support_in_push_and_pull/comment_6_97cf6e37c6b87f7b256797b3a72c8801._comment
new file mode 100644
index 0000000000..4c3c02f450
--- /dev/null
+++ b/doc/todo/add_--json-progress_support_in_push_and_pull/comment_6_97cf6e37c6b87f7b256797b3a72c8801._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 6"""
+ date="2026-05-06T12:42:20Z"
+ content="""
+> In the case where the git operation needs to prompt for a password, this would leave the user with a password prompt with no prior indication of what is being done. I don't think that's acceptable.
+
+`git pull` and `git push` over ssh prompt for the password (to /dev/tty)
+before outputing anything else. So I suppose it *is* acceptable.
+"""]]
diff --git a/doc/todo/add_--json-progress_support_in_push_and_pull/comment_7_819c4b701feb1e2dbf4e215cb898f5b1._comment b/doc/todo/add_--json-progress_support_in_push_and_pull/comment_7_819c4b701feb1e2dbf4e215cb898f5b1._comment
new file mode 100644
index 0000000000..9fd5408428
--- /dev/null
+++ b/doc/todo/add_--json-progress_support_in_push_and_pull/comment_7_819c4b701feb1e2dbf4e215cb898f5b1._comment
@@ -0,0 +1,27 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 7"""
+ date="2026-05-06T12:56:10Z"
+ content="""
+`git pull` outputs its progress to stderr. So --json could leave that alone
+and a program wanting to parse it just consume stderr. Delimiters could
+be added to stderr around the `git pull` (with a separate option)
+to make it easier for a program to find and parse it.
+
+`git pull` also outputs some things to stdout. 
+In particular, that includes the `git merge` output when the merge is
+successful. It seems to me that could be put in the json object, eg:
+
+	{"command":"pull","output":["Updating 8a433d0..9d47770" ...
+
+While that will buffer it until the pull is complete. That seems ok;
+it's displayed by `git pull` after the usually more expensive
+network operation, so buffering it briefly wouldn't be too noticable if
+a json consumer chooses to show it to the user.
+
+Note that `git-annex pull` will pull from the remote a second time after
+transferring content to/from it. So the json will have 2 "command":"pull"
+records. And stderr may contain 2 delimited `git pull` stderrs.
+The --json consumer may find that surprising, and it doesn't always happen,
+which gets back to the original problem of the --json not being discoverable.
+"""]]

Added a comment
diff --git a/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_2_f6f6db945c6a158d3e9d94d2ce7df6bc._comment b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_2_f6f6db945c6a158d3e9d94d2ce7df6bc._comment
new file mode 100644
index 0000000000..c612aed233
--- /dev/null
+++ b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_2_f6f6db945c6a158d3e9d94d2ce7df6bc._comment
@@ -0,0 +1,23 @@
+[[!comment format=mdwn
+ username="matrss"
+ avatar="http://cdn.libravatar.org/avatar/cd1c0b3be1af288012e49197918395f0"
+ subject="comment 2"
+ date="2026-05-06T10:21:54Z"
+ content="""
+The ca-certificates.crt file seems to be hardcoded in the git-annex-standalone package:
+
+[[!format sh \"\"\"
+$ grep -R ca-certificates.crt .
+grep: ./usr/lib/x86_64-linux-gnu/tls/x86_64: Warnung: rekursive Verzeichnisschleife
+grep: ./usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3: Warnung: rekursive Verzeichnisschleife
+grep: ./usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2: Warnung: rekursive Verzeichnisschleife
+grep: ./usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v4: Warnung: rekursive Verzeichnisschleife
+grep: ./usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4: Übereinstimmungen in Binärdatei
+grep: ./usr/lib/x86_64-linux-gnu/libgnutls.so.30: Übereinstimmungen in Binärdatei
+grep: ./usr/lib/x86_64-linux-gnu/x86_64: Warnung: rekursive Verzeichnisschleife
+$ strings ./usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4 | grep ca-certificates
+/etc/ssl/certs/ca-certificates.crt
+$ strings ./usr/lib/x86_64-linux-gnu/libgnutls.so.30 | grep ca-certificates
+/etc/ssl/certs/ca-certificates.crt
+\"\"\"]]
+"""]]

Added a comment
diff --git a/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_1_a21dabd18b508b3aa34d753c6c6ece5f._comment b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_1_a21dabd18b508b3aa34d753c6c6ece5f._comment
new file mode 100644
index 0000000000..b9c5923966
--- /dev/null
+++ b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9/comment_1_a21dabd18b508b3aa34d753c6c6ece5f._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="matrss"
+ avatar="http://cdn.libravatar.org/avatar/cd1c0b3be1af288012e49197918395f0"
+ subject="comment 1"
+ date="2026-05-06T10:16:52Z"
+ content="""
+In a Debian 13 container this is all working fine. AFAICT the ca-certificates packages are very different between Rocky and Debian, on Debian I am getting /etc/ssl/certs populated with a bunch of files (presumably all CAs) and with a ca-certificates.crt file, while on Rocky I am only getting /etc/ssl/certs/ca-bundle.crt and /etc/ssl/certs/ca-bundle.trust.crt. After uninstalling ca-certificates on Debian the only file left in that directory is ca-certificates.crt and git-annex continues to work, so I assume this file is required but doesn't exist on Rocky.
+"""]]

diff --git a/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9.mdwn b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9.mdwn
new file mode 100644
index 0000000000..0656deb131
--- /dev/null
+++ b/doc/bugs/Problem_with_SSL_CA_cert_on_Rocky_Linux_9.mdwn
@@ -0,0 +1,64 @@
+### Please describe the problem.
+
+On Rocky Linux 9 (and therefore on the HPC Systems at FZJ) with git-annex installed using the standalone package (either directly or through pixi/conda-forge) I am getting this error message from `git annex pull`:
+
+[[!format sh """
+# git annex pull origin --no-content
+pull origin 
+fatal: unable to access 'https://hub.datalad.org/distribits/recordings.git/': Problem with the SSL CA cert (path? access rights?)
+ok
+"""]]
+
+### What steps will reproduce the problem?
+
+[[!format sh """
+dnf update -y
+dnf install -y wget git
+cd /opt
+wget https://downloads.kitenet.net/git-annex/linux/current/git-annex-standalone-amd64.tar.gz
+tar xzvf git-annex-standalone-amd64.tar.gz
+ln -s /opt/git-annex.linux/git-annex /usr/local/bin
+cd /tmp
+git config --global user.email "you@example.com"
+git config --global user.name "Your Name"
+git clone https://hub.datalad.org/distribits/recordings.git
+cd recordings
+git annex pull origin --no-content
+"""]]
+
+Saved as `reproducer.bash` this can be easily tested using:
+
+    podman run --rm -it docker.io/library/rockylinux:9 bash < reproducer.bash
+
+### What version of git-annex are you using? On what operating system?
+
+```
+# git annex version
+git-annex version: 10.20260420-g74cffe2f348afd81711fa9f69e165e04e11f1ef0
+build flags: Assistant Webapp Inotify DBus DesktopNotify TorrentParser MagicMime Benchmark Feeds Testsuite S3 WebDAV Servant OsPath
+dependency versions: aws-0.24.4 bloomfilter-2.0.1.3 crypton-1.0.4 DAV-1.3.4 feed-1.3.2.1 ghc-9.10.3 http-client-0.7.19 torrent-10000.1.3 uuid-1.3.16 yesod-1.6.2.1
+key/value backends: SHA256E SHA256 SHA512E SHA512 SHA224E SHA224 SHA384E SHA384 SHA3_256E SHA3_256 SHA3_512E SHA3_512 SHA3_224E SHA3_224 SHA3_384E SHA3_384 SKEIN256E SKEIN256 SKEIN512E SKEIN512 BLAKE2B256E BLAKE2B256 BLAKE2B512E BLAKE2B512 BLAKE2B160E BLAKE2B160 BLAKE2B224E BLAKE2B224 BLAKE2B384E BLAKE2B384 BLAKE2BP512E BLAKE2BP512 BLAKE2S256E BLAKE2S256 BLAKE2S160E BLAKE2S160 BLAKE2S224E BLAKE2S224 BLAKE2SP256E BLAKE2SP256 BLAKE2SP224E BLAKE2SP224 SHA1E SHA1 MD5E MD5 WORM URL GITBUNDLE GITMANIFEST VURL X*
+remote types: git gcrypt p2p S3 bup directory rsync web bittorrent webdav adb tahoe glacier ddar git-lfs httpalso borg rclone hook external compute mask
+operating system: linux x86_64
+supported repository versions: 8 9 10
+upgrade supported from repository versions: 0 1 2 3 4 5 6 7 8 9 10
+local repository version: 10
+```
+
+on Rocky Linux 9, reproduced in a podman container as mentioned above.
+
+### 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
+
+
+# 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)
+
+
+
+[[!tag projects/ICE4]]

comment
diff --git a/doc/todo/add_--json-progress_support_in_push_and_pull/comment_5_2dc662fe0bd965da9946fbf582dc08c5._comment b/doc/todo/add_--json-progress_support_in_push_and_pull/comment_5_2dc662fe0bd965da9946fbf582dc08c5._comment
new file mode 100644
index 0000000000..82788e9107
--- /dev/null
+++ b/doc/todo/add_--json-progress_support_in_push_and_pull/comment_5_2dc662fe0bd965da9946fbf582dc08c5._comment
@@ -0,0 +1,19 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 5"""
+ date="2026-05-05T14:37:42Z"
+ content="""
+`datalad push` currently does not use `git-annex push` and it would be good
+it it could in order to avoid some surprising behavior with its current
+implementation.
+
+But, it parses the `git push` output to display its own
+progress messages. Since `git-annex push` interleaves that with whatever
+else it outputs, adapting to parsing it would be difficult.
+
+In order for it to use `git-annex push`, it seems it
+would need --json-progress support, and either parsing of the `git push`
+in git-annex that feeds through to the --json-progress, or some form of
+machine readable delimiters in stdout and stderr around the `git push`
+output.
+"""]]

tag INM7
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 36c8337293..4e18897297 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 +1,3 @@
 The pull and push commands do not have --json-progress support.  Please add.
+
+[[!tag projects/INM7]]

Added a comment
diff --git a/doc/bugs/concurrent_get_from_separate_clones_fails/comment_5_bec4fd724e73338171a5b7bef9612a45._comment b/doc/bugs/concurrent_get_from_separate_clones_fails/comment_5_bec4fd724e73338171a5b7bef9612a45._comment
new file mode 100644
index 0000000000..207aa2c59f
--- /dev/null
+++ b/doc/bugs/concurrent_get_from_separate_clones_fails/comment_5_bec4fd724e73338171a5b7bef9612a45._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="yarikoptic"
+ avatar="http://cdn.libravatar.org/avatar/f11e9c84cb18d26a1748c33b48c924b4"
+ subject="comment 5"
+ date="2026-04-28T18:11:12Z"
+ content="""
+> fixed in [10.20260115-105-gfc28e5d81e AKA 10.20260213~17](https://git.kitenet.net/index.cgi/git-annex.git/commit/?id=fc28e5d81e0fc300865c44ad7688e3a60f25e858)
+"""]]

update
diff --git a/doc/todo/option_for___40__fast__41___compression_on_special_remotes_like___34__directory__34__/comment_6_137879f59a73f84385c9aa1c0e953c0b._comment b/doc/todo/option_for___40__fast__41___compression_on_special_remotes_like___34__directory__34__/comment_6_137879f59a73f84385c9aa1c0e953c0b._comment
index 4f1a5c3d0e..67ca9aa594 100644
--- a/doc/todo/option_for___40__fast__41___compression_on_special_remotes_like___34__directory__34__/comment_6_137879f59a73f84385c9aa1c0e953c0b._comment
+++ b/doc/todo/option_for___40__fast__41___compression_on_special_remotes_like___34__directory__34__/comment_6_137879f59a73f84385c9aa1c0e953c0b._comment
@@ -3,9 +3,14 @@
  subject="""comment 6"""
  date="2026-04-28T17:33:19Z"
  content="""
-Well, it could store the compressor at the start of the object file. Then
-there would only need to be a single namespace for compressed objects. That
-avoids the exponential blowup with chunking, more or less. If it currently
-tries 4 chunk sizes, also checking for compressed and non-compressed
-objects would double the overhead.
+Well, it could store the compressor in a byte or two at the start of the
+object file. Then there would only need to be a single namespace for
+compressed objects. That avoids the exponential blowup with chunking, more
+or less. If it currently tries 4 chunk sizes, also checking for compressed
+and non-compressed objects would double the overhead.
+
+When not using chunking, there would also be a doubling of the overhead.
+
+That seems acceptable, if only special remotes with compression enabled pay
+the price.
 """]]

comments
diff --git a/doc/todo/option_for___40__fast__41___compression_on_special_remotes_like___34__directory__34__/comment_6_137879f59a73f84385c9aa1c0e953c0b._comment b/doc/todo/option_for___40__fast__41___compression_on_special_remotes_like___34__directory__34__/comment_6_137879f59a73f84385c9aa1c0e953c0b._comment
new file mode 100644
index 0000000000..4f1a5c3d0e
--- /dev/null
+++ b/doc/todo/option_for___40__fast__41___compression_on_special_remotes_like___34__directory__34__/comment_6_137879f59a73f84385c9aa1c0e953c0b._comment
@@ -0,0 +1,11 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 6"""
+ date="2026-04-28T17:33:19Z"
+ content="""
+Well, it could store the compressor at the start of the object file. Then
+there would only need to be a single namespace for compressed objects. That
+avoids the exponential blowup with chunking, more or less. If it currently
+tries 4 chunk sizes, also checking for compressed and non-compressed
+objects would double the overhead.
+"""]]
diff --git a/doc/todo/option_for___40__fast__41___compression_on_special_remotes_like___34__directory__34__/comment_7_3e33992559ca8209e7b4591e45aa82d8._comment b/doc/todo/option_for___40__fast__41___compression_on_special_remotes_like___34__directory__34__/comment_7_3e33992559ca8209e7b4591e45aa82d8._comment
new file mode 100644
index 0000000000..315083f7aa
--- /dev/null
+++ b/doc/todo/option_for___40__fast__41___compression_on_special_remotes_like___34__directory__34__/comment_7_3e33992559ca8209e7b4591e45aa82d8._comment
@@ -0,0 +1,30 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 7"""
+ date="2026-04-28T17:36:57Z"
+ content="""
+The external special remote protocol recently got a DELEGATE extension.
+That offers a possible alternative way to handle wanting to compress some
+files and not others.
+
+Suppose that special remotes can have compression enabled, or not, at
+initremote time. The compressor is also chosen then. Neither can be
+changed. And all files stored in the special remote are compressed.
+Very simple.
+
+In order to compress some files, but not others, an external special remote
+could pick which files to compress (based on extension say). It would
+delegate to two different special remote configurations, one with
+compression and one without.
+
+Similarly, if some files use one compressor and some files another one,
+it can delegate to different special remote configurations with the
+compressor it selects.
+
+Note that, with this approach, the external special remote needs to take
+care to always compress the same set of files with the same compressor.
+If it changes its mind retrieval will fail at checksum verification time.
+
+I'm not sold on this idea, but it's an interesting application of the
+DELEGATE extension.
+"""]]

comment
diff --git a/doc/todo/addurl___8211__force-torrent_option/comment_3_c9fb4f8ace5ad2dbd2ad59bc4225c123._comment b/doc/todo/addurl___8211__force-torrent_option/comment_3_c9fb4f8ace5ad2dbd2ad59bc4225c123._comment
new file mode 100644
index 0000000000..b0d82664ca
--- /dev/null
+++ b/doc/todo/addurl___8211__force-torrent_option/comment_3_c9fb4f8ace5ad2dbd2ad59bc4225c123._comment
@@ -0,0 +1,11 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 3"""
+ date="2026-04-28T17:05:56Z"
+ content="""
+`git-annex addurl --no-raw` will prevent it from using the web remote in
+these cases.
+
+But, it does not force treating a given url as a torrent. I suppose the
+`torrent:url` idea still has merit.
+"""]]

comment
diff --git a/doc/todo/wishlist__58___archive_from_remote_with_the_least_free_space/comment_3_acf02b10f742395bc851bf0b437ddd61._comment b/doc/todo/wishlist__58___archive_from_remote_with_the_least_free_space/comment_3_acf02b10f742395bc851bf0b437ddd61._comment
new file mode 100644
index 0000000000..deaa904117
--- /dev/null
+++ b/doc/todo/wishlist__58___archive_from_remote_with_the_least_free_space/comment_3_acf02b10f742395bc851bf0b437ddd61._comment
@@ -0,0 +1,17 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 3"""
+ date="2026-04-28T16:54:00Z"
+ content="""
+Some similar things can now be accomplished using the `sizebalanced`
+preferred content expression. When there are several repositories in a
+group that are all sizebalanced, a file will be wanted by repositories
+that have space for it.
+
+That preferred content expression needs the size of the remote to be
+configured with `git-annex maxsize` in order for the remote to want
+to contain any content.
+
+I think it would be possible to have a similar preferred content expression
+that just makes the repo that is least full want the file.
+"""]]

fixed
diff --git a/doc/todo/Specify_maximum_usable_space_per_remote.mdwn b/doc/todo/Specify_maximum_usable_space_per_remote.mdwn
index 14f9d548b2..7d8ef1d59f 100644
--- a/doc/todo/Specify_maximum_usable_space_per_remote.mdwn
+++ b/doc/todo/Specify_maximum_usable_space_per_remote.mdwn
@@ -7,3 +7,5 @@ Many of the cloud storage providers that git-annex supports through special remo
 Currently I can see the size of a remote using `git annex info gdrive`, so git-annex appears to have the needed information.
 
 This is sort of like `annex.diskreserve`, but more useful for special remotes where setting an amount of space to keep free is not relevant.
+
+> [[done]] --[[Joey]]
diff --git a/doc/todo/Specify_maximum_usable_space_per_remote/comment_7_0905b7b7e62ecc26e5141341eb247bf7._comment b/doc/todo/Specify_maximum_usable_space_per_remote/comment_7_0905b7b7e62ecc26e5141341eb247bf7._comment
new file mode 100644
index 0000000000..f124af0fea
--- /dev/null
+++ b/doc/todo/Specify_maximum_usable_space_per_remote/comment_7_0905b7b7e62ecc26e5141341eb247bf7._comment
@@ -0,0 +1,15 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 7"""
+ date="2026-04-28T16:45:57Z"
+ content="""
+`git-annex maxsize` got implemented a while ago. There are some preferred
+content expressions that take it into account, avoding using more than the
+maximum size when possible. Currently that is limited to balancing
+content amoung several repositories, and there is a rebalancing operation
+for situations where multiple writers have caused the maxsize to be
+exceeded.
+
+There might be room for other preferred content expressions using maxsize,
+but I feel that is enough to close this old todo!
+"""]]

comment
diff --git a/doc/todo/option_to_not_ignore_symlinks_in_import/comment_3_a110fc15aa11333b4944441f87295992._comment b/doc/todo/option_to_not_ignore_symlinks_in_import/comment_3_a110fc15aa11333b4944441f87295992._comment
new file mode 100644
index 0000000000..fe2240ede9
--- /dev/null
+++ b/doc/todo/option_to_not_ignore_symlinks_in_import/comment_3_a110fc15aa11333b4944441f87295992._comment
@@ -0,0 +1,18 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 3"""
+ date="2026-04-28T16:34:49Z"
+ content="""
+This is about importing from a directory, not from a special remote.
+
+I wonder if it's worth making changes to that,
+given plans to [[todo/remove_legacy_import_directory_interface]].
+
+One of the ways that might be accomplished would be to make the old
+interface still work but be reimplemented in terms of automatically setting
+up a directory special remote and importing from it. But importing symlinks
+from a special remote is also not supported, and is probably considerably
+harder, and/or more of a footbomb if multiple special remotes support it.
+
+(See also [[bugs/non-git-annex_symlinks_not_perserved_when_exporting_tree_via_rsync]]))
+"""]]

remove duplicate of 1st half of file
diff --git a/doc/todo/either_support_or_fail___34__more_gracefully__34___on_encfs.mdwn b/doc/todo/either_support_or_fail___34__more_gracefully__34___on_encfs.mdwn
index 4b33938e00..d6d332d542 100644
--- a/doc/todo/either_support_or_fail___34__more_gracefully__34___on_encfs.mdwn
+++ b/doc/todo/either_support_or_fail___34__more_gracefully__34___on_encfs.mdwn
@@ -56,64 +56,3 @@ git-annex: cannot determine uuid for origin (perhaps you need to run "git annex
 ```
 
 which is simply due to the fact that git-annex does not only unable to parse, it is unable to connect.  But if so, IMHO ideally it should avoid claiming anything about git annex installation there.
-
-
-
-After spending some time in troubleshooting the situation that `git-annex` for some reason claims that `origin` remote does not support git-annex, I have ran into [11 year old discussion](https://git-annex.branchable.com/forum/ssh__95__exchange__95__identification__58___read__58___Connection_reset_by_peer/#comment-1776b4d3b175c77cdb44fc8656e3352c) which boils down to
-
-> It would be a good idea to `git config annex.sshcaching` false in repositories stored on encfs.
-
-As AFAIK encfs is generally working ok (seems to test ok with bleeding edge [ref](https://github.com/datalad/git-annex/issues/216)), and overall if there is something wrong, it better be fixed and not "avoided", I think that git-annex should either inform user about necessity to not do internal caching within the same repository (e.g. to have it configured to be shared somewhere under ~/.cache/` instead or a like) if file system does not support the ssh caching, or even somehow automagically handle the case, but it should not mislead in its reporting stating that remote does not support git-annex whenever it does.
-
-With this minimalistic reproducer where origin on a regular filesystem and a clone is under `encfs`, we receive a misleading error:
-
-<details>
-<summary>reproducer</summary> 
-
-```
-#!/bin/bash                                                                                                                                                                         
-export PS4='> '                                                                                                                                                                     
-set -x                                                                                                                                                                              
-set -eu                                                                                                                                                                             
-                                                                                                                                                                                    
-cd "$(mktemp -d ${TMPDIR:-/tmp}/dl-XXXXXXX)"                                                                                                                                        
-
-topd=$PWD
-mkdir -p denc{r,}; encfs --standard --extpass="echo 123" $PWD/denc{r,}
-
-cleanup () {
-    # to possible kill/troubleshoot
-    if ! fusermount -u $topd; then
-        lsof $topd/denc
-        echo "ERROR: failed to unmount"
-        exit 1
-    fi
-}
-trap cleanup SIGINT SIGHUP SIGABRT EXIT
-
-
-mkdir d
-(cd d; git init; git annex init; echo 1 > 1.dat; git annex add 1.dat; git commit -m 1 1.dat)
-
-echo "cloning locally and ssh works ok, testing"
-git clone localhost:$topd/d d-clone
-git -C d-clone annex wanted origin
-
-echo "but would not be happy under encfs with misleading error:"
-cd denc
-git clone localhost:$topd/d d-clone
-git -C d-clone annex wanted origin
-
-```
-</details>
-
-
-```
-> git -C d-clone annex wanted origin
-  Unable to parse git config from origin
-  Remote origin does not have git-annex installed; setting annex-ignore
-  This could be a problem with the git-annex installation on the remote. Please make sure that git-annex-shell is available in PATH when you ssh into the remote. Once you have fixed the git-annex installation, run: git annex enableremote origin
-git-annex: cannot determine uuid for origin (perhaps you need to run "git annex sync"?)
-```
-
-which is simply due to the fact that git-annex does not only unable to parse, it is unable to connect.  But if so, IMHO ideally it should avoid claiming anything about git annex installation there.

comment
diff --git a/doc/todo/fsck_against_versioned_S3_should_populate_log.rmet/comment_1_ec4901628100b0dc29d89c680047b387._comment b/doc/todo/fsck_against_versioned_S3_should_populate_log.rmet/comment_1_ec4901628100b0dc29d89c680047b387._comment
new file mode 100644
index 0000000000..39cd68b35b
--- /dev/null
+++ b/doc/todo/fsck_against_versioned_S3_should_populate_log.rmet/comment_1_ec4901628100b0dc29d89c680047b387._comment
@@ -0,0 +1,13 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2026-04-28T16:04:30Z"
+ content="""
+1. 20260408-noversionid is slop and I will not look at it
+2. effigies comment here <https://github.com/OpenNeuroOrg/openneuro/issues/3875#issuecomment-4209201798>
+   confirms that this is expected behavior of a repository that
+   started out without version IDs and got them turned on later,
+   back in 2019 when git-annex allowed doing that.
+
+Downprioritized appropriately.
+"""]]

Added a comment
diff --git a/doc/bugs/git_annex_get_is_silently_stuck_on__P2P___62___GET_0/comment_5_52862d85555e3810fd4717badd27c4d8._comment b/doc/bugs/git_annex_get_is_silently_stuck_on__P2P___62___GET_0/comment_5_52862d85555e3810fd4717badd27c4d8._comment
new file mode 100644
index 0000000000..8513f9d2b8
--- /dev/null
+++ b/doc/bugs/git_annex_get_is_silently_stuck_on__P2P___62___GET_0/comment_5_52862d85555e3810fd4717badd27c4d8._comment
@@ -0,0 +1,17 @@
+[[!comment format=mdwn
+ username="yarikoptic"
+ avatar="http://cdn.libravatar.org/avatar/f11e9c84cb18d26a1748c33b48c924b4"
+ subject="comment 5"
+ date="2026-04-28T12:06:32Z"
+ content="""
+FWIW, I guess could be closed -- can no longer  reproduce, git-annex 10.20241031-1~ndall+1 : `git annex copy --debug --to typhon --fast --not --in typhon` took super long to transfer everything but completed without errors. I do not think I have any system accessible to me with `/tmp` on NFS.  ATM it is
+
+```
+[bids@rolando 1076_spacetop.git] > df /tmp
+Filesystem     1K-blocks  Used Available Use% Mounted on
+/dev/sdb1      961102624 78224 912179920   1% /tmp
+[bids@rolando 1076_spacetop.git] > mount | grep /tmp
+/dev/sdb1 on /tmp type ext4 (rw,relatime,stripe=192,data=ordered)
+```
+
+"""]]

pull does not drop from remote, and push does not drop from local
Behavior change to git-annex pull and push's handling of unwanted files.
While previously both commands dropped unwanted files from both the remote
and the local repository, now pull only drops unwanted files from the local
repository, and push only drops unwanted files from the remote.
Sponsored-by: Jack Hill
diff --git a/CHANGELOG b/CHANGELOG
index a904dbbe15..445b34ba47 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,11 @@ git-annex (10.20260422) UNRELEASED; urgency=medium
 
   * info: Report the total size of unused keys found by the last run
     of git-annex unused.
+  * Behavior change to git-annex pull and push's handling of unwanted
+    files. While previously both commands dropped unwanted files from
+    both the remote and the local repository, now pull only drops unwanted
+    files from the local repository, and push only drops unwanted files
+    from the remote.
 
  -- Joey Hess <id@joeyh.name>  Mon, 27 Apr 2026 11:41:49 -0400
 
diff --git a/Command/Sync.hs b/Command/Sync.hs
index 5fed2027bf..54fcf48e0c 100644
--- a/Command/Sync.hs
+++ b/Command/Sync.hs
@@ -910,10 +910,11 @@ seekSyncContent o rs currbranch = do
  - Send it to each remote that doesn't have it, and for which it's
  - preferred content.
  -
- - Drop it locally if it's not preferred content (honoring numcopies).
- - 
- - Drop it from each remote that has it, where it's not preferred content
+ - When pulling, drop it locally if it's not preferred content
  - (honoring numcopies).
+ - 
+ - When pushing, drop it from each remote that has it, where it's
+ - not preferred content (honoring numcopies).
  -
  - Returns True if any file transfers were made.
  -}
@@ -949,13 +950,14 @@ syncFile o ebloom rs af k = do
 		-- includeCommandAction for drops,
 		-- because a failure to drop does not mean
 		-- the sync failed.
-		handleDropsFrom locs' rs "unwanted" True k af si []
+		handleDropsFrom locs' dropfromrs "unwanted" dropfromhere
+			k af si []
 			callCommandAction
 	
 	return (got || not (null putrs))
   where
 	wantget lu have inhere = allM id 
-		[ pure (pullOption o || operationMode o == SatisfyMode)
+		[ pure (pullOption o || satisfymode)
 		, pure (not $ null have)
 		, pure (not inhere)
 		, wantGet lu True (Just k) af
@@ -971,7 +973,7 @@ syncFile o ebloom rs af k = do
 			next $ return True
 
 	wantput lu r
-		| pushOption o == False && operationMode o /= SatisfyMode = return False
+		| pushOption o == False && not satisfymode = return False
 		| Remote.readonly r || remoteAnnexReadOnly (Remote.gitconfig r) = return False
 		| isImport r && not (isExport r) = return False
 		| isExport r && not (exportHasAnnexObjects r) = return False
@@ -989,6 +991,14 @@ syncFile o ebloom rs af k = do
 		| otherwise = return []
 	put lu dest = includeCommandAction $ 
 		Command.Move.toStart' lu dest Command.Move.RemoveNever af k ai si
+	
+	dropfromhere = pullOption o || satisfymode
+
+	dropfromrs
+		| pushOption o || satisfymode = rs
+		| otherwise = []
+	
+	satisfymode = operationMode o == SatisfyMode
 
 	ai = mkActionItem (k, af)
 	si = SeekInput []
diff --git a/doc/git-annex-pull.mdwn b/doc/git-annex-pull.mdwn
index 29833e46c6..2ea45dd081 100644
--- a/doc/git-annex-pull.mdwn
+++ b/doc/git-annex-pull.mdwn
@@ -36,8 +36,8 @@ this updates the content in the local repository for those migrations as well.
 Normally this tries to download the content of each annexed file,
 from any remote that it's pulling from that has a copy. 
 To control which files it downloads, configure the preferred
-content of the local repository. It will also drop files from a
-remote that are not preferred content of the remote.
+content of the local repository. It will also drop files
+from the local repository that are not preferred content.
 See [[git-annex-preferred-content]](1).
 
 # OPTIONS
diff --git a/doc/git-annex-push.mdwn b/doc/git-annex-push.mdwn
index e8e140ba5f..6a1509a86e 100644
--- a/doc/git-annex-push.mdwn
+++ b/doc/git-annex-push.mdwn
@@ -44,7 +44,7 @@ Normally this tries to upload the content of each annexed file that is
 in the working tree, to any remote that it's pushing to that does not have
 a copy. To control which files are uploaded to a remote, configure the preferred
 content of the remote. When a file is not the preferred content of a remote,
-or of the local repository, this command will try to drop the file's content.
+this command will try to drop the file's content from it.
 See [[git-annex-preferred-content]](1).
 
 # OPTIONS
diff --git a/doc/todo/should_pull_drop_from_remote.mdwn b/doc/todo/should_pull_drop_from_remote.mdwn
index 8fc051ca53..23c2432103 100644
--- a/doc/todo/should_pull_drop_from_remote.mdwn
+++ b/doc/todo/should_pull_drop_from_remote.mdwn
@@ -40,3 +40,8 @@ possible to only document this behavior change, and if a user has set up
 such a preferred content, they can of course change it to something that
 picks the repository they want to keep the copy.
 --[[Joey]]
+
+> While this is a behavior change, it's also clearly a bug fix.
+> So it's ok to change behavior. I did call it out as a behavior change in
+> the changelog so affected users will hopefully notice. It did not seem
+> a big enough behavior change for a news entry though. [[done]] --[[Joey]]

some thoughts on this, no clear path forward
diff --git a/doc/todo/support_--not_--unused/comment_2_6924c4c2c02d81d9f05937dc01b82da6._comment b/doc/todo/support_--not_--unused/comment_2_6924c4c2c02d81d9f05937dc01b82da6._comment
new file mode 100644
index 0000000000..d9df25d045
--- /dev/null
+++ b/doc/todo/support_--not_--unused/comment_2_6924c4c2c02d81d9f05937dc01b82da6._comment
@@ -0,0 +1,29 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 2"""
+ date="2026-04-27T17:18:02Z"
+ content="""
+`git-annex find` does not accept the `--unused` option. Only copy, drop,
+get, whereis, and a few other commands like that do.
+
+But, the bug still holds, for example `git-annex get --not --unused` will
+confusingly get all unused files and not any other files.
+
+There is a similar problem with `--not --key=foo`, which might be expected
+to get all other keys. Or even `--not --branch=foo`.
+
+It seems difficult to detect all such mistakes though. Consider 
+`git-annex get --not --unused --smallerthan=1mb`.
+The user might expect that to get small files that are not unused, 
+but actually it gets large files that are unused. To detect
+that mistake, the option parser for `--unused` (and `--key` and `--branch`)
+would need to detect that a file matching expression was started before
+it, and is not complete.
+
+I think at some point it just doesn't make sense to prevent user foot
+shooting. `--not` is well documented in what it can be used with, and if
+the user comes up with some combination of options that includes it and
+tries to read it as english, we'd even have to worry about things like
+rejecting `--not --quiet --smallerthan=1mb` since the user might expect
+it to behave like `--verbose`.
+"""]]
diff --git a/doc/todo/support_--not_--unused/comment_3_cddadb4cb92195f77a32a0a6016a5c95._comment b/doc/todo/support_--not_--unused/comment_3_cddadb4cb92195f77a32a0a6016a5c95._comment
new file mode 100644
index 0000000000..5cffda1edb
--- /dev/null
+++ b/doc/todo/support_--not_--unused/comment_3_cddadb4cb92195f77a32a0a6016a5c95._comment
@@ -0,0 +1,23 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 3"""
+ date="2026-04-27T17:28:19Z"
+ content="""
+A `--used` type file matching option would only make sense combined
+with `--all` or perhaps `--key`. Otherwise, it's the default to not operate
+on unused keys, because commands operate on keys that are referenced by
+files in the working tree.
+
+Having that as a file matching option would open a new user confusion.
+Consider  "git-annex drop --not --used". That would never drop any files
+because `drop` by default operates only on used files.
+
+(Except for in the case where `git-annex unused` was run in the past,
+then an unused file were added back to the tree.. then it would surprise
+the user in a different way!)
+
+Given that `--unused` is already potentially confusing since it's not a
+file matching option and can behave in surprising ways when treated as one,
+having a `--used` or similar that *is* a file matching option but doesn't
+usually do anything seems like it only adds to the confusion.
+"""]]

info: Report the total size of unused keys
Sponsored-by: unqueued
diff --git a/CHANGELOG b/CHANGELOG
index 09807bbe27..c1831b7ca6 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,9 @@
+git-annex (10.20260422) UNRELEASED; urgency=medium
+
+  * info: Report the total size of unused keys.
+
+ -- Joey Hess <id@joeyh.name>  Mon, 27 Apr 2026 11:41:49 -0400
+
 git-annex (10.20260421) upstream; urgency=medium
 
   * disableremote: New command.
diff --git a/Command/Info.hs b/Command/Info.hs
index 689fb2b130..dc6dc9d592 100644
--- a/Command/Info.hs
+++ b/Command/Info.hs
@@ -1,6 +1,6 @@
 {- git-annex command
  -
- - Copyright 2011-2025 Joey Hess <id@joeyh.name>
+ - Copyright 2011-2026 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU AGPL version 3 or higher.
  -}
@@ -33,6 +33,7 @@ import Annex.WorkTree
 import Logs.UUID
 import Logs.Trust
 import Logs.Location
+import Logs.Unused
 import Annex.Branch (UnmergedBranches(..), getUnmergedRefs)
 import Annex.NumCopies
 import Git.Config (boolConfig)
@@ -293,6 +294,7 @@ global_slow_stats :: [Stat]
 global_slow_stats = 
 	[ tmp_size
 	, bad_data_size
+	, unused_data_size
 	, local_annex_keys
 	, local_annex_size
 	, known_annex_files True
@@ -469,10 +471,15 @@ treeDesc True = "working tree"
 treeDesc False = "tree"
 
 tmp_size :: Stat
-tmp_size = staleSize "temporary object directory size" gitAnnexTmpObjectDir
+tmp_size = staleDirSize "temporary object directory size" gitAnnexTmpObjectDir
 
 bad_data_size :: Stat
-bad_data_size = staleSize "bad keys size" gitAnnexBadDir
+bad_data_size = staleDirSize "bad keys size" gitAnnexBadDir
+
+unused_data_size :: Stat
+unused_data_size = staleSize "unused keys size"
+	(M.keys <$> readUnusedLog (literalOsPath ""))
+	(pure (calcRepo . gitAnnexLocation))
 
 key_size :: Key -> Stat
 key_size k = simpleStat "size" $ showSizeKeys $ addKey k emptyKeyInfo
@@ -829,10 +836,17 @@ showSizeKeys d = do
 			"+ " ++ show (unknownSizeKeys d) ++
 			" unknown size"
 
-staleSize :: String -> (Git.Repo -> OsPath) -> Stat
-staleSize label dirspec = Stat label $ do
-	keys <- lift $ dirKeys dirspec	
-	onsize =<< sum <$> keysizes keys
+staleDirSize :: String -> (Git.Repo -> OsPath) -> Stat
+staleDirSize label dirspec = staleSize label (dirKeys dirspec) getpath
+  where
+	getpath = do
+		dir <- fromRepo dirspec
+		return (\k -> pure (dir </> keyFile k))
+
+staleSize :: String -> Annex [Key] -> (Annex (Key -> Annex OsPath)) -> Stat
+staleSize label listkeys getpath = Stat label $ do
+	keys <- lift listkeys
+	onsize =<< sum <$> lift (keysizes keys)
   where
 	onsize 0 = return Nothing
 	onsize size = return $ Just $
@@ -841,9 +855,10 @@ staleSize label dirspec = Stat label $ do
 			return $ sizer storageUnits False size
 		in json (++ aside "clean up with git-annex unused") val label
 	keysizes keys = do
-		dir <- lift $ fromRepo dirspec
-		liftIO $ forM keys $ \k -> 
-			catchDefaultIO 0 $ getFileSize (dir </> keyFile k)
+		getpath' <- getpath
+		forM keys $ \k -> do
+			p <- getpath' k
+			liftIO $ catchDefaultIO 0 $ getFileSize p
 
 aside :: String -> String
 aside s = " (" ++ s ++ ")"
diff --git a/doc/todo/Size_of_unused_files.mdwn b/doc/todo/Size_of_unused_files.mdwn
index d16b4e09fc..7af07cfe66 100644
--- a/doc/todo/Size_of_unused_files.mdwn
+++ b/doc/todo/Size_of_unused_files.mdwn
@@ -12,3 +12,5 @@ Maybe I'm missing something, but it feels like having `git annex unused` and `gi
 
 Cheers,
 Yann
+
+> [[done]] --[[Joey]]
diff --git a/doc/todo/Size_of_unused_files/comment_2_e94da18cff0d57c1e0216d91388b19f0._comment b/doc/todo/Size_of_unused_files/comment_2_e94da18cff0d57c1e0216d91388b19f0._comment
new file mode 100644
index 0000000000..b4ccc67a8a
--- /dev/null
+++ b/doc/todo/Size_of_unused_files/comment_2_e94da18cff0d57c1e0216d91388b19f0._comment
@@ -0,0 +1,26 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 2"""
+ date="2026-04-27T15:48:40Z"
+ content="""
+Note that `git-annex info` already shows the size of the keys in the
+temporary directory, and the bad directory. `git-annex unused` lists
+the keys in those 2 directories, in separate tables from the unused keys.
+
+This is making me rethink whether it might make sense for `git-annex info`
+to display the total size of the unused keys as well. While that would make
+the output of info depend on when `git-annex unused` was last run, and
+also on *how* it was run, it would be consistent.
+
+Also, someone may run `git-annex unused` regularly, or have run it and not
+paid much attention to the output, and not want to run it again in order to
+see how much space is used by the unused keys.
+
+And `info` has repository size information, so it would make sense to look
+at it when considering a `git-annex move --unused`.
+
+As for making `git-annex unused` also report the size, it would necessarily
+use a different output format than `git-annex info`. This feels like
+unnecessary duplication of functionality, even if it shared a common
+implementation.
+"""]]

comment
diff --git a/doc/todo/using_file_metadata_for_preferred___40__wanted__41___content/comment_2_665b5497c23201fa2ba4d4e50cd99088._comment b/doc/todo/using_file_metadata_for_preferred___40__wanted__41___content/comment_2_665b5497c23201fa2ba4d4e50cd99088._comment
new file mode 100644
index 0000000000..1854243ead
--- /dev/null
+++ b/doc/todo/using_file_metadata_for_preferred___40__wanted__41___content/comment_2_665b5497c23201fa2ba4d4e50cd99088._comment
@@ -0,0 +1,14 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 2"""
+ date="2026-04-27T15:32:13Z"
+ content="""
+I could imagine adding something to preferred content expressions like
+`metadatawanted` that looks to see if the metadata contains a `wanted`
+field that is the uuid of the repository.
+
+I doubt that this belongs in the standard preferred content expression
+though. But `annex.initwanted` can be used to configure a preferred content
+expression that you want to use in all new repositories that `git-annex`
+inits.
+"""]]

remove OSX and Windows from sidebar
As there are no OSX or Windows builds currently, it's confusing to have
the old builds listed there.
diff --git a/doc/builds.mdwn b/doc/builds.mdwn
index 5e4cc1fbeb..5a0f03134d 100644
--- a/doc/builds.mdwn
+++ b/doc/builds.mdwn
@@ -18,12 +18,6 @@
 <h2>Linux arm64-ancient</h2>
 <iframe width=1024 height=40em scrolling=no frameborder=0 marginheight=0 marginwidth=0 src="https://downloads.kitenet.net/git-annex/autobuild/arm64-ancient/build-version">
 </iframe>
-<h2>OSX</h2>
-<iframe width=1024 height=40em scrolling=no frameborder=0 marginheight=0 marginwidth=0 src="https://downloads.kitenet.net/git-annex/autobuild/x86_64-apple-catalina/build-version">
-</iframe>
-<h2>Windows</h2>
-<iframe width=1024 height=40em scrolling=no frameborder=0 marginheight=0 marginwidth=0 src="https://downloads.kitenet.net/git-annex/autobuild/windows/build-version">
-</iframe>
 """]]
 
 # build logs

update
diff --git a/doc/todo/new_windows_and_OSX_build_hosts_needed.mdwn b/doc/todo/new_windows_and_OSX_build_hosts_needed.mdwn
index 8b8fcf76bb..b83d65c375 100644
--- a/doc/todo/new_windows_and_OSX_build_hosts_needed.mdwn
+++ b/doc/todo/new_windows_and_OSX_build_hosts_needed.mdwn
@@ -13,7 +13,7 @@ A possible alternative for OSX would be to stop providing builds,
 and rely on homebrew's builds. 
 
 And/or the [pipi/uv](https://pypi.org/project/git-annex/) builds could
-perhaps be blessed as the official builds. Although they may currently be
-built from on datalad/git-annex?
+perhaps be blessed as the official builds. mih assures me those builds
+will contiue to be from git-annex master.
 
 --[[Joey]]

update
diff --git a/doc/todo/new_windows_and_OSX_build_hosts_needed.mdwn b/doc/todo/new_windows_and_OSX_build_hosts_needed.mdwn
index d9dd02df9a..8b8fcf76bb 100644
--- a/doc/todo/new_windows_and_OSX_build_hosts_needed.mdwn
+++ b/doc/todo/new_windows_and_OSX_build_hosts_needed.mdwn
@@ -10,8 +10,10 @@ Note that CI for Windows and OSX is still available through
 appveyor. But I don't think build artifacts can be extracted from there?
 
 A possible alternative for OSX would be to stop providing builds, 
-and rely on homebrew's builds. And/or the
-[pipi/uv](https://pypi.org/project/git-annex/)
-builds could perhaps be blessed as the official builds.
+and rely on homebrew's builds. 
+
+And/or the [pipi/uv](https://pypi.org/project/git-annex/) builds could
+perhaps be blessed as the official builds. Although they may currently be
+built from on datalad/git-annex?
 
 --[[Joey]]

unfortunate todo
diff --git a/doc/todo/new_windows_and_OSX_build_hosts_needed.mdwn b/doc/todo/new_windows_and_OSX_build_hosts_needed.mdwn
new file mode 100644
index 0000000000..d9dd02df9a
--- /dev/null
+++ b/doc/todo/new_windows_and_OSX_build_hosts_needed.mdwn
@@ -0,0 +1,17 @@
+The datalad/git-annex repository is no longer used as an autobuilder of
+of git-annex. <https://github.com/datalad/git-annex/issues/260>
+
+Specifically, it was used before for the Windows and OSX autobuilds.
+
+A new build host is needed in order for git-annex releases to be
+accompanied by Windows and OSX builds.
+
+Note that CI for Windows and OSX is still available through
+appveyor. But I don't think build artifacts can be extracted from there?
+
+A possible alternative for OSX would be to stop providing builds, 
+and rely on homebrew's builds. And/or the
+[pipi/uv](https://pypi.org/project/git-annex/)
+builds could perhaps be blessed as the official builds.
+
+--[[Joey]]

remove some old and no longer present branches from list
diff --git a/doc/download.mdwn b/doc/download.mdwn
index 9fbd9878d7..2d2f45249d 100644
--- a/doc/download.mdwn
+++ b/doc/download.mdwn
@@ -19,9 +19,6 @@ others need some manual work. See [[install]] for details.
 
 The git repository has some branches, including:
 
-* `ghc7.0` is a by now very out of date branch that can be built with
-  ghc 7.0.
-* `debian-*-backport` contains the latest backport of git-annex.
 * `setup` contains configuration for this website
 
 ----

despam
diff --git a/doc/forum/OSX__39__s_default_sshd_behaviour_has_limited_paths_set/comment_4_fc4bc5c0f4e3f75b862adc517739c334._comment b/doc/forum/OSX__39__s_default_sshd_behaviour_has_limited_paths_set/comment_4_fc4bc5c0f4e3f75b862adc517739c334._comment
deleted file mode 100644
index beeca24e25..0000000000
--- a/doc/forum/OSX__39__s_default_sshd_behaviour_has_limited_paths_set/comment_4_fc4bc5c0f4e3f75b862adc517739c334._comment
+++ /dev/null
@@ -1,8 +0,0 @@
-[[!comment format=mdwn
- username="cxararea"
- avatar="http://cdn.libravatar.org/avatar/2718f71ca02c851974140f2a0c457b1b"
- subject="Poor Bunny"
- date="2026-01-21T07:29:04Z"
- content="""
-Another standout feature is replayability. Each run feels different due to <a href=\"https://poorbunnygame.com\">Poor Bunny</a> random trap patterns, and the desire to beat your previous high score creates a strong “one more try” loop.
-"""]]

remove links to datalad fork of git-annex
https://github.com/datalad/git-annex/ is now being used as a place to
file AI generated bug reports, which I have deleted from here. As such,
I condider it a fork. Since the OSX and Windows autobuilds are built
from there, they're built from a fork and cannot be linked to from here.
diff --git a/doc/builds.mdwn b/doc/builds.mdwn
index 48744dda62..5e4cc1fbeb 100644
--- a/doc/builds.mdwn
+++ b/doc/builds.mdwn
@@ -43,17 +43,5 @@
 <h2>Linux arm64-ancient</h2>
 <iframe width=1024 scrolling=no frameborder=0 marginheight=0 marginwidth=0 src="https://downloads.kitenet.net/git-annex/autobuild/arm64-ancient/">
 </iframe>
-<h2>OSX</h2>
-<a href="https://github.com/datalad/git-annex/actions?query=workflow%3A%22Build+git-annex+on+macOS%22">
-<img src="https://github.com/datalad/git-annex/actions/workflows/build-macos.yaml/badge.svg">
-</a>
-<h2>Windows</h2>
-<a href="https://github.com/datalad/git-annex/actions?query=workflow%3A%22Build+git-annex+on+Windows%22">
-<img src="https://github.com/datalad/git-annex/actions/workflows/build-windows.yaml/badge.svg">
-</a>
-<h2>Debian standalone packages</h2>
-<a href="https://github.com/datalad/git-annex/actions?query=workflow%3A%22Build+git-annex+on+Ubuntu%22">
-<img src="https://github.com/datalad/git-annex/actions/workflows/build-ubuntu.yaml/badge.svg">
-</a>
 <h2>Appveyor</h2>
 <a href="https://ci.appveyor.com/project/mih/git-annex">here</a>
diff --git a/doc/install/OSX.mdwn b/doc/install/OSX.mdwn
index eba4050544..32ee0e856e 100644
--- a/doc/install/OSX.mdwn
+++ b/doc/install/OSX.mdwn
@@ -18,10 +18,8 @@ several more. Handy if you don't otherwise have git installed.
 
 ## autobuilds
 
-An autobuild is also available, thanks to the Datalad project.
-
-* [git-annex.dmg](https://downloads.kitenet.net/git-annex/autobuild/x86_64-apple-catalina/git-annex.dmg)
-  ([build logs](https://github.com/datalad/git-annex/actions/workflows/build-macos.yaml?query=Build+git-annex+on+macOS))
+No autobuilds are currently available, however there is a Appveyor CI
+[here](https://ci.appveyor.com/project/mih/git-annex).
 
 ## download security
 
diff --git a/doc/install/Windows.mdwn b/doc/install/Windows.mdwn
index 6ea4b5f756..b795d2919f 100644
--- a/doc/install/Windows.mdwn
+++ b/doc/install/Windows.mdwn
@@ -13,10 +13,8 @@ current status.
 
 ## autobuilds
 
-An autobuild is also available, thanks to the Datalad project.
-
-* Windows 10 [download](https://downloads.kitenet.net/git-annex/autobuild/windows/git-annex-installer.exe)
-  ([build logs](https://github.com/datalad/git-annex/actions?query=workflow%3A%22Build+git-annex+on+Windows%22))
+No autobuilds are currently available, however there is a Appveyor CI
+[here](https://ci.appveyor.com/project/mih/git-annex).
 
 ## download security
 

remove unhelpful arguments
These are not bug reports in any valuable sense. They do not belong in
this repository or website.
diff --git a/doc/bugs/git_annex_copy_+_git_push_get_stuck__in_parallel.mdwn b/doc/bugs/git_annex_copy_+_git_push_get_stuck__in_parallel.mdwn
deleted file mode 100644
index 2fbda7139b..0000000000
--- a/doc/bugs/git_annex_copy_+_git_push_get_stuck__in_parallel.mdwn
+++ /dev/null
@@ -1 +0,0 @@
-Deleted AI generated bug report. [[done]] --[[Joey]]
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err.mdwn b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err.mdwn
deleted file mode 100644
index 9d80e78e5f..0000000000
--- a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err.mdwn
+++ /dev/null
@@ -1,3 +0,0 @@
-Deleted AI generated bug report. --[[Joey]]
-
-[[done]]
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_10_1db64b7075ec519dd68d68ea24342a83._comment b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_10_1db64b7075ec519dd68d68ea24342a83._comment
deleted file mode 100644
index f597ded910..0000000000
--- a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_10_1db64b7075ec519dd68d68ea24342a83._comment
+++ /dev/null
@@ -1,10 +0,0 @@
-[[!comment format=mdwn
- username="joey"
- subject="""comment 10"""
- date="2026-04-22T14:15:37Z"
- content="""
-I have no interest in drafting an AI policy. I do have interest in
-communicating with human beings who respect my time and work. By causing an
-AI to blather at me in corpspeak ("smoothed") you once again demonstrate
-you do not.
-"""]]
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_1_fb77f4b017401ba3a9fb3c114919bedb._comment b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_1_fb77f4b017401ba3a9fb3c114919bedb._comment
deleted file mode 100644
index 2165b2e652..0000000000
--- a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_1_fb77f4b017401ba3a9fb3c114919bedb._comment
+++ /dev/null
@@ -1,12 +0,0 @@
-[[!comment format=mdwn
- username="joey"
- subject="""comment 1"""
- date="2026-04-21T18:33:33Z"
- content="""
-I refuse to read, respond, or track AI generated bug reports. 
-
-As such, I am closing this bug report.
-
-I am asking for a second time, that you cease submitting such bug reports
-to this site. I will not ask a third time.
-"""]]
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_2_1862351058301fbe147b6ddbcfb0f44a._comment b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_2_1862351058301fbe147b6ddbcfb0f44a._comment
deleted file mode 100644
index 7b8a193fac..0000000000
--- a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_2_1862351058301fbe147b6ddbcfb0f44a._comment
+++ /dev/null
@@ -1,10 +0,0 @@
-[[!comment format=mdwn
- username="yarikoptic"
- avatar="http://cdn.libravatar.org/avatar/f11e9c84cb18d26a1748c33b48c924b4"
- subject="comment 2"
- date="2026-04-21T20:59:45Z"
- content="""
-The **report** was generated by me and there was nothing in the report itself produced by AI: I cited a few invocations of git commands from the script produced by AI (not alone, but with me) -- output there was from git and git-annex.  I am not sure how more non-AI the report itself could have been.  
-
-The issue seems to be real and I did use claude code, as disclosed, to identify it to get myself unstuck since otherwise there were no feedback or information provided.
-"""]]
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_3_5c9478eac4078f697d04096b2d5f32c8._comment b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_3_5c9478eac4078f697d04096b2d5f32c8._comment
deleted file mode 100644
index 5e75df6bf5..0000000000
--- a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_3_5c9478eac4078f697d04096b2d5f32c8._comment
+++ /dev/null
@@ -1,14 +0,0 @@
-[[!comment format=mdwn
- username="joey"
- subject="""comment 3"""
- date="2026-04-22T00:59:58Z"
- content="""
-The report did not include instructions for reproducing it save for 315
-lines of slop. It would take a long time to read and comprehend what is
-being done in there. Dumping that on me shows that you do not respect my
-time.
-
-Putting that on a different page than directly in the bug report as a way
-to attempt to work around my request that it not be posted here just shows
-that you do not respect my boundaries.
-"""]]
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_4_f5b8938e1c4ffec8c3d9dfeef1b2cd57._comment b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_4_f5b8938e1c4ffec8c3d9dfeef1b2cd57._comment
deleted file mode 100644
index 755f25e4dc..0000000000
--- a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_4_f5b8938e1c4ffec8c3d9dfeef1b2cd57._comment
+++ /dev/null
@@ -1,10 +0,0 @@
-[[!comment format=mdwn
- username="yarikoptic"
- avatar="http://cdn.libravatar.org/avatar/f11e9c84cb18d26a1748c33b48c924b4"
- subject="comment 4"
- date="2026-04-22T03:24:29Z"
- content="""
-**This comment consisted of AI slop and as such has been deleted.
-(It was also condescending corporate speak bullshit and techinically wrong
-to boot.)** --[[Joey]]
-"""]]
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_5_dacbb561579fd22f86b435d582cb3375._comment b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_5_dacbb561579fd22f86b435d582cb3375._comment
deleted file mode 100644
index 5c165cc691..0000000000
--- a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_5_dacbb561579fd22f86b435d582cb3375._comment
+++ /dev/null
@@ -1,8 +0,0 @@
-[[!comment format=mdwn
- username="yarikoptic"
- avatar="http://cdn.libravatar.org/avatar/f11e9c84cb18d26a1748c33b48c924b4"
- subject="comment 5"
- date="2026-04-22T04:13:37Z"
- content="""
-FWIW, the issue is likely not in git-annex itself but rather in forgejo-aneksjo not populating annex.uuid in the config although populating annex.url upon \"push to create\". Filed [forgejo-aneksajo/issues/113](https://codeberg.org/forgejo-aneksajo/forgejo-aneksajo/issues/113).
-"""]]
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_6_0254810faab3f3392cdb255bf0e7b186._comment b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_6_0254810faab3f3392cdb255bf0e7b186._comment
deleted file mode 100644
index 12dd223414..0000000000
--- a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_6_0254810faab3f3392cdb255bf0e7b186._comment
+++ /dev/null
@@ -1,7 +0,0 @@
-[[!comment format=mdwn
- username="joey"
- subject="""comment 6"""
- date="2026-04-22T06:23:40Z"
- content="""
-Was your comment #4 above written with the assistance of AI?
-"""]]
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_7_4a4445b46d177942e73bd8741ece7011._comment b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_7_4a4445b46d177942e73bd8741ece7011._comment
deleted file mode 100644
index afa17cecec..0000000000
--- a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_7_4a4445b46d177942e73bd8741ece7011._comment
+++ /dev/null
@@ -1,11 +0,0 @@
-[[!comment format=mdwn
- username="joey"
- subject="""comment 7"""
- date="2026-04-22T06:33:59Z"
- content="""
-Re "This forces git-annex clients to probe the p2p-http endpoint to
-discover the remote's UUID" in your forgejo-aneksajo bug report.
-
-There is no remote UUID discovery operation in the P2P protocol.
-That is an AI hallucination.
-"""]]
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_8_eb2b702793821159d41dee698e215366._comment b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_8_eb2b702793821159d41dee698e215366._comment
deleted file mode 100644
index c7eb89f639..0000000000
--- a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_8_eb2b702793821159d41dee698e215366._comment
+++ /dev/null
@@ -1,8 +0,0 @@
-[[!comment format=mdwn
- username="yarikoptic"
- avatar="http://cdn.libravatar.org/avatar/f11e9c84cb18d26a1748c33b48c924b4"
- subject="comment 8"
- date="2026-04-22T13:25:47Z"
- content="""
-thanks, roger that.
-"""]]
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_9_6437b029e09543eed8c342a95fa75185._comment b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_9_6437b029e09543eed8c342a95fa75185._comment
deleted file mode 100644
index 62456ebf18..0000000000
--- a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_9_6437b029e09543eed8c342a95fa75185._comment
+++ /dev/null
@@ -1,17 +0,0 @@
-[[!comment format=mdwn
- username="yarikoptic"
- avatar="http://cdn.libravatar.org/avatar/f11e9c84cb18d26a1748c33b48c924b4"
- subject="comment 9"
- date="2026-04-22T13:43:59Z"
- content="""
-now spotted:
-
-> [!comment format=mdwn username=\"joey\" subject=\"\"\"comment 6\"\"\" date=\"2026-04-22T06:23:40Z\" content=\"\"\" Was your comment #4 above written with the assistance of AI? \"\"\"]]
-
-and again, out of respect — I am neither ignoring your question nor hiding provenance: 
-
-\"with assistance\" -- yes, as with assistance of a keyboard, monitor, spell checker, etc. But it was not written by AI:  I wrote it first in full first, then shortened & \"smoothed\" with AI (as I am not a native English speaker etc), reread and re-extended by myself in few iterations. It did come out long but representing my thoughts adequately. 
-
-The request for clear a policy remains outstanding.  
-I guess it could be a variant (or better exact) version of the [forgejo's AI agreement](https://codeberg.org/forgejo/governance/src/branch/main/AIAgreement.md) agreement.
-"""]]
diff --git a/doc/bugs/recent_annex_p2phttp_silently___40__in_--debug__41___refuses.mdwn b/doc/bugs/recent_annex_p2phttp_silently___40__in_--debug__41___refuses.mdwn
deleted file mode 100644
index 11b4895ce4..0000000000
--- a/doc/bugs/recent_annex_p2phttp_silently___40__in_--debug__41___refuses.mdwn
+++ /dev/null
@@ -1,110 +0,0 @@
-### Please describe the problem.
-
-Finally got to try the neat p2p (inspired by trr379 use-case raised in matrix), ultimately with the hope to connect to datalad-fuse. Wanted to test range request support (since was reported to be lacking by claude on a forgejo+aneksjo instance) and thus thought to try on the most recent version locally.
-Unfortunately 
-
-<details>
-<summary>whenever p2phttp worked fine (for a full file) request on 10.20251029</summary> 
-
-```shell
-❯ curl  http://localhost:8081/git-annex/90d896aa-00d0-4f85-bcae-2fd1e992fcab/key/SHA256E-s101318091--02b4a96d66121ddbb5d51fa3f22c2b929bc16d955f438421c1f1b04a1264a50f.tgz >| out.tgz
-  % Total    % Received % Xferd  Average Speed  Time    Time    Time   Current

(Diff truncated)
Added a comment
diff --git a/doc/bugs/recent_annex_p2phttp_silently___40__in_--debug__41___refuses/comment_2_a37f1a012f0988be433177bf39a0447b._comment b/doc/bugs/recent_annex_p2phttp_silently___40__in_--debug__41___refuses/comment_2_a37f1a012f0988be433177bf39a0447b._comment
new file mode 100644
index 0000000000..53a9986752
--- /dev/null
+++ b/doc/bugs/recent_annex_p2phttp_silently___40__in_--debug__41___refuses/comment_2_a37f1a012f0988be433177bf39a0447b._comment
@@ -0,0 +1,97 @@
+[[!comment format=mdwn
+ username="yarikoptic"
+ avatar="http://cdn.libravatar.org/avatar/f11e9c84cb18d26a1748c33b48c924b4"
+ subject="comment 2"
+ date="2026-04-22T17:02:04Z"
+ content="""
+FWIW: Nothing in the original report was produced by AI. Mention of claude and absent range requests support was only to provide provenance on what brought me here to discover this issue.
+
+Here is a full trivial reproducer collating those manually ran commands into 1 script:
+
+```
+#!/bin/bash
+
+export PS4='> '
+set -xeu
+
+cd \"$(mktemp -d ${TMPDIR:-/tmp}/dl-XXXXXXX)\"
+git clone https://datasets.datalad.org/dbic/QA/.git
+cd QA
+git annex version --raw; echo; 
+
+sha256=02b4a96d66121ddbb5d51fa3f22c2b929bc16d955f438421c1f1b04a1264a50f
+key=SHA256E-s101318091--$sha256.tgz
+
+git annex get  --key \"$key\"
+uuid=$(git config annex.uuid)
+
+git annex --debug p2phttp --port 8081 --wideopen &
+
+sleep 2
+
+curl http://localhost:8081/git-annex/$uuid/key/$key >| out.gz
+
+ls -l out.gz; sha256sum out.gz
+
+kill %1
+
+echo \"done ok\"
+```
+
+which with recent git-annex produces
+
+```
+...
+> git annex version --raw
+10.20260316+git92-g28d90e468f-1~ndall+1> echo
+...
+curl: (52) Empty reply from server
+...
+```
+
+while passing all the way to 'done ok' with `10.20251029`.
+
+
+<details>
+<summary>with bleeding edge snapshot 10.20260421+git5-g38a24cc9df-1~ndall+1 - I still get \"Empty reply from server\" but now there are also logs from the git-annex server for `P2P .* DATA 101318091` but no `P2P .* SUCCESS`</summary> 
+
+```shell
+> git annex version --raw
+10.20260421+git5-g38a24cc9df-1~ndall+1> echo
+
+> sha256=02b4a96d66121ddbb5d51fa3f22c2b929bc16d955f438421c1f1b04a1264a50f
+> key=SHA256E-s101318091--02b4a96d66121ddbb5d51fa3f22c2b929bc16d955f438421c1f1b04a1264a50f.tgz
+> git annex get --key SHA256E-s101318091--02b4a96d66121ddbb5d51fa3f22c2b929bc16d955f438421c1f1b04a1264a50f.tgz
+get SHA256E-s101318091--02b4a96d66121ddbb5d51fa3f22c2b929bc16d955f438421c1f1b04a1264a50f.tgz (from origin...) (scanning for annexed files...)
+ok
+(recording state in git...)
+>> git config annex.uuid
+> uuid=6a1c5631-aa13-45be-babb-48aed74bcff9
+> sleep 2
+> git annex --debug p2phttp --port 8081 --wideopen
+[2026-04-22 12:59:21.489519787] (Utility.Process) process [3021850] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"show-ref\",\"git-annex\"]
+[2026-04-22 12:59:21.493864396] (Utility.Process) process [3021850] done ExitSuccess
+[2026-04-22 12:59:21.494532963] (Utility.Process) process [3021851] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"show-ref\",\"--hash\",\"refs/heads/git-annex\"]
+[2026-04-22 12:59:21.498327575] (Utility.Process) process [3021851] done ExitSuccess
+[2026-04-22 12:59:21.498911996] (Utility.Process) process [3021854] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"log\",\"refs/heads/git-annex..7487ff3e269d9c37208e4f2a93e31a1ff6103f4c\",\"--pretty=%H\",\"-n1\"]
+[2026-04-22 12:59:21.50282289] (Utility.Process) process [3021854] done ExitSuccess
+[2026-04-22 12:59:21.504379992] (Utility.Process) process [3021855] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"cat-file\",\"--batch\"]
+[2026-04-22 12:59:21.509479669] (Annex.Branch) read proxy.log
+> curl http://localhost:8081/git-annex/6a1c5631-aa13-45be-babb-48aed74bcff9/key/SHA256E-s101318091--02b4a96d66121ddbb5d51fa3f22c2b929bc16d955f438421c1f1b04a1264a50f.tgz
+  % Total    % Received % Xferd  Average Speed  Time    Time    Time   Current
+                                 Dload  Upload  Total   Spent   Left   Speed
+  0      0   0      0   0      0      0      0                              0[2026-04-22 12:59:23.475306344] (P2P.IO) [http client] [ThreadId 23] P2P > GET 0  SHA256E-s101318091--02b4a96d66121ddbb5d51fa3f22c2b929bc16d955f438421c1f1b04a1264a50f.tgz
+[2026-04-22 12:59:23.475728505] (P2P.IO) [http server] [ThreadId 22] P2P < GET 0  SHA256E-s101318091--02b4a96d66121ddbb5d51fa3f22c2b929bc16d955f438421c1f1b04a1264a50f.tgz
+[2026-04-22 12:59:23.477029319] (Utility.Process) process [3022009] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"-c\",\"filter.annex.smudge=\",\"-c\",\"filter.annex.clean=\",\"-c\",\"filter.annex.process=\",\"write-tree\"]
+[2026-04-22 12:59:23.487752805] (Utility.Process) process [3022009] done ExitSuccess
+[2026-04-22 12:59:23.488176365] (Utility.Process) process [3022015] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"show-ref\",\"--hash\",\"refs/annex/last-index\"]
+[2026-04-22 12:59:23.492356509] (Utility.Process) process [3022015] done ExitSuccess
+[2026-04-22 12:59:23.493004854] (P2P.IO) [http server] [ThreadId 22] P2P > DATA 101318091
+[2026-04-22 12:59:23.493137804] (P2P.IO) [http client] [ThreadId 23] P2P < DATA 101318091
+  0      0   0      0   0      0      0      0                              0
+curl: (52) Empty reply from server
+bash p2p-notworking.sh  10.64s user 3.16s system 75% cpu 18.358 total
+
+```
+</details>
+"""]]

comment
diff --git a/doc/todo/test_script_against_headless_forgejo-aneksajo_/comment_1_bd6dbbbdec6fb0fba34dcda824a0568f._comment b/doc/todo/test_script_against_headless_forgejo-aneksajo_/comment_1_bd6dbbbdec6fb0fba34dcda824a0568f._comment
new file mode 100644
index 0000000000..595f720b0c
--- /dev/null
+++ b/doc/todo/test_script_against_headless_forgejo-aneksajo_/comment_1_bd6dbbbdec6fb0fba34dcda824a0568f._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2026-04-22T15:06:30Z"
+ content="""
+I have no forgejo-aneksajo experience. In any case, I don't see how this is
+a git-annex todo.
+"""]]

uninterested
diff --git a/doc/bugs/recent_annex_p2phttp_silently___40__in_--debug__41___refuses.mdwn b/doc/bugs/recent_annex_p2phttp_silently___40__in_--debug__41___refuses.mdwn
index 6f3492dc88..11b4895ce4 100644
--- a/doc/bugs/recent_annex_p2phttp_silently___40__in_--debug__41___refuses.mdwn
+++ b/doc/bugs/recent_annex_p2phttp_silently___40__in_--debug__41___refuses.mdwn
@@ -107,3 +107,4 @@ FWIW -- https://github.com/datalad/git-annex testing was not happy for awhile bu
 
 [[!meta author=yoh]]
 
+> [[done]] with this BS --[[Joey]]
diff --git a/doc/bugs/recent_annex_p2phttp_silently___40__in_--debug__41___refuses/comment_1_3672a7e460436c3c100e2a1287f4bdb6._comment b/doc/bugs/recent_annex_p2phttp_silently___40__in_--debug__41___refuses/comment_1_3672a7e460436c3c100e2a1287f4bdb6._comment
new file mode 100644
index 0000000000..2ad861f3b9
--- /dev/null
+++ b/doc/bugs/recent_annex_p2phttp_silently___40__in_--debug__41___refuses/comment_1_3672a7e460436c3c100e2a1287f4bdb6._comment
@@ -0,0 +1,17 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2026-04-22T14:59:36Z"
+ content="""
+> since was reported to be lacking by claude on a forgejo+aneksjo instance
+
+Your slop machine is hallucinating again. forgejo+aneksjo has range
+support.
+
+The git-annex p2phttp endpoint, being an API endpoint for a protocol that
+does not use range support, does not have range support.
+
+I suspect that the rest of this bug report is similar AI-addled thinking.
+It's not worth my time to try to understand what you or an AI were doing
+here. Thus, closing.
+"""]]

close non-bug report
diff --git a/doc/bugs/git_annex_copy_+_git_push_get_stuck__in_parallel.mdwn b/doc/bugs/git_annex_copy_+_git_push_get_stuck__in_parallel.mdwn
index dfed9e9a7e..2fbda7139b 100644
--- a/doc/bugs/git_annex_copy_+_git_push_get_stuck__in_parallel.mdwn
+++ b/doc/bugs/git_annex_copy_+_git_push_get_stuck__in_parallel.mdwn
@@ -1 +1 @@
-Deleted AI generated bug report.
+Deleted AI generated bug report. [[done]] --[[Joey]]

deslop
diff --git a/doc/bugs/git_annex_copy_+_git_push_get_stuck__in_parallel.mdwn b/doc/bugs/git_annex_copy_+_git_push_get_stuck__in_parallel.mdwn
index 9f301ff7f3..dfed9e9a7e 100644
--- a/doc/bugs/git_annex_copy_+_git_push_get_stuck__in_parallel.mdwn
+++ b/doc/bugs/git_annex_copy_+_git_push_get_stuck__in_parallel.mdwn
@@ -1,49 +1 @@
-### Please describe the problem.
-
-I was investigating the safety of parallel workers pushing + annex copying to the same original local origin location. 
-It gets stuck (I have not even tried yet that "ssh" option...) and it seems potentially the counter play of 'annex copy' like
-
-```
-yoh      3858496  0.0  0.0   7628  3844 pts/29   S    15:25   0:00  |               \_ /usr/bin/bash -c worker 3
-yoh      3861583  0.0  0.0   7984  3936 pts/29   S    15:25   0:00  |               |   \_ git annex copy --to origin file-3-1.txt file-3-2.txt file-3-3.txt file-3-4.txt file-3-5.txt file-common.txt
-yoh      3861585  3.7  0.1 1075475816 72956 pts/29 Sl 15:25   0:05  |               |       \_ /usr/bin/git-annex copy --to origin file-3-1.txt file-3-2.txt file-3-3.txt file-3-4.txt file-3-5.txt file-common.txt
-yoh      3861886  0.0  0.0   8116  4564 pts/29   S    15:25   0:00  |               |           \_ git --git-dir=.git --work-tree=. --literal-pathspecs cat-file --batch
-
-```
-(of which I have ATM multiple going on)
-
-and 'annex post-receive' hook (of which I have only one) running upon `git push`
-
-```
-yoh      3858498  0.0  0.0   7628  3764 pts/29   S    15:25   0:00  |               \_ /usr/bin/bash -c worker 4
-yoh      3863122  0.0  0.0  17340  4948 pts/29   Sl   15:25   0:00  |               |   \_ git push origin master:br-4
-yoh      3863130  0.0  0.0   2692  1912 pts/29   S    15:25   0:00  |               |       \_ /bin/sh -c git-receive-pack '/home/yoh/.tmp/parallel-push-3858314/origin' git-receive-pack '/home/yoh/.tmp/parallel-push-3858314/origin'
-yoh      3863134  0.0  0.0  16980  5312 pts/29   Sl   15:25   0:00  |               |           \_ git-receive-pack /home/yoh/.tmp/parallel-push-3858314/origin
-yoh      3863172  0.0  0.0   2692  1872 pts/29   S    15:25   0:00  |               |               \_ /bin/sh hooks/post-receive
-yoh      3863192  0.0  0.0   7984  4060 pts/29   S    15:25   0:00  |               |                   \_ git annex post-receive
-yoh      3863195  0.3  0.0 1074074572 17816 pts/29 Sl 15:25   0:00  |               |                       \_ /usr/bin/git-annex post-receive
-```
-
-
-### What steps will reproduce the problem?
-
-[here](https://www.oneukrainian.com/tmp/parallel-push.sh) is a claude-code (with use of LLMs and HI; I did not even review in detail/try yet 'ssh' part coded there) generated script (look or use at your own discretion), on execution of which as `./parallel-push.sh --max-file-size 409600 --max-files 10 40 20` it gets stuck (this is the 4th run I think, consistent stuck at different places) with
-
-```
-copy file-common.txt ok
-copy file-12-1.txt (to origin...) (checksum...) ok
-(recording state in git...)
-clone-12: done (1 files)
-Cloning into '/home/yoh/.tmp/parallel-push-3858314/clone-12'...
-done.
-remote: (recording state in git...)        
-remote: (recovering from race...)        
-To /home/yoh/.tmp/parallel-push-3858314/origin
- * [new branch]      master -> br-12
-
-
-```
-
-### What version of git-annex are you using? On what operating system?
-
-this run is with `10.20251029` but I tried bleeding edge standalone build `10.20260213+git57-gffa771e735-1~ndall+1` to the same result but process traces are more garbled so for the benefit of our both HI I pasted from the non-standalone built version 
+Deleted AI generated bug report.

fixed
diff --git a/doc/bugs/git-annex__58_____60__stdout__62____58___hPutBuf__58___resource_vanished.mdwn b/doc/bugs/git-annex__58_____60__stdout__62____58___hPutBuf__58___resource_vanished.mdwn
index 1600d0ed3e..b55912deea 100644
--- a/doc/bugs/git-annex__58_____60__stdout__62____58___hPutBuf__58___resource_vanished.mdwn
+++ b/doc/bugs/git-annex__58_____60__stdout__62____58___hPutBuf__58___resource_vanished.mdwn
@@ -45,3 +45,5 @@ upgrade supported from repository versions: 0 1 2 3 4 5 6 7 8 9 10
 ### 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)
 
 This is my first post here. First, I use git-annex for both my personal files and professional datasets since around 5 years. So I have to say this wonderful piece of software helped me a lot, therefore a big thank you Joey and other contributors. ;) Second, as a reminder to myself, I really should consider to add tips to the website, since I accumulated a lot of self-wrote documentation in my notes!
+
+> [[fixed|done]] --[[Joey]]
diff --git a/doc/bugs/git-annex__58_____60__stdout__62____58___hPutBuf__58___resource_vanished/comment_5_0bd5fed989b1b97ad9d19d5e40d455fe._comment b/doc/bugs/git-annex__58_____60__stdout__62____58___hPutBuf__58___resource_vanished/comment_5_0bd5fed989b1b97ad9d19d5e40d455fe._comment
new file mode 100644
index 0000000000..04114b7a2d
--- /dev/null
+++ b/doc/bugs/git-annex__58_____60__stdout__62____58___hPutBuf__58___resource_vanished/comment_5_0bd5fed989b1b97ad9d19d5e40d455fe._comment
@@ -0,0 +1,7 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 5"""
+ date="2026-04-22T14:43:30Z"
+ content="""
+Fixed in [[!commit de5dee49da1dc9ca7733f723299235da1da52b10]].
+"""]]

close
diff --git a/doc/bugs/does_not_clean_sub_processes_until_freeze.mdwn b/doc/bugs/does_not_clean_sub_processes_until_freeze.mdwn
index 3291e35910..b66702eaa0 100644
--- a/doc/bugs/does_not_clean_sub_processes_until_freeze.mdwn
+++ b/doc/bugs/does_not_clean_sub_processes_until_freeze.mdwn
@@ -63,3 +63,6 @@ upgrade supported from repository versions: 0 1 2 3 4 5 6 7
 I use it for all kind of data I have both in private and at work. Amazing
 piece of software. I'm sure my colleagues/IT are annoyed of me plugging it to
 every possible discussion.
+
+> [[done]] as this seems like a bug that was already fixed in a newer
+> version. --[[Joey]]

markup
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_4_f5b8938e1c4ffec8c3d9dfeef1b2cd57._comment b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_4_f5b8938e1c4ffec8c3d9dfeef1b2cd57._comment
index 82a74472bf..755f25e4dc 100644
--- a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_4_f5b8938e1c4ffec8c3d9dfeef1b2cd57._comment
+++ b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_4_f5b8938e1c4ffec8c3d9dfeef1b2cd57._comment
@@ -4,7 +4,7 @@
  subject="comment 4"
  date="2026-04-22T03:24:29Z"
  content="""
-This comment consisted of AI slop and as such has been deleted.
+**This comment consisted of AI slop and as such has been deleted.
 (It was also condescending corporate speak bullshit and techinically wrong
-to boot.) --[[Joey]]
+to boot.)** --[[Joey]]
 """]]

fix formatting
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_6_0254810faab3f3392cdb255bf0e7b186._comment b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_6_0254810faab3f3392cdb255bf0e7b186._comment
index 256698d02d..12dd223414 100644
--- a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_6_0254810faab3f3392cdb255bf0e7b186._comment
+++ b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_6_0254810faab3f3392cdb255bf0e7b186._comment
@@ -1,4 +1,4 @@
-[!comment format=mdwn
+[[!comment format=mdwn
  username="joey"
  subject="""comment 6"""
  date="2026-04-22T06:23:40Z"

deslop
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_4_f5b8938e1c4ffec8c3d9dfeef1b2cd57._comment b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_4_f5b8938e1c4ffec8c3d9dfeef1b2cd57._comment
index 2d6a74bdb4..82a74472bf 100644
--- a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_4_f5b8938e1c4ffec8c3d9dfeef1b2cd57._comment
+++ b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_4_f5b8938e1c4ffec8c3d9dfeef1b2cd57._comment
@@ -4,11 +4,7 @@
  subject="comment 4"
  date="2026-04-22T03:24:29Z"
  content="""
-Joey, You asked that AI-generated bug reports not be posted -- and I didn't post one. The report itself was written by me. What it contained inline was a short, focused excerpt of `git-annex`'s own debug output showing exactly where `git credential fill` exits 128 and where git-annex then sets `annex-ignore` on the remote. That is the evidence for the bug, extracted and summarized by me so you would not have to wade through anything longer. It is not 315 lines, and it is not AI output -- it is your program's log output. If to understand more fully you need more information -- just ask, and I will try to distill.
-
-The fuller reproducer script lived behind a link, deliberately, so that you would not have to read it, and so that it is not posted on this site, as per your request. I included that link, together with the explicit AI disclaimer, because I wanted to be transparent about provenance rather than hide how I arrived at the diagnosis. Reading that as an attempt to \"work around\" your request is the opposite of what I intended, and I'd ask you to reconsider it.
-
-In the past I've done my best to produce minimal reproducers, and I'll keep doing that as feasible and time permits -- here I did not have one hand-crafted. But I don't recall a stated policy that reports without a complete hand-crafted reproducer would be deleted as AI slop — and that's the part that rubs me wrong, because the concise summary I did write is the part that seems went unread.
-
-I would genuinely appreciate a clearer statement of what you will and will not accept for bug and todo contributions, so I can either meet that bar or stop contributing here. I will respect whatever policy you set for this site. I would hope that policy would concern what gets posted here, and not what tools I use in my own work elsewhere, where I will continue to use what I need, including AI assistance, to do my job. I won't ask you to look at external reproducers going forward, but I would appreciate if the policy would not forbid me to link such materials when they exist, for provenance.
+This comment consisted of AI slop and as such has been deleted.
+(It was also condescending corporate speak bullshit and techinically wrong
+to boot.) --[[Joey]]
 """]]

no
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_10_1db64b7075ec519dd68d68ea24342a83._comment b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_10_1db64b7075ec519dd68d68ea24342a83._comment
new file mode 100644
index 0000000000..f597ded910
--- /dev/null
+++ b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_10_1db64b7075ec519dd68d68ea24342a83._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 10"""
+ date="2026-04-22T14:15:37Z"
+ content="""
+I have no interest in drafting an AI policy. I do have interest in
+communicating with human beings who respect my time and work. By causing an
+AI to blather at me in corpspeak ("smoothed") you once again demonstrate
+you do not.
+"""]]

Added a comment
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_9_6437b029e09543eed8c342a95fa75185._comment b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_9_6437b029e09543eed8c342a95fa75185._comment
new file mode 100644
index 0000000000..62456ebf18
--- /dev/null
+++ b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_9_6437b029e09543eed8c342a95fa75185._comment
@@ -0,0 +1,17 @@
+[[!comment format=mdwn
+ username="yarikoptic"
+ avatar="http://cdn.libravatar.org/avatar/f11e9c84cb18d26a1748c33b48c924b4"
+ subject="comment 9"
+ date="2026-04-22T13:43:59Z"
+ content="""
+now spotted:
+
+> [!comment format=mdwn username=\"joey\" subject=\"\"\"comment 6\"\"\" date=\"2026-04-22T06:23:40Z\" content=\"\"\" Was your comment #4 above written with the assistance of AI? \"\"\"]]
+
+and again, out of respect — I am neither ignoring your question nor hiding provenance: 
+
+\"with assistance\" -- yes, as with assistance of a keyboard, monitor, spell checker, etc. But it was not written by AI:  I wrote it first in full first, then shortened & \"smoothed\" with AI (as I am not a native English speaker etc), reread and re-extended by myself in few iterations. It did come out long but representing my thoughts adequately. 
+
+The request for clear a policy remains outstanding.  
+I guess it could be a variant (or better exact) version of the [forgejo's AI agreement](https://codeberg.org/forgejo/governance/src/branch/main/AIAgreement.md) agreement.
+"""]]

Added a comment
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_8_eb2b702793821159d41dee698e215366._comment b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_8_eb2b702793821159d41dee698e215366._comment
new file mode 100644
index 0000000000..c7eb89f639
--- /dev/null
+++ b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_8_eb2b702793821159d41dee698e215366._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="yarikoptic"
+ avatar="http://cdn.libravatar.org/avatar/f11e9c84cb18d26a1748c33b48c924b4"
+ subject="comment 8"
+ date="2026-04-22T13:25:47Z"
+ content="""
+thanks, roger that.
+"""]]

bs
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_7_4a4445b46d177942e73bd8741ece7011._comment b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_7_4a4445b46d177942e73bd8741ece7011._comment
new file mode 100644
index 0000000000..afa17cecec
--- /dev/null
+++ b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_7_4a4445b46d177942e73bd8741ece7011._comment
@@ -0,0 +1,11 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 7"""
+ date="2026-04-22T06:33:59Z"
+ content="""
+Re "This forces git-annex clients to probe the p2p-http endpoint to
+discover the remote's UUID" in your forgejo-aneksajo bug report.
+
+There is no remote UUID discovery operation in the P2P protocol.
+That is an AI hallucination.
+"""]]

comment
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_6_0254810faab3f3392cdb255bf0e7b186._comment b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_6_0254810faab3f3392cdb255bf0e7b186._comment
new file mode 100644
index 0000000000..256698d02d
--- /dev/null
+++ b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_6_0254810faab3f3392cdb255bf0e7b186._comment
@@ -0,0 +1,7 @@
+[!comment format=mdwn
+ username="joey"
+ subject="""comment 6"""
+ date="2026-04-22T06:23:40Z"
+ content="""
+Was your comment #4 above written with the assistance of AI?
+"""]]

Added a comment
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_5_dacbb561579fd22f86b435d582cb3375._comment b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_5_dacbb561579fd22f86b435d582cb3375._comment
new file mode 100644
index 0000000000..5c165cc691
--- /dev/null
+++ b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_5_dacbb561579fd22f86b435d582cb3375._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="yarikoptic"
+ avatar="http://cdn.libravatar.org/avatar/f11e9c84cb18d26a1748c33b48c924b4"
+ subject="comment 5"
+ date="2026-04-22T04:13:37Z"
+ content="""
+FWIW, the issue is likely not in git-annex itself but rather in forgejo-aneksjo not populating annex.uuid in the config although populating annex.url upon \"push to create\". Filed [forgejo-aneksajo/issues/113](https://codeberg.org/forgejo-aneksajo/forgejo-aneksajo/issues/113).
+"""]]

Added a comment
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_4_f5b8938e1c4ffec8c3d9dfeef1b2cd57._comment b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_4_f5b8938e1c4ffec8c3d9dfeef1b2cd57._comment
new file mode 100644
index 0000000000..2d6a74bdb4
--- /dev/null
+++ b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_4_f5b8938e1c4ffec8c3d9dfeef1b2cd57._comment
@@ -0,0 +1,14 @@
+[[!comment format=mdwn
+ username="yarikoptic"
+ avatar="http://cdn.libravatar.org/avatar/f11e9c84cb18d26a1748c33b48c924b4"
+ subject="comment 4"
+ date="2026-04-22T03:24:29Z"
+ content="""
+Joey, You asked that AI-generated bug reports not be posted -- and I didn't post one. The report itself was written by me. What it contained inline was a short, focused excerpt of `git-annex`'s own debug output showing exactly where `git credential fill` exits 128 and where git-annex then sets `annex-ignore` on the remote. That is the evidence for the bug, extracted and summarized by me so you would not have to wade through anything longer. It is not 315 lines, and it is not AI output -- it is your program's log output. If to understand more fully you need more information -- just ask, and I will try to distill.
+
+The fuller reproducer script lived behind a link, deliberately, so that you would not have to read it, and so that it is not posted on this site, as per your request. I included that link, together with the explicit AI disclaimer, because I wanted to be transparent about provenance rather than hide how I arrived at the diagnosis. Reading that as an attempt to \"work around\" your request is the opposite of what I intended, and I'd ask you to reconsider it.
+
+In the past I've done my best to produce minimal reproducers, and I'll keep doing that as feasible and time permits -- here I did not have one hand-crafted. But I don't recall a stated policy that reports without a complete hand-crafted reproducer would be deleted as AI slop — and that's the part that rubs me wrong, because the concise summary I did write is the part that seems went unread.
+
+I would genuinely appreciate a clearer statement of what you will and will not accept for bug and todo contributions, so I can either meet that bar or stop contributing here. I will respect whatever policy you set for this site. I would hope that policy would concern what gets posted here, and not what tools I use in my own work elsewhere, where I will continue to use what I need, including AI assistance, to do my job. I won't ask you to look at external reproducers going forward, but I would appreciate if the policy would not forbid me to link such materials when they exist, for provenance.
+"""]]

no
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_3_5c9478eac4078f697d04096b2d5f32c8._comment b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_3_5c9478eac4078f697d04096b2d5f32c8._comment
new file mode 100644
index 0000000000..5e75df6bf5
--- /dev/null
+++ b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_3_5c9478eac4078f697d04096b2d5f32c8._comment
@@ -0,0 +1,14 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 3"""
+ date="2026-04-22T00:59:58Z"
+ content="""
+The report did not include instructions for reproducing it save for 315
+lines of slop. It would take a long time to read and comprehend what is
+being done in there. Dumping that on me shows that you do not respect my
+time.
+
+Putting that on a different page than directly in the bug report as a way
+to attempt to work around my request that it not be posted here just shows
+that you do not respect my boundaries.
+"""]]

Added a comment
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_2_1862351058301fbe147b6ddbcfb0f44a._comment b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_2_1862351058301fbe147b6ddbcfb0f44a._comment
new file mode 100644
index 0000000000..7b8a193fac
--- /dev/null
+++ b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_2_1862351058301fbe147b6ddbcfb0f44a._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="yarikoptic"
+ avatar="http://cdn.libravatar.org/avatar/f11e9c84cb18d26a1748c33b48c924b4"
+ subject="comment 2"
+ date="2026-04-21T20:59:45Z"
+ content="""
+The **report** was generated by me and there was nothing in the report itself produced by AI: I cited a few invocations of git commands from the script produced by AI (not alone, but with me) -- output there was from git and git-annex.  I am not sure how more non-AI the report itself could have been.  
+
+The issue seems to be real and I did use claude code, as disclosed, to identify it to get myself unstuck since otherwise there were no feedback or information provided.
+"""]]

add news item for git-annex 10.20260420
diff --git a/doc/news/version_10.20251114.mdwn b/doc/news/version_10.20251114.mdwn
deleted file mode 100644
index 63255f2897..0000000000
--- a/doc/news/version_10.20251114.mdwn
+++ /dev/null
@@ -1,10 +0,0 @@
-git-annex 10.20251114 released with [[!toggle text="these changes"]]
-[[!toggleable text="""  * p2p --pair: Fix to work with external P2P networks.
-  * p2phttp: Significant robustness fixes for bugs that caused the
-    server to stall.
-  * p2phttp: Fix a file descriptor leak.
-  * p2phttp: Added the --lockedfiles option.
-  * dropunused: Run the annex.secure-erase-command
-    (or .git/hooks/secure-erase-annex) when deleting
-    temp and bad object files.
-  * remotedaemon: Avoid crashing when run with --debug."""]]
\ No newline at end of file
diff --git a/doc/news/version_10.20260420.mdwn b/doc/news/version_10.20260420.mdwn
new file mode 100644
index 0000000000..abd090e745
--- /dev/null
+++ b/doc/news/version_10.20260420.mdwn
@@ -0,0 +1,10 @@
+git-annex 10.20260420 released with [[!toggle text="these changes"]]
+[[!toggleable text="""  * disableremote: New command.
+  * Fix annexUrl to inherit any password that is set in the remote url.
+  * Add DELEGATE extension to the external special remote protocol.
+  * Avoid dying of an exception when when stdout gets closed by eg head(1),
+    and avoid a crash loop when stderr is closed and git-annex dies of an
+    exception.
+    Fixes reversion introduced in version 10.20230407.
+  * Improve UUID sanitization.
+  * Deal with breaking changes to test concurrency in tasty-1.5.4."""]]
\ No newline at end of file

close
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err.mdwn b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err.mdwn
index f823a12899..9d80e78e5f 100644
--- a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err.mdwn
+++ b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err.mdwn
@@ -1 +1,3 @@
 Deleted AI generated bug report. --[[Joey]]
+
+[[done]]

delete slop
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err.mdwn b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err.mdwn
index 2db7b5f377..f823a12899 100644
--- a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err.mdwn
+++ b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err.mdwn
@@ -1,50 +1 @@
-### Please describe the problem.
-
-Disclaimer: this is heavily AI-driven investigation since neither I figured it out myself, nor a complete reproducer to setup such an env existed/was provided. Origin: [PR in datalad-fuse](https://github.com/datalad/datalad-fuse/pull/127) where I want to establish a complete turnkey testing fixture against forgejo+aneksjo instance.
-
-In case of working with forgejo+anexksjo, it seems that if read `url` is publicly (no auth needed) available, but `pushurl` requires authentication and token is specified:
-
-```
-[remote "forgejo"]
-	url = http://127.0.0.1:34201/testadmin/repro-1776783743.git
-	fetch = +refs/heads/*:refs/remotes/forgejo/*
-	pushurl = http://32c116cc671332bf9518d31371a8b515266aa80e:@127.0.0.1:34201/testadmin/repro-1776783743.git
-
-```
-
-`git annex init` (10.20260316+git92-g28d90e468f-1~ndall+1) calls `git credential fill` which might fail e.g. in non interactive sessions and where no credential helper is available/configured, and that leads git-annex to announcement that remote is "not usable by git-annex; setting annex-ignore"
-
-
-<details>
-<summary>relevant excerpt from a run by an AI-produced script using 10.20260316+git92-g28d90e468f-1~ndall+1</summary> 
-
-```shell
-❯ NO_CRED_HELPER=1 ANNEX=1 tools/forgejo-repro.sh
-[repro] git-annex version: 10.20260316+git92-g28d90e468f-1~ndall+1
-...
-+ git fetch -q forgejo
-+ git annex init --debug -q repro-local
-+ grep -i -E '(credential|annex-ignore|usable|error|fail|uuid)'
-+ sed 's/^/  [annex init] /'
-  [annex init] [2026-04-21 11:02:29.572106245] (Git.Config) git config read: [("",[""]),("annex.security.allowed-http-addresses",["all"]),("annex.security.allowed-ip-addresses",["127.0.0.1"]),("annex.security.allowed-url-schemes",["http https file"]),("annex.uuid",["d6b16f32-7ddd-4107-8b0e-8db60a996119"]),("annex.version",["10"]),("core.bare",["false"]),("core.filemode",["true"]),("core.logallrefupdates",["true"]),("core.repositoryformatversion",["0"]),("filter.annex.clean",["git-annex smudge --clean -- %f"]),("filter.annex.process",["git-annex filter-process"]),("filter.annex.smudge",["git-annex smudge -- %f"]),("filter.lfs.clean",["git-lfs clean -- %f"]),("filter.lfs.process",["git-lfs filter-process"]),("filter.lfs.required",["true"]),("filter.lfs.smudge",["git-lfs smudge -- %f"]),("remote.forgejo.fetch",["+refs/heads/*:refs/remotes/forgejo/*"]),("remote.forgejo.pushurl",["http://32c116cc671332bf9518d31371a8b515266aa80e:@127.0.0.1:34201/testadmin/repro-1776783743.git"]),("remote.forgejo.url",["http://127.0.0.1:34201/testadmin/repro-1776783743.git"]),("user.email",["test@test.nil"]),("user.name",["Test User"])]
-  [annex init] [2026-04-21 11:02:29.581477964] (Git.Config) git config read: [("",[""]),("annex.security.allowed-http-addresses",["all"]),("annex.security.allowed-ip-addresses",["127.0.0.1"]),("annex.security.allowed-url-schemes",["http https file"]),("annex.uuid",["d6b16f32-7ddd-4107-8b0e-8db60a996119"]),("annex.version",["10"]),("core.bare",["false"]),("core.filemode",["true"]),("core.logallrefupdates",["true"]),("core.repositoryformatversion",["0"]),("filter.annex.clean",["git-annex smudge --clean -- %f"]),("filter.annex.process",["git-annex filter-process"]),("filter.annex.smudge",["git-annex smudge -- %f"]),("filter.lfs.clean",["git-lfs clean -- %f"]),("filter.lfs.process",["git-lfs filter-process"]),("filter.lfs.required",["true"]),("filter.lfs.smudge",["git-lfs smudge -- %f"]),("remote.forgejo.fetch",["+refs/heads/*:refs/remotes/forgejo/*"]),("remote.forgejo.pushurl",["http://32c116cc671332bf9518d31371a8b515266aa80e:@127.0.0.1:34201/testadmin/repro-1776783743.git"]),("remote.forgejo.url",["http://127.0.0.1:34201/testadmin/repro-1776783743.git"]),("user.email",["test@test.nil"]),("user.name",["Test User"])]
-  [annex init] [2026-04-21 11:02:29.588763529] (Git.Config) git config read: [("",[""]),("annex.security.allowed-http-addresses",["all"]),("annex.security.allowed-ip-addresses",["127.0.0.1"]),("annex.security.allowed-url-schemes",["http https file"]),("annex.uuid",["d6b16f32-7ddd-4107-8b0e-8db60a996119"]),("annex.version",["10"]),("core.bare",["false"]),("core.filemode",["true"]),("core.logallrefupdates",["true"]),("core.repositoryformatversion",["0"]),("filter.annex.clean",["git-annex smudge --clean -- %f"]),("filter.annex.process",["git-annex filter-process"]),("filter.annex.smudge",["git-annex smudge -- %f"]),("filter.lfs.clean",["git-lfs clean -- %f"]),("filter.lfs.process",["git-lfs filter-process"]),("filter.lfs.required",["true"]),("filter.lfs.smudge",["git-lfs smudge -- %f"]),("remote.forgejo.fetch",["+refs/heads/*:refs/remotes/forgejo/*"]),("remote.forgejo.pushurl",["http://32c116cc671332bf9518d31371a8b515266aa80e:@127.0.0.1:34201/testadmin/repro-1776783743.git"]),("remote.forgejo.url",["http://127.0.0.1:34201/testadmin/repro-1776783743.git"]),("user.email",["test@test.nil"]),("user.name",["Test User"])]
-  [annex init] [2026-04-21 11:02:29.605283022] (Annex.Branch) read uuid.log
-  [annex init] [2026-04-21 11:02:29.605605509] (Annex.Branch) set uuid.log
-  [annex init] [2026-04-21 11:02:29.620280198] (Utility.Process) process [1561063] chat: git ["--git-dir=.git","--work-tree=.","--literal-pathspecs","-c","annex.debug=true","credential","fill"]
-  [annex init] [2026-04-21 11:02:29.623557836] (Utility.Process) process [1561063] done ExitFailure 128
-  [annex init]   Remote forgejo not usable by git-annex; setting annex-ignore
-```
-
-</details>
-
-### What steps will reproduce the problem?
-
-Full version of the script is [available in the aforementioned PR](https://github.com/datalad/datalad-fuse/pull/127/changes#diff-604675e9a53a0ae87fcf02ab81e613cf17b48b3f354ecb8c491a83dcd8d345e1) and could be used to reproduce above via `NO_CRED_HELPER=1 ANNEX=1 tools/forgejo-repro.sh`.
- 
-
-
-### What version of git-annex are you using? On what operating system?
-
-10.20260316+git92-g28d90e468f-1~ndall+1
-
+Deleted AI generated bug report. --[[Joey]]

no
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_1_fb77f4b017401ba3a9fb3c114919bedb._comment b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_1_fb77f4b017401ba3a9fb3c114919bedb._comment
new file mode 100644
index 0000000000..2165b2e652
--- /dev/null
+++ b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err/comment_1_fb77f4b017401ba3a9fb3c114919bedb._comment
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2026-04-21T18:33:33Z"
+ content="""
+I refuse to read, respond, or track AI generated bug reports. 
+
+As such, I am closing this bug report.
+
+I am asking for a second time, that you cease submitting such bug reports
+to this site. I will not ask a third time.
+"""]]

initial report on credential fill
diff --git a/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err.mdwn b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err.mdwn
new file mode 100644
index 0000000000..2db7b5f377
--- /dev/null
+++ b/doc/bugs/init_unnecessarily_errors_if_credentials_fill_err.mdwn
@@ -0,0 +1,50 @@
+### Please describe the problem.
+
+Disclaimer: this is heavily AI-driven investigation since neither I figured it out myself, nor a complete reproducer to setup such an env existed/was provided. Origin: [PR in datalad-fuse](https://github.com/datalad/datalad-fuse/pull/127) where I want to establish a complete turnkey testing fixture against forgejo+aneksjo instance.
+
+In case of working with forgejo+anexksjo, it seems that if read `url` is publicly (no auth needed) available, but `pushurl` requires authentication and token is specified:
+
+```
+[remote "forgejo"]
+	url = http://127.0.0.1:34201/testadmin/repro-1776783743.git
+	fetch = +refs/heads/*:refs/remotes/forgejo/*
+	pushurl = http://32c116cc671332bf9518d31371a8b515266aa80e:@127.0.0.1:34201/testadmin/repro-1776783743.git
+
+```
+
+`git annex init` (10.20260316+git92-g28d90e468f-1~ndall+1) calls `git credential fill` which might fail e.g. in non interactive sessions and where no credential helper is available/configured, and that leads git-annex to announcement that remote is "not usable by git-annex; setting annex-ignore"
+
+
+<details>
+<summary>relevant excerpt from a run by an AI-produced script using 10.20260316+git92-g28d90e468f-1~ndall+1</summary> 
+
+```shell
+❯ NO_CRED_HELPER=1 ANNEX=1 tools/forgejo-repro.sh
+[repro] git-annex version: 10.20260316+git92-g28d90e468f-1~ndall+1
+...
++ git fetch -q forgejo
++ git annex init --debug -q repro-local
++ grep -i -E '(credential|annex-ignore|usable|error|fail|uuid)'
++ sed 's/^/  [annex init] /'
+  [annex init] [2026-04-21 11:02:29.572106245] (Git.Config) git config read: [("",[""]),("annex.security.allowed-http-addresses",["all"]),("annex.security.allowed-ip-addresses",["127.0.0.1"]),("annex.security.allowed-url-schemes",["http https file"]),("annex.uuid",["d6b16f32-7ddd-4107-8b0e-8db60a996119"]),("annex.version",["10"]),("core.bare",["false"]),("core.filemode",["true"]),("core.logallrefupdates",["true"]),("core.repositoryformatversion",["0"]),("filter.annex.clean",["git-annex smudge --clean -- %f"]),("filter.annex.process",["git-annex filter-process"]),("filter.annex.smudge",["git-annex smudge -- %f"]),("filter.lfs.clean",["git-lfs clean -- %f"]),("filter.lfs.process",["git-lfs filter-process"]),("filter.lfs.required",["true"]),("filter.lfs.smudge",["git-lfs smudge -- %f"]),("remote.forgejo.fetch",["+refs/heads/*:refs/remotes/forgejo/*"]),("remote.forgejo.pushurl",["http://32c116cc671332bf9518d31371a8b515266aa80e:@127.0.0.1:34201/testadmin/repro-1776783743.git"]),("remote.forgejo.url",["http://127.0.0.1:34201/testadmin/repro-1776783743.git"]),("user.email",["test@test.nil"]),("user.name",["Test User"])]
+  [annex init] [2026-04-21 11:02:29.581477964] (Git.Config) git config read: [("",[""]),("annex.security.allowed-http-addresses",["all"]),("annex.security.allowed-ip-addresses",["127.0.0.1"]),("annex.security.allowed-url-schemes",["http https file"]),("annex.uuid",["d6b16f32-7ddd-4107-8b0e-8db60a996119"]),("annex.version",["10"]),("core.bare",["false"]),("core.filemode",["true"]),("core.logallrefupdates",["true"]),("core.repositoryformatversion",["0"]),("filter.annex.clean",["git-annex smudge --clean -- %f"]),("filter.annex.process",["git-annex filter-process"]),("filter.annex.smudge",["git-annex smudge -- %f"]),("filter.lfs.clean",["git-lfs clean -- %f"]),("filter.lfs.process",["git-lfs filter-process"]),("filter.lfs.required",["true"]),("filter.lfs.smudge",["git-lfs smudge -- %f"]),("remote.forgejo.fetch",["+refs/heads/*:refs/remotes/forgejo/*"]),("remote.forgejo.pushurl",["http://32c116cc671332bf9518d31371a8b515266aa80e:@127.0.0.1:34201/testadmin/repro-1776783743.git"]),("remote.forgejo.url",["http://127.0.0.1:34201/testadmin/repro-1776783743.git"]),("user.email",["test@test.nil"]),("user.name",["Test User"])]
+  [annex init] [2026-04-21 11:02:29.588763529] (Git.Config) git config read: [("",[""]),("annex.security.allowed-http-addresses",["all"]),("annex.security.allowed-ip-addresses",["127.0.0.1"]),("annex.security.allowed-url-schemes",["http https file"]),("annex.uuid",["d6b16f32-7ddd-4107-8b0e-8db60a996119"]),("annex.version",["10"]),("core.bare",["false"]),("core.filemode",["true"]),("core.logallrefupdates",["true"]),("core.repositoryformatversion",["0"]),("filter.annex.clean",["git-annex smudge --clean -- %f"]),("filter.annex.process",["git-annex filter-process"]),("filter.annex.smudge",["git-annex smudge -- %f"]),("filter.lfs.clean",["git-lfs clean -- %f"]),("filter.lfs.process",["git-lfs filter-process"]),("filter.lfs.required",["true"]),("filter.lfs.smudge",["git-lfs smudge -- %f"]),("remote.forgejo.fetch",["+refs/heads/*:refs/remotes/forgejo/*"]),("remote.forgejo.pushurl",["http://32c116cc671332bf9518d31371a8b515266aa80e:@127.0.0.1:34201/testadmin/repro-1776783743.git"]),("remote.forgejo.url",["http://127.0.0.1:34201/testadmin/repro-1776783743.git"]),("user.email",["test@test.nil"]),("user.name",["Test User"])]
+  [annex init] [2026-04-21 11:02:29.605283022] (Annex.Branch) read uuid.log
+  [annex init] [2026-04-21 11:02:29.605605509] (Annex.Branch) set uuid.log
+  [annex init] [2026-04-21 11:02:29.620280198] (Utility.Process) process [1561063] chat: git ["--git-dir=.git","--work-tree=.","--literal-pathspecs","-c","annex.debug=true","credential","fill"]
+  [annex init] [2026-04-21 11:02:29.623557836] (Utility.Process) process [1561063] done ExitFailure 128
+  [annex init]   Remote forgejo not usable by git-annex; setting annex-ignore
+```
+
+</details>
+
+### What steps will reproduce the problem?
+
+Full version of the script is [available in the aforementioned PR](https://github.com/datalad/datalad-fuse/pull/127/changes#diff-604675e9a53a0ae87fcf02ab81e613cf17b48b3f354ecb8c491a83dcd8d345e1) and could be used to reproduce above via `NO_CRED_HELPER=1 ANNEX=1 tools/forgejo-repro.sh`.
+ 
+
+
+### What version of git-annex are you using? On what operating system?
+
+10.20260316+git92-g28d90e468f-1~ndall+1
+

forgot to add a comment
diff --git a/doc/bugs/find_should_quite_if_output_of_the_pipe_closes/comment_4_dda5420ba6169e8e9c449aea3532cbf3._comment b/doc/bugs/find_should_quite_if_output_of_the_pipe_closes/comment_4_dda5420ba6169e8e9c449aea3532cbf3._comment
new file mode 100644
index 0000000000..c9f52d4730
--- /dev/null
+++ b/doc/bugs/find_should_quite_if_output_of_the_pipe_closes/comment_4_dda5420ba6169e8e9c449aea3532cbf3._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 4"""
+ date="2026-04-13T16:58:54Z"
+ content="""
+Was able to get git-annex back to typical unix-like behavior on sigpipe,
+and also avoided the crash loop when stderr is closed.
+"""]]

Added a comment
diff --git a/doc/bugs/s3_imported_branch_is___34__git_buggy__34____58____bad_blobs/comment_11_2db0adbd5d15eba0442afec572a84413._comment b/doc/bugs/s3_imported_branch_is___34__git_buggy__34____58____bad_blobs/comment_11_2db0adbd5d15eba0442afec572a84413._comment
new file mode 100644
index 0000000000..911e23259c
--- /dev/null
+++ b/doc/bugs/s3_imported_branch_is___34__git_buggy__34____58____bad_blobs/comment_11_2db0adbd5d15eba0442afec572a84413._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="yarikoptic"
+ avatar="http://cdn.libravatar.org/avatar/f11e9c84cb18d26a1748c33b48c924b4"
+ subject="comment 11"
+ date="2026-04-15T19:55:19Z"
+ content="""
+FTR: fixed in [10.20251215-51-g69e6c4d024 AKA 10.20260115~59](https://git.kitenet.net/index.cgi/git-annex.git/commit/?id=69e6c4d024dcff7c2f8ea1a2ed3b483a86b2cc7d)
+"""]]

bug report
diff --git a/doc/bugs/annex.adjustedbranchrefresh_of_remote_not_honored.mdwn b/doc/bugs/annex.adjustedbranchrefresh_of_remote_not_honored.mdwn
new file mode 100644
index 0000000000..c527c40ae9
--- /dev/null
+++ b/doc/bugs/annex.adjustedbranchrefresh_of_remote_not_honored.mdwn
@@ -0,0 +1,8 @@
+When a git remote has annex.adjustedbranchrefresh set to 1, `git-annex sync --content`
+run with that remote should only refresh the adjusted branch there once.
+But, I've verified it does so after every file is sent. Which is quite
+slow.
+
+Apparently this is because in this case it registers a cleanup action, and
+the way the Annex monad works for a local git remote, it runs those each
+time, due to calling quiesce. --[[Joey]]

Added a comment
diff --git a/doc/bugs/find_should_quite_if_output_of_the_pipe_closes/comment_5_640df954a31d87bcda0dbfe4463e2a4b._comment b/doc/bugs/find_should_quite_if_output_of_the_pipe_closes/comment_5_640df954a31d87bcda0dbfe4463e2a4b._comment
new file mode 100644
index 0000000000..072cc430af
--- /dev/null
+++ b/doc/bugs/find_should_quite_if_output_of_the_pipe_closes/comment_5_640df954a31d87bcda0dbfe4463e2a4b._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="yarikoptic"
+ avatar="http://cdn.libravatar.org/avatar/f11e9c84cb18d26a1748c33b48c924b4"
+ subject="comment 5"
+ date="2026-04-13T17:30:16Z"
+ content="""
+FWIW -- never returned, doing on another box -- here is a complete command : `git clone https://github.com/dandisets/000026.git && cd 000026 &&  git annex init && git annex find --not --in here --fast | head -n 1` -- stalled as well.  I wonder if replicates for you. Also there with `2>/dev/null` returned right away, but on rerun without - stalled again.
+"""]]

fix sanitizeTopLevelExceptionMessages
Avoid dying of an exception when when stdout gets closed by eg head(1), and
avoid a crash loop when stderr is closed and git-annex dies of an
exception. Fixes reversion introduced in version 10.20230407.
Note that giveup sanitizes escape characters, so
sanitizeTopLevelExceptionMessages can just use it to rethrow
the exception. But the exception type information is lost, so
an exception caused by sigPIPE would be displayed.
I don't entirely understand the crash loop, but it seemed to be caused
by the exitWith $ ExitFailure 1. Which is not necessary when using
giveup.
It's a bit scary to mess with the sigPIPE handler, but restoring the
Default does get the behavior we want. If that turned out to cause a
problem though, that part of this could be reverted, and git-annex would
only display the kind of ugly error message when piped to head.
Sponsored-by: Dartmouth College's OpenNeuro project
diff --git a/CHANGELOG b/CHANGELOG
index a791dfdaa8..aa29f974f7 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -4,6 +4,10 @@ git-annex (10.20260317) UNRELEASED; urgency=medium
   * disableremote: New command.
   * Add DELEGATE extension to the external special remote protocol.
   * Improve UUID sanitization.
+  * Avoid dying of an exception when when stdout gets closed by eg head(1),
+    and avoid a crash loop when stderr is closed and git-annex dies of an
+    exception.
+    Fixes reversion introduced in version 10.20230407.
 
  -- Joey Hess <id@joeyh.name>  Mon, 23 Mar 2026 11:37:09 -0400
 
diff --git a/Messages.hs b/Messages.hs
index 704d5cfeac..25b129e93d 100644
--- a/Messages.hs
+++ b/Messages.hs
@@ -1,6 +1,6 @@
 {- git-annex output messages
  -
- - Copyright 2010-2023 Joey Hess <id@joeyh.name>
+ - Copyright 2010-2026 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU AGPL version 3 or higher.
  -}
@@ -65,6 +65,9 @@ import qualified Data.ByteString.Char8 as S8
 import System.Exit
 import qualified Control.Monad.Catch as M
 import Data.String
+#ifndef mingw32_HOST_OS
+import System.Posix.Signals
+#endif
 
 import Common
 import Types
@@ -355,15 +358,23 @@ mkPrompter = getConcurrency >>= \case
 {- Catch all (non-async and not ExitCode) exceptions and display, 
  - sanitizing any control characters in the exceptions.
  -
- - Exits nonzero on exception, so should only be used at topmost level.
+ - Should only be used at topmost level.
  -}
 sanitizeTopLevelExceptionMessages :: IO a -> IO a
-sanitizeTopLevelExceptionMessages a = a `catches`
-	((M.Handler (\ (e :: ExitCode) -> throwM e)) : nonAsyncHandler go)
+sanitizeTopLevelExceptionMessages a = do
+#ifndef mingw32_HOST_OS
+	-- By default ghc Ignores sigPIPE, and then does not display
+	-- exceptions like <stdout>: hFlush: resource vanished (Broken pipe)
+	--
+	-- Since this would display such exceptions, instead restore the
+	-- Default sigPIPE behavior, which is for the program to
+	-- immediately exit.
+	void $ installHandler sigPIPE Default Nothing
+#endif
+	a `catches`
+		((M.Handler (\ (e :: ExitCode) -> throwM e)) : nonAsyncHandler go)
   where
-	go e = do
-		hPutStrLn stderr $ safeOutput $ toplevelMsg (show e)
-		exitWith $ ExitFailure 1
+	go e = giveup $ show e
 
 {- Used to only run an action that displays a message after the specified
  - number of steps. This is useful when performing an action that can
diff --git a/doc/bugs/find_should_quite_if_output_of_the_pipe_closes.mdwn b/doc/bugs/find_should_quite_if_output_of_the_pipe_closes.mdwn
index 58fea8f47a..0558fc1204 100644
--- a/doc/bugs/find_should_quite_if_output_of_the_pipe_closes.mdwn
+++ b/doc/bugs/find_should_quite_if_output_of_the_pipe_closes.mdwn
@@ -41,3 +41,5 @@ I didn't check other commands , but they all should behave sane as not to stall
 
 [[!meta author=yoh]]
 [[!tag projects/openneuro]]
+
+> [[fixed|done]] --[[Joey]]
diff --git a/doc/bugs/find_should_quite_if_output_of_the_pipe_closes/comment_3_2e95dcff2f5776f97eaad22e8b284f24._comment b/doc/bugs/find_should_quite_if_output_of_the_pipe_closes/comment_3_2e95dcff2f5776f97eaad22e8b284f24._comment
index 529216f696..789fdcdc0f 100644
--- a/doc/bugs/find_should_quite_if_output_of_the_pipe_closes/comment_3_2e95dcff2f5776f97eaad22e8b284f24._comment
+++ b/doc/bugs/find_should_quite_if_output_of_the_pipe_closes/comment_3_2e95dcff2f5776f97eaad22e8b284f24._comment
@@ -12,12 +12,9 @@ pipe exception, and so the crash loop never happens when stderr is closed.
 That is relatively new; it was added in git-annex 10.20230407.
 
 And apparently what ghc's default exception display mechanism does is
-actually to ignore the broken pipe exception for stdout. Which leads
-to the more typical unix behavior of silently stopping on SIGPIPE.
-See also <https://mail.haskell.org/pipermail/haskell-cafe/2023-May/136194.html>
+actually to avoid displaying anything for the broken pipe exception for
+stdout. Which leads to the more typical unix behavior of silently
+stopping on SIGPIPE. 
 
-Note that the loop when displaying an exception fails with an exception due
-to stderr being closed still seems to be the fault of ghc/base, not
-git-annex. All that sanitizeTopLevelExceptionMessages does is cause the
-exception to be displayed.
+See also <https://mail.haskell.org/pipermail/haskell-cafe/2023-May/136194.html>
 """]]

comment
diff --git a/doc/bugs/find_should_quite_if_output_of_the_pipe_closes/comment_3_2e95dcff2f5776f97eaad22e8b284f24._comment b/doc/bugs/find_should_quite_if_output_of_the_pipe_closes/comment_3_2e95dcff2f5776f97eaad22e8b284f24._comment
new file mode 100644
index 0000000000..529216f696
--- /dev/null
+++ b/doc/bugs/find_should_quite_if_output_of_the_pipe_closes/comment_3_2e95dcff2f5776f97eaad22e8b284f24._comment
@@ -0,0 +1,23 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 3"""
+ date="2026-04-13T15:22:17Z"
+ content="""
+Turns out that a git-annex that does not
+use sanitizeTopLevelExceptionMessages will not have this behavior.
+
+Without that, `git-annex find | head -n1` does not display the broken
+pipe exception, and so the crash loop never happens when stderr is closed.
+
+That is relatively new; it was added in git-annex 10.20230407.
+
+And apparently what ghc's default exception display mechanism does is
+actually to ignore the broken pipe exception for stdout. Which leads
+to the more typical unix behavior of silently stopping on SIGPIPE.
+See also <https://mail.haskell.org/pipermail/haskell-cafe/2023-May/136194.html>
+
+Note that the loop when displaying an exception fails with an exception due
+to stderr being closed still seems to be the fault of ghc/base, not
+git-annex. All that sanitizeTopLevelExceptionMessages does is cause the
+exception to be displayed.
+"""]]

Added a comment
diff --git a/doc/bugs/find_should_quite_if_output_of_the_pipe_closes/comment_3_9c1bd4016e326cf9e100a697798382df._comment b/doc/bugs/find_should_quite_if_output_of_the_pipe_closes/comment_3_9c1bd4016e326cf9e100a697798382df._comment
new file mode 100644
index 0000000000..037cabf9dc
--- /dev/null
+++ b/doc/bugs/find_should_quite_if_output_of_the_pipe_closes/comment_3_9c1bd4016e326cf9e100a697798382df._comment
@@ -0,0 +1,37 @@
+[[!comment format=mdwn
+ username="yarikoptic"
+ avatar="http://cdn.libravatar.org/avatar/f11e9c84cb18d26a1748c33b48c924b4"
+ subject="comment 3"
+ date="2026-04-13T15:56:23Z"
+ content="""
+> I'm curious if you also ran git-annex with FD 2 closed?
+
+how do I discover that ?  it worked fine if I redirect stderr:
+
+```
+$> git annex find --in here 2>/dev/null | head -n 1
+derivatives/linear_anatomical_alignment/sub-01/ses-forrestgump/func/sub-01_ses-forrestgump_task-forrestgump_rec-XFMdico7Tad2grpbold7Tad_run-01_bold.mat
+
+$> echo $?
+0
+
+```
+
+and damn it -- after that it started to work in that shell:
+
+```
+$> git annex find --in here | head -n 1   
+derivatives/linear_anatomical_alignment/sub-01/ses-forrestgump/func/sub-01_ses-forrestgump_task-forrestgump_rec-XFMdico7Tad2grpbold7Tad_run-01_bold.mat
+git-annex: <stdout>: hFlush: resource vanished (Broken pipe)
+```
+
+:-/  I think it relates to dataset size as if I go to other small datasets in that shell now -- it returns fine as expected, but in huge `/mnt/btrfs/datasets/datalad/crawl/dandi/dandisets/000026` -- still running (likely more stuff spit out to stdout), even with
+
+```
+(git)smaug:/mnt/btrfs/datasets/datalad/crawl/dandi/dandisets/000026[draft]git
+$> git annex find --not --in here --fast 2>/dev/null | head -n 1
+derivatives/Depth_normalized_OCT_volume/I38/sub-I38_ses-OCT_sample-BrocaAreaS01_depth-normed_OCT.ome.tiff
+```
+
+I will keep it going to see if ever returns, will check in an hour. FWIW -- that dataset is [here](https://github.com/dandisets/000026)
+"""]]

comment
diff --git a/doc/bugs/find_should_quite_if_output_of_the_pipe_closes/comment_2_a906714f7e4ab7d9e50745f60e6da5d0._comment b/doc/bugs/find_should_quite_if_output_of_the_pipe_closes/comment_2_a906714f7e4ab7d9e50745f60e6da5d0._comment
new file mode 100644
index 0000000000..13ff17f759
--- /dev/null
+++ b/doc/bugs/find_should_quite_if_output_of_the_pipe_closes/comment_2_a906714f7e4ab7d9e50745f60e6da5d0._comment
@@ -0,0 +1,36 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 2"""
+ date="2026-04-13T14:29:51Z"
+ content="""
+I was able to reproduce this, but only when I ran git-annex with FD 2
+closed.
+
+	perl -e 'close(STDERR); system("git-annex find --not --in here --fast | head -n 1")'
+
+I'm curious if you also ran git-annex with FD 2 closed?
+
+I suspect what must be happening is that the exception handler crashes when
+outputting to stderr, which causes an exception to be thrown,
+leading to a crash loop.
+
+If so, it would seem likely to be a bug in ghc/base. And I'd not be surprised to find
+such a bug somewhere in its bug tracker. In fact, I almost remember finding this same
+behavior before, which may have helped me guess this due was FD 2 being closed.
+
+With that said, I've not been able to reproduce the behavior yet with a simpler
+haskell program like this one:
+
+	import System.IO
+
+	main = do
+		print "foo"
+		hFlush stdout
+		print "bar"
+		hFlush stdout
+		main
+
+But, that simple program also doesn't throw
+"hFlush: resource vanished (Broken pipe)" when piped to `head -n1`,
+so it's not quite replicating what git-annex does.
+"""]]

comment
diff --git a/doc/special_remotes/S3/comment_41_138b9c48237626506b42a9f133612a40._comment b/doc/special_remotes/S3/comment_41_138b9c48237626506b42a9f133612a40._comment
new file mode 100644
index 0000000000..bdee883797
--- /dev/null
+++ b/doc/special_remotes/S3/comment_41_138b9c48237626506b42a9f133612a40._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""Re: git-annex: potential data loss with initremote and push with S3 special remotes."""
+ date="2026-04-13T13:59:28Z"
+ content="""
+That needs to be a bug report. I have copied it to one here:
+[[bugs/S3_pointed_to_minio_console_potential_data_loss]]
+"""]]

comment
diff --git a/doc/bugs/S3_pointed_to_minio_console_potential_data_loss/comment_1_de78ed6d5da146b31516c0c830a5742d._comment b/doc/bugs/S3_pointed_to_minio_console_potential_data_loss/comment_1_de78ed6d5da146b31516c0c830a5742d._comment
new file mode 100644
index 0000000000..3e13fe424f
--- /dev/null
+++ b/doc/bugs/S3_pointed_to_minio_console_potential_data_loss/comment_1_de78ed6d5da146b31516c0c830a5742d._comment
@@ -0,0 +1,28 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2026-04-13T14:01:37Z"
+ content="""
+It's arguably not git-annex's fault if it was pointed to an API endpoint
+that behaves enough like S3 to make it seems like it's stored data,
+but does not store the data.
+
+With that said, for there to be data loss here, the file would need to be
+dropped from the local repository, relying on the copy "stored" in S3.
+So the S3 special remote's checkPresent could be improved to prevent
+such a bad endpoint from being treated as containing the content of an
+object.
+
+For S3, checkPresent does pass in the VersionID when git-annex knows one.
+(Which that doesn't help if the API endpoint ignores that header.)
+What it does not do is check the response from S3 for a VersionID or ETag.
+Improving that seems like a possible way to avoid this kind of problem.
+
+It does check the ETag when the S3 remote is configured with
+exporttree=true.
+
+As for the idea of checking the annex-uuid write by reading the file back,
+the difficulty with that is S3 `DEEP_ARCHIVE` and similar can have an
+hours-long delay to get back out a file that is already stored in the
+bucket. Also, the annex-uuid file is not used for exporttree=yes remotes.
+"""]]

promote comment to bug report
diff --git a/doc/bugs/S3_pointed_to_minio_console_potential_data_loss.mdwn b/doc/bugs/S3_pointed_to_minio_console_potential_data_loss.mdwn
new file mode 100644
index 0000000000..51b043b042
--- /dev/null
+++ b/doc/bugs/S3_pointed_to_minio_console_potential_data_loss.mdwn
@@ -0,0 +1,24 @@
+A colleague used a wrong config, which was pointing to minio console rather than the S3 endpoint. When they ran initremote, the console wrongfully replied 200-OK when PUTting the annex-uuid file, same when they then pushed the data. The minio console always redirect to a login page, and doesn't fail on PUT ( which is non-compliant ).  So the dataset recorded all the data being present in that remote, while there was no trace of any buckets or objects in the S3.
+
+## steps to reproduce:
+
+```
+git init test_s3
+cd test_s3/
+git-annex init
+export AWS_ACCESS_KEY_ID=john AWS_SECRET_ACCESS_KEY=doe
+git annex initremote -d test_remote  host=\"play.min.io\" bucket=\"test_bucket\" type=S3 encryption=none autoenable=true port=9443 protocol=https chunk=1GiB requeststyle=pathecho test > test_annexed_file
+git-annex add test_annexed_file
+git commit -m 'add annexed file'
+git-annex copy --fast --to test_remote
+```
+
+I am showing it with `--fast` flag here, as this is what datalad uses by default. Without `--fast`, it fails with (HeaderException {headerErrorMessage = \"ETag missing\"}) failed which is better.
+
+So to sum it up, the unfortunate circumstances are:
+
+1. the initremote PUT of annex-uuid is not performing check that the annex-uuid file was effectively pushed in a bucket.
+2. minio console replies with 200-OK for all http requests
+3. datalad uses `push --fast` by default, which recorded files as being pushed without performing a HEAD after push. I guess that's for performance reason, but that is dangerous if a server or reverse-proxy ends-up responding 200-OK to all requests after init.
+
+Thanks for your help! 

Added a comment
diff --git a/doc/todo/forget_dead_keys/comment_2_574c34d5fdc7b141970459af5985ff67._comment b/doc/todo/forget_dead_keys/comment_2_574c34d5fdc7b141970459af5985ff67._comment
new file mode 100644
index 0000000000..075b3b1b14
--- /dev/null
+++ b/doc/todo/forget_dead_keys/comment_2_574c34d5fdc7b141970459af5985ff67._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="yarikoptic"
+ avatar="http://cdn.libravatar.org/avatar/f11e9c84cb18d26a1748c33b48c924b4"
+ subject="comment 2"
+ date="2026-04-10T13:03:09Z"
+ content="""
+FWIW, I think this might be useful for openneuro as I think we run into cases (e.g. ds000113) where we have records on some elderly keys (such as SHA1--771e0eea7ceb32216a5a06c89c50d1f02bc79d6d) for which I think we no longer have any commit in the history pointing to them or even if we do -- we have no such key exported in the bucket (I think).
+"""]]

done with DELEGATE extension
diff --git a/doc/todo/Ephemeral_special_remotes.mdwn b/doc/todo/Ephemeral_special_remotes.mdwn
index 7082e52512..79fce6c3d6 100644
--- a/doc/todo/Ephemeral_special_remotes.mdwn
+++ b/doc/todo/Ephemeral_special_remotes.mdwn
@@ -12,3 +12,5 @@ A use case would be to have an "orchestration" special remotes that maybe repres
 in some way also an alternative to the `sameas` approach, where the alternatives are hidden in the implementation of a special remote, rather than in *each* repository.
 
 [[!tag projects/INM7]]
+
+> [[done]]! --[[Joey]]
diff --git a/doc/todo/Ephemeral_special_remotes/comment_13_7527e441ff29366ab5a289090767f930._comment b/doc/todo/Ephemeral_special_remotes/comment_13_7527e441ff29366ab5a289090767f930._comment
new file mode 100644
index 0000000000..8610d3b9b6
--- /dev/null
+++ b/doc/todo/Ephemeral_special_remotes/comment_13_7527e441ff29366ab5a289090767f930._comment
@@ -0,0 +1,7 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 13"""
+ date="2026-04-08T19:22:38Z"
+ content="""
+Finished implementing this!
+"""]]

implement DELEGATE with ephemeral=yes
Factored Annex.DisableRemote out of Command.DisableRemote
diff --git a/Annex/DisableRemote.hs b/Annex/DisableRemote.hs
new file mode 100644
index 0000000000..bcaed58d03
--- /dev/null
+++ b/Annex/DisableRemote.hs
@@ -0,0 +1,189 @@
+{- disable a remote
+ -
+ - Copyright 2026 Joey Hess <id@joeyh.name>
+ -
+ - Licensed under the GNU AGPL version 3 or higher.
+ -}
+
+{-# LANGUAGE OverloadedStrings #-}
+
+module Annex.DisableRemote (disableRemote) where
+
+import Git
+import Annex.Common
+import qualified Annex
+import qualified Git.Remote.Remove
+import qualified Git.Ref
+import Types.Remote
+import Annex.Journal
+import qualified Annex.Branch
+import Annex.Branch.Transitions
+import Types.Transitions
+import Logs
+import Logs.Remote.Pure
+import Logs.MapLog
+import Logs.Transfer
+import Types.Transfer
+import qualified Database.Export
+import qualified Database.Fsck
+import qualified Database.RepoSize
+import qualified Database.ContentIdentifier
+import qualified Utility.OsString as OS
+
+import Data.ByteString.Builder
+import qualified Data.Map as M
+import qualified Data.Set as S
+import qualified Data.ByteString.Lazy as L
+
+disableRemote :: Remote -> RemoteName -> [Remote] -> Annex ()
+disableRemote r remotename remotelist = do
+	let uniqueuuid = not $
+		any (\r' -> uuid r' == uuid r && name r' /= name r) remotelist
+	
+	when uniqueuuid $
+		-- If there are transfers to/from the remote still
+		-- running, this fails. That's why it's run early.
+		removeTransferLogs (uuid r)
+		
+	cleanPrivateJournal r uniqueuuid
+
+	when uniqueuuid $ do
+		-- Each uuid has its own export and fsck database,
+		-- so always remove them, so long as this is the
+		-- only remote using this uuid.
+		Database.Export.removeDb (uuid r)
+		Database.Fsck.removeDb (uuid r)
+		-- These databases are updated from information
+		-- in the git-annex branch, so there is no point in
+		-- removing the uuid from them unless it's private.
+		whenM (isPrivateUUID (uuid r)) $ do
+			Database.RepoSize.removeUUID (uuid r)
+			Database.ContentIdentifier.removeUUID (uuid r) True
+
+		removeFsckState (uuid r)
+		removeImportLog (uuid r)
+		removeCredFiles (uuid r)
+		
+	inRepo $ Git.Remote.Remove.remove remotename
+	removeRemoteTrackingBranches remotename
+
+-- Remove any remote branches. 
+-- This is done because git remote remove only removes the configured
+-- remote tracking branch, not other remote branches.
+removeRemoteTrackingBranches :: String -> Annex ()
+removeRemoteTrackingBranches remotename = do
+	branches <- filter (\b -> branchprefix `isPrefixOf` fromRef b) 
+		. map snd
+		<$> inRepo Git.Ref.list
+	forM_ branches $ \b -> 
+		inRepo $ Git.Ref.delete' b
+  where
+	branchprefix = "refs/remotes/" ++ remotename ++ "/"
+
+isPrivateUUID :: UUID -> Annex Bool
+isPrivateUUID u = 
+	(\c -> u `S.member` annexPrivateRepos c)
+		<$> Annex.getGitConfig
+
+{- Remove a private remote's uuid from the private journal
+ - entirely when it is the only remote using that uuid.
+ -
+ - And, when the remote is a sameas remote, its config is stored
+ - under its config-uuid. Remove that from the private remote log.
+ -}
+cleanPrivateJournal :: Remote -> Bool -> Annex ()
+cleanPrivateJournal r uniqueuuid
+	| uniqueuuid == True = do
+		whenM (isPrivateUUID (uuid r)) $ do
+			gc <- Annex.getGitConfig
+			let tc = filterBranch (\u -> u /= uuid r) gc
+			let handlestale = \_ b -> return (b, Nothing)
+			lockJournal $ \jl -> 
+				overPrivateJournalFileContents handlestale Just
+					(go jl tc)
+		removeconfiguuid
+	| otherwise = removeconfiguuid
+  where
+	go jl tc getfilecontents = getfilecontents >>= \case
+		Just (_, p, Just (b, _)) -> do
+			cleaner jl tc p b
+			go jl tc getfilecontents
+		Just (_, _, Nothing) ->
+			go jl tc getfilecontents
+		Nothing -> return ()
+			
+	cleaner jl tc p b = case tc p b of
+		PreserveFile -> return ()
+		ChangeFile builder ->
+			setlocaljournal jl (RegardingUUID [uuid r]) p builder
+	
+	removeconfiguuid = case remoteAnnexConfigUUID (gitconfig r) of
+		Nothing -> return ()
+		Just cu -> whenM (isPrivateUUID cu) $
+			lockJournal $ \jl ->
+				getJournalFile jl (GetPrivate True) remoteLog >>= \case
+					JournalledContent b -> 
+						scrub jl cu b
+					PossiblyStaleJournalledContent b -> 
+						scrub jl cu b
+					NoJournalledContent ->
+						return ()
+	  where
+		scrub jl cu b =
+			setlocaljournal jl (RegardingUUID [cu]) remoteLog $
+				buildRemoteConfigLog $ MapLog $ M.delete cu $
+					fromMapLog $ parseRemoteConfigLog b
+
+	setlocaljournal jl ru p builder =
+		let b' = toLazyByteString builder
+		in if L.null b'
+			then deleteJournalFile jl ru p
+			else do
+				b'' <- Annex.Branch.getLocal' (GetPrivate False) p
+				if b'' == b'
+					then deleteJournalFile jl ru p
+					else setJournalFile jl ru p builder
+
+removeFsckState :: UUID -> Annex ()
+removeFsckState u = do
+	d <- fromRepo (gitAnnexFsckStateDir u)
+	liftIO $ whenM (doesDirectoryExist d) $
+		removeDirectoryRecursive d
+	f <- fromRepo (gitAnnexFsckResultsLog u)
+	liftIO $ removeWhenExistsWith removeFile f
+
+removeImportLog :: UUID -> Annex ()
+removeImportLog u = do
+	f <- calcRepo' (gitAnnexImportLog u)
+	liftIO $ removeWhenExistsWith removeFile f
+	
+removeTransferLogs :: UUID -> Annex ()
+removeTransferLogs u = do
+	-- getTransfers calls checkTransfer, which cleans up
+	-- transfer log files for transfers that are no longer running.
+	whenM (any foru <$> getTransfers) $
+		error "Active trasfers, cannot disable the remote."
+	forM_ [Upload, Download] $ \direction -> do
+		d <- fromRepo $ gitAnnexTransferUUIDDirectionDir u direction
+		liftIO $ void $ tryNonAsync $ removeDirectory d
+		d' <- fromRepo $ gitAnnexFailedTransferDir u direction
+		liftIO $ void $ tryNonAsync $ removeDirectory d'
+	clearFailedTransfers u
+  where
+	foru (t, _) = transferUUID t == u
+
+removeCredFiles :: UUID -> Annex ()
+removeCredFiles u = do
+	d <- fromRepo gitAnnexCredsDir
+	liftIO $ whenM (doesDirectoryExist d) $ do
+		mapM_ (removeWhenExistsWith removeFile)
+			=<< filter foru <$> dirContents d
+  where
+	us = fromUUID u
+
+	-- Remotes that use creds always include their UUID as part of the
+	-- filename. However, some remotes (Remote.External) need more than
+	-- one creds file, and add a "-foo" suffix to the UUID.
+	foru p = 
+		let f = takeFileName p
+		in f == us || (us <> literalOsPath "-") `OS.isPrefixOf` f
diff --git a/Command/DisableRemote.hs b/Command/DisableRemote.hs
index 46130bc273..d3bfe80d05 100644
--- a/Command/DisableRemote.hs
+++ b/Command/DisableRemote.hs
@@ -5,36 +5,11 @@

(Diff truncated)