<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.3.4">Jekyll</generator><link href="https://radicle.dev/https://radicle-website.liw.fi/feed.xml" rel="self" type="application/atom+xml" /><link href="https://radicle.dev/https://radicle-website.liw.fi/" rel="alternate" type="text/html" /><updated>2026-05-21T19:44:11+03:00</updated><id>https://radicle.dev/https://radicle-website.liw.fi/feed.xml</id><title type="html">Radicle: the sovereign forge</title><subtitle>The Radicle forge is an open source, peer-to-peer code collaboration stack built on Git.</subtitle><entry><title type="html">Radicle 1.9.0 – Hawthorn</title><link href="https://radicle.dev/https://radicle-website.liw.fi/2026/05/19/radicle-1.9.0.html" rel="alternate" type="text/html" title="Radicle 1.9.0 – Hawthorn" /><published>2026-05-19T00:00:00+03:00</published><updated>2026-05-19T00:00:00+03:00</updated><id>https://radicle.dev/https://radicle-website.liw.fi/2026/05/19/radicle-1.9.0</id><content type="html" xml:base="https://radicle.dev/https://radicle-website.liw.fi/2026/05/19/radicle-1.9.0.html"><![CDATA[<p>The Radicle team would like to announce the release of Radicle 1.9.0, code name <em><a href="https://en.wikipedia.org/wiki/Crataegus">Hawthorn</a></em>.
The Hawthorn tree, or Mayflower, signifies the coming of summer, and has significance for many cultures.
In particular, the Hawthorn tree represents the door to the “other side” and is the home of the fairies in Irish culture.
It is forbidden to cut down the Hawthorn tree, unless you want to be cursed by the fairies.
So, this release represents being on the other side of the <a href="/https://radicle-website.liw.fi/2026/03/30/disclosure-of-vulnerability-in-signed-references.html">fixed security vulnerability in 1.8.0</a>, and readying ourselves to ensure stronger foundations for the future.</p>

<p>This release contains 165 commits by 9 contributors, with a big thanks to:</p>
<ul>
  <li>Daniel Norman</li>
  <li>Josh Soref</li>
  <li>Richard Levitte</li>
  <li>stefan</li>
  <li>Wiktor Kwapisiewicz</li>
</ul>

<h2 id="installation">Installation</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl -sSLf https://radicle.dev/install | sh -s -- --no-modify-path --version=1.9.0
</code></pre></div></div>

<h2 id="in-this-release">In this Release</h2>

<h3 id="domain-name-migration">Domain Name Migration</h3>

<p>Following a <a href="/https://radicle-website.liw.fi/2026/04/23/domain-move.html">domain move of the project</a>, the names of the bootstrap nodes have changed to: <code class="language-plaintext highlighter-rouge">{iris,rosa}.radicle.{xyz → network}</code>.
If you are still using the old names in the Radicle configuration, this will be detected and you will see warnings printed.
Similarly, if you are using systemd credentials, then you should migrate from <code class="language-plaintext highlighter-rouge">xyz.radicle.node.*</code> to <code class="language-plaintext highlighter-rouge">dev.radicle.node.*</code>.
The COB type names and payload IDs remain unchanged for backwards compatibility.</p>

<h3 id="revision-ranges-in-rad-patch-show">Revision Ranges in <code class="language-plaintext highlighter-rouge">rad patch show</code></h3>

<p>Each revision in the output of <code class="language-plaintext highlighter-rouge">rad patch show</code> now shows the base and head of the revision in the format: <code class="language-plaintext highlighter-rouge">&lt;base&gt;..&lt;head&gt;</code>.
The shortened form is used, but the full commit OID is used when <code class="language-plaintext highlighter-rouge">--verbose</code> is passed.
This makes comparing two revisions much easier in combination with <code class="language-plaintext highlighter-rouge">git range-diff</code>.
For example, here is a patch in <code class="language-plaintext highlighter-rouge">heartwood</code>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>╭───────────────────────────────────────────────────────────────────────────╮
│ Title    .radicle/ambient: Add pre-plan action for rustup                 │
│ Patch    3bb6f611190fc40207cdee0d22c421b02a6bc717                         │
│ Author   fintohaps (you)                                                  │
│ Head     d9f9d090bde88ba0b6596614579641a15acff871                         │
│ Base     9158df5067429282cbec60292316c13b3d965c5a                         │
│ Commits  ahead 1, behind 3                                                │
│ Status   open                                                             │
│                                                                           │
│ To ensure the correct toolchain is used when building and testing the     │
│ project, a pre-plan action is added for `rustup`.                         │
│ It uses the same `channel` as defined in the `rust-toolchain.toml`.       │
│ A note is left about this duplication, and the possibility of it being    │
│ supported in the future.                                                  │
├───────────────────────────────────────────────────────────────────────────┤
│ d9f9d09 .radicle/ambient: Add pre-plan action for rustup                  │
├───────────────────────────────────────────────────────────────────────────┤
│ ● Revision 3bb6f61 @ 9158df5..d9f9d09 by fintohaps (you) 5 days ago       │
│ ↑ Revision 183d186 @ 9158df5..040ab10 by lars z6MkgEM…1b2w2FV 2 hours ago │
╰───────────────────────────────────────────────────────────────────────────╯
</code></pre></div></div>

<p>As long as the commits are fetched from <code class="language-plaintext highlighter-rouge">fintohaps</code> and <code class="language-plaintext highlighter-rouge">lars</code>, then you can run:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ git range-diff 9158df5..d9f9d09 9158df5..040ab10
1:  d9f9d090b = 1:  d9f9d090b .radicle/ambient: Add pre-plan action for rustup
-:  --------- &gt; 2:  040ab1045 work around problems with Ambient Rust toolchain downloading
</code></pre></div></div>

<p>Showing that a new commit was added, and no other changes were made.</p>

<h3 id="nodes-advertise-radicle-version">Nodes Advertise Radicle Version</h3>

<p>Nodes will now advertise the version of Radicle they are running in the node announcement as part of the “user agent”, which is shared among the network.
For example, the value that will be shared by Radicle 1.9.0 will be <code class="language-plaintext highlighter-rouge">/radicle:1.9.0/</code>.
This value is also customizable by node operators via the configuration value <code class="language-plaintext highlighter-rouge">node.userAgent</code>. Refer to <code class="language-plaintext highlighter-rouge">rad config schema</code> for more information on the possible values.
Operators that choose to set a custom value are asked to keep the substring <code class="language-plaintext highlighter-rouge">/radicle:{YOUR_VERSION}/</code> which allows for better telemetry regarding version distribution on the network.
To opt-out of sending any meaningful user agent, set <code class="language-plaintext highlighter-rouge">node.userAgent = null</code>.</p>

<h3 id="introducing-i2p-support">Introducing I2P Support</h3>

<p>In addition to connections via SOCKS proxy and Tor for *.onion hostnames, I2P hostnames are now supported.
These names are of the form *.i2p{,.alt}.
To enable making connections via I2P, configure <code class="language-plaintext highlighter-rouge">node.i2p</code>, for example:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"node"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"i2p"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"mode"</span><span class="p">:</span><span class="w"> </span><span class="s2">"proxy"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"address"</span><span class="p">:</span><span class="w"> </span><span class="s2">"127.0.0.1:4447"</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<h3 id="symbolic-canonical-references">Symbolic Canonical References</h3>

<p>It is now possible to define symbolic canonical references for a repository.
The payload <code class="language-plaintext highlighter-rouge">xyz.radicle.crefs</code> was extended to accept an object with key “symbolic” next to “rules”.
Consider the following example:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"payload"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"xyz.radicle.crefs"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"rules"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"refs/heads/qa"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"allow"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
            </span><span class="s2">"did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk"</span><span class="w">
          </span><span class="p">],</span><span class="w">
          </span><span class="nl">"threshold"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="w">
        </span><span class="p">},</span><span class="w">
        </span><span class="nl">"refs/tags/*"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"allow"</span><span class="p">:</span><span class="w"> </span><span class="s2">"delegates"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"threshold"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="w">
        </span><span class="p">},</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="nl">"symbolic"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"refs/heads/staging"</span><span class="p">:</span><span class="w"> </span><span class="s2">"refs/heads/qa"</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>Delegates are allowed to create tags, and one particular user is allowed to control the branch named “qa”.
The team working on this repository used to call the “qa” branch “staging”, so they decided to keep a symbolic reference from “staging” to “qa” around for a while.</p>

<p>For further information about symbolic references also refer to the documentation of <a href="https://git-scm.com/docs/git-symbolic-ref"><code class="language-plaintext highlighter-rouge">git symbolic-ref</code></a>.</p>

<h3 id="deprecating-rad-config-subcommands">Deprecating <code class="language-plaintext highlighter-rouge">rad config</code> Subcommands</h3>

<p>The commands to read and modify particular values in Radicle configuration via the CLI were marked as obsolete, i.e.,</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">rad config get</code></li>
  <li><code class="language-plaintext highlighter-rouge">rad config push</code></li>
  <li><code class="language-plaintext highlighter-rouge">rad config remove</code></li>
  <li><code class="language-plaintext highlighter-rouge">rad config set</code></li>
  <li><code class="language-plaintext highlighter-rouge">rad config unset</code></li>
</ul>

<p>In the future, please modify Radicle configuration with your favorite text editor (e.g. via <code class="language-plaintext highlighter-rouge">rad config edit</code>), or specialized tools like <code class="language-plaintext highlighter-rouge">jq</code>.</p>

<h3 id="fixed-bugs">Fixed Bugs</h3>

<h4 id="gracefully-handle-malformed-addresses">Gracefully Handle Malformed Addresses</h4>

<p>Skip node address entries that cannot be parsed from an SQLite row into a valid address entry.
This improves the node service, when it checks available peers.
Previously, if it found a row it could not parse, then it would fail the whole process.
Now, it will continue, providing valid entries to connect to.</p>

<p>To ensure that invalid IPv6 addresses no longer exist in your SQLite database, invalid addresses are removed.
Entries deleted include ones that have an address of the form <code class="language-plaintext highlighter-rouge">[]:port</code>, or that have an invalid address within the <code class="language-plaintext highlighter-rouge">[]</code>.
This removal happens automatically through a database migration, that runs at node startup.</p>

<h4 id="handling-of--in-canonical-references">Handling of <code class="language-plaintext highlighter-rouge">*</code> in Canonical References</h4>

<p>Correctly handle the canonical reference rules that have a glob star suffix, e.g., <code class="language-plaintext highlighter-rouge">refs/heads/main*</code>, <code class="language-plaintext highlighter-rouge">refs/heads/main-*</code>, etc.
Previously, these would be expanded into sub-component searches.
For example, in the previous examples, the search would be expanded to <code class="language-plaintext highlighter-rouge">refs/heads/main**/*</code> and <code class="language-plaintext highlighter-rouge">refs/heads/main-**/*</code>.
Now, the rule will match by prefix, e.g. <code class="language-plaintext highlighter-rouge">refs/heads/main-*</code> will match <code class="language-plaintext highlighter-rouge">refs/heads/main-a</code>, <code class="language-plaintext highlighter-rouge">refs/heads/main-b</code>, <code class="language-plaintext highlighter-rouge">refs/heads/main-deadbeef</code>, etc.</p>

<h2 id="changelog">Changelog</h2>

<ul>
  <li><code class="language-plaintext highlighter-rouge">100040253</code> <strong>node: upgrade cyphernet to fix a panic in socks5-client when using artix</strong> <em><a href="mailto:stefan.r.boca@gmail.com">stefan.r.boca@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9158df506</code> <strong>flake: Add NixOS tests to checks</strong> <em><a href="mailto:lorenz.leutgeb@radicle.dev">lorenz.leutgeb@radicle.dev</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">767b80e7f</code> <strong>flake: Sort Inputs Lexicographically</strong> <em><a href="mailto:lorenz.leutgeb@radicle.dev">lorenz.leutgeb@radicle.dev</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c5043617b</code> <strong>flake: Fix nixpkgs inputs</strong> <em><a href="mailto:lorenz.leutgeb@radicle.dev">lorenz.leutgeb@radicle.dev</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">caee776c3</code> <strong>log: New crate for logger implementations</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f22811e01</code> <strong>simulation/README: Note for running on NixOS</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">277f2615c</code> <strong>simulation: Ensure OVMF is available</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9dda890fb</code> <strong>flake.nix: Add simulation requirements to devShell</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ac6759b74</code> <strong>simulation: Switch externalAddress config parsing to jq</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d64889200</code> <strong>simulation: Extract external address configuration bash commands</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f41bea1d6</code> <strong>simulation: Vendor Timoni dependencies as part of start-network</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ae4a70e3b</code> <strong>simulation: Update README</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d197ab613</code> <strong>simulation: Add justfile and network.cue topology definition</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8622a466c</code> <strong>simulation: Ignore cue.mod/pkg and cue.mod/gen for Timoni</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">620a1ec69</code> <strong>simulation: Introduce particle CUE module for radicle-node</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">be5a1742f</code> <strong>flake.lock: Update nixpkgs-stable</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0d7bc8d1d</code> <strong>build: Update apline version to 3.22</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">420af3b71</code> <strong>workspace/rust: 1.90 → 1.95</strong> <em><a href="mailto:lorenz.leutgeb@radicle.dev">lorenz.leutgeb@radicle.dev</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9ea040ccd</code> <strong>rust/msrv: 1.85.0 → 1.88.0</strong> <em><a href="mailto:lorenz.leutgeb@radicle.dev">lorenz.leutgeb@radicle.dev</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0a0e70b1d</code> <strong>node/systemd: Fix reading credentials</strong> <em><a href="mailto:lorenz.leutgeb@radicle.dev">lorenz.leutgeb@radicle.dev</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">6b460c442</code> <strong>logger: Respect config file log level</strong> <em><a href="mailto:daniel@norman.life">daniel@norman.life</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">917714679</code> <strong>radicle/web: Fix schema of <code class="language-plaintext highlighter-rouge">Config::description</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.dev">lorenz.leutgeb@radicle.dev</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ee9a9de36</code> <strong>radicle/web: Relax deserialization of <code class="language-plaintext highlighter-rouge">Config</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.dev">lorenz.leutgeb@radicle.dev</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">53db99414</code> <strong>schemars: Release 0.8.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ad068309c</code> <strong>fetch: Release 0.20.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ab3621d5d</code> <strong>remote-helper: Release 0.17.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f5c39dd60</code> <strong>cob: Release 0.20.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">baf533b37</code> <strong>cli: Release 0.21.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">342b4d963</code> <strong>node: Release 0.20.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">622f3827b</code> <strong>protocol: Release 0.8.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">2707f6b4b</code> <strong>radicle: Release 0.24.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">3486c028e</code> <strong>term: Release 0.18.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">5991bdfa9</code> <strong>systemd: Release 0.13.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">287141780</code> <strong>oid: Release 0.2.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">4ca2098cb</code> <strong>core: Release 0.3.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">64a419d79</code> <strong>crypto: Release 0.17.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">3f81e83d3</code> <strong>radicle/crefs: Support Symbolic References</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">080790d84</code> <strong>radicle/git/canonical: Add explicit test case for fast_glob pattern match syntax</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">80d30d3b5</code> <strong>e2e: Fix false-positive in canonical ref update test</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ed340f572</code> <strong>e2e: Add partial glob match cref test</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">e87af868d</code> <strong>node/test: <code class="language-plaintext highlighter-rouge">NodeHandle::commit_to</code> should namespace</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8724ebe78</code> <strong>radicle/git/canonical: Introduce property tests for glob matching behaviour</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">fb40bdc0a</code> <strong>radicle/git/canonical: Fix glob rewrite rule for trailing asterisk</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">455138f4a</code> <strong>radicle/canonical/rules: Reorganise test suite</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">998f527bd</code> <strong>node/db: delete unparseable ipv6 rows</strong> <em><a href="mailto:daniel@norman.life">daniel@norman.life</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a45a1078a</code> <strong>node: Skip unreadable address rows in <code class="language-plaintext highlighter-rouge">entries()</code></strong> <em><a href="mailto:daniel@norman.life">daniel@norman.life</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">5dae2a8b5</code> <strong>treewide: Spelling</strong> <em>&lt;2119212+jsoref@users.noreply.github.com&gt;</em></li>
  <li><code class="language-plaintext highlighter-rouge">a10170501</code> <strong>term: Rename <code class="language-plaintext highlighter-rouge">Row::Divid{i,}er</code></strong> <em>&lt;2119212+jsoref@users.noreply.github.com&gt;</em></li>
  <li><code class="language-plaintext highlighter-rouge">08dd1dfda</code> <strong>node/test: Fix Spelling</strong> <em>&lt;2119212+jsoref@users.noreply.github.com&gt;</em></li>
  <li><code class="language-plaintext highlighter-rouge">8391599f6</code> <strong>oid: Fix spelling</strong> <em>&lt;2119212+jsoref@users.noreply.github.com&gt;</em></li>
  <li><code class="language-plaintext highlighter-rouge">b482845e7</code> <strong>sigrefs/git/properties: Restore property tests</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">92347a307</code> <strong>justfile: Add Rust tests to pre-push</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">b4707e550</code> <strong>cli: Amend jj tests</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">378365aa4</code> <strong>term: Deny <code class="language-plaintext highlighter-rouge">print_stdout</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">cc70d7dad</code> <strong>radicle/cob: Do not return <code class="language-plaintext highlighter-rouge">BrokenPipe</code> from external COB invocation</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">553a3ebd0</code> <strong>cli/cob: Remove check of <code class="language-plaintext highlighter-rouge">BrokenPipe</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">56625a42f</code> <strong>term: Rename print_inline to print</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">2262b8d9b</code> <strong>term: Rename print to println</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">e7d519cf6</code> <strong>term: Rename println to println_prefixed</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">1a31a9f54</code> <strong>cli: Handle broken pipe (SIGPIPE) gracefully</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">e1f16bee2</code> <strong>term: Catch EPIPE and swallow</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8f4b90db7</code> <strong>cli/test: Add broken pipe (SIGPIPE) tests</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">7b07e57b9</code> <strong>treewide/test: Use <code class="language-plaintext highlighter-rouge">impl Arbitrary for Oid</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">88a7252e3</code> <strong>oid: Fix <code class="language-plaintext highlighter-rouge">impl Arbitrary for Oid</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">deabe6d2c</code> <strong>oid: Nicer panic message</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">60f42bff5</code> <strong>protocol: Minimize scope of <code class="language-plaintext highlighter-rouge">radicle::git::raw</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8dba3ca9d</code> <strong>protocol: Decode <code class="language-plaintext highlighter-rouge">radicle_oid::Oid</code> without <code class="language-plaintext highlighter-rouge">git2</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">3d1b37fcb</code> <strong>oid: Make <code class="language-plaintext highlighter-rouge">Oid::SHA1_LEN</code> public</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f46624b81</code> <strong>oid: SHA1_DIGEST_LEN → Oid::LEN_SHA1</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">4c605c067</code> <strong>radicle: Avoid comparison with <code class="language-plaintext highlighter-rouge">ZERO_SHA1</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ecca50a5f</code> <strong>treewide: Avoid <code class="language-plaintext highlighter-rouge">git2::Oid::zero</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f65175397</code> <strong>oid: <code class="language-plaintext highlighter-rouge">const ZERO_SHA1</code> instead of <code class="language-plaintext highlighter-rouge">fn sha1_zero</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">aa177b040</code> <strong>treewide: radicle.{xyz → dev,network}</strong> <em><a href="mailto:lorenz.leutgeb@radicle.dev">lorenz.leutgeb@radicle.dev</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">cb57e6560</code> <strong>node: Rename systemd Credentials</strong> <em><a href="mailto:lorenz.leutgeb@radicle.dev">lorenz.leutgeb@radicle.dev</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">06ff36ebc</code> <strong>cli: Update warning for new bootstrap node names</strong> <em><a href="mailto:lorenz.leutgeb@radicle.dev">lorenz.leutgeb@radicle.dev</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">22287fd94</code> <strong>radicle: Change names of bootstrap nodes</strong> <em><a href="mailto:lorenz.leutgeb@radicle.dev">lorenz.leutgeb@radicle.dev</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">3bc8abdc2</code> <strong>radicle/node/config: Use <code class="language-plaintext highlighter-rouge">IndexSet</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.dev">lorenz.leutgeb@radicle.dev</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">099722dd0</code> <strong>radicle: Propagate <code class="language-plaintext highlighter-rouge">radicle-oid/qcheck</code></strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">5d8988b1a</code> <strong>CONTRIBUTING/HACKING: Add note on direnv</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8af0b623f</code> <strong>.envrc: Replace .envrc with .envrc.sample</strong> <em><a href="mailto:richard@levitte.org">richard@levitte.org</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">bdd991a5f</code> <strong>e2e: Fix race condition in test_non_fastforward_identity_doc</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">802e4726e</code> <strong>e2e: Replace the hardcoded 1-second sleep in <code class="language-plaintext highlighter-rouge">test_connection_crossing</code> with polling loop</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">bfb54bf4b</code> <strong>e2e: Fix flakiness in <code class="language-plaintext highlighter-rouge">test_connection_crossing</code> test</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">bbb127960</code> <strong>cli/config: Obsolete <code class="language-plaintext highlighter-rouge">{get,set,push,remove,unset}</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f83eb5771</code> <strong>ci: Update GitHub action <code class="language-plaintext highlighter-rouge">actions/cache</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">224c03daf</code> <strong>node: Expand <code class="language-plaintext highlighter-rouge">target_os</code> condition for keep-alive</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">4a81673d0</code> <strong>node: Fix conditions for socket activation</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">354805aeb</code> <strong>cli/test: Fix failures related to remote HEAD</strong> <em><a href="mailto:richard@levitte.org">richard@levitte.org</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">6ce2d00be</code> <strong>flake: Set <code class="language-plaintext highlighter-rouge">RUST_BACKTRACE</code> in development shell</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">2d20e249f</code> <strong>cli/init: Deduplicate <code class="language-plaintext highlighter-rouge">ScopeParser</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f8ec40a33</code> <strong>just: Make it possible to give your own cargo command</strong> <em><a href="mailto:richard@levitte.org">richard@levitte.org</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">4f647b2a1</code> <strong>Spell “Radicle” with a captial R</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">bb97414a2</code> <strong>cli: Deduplicate RID Argument Handling</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f2e96c96c</code> <strong>cli: Rename all <code class="language-plaintext highlighter-rouge">RepoId</code> args to <code class="language-plaintext highlighter-rouge">repo</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">07c624499</code> <strong>just: Check for Git and Jujutsu-VCS conflict markers</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f00a1624d</code> <strong>codespell: Add .direnv to skip list</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8a38fa8c7</code> <strong>typos: Rule for … -&gt; …</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">fe353ea7e</code> <strong>codespell: Rule for … -&gt; …</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">179a08086</code> <strong>just: Introduce commit-msg hook for typos</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f6bf13422</code> <strong>just: Fix doublestar expansion in check-scripts</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">083c9d1ab</code> <strong>just: Replace inline scripts with script file calls</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">421a43376</code> <strong>just: Drop underline from output styline</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">6744384ac</code> <strong>just: Extract inline bash scripts out to files</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">df31702b8</code> <strong>flake: Add <code class="language-plaintext highlighter-rouge">just</code> to development shell</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">fc1241477</code> <strong>just: Rename <code class="language-plaintext highlighter-rouge">HOOK_NAME</code> to just <code class="language-plaintext highlighter-rouge">HOOK</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">112c901de</code> <strong>flake: Add codespell</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">69ccabacd</code> <strong>just: Use bash to perform install-hook confirmation</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">1f4de60ba</code> <strong>just: Add minimum version to CONTRIBUTING and HACKING</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">11e80d309</code> <strong>just: Check for file before removing in install-hooks</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a74befd2a</code> <strong>just: Expand shellcheck glob to all shell scripts</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">983e5e19d</code> <strong>just: Use full argument names for codespell</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">3e9df1c8e</code> <strong>just: Remove existing hooks during install-hooks</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ffe5b9ed0</code> <strong>just: Better doc comment for check-keywords</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">b0af317ea</code> <strong>hacking: Update docs with ‘just’ commands</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">6e2b71035</code> <strong>contributing: Update docs with ‘just’ commands</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">1df1acabf</code> <strong>git-hook-template: minor output formatting</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">4e0f739c2</code> <strong>just: Add post-checkout hook</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">09cd3eeb8</code> <strong>just: Add check-hooks to confirm presence and integrity</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">eb8467cb6</code> <strong>just: Introduce output formatting</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">bdb2a1fc7</code> <strong>just: Introduce pre-commit and pre-push installer</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">576bc6d6a</code> <strong>just: Add groupings and parallel where possible</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">3082f9976</code> <strong>just: Add pre-commit hook</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9310b1eff</code> <strong>just: Add more pre-push tasks</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9210f0871</code> <strong>just: Introduce justfile with pre-push hook cmds</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">430868ffb</code> <strong>codespell: Add ‘ser’ to <code class="language-plaintext highlighter-rouge">ignore-words-list</code></strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9c6bcd277</code> <strong>cli: Fix typo “writeable” → “writable”</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ac3eba09a</code> <strong>I2P Support</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9b9b5ca99</code> <strong>cargo: Update <code class="language-plaintext highlighter-rouge">cyphernet</code> from 0.5.2 to 0.5.3</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">91b2fd898</code> <strong>clippy: Deny <code class="language-plaintext highlighter-rouge">unwrap_used</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">4d57ba496</code> <strong>rust: Disallow lint <code class="language-plaintext highlighter-rouge">dead_code</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c23a257f3</code> <strong>clippy: Configure lint <code class="language-plaintext highlighter-rouge">unwrap_used</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">dbec748c4</code> <strong>clippy: Disallow unused lints</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">63f960742</code> <strong>clippy: Disallow lint <code class="language-plaintext highlighter-rouge">iter_nth_zero</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f87d25439</code> <strong>clippy: Disallow lint <code class="language-plaintext highlighter-rouge">identity_op</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">33a8c09f7</code> <strong>clippy: Disallow lint <code class="language-plaintext highlighter-rouge">match_like_matches_macro</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ca732015f</code> <strong>clippy: Disallow lints <code class="language-plaintext highlighter-rouge">collapsible_*</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">44244dc00</code> <strong>clippy: Disallow lint <code class="language-plaintext highlighter-rouge">type_complexity</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ffc81154e</code> <strong>clippy: Disallow lint <code class="language-plaintext highlighter-rouge">enum_variant_names</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ae55d935b</code> <strong>cargo/workspace/lints: Shorten notation</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">547a75376</code> <strong>simulation: Add README with overview and plan</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">94f65a71d</code> <strong>cargo: Remove unused dependencies</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">adfd89f60</code> <strong>cli-test: Respect <code class="language-plaintext highlighter-rouge">CARGO_TARGET_DIR</code></strong> <em><a href="mailto:richard@levitte.org">richard@levitte.org</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">80c1bba76</code> <strong>radicle: Prevent <code class="language-plaintext highlighter-rouge">RAD_SOCKET</code> from polluting tests</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a2de55cbb</code> <strong>radicle/crefs: Use <code class="language-plaintext highlighter-rouge">GetPayload</code> to load</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">516736791</code> <strong>radicle: Introduce <code class="language-plaintext highlighter-rouge">trait GetPayload</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">aa2856703</code> <strong>radicle/crefs: Refactor <code class="language-plaintext highlighter-rouge">GetCanonicalRefs</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ef101d9ab</code> <strong>radicle/crefs/protect: Module for protected refs</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">e822623dc</code> <strong>radicle/crefs/rules: Exact patterns for branches</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">bfb285805</code> <strong>radicle/storage: Split <code class="language-plaintext highlighter-rouge">WriteRepository::set_head</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0eba6caf9</code> <strong>radicle: More convenience methods to get default branch</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">22b2871f6</code> <strong>radicle: Add Version to User Agent</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">48551cde9</code> <strong>crypto: Use <code class="language-plaintext highlighter-rouge">ssh-agent-lib</code> for SSH Agent</strong> <em><a href="mailto:wiktor@metacode.biz">wiktor@metacode.biz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0080813c9</code> <strong>term: Update inquire to 0.9.4</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">5b6ae0ac4</code> <strong>Update radicle-surf to 0.27.1</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">546001253</code> <strong>protocol: Use pastey fork</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">96f573b76</code> <strong>cargo: Update dependencies with <code class="language-plaintext highlighter-rouge">cargo update</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">91590a328</code> <strong>cli/patch: Show Commit Ranges of Revisions</strong> <em><a href="mailto:richard@levitte.org">richard@levitte.org</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">b8f8cfb31</code> <strong>cli/terminal: Formatting Functions for Ranges</strong> <em><a href="mailto:richard@levitte.org">richard@levitte.org</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">b54fc820e</code> <strong>radicle/tor: Fixes</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f223afd9d</code> <strong>radicle: Refactor COB Storage Access</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">10a82958c</code> <strong>node: Explicit default for <code class="language-plaintext highlighter-rouge">AddressConfig</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">fb1808395</code> <strong>radicle/serde_ext: <code class="language-plaintext highlighter-rouge">fn null_to_default</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">1e132685b</code> <strong>cargo: Add feature for Tor support</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8bac24d6a</code> <strong>rust/edition/fmt: 2021 → 2024</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0494227e7</code> <strong>rust/edition: 2021 → 2024</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
</ul>

<h2 id="checksums">Checksums</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>42c90f273cf20c4ee1614dc7601c7595b900bf796ef97ba408dc262d48b7e514  radicle-1.9.0-x86_64-apple-darwin.tar.xz
bf5b7d6437eb1a378502d2e7ffbb192381f82a4d093018021585e1fd2e639530  radicle-1.9.0-aarch64-unknown-linux-musl.tar.xz
7adee42d3c3db6e9ba234040b1d9e37f4c2ea152ba7251e80b61a1afef3362a1  radicle-1.9.0-x86_64-unknown-linux-musl.tar.xz
768ef26013df96ea3506e6cf917726550e2d4bb94be3361dd2d7d6522be2ccf6  radicle-1.9.0-aarch64-apple-darwin.tar.xz
</code></pre></div></div>]]></content><author><name></name></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://radicle.dev/https://radicle-website.liw.fi/radicle-1.png" /><media:content medium="image" url="https://radicle.dev/https://radicle-website.liw.fi/radicle-1.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">We have moved to radicle.{dev,network}!</title><link href="https://radicle.dev/https://radicle-website.liw.fi/2026/04/23/domain-move.html" rel="alternate" type="text/html" title="We have moved to radicle.{dev,network}!" /><published>2026-04-23T00:00:00+03:00</published><updated>2026-04-23T00:00:00+03:00</updated><id>https://radicle.dev/https://radicle-website.liw.fi/2026/04/23/domain-move</id><content type="html" xml:base="https://radicle.dev/https://radicle-website.liw.fi/2026/04/23/domain-move.html"><![CDATA[<p>We have moved! Our main domain changed from <a href="https://radicle.xyz">radicle.xyz</a> to <a href="https://radicle.dev">radicle.dev</a>, because we wanted to be closer to our main audience of software developers. In addition, we use this occasion to implement another change, with a more technical motivation.</p>

<p>Back in 2025-10, we received multiple reports that our domain, radicle.xyz, did not resolve via the ISPs Swisscom, Telenor, and Virgin Media. The domain was indexed and added to various block lists. Unfortunately, the keepers of these block lists are not very open about their reasons for blocking, so we do not know exactly why radicle.xyz was indexed. We believe that the reason was content served via app.radicle.xyz, our public instance of Radicle Explorer, which allows you to access many nodes in the network. (Note that most of these block lists do not differentiate subdomains, but have exceptions for cases like co.uk.)</p>

<p>Since that incident, we were looking for ways to protect ourselves from getting blocked again in the future. The obvious way would be to self-censor, and have app.radicle.xyz only serve curated content. Obviously we reject this approach, because we want to host an instance of Radicle Explorer to provide a view onto as many repositories as possible, with as little discrimination/censorship as possible. (Please note that we have blocked nodes and repositories on iris.radicle.xyz and rosa.radicle.xyz in the past, if we felt that they were clearly overstepping boundaries, and we will continue to do so. If anyone thinks that this undermines the censorship resistance of Radicle, please think again.)</p>

<p>Rather, the mitigation that we found more appealing, was to use a different domain, and separate content out accordingly. This means that, going forward, we will split:</p>
<ol>
  <li>Content <em>about</em> Radicle (explainers, guides, download links, blog posts) which is under control of the Radicle team. We will use radicle.dev for these purposes.</li>
  <li>Content <em>on</em> Radicle (repositories hosted on practically any node on the network) which the Radicle team has only very little control over, accessible via Radicle Explorer. Going forward, our deployment of Radicle Explorer will <em>not</em> be hosted on app.radicle.xyz anymore, but instead it will be hosted at <a href="https://radicle.network">radicle.network</a>.</li>
</ol>

<p>The idea is of course that if there are complaints about or issues with radicle.network in the future, we hope that radicle.dev stays largely unaffected and people can continue to inform themselves about Radicle and learn how to set it up.</p>

<p>We will, for the foreseeable future, serve redirects from app.radicle.xyz to radicle.network, so that your links do not break, but please make the switch soon.</p>

<p>Our permissive seed nodes Iris and Rosa should now be addressed as iris.radicle.network and rosa.radicle.network, and the next release of Radicle will include an appropriate change. Note that they also will keep responding to iris.radicle.xyz and rosa.radicle.xyz for some time to ensure a smooth transition. The (non-permissive) seed node that the team uses for development was renamed to seed.radicle.dev.</p>

<p>Our AT Protocol handle changed to radicle.dev. Our Mastodon handle has changed to @radicle@toot.radicle.dev.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[We have moved! Our main domain changed from radicle.xyz to radicle.dev, because we wanted to be closer to our main audience of software developers. In addition, we use this occasion to implement another change, with a more technical motivation.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://radicle.dev/https://radicle-website.liw.fi/radicle-1.png" /><media:content medium="image" url="https://radicle.dev/https://radicle-website.liw.fi/radicle-1.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Disclosure of Replay Attack Vulnerability in Signed References</title><link href="https://radicle.dev/https://radicle-website.liw.fi/2026/03/30/disclosure-of-vulnerability-in-signed-references.html" rel="alternate" type="text/html" title="Disclosure of Replay Attack Vulnerability in Signed References" /><published>2026-03-30T00:00:00+03:00</published><updated>2026-03-30T00:00:00+03:00</updated><id>https://radicle.dev/https://radicle-website.liw.fi/2026/03/30/disclosure-of-vulnerability-in-signed-references</id><content type="html" xml:base="https://radicle.dev/https://radicle-website.liw.fi/2026/03/30/disclosure-of-vulnerability-in-signed-references.html"><![CDATA[<p>As announced in the release notes for <a href="/https://radicle-website.liw.fi/2026/03/18/radicle-1.7.0.html">Radicle 1.7.0</a>,
that version contains a fix for a security vulnerability.
<a href="/https://radicle-website.liw.fi/2026/03/20/radicle-1.7.1.html">Radicle 1.7.1</a>, and
<a href="/https://radicle-website.liw.fi/2026/03/30/radicle-1.8.0.html">Radicle 1.8.0</a>,
which were released since, also contain this fix.
We did not disclose the vulnerability at the time of releasing Radicle 1.7.0 in order to give users time to upgrade,
before we disclose the security vulnerability in detail, which is the purpose of this post.</p>

<p>First off, we would like to offer our heartfelt thanks to our community member Felix Bargfeldt, online also known as <a href="https://defelo.de/">Defelo</a>. 🙌
He made us aware of the vulnerability and explained the problem in detail.
We stayed in touch with Felix during the process starting from the notification up to the release of the mitigation,
and Felix stayed responsive with valuable feedback throughout the process.</p>

<p>In this, we see confirmation of how valuable our community is and how it shapes Radicle, even when it comes to complex issues at the core of the system.
It is evidence for the power of free software, not just as code bases but as community efforts.</p>

<h2 id="timeline">Timeline</h2>

<table>
  <thead>
    <tr>
      <th>Date and Time</th>
      <th>Event</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>2026-02-14T23:43Z</td>
      <td>Felix notifies us about the security vulnerability.</td>
    </tr>
    <tr>
      <td>2026-02-14T23:51Z</td>
      <td>We reply to Felix, acknowledging the issue.</td>
    </tr>
    <tr>
      <td>2026-02-17T00:20Z</td>
      <td>We have implemented an exploit in the form of an E2E test, and inform Felix.</td>
    </tr>
    <tr>
      <td>2026-03-05T18:47Z</td>
      <td>We inform Felix about our plan to implement a mitigation.</td>
    </tr>
    <tr>
      <td>2026-03-05T23:13Z</td>
      <td>Felix provides us with valuable feedback on our mitigation.</td>
    </tr>
    <tr>
      <td>2026-03-18T16:11Z</td>
      <td>We release Radicle 1.7.0.</td>
    </tr>
    <tr>
      <td>2026-03-20T08:27Z</td>
      <td>We release Radicle 1.7.1.</td>
    </tr>
    <tr>
      <td>2026-03-30T12:00Z</td>
      <td>We release Radicle 1.8.0.</td>
    </tr>
  </tbody>
</table>

<h2 id="introduction-to-signed-references">Introduction to Signed References</h2>

<p>In order to understand the vulnerability, some knowledge about Signed References is required.
However, this knowledge is not required for regular use of Radicle.
Signed References surface via <code class="language-plaintext highlighter-rouge">rad inspect --sigrefs</code> and <code class="language-plaintext highlighter-rouge">rad sync status</code>,
but are otherwise internal, and not a concept that users will have to think about much when they use Radicle.
We thus briefly explain the relevant parts of the design.</p>

<p>Whenever a user pushes changes to a repository via <code class="language-plaintext highlighter-rouge">git push</code>,
and whenever a user operates on <a href="https://radicle.xyz/guides/protocol#collaborative-objects">Collaborative Objects</a> (e.g., repository identity, issues, and patches),
associated with a repository, they “change their references”.
This means that the target object identifiers (OIDs) of some Git references in their own namespace changes.</p>

<p>For example, consider this invocation of <code class="language-plaintext highlighter-rouge">git push</code>:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>git push
To rad://z4…ji/z6Mk…BU8Vi
   87fa120...145e1e6 cool-feature -&gt; cool-feature
</code></pre></div></div>

<p>Here, the user <code class="language-plaintext highlighter-rouge">z6Mk…BU8Vi</code> is working on repository <code class="language-plaintext highlighter-rouge">z4…ji</code> and
intends to advance the branch <code class="language-plaintext highlighter-rouge">cool-feature</code> from
the target OID with unique prefix <code class="language-plaintext highlighter-rouge">87fa120</code> to
the target OID with unique prefix <code class="language-plaintext highlighter-rouge">145e1e6</code>.
When operating on a Collaborative Object, the name of the updated reference is of the form <code class="language-plaintext highlighter-rouge">refs/cobs/&lt;typename&gt;/&lt;id&gt;</code>, but the principle is the same.
A reference is updated.
(It is possible to update multiple references “at once”, but this is not relevant with regards to the vulnerability.)</p>

<p>This update of a reference is recorded in what we call the Signed References of the user.
In the corresponding bare repository in Radicle storage, i.e. in our example <code class="language-plaintext highlighter-rouge">$RAD_HOME/storage/z4…ji</code>,
the reference <code class="language-plaintext highlighter-rouge">refs/namespaces/z6Mk…BU8Vi/refs/rad/sigrefs</code> targets a commit which encodes the current state of the user’s references.
Think of this commit as a snapshot of all Git references and all Collaborative Objects at some point in time.
This commit is internal to Radicle.
Its commit message and contents are <em>not</em> user-controlled, but computed by Radicle.</p>

<p>The contents of this commit are as follows:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ git -C $RAD_HOME/storage/z4…ji ls-tree refs/namespaces/z6Mk…BU8Vi/refs/rad/sigrefs
100644 blob d5…bc    refs
100644 blob 6c…0a    signature
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">refs</code> is a text file.
Its contents are in the same format as the output of <a href="https://git-scm.com/docs/git-show-ref"><code class="language-plaintext highlighter-rouge">git show-ref</code></a>,
which lists, line by line in lexicographical order, all references with their respective target OID:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>e4…f0 refs/cobs/xyz.radicle.id/c9…d9
e1…6a refs/cobs/xyz.radicle.patch/f2…f4
87…20 refs/heads/cool-feature
83…40 refs/heads/main
b1…3a refs/tags/releases/0.9.3
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">signature</code> is a binary file which contains an Ed25519 signature over <code class="language-plaintext highlighter-rouge">refs</code>,
performed with the user’s signing key.</p>

<p>As the user intends to change the target for <code class="language-plaintext highlighter-rouge">refs/heads/cool-feature</code>,
a new commit of the above shape is computed, and the reference <code class="language-plaintext highlighter-rouge">refs/namespaces/z6Mk…BU8Vi/refs/rad/sigrefs</code>
is advanced to point at it.
The purpose of the new commit is to record the new state of the references of the user,
after applying the user-intended changes to the user-controlled references.</p>

<p>The (shortened) diff for <code class="language-plaintext highlighter-rouge">refs</code> implied by the above example looks like this:</p>

<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gd">-87…20 refs/heads/cool-feature
</span><span class="gi">+14…e6 refs/heads/cool-feature
</span></code></pre></div></div>

<p>The history of these commits thus makes up all changes the user made to their references,
starting from their earliest change (which might be repository initialization, if they did initialize the repository) to their latest, like advancing <code class="language-plaintext highlighter-rouge">cool-feature</code>.</p>

<p>During the process of fetching this history, only fast-forward changes to this history are accepted.</p>

<h2 id="replay-vulnerability">Replay Vulnerability</h2>

<p>Versions of Radicle prior to 1.7.0 were vulnerable to replay attacks.
It was possible to pick any previous <code class="language-plaintext highlighter-rouge">refs</code> file, together with the corresponding <code class="language-plaintext highlighter-rouge">signature</code> file,
out of the victim’s history, and forge a new commit as a child of the latest, legitimate commit made by the victim
without the victim knowing or agreeing.
The forged commit could be shared with other nodes among the network, and such changes, unintended by the victim,
would be indistinguishable from intended changes.</p>

<p>This was possible since the signature was only made over <code class="language-plaintext highlighter-rouge">refs</code>,
which does not include any kind of <a href="https://csrc.nist.gov/glossary/term/nonce">nonce</a> or further replay protection.</p>

<p>One possible attack would be to replay the earliest <code class="language-plaintext highlighter-rouge">refs</code> in a victim’s history, whenever they advance their <code class="language-plaintext highlighter-rouge">refs/rad/sigrefs</code>.
The effect would very likely be that their repository appears empty and stale, as most repositories start out with just an initial commit.</p>

<p>Another possible attack would be to replay <code class="language-plaintext highlighter-rouge">refs</code> at a state where the repository contains a security vulnerability,
to prevent dissemination of a mitigation.</p>

<p>These attacks can be performed at scale.</p>

<h2 id="mitigation">Mitigation</h2>

<p>A widely known measure to prevent replay attacks is to use cryptographic <a href="https://csrc.nist.gov/glossary/term/nonce">nonce</a>s.</p>

<p>There are two immediate questions to answer:</p>
<ul>
  <li>Where to “put” the nonce?</li>
  <li>How to generate or compute the nonce?</li>
</ul>

<h3 id="where">Where?</h3>

<p>Within the team, we discussed three proposals mitigate.</p>

<h5 id="nonce-in-new-blob">Nonce in New Blob</h5>

<p>One proposal we considered was to add another blob to the aforementioned shape of commits.
This blob would contain the object ID of the <code class="language-plaintext highlighter-rouge">refs</code> blob, and the nonce.
It would of course also be signed using the signing key of the respective user that controls the namespace.
Such a design would have introduced more complexity into the verification process.</p>

<h5 id="signed-pushes">Signed Pushes</h5>

<p>We did consider to immediately implement a new component to succeed Signed References based on <a href="https://people.kernel.org/monsieuricon/signed-git-pushes">signed pushes</a>.
Such a change would have meant introducing a new component,
at the core of Radicle, just like Signed References;
which is a complex task.
We quickly realized that this is likely the better alternative to Signed References in the long term (more on that below),
but that it would be very risky to implement under time pressure,
as we wanted to secure the network as quickly as possible.</p>

<h5 id="nonce-in-references">Nonce in References</h5>

<p>Another proposal we considered was to add a new internal reference,
right into the list of references into the <code class="language-plaintext highlighter-rouge">refs</code> blob.
This “internal” reference would not be user-controlled, but its target would always be the value of the nonce.
The drawback of this design is that it conflates two concerns,
or rather, two kinds of data:
User-controlled references and internal references.
Both would appear next to each other in <code class="language-plaintext highlighter-rouge">refs</code> with no way to distinguish the two cases,
other than the name of the reference, which in the case of user-controlled references is, also, user-controlled.
This design is less clean in a sense.</p>

<p>Such a decision was made in the past already.
In commit <code class="language-plaintext highlighter-rouge">989edacd564fa658358f5ccfd08c243c5ebd8cda</code>,
which was released as part of Radicle 1.1.0,
the reference <code class="language-plaintext highlighter-rouge">refs/rad/root</code> was introduced.
At that time, the reason was to prevent so called “graft attacks”,
which we will not go into detail here.</p>

<h4 id="decision">Decision</h4>

<p>With new ideas to improve Signed References on a more pervasive way,
and the pre-existing <code class="language-plaintext highlighter-rouge">refs/rad/root</code> mixup, we decided to implement
the third design proposal, that is, to add an internal reference.</p>

<h3 id="what">What?</h3>

<p>In our case, to simplify, including a nonce in <code class="language-plaintext highlighter-rouge">refs</code> (“signing over a nonce”) would mean to sign over data that is never re-used.
Using a cryptographically secure source of randomness is often regarded as a sufficient condition for obtaining nonces,
and this way of obtaining nonces is very common.
The chance of reading the same random data twice in that case is vanishingly small.
However, it is not a necessary condition for a nonce to be random in that sense.
The important property is that the nonce is never re-used.
Also, in many other session-based protocols, it is also important that the nonce is not guessable.
In our case, no sessions are involved.</p>

<p>We realized that realistically our design space for a nonce in the <code class="language-plaintext highlighter-rouge">refs</code> blob
is very constrained.</p>

<h4 id="backwards-compatibility">Backwards Compatibility</h4>

<p>Mitigation of such a vulnerability “in a void”,
is straight forward, when disregarding
backwards compatibility.
Implementing a backward incompatible change would have meant that we would
have to implement migration tools, and require action by all users.
It was thus pretty clear to us from the beginning that we would aim
for a mitigation that is backwards compatible.</p>

<p>The crucial design constraint we ran into was that in earlier and widely deployed versions of Radicle fetching fails.
The failure was due to a check for dangling references, i.e., references that target OIDs which do not resolve to an object, during fetch.
This ruled out the possibility to abuse the target OID of the newly introduced reference to a random number.</p>

<p>However, we are lucky!
With the exception of the root commit, there always is one object that we can use as a target, and whose value is a hash over all previous history.
It is the OID of the previous commit in history, in Git also called the “parent”.
Note that commits can have any positive integer number of parents.
If that number is zero, we call the commit a root commit.
If the number is greater than one, we call the commit a merge commit.</p>

<p>The fact that for the root commit we cannot point at the parent is not problematic, since there also is no prior history that might be replayed.</p>

<p>Thus, in commit <code class="language-plaintext highlighter-rouge">d3bc868e84c334f113806df1737f52cc57c5453d</code>,
we introduced the new internal reference <code class="language-plaintext highlighter-rouge">refs/rad/sigrefs-parent</code>.
It may only be present in <code class="language-plaintext highlighter-rouge">refs</code> if there is some prior history, i.e.,
if the commit is not the root commit.
If it is present, then its value must match the <code class="language-plaintext highlighter-rouge">parent</code> header of the commit that contains the <code class="language-plaintext highlighter-rouge">ref</code> blob.</p>

<h4 id="upsides-of-this-design">Upsides of this Design</h4>

<p>When considering the complexity of the verification mechanism,
using the commit ID of the parent has advantages compared to the use of a random number.
When using a random number, to be sure that it was not used before,
and thus to detect an attack, all random numbers used previously
must be compared.
This translates to a traversal of all prior history in the namespace,
which is expensive.
The cost to do so grows linearly in the length of the history.
On the other hand, the hash of the parent commit is known locally,
with constant overhead, no matter how large the history grows.</p>

<h4 id="downsides-of-this-design">Downsides of this Design</h4>

<p>Earlier versions of Radicle do not know about this new internal reference,
and will thus treat it just like a user-controlled reference.
This might cause confusion, because the user never explicitly creates or modifies the reference.</p>

<h2 id="scanning-the-network">Scanning the Network</h2>

<p>To assess the impact of this vulnerability, and improve our understanding how widespread attacks might be on the network, we developed a dedicated scanning tool (see <a href="https://radicle.network/nodes/seed.radicle.dev/rad:z3zzcqqBGP1NdvvMbSDt2jYYp9jSB"><code class="language-plaintext highlighter-rouge">rad:z3zzcqqBGP1NdvvMbSDt2jYYp9jSB</code></a>).
The scanner operates on Radicle storage of a node.
It traverses the history of Signed References (<code class="language-plaintext highlighter-rouge">refs/rad/sigrefs</code>), across all repositories and their namespaces in storage.</p>

<p>Specifically, it looks for evidence of replay attacks by detecting sets of commits that all refer to the same state. We want to select, out of one history pointed at by <code class="language-plaintext highlighter-rouge">refs/rad/sigrefs</code>, all commits that refer to the same <code class="language-plaintext highlighter-rouge">refs</code> blob.
We call a collection of commits that all refer to the same <code class="language-plaintext highlighter-rouge">refs</code> blob a <em>cluster</em>.
Naturally such clusters can be identified by the combination of Repository Identifier and Node Identifier,
which narrows down the history it was found in, and the blob ID of the <code class="language-plaintext highlighter-rouge">refs</code> blob that all commits, that are members of the cluster.
Note that empty clusters are not meaningful in our context,
and that clusters of size 1 are of no particular interest to us.
We are interested in clusters with a size of at least two,
which is the smallest kind of cluster that could be an attack.</p>

<h3 id="false-positives">False Positives</h3>

<p>Also note that this analysis is prone to false positives.
Seeing a cluster is necessary for an attack, but not sufficient.
It is possible for users to legitimately arrive at the same state twice.
For example, assume that <code class="language-plaintext highlighter-rouge">HEAD</code> is not behind <code class="language-plaintext highlighter-rouge">rad/main</code> and that there are no other changes to the namespace in parallel, then this simple sequence of pushes would lead to at least one cluster of size at least two:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git push HEAD:main
git push HEAD^1:main
git push HEAD:main
</code></pre></div></div>

<p>Further, note that the scanner does not perform any cryptographic verification of the
signature in the <code class="language-plaintext highlighter-rouge">signature</code> blob.
This makes the scanner much faster, and may only increase the number of false positives.
As Radicle storage is under control of Radicle tooling, which of course does verify
signatures, we chose to trust that the data in the store was not otherwise tampered with.</p>

<h3 id="scope-of-our-scans">Scope of Our Scans</h3>

<p>We scanned our two nodes iris.radicle.xyz and rosa.radicle.xyz at 2026-03-30T08:30Z.
These two nodes are very well connected to the rest of the network,
and they have a permissive seeding policy.
Thus, they provide a good view of all public repositories on the main network.</p>

<h3 id="results">Results</h3>

<table>
  <thead>
    <tr>
      <th>Measure</th>
      <th style="text-align: right">iris</th>
      <th style="text-align: right">rosa</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Repositories scanned</td>
      <td style="text-align: right">7 090</td>
      <td style="text-align: right">7 073</td>
    </tr>
    <tr>
      <td>Repositories containing duplication</td>
      <td style="text-align: right">199</td>
      <td style="text-align: right">199</td>
    </tr>
    <tr>
      <td>Namespaces   scanned</td>
      <td style="text-align: right">9 212</td>
      <td style="text-align: right">9 174</td>
    </tr>
    <tr>
      <td>Namespaces   containing duplication</td>
      <td style="text-align: right">228</td>
      <td style="text-align: right">228</td>
    </tr>
    <tr>
      <td>Duplication clusters</td>
      <td style="text-align: right">477</td>
      <td style="text-align: right">476</td>
    </tr>
    <tr>
      <td>Maximum cluster size</td>
      <td style="text-align: right">24</td>
      <td style="text-align: right">24</td>
    </tr>
    <tr>
      <td>Median cluster size</td>
      <td style="text-align: right">2</td>
      <td style="text-align: right">2</td>
    </tr>
    <tr>
      <td>Average cluster size (nearest integer)</td>
      <td style="text-align: right">2</td>
      <td style="text-align: right">2</td>
    </tr>
  </tbody>
</table>

<p>A histogram of cluster sizes on iris.radicle.xyz follows.
The data for rosa.radicle.xyz differs, as expected, only marginally (see table above).</p>

<table>
  <thead>
    <tr>
      <th>Size</th>
      <th style="text-align: right">2</th>
      <th style="text-align: right">3</th>
      <th style="text-align: right">4</th>
      <th style="text-align: right">5</th>
      <th style="text-align: right">6</th>
      <th style="text-align: right">9</th>
      <th style="text-align: right">10</th>
      <th style="text-align: right">21</th>
      <th style="text-align: right">24</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Count</td>
      <td style="text-align: right">421</td>
      <td style="text-align: right">36</td>
      <td style="text-align: right">6</td>
      <td style="text-align: right">7</td>
      <td style="text-align: right">3</td>
      <td style="text-align: right">1</td>
      <td style="text-align: right">1</td>
      <td style="text-align: right">1</td>
      <td style="text-align: right">1</td>
    </tr>
  </tbody>
</table>

<p>The larger a cluster, the less likely it is that such a cluster is the
result of legitimate activity.</p>

<h3 id="inspecting-duplication-clusters-in-your-namespace">Inspecting Duplication Clusters in Your Namespace</h3>

<details>
  <summary>Show all clusters of size greater than two.</summary>
Data is shown in YAML to save some vertical space.
The structure of keys is RID → NID → Object ID of <code>refs</code>.
The values are the object IDs of commits in the cluster.

For example, the first two clusters in the listing below are in repository
<code>z2…4C</code> and namespace <code>z6Mk…5Tkm</code>. The duplicated <code>refs</code> are
identified by <code>10…d9</code> for the first cluster of size 3, and
by <code>8d…d8</code> for the second cluster of size 3.
  <pre>
data:
  z22qZYU1Rozc61i8kT7RCt3Wmwa4C:
    z6MktwkohCx8aHZ1QCjVZUiLmX92oPZFxRiFZkbq32Tk5Tkm:
      10fc2cfb880bb7e2a96df378cd4869747b35ced9:
        - 020d2110c8ec5ce0ccfc9cdce88f639fe094ee0e
        - 3996116f2628af1033d48ec20ebd656b0c2a4922
        - b68d4e6795ba13a5380e476766f82c6c61cef17e
      8d901f488e1a68bab5383619da8126c34af7aad8:
        - e2973b023e5b93daf24cbd45fc4dce640dae26c7
        - 8fb4cd4f89b1d632a937c4479dbb9398f05345f1
        - ff0ec7352ed28b922e286dc991c928724f649187
  z233GtFMEuSTU35DQ7Ya8GuCD7TVr:
    z6MkuvmuRwL2XVB3zDFZQpiY2fxnr6rp4Q1L61uZ1RDTk9Nf:
      5a068717317eba995abd2e5fe423dfbfae60c8f7:
        - fa112a588c8bdf34ff255fc43272b63505e45d29
        - 46f81c05eb5e0454e21487d44782d8c28201f0d5
        - 63a8a6947b30b48133be5efefd65b3fde9122780
        - 5af4f25a846a47d41ee1cd8968617bde531970c9
        - c1e2510fb16a537a3173dacc18caab4e0a2e958a
        - 9d3f0a3647e7d022b0eb06b1aee734d70e5e4448
        - b809917f5ae21c3dbe4858d6d6e0302488ede004
        - 7e7c85e1bbc0341ab9d24c369043d31a626285a0
        - 9885c53ce0a5212aa0c44eac591fabfc9b3e6d1d
      bacac318f72171920749ce6d8ae6679a0557cf0b:
        - 675e4186f0324c15ec7f0e41f0f5508b2e4a9407
        - ca70fb259845a75e720971ac40fce70502732b8a
        - 2c633473b1789024ae3e4074cb238850ddddcc55
        - cf823b6ae75528650a5f3385446ed8d9d9cc83f7
        - 0286b3d098d55f39b598a80e9151aea1b6555dbe
      c45eede36f0f5ddf54c95cdc392e3d43d1a2184a:
        - 599ab3267c6dc371c5a3d623df1c6a6f4ae1208d
        - 59504a6ab0d1e409fd59746ac12ca6cde2450d1d
        - 33c4e6fec3cefdda7ab53ce546d0767ab033b813
        - 8311f777e544168bcb402906897a115334bc2210
        - d55539ba6a11f6bcf1881b411555fb277e837cd2
        - 9e92764db881fd77f5bf09a1f4c4184573ab00e1
        - 08e6c1ff9c3e46b3a949df9f9b567f9246aceb7a
        - 0d885934bf59df743cde21fd110320f1ced0faeb
        - 94af66ae97bd7b31b1192957467b4b23a9f8e131
        - e419d91c3c0deedb7615875cef629f20d69d83fa
        - c96144f14d32a62b43631f0d5b1a0a8b4ec81c25
        - 8fa0c1b0c4c46f053efbf683102f5d669fc8c587
        - 9774ac4729cfbd487fdc3b6dc3e91fb09d2c3d9a
        - 3e188979ed34d546d6a247a9537ed540d3f2852f
        - aacb4bd22068d64c5834720911d6c1468ccbd1c2
        - 893f75739b782a1190fc35d1d20be08217f5132f
        - 477ee900e592af7625921beede080e1cdd7d0c7c
        - 589ddd8b56a8a9540a8316f624d1e44f3c84ab0c
        - 68e1e31c4be1f8a9ca6ad6b6c36387893079f17c
        - 395deda862561ccf15dad3553ea851e27184fc21
        - a8ef1db64223235074ed0e633e4336c9db433b47
        - 95e9e3ad4fd68d23d994d120f5e422eb93e5af50
        - fd65fb4c2e66dd3b672419d82dfb1d9bfb10a054
        - dff86f8e623b5964bd4fa87459b46fd7c3d73ce0
      fc2f3d44f50e4f0558a4911812d8863fab8473bc:
        - f8a692f98629ccd366859b65ce4c1ab3dd99b39b
        - e2decf4023e5d0f8f6a1d36ba5a0f20f69f54d46
        - 8be1619100b5b08c22e582664fb7bf2590dceb62
        - 745b0c26a85bb599970f43a05f0e805e270c754f
  z292aD8q3r8xqhJvLe2zv1b24gu7a:
    z6MkvVZk1A3KBApWJXv2Ju4H14ErDfRGxh8zxdXSZ4vACDg5:
      54d0afcb118591ba1f45e822787ee149289da62f:
        - fc98f114b5e9f47356dede7a11f37deba2153a85
        - a536df85542a4e0a6b115d604db32c26d502f7d9
        - b15e19bcd897cbcc2d12e35671ae6cc4a6f1ae19
  z2DJwn8E33K8RVGPFzJwCmuB8rCGP:
    z6Mkondm5dgAxsQnV3iuvZBCGMAQgfAg4zSdJWoNVJr7i7wp:
      57d28bd65223769563a12eb7bf81176f70a83461:
        - 743aa52dd80abd549a557809cba1a9809bcd4a30
        - 6bd29cecfa07f32f0e339e2a4bb4b7329362a03a
        - 08c6e6cc77a5af5e44c09c133f8eb0f44428af7e
  z2G17GyYnKvPja34T4fWjiT6Bmrm2:
    z6MksoRnvY29wWrgpGaeg5ztVAy1D3xVNjC1n5mFwuWPtwDz:
      56fb7f200d7e03def9b32ca538d022c96e1fc00c:
        - a021902e967d3270c366632b0cf797f847b4aa51
        - c40d455ed716f47bd39ed55511bd534344a96a71
        - fcac32e023de0e8702be6a3eb98dfb9ecf1bbb06
        - 7d576445429711b6e04d6cde77a0c9d644f6c18e
  z2M2jmXxycq7i2Yqx6PjidxUgdGDe:
    z6Mkondm5dgAxsQnV3iuvZBCGMAQgfAg4zSdJWoNVJr7i7wp:
      afb3c989b0a77c2fa39fc337adb336633e12a3fc:
        - eff038cb188c5f5eef8c91c3e915bddd9ee765fa
        - fdc35f8432464210ffd214f8bb783e9582b69792
        - afce8df50881ced72cf91678c994d35122df9c0f
  z2SWNmqFhpqKCwBCFLjosCnjny5b1:
    z6Mknjohi1pApYKAt8XeZzjwiWSqhG8bJS77ZT8pcyTrj9ir:
      e4792a846a12e85cacca51153081320b357101a5:
        - 6089f604ef6f385c2fbebcef452d3ff6796c82cd
        - 9060e7da5f0c85bf308dc69f9edfaba0435f1aad
        - 167bf94bb8d0bf4368d2bfc0381c4425191047c9
        - cd24cb2f721e7d35d729dcaf8d6d4bb200a89d30
        - 4d2a29ee2186ce0bda2110cf4dee4a3840dc7b05
  z2SXkaceJw3YmS89T1xGysnFSjWsw:
    z6MkvVZk1A3KBApWJXv2Ju4H14ErDfRGxh8zxdXSZ4vACDg5:
      17962e342eb08d3380f08bf9e0c084749d8e6423:
        - b980d0dc074e61b69c73f09ff3e110a3e272a7d9
        - fcc743e8908c61def5e388cdd78afcb6d793511b
        - 820852767b33581f49fbe93474ff0c0e03821702
      9e5f6d3ce756b7531063c34f285f625c2e45e5d7:
        - 2dfae40117a6ddc69fbe68f772d9974971b5ec1e
        - 675c57c5dec49cb2cbb8b23382e0f796a89207f6
        - a7b733f9187ee893a361aedcdc5c284a2690e9f9
      b468e088741015fbe10ebbbab3b46ed002f347f1:
        - acaf9014354b97d3414b5386c3595bc6a489ec93
        - 5c88f502495edd901ad4e6e79adebd8a8fea4e36
        - 56b34e6a79a45e2b239f91631ba9bd97a344273c
  z2UPb8WFofVxXXK1A7918M3gxe1s2:
    z6MktH4iY2Mvq5ZkmoM7ayB4GM3U4p6HXKgB98nafiWkCam7:
      71ec6ed930d93e4eb17aa8b97fb6cb683941ce00:
        - 51bc3f33cb677b6714f846f09cbf80ce31d4ba3b
        - 1496341c0c335ef4da53d409cc22658c5795c050
        - f86f63915f942c8fbf4d858d7cd17305ed450fc2
  z2a7Te5b28CX5YyPQ7ihrdG2EEUsC:
    z6MkiuWYPxbojmhUiGGWrzSuJK3HDpbbtWo3QMm3e9VP2gJP:
      aa0319d9e647a13ee9d8dd4339d0e23faba7701e:
        - d6c032e15173e7c803343989f107126d187acd65
        - e8e506ae8025f7b335b99b8cd4f88359b16ad786
        - 8c953561309289057af43d36866bc1b211f07b5e
        - cf20913f07da4da0ad99e3439ee5b450c1c7d410
        - c4a60d727d45851bb8ab998b0efb4742745a8934
        - 6f9e7185a80c9ea2cccafc31bd0bebdf9c8d3ca9
    z6MksH6Yr4pkJqPYnY4N5e5a5bCdyCW88grKRkkK6KeMGwLN:
      6c83cd06fab7dd8b0c59ab0b1d268460870384e5:
        - 5748faf8d6f4f4cbf31a82e92c21198f8eb1cfcd
        - efb603a0570c596d81cf226930e1c33016948310
        - 2844cae8e87fbda1334fcf818b8e2b63fc3d1a3e
  z2tDzYbAXxTQEKTGFVwiJPajkbeDU:
    z6MkiksiCWT4LDhMQK75t6y3m2gj5iQPE1nhJfJuX1wd5Uef:
      4224a04869cf6abf60562c58ad793256a9e2fb5e:
        - c59eedd1f496d1837629d25f94d5b110c149c1ea
        - 1be90b217604b93ca89d2492b4ac0b19cc9d6efb
        - a93136ea49b575065959cb0f9c416d85218f9748
  z31RADNa8uNMWFep88bhenzxTR1Ei:
    z6MkpC1ahHS1r9KR12LbYnoponj8swuaAEiNpvVvB9hcXhvh:
      156bae94c8df83e75a00a3e07e94120c7f873a7e:
        - 4bad6e268ab12e6c5e6c42972d7e3d5555d7559d
        - 7339bfd5ef35cb2cbd34999658adbdb9388f79b1
        - 6f3fb0a302a6f27a7dc4fe1a21a29f6292edc811
      9e5254c88d36fc6dc42145c897ec242d359b6ace:
        - 35fabc1232f1682ac1de036b3ae9badfac8066ed
        - f5fe3e0b6c7c6a0a88c11c95ce462165a89791aa
        - 4ca5aa550a6a10e7125e3478bc6102df6a1b5586
  z3bBVej6SJXuahv5hCXhiLKeB9N9k:
    z6MkvVZk1A3KBApWJXv2Ju4H14ErDfRGxh8zxdXSZ4vACDg5:
      ac1013b2f350d0b8b64b287d7e0d03ceb819161c:
        - 66060f455ca37923d5f80407484de8f2d7999325
        - fdac3aac66474d0d71adbd4d2a2e22c00cadcd46
        - a2f8a5c0229b79c1e9bc4c18e7806239fd19451c
  z3cyotNHuasWowQ2h4yF9c3tFFdvc:
    z6Mkgom1bTxdh9fMFxFNXFMw3SbXnma6NARdsfcFuunurCap:
      39fd416cd098ca04e92808fbda34ba6ed5ed1003:
        - 6cb96494730c64e0936c4e6c81813b5fef4b041b
        - 5bf7ee385158e6591a6ff5ea8281140c1ea768d3
        - 322fd2ead09b974c1c179114414412b52dcd8563
    z6MkvZwzK64f3GuDcAs6dEcje89ddfHkBjS1v9Dkh7aCGq3C:
      9bf2cf1021e0ca153212db5c530349e59729ad50:
        - e81e336b1f89f78e8362c9c33fc659aec6ef8e38
        - b4c8b0cceb0fd00215b9cd4eb58c1284c4d05eeb
        - 91d69ad99564695610b111a2186781e1bdd93d71
  z3gqcJUoA1n9HaHKufZs5FCSGazv5:
    z6MkgEMYod7Hxfy9qCvDv5hYHkZ4ciWmLFgfvm3Wn1b2w2FV:
      27b23b3e05c6d6a4ae1d9db3e53e046989dabd0d:
        - 406c96681faca1a8def7ab01184f6bcc16dd55d6
        - b748c1d7cda0486fd02565bfeb556f65da8826cd
        - 3708d86b4d14b34b9dd1cc2b5b3785f4bdc2f852
      9167c0a5c209bf3a31adf25d59acc411e469fe70:
        - e11752a3a42617b40c427292add2235db54308c9
        - 420a0134ff94e9037c10bfb324cc403f01d119a1
        - 69145ba62b572ff49b7c8836d8efce348c23e2f2
        - f0a59d5fd4ec17d3a12b88732cb52651233b72d6
        - 6f5c92b73e1756098fbe99a5e2b98fdcd1888f1e
        - 4910e88b9caddb43382fea2a75ea1dd0a674f7c6
    z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM:
      1f3685f577c2319748cc43f2b97559e6e6f27b30:
        - f0ad9600f3bfa3c193f52507480ec161be0b0cd0
        - 2fc43986f24c1a8ca092186e9d179f02d4a5f288
        - 979e00e332a9dff186e28bf6f2ed8cc62047b558
      fb8387acc1c8cb9fe33d13ecaf01f3a5eff6e07e:
        - 40361a592d391b8b56e23173605ac490eb227d94
        - ab52bc081d8720216c67c2643b70779e31467199
        - 729ef07fef8fc79fb2d6dcfc71d374b20095471b
    z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz:
      4996cff3821f7cc5b4850a56efcc887ff6983866:
        - e0502b2c843d0997e43e63548388ce6884d73dd0
        - 178142f005781af571830ba573019e3e57e28f62
        - 7176c630b9f2cc22c8859ccfdcfd6d66da438af7
        - ac7dcb92b998f9716872421f2d45faf285784940
      ebf3aedc50f350e8670a1178a70c5af1217eb664:
        - dee5da561a0c76ec07938f9b88047b3f3bb210c7
        - d3f58fe73caeededacb892c82cc649545b1008e0
        - 6d28c01d2afaf9fd0919592b2e90ea94e48e9905
        - 34c04e812208f53ea43fabba3a70720b949f6c72
        - a8301092c4983b672a66f0a263aa6c95b813caaa
  z3i8ZmSrLFsuGFkvCsMBCSskqDipZ:
    z6Mkum88mKcX2sARx8R18RZUmAdakPFbXtdHzn8JNVEDqkxj:
      10ab8994984779b7746bcbfd84d837aba87d9d47:
        - d8f8dcb0f40af5fae6ec61fe8223c0b0a02fba7f
        - e6b58eb83fb64e662b0cb6acae2e207271fc9e4b
        - 4f40235f10e11a7569b69fae658466918bc74300
        - d83c5dba70548f42e53ccdbb4bb0133d1c3f16bc
  z3kozTn4Kn5eJtgJQj1aCFUpqxW5Y:
    z6MkvVZk1A3KBApWJXv2Ju4H14ErDfRGxh8zxdXSZ4vACDg5:
      a1f828485c94c89636d5c9e22a541dcc908a203a:
        - 0fecd475bd4df5cd2003f6e492d2505c7071e53f
        - dc737994daff3d70f92a80aff220b1090a5ff041
        - 090a873a48ad5815ce40078c10f443b87d8cdcf2
  z3nSmSzzTjgtbapU2P33JDdZ9Tca:
    z6MkuvmuRwL2XVB3zDFZQpiY2fxnr6rp4Q1L61uZ1RDTk9Nf:
      17207437aa5606e660b95066a0e9ac7b42a1eee3:
        - 9ad94184c9fc8056103a8d31dd4f3c1c1df3362a
        - fa5ce57a31843137769a85aa9425fdd872e5e29b
        - 507b9b36086db7e6a55a61bc67a7fe6a9312db9d
        - 72e2c085aad4b34f7f5bbcb0cd89c32a9d34243f
        - b4457712ae6f94886f1d3040aa93a1fa6e9661c9
        - 8a4a76c132672b8d91cb5d1a9f521a1d2d36d7cf
        - 9333a611f28e897afaf0290badf8db1d4c06fa8f
        - 89990057bd7b6bf9f9b779c78efb995458569b14
        - b5bb2f7011fb9d20a8f9e92f41070a838b48ba25
        - 6b23ea763d319333257caabd2875255660ed5ab8
      472d33e0d3bef33f5c5fb4914826b62d65fc7bea:
        - f8b44c41c15e91041dd54bd92f8a1797d55347eb
        - 021a78dc7265aab50b531829179dcf71d0d0b468
        - 07bb5c12feacb35989efebf1e3d9b0f5310e65da
        - 9fcc377078cca9bca17105b7ddc6297c4fe7a983
        - 7b794d3d35e563258bf5d9adc0778fda06bc8197
      66721d2144d0958526fa3325a5dc36b2a62dc488:
        - a48104cdc5d6c932ee7bec90000f19c4a6ca49e4
        - c2755f5706a240f5b95e1c9458b736799dd5eeac
        - 8b0319df5b51b56c1d4325f328d3803b766370b7
        - 0d882594a00d654b20528a8acdc185798becf623
        - c019f8d3be7650cc13cf21f21c0282864c257e55
      99f9a48b0ba538e7f27317be95bb4cdc51c49daa:
        - 0db528badd5050b34051c3979e5d830f01cc3641
        - bc3bbfb732ac8a29fe14d7b0e709987c8a16e254
        - 66553217cf89ac330e44753637c3e4fc5143d39b
        - cc5fe0d799d35b9b8435cd759dfedaef2d37224b
        - b13205272467ba26553379cdaea893b81efa217b
      c6ca4c1bdbaaaa2072a6cbe8a8c0dd35e17d054e:
        - bf927bab4c19d1dd9ff7fa54cfe4c856c5ca59f6
        - 2a47e681d9f2ea5ddd41880854ff48b907718752
        - b3e532bf7173d40623d50b18003694331ee80aa1
        - 2de991b41ad48faa98e1040e31370363a6640581
        - 2c402f3f304f438781b15c3737a1560a0f5adc7a
        - 194b61a9f6b189f608881985fd40d5e8558c2267
        - 7557388731ea0423262ac4b1f6a2244e011ff475
        - 6582b20dfa5f27155aab2dc9a6bc06d13f40774e
        - 6a6bbc67eaeb0051acf84da47eeea4472961f152
        - e3e134332b6c34eec0cc30be2cda372c6a92e3f4
        - 5d0d86ee7096389a417d0bfd027a17b6a528b9eb
        - 33cc59256f07423667100a85257859e777506175
        - e993a8beea0af22b10123967bc7132b1711ce7ac
        - 3e83e00b335a111b8dc1e014aed4e3cfb7fa368e
        - 83958c8a9f43d284e0ef241e70176012a34f1959
        - d78e17ef99837cecc7dc1c6207d0f00217d4d241
        - 1c5f2a29b0b1b68cfe1094c2c3bd81dec907a3ee
        - cdd4571c8ca88fcd3aaaf70cc2ad7ec865a0c55a
        - 6a2c1ed4bdb097c1174fdec1a498b74b24bf69f5
        - d1ce807a52045776ea73af97a2f9d4b7e2cbd6e6
        - 294f05fc3fcc0269bf1e61cf6ed7b0997fcfe743
  z3qsiV1cLueoZ7mbEAHCTA58yPP7e:
    z6MkfSMUiSTtktgCbXDgjkAUcBadNzKgHrNnE6BPRC6GnNk4:
      02cb4108bea242fa2dc698c66fd2d7ecf3882609:
        - 13ca3c8d3808d4c2dc654e764927a80b66398c53
        - ab8d6a02fe136652e1a52f04640ca92c9d091895
        - 5173ae463e6614117eba2c473c53560c39f962d4
        - 17267c59133cb2c6b629f51852f40cf25c6e036c
      6452b1f1a37939d0e8d8b7d91c72f6244d790627:
        - a4c02a390638da0a0aa0aded889caab47faa6eb2
        - 5b8151b4e73e8492b88612e3c19e9a4aff37b671
        - 6dd4a929c83431a7129c1c7d40015f2d574d1dbf
  z3rwhJ9rQ82H6GXg7ZCt3UNpStbaW:
    z6Mkg4WMCHiK1wGCXLJidM4fWQuuCtb7jVmuLqCxSEwJLtvp:
      ef70e392e8afb2327318c897900a90c8d920f5d8:
        - 8939508dc9cfe8f31fc06e194130a679aae9b2ce
        - ad545fbbc5ac30ddcd39959bf8dbe07e7e7e9883
        - f4ff9f55a20689cd9a11dd13c811dfbfe46c4823
  z3xjvkTXHZpBuLUEZjEqmmcsk8HPe:
    z6MksoRnvY29wWrgpGaeg5ztVAy1D3xVNjC1n5mFwuWPtwDz:
      fff559359e9b22c3b309dabae53a47d0a6559d0e:
        - 546bc4a6364ac2c573367707480a3c68f817f939
        - 76ac736a3eff6d45812127cc7ce7a8eca77262f8
        - 0b01f44d1c574ee54583519d9fed104687fdfbc0
  z4P7htL76j7ag3F76gTaT1zLuZRe7:
    z6MkvVZk1A3KBApWJXv2Ju4H14ErDfRGxh8zxdXSZ4vACDg5:
      cfe6ba4988ea2810dc597ba9f7e7f267ff8fc476:
        - 2ee7eb06e05afd9e59f9173de38106db591a91c1
        - 9634b76df4de925fcc3adef4399731b6c52f75e5
        - 371b13211bbbf7316a890678ae845a9810c77e11
        - e770f7d340ab06314ca0af4e0f0fd03a3cf11bd5
        - a7e51437bb06757807b0a59dcefd3f6230e88d5a
        - 5aaf3dc86d8be531d271c73d9eb9474beebea8ed
      dc10dcaa1b25378d08fc855febe81ea79c823ea0:
        - 7ef26dd108bdfbb95b9e2e4a84e629c46d68274a
        - 7977fa4c1d2f78ac6a4554f0fe16738fee7f2340
        - 54de6e53f6303cdddc0e974f7b69b6057ac9714c
        - 7c09f2fa5e3d1e311f868f9d711df3b1f34f3c85
        - 8f3d5a12f84c1041ea2882fbecfae588c89b88b6
  z4SmCptZ81EcBS5pbvFNbppFkY1Cw:
    z6MkpZ5eyZFjPDiF3KqtS6yJmqq1gkN3KRMHx64ein5qTtb9:
      459ec8af8ac81d68a961d67d7ad30e49a6627c56:
        - 104f16f083d510415a280d61e8e34f457190b35d
        - 45f94ce863f46333e9bb83d03daa3cac6691953a
        - 09e0f91ace979849cf0a10e9431ab2dbac26df80
  z4V1sjrXqjvFdnCUbxPFqd5p4DtH5:
    z6MkeyYzy2PmF8RdXzDXeNzbUPmqxjPG9mgDSwZGcr5Dccbv:
      c896b7e48ec5eafa181d705454034405ee0a5d17:
        - d9e34d2957cfad92d6027e080f59bd9f070e81a6
        - 76b44d734b28d2827d997a1680cf71d474299203
        - c362cd037f247eaf393c646af0a52670a74b22c4
  z4V2SLbvf46Ttgkxkuyvboc5yYbGy:
    z6MksYHVGBqiS1dpnhToGMP6gMjHPnHrbH5NEqa54W32CAjk:
      9c62d61f65d9d8655f8bfb3877b197f1e794e691:
        - 2e0a912e0702da0591c1eb229a87e1addb326c61
        - d5a0dbdf6db706729ce48c03571892e4ec6eaeb3
        - e69e8ba85fbfd0b8dc7b21b7203a7247702c6a81
  z5EmYRhaFMaaccNYmeufWat8x1BA:
    z6MkgvaRdahQZfnf7ccMHByeHtTYrMrM3MuSGYawF6ZL6DNj:
      3b74250fd2343e03f479495ccdb9e054326efca9:
        - 57857ec2e1e1e782b554ddd21158076ea0744986
        - 47449832294923399fdc44d875c73b43fd13c0d8
        - 2548f44064824ec39f566a20e292c5caddb6f398
  z8sG73WVo2TAKjoqh3vBvhfRqPsw:
    z6MkvVZk1A3KBApWJXv2Ju4H14ErDfRGxh8zxdXSZ4vACDg5:
      52c8f1d5c7eee9f2e40f376219f8018166a7e298:
        - c6357c77874ff8e3a61ee91e247b2c5b19256223
        - 79f89bf1d911fd13cb0635e5d910506417f656e4
        - 20f5a8643df6d891a970e1ad60217d6bceb8cfe8
        - 9404609cefe6f61a9c723d3da80b014ae7e4f4d5
      a5cd8e052ee1207e9d7767e285f7b9d72ca8640b:
        - b8a1b10684646f5b5c0a452faca73e45037c5cd8
        - 62bd2e9431c2fba38525f75b3f92f25b8740ee23
        - ec48e456ee6ae7bdb1c883650872e64d11a46926
  zcmrr8AZD7dcRwAKnXBroJKyT2En:
    z6MkpC1ahHS1r9KR12LbYnoponj8swuaAEiNpvVvB9hcXhvh:
      641b572966b093f16d7bdf9236fc5f1328f6b221:
        - af6a171c5b48ad9e1dcf00ac4de777d6b1f53f3a
        - bacc1a70110fbcb293861f86f85a1c9aaca927a8
        - 6fc23526bf9ad9f40f51b778dcda804f1e6eec44
  zjTKEBr1jwtpu7CkJtBd6jTnCXSE:
    z6MkpC1ahHS1r9KR12LbYnoponj8swuaAEiNpvVvB9hcXhvh:
      0774b3680463fb175c1bbc18d5d6ada7f70e7bde:
        - 40a9bc8ba4a26be70fa547ee41c05e3faab26cca
        - 6015e13edb37132dc9b2064d8c35e4b737efe786
        - 2cee6f9645d259fc317ae351c6d8c344b89f17de
      2c2bc8da268c4f4f4390ffe74acc9108165f0ae5:
        - 35db02c7d4577cbb36211e355e089ea7fbafa745
        - 8f50aa62cb1bb88706623beaa85e331bc49f8db9
        - 51f567a1cede0e5adb3cf016a232a105ed08a4f9
      8d897c693c1818d2b3e20a3c9bc4850b3aa399b2:
        - 7c52d18dbf0482342b24ca408695f8ff30b218e5
        - 861e64627a58e708dbdba038be27035388710c9e
        - 364ef81a3563d12d5147a3d63ebe8e15d87bd090
      f20ae096292aa467e3f22765bdfdb6e6dde874f6:
        - 4ac9381c78a06668314b76be1f41bb487ebc70f4
        - 2d65a1b459d8c15f8dd48907da0e925d81859140
        - 6b51bc85a5121985d5b5bce498580cd871d748b4
      fd1ae02017faa8be202f2756d50ef96a1b35cfde:
        - bca64f8cb5fe5bee3b0a80b307d5b35a01874bb8
        - e5dd135f1d7f37aed5f15a4eb52983ce043e83c0
        - a22eac9724b66573680d84f8d39bf406e17518f6
  zoBPQV6X2FH296n9gQxJr6suvSSi:
    z6MkewCavrcnLurWU4TzMUYT4kX9FSknYvbZEWbh1CnGdzaP:
      f84508c2e4ea65a8779bd03981b54680322c0d73:
        - ee4d6709d57c0846c9a2f39d4084d2a3e236b299
        - 435c10668b909d59bc7e182ed4bb8af9ceccc8c4
        - 7128946bde23df75ca4fae07c0815c27aed150c0
  zu5U7GRpyZRXeHfz6K5vdPq5CVVM:
    z6MkvVZk1A3KBApWJXv2Ju4H14ErDfRGxh8zxdXSZ4vACDg5:
      ced794c0d15bb629df1eb3d8f3637a083dd754ef:
        - 1932fb5ef1f27eea461ed042ef1fe173114e7fc1
        - 7153ece0e045fce12d715ccd328f4abe990f3a9a
        - 4b56ab21a4b8705e7a6ba4d2862f4a0b67903fd4
  </pre>
</details>

<p>Alternatively, consult one of the files <code class="language-plaintext highlighter-rouge">{iris,rosa}-aggregated.json</code> in
<a href="https://radicle.network/nodes/seed.radicle.dev/rad:z3zzcqqBGP1NdvvMbSDt2jYYp9jSB"><code class="language-plaintext highlighter-rouge">rad:z3zzcqqBGP1NdvvMbSDt2jYYp9jSB</code></a> or run the scanner on your own node.</p>

<p>If you need help interpreting the data, please reach out to us <a href="mailto:team@radicle.xyz">via team@radicle.xyz</a>
or <a href="https://radicle.zulipchat.com/#narrow/channel/369873-Support">via Zulip</a>.</p>

<h2 id="vulnerable-versions">Vulnerable Versions</h2>

<p>All versions of Radicle prior to <code class="language-plaintext highlighter-rouge">d3bc868e84c334f113806df1737f52cc57c5453d</code>,
which is included in release 1.7.0, are vulnerable.</p>

<h2 id="fixed-version">Fixed Version</h2>

<h3 id="in-radicle-170">In Radicle 1.7.0</h3>

<p>In Radicle 1.7.0, a major refactor of the signed references logic was written.
The base of the refactor was taking the previous implementation and performing a rewrite that allowed us to focus on the core logic.
This allowed us to quickly iterate on the above ideas,
and then implement the mitigation mechanism of including the <code class="language-plaintext highlighter-rouge">refs/rad/sigrefs-parent</code> in the <code class="language-plaintext highlighter-rouge">refs</code> blob.</p>

<p>As mentioned earlier, the inclusion of the <code class="language-plaintext highlighter-rouge">refs/rad/root</code> in the <code class="language-plaintext highlighter-rouge">refs</code> blob was previously introduced to prevent graft attacks.
There was a note to make its inclusion a hard error once enough time had passed.
We took the opportunity of this release to make this change as well.</p>

<p>If Radicle 1.7.0 would have rejected all histories that do not end in a commit with <code class="language-plaintext highlighter-rouge">refs/rad/sigrefs-parent</code> in their <code class="language-plaintext highlighter-rouge">refs</code>,
this would have also amounted to backwards incompatibility.
It would be impossible to fetch updates from nodes that have not yet updated to Radicle 1.7.0 via the network.
That would have caused lots of disruption.</p>

<h4 id="replay-detection">Replay Detection</h4>

<p>We cannot travel back in time and retroactively add <code class="language-plaintext highlighter-rouge">refs/rad/sigrefs-parent</code> to
the <code class="language-plaintext highlighter-rouge">refs</code> blob in the histories of all namespaces.
What is possible, however, is to detect replay attacks in old histories.</p>

<p>It is possible to traverse the history and look for duplicate <code class="language-plaintext highlighter-rouge">refs</code> blobs
(or <code class="language-plaintext highlighter-rouge">signature</code> blobs, as the signature is deterministic from the signing key of the user and the <code class="language-plaintext highlighter-rouge">refs</code> blob).
If the <code class="language-plaintext highlighter-rouge">refs</code> of the head of <code class="language-plaintext highlighter-rouge">refs/rad/sigrefs</code> is found to be duplicated in the history,
we can decide to skip this head, and try its parent.
This process can be repeated iteratively, and it is guaranteed to terminate,
since the <code class="language-plaintext highlighter-rouge">refs</code> blob in the root commit cannot possibly be referred to by any
earlier commit in the history; simply because there is no earlier commit.</p>

<p>There is one slight oddity. As alluded to earlier the user may legitimately
wish to restore an earlier state.
The detection mechanisms would skip such an update, and effectively drop the update.</p>

<h3 id="in-radicle-171">In Radicle 1.7.1</h3>

<p>Once Radicle 1.7.0 was released, our community was encouraged to update.
Generally, we would introduce release candidates before releasing a new version.
Unfortunately, due to the vulnerability, we needed to release without the usual ceremony.</p>

<p>When our users updated to 1.7.0, they quickly noted that there were some issues.
The first was unrelated to the vulnerability, and revolved around parsing of IPv6 addresses.
However, the second was due to the aforementioned hard error of the reference <code class="language-plaintext highlighter-rouge">refs/rad/root</code>
not present in the <code class="language-plaintext highlighter-rouge">refs</code> blob.</p>

<p>To provide some context, the <code class="language-plaintext highlighter-rouge">refs/rad/root</code> mechanism was introduced to prevent a graft attack.
Essentially, it ties the commits in <code class="language-plaintext highlighter-rouge">refs/rad/sigrefs</code> to the repository they are introduced in.
This reference is calculated by Radicle, and there was a code path that introduced a check for its existence,
and if it did not exist then it would be created.
This change was introduced in <code class="language-plaintext highlighter-rouge">989edacd564fa658358f5ccfd08c243c5ebd8cda</code>.
Then, 10 days later, another change was introduced.
From that change (commit <code class="language-plaintext highlighter-rouge">09f796234d76f4a25807371bb709c18678ac7bc9</code>) onwards the identity root would <em>always</em> be computed
(by traversing the history of the identity COB to its root).
Since this method would now always result in returning an OID,
our previous condition for a missing <code class="language-plaintext highlighter-rouge">refs/rad/root</code> would never return true.
Any repositories initialized via <code class="language-plaintext highlighter-rouge">rad init</code> after 1.1.0 were not affected,
but those initialized earlier, e.g., on 1.0.0, would be missing <code class="language-plaintext highlighter-rouge">refs/rad/root</code>.</p>

<p>All that said, there were a significant number of repositories that did not include the <code class="language-plaintext highlighter-rouge">refs/rad/root</code> reference.
Furthermore, this meant the hard error became a backwards incompatible change.
We relaxed this condition so that nodes could make progress in Radicle 1.7.1.</p>

<h3 id="in-radicle-180">In Radicle 1.8.0</h3>

<p>With 1.7.1 released, we realised that we had one more piece of the puzzle to implement.
We needed to make sure that downgrade attacks are not possible,
and to allow users to opt-in for more strict verification.</p>

<p>In order to achieve this, we introduced a new concept, which we call “feature level”.
It describes, on an ordinal scale, which features are detected on
the history of Signed References.
For now, all known features are security features, so currently
feature levels translate directly to security level.
Also, these feature levels are strictly monotonic, i.e., higher
ones include all features of the lower ones.</p>

<p>The three feature levels, as of Radicle 1.8.0, are:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>none  &lt;  root  &lt;  parent
</code></pre></div></div>

<ul>
  <li><code class="language-plaintext highlighter-rouge">none</code>: This is the original behaviour with a <code class="language-plaintext highlighter-rouge">refs</code> and <code class="language-plaintext highlighter-rouge">signature</code> blob,
where the <code class="language-plaintext highlighter-rouge">refs</code> contain neither <code class="language-plaintext highlighter-rouge">refs/rad/root</code> nor <code class="language-plaintext highlighter-rouge">refs/rad/sigrefs-parent</code>.</li>
  <li><code class="language-plaintext highlighter-rouge">root</code>: Requires the reference <code class="language-plaintext highlighter-rouge">refs/rad/root</code>. Added in
Radicle 1.1.0 (see above).</li>
  <li><code class="language-plaintext highlighter-rouge">parent</code>: Requires the same features as <code class="language-plaintext highlighter-rouge">root</code>, and additionally the
reference <code class="language-plaintext highlighter-rouge">refs/rad/sigrefs-parent</code>. Added in Radicle 1.7.0.</li>
</ul>

<p>The feature level for namespaces is now printed by <code class="language-plaintext highlighter-rouge">rad inspect --sigrefs</code>.
This allows users to understand which feature level their collaborators are on.</p>

<p>The reading and verification of signed references now detects if the feature level is <code class="language-plaintext highlighter-rouge">parent</code>.
If so, verification can return quickly.
Otherwise, in the case that it is <code class="language-plaintext highlighter-rouge">root</code> or <code class="language-plaintext highlighter-rouge">none</code>, the history is traversed.
The traversal is expensive, as it performs a number of reads from the Git repository that is
roughly linear in the length of the history.
As more and more users upgrade to 1.7.0 and above these traversals will have to be
performed less and less, restoring loading performance of Signed References.
The results of the traversal is used for further feature detection, and also for detection of duplicate <code class="language-plaintext highlighter-rouge">refs</code>.</p>

<p>After completion of the traversal, the features can be inspected detect downgrade attacks.
For example, this would be the case if the head commit could be at a <code class="language-plaintext highlighter-rouge">root</code> feature level, and its parent be at the <code class="language-plaintext highlighter-rouge">parent</code> feature level.
In some cases, this could be a legitimate downgrade from a user upgrading to 1.7.0 and back to 1.6.1, due to the aforementioned compatibility issues.
The solution to this is to always allow the user to create a new commit with the latest feature level.</p>

<p>If no downgrade was detected, the verification process then takes the first non-replayed commit as the head,
and loads references from it.</p>

<p>With the feature levels in place, we introduced a configuration option for the fetch protocol.
In the Radicle configuration file, <code class="language-plaintext highlighter-rouge">$RAD_HOME/config.json</code>, a new option was introduced.
The option’s key is <code class="language-plaintext highlighter-rouge">node.fetch.signedReferences.featureLevel.minimum</code> and its value is one of the feature level values, as string: <code class="language-plaintext highlighter-rouge">"none"</code>, <code class="language-plaintext highlighter-rouge">"root"</code>, <code class="language-plaintext highlighter-rouge">"parent"</code>; defaulting to <code class="language-plaintext highlighter-rouge">"none"</code>.
The value is used during a fetch of a repository from the network.
The fetch will reject any namespaces that have a <code class="language-plaintext highlighter-rouge">rad/sigrefs</code> head commit that is below the given minimum.
That is to say, if set to <code class="language-plaintext highlighter-rouge">none</code>, then namespaces will be fetched, but still verified with above rules.
If set to <code class="language-plaintext highlighter-rouge">root</code>, then the fetched namespaces are protected from graft attacks.
Finally, if set to <code class="language-plaintext highlighter-rouge">parent</code>, then the fetched namespaces are protected from graft attacks, and replay attacks.</p>

<p>You may notice that setting this configuration value allows to trade-off security vs. backwards compatibility.
As more nodes upgrade to 1.8.0, users should update the minimum to <code class="language-plaintext highlighter-rouge">parent</code>, as soon as possible.
Once that is done, there is one last escape hatch for fetching and cloning.
The <code class="language-plaintext highlighter-rouge">rad sync --fetch</code> and <code class="language-plaintext highlighter-rouge">rad clone</code> commands now include a <code class="language-plaintext highlighter-rouge">--signed-refs-feature-level</code> option.
Its expected value is, once again, one of the feature levels,
and its behaviour is the same as the above configuration option.</p>

<p>Roughly speaking, by increasing the feature level to <code class="language-plaintext highlighter-rouge">root</code>, one can expect
backwards compatibility to 1.1.0, and by setting <code class="language-plaintext highlighter-rouge">parent</code>, one can expect
backwards compatibility to 1.7.0.</p>

<h2 id="recommended-actions">Recommended Actions</h2>

<ol>
  <li>Update to Radicle 1.8.0 as soon as possible.</li>
  <li>Wait until other users, especially those that you collaborate with, have updated to Radicle 1.8.0.
Use <code class="language-plaintext highlighter-rouge">rad inspect --sigrefs</code> per repository to assess.</li>
  <li>Edit your configuration with <code class="language-plaintext highlighter-rouge">node.fetch.signedReferences.featureLevel.minimum = "parent"</code> for improved security.</li>
</ol>

<h3 id="seed-node-operators">Seed Node Operators</h3>

<p>Because, to the best of our knowledge, there are no replay attacks happening on the network,
we think that no immediate action other than updating to Radicle 1.8.0 is necessary.</p>

<p>However, please familiarize yourself with the newly introduced concept of a “feature level” (see above).
Consider to set <code class="language-plaintext highlighter-rouge">node.fetch.signedReferences.featureLevel.minimum = "parent"</code> after a reasonable period of time to allow others to update.
The Radicle team will do this for seed.radicle.xyz within days, and for iris.radicle.xyz and rosa.radicle.xyz
within the next weeks.
If however, we notice an uptick in suspicious behavior on the network, we will considerably accelerate these timelines.</p>

<h2 id="the-future">The Future</h2>

<h3 id="monitoring-the-network">Monitoring the Network</h3>

<p>We will use the scanner mentioned above to continuously detect potential attacks,
and extend it to also understand how many nodes have updated to Radicle 1.8.0.</p>

<h3 id="automated-cross-version-testing">Automated Cross-Version Testing</h3>

<p>One take away from the process of implementing and testing mitigations,
and their impact on compatibility, was that we will continue to improve our
automated cross-version testing capabilities.
This will help reveal issues before we release.</p>

<h3 id="signed-references">Signed References</h3>

<p>Signed References are a design that was conceived some time ago before Radicle reached 1.0.0.
We think that a similar solution, based on <a href="https://people.kernel.org/monsieuricon/signed-git-pushes">signed pushes</a> and storing <a href="https://git-scm.com/docs/pack-protocol#_push_certificate">push certificates</a> would be more sustainable.
The Linux kernel project, for example, provides transparency logs based on this format,
and it is not specific to Radicle, but defined and maintained by the Git project.</p>

<p>Our goal is to have future versions of Radicle to support both Signed References as well as push certificates,
to allow for a large time-window of cross-compatibility.
Of course, removing support for Signed References means a breaking change down the line.</p>

<hr />

<p>Acknowledgements: We would like to thank maninak and rudolfs for their helpful comments on drafts of this disclosure.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[As announced in the release notes for Radicle 1.7.0, that version contains a fix for a security vulnerability. Radicle 1.7.1, and Radicle 1.8.0, which were released since, also contain this fix. We did not disclose the vulnerability at the time of releasing Radicle 1.7.0 in order to give users time to upgrade, before we disclose the security vulnerability in detail, which is the purpose of this post.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://radicle.dev/https://radicle-website.liw.fi/radicle-1.png" /><media:content medium="image" url="https://radicle.dev/https://radicle-website.liw.fi/radicle-1.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Radicle 1.8.0 – Drosera</title><link href="https://radicle.dev/https://radicle-website.liw.fi/2026/03/30/radicle-1.8.0.html" rel="alternate" type="text/html" title="Radicle 1.8.0 – Drosera" /><published>2026-03-30T00:00:00+03:00</published><updated>2026-03-30T00:00:00+03:00</updated><id>https://radicle.dev/https://radicle-website.liw.fi/2026/03/30/radicle-1.8.0</id><content type="html" xml:base="https://radicle.dev/https://radicle-website.liw.fi/2026/03/30/radicle-1.8.0.html"><![CDATA[<p>The Radicle team are back sooner than later for this important release, Radicle 1.8.0, code name <em><a href="https://en.wikipedia.org/wiki/Drosera">Drosera</a></em>.
<a href="(/https://radicle-website.liw.fi/2026/03/18/radicle-1.7.0.html)">Radicle 1.7.0</a> included a security fix,
and the team worked hard since that release to provide improved security on top of this.</p>

<p>Our post <a href="/https://radicle-website.liw.fi/2026/03/30/disclosure-of-vulnerability-in-signed-references.html">“Disclosure of Vulnerability in Signed References”</a>
provides more context on the features listed below.</p>

<h2 id="signed-references-feature-levels">Signed References Feature Levels</h2>

<h3 id="feature-level-detection">Feature Level Detection</h3>

<p>Radicle’s Signed References now detect which feature level they have been upgraded to.
This feature level is monotonically increasing starting from <code class="language-plaintext highlighter-rouge">none</code>.
The <code class="language-plaintext highlighter-rouge">none</code> feature level means that the <code class="language-plaintext highlighter-rouge">refs</code> and <code class="language-plaintext highlighter-rouge">signature</code> blobs are present,
but the <code class="language-plaintext highlighter-rouge">refs</code> do not contain <code class="language-plaintext highlighter-rouge">refs/rad/root</code> nor <code class="language-plaintext highlighter-rouge">refs/rad/sigrefs-parent</code>.
This still implies that the <code class="language-plaintext highlighter-rouge">signature</code> in <code class="language-plaintext highlighter-rouge">refs</code> must verify against the public key of the namespace.
The next level increases by including <code class="language-plaintext highlighter-rouge">refs/rad/root</code>, and the feature level is known as <code class="language-plaintext highlighter-rouge">root</code>.
Once again, since these are monotonically increasing, <code class="language-plaintext highlighter-rouge">root</code> implies <code class="language-plaintext highlighter-rouge">none</code>.
The latest feature level is <code class="language-plaintext highlighter-rouge">parent</code>, which implies <code class="language-plaintext highlighter-rouge">root</code>, and means that <code class="language-plaintext highlighter-rouge">refs/rad/sigrefs-parent</code> is included.</p>

<h3 id="feature-level-downgrade-detection">Feature Level Downgrade Detection</h3>

<p>Since feature levels are monotonically increasing, this allows us to detect when downgrade attacks are attempted.
When the head commit of a signed references entry is at a <code class="language-plaintext highlighter-rouge">parent</code> feature level,
then they are secure.
However, if the current head is found to be <code class="language-plaintext highlighter-rouge">root</code> or <code class="language-plaintext highlighter-rouge">none</code>,
then the rest of the commits are inspected to see if the head is a result of a downgrade.</p>

<p>Note that, in some cases, downgrades may have occurred due to moving between different
versions of Radicle releases.
In these cases, there are recovery mechanisms, since the user can always create a new
signed references commit, and these upgrades can be fetched by other nodes.</p>

<h3 id="feature-level-migration">Feature Level Migration</h3>

<p>The detection of these feature level allows the node to detect when a migration is needed.
Upon startup of the <code class="language-plaintext highlighter-rouge">radicle-node</code>, if any of the local user’s signed references are not at the <code class="language-plaintext highlighter-rouge">parent</code> feature level, a new signed references entry will be automatically created.</p>

<h3 id="feature-level-inspection">Feature Level Inspection</h3>

<p>To help understand and debug a user’s signed references,
the <code class="language-plaintext highlighter-rouge">rad inspect --sigrefs</code> command has learned to output the feature levels of the signed references entries. For example:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM bf789d587a4f399b0580146cb06634d87188400c parent
z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz 7d1c1aa1816a3bb43b9667ec3d0ee7324b98cb3e parent
z6Mkf8A8EV6M8KjAFyjpvLexQMrixSmHu3hiP45qUMW6FoXE e1d57a292eba718b5bb192c5ba61c5b38ba07398 root
z6MkfXa53s1ZSFy8rktvyXt5ADCojnxvjAoQpzajaXyLqG5n 851d11cf8e6e208b96d72e71181700b822301a48 root
z6MkfgZKQgtWtgNsVizqWqFKf6ka7oo8vS8mppKDVhDM5YMm c5d091bb7d63f2dae517f78f77ae9e0a7e0607b4 none
</code></pre></div></div>

<p>The first column shows the Node Identifier, the second column shows the OID of the head of the respective <code class="language-plaintext highlighter-rouge">refs/rad/sigrefs</code>,
and the third column shows the feature level detected.</p>

<h3 id="feature-level-option">Feature Level Option</h3>

<p>Finally, the <code class="language-plaintext highlighter-rouge">node</code> configuration learned a new configuration option,
under <code class="language-plaintext highlighter-rouge">node.fetch.signedReferences.featureLevel.minimum</code>.
This prevents your node fetching namespaces that are at a feature level below the specified <code class="language-plaintext highlighter-rouge">minimum</code>.
The current default is <code class="language-plaintext highlighter-rouge">none</code>, but as time goes on, and nodes upgrade,
you should choose to update this minimum to <code class="language-plaintext highlighter-rouge">parent</code>.
Once you have updated this minimum, it is still possible to perform a one-shot <code class="language-plaintext highlighter-rouge">rad sync</code> or <code class="language-plaintext highlighter-rouge">rad clone</code> with a lower minimum by using the <code class="language-plaintext highlighter-rouge">--signed-refs-feature-level</code> option.</p>

<h3 id="performance-impact-of-signed-references-verification">Performance Impact of Signed References Verification</h3>

<p>It is important to note that there will be a perceived performance impact on the verification of signed references.
The performance degradation is due to the verification process having to walk the history of the commits.
However, when signed references are on the <code class="language-plaintext highlighter-rouge">parent</code> feature level,
this walk is unnecessary.</p>

<p>This is provides another reason for users to upgrade as soon as possible,
so that fetches are fast again, as well as more secure.</p>

<h2 id="changelog">Changelog</h2>

<ul>
  <li><code class="language-plaintext highlighter-rouge">edde15d9</code> <strong>Release 1.8.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">263d04b5</code> <strong>schemars: Update to 0.7.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">597b514d</code> <strong>remote-helper: Update to 0.16.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d685d6f9</code> <strong>cli: Update to 0.20.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">78908682</code> <strong>node: Update to 0.19.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">6e40a617</code> <strong>protocol: Update to 0.7.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">5a2e7841</code> <strong>fetch: Update to 0.19.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9f91817d</code> <strong>radicle: Update to 0.23.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">46f4c0f3</code> <strong>protocol/service: Increase timeout for fetches</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">e7467fb1</code> <strong>protocol: SignedRefs upgrades provide <code class="language-plaintext highlighter-rouge">SyncedAt</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">6d771abf</code> <strong>radicle/storage/refs: Remove <code class="language-plaintext highlighter-rouge">RefAt::load</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ec36d1c3</code> <strong>radicle/sigrefs: Merge <code class="language-plaintext highlighter-rouge">SignedRefs{,At}</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">07011233</code> <strong>radicle/sigrefs: Use <code class="language-plaintext highlighter-rouge">SignedRefsAt</code> everywhere</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d25fb7f6</code> <strong>radicle/sigrefs/git: Refactor <code class="language-plaintext highlighter-rouge">Committer</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">5d583338</code> <strong>radicle/sigrefs/git: Use stable <code class="language-plaintext highlighter-rouge">RAD_LOCAL_TIME</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">86cacfb8</code> <strong>radicle: Have migration repair downgrades</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">33db6637</code> <strong>radicle: Teach <code class="language-plaintext highlighter-rouge">rad sync</code> and <code class="language-plaintext highlighter-rouge">rad clone</code> to accept feature levels</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ef4ddf06</code> <strong>node: Remove <code class="language-plaintext highlighter-rouge">radicle_fetch::Config</code> from <code class="language-plaintext highlighter-rouge">worker::Config</code></strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">07f3d565</code> <strong>protocol: Allow configuration of <code class="language-plaintext highlighter-rouge">radicle_fetch::Config</code></strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">81ca4b9e</code> <strong>fetch: Allow upgrading Signed References</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">e245e311</code> <strong>fetch: Configure Minimum Feature Level</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">47063057</code> <strong>radicle/sigrefs: Automatically Migrate</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8b166b23</code> <strong>fetch: Log on old sigrefs</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">7fb032da</code> <strong>cli/inspect: Show feature level of sigrefs</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">404fe33a</code> <strong>radicle/sigrefs: Remove <code class="language-plaintext highlighter-rouge">MissingIdentity</code> error</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">7f19044a</code> <strong>radicle/sigrefs/write: Treat error to verify head</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8bc3ffc0</code> <strong>radicle/sigrefs: Detect features when writing</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">372a7875</code> <strong>radicle/sigrefs: Implement feature detection</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9a4539fe</code> <strong>radicle/sigrefs: Find first non-replayed commit</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">b5dc3486</code> <strong>node/wire: Remove <code class="language-plaintext highlighter-rouge">FetchResult</code> log</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">14493cbf</code> <strong>core: Enable <code class="language-plaintext highlighter-rouge">radicle-oid/qcheck</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9fda8c6d</code> <strong>radicle: Update to 0.22.1</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
</ul>

<h2 id="checksums">Checksums</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>c6cf18a44d64182270bfcfcb70a19bc1556e8627bcd6d3b6d373fe7e1c461cc2  radicle-1.8.0-x86_64-unknown-linux-musl.tar.xz
72ac7abde20eee1973bcdcd2d2022916fbb371fc3651ffba9166d15109923ace  radicle-1.8.0-aarch64-unknown-linux-musl.tar.xz
fe68c9a0e5bbceb3cc1c123e99ee2835673759c8acc33511ada995abd33d0abd  radicle-1.8.0-aarch64-apple-darwin.tar.xz
238d9df6204f0ea9e42c9fe508a848e18799abd660483add346908a5f2754826  radicle-1.8.0-x86_64-apple-darwin.tar.xz
</code></pre></div></div>]]></content><author><name></name></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://radicle.dev/https://radicle-website.liw.fi/radicle-1.png" /><media:content medium="image" url="https://radicle.dev/https://radicle-website.liw.fi/radicle-1.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Radicle 1.7.1</title><link href="https://radicle.dev/https://radicle-website.liw.fi/2026/03/20/radicle-1.7.1.html" rel="alternate" type="text/html" title="Radicle 1.7.1" /><published>2026-03-20T00:00:00+02:00</published><updated>2026-03-20T00:00:00+02:00</updated><id>https://radicle.dev/https://radicle-website.liw.fi/2026/03/20/radicle-1.7.1</id><content type="html" xml:base="https://radicle.dev/https://radicle-website.liw.fi/2026/03/20/radicle-1.7.1.html"><![CDATA[<p>The Radicle team would like to announce the release of Radicle 1.7.1 (<a href="https://radicle.network/nodes/seed.radicle.dev/rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5/commits/d9915d275fd07d20db08cf7d3488f8650e66b88a"><code class="language-plaintext highlighter-rouge">d9915d2</code></a>).
After releasing <a href="/https://radicle-website.liw.fi/2026/03/18/radicle-1.7.0.html">1.7.0</a>, our users reported issues after upgrading.
These issues were identified and fixed by the team within a 24 hour window, with help from active contributors; thank you Defelo and rudolfs!</p>

<p>These fixes are included in the notes below.</p>

<h2 id="fixes">Fixes</h2>

<h3 id="ipv6-parsing">IPv6 Parsing</h3>

<p>The fix to ambiguous IPv6 addresses, e.g. <code class="language-plaintext highlighter-rouge">::1:8776</code> vs. <code class="language-plaintext highlighter-rouge">[::1]:8776</code>, resulted in backward incompatibility.
Configuration files containing addresses in the ambiguous format could not be parsed anymore.
Partially undo this change to stay backward compatible, but log a warning in case ambiguous addresses are encountered.</p>

<h3 id="signed-references-compatibility">Signed References compatibility</h3>

<p>In commit <a href="https://radicle.network/nodes/seed.radicle.dev/rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5/commits/d3bc868e84c334f113806df1737f52cc57c5453d"><code class="language-plaintext highlighter-rouge">d3bc868e84c334f113806df1737f52cc57c5453d</code></a> which was released in version 1.7.0, the criteria for verification of Signed References was changed to be more strict.
In particular, to require the reference <code class="language-plaintext highlighter-rouge">refs/rad/root</code> pointing at the root commit in the history of the repository identity.
This was done under the assumption that the overwhelming majority of repositories on the network would have this reference, thus not many users would be negatively affected, in a trade for improved security.
It turned out that this assumption was wrong, and that a larger-than-expected portion of the network is affected by verification errors.
The change is reverted, relaxing the verification criteria again.</p>

<h2 id="changelog">Changelog</h2>

<ul>
  <li><code class="language-plaintext highlighter-rouge">d9915d275</code> <strong>Release 1.7.1</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c627e68fd</code> <strong>node/reactor: Demote reactor lag log to DEBUG</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a6a3716f5</code> <strong>radicle/node/db: Fix type of IPv6 addresses</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">fa1699e5d</code> <strong>radicle/sigrefs: Revert strict verification of <code class="language-plaintext highlighter-rouge">refs/rad/root</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d01ff2e79</code> <strong>radicle/node: Do not error on IPv6 without <code class="language-plaintext highlighter-rouge">[]</code></strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c237a3fe4</code> <strong>radicle: Fix JSON Schema for <code class="language-plaintext highlighter-rouge">node::Address</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9fd4f00c2</code> <strong>remote-helper: Update to 0.15.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d7e7db35e</code> <strong>cli: Update to 0.19.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">026dcdb24</code> <strong>node: Update 0.18.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a9c1c6ef5</code> <strong>protocol: Update to 0.6.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8660b2f00</code> <strong>fetch: Update to 0.18.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">4a731e34e</code> <strong>radicle: Update to 0.22.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">dafd3527e</code> <strong>git-metadata: Update to 0.2.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c9450fe84</code> <strong>cob: Update to 0.19.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">244be7159</code> <strong>core: Update to 0.2.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">674586519</code> <strong>crypto: Update to 0.16.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a2e72b48e</code> <strong>node: Serialize and deserialize ipv6 addresses in square brackets</strong> <em><a href="mailto:mail@defelo.de">mail@defelo.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">addce859f</code> <strong>sigrefs/read: fix typo in doc string</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c824d317e</code> <strong>radicle: Fix <code class="language-plaintext highlighter-rouge">storage::refs::Error::is_not_found</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
</ul>

<h2 id="checksums">Checksums</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>37980a3b7660704007c3fa100bb6aa452ffb3cd13426fbf0f4f824f8f49bca95  radicle-1.7.1-x86_64-unknown-linux-musl.tar.xz
e979a09dfa9bd78293780368f02bcf840a849c19e1e71d276047f35939e595fb  radicle-1.7.1-aarch64-unknown-linux-musl.tar.xz
2043102c423d83e0f411b63d8360000aecd03fa3643ea2ff679dd4333a2984d5  radicle-1.7.1-x86_64-apple-darwin.tar.xz
dafa7f701e5da3f8006e0a0179b19562a2af271d8b0a6c8d4e66ad0ec06de78a  radicle-1.7.1-aarch64-apple-darwin.tar.xz
</code></pre></div></div>]]></content><author><name></name></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://radicle.dev/https://radicle-website.liw.fi/radicle-1.png" /><media:content medium="image" url="https://radicle.dev/https://radicle-website.liw.fi/radicle-1.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Radicle 1.7.0 – Daffodil</title><link href="https://radicle.dev/https://radicle-website.liw.fi/2026/03/18/radicle-1.7.0.html" rel="alternate" type="text/html" title="Radicle 1.7.0 – Daffodil" /><published>2026-03-18T00:00:00+02:00</published><updated>2026-03-18T00:00:00+02:00</updated><id>https://radicle.dev/https://radicle-website.liw.fi/2026/03/18/radicle-1.7.0</id><content type="html" xml:base="https://radicle.dev/https://radicle-website.liw.fi/2026/03/18/radicle-1.7.0.html"><![CDATA[<p>Spring has sprung, where we’re writing from, and Daffodils are in season!</p>

<p>The Radicle team are springing into action and announcing the release of Radicle 1.7.0 (<a href="https://radicle.network/nodes/seed.radicle.dev/rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5/commits/748ddade2feb6f00245c2ba878bd54842dc57506">748ddad</a>), code name <em>Daffodil</em>.
The Daffodil is the national flower of Wales and starts to pop up in February/March – guiding us into the spring time.</p>

<p>This release consists of 226 commits from 11 contributors.
Thank you to all the amazing contributors who provided valuable work this release:</p>
<ul>
  <li>Aaron Würth</li>
  <li>Defelo</li>
  <li>justarandomgeek</li>
  <li>Matthias Beyer</li>
  <li>Sebastian Martinez</li>
  <li>srestegosaurio</li>
  <li>Yorgos Saslis</li>
</ul>

<h2 id="installation">Installation</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl -sSLf https://radicle.dev/install | sh -s -- --no-modify-path --version=1.7.0
</code></pre></div></div>

<h2 id="️-security-fix">⚠️ Security Fix</h2>

<p>This release contains a security fix, and so it is <strong>highly recommended that you update all of your nodes</strong>.
The information on the vulnerability will be disclosed on the 2026-03-30, with a full write-up at <a href="https://radicle.dev/https://radicle-website.liw.fi/2026/03/30/disclosure-of-vulnerability-in-signed-references.html">https://radicle.dev/https://radicle-website.liw.fi/2026/03/30/disclosure-of-vulnerability-in-signed-references.html</a>.</p>

<p>We have taken the time to scan all existing repositories on our public seeds, and have not detected any active exploitation of the vulnerability with malicious intent as of today, 2026-03-18.</p>

<h2 id="new-features">New Features</h2>

<h3 id="improved-radsigrefs">Improved <code class="language-plaintext highlighter-rouge">rad/sigrefs</code></h3>

<p>The “Signed References” feature was reimplemented.
The commits in <code class="language-plaintext highlighter-rouge">refs/rad/sigrefs</code> will now only verify if they carry an appropriate value for <code class="language-plaintext highlighter-rouge">refs/rad/root</code> in the associated <code class="language-plaintext highlighter-rouge">refs</code> blob.
This reference was introduced in commit <a href="https://radicle.network/nodes/seed.radicle.dev/rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5/commits/989edacd564fa658358f5ccfd08c243c5ebd8cda"><code class="language-plaintext highlighter-rouge">989edacd564fa658358f5ccfd08c243c5ebd8cda</code></a>, which was released via version 1.1.0.
A new reference, <code class="language-plaintext highlighter-rouge">refs/rad/sigrefs-parent</code>, is now recorded in the <code class="language-plaintext highlighter-rouge">refs</code> blob, when writing a new entry.
If present, its target must match the parent commit. This is to prevent a replay of a previous <code class="language-plaintext highlighter-rouge">refs/rad/sigrefs</code> commit.
It is optional to maintain backwards compatibility, and might become mandatory (like <code class="language-plaintext highlighter-rouge">refs/rad/root</code> does in this release) in the future.
Further, the new implementation detects replay of <code class="language-plaintext highlighter-rouge">refs</code> blobs.
In order to do so, it walks the history of <code class="language-plaintext highlighter-rouge">refs/rad/sigrefs</code> backwards to the root commit, if <code class="language-plaintext highlighter-rouge">refs/rad/sigrefs-parent</code> is not set.</p>

<h3 id="blocking-policies">Blocking Policies</h3>

<p>For those familiar with <code class="language-plaintext highlighter-rouge">rad block</code>, you may be aware that you can block a <code class="language-plaintext highlighter-rouge">NodeId</code>.
Previous to this release, the blocked node’s references would be rejected during a fetch.
However, it would not be blocked on the connection management level.
With the changes included in this release, blocked nodes are now also blocked at the connection level.
Any attempts for inbound or outbound connections will be rejected.</p>

<h3 id="include-a-wider-set-of-references">Include a Wider Set of References</h3>

<p>The references of a remote were restricted to <code class="language-plaintext highlighter-rouge">heads</code>, <code class="language-plaintext highlighter-rouge">tags</code>, <code class="language-plaintext highlighter-rouge">notes</code>, <code class="language-plaintext highlighter-rouge">rad</code>, and <code class="language-plaintext highlighter-rouge">cobs</code>.
This is too restrictive, and does not allow the extensibility that Git affords us as users.
The restriction is now lifted, and the only references that are filtered out are <code class="language-plaintext highlighter-rouge">refs/tmp/heads</code>; used by <code class="language-plaintext highlighter-rouge">radicle-remote-helper</code> to create temporary patches.</p>

<h3 id="better-errors-for-rad-id-updates">Better Errors for <code class="language-plaintext highlighter-rouge">rad id</code> Updates</h3>

<p>Using <code class="language-plaintext highlighter-rouge">rad id</code> to update the identity document as a non-delegate would result in unclear errors.
Now, when a non-delegate user attempts to update the document, they will have a clearer error given to them.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ rad id update \
    --repo rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji \
    --title "Add myself!" \
    --delegate did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk \
    --no-confirm
✗ Error: did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk is not a delegate, and only delegates are allowed to create a revision
✗ Hint: bob (you) is attempting to modify the identity document but is not a delegate!
</code></pre></div></div>

<h3 id="improved-io-usage">Improved I/O Usage</h3>

<p>Radicle uses <code class="language-plaintext highlighter-rouge">sqlite</code> for local state storage, and it was configured to use <code class="language-plaintext highlighter-rouge">journal_mode = WAL</code>, and the default value of <code class="language-plaintext highlighter-rouge">synchronous = FULL</code>.
It was recently found that this combination would result in a high amount of I/O operations for a long running node.
The <code class="language-plaintext highlighter-rouge">journal_mode</code> and <code class="language-plaintext highlighter-rouge">synchronous</code> pragmas are now configurable from <code class="language-plaintext highlighter-rouge">rad config edit</code>.
The new default values for both are <code class="language-plaintext highlighter-rouge">WAL</code> and <code class="language-plaintext highlighter-rouge">NORMAL</code>, respectively. This results in less I/O operations.
On power loss, transactions might be rolled back, but SQLite still guarantees consistency in this mode.</p>

<h2 id="fixed-bugs">Fixed Bugs</h2>

<h3 id="windows">Windows</h3>

<h4 id="use-winsplit-on-windows">Use <code class="language-plaintext highlighter-rouge">winsplit</code> on Windows</h4>

<p>When preparing commands to execute, the <code class="language-plaintext highlighter-rouge">shlex</code> crate was used on all platforms.
The semantics on Windows are different (e.g. ‘\’ is a path separator on Windows but marks an escape sequence on Unix-like systems).
This lead to issues when attempting to execute child processes, and was fixed by using <code class="language-plaintext highlighter-rouge">winsplit</code> on Windows instead.</p>

<h4 id="prevent-git-upload-pack-zombies">Prevent <code class="language-plaintext highlighter-rouge">git-upload-pack</code> Zombies</h4>

<p>One of our Windows users noticed that <code class="language-plaintext highlighter-rouge">git-upload-pack</code> processes would never be reaped, resulting in zombie processes.
These zombie processes are now prevented by using the “<a href="https://learn.microsoft.com/en-us/windows/win32/procthread/job-objects">Job</a>” API of the operating system to group child processes and their children.</p>

<h4 id="signal-handling-support">Signal Handling Support</h4>

<p>Signal handling is now supported, and so the <code class="language-plaintext highlighter-rouge">radicle-node</code> executable will now respect signals on Windows.</p>

<h3 id="responsive-cli-commands">Responsive CLI Commands</h3>

<p>Users of the <code class="language-plaintext highlighter-rouge">rad</code> CLI would often encounter the following output:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✗ Error: timed out reading from control socket
</code></pre></div></div>

<p>The reason for this was that the request/response pattern that was implemented never accounted for errors.
When the <code class="language-plaintext highlighter-rouge">Service</code> would receive a request that resulted in a failure, it would log it, and move on.
The <code class="language-plaintext highlighter-rouge">Service</code> has now learned to respond with errors.
This will improve the above error scenarios by providing more information about the error that occurred.</p>

<h3 id="ipv6-address-parsing">IPv6 Address Parsing</h3>

<p>Parsing addresses involving an IPv6 host failed if they were enclosed in square brackets, e.g. in <code class="language-plaintext highlighter-rouge">rad node connect z6Mk...@[::1]:8776</code>.
Also, ambiguous addresses would parse, e.g. <code class="language-plaintext highlighter-rouge">::1:8776</code> would be indistinguishable from <code class="language-plaintext highlighter-rouge">[::1]:8776</code>.
Since a port number is always required along with a host when providing an address, IPv6 addresses now always require brackets to avoid confusion.
Existing IPv6 addresses that are stored in the <code class="language-plaintext highlighter-rouge">sqlite</code> database are migrated automatically on node startup.</p>

<h2 id="deprecations">Deprecations</h2>

<h3 id="rad-fork"><code class="language-plaintext highlighter-rouge">rad fork</code></h3>

<p>The <code class="language-plaintext highlighter-rouge">rad fork</code> command was confusing, and mislead users as to what its purpose was.
Many believed it to create a hard-fork of the repository.
Instead, it pushed the default branch to the local user’s namespace.
The command is now deprecated, and you should use <code class="language-plaintext highlighter-rouge">git push</code> instead.</p>

<h2 id="breaking-changes">Breaking Changes</h2>

<h3 id="seeds-no-longer-contains-fetching-information"><code class="language-plaintext highlighter-rouge">Seeds</code> No Longer Contains Fetching Information</h3>

<p>If you are using the <code class="language-plaintext highlighter-rouge">radicle-node</code> control socket, and request <code class="language-plaintext highlighter-rouge">Seeds</code> information, then expect a breaking change to the output.
The <code class="language-plaintext highlighter-rouge">Connected</code> state of a peer no longer contains fetching information, which was separated out.
This has resulted in the entire <code class="language-plaintext highlighter-rouge">fetching</code> value being removed.</p>

<h3 id="changes-to-rad-node-debug-information">Changes to <code class="language-plaintext highlighter-rouge">rad node debug</code> Information</h3>

<p>The <code class="language-plaintext highlighter-rouge">rad node debug</code> information for ongoing fetches contained the number of subscribers awaiting for results, this was removed.</p>

<h3 id="cob-type-names-are-more-dns-compliant">COB Type Names are More DNS Compliant</h3>

<p>The <code class="language-plaintext highlighter-rouge">TypeName</code> strings defined in <code class="language-plaintext highlighter-rouge">radicle-cob</code> are restricted to reflect the size limits on domain names as specified in <a href="https://www.rfc-editor.org/rfc/rfc1035#section-2.3.4">RFC-1035</a>.
These restrictions are:</p>
<ul>
  <li>A total length of 255 bytes.</li>
  <li>A max component length of 63 bytes.</li>
</ul>

<h3 id="human-readable-timeout-durations">Human-readable Timeout Durations</h3>

<p>Several <code class="language-plaintext highlighter-rouge">rad</code> commands take a <code class="language-plaintext highlighter-rouge">--timeout</code> option, and each one would vary in units, e.g. seconds, milliseconds.
These options now take human-readable durations as values, e.g. “9s” for 9 seconds, “1min” for 1 minute, etc.
This is a breaking change since these options now require the unit to be specified.</p>

<h2 id="changelog">Changelog</h2>

<p>This release contains 226 commit(s) by 11 contributor(s).</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">748ddade</code> <strong>fetch: Make <code class="language-plaintext highlighter-rouge">RemoteRefs</code> an alias</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">35d71f59</code> <strong>fetch: Remove <code class="language-plaintext highlighter-rouge">DelegateStatus</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">363a7231</code> <strong>fetch: Remove dead code from <code class="language-plaintext highlighter-rouge">DataRefs</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">725ced09</code> <strong>fetch: Prune remotes with sigrefs failures</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">6967bf8f</code> <strong>radicle: Automatically upgrade sigrefs</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">20598d39</code> <strong>radicle: Remove unused <code class="language-plaintext highlighter-rouge">SyncedAt::load</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0f9eace8</code> <strong>crypto: Remove markers <code class="language-plaintext highlighter-rouge">Verified</code> and <code class="language-plaintext highlighter-rouge">Unverified</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">304a6631</code> <strong>radicle: Remove generics for verification markers</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">393eca39</code> <strong>node/e2e: <code class="language-plaintext highlighter-rouge">rad/sigrefs-parent</code> is not fetched</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d40fa9a3</code> <strong>radicle/sigrefs: Switch to new implementation</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d3bc868e</code> <strong>radicle/sigrefs: Rewrite Signed References</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">52a660fd</code> <strong>node/test: Set <code class="language-plaintext highlighter-rouge">RAD_RNG_SEED</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">99d92421</code> <strong>Use humantime to parse timeouts</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">52e55812</code> <strong>cli: Don’t override existing seeding scope in <code class="language-plaintext highlighter-rouge">rad seed</code></strong> <em><a href="mailto:mail@defelo.de">mail@defelo.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">281f92e9</code> <strong>cli/tests: Add test for <code class="language-plaintext highlighter-rouge">rad clone --scope</code></strong> <em><a href="mailto:mail@defelo.de">mail@defelo.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">eea36177</code> <strong>use <code class="language-plaintext highlighter-rouge">CONIN$</code> instead of <code class="language-plaintext highlighter-rouge">/dev/tty</code> on windows</strong> <em><a href="mailto:justarandomgeek@gmail.com">justarandomgeek@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a1fd9e04</code> <strong>radicle: Update <code class="language-plaintext highlighter-rouge">sqlite</code> to 0.37</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">07369771</code> <strong>node: Migrate IPv6 addresses in database</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9e8f09a1</code> <strong>Remove stray files</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0c47d06f</code> <strong>radicle/storage/refs: Strengthen Encapsulation</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f4495e92</code> <strong>radicle/device: <code class="language-plaintext highlighter-rouge">impl Keypair for BoxedSigner</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">74fa4425</code> <strong>crypto: Require <code class="language-plaintext highlighter-rouge">Signer: signature::Signer</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">06fae85e</code> <strong>crypto: <code class="language-plaintext highlighter-rouge">impl Signer</code> based on <code class="language-plaintext highlighter-rouge">Keypair</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f2ad5454</code> <strong>crypto: <code class="language-plaintext highlighter-rouge">impl signature::KeypairRef</code> for Signers</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">768ecf56</code> <strong>crypto: Add <code class="language-plaintext highlighter-rouge">impl Verifier for PublicKey</code></strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">01c60388</code> <strong>git-metadata: Add parsing of <code class="language-plaintext highlighter-rouge">CommitData</code></strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">58624148</code> <strong>git-metadata: Add <code class="language-plaintext highlighter-rouge">CommitData::strip_signatures</code></strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">60871de8</code> <strong>git-metadata: Add derivable traits</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0e45347b</code> <strong>radicle/storage: Improve <code class="language-plaintext highlighter-rouge">Validation</code> error</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ba9c09fa</code> <strong>radicle/refs: Better <code class="language-plaintext highlighter-rouge">SignedRefs</code> Encapsulation</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">39a58ded</code> <strong>node/test: Use <code class="language-plaintext highlighter-rouge">Arbitrary</code> for <code class="language-plaintext highlighter-rouge">SignedRefs</code></strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f7ff4d8f</code> <strong>radicle/arbitrary: Move <code class="language-plaintext highlighter-rouge">impl Arbitrary</code> of refs</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">b8502397</code> <strong>protocol/wire: Remove SignedRefs encoding/decoding</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ba8d6b88</code> <strong>radicle/storage: Remove unused Remote methods</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">e78d477b</code> <strong>radicle/git: Remove unused <code class="language-plaintext highlighter-rouge">fn remote_refs</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">759a6fb9</code> <strong>radicle: Compile <code class="language-plaintext highlighter-rouge">rad::fork_remote</code> only for tests</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">7bac1714</code> <strong>CHANGELOG: fix typo</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">cb3ca622</code> <strong>radicle/CHANGELOG: remove variant typo</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9dbbb01d</code> <strong>radicle: remove <code class="language-plaintext highlighter-rouge">TryFrom</code></strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">57da7799</code> <strong>radicle: Add a <code class="language-plaintext highlighter-rouge">load</code> method to <code class="language-plaintext highlighter-rouge">radicle::profile::Home</code></strong> <em><a href="mailto:me@sebastinez.dev">me@sebastinez.dev</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ff85c74e</code> <strong>cli: Add blank line after issue reply header</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">1b986af0</code> <strong>cli/tests: Refactor workflow test</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">fa82bd5f</code> <strong>cli/tests: Refactor watch command tests</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">45e6afd0</code> <strong>cli/tests: Refactor utility command tests</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d282e0d0</code> <strong>cli/tests: Refactor sync command tests</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">7d2842a4</code> <strong>cli/tests: Refactor remote command tests</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c1ab7c38</code> <strong>cli/tests: Refactor policy command tests</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">18d7f99e</code> <strong>cli/tests: Refactor patch command tests</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">4ffabde6</code> <strong>cli/tests: Refactor node command tests</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">b2568f0b</code> <strong>cli/tests: Refactor jj command tests</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">4753b889</code> <strong>cli/tests: Refactor issue command tests</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8bf655ef</code> <strong>cli/tests: Refactor init command tests</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a1c1b03b</code> <strong>cli/tests: Refactor inbox command tests</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">cd4532ec</code> <strong>cli/tests: Refactor id command tests</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">dac099e4</code> <strong>cli/tests: Refactor git command tests</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d39e485c</code> <strong>cli/tests: Refactor cob command tests</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">1f3dc6ae</code> <strong>cli/tests: Refactor clone command tests</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">7a1e6a24</code> <strong>cli/tests: Refactor checkout command tests</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">5aaf978f</code> <strong>radicle: Configure database connections on open</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f3afe7b0</code> <strong>radicle/config/sqlite: Use <code class="language-plaintext highlighter-rouge">synchronous = NORMAL</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f4aee203</code> <strong>radicle: Make SQLite pragmas configurable</strong> <em><a href="mailto:yorgos.work@proton.me">yorgos.work@proton.me</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">6cc3da95</code> <strong>radicle/node/db: Model SQLite <code class="language-plaintext highlighter-rouge">synchronous</code> pragma</strong> <em><a href="mailto:yorgos.work@proton.me">yorgos.work@proton.me</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d36bf41f</code> <strong>radicle/node/db: Directly represent SQLite pragmas</strong> <em><a href="mailto:yorgos.work@proton.me">yorgos.work@proton.me</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9ff67562</code> <strong>cli: Format IPv6 addresses in square brackets</strong> <em><a href="mailto:mail@defelo.de">mail@defelo.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">df8e4e6c</code> <strong>node: Parse IPv6 addresses in square brackets</strong> <em><a href="mailto:mail@defelo.de">mail@defelo.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">7c923608</code> <strong>radicle: fix to schemars of DefaultSeedingPolicy</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">6291cae5</code> <strong>cli: add <code class="language-plaintext highlighter-rouge">rad config schema</code> to the <code class="language-plaintext highlighter-rouge">rad-config</code> test</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f018b434</code> <strong>node: control debug serialization of FetcherState</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9ea1ea24</code> <strong>Revert “node/debug: Use derived serializers”</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">e9245b63</code> <strong>cli: don’t override existing seeding scope in <code class="language-plaintext highlighter-rouge">rad clone</code></strong> <em><a href="mailto:mail@defelo.de">mail@defelo.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">b04f487b</code> <strong>term: Update to 0.17.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9a98cf7b</code> <strong>keccak: Update to 0.1.6</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">bab3f82a</code> <strong>fetch: Update to 0.17.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a0b434c3</code> <strong>localtime: add description in Cargo.toml</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9dba9130</code> <strong>core: use “data-types” instead of “data types”</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f9a36ef7</code> <strong>systemd: Update to 0.12.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">18d6ce94</code> <strong>protocol: Update 0.5.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c0ae5e32</code> <strong>node: Update to 0.17.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">963b4ded</code> <strong>crypto: Update to 0.15.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">84e9ffe4</code> <strong>cob: Update to 0.18.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">186d8d30</code> <strong>cli: Update to 0.18.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">3a110746</code> <strong>radicle: Update to 0.21.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">15666467</code> <strong>radcile/cob/identity: mark ApplyError as non_exhaustive</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d596b14e</code> <strong>build: Pin Zig to 0.13.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">4c759a26</code> <strong>build: Update macos-sdk to include IOKit, libconv, and libcharset</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">57a44dae</code> <strong>build: Update cargo-zigbuild to 0.22.1</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">89478b16</code> <strong>cargo/git2: Update to 0.20.4</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">423cf604</code> <strong>nix: update to 25.11</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">30701cc6</code> <strong>node/runtime: Make <code class="language-plaintext highlighter-rouge">Runtime::run</code> more readable</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">057edf55</code> <strong>node/reactor: Introduce <code class="language-plaintext highlighter-rouge">LAG_TIMEOUT</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ae06111e</code> <strong>node/reactor: Rewrite <code class="language-plaintext highlighter-rouge">Runtime::run</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">4d7b942b</code> <strong>remote-helper: Rename <code class="language-plaintext highlighter-rouge">to_branch_name</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">6d2a99e1</code> <strong>remote-helper: Remove Unused Error Variants</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a69420b9</code> <strong>remote-helper: Rework Visibility Modifiers</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d36ed7c8</code> <strong>remote-helper/protocol: Introduce Line and Command</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">27493c22</code> <strong>remote-helper/service: Introduce <code class="language-plaintext highlighter-rouge">NodeSession</code></strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">56253b52</code> <strong>remote-helper/service: Introduce <code class="language-plaintext highlighter-rouge">GitService</code></strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">bd30e80b</code> <strong>remote-helper/list: Remove printing to stdio</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">119445ce</code> <strong>cli-test: Move <code class="language-plaintext highlighter-rouge">let mut args</code> closer to its uses</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">56ece480</code> <strong>cli-test: Remove special handling for <code class="language-plaintext highlighter-rouge">rad</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">3cd1af1d</code> <strong>cli-test: Configure <code class="language-plaintext highlighter-rouge">escargot</code> properly</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">5aca9bf1</code> <strong>cli-test: Refactor Path Handling</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d88ef3fa</code> <strong>e2e: Introduce 3 tests for block command</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a4806f27</code> <strong>node/test: check remote events for <code class="language-plaintext highlighter-rouge">Event::PeerDisconnected</code></strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">1fa14ef5</code> <strong>protocol/service: Use block list for connections</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">94e0a512</code> <strong>node: Add block command to control socket</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">4286590f</code> <strong>fetch: move <code class="language-plaintext highlighter-rouge">Component::from</code> outside of loop</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0e9d7607</code> <strong>hooks: Enable typos, fix reported errors</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">5fa68ed8</code> <strong>node: Use <code class="language-plaintext highlighter-rouge">gix_packetline</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c96aea06</code> <strong>node/e2e: Fix test_non_fastforward_identity_doc</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">832598ce</code> <strong>cli: Warn user about implicit seeding policy</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">cee3659e</code> <strong>radicle: Introduce <code class="language-plaintext highlighter-rouge">radicle::node::config::Scope</code></strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">306d0afb</code> <strong>protocol: Note on peering and fetches</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0684d1cc</code> <strong>cli: Changed the default scope from all to followed for clone and seed</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">dd13eed1</code> <strong>cli: Do not print scope in block table</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">b5e8776e</code> <strong>fetch: Improve <code class="language-plaintext highlighter-rouge">refs/rad/id</code> resolution</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">84320919</code> <strong>node/tests/e2e: use assert_eq! in test</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">7862e108</code> <strong>Update gix-* crates</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">39157117</code> <strong>fetch: introduce domain type RefPrefix</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8070f98a</code> <strong>fetch/transport/ls_refs: Post-filter of references</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">980ed561</code> <strong>protocol/service: rename <code class="language-plaintext highlighter-rouge">Responder::new</code> to <code class="language-plaintext highlighter-rouge">Responder::oneshot</code></strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0d628a45</code> <strong>protocol: refactor to use Responder</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">b1eedd3b</code> <strong>protocol/service: introduce Responder type</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">61a9b214</code> <strong>protocol/service: introduce Result synonym</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">2c197215</code> <strong>protocol: opaque command error</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">38713a8e</code> <strong>protocol/service: drop <code class="language-plaintext highlighter-rouge">chan</code> qualifier</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">912a5ca4</code> <strong>protocol/service: create command module</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">fa94638a</code> <strong>radicle/storage/init: Remove placeholder files</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">7425ae4b</code> <strong>ssh: Treat “connection refused” on Windows</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">5099c25d</code> <strong>node/debug: Use derived serializers</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a1fa3801</code> <strong>protocol: Depend on <code class="language-plaintext highlighter-rouge">cypheraddr</code> not <code class="language-plaintext highlighter-rouge">cyphernet</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d530f126</code> <strong>node/test: Remove unused file <code class="language-plaintext highlighter-rouge">environment.rs</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">730d696d</code> <strong>node/test: Bind to loopback interface</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">dfe3b501</code> <strong>radicle/git/raw: <code class="language-plaintext highlighter-rouge">Config</code> not used on Windows</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ed2b36cf</code> <strong>cli-test: Log line of assertion being executed</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9055a204</code> <strong>cli-test: Add placeholder for executable extension</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">e831aeb5</code> <strong>cli-test: Do not store <code class="language-plaintext highlighter-rouge">bins</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8fbdd46c</code> <strong>cli-test: Cheat to find coreutils on Windows</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">4894657b</code> <strong>cli-test: Simplify cargo path handling</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">25d1974c</code> <strong>cli-test: Deduplicate populating <code class="language-plaintext highlighter-rouge">bins</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">44f52f4c</code> <strong>cli-test: Fix uses of <code class="language-plaintext highlighter-rouge">PATH_SEPARATOR</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">dd122f10</code> <strong>cli/test: Ignore <code class="language-plaintext highlighter-rouge">rad_diff</code> on Windows</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">5974fa32</code> <strong>windows: Add installer build</strong> <em><a href="mailto:lorenz@lap-21-0150.mpi-inf.mpg.de">lorenz@lap-21-0150.mpi-inf.mpg.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c06b00e3</code> <strong>CVE-2026-25727</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">31607cf7</code> <strong>CVE-2026-25541</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">2d0db3c6</code> <strong>CVE-2025-58160</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">03bbe524</code> <strong>signals: Add support for Windows</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">865abd35</code> <strong>protocol/fetcher: Intro <code class="language-plaintext highlighter-rouge">RefsToFetch</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9081c11b</code> <strong>protocol/fetcher: Remove <code class="language-plaintext highlighter-rouge">from</code> from <code class="language-plaintext highlighter-rouge">QueuedFetch</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">53a12869</code> <strong>protocol/service: Remove unnecessary arg</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">94d7799f</code> <strong>protocol/fetcher/state: Typo</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">56ee626a</code> <strong>protocol/fetcher: Delete unused file</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">41f77a49</code> <strong>RELEASE: start at rc.1</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">613c4e83</code> <strong>protocol: separate subscribers by RefsAt</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">993428df</code> <strong>node: donwgrade log error to trace for disconnection</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">aeba81f4</code> <strong>core: add documentation to <code class="language-plaintext highlighter-rouge">RepoId::from_canonical</code></strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">35a01898</code> <strong>core: guard on expected multibase</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8ee32168</code> <strong>radicle: remove file</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ebf7d876</code> <strong>node: Control via <code class="language-plaintext highlighter-rouge">uds_windows</code> not <code class="language-plaintext highlighter-rouge">winpipe</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">90cf37c4</code> <strong>node: On Windows, use job for upload-pack child</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">990edbf0</code> <strong>windows: Introduce new crate</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">50fb228a</code> <strong>term/editor: Implement <code class="language-plaintext highlighter-rouge">exists</code> for Windows</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">450b664a</code> <strong>term/editor: Use <code class="language-plaintext highlighter-rouge">cfg</code>-attribute instead of macro</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8fb2d96b</code> <strong>radicle/profile: No pager from Git on Windows</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">930ec175</code> <strong>term, cli: <code class="language-plaintext highlighter-rouge">winsplit</code> over <code class="language-plaintext highlighter-rouge">shlex</code> on Windows</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">537eaba8</code> <strong>Use rust-analyzer from tool chain in devShell</strong> <em><a href="mailto:aaron.wuerth@posteo.de">aaron.wuerth@posteo.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d7a4137e</code> <strong>systemd: remove redundant lines from system unit</strong> <em><a href="mailto:lcdt@disroot.org">lcdt@disroot.org</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">27ee6e10</code> <strong>ci: Enable debugging on Windows</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">fefa2837</code> <strong>cli/init: Canonicalize path before comparison</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ffbbb374</code> <strong>cli-test: Path separation compatible with Windows</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">faeee9f3</code> <strong>crypto: Optionally provide JSON Schema</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">82ad52b1</code> <strong>cob: further restrict TypeName</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">fe09cd4a</code> <strong>cob: split up typename tests</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">204db22b</code> <strong>cob: enable sha1 feature</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">1cab036c</code> <strong>protocol/service: Wire up <code class="language-plaintext highlighter-rouge">FetcherService</code></strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9e208909</code> <strong>protocol: Introduce <code class="language-plaintext highlighter-rouge">FetcherService</code></strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f0e3ca34</code> <strong>protocol: Introduce <code class="language-plaintext highlighter-rouge">FetcherState</code></strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">7cf73300</code> <strong>radicle/storage/refs: Derive <code class="language-plaintext highlighter-rouge">Hash</code> for <code class="language-plaintext highlighter-rouge">RefsAt</code></strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">eccfd6ba</code> <strong>cli: optional message for issue comments</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c33c26fa</code> <strong>cli: fix casing for warning of preferred_seeds</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">15adb161</code> <strong>protocol: missed formatting</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">91eb6fc0</code> <strong>protocol: ensure <code class="language-plaintext highlighter-rouge">connect</code> supports connecting address</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">36d5a4c8</code> <strong>protocol: use helper method</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">73f9a350</code> <strong>protocol: reuse session address for reconnect</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">589925e3</code> <strong>radicle/node: avoid unnecessary allocations in <code class="language-plaintext highlighter-rouge">Emitter::emit_all</code></strong> <em><a href="mailto:mail@defelo.de">mail@defelo.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8b1d4751</code> <strong>protocol: batch inventory removals and events in <code class="language-plaintext highlighter-rouge">sync_routing</code></strong> <em><a href="mailto:mail@defelo.de">mail@defelo.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d2ab7b1b</code> <strong>RELEASE: include patch releases</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">1c9a1b4f</code> <strong>RELEASE: Add file documenting the release process</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">e63c3097</code> <strong>cli/fork: Deprecate</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">b937a938</code> <strong>radicle-cli: more helpful error for non-delegate updates</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">60959f7e</code> <strong>cli: promote WithHint hint type to String</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">67a4a712</code> <strong>radicle: add new error type for unauthorized non-delegates</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">bd5436d7</code> <strong>core: Fix doctest</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">b41ce2e6</code> <strong>radicle/canonical: provide public Canonical JSON link</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f6d3dae4</code> <strong>CHANGELOG: Release 1.6.1</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a4e66d14</code> <strong>radicle: Allow all references to be included in sigrefs</strong> <em><a href="mailto:mail@defelo.de">mail@defelo.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">67dee655</code> <strong>Release 1.6.0 CHANGELOG</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">6d1abd28</code> <strong>node: downgrade <code class="language-plaintext highlighter-rouge">error!</code> logs</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">b020543c</code> <strong>node: downgrade <code class="language-plaintext highlighter-rouge">warn!</code> logs</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ee1f5542</code> <strong>protocol: downgrade <code class="language-plaintext highlighter-rouge">error!</code> logs</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">eeadffa6</code> <strong>node: update comment</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">958422a7</code> <strong>node/routing: remove error scenario from Database::prune</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">95b3d109</code> <strong>protocol: downgrade <code class="language-plaintext highlighter-rouge">warn!</code> logs</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9236277a</code> <strong>fetch: remove <code class="language-plaintext highlighter-rouge">target: "fetch"</code></strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">e3cb36d9</code> <strong>fetch: clean up logging</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d860ec15</code> <strong>cli: Remove dead <code class="language-plaintext highlighter-rouge">fn parse_remote</code></strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">53cb8da8</code> <strong>clippy: Deny and fix <code class="language-plaintext highlighter-rouge">must_use_candidate</code></strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">2df32c00</code> <strong>clippy: Deny <code class="language-plaintext highlighter-rouge">fn_params_excessive_bools</code></strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">4c1b7fcd</code> <strong>clippy: Deny and fix <code class="language-plaintext highlighter-rouge">index_slicing</code></strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0855af00</code> <strong>clippy: Deny and fix <code class="language-plaintext highlighter-rouge">unneeded_field_pattern</code></strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9cc2c869</code> <strong>clippy: Deny and fix <code class="language-plaintext highlighter-rouge">wildcard_enum_match_arm</code></strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">001aba0d</code> <strong>clippy: Deny and fix <code class="language-plaintext highlighter-rouge">fallible_impl_from</code></strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">02318f19</code> <strong>radicle: Re-export <code class="language-plaintext highlighter-rouge">radicle_core::RepoId</code></strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">73827f53</code> <strong>radicle: Re-export <code class="language-plaintext highlighter-rouge">radicle_core::NodeId</code></strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">7c016f92</code> <strong>core: Introduce NodeId</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d5fea632</code> <strong>core: Introduce RepoId</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">af3f0762</code> <strong>chore: Update thiserror from 1 to 2</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d98033a1</code> <strong>localtime: localise the localtime dependency</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">3168107d</code> <strong>fetch: surface underlying I/O error</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">75b665ff</code> <strong>node/wire: manage logs for error establishing connection</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">47dc2c56</code> <strong>protocol/service: defensive storage.contains check</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a46f8eb1</code> <strong>node: use <code class="language-plaintext highlighter-rouge">outbound.get</code> over <code class="language-plaintext highlighter-rouge">outbound.get_mut</code></strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">b8a6e1a5</code> <strong>radicle/cob/stream: skip commits that do not have a manifest</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">cf023f75</code> <strong>cob: allow hyphens in <code class="language-plaintext highlighter-rouge">TypeName</code></strong> <em><a href="mailto:mail@defelo.de">mail@defelo.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">352c29c2</code> <strong>cargo(deny): allow Zlib</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a66d44eb</code> <strong>workspace: update git-ref-format-core and radicle-surf</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
</ul>

<h2 id="checksums">Checksums</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>e6de41ba2b2efd07b9ab008717d720184f8385c3bb93ad5c4a37f257179ecfed  radicle-1.7.0-x86_64-apple-darwin.tar.xz
0dd4d185bd6a1e5588ec879471678c482b0cc27d92cb2cc3b22982e63e920049  radicle-1.7.0-aarch64-unknown-linux-musl.tar.xz
dd9b734dc7b7b7132e7a27e5a53e268276870bbebd195ff6c0e1273ec2984dea  radicle-1.7.0-aarch64-apple-darwin.tar.xz
e23ad2f616d9730db5ae4eb730baad1373172e2dcaec1fef2c6b199dba514378  radicle-1.7.0-x86_64-unknown-linux-musl.tar.xz
</code></pre></div></div>]]></content><author><name></name></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://radicle.dev/https://radicle-website.liw.fi/radicle-1.png" /><media:content medium="image" url="https://radicle.dev/https://radicle-website.liw.fi/radicle-1.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Radicle 1.6.0 – Amaryllis</title><link href="https://radicle.dev/https://radicle-website.liw.fi/2026/01/14/radicle-1.6.0.html" rel="alternate" type="text/html" title="Radicle 1.6.0 – Amaryllis" /><published>2026-01-14T00:00:00+02:00</published><updated>2026-01-14T00:00:00+02:00</updated><id>https://radicle.dev/https://radicle-website.liw.fi/2026/01/14/radicle-1.6.0</id><content type="html" xml:base="https://radicle.dev/https://radicle-website.liw.fi/2026/01/14/radicle-1.6.0.html"><![CDATA[<p>Happy new year!</p>

<p>The Radicle team is excited to announce the release of Radicle 1.6.0 (4a5a51e6), code name <em>Amaryllis</em>.
The Amaryllis flower blooms late winter and prefers to sit in the <em>window</em> (<strong>foreshadowing…</strong>)</p>

<p>First off, we would like to say sorry for the hiatus.
As the team worked on some major refactoring, we ran into a snag before we could perform this release.
Thankfully, we caught the bug, but as we were pushing up against holiday time, we put a hold on releasing.
Now that we are on the other side of the new year, and sufficiently defrosted, we are back to making regular releases!</p>

<p>This release consists of massive 153 commits from 12 contributors.
People really banded together to make a better release for Radicle this time round!
Let’s give thanks to:</p>
<ul>
  <li>ade</li>
  <li>icetan</li>
  <li>defelo</li>
  <li>Johannes K.</li>
  <li>matthias</li>
  <li>Richard L.</li>
  <li>Sebastian M.</li>
  <li>Yaroslav H.</li>
</ul>

<h2 id="installation">Installation</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl -sSLf https://radicle.dev/install | sh -s -- --no-modify-path --version=1.6.0
</code></pre></div></div>

<h2 id="migrating-radicle-node-to-mio">Migrating <code class="language-plaintext highlighter-rouge">radicle-node</code> to <code class="language-plaintext highlighter-rouge">mio</code></h2>

<p>The crates <a href="https://crates.io/crates/netservices"><code class="language-plaintext highlighter-rouge">netservices</code></a>, <a href="https://crates.io/crates/io-reactor"><code class="language-plaintext highlighter-rouge">io-reactor</code></a>, and <a href="https://crates.io/crates/popol"><code class="language-plaintext highlighter-rouge">popol</code></a> were crucially valuable
for implementing <code class="language-plaintext highlighter-rouge">radicle-node</code>. However, they are not ideal dependencies for
ensuring long-term health of the network I/O layer:</p>

<ul>
  <li><a href="https://crates.io/crates/popol"><code class="language-plaintext highlighter-rouge">popol</code></a> is only intended to support Unix-like platforms, and support on other
platforms, like Windows, is desired.</li>
  <li>Even though <a href="https://crates.io/crates/io-reactor"><code class="language-plaintext highlighter-rouge">io-reactor</code></a> defines the trait <a href="https://docs.rs/io-reactor/0.5.2/reactor/poller/trait.Poll.html"><code class="language-plaintext highlighter-rouge">reactor::poller::Poll</code></a> to
potentially support multiple I/O polling mechanisms, there is only one single
implementation wrapping <a href="https://crates.io/crates/popol"><code class="language-plaintext highlighter-rouge">popol</code></a>. Issues for other polling crates are open
since 2023 without tangible progress: <a href="https://github.com/rust-amplify/io-reactor/issues/10">#10 for <code class="language-plaintext highlighter-rouge">mio</code></a>, <a href="https://github.com/rust-amplify/io-reactor/issues/9">#9 for <code class="language-plaintext highlighter-rouge">polling</code></a>,
<a href="https://github.com/rust-amplify/io-reactor/issues/8">#8 for <code class="language-plaintext highlighter-rouge">epoll</code></a>. This suggests that it is not a high priority for the maintainers
to integrate with other polling abstractions which might offer better
cross-platform compatibility when compared to <code class="language-plaintext highlighter-rouge">popol</code>.</li>
  <li>The trait <a href="https://docs.rs/io-reactor/0.5.2/reactor/poller/trait.Poll.html"><code class="language-plaintext highlighter-rouge">reactor::poller::Poll</code></a> can only be implemented for file
descriptors which also implement <a href="https://doc.rust-lang.org/nightly/std/os/fd/raw/trait.AsRawFd.html"><code class="language-plaintext highlighter-rouge">std::os::fd::raw::AsRawFd</code></a>, which is only
implemented on Unix-like platforms and WASI. It is believed that this is
leaked from <code class="language-plaintext highlighter-rouge">popol</code> as the only known implementation of the trait wraps it.</li>
  <li>To benefit from network effects, it would be nice to see others maintaining crates
that depend on <code class="language-plaintext highlighter-rouge">io-reactor</code>. However, according to crates.io, the
<a href="https://crates.io/crates/io-reactor/reverse_dependencies">only dependent is <code class="language-plaintext highlighter-rouge">radicle-node</code></a> (via <code class="language-plaintext highlighter-rouge">netservices</code>). Contrary to that,
at the time of writing, <code class="language-plaintext highlighter-rouge">mio</code> has 494 dependents according to
<a href="https://crates.io/crates/mio/reverse_dependencies">crates.io</a>, and, notably, <code class="language-plaintext highlighter-rouge">tokio</code>, which has
30628 dependents on <a href="https://crates.io/crates/tokio/reverse_dependencies">crates.io</a>, is dependent on
[<code class="language-plaintext highlighter-rouge">mio</code>]. We therefore think that even if <code class="language-plaintext highlighter-rouge">mio</code> is obsoleted, e.g. by <a href="https://crates.io/crates/a10"><code class="language-plaintext highlighter-rouge">a10</code></a>
(which is based on <a href="https://en.wikipedia.org/wiki/Io_uring"><code class="language-plaintext highlighter-rouge">io_uring</code></a> on Linux and could potentially build on top of
<a href="https://learn.microsoft.com/en-us/windows/win32/api/ioringapi/">I/O rings on Windows</a>) the people behind a large network of dependent projects
are expected to come up with new ideas and solutions, that Radicle would then
benefit from.</li>
  <li>One downside of using <code class="language-plaintext highlighter-rouge">mio</code> is that it forces the use of <a href="https://docs.rs/mio/1.0.4/mio/struct.Token.html"><code class="language-plaintext highlighter-rouge">mio::Token</code></a> to
identify sources (while a type that is <code class="language-plaintext highlighter-rouge">Eq + Clone</code> might be enough). Another
downside is that it forces the use of the types in <a href="https://docs.rs/mio/1.0.4/mio/net/index.html"><code class="language-plaintext highlighter-rouge">mio::net</code></a> for sockets,
which need to be converted to/from <a href="https://doc.rust-lang.org/stable/std/net/index.html"><code class="language-plaintext highlighter-rouge">std::net</code></a> if required. These
distinctions are also <a href="https://cloudhead.io/popol/">noted by cloudhead</a>. This is acceptable to the team, in
order to leverage the benefits of a well-tested and cross-platform network I/O
layer.</li>
</ul>

<h2 id="building-radicle-node-on-windows">Building <code class="language-plaintext highlighter-rouge">radicle-node</code> on Windows</h2>

<p>The efforts to migrate <code class="language-plaintext highlighter-rouge">radicle-node</code> to use <code class="language-plaintext highlighter-rouge">mio</code>, alongside changes that fixed
path canonicalization and supporting Windows pipes, have allowed developers to
build <code class="language-plaintext highlighter-rouge">radicle-node</code> on Windows.</p>

<p>We encourage users to try out Radicle on Windows by building from source. At the
time of writing, there may be undiscovered issues, since this is a nascent time
for <code class="language-plaintext highlighter-rouge">radicle-node</code> on Windows. Please report any issues you see via <code class="language-plaintext highlighter-rouge">rad issue</code>
or on our <a href="https://radicle.zulipchat.com">Zulip</a>.</p>

<h2 id="rust-msrv-update-to-185">Rust MSRV Update to 1.85</h2>

<p>For those who are developing on top of the <code class="language-plaintext highlighter-rouge">heartwood</code> crates, it is important
to note that the Minimum Supported Rust Version (MSRV) is now 1.85.</p>

<h2 id="argument-parsing-via-clap">Argument Parsing via <code class="language-plaintext highlighter-rouge">clap</code></h2>

<p><code class="language-plaintext highlighter-rouge">rad</code> now uses the <code class="language-plaintext highlighter-rouge">clap</code> crate for parsing its command-line arguments. This
brings a brand new look to the help output for the <code class="language-plaintext highlighter-rouge">rad</code> CLI, and ensures that
we do not miss documenting options when they are added. Note that this does
affect error reporting, as they are now reported by <code class="language-plaintext highlighter-rouge">clap</code> when parsing fails.</p>

<h3 id="shell-completions">Shell Completions</h3>

<p>With the introduction of <code class="language-plaintext highlighter-rouge">clap</code>, this helped with the introduction of a command
<code class="language-plaintext highlighter-rouge">rad completion</code> to emit shell completions for static information.</p>

<h2 id="systemd-credentials-for-radicle-node">systemd Credentials for <code class="language-plaintext highlighter-rouge">radicle-node</code></h2>

<p><code class="language-plaintext highlighter-rouge">radicle-node</code> now supports systemd Credentials (refer to
<a href="https://systemd.io/CREDENTIALS">https://systemd.io/CREDENTIALS</a> for more information) to load:
    1. The secret key, in addition to the commandline argument <code class="language-plaintext highlighter-rouge">--secret</code>
       (higher priority than the credential) and the configuration file (lower
       priority than the credential). The identifier of the credential is
       “xyz.radicle.node.secret”.
    2. The optional passphrase for the secret key, in addition to the
       environment variable <code class="language-plaintext highlighter-rouge">RAD_PASSPHRASE</code> (lower priority than the
       credential). The identifier of the credential is
       “xyz.radicle.node.passphrase”.</p>

<h2 id="fix-bootstrapping">Fix Bootstrapping</h2>

<p>The IP (both IPv4 and IPv6) and the Tor onion addresses were specified for the
bootstrap nodes. When a new user came to using Radicle, there was a chance that
their setup did not support IPv6 or Tor, resulting in a failure to connect to
one of those addresses. The node does not know how to try a follow-up address,
for the moment, so we have decided to skip Tor addresses when it is not
configured, and removed the IP addresses in favor of the DNS names.</p>

<h2 id="changelog">Changelog</h2>

<p>This release contains 153 commit(s) by 12 contributor(s).</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">4a5a51e6e</code> <strong>node: Do not mix monotonic and system time</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">58305cda3</code> <strong>protocol/limiter: impl AsTokens for limits</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c675683da</code> <strong>protocol: IntoIterator for BoundedVec</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">37d4ae4a9</code> <strong>radicle/node: Revisit routeability of IP addresses</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f9a62e7d8</code> <strong>radicle/node: <code class="language-plaintext highlighter-rouge">Address::is_local</code> for DNS names</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">dc624ed51</code> <strong>radicle/node/bootstrap: Remove IP addresses</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">45abb881a</code> <strong>node: Only consider onion addresses if configured</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">93d2ed8c6</code> <strong>cli/completion: Static shell completion for <code class="language-plaintext highlighter-rouge">rad</code></strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">7e5a1abab</code> <strong>radicle: Skip invalid named folders</strong> <em><a href="mailto:me@sebastinez.dev">me@sebastinez.dev</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0c70e1712</code> <strong>remote-helper: inform the user of an empty patch</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">28c8c1531</code> <strong>cli/sync: filter seeds without an address</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0ec084fc2</code> <strong>remote-helper: Support push –force-with-lease</strong> <em><a href="mailto:mail@defelo.de">mail@defelo.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">6d0c571ea</code> <strong>radicle: Return individual results for repo in <code class="language-plaintext highlighter-rouge">repositories_by_id</code></strong> <em><a href="mailto:me@sebastinez.dev">me@sebastinez.dev</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c268e809e</code> <strong>chore: Fix mistakes discovered by typos</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">11cbc2e51</code> <strong>hooks: Run “pre-push” by default</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">7ccdd4c81</code> <strong>ci: Activate all features when building docs</strong> <em><a href="mailto:erik@zirkular.io">erik@zirkular.io</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">32d77641a</code> <strong>chore: Fix spelling errors with codespell</strong> <em><a href="mailto:debian@onerussian.com">debian@onerussian.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f7e57361d</code> <strong>hooks: Add codespell</strong> <em><a href="mailto:debian@onerussian.com">debian@onerussian.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8e331ce18</code> <strong>node/reactor/transport: Implement <code class="language-plaintext highlighter-rouge">Debug</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">bc1d9ed49</code> <strong>cli: remove lexopt dependency</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">83f26abaa</code> <strong>cli/main: refactor external command</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f60922d12</code> <strong>cli/terminal: make args module private</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">961301f64</code> <strong>cli/terminal: clean up args::Error type</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a75db6a69</code> <strong>cli/terminal: remove argument helpers</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">fec8a27a3</code> <strong>cli/terminal: remove Help struct</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">e35943504</code> <strong>cli/main: move run_command_fn to main</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">7533db62f</code> <strong>cli/terminal: remove unused parameter</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">1f80eb61e</code> <strong>cli/terminal: remove unused trait</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d41ac5982</code> <strong>cli/help: remove the help module</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">23332fa31</code> <strong>cli/main: migrate main to use clap</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">5053a1aa7</code> <strong>cli/unseed: rename options to args</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">6ca129235</code> <strong>cli/unfollow: rename options to args</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">3c8952500</code> <strong>cli/sync: migrate to clap</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d1e19a87b</code> <strong>cli/patch: migrate patch CLI parsing to clap</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">3ea61f0f9</code> <strong>cli/patch: move comment actions</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">e404f1038</code> <strong>node: Use <code class="language-plaintext highlighter-rouge">std::time</code> for reactor and wire</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9bcdd353c</code> <strong>cli/inbox: Use clap</strong> <em><a href="mailto:me@sebastinez.dev">me@sebastinez.dev</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">5741bafa3</code> <strong>radicle/cob/db: Add index for issues and patches</strong> <em><a href="mailto:johannes.kuehlewindt@gmail.com">johannes.kuehlewindt@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">990e22acf</code> <strong>cli/inspect: use Clap</strong> <em><a href="mailto:richard@levitte.org">richard@levitte.org</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">5ed1b8e57</code> <strong>node: Fix test ‘test_concurrent_fetches’</strong> <em><a href="mailto:adrian.duke@gmail.com">adrian.duke@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">e8f9d21be</code> <strong>cli/node: Use clap</strong> <em><a href="mailto:erik@zirkular.io">erik@zirkular.io</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f20c2f215</code> <strong>node: Re-export <code class="language-plaintext highlighter-rouge">PeerAddrParseError</code></strong> <em><a href="mailto:erik@zirkular.io">erik@zirkular.io</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">6cfed884b</code> <strong>cli/remote: migrate to clap</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">93578340d</code> <strong>Add changelog for Radicle 1.4.0</strong> <em><a href="mailto:erik@zirkular.io">erik@zirkular.io</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f8fe296ce</code> <strong>radicle/rad: Fix typo</strong> <em><a href="mailto:me@sebastinez.dev">me@sebastinez.dev</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8604d3bcc</code> <strong>cli/config: Use clap</strong> <em><a href="mailto:me@sebastinez.dev">me@sebastinez.dev</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8d90699c3</code> <strong>cli/cob: Use clap</strong> <em><a href="mailto:erik@zirkular.io">erik@zirkular.io</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">38ca038a0</code> <strong>cli: fix test regression in 27a85987c31ed3002369dfdc434a74797d07d56d</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c1d9f0496</code> <strong>cli/self: Use clap</strong> <em><a href="mailto:me@sebastinez.dev">me@sebastinez.dev</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">27a85987c</code> <strong>cli: Fix argument value names in <code class="language-plaintext highlighter-rouge">auth</code> and <code class="language-plaintext highlighter-rouge">init</code></strong> <em><a href="mailto:erik@zirkular.io">erik@zirkular.io</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">44efdc02f</code> <strong>flake: Fix source filtering</strong> <em><a href="mailto:lorenz@leutgeb.xyz">lorenz@leutgeb.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">b3f23594d</code> <strong>git: Ignore parent from blame</strong> <em><a href="mailto:lorenz@leutgeb.xyz">lorenz@leutgeb.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">b0beef439</code> <strong>workspace/rust/clippy: Fix all warnings</strong> <em><a href="mailto:lorenz@leutgeb.xyz">lorenz@leutgeb.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">e1b406535</code> <strong>workspace/rust: 1.88 → 1.90</strong> <em><a href="mailto:lorenz@leutgeb.xyz">lorenz@leutgeb.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0dd2f3f40</code> <strong>workspace/rust/msrv: 1.81 → 1.85</strong> <em><a href="mailto:lorenz@leutgeb.xyz">lorenz@leutgeb.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">407abc6a2</code> <strong>cli/follow: Use clap</strong> <em><a href="mailto:erik@zirkular.io">erik@zirkular.io</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">deaf77e5b</code> <strong>cli/unfollow: Use common DID / NID argument parser</strong> <em><a href="mailto:erik@zirkular.io">erik@zirkular.io</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">e488ddb44</code> <strong>cli: Add common value parser for NID / DID</strong> <em><a href="mailto:erik@zirkular.io">erik@zirkular.io</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">06e22434e</code> <strong>cli/checkout: use Clap</strong> <em><a href="mailto:richard@levitte.org">richard@levitte.org</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">28824a312</code> <strong>cli/init: Fix argument value names</strong> <em><a href="mailto:erik@zirkular.io">erik@zirkular.io</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">634866889</code> <strong>cli/id: Use clap</strong> <em><a href="mailto:erik@zirkular.io">erik@zirkular.io</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d3ed4bb49</code> <strong>radicle/id: Introduce <code class="language-plaintext highlighter-rouge">PayloadUpsert</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ec1d75430</code> <strong>cli/unblock: Use clap</strong> <em><a href="mailto:erik@zirkular.io">erik@zirkular.io</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">faf19af9d</code> <strong>cli: Share common argument types used in <code class="language-plaintext highlighter-rouge">(un)block</code></strong> <em><a href="mailto:erik@zirkular.io">erik@zirkular.io</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">cef0ff571</code> <strong>oid: use <code class="language-plaintext highlighter-rouge">std::hash::Hasher::hash</code> over <code class="language-plaintext highlighter-rouge">Hasher::write</code></strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d9ae29dea</code> <strong>cli/seed: Use clap</strong> <em><a href="mailto:erik@zirkular.io">erik@zirkular.io</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">80198d68b</code> <strong>cli: Share value parser for <code class="language-plaintext highlighter-rouge">Scope</code></strong> <em><a href="mailto:erik@zirkular.io">erik@zirkular.io</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">b7a7f55e7</code> <strong>gix: CVE-2025-31130</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0b3424857</code> <strong>node/reactor: Correctly handle error events</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">72cf3d191</code> <strong>cli/diff: Use clap</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">532e5a0de</code> <strong>build: Use <code class="language-plaintext highlighter-rouge">git describe</code> to generate a version</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">384c50648</code> <strong>cli/auth: use Clap</strong> <em><a href="mailto:richard@levitte.org">richard@levitte.org</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">dfd35480b</code> <strong>cli/watch: Use clap</strong> <em><a href="mailto:erik@zirkular.io">erik@zirkular.io</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">efe10f95b</code> <strong>workspace: Enable vendored <code class="language-plaintext highlighter-rouge">libgit2</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">b7cfcfff7</code> <strong>workspace: A Little Less <code class="language-plaintext highlighter-rouge">git2</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f4a890872</code> <strong>git-metadata: New crate extract from <code class="language-plaintext highlighter-rouge">radicle-git</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">793f53b5f</code> <strong>oid: New crate</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">3fcf2a86d</code> <strong>git-ref-format: New crate</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">292befdb3</code> <strong>radicle: Add <code class="language-plaintext highlighter-rouge">tempfile</code> to dev-dependencies</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">3e98589a7</code> <strong>github/build: Fix runner names</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">84dd89180</code> <strong>radicle: Fix required features for <code class="language-plaintext highlighter-rouge">fastrand</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f232acda7</code> <strong>cli/diff: Print cross-platform line endings</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d8ab40777</code> <strong>radicle/storage: Fix temporary path generation</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">013da67aa</code> <strong>cli/test: Skip <code class="language-plaintext highlighter-rouge">rad_diff</code> on macOS</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f7af91819</code> <strong>cli/test: Fix <code class="language-plaintext highlighter-rouge">rad_patch_delete</code> for macOS</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">7d6d2e51d</code> <strong>cli/test: Clean up testing environment</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">3780f908a</code> <strong>radicle/identity: Stabilize tests</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">60798cdbc</code> <strong>radicle/profile: Canonicalize during test</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">86b7ef23c</code> <strong>radicle/git/raw: Limit scope of <code class="language-plaintext highlighter-rouge">RemoteCallbacks</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">191c28795</code> <strong>cli/ls: use Clap</strong> <em><a href="mailto:richard@levitte.org">richard@levitte.org</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8ba3087cb</code> <strong>cli/init: use Clap</strong> <em><a href="mailto:richard@levitte.org">richard@levitte.org</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">10e7b94c3</code> <strong>workspace: Add <code class="language-plaintext highlighter-rouge">.rustfmt</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ea562215e</code> <strong>radicle/git/raw: Introduce <code class="language-plaintext highlighter-rouge">trait ErrorExt</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">837f4694d</code> <strong>hook: Add check for <code class="language-plaintext highlighter-rouge">git2</code> in <code class="language-plaintext highlighter-rouge">radicle</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">880634acd</code> <strong>radicle/git/raw: Capture all <code class="language-plaintext highlighter-rouge">git2</code> re-exports</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">633059040</code> <strong>node/wire: Refactor precedence</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">cb7bed556</code> <strong>node: Remove dependency on amplify</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">3c3d81a08</code> <strong>node: Use Mio</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">b25d80d27</code> <strong>crypto: Depend on <code class="language-plaintext highlighter-rouge">git-ref-format-core</code> only</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ac572e64e</code> <strong>node: Support systemd credential for passphrase</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ae39f24b5</code> <strong>node: Support systemd credential for secret</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0c513e981</code> <strong>systemd: Support Credentials</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8c1073b9c</code> <strong>cli/publish: Use clap</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">7effa7c64</code> <strong>node: Report sync status for given namespaces</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9689de9af</code> <strong>node: Allow announcing refs for given public keys</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">4dbb022d2</code> <strong>radicle/node: Create submodule “command”</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8e7d19320</code> <strong>radicle: Update <code class="language-plaintext highlighter-rouge">CHANGELOG.md</code> for next iteration</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">7b8da0e72</code> <strong>cli/fork: Use clap</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">3992d519c</code> <strong>cli/clone: Use clap</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">7c89045ea</code> <strong>cli/debug: Use clap</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">2e77d5ef4</code> <strong>cli/block: Improve example values for target argument</strong> <em><a href="mailto:erik@zirkular.io">erik@zirkular.io</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">6d698bb79</code> <strong>cli/block: Use clap</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ed5a68c1d</code> <strong>node: mark modules as private</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">59e09078b</code> <strong>radicle: mark <code class="language-plaintext highlighter-rouge">CheckoutError</code> as <code class="language-plaintext highlighter-rouge">non_exhaustive</code></strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">5b260964c</code> <strong>crypto: mark errors as <code class="language-plaintext highlighter-rouge">non_exhaustive</code></strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">30908dcf4</code> <strong>radicle/git/canonical: Actually use qualified refs</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ee041d8d0</code> <strong>crates: bump for release</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">2149770a4</code> <strong>storage: Rewrite temporary repositories for clones</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">31a7d3bd3</code> <strong>fetch: add <code class="language-plaintext highlighter-rouge">Handle::into_inner</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">e40fe86ff</code> <strong>fetch: use <code class="language-plaintext highlighter-rouge">AsRef&lt;Repository&gt;</code></strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a163f4e93</code> <strong>fetch: refactor repository access</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">5caa7b302</code> <strong>remote-helper: Check base when matching revisions</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9bb136105</code> <strong>remote-helper: Only update patch after evaluating base</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">5cd016b58</code> <strong>radicle-systemd: Guard <code class="language-plaintext highlighter-rouge">mod listen</code> for Unix</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0095fdc58</code> <strong>flake: Keep <code class="language-plaintext highlighter-rouge">crates/**/*.txt</code> files for build</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9954a7949</code> <strong>flake: Add binary cache configuration</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9c8ab7fa6</code> <strong>fetch: Rewrite <code class="language-plaintext highlighter-rouge">git::repository::direct</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d9ce078d5</code> <strong>protocol: Decrease log-level for logging ping/pong</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">474b97950</code> <strong>node/log: Define syslog identifier</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ee49e2876</code> <strong>cli/unfollow: Use clap</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">6fb1ebec4</code> <strong>cli/clean: Use clap</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">753b7aef9</code> <strong>cli/path: Use clap</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">4787b53b1</code> <strong>CHANGELOG: Radicle 1.5.0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8bc578bfa</code> <strong>build/release: missed updating the symlink</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">01f9f3fcd</code> <strong>cli/unseed: Use clap</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">80bc95269</code> <strong>cli/stats: Use clap</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f1c7c9860</code> <strong>cli/issue: Move definition of “about” to args</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c7bff2845</code> <strong>cli/issue: Use clap</strong> <em><a href="mailto:me@icetan.org">me@icetan.org</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">675a0f81d</code> <strong>cli: Depend on clap</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">5a958b5eb</code> <strong>cli/test: Output of <code class="language-plaintext highlighter-rouge">rad --help</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">22720e718</code> <strong>node: Make location of secret key configurable</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">5887edf93</code> <strong>crypto/ssh/keystore: Explicit paths</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9e1d6b1fe</code> <strong>radicle: Detect current repository using <code class="language-plaintext highlighter-rouge">jj</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">abc963f2f</code> <strong>radicle-cli/tests: Add <code class="language-plaintext highlighter-rouge">rad_jj_patch</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">731688d3f</code> <strong>flake: Install Jujutsu for testing</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">fd5043d57</code> <strong>radicle-cli-test: Prepare testing with <code class="language-plaintext highlighter-rouge">jj</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">53522288c</code> <strong>radicle-cli/tests: <code class="language-plaintext highlighter-rouge">fn program_reports_version</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">fafb3493d</code> <strong>cli: Detect key mismatch</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ed8b08604</code> <strong>node: Log Panics</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0441b048f</code> <strong>cli: Don’t add newlines for empty descriptions in editor</strong> <em><a href="mailto:mail@defelo.de">mail@defelo.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ae01a4243</code> <strong>radicle: Allow to clear issue descriptions and comments</strong> <em><a href="mailto:mail@defelo.de">mail@defelo.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ec22c9432</code> <strong>cli/issue: Show previous title in <code class="language-plaintext highlighter-rouge">rad issue edit</code> editor</strong> <em><a href="mailto:mail@defelo.de">mail@defelo.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9f62a82b0</code> <strong>radicle: Fix <code class="language-plaintext highlighter-rouge">cob::common::Title::new</code></strong> <em><a href="mailto:mail@defelo.de">mail@defelo.de</a></em></li>
</ul>

<h2 id="checksums">Checksums</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ec54696394ec8cdb6e7046882de1fd242259db260b53204b74a4a20a0437bcd0  radicle-1.6.0-x86_64-apple-darwin.tar.xz
906d7906f4346ed6c7c6069a5a44254da2aad43ec71b02e3c2d71d73ac0d503e  radicle-1.6.0-aarch64-apple-darwin.tar.xz
d390cabc3d06502580ce0140863d6315890525f9976446d8c1c252809a3c21b8  radicle-1.6.0-x86_64-unknown-linux-musl.tar.xz
8bc5f8fad9dfa0b038903ff961e313fe806450680e94e7228b12668ac95bf5ea  radicle-1.6.0-aarch64-unknown-linux-musl.tar.xz
</code></pre></div></div>]]></content><author><name></name></author><summary type="html"><![CDATA[Happy new year!]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://radicle.dev/https://radicle-website.liw.fi/radicle-1.png" /><media:content medium="image" url="https://radicle.dev/https://radicle-website.liw.fi/radicle-1.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Radicle 1.5.0 – Hibiscus 🌺</title><link href="https://radicle.dev/https://radicle-website.liw.fi/2025/09/30/radicle-1.5.0.html" rel="alternate" type="text/html" title="Radicle 1.5.0 – Hibiscus 🌺" /><published>2025-09-30T00:00:00+03:00</published><updated>2025-09-30T00:00:00+03:00</updated><id>https://radicle.dev/https://radicle-website.liw.fi/2025/09/30/radicle-1.5.0</id><content type="html" xml:base="https://radicle.dev/https://radicle-website.liw.fi/2025/09/30/radicle-1.5.0.html"><![CDATA[<p>The Radicle team is delighted to announce the release of Radicle 1.5.0 (5fea9ac0), code name <em>Hibiscus</em>.
The Hibiscus flower tends to bloom from late spring through autumn, and can be made into a nice warming tea.
So grab your cup and take a seat, while we walk through this 1.5.0 release.</p>

<p>This release consists of 74 commits from 7 contributors.
Thanks to the following contributors for their effort in making Radicle better:</p>
<ul>
  <li>yorgos</li>
  <li>defelo</li>
  <li>Sebastian</li>
  <li>Matthias</li>
</ul>

<h2 id="installation">Installation</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl -sSLf https://radicle.dev/install | sh -s -- --no-modify-path --version=1.5.0
</code></pre></div></div>

<h2 id="better-support-for-bare-repositories">Better Support for Bare Repositories</h2>

<p>Some improvements to supporting bare repositories have been made for <code class="language-plaintext highlighter-rouge">rad</code> and
<code class="language-plaintext highlighter-rouge">git-remote-rad</code>. For <code class="language-plaintext highlighter-rouge">rad</code>, the <code class="language-plaintext highlighter-rouge">rad clone</code> command has learned a new flag
<code class="language-plaintext highlighter-rouge">--bare</code>, which clones the repository into a bare repository, as opposed to
having a working tree (see <a href="https://git-scm.com/docs/gitrepository-layout/2.49.0">gitrepository-layout</a>).</p>

<p><code class="language-plaintext highlighter-rouge">git-remote-rad</code> (our Git remote helper), also learned to better handle bare
repositories, when using <code class="language-plaintext highlighter-rouge">git push</code> and <code class="language-plaintext highlighter-rouge">git fetch</code> with a <code class="language-plaintext highlighter-rouge">rad://</code> remote.</p>

<p>For <code class="language-plaintext highlighter-rouge">jj</code> users, this begins to unlock being able to use <code class="language-plaintext highlighter-rouge">jj</code> without co-location
of the Git repository. Further improvements to interoperability with <code class="language-plaintext highlighter-rouge">jj</code> are
in progress and will be released in future versions.</p>

<h2 id="introducing-the-patchbranch-option">Introducing the <code class="language-plaintext highlighter-rouge">patch.branch</code> Option</h2>

<p>Continuing on the theme of making <code class="language-plaintext highlighter-rouge">jj</code> users happy, <code class="language-plaintext highlighter-rouge">git-remote-rad</code> can now
handle the option <code class="language-plaintext highlighter-rouge">-o patch.branch[=&lt;name&gt;]</code>. When the option is passed without
a name, i.e. <code class="language-plaintext highlighter-rouge">-o patch.branch</code>, an upstream branch will be created which is
named after the patch being created – <code class="language-plaintext highlighter-rouge">patches/&lt;PATCH ID&gt;</code>. Alternatively, the
<code class="language-plaintext highlighter-rouge">&lt;name&gt;</code> value is used if supplied.</p>

<p>This allows you to specify if you want a tracking branch (or bookmark in <code class="language-plaintext highlighter-rouge">jj</code>)
for the patch. This means that you can avoid using <code class="language-plaintext highlighter-rouge">rad patch checkout</code>.</p>

<h2 id="improved-rad-patch-show">Improved <code class="language-plaintext highlighter-rouge">rad patch show</code></h2>

<p>The <code class="language-plaintext highlighter-rouge">rad patch show</code> command has received some love by improving its output. The
<code class="language-plaintext highlighter-rouge">Base</code> of the patch is now always output, where before it was behind the
<code class="language-plaintext highlighter-rouge">--verbose</code> flag.</p>

<p>The previous output would differentiate “updates”, where the original author
creates a new revision, and “revisions”, where another author creates a
revision. This could be confusing since updates are also revisions. Instead, the
output shows a timeline of the root of the patch and each new revision, without
any differentiation. The revision identifiers, head commit of the revision, and
author are still printed as per usual.</p>

<h2 id="structured-logging">Structured Logging</h2>

<p>The <code class="language-plaintext highlighter-rouge">radicle-node</code> has learned to output structure logging using the new
<code class="language-plaintext highlighter-rouge">--log-logger structured</code> and <code class="language-plaintext highlighter-rouge">--log-format json</code> option pairs. If they are not
specified, then the logging will remain the same as per usual.</p>

<h2 id="deprecations-in-rad">Deprecations in <code class="language-plaintext highlighter-rouge">rad</code></h2>

<p>It is important to note that we are now emitting deprecation and obsoletion
warnings for several <code class="language-plaintext highlighter-rouge">rad</code> commands and options.</p>

<p>For <code class="language-plaintext highlighter-rouge">rad diff</code>, the whole command is deprecated, and <code class="language-plaintext highlighter-rouge">git diff</code> should be used
instead. It is better to use the tools that already exist in this case.</p>

<p>The option <code class="language-plaintext highlighter-rouge">rad self --nid</code> was deprecated in favor of <code class="language-plaintext highlighter-rouge">rad node status --only nid</code>.
The reason for this is that we will be making efforts to separate the cryptographic
identity of user and node.
For this case, the node will – in a future version – read the location of the
secret key to use from configuration or arguments at runtime. This means that a
running node is required to report the correct Node ID – and the command cannot
rely on the default location, which is shared with the user.</p>

<p>The options <code class="language-plaintext highlighter-rouge">rad patch review [--patch | --delete]</code> are marked as obsolete,
since their functionality never worked as intended. Reviews are something that
requires more research and time to implement. These commands will likely be
removed before a next major release, since their lack of functionality is
confusing.</p>

<h2 id="changelog">Changelog</h2>

<p>This release contains 74 commit(s) by 7 contributor(s).</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">5fea9ac05</code> <strong>node: Add <code class="language-plaintext highlighter-rouge">--log-logger structured</code> and <code class="language-plaintext highlighter-rouge">--log-format json</code></strong> <em><a href="mailto:me@sebastinez.dev">me@sebastinez.dev</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">e56311739</code> <strong>node: Refactor logging initialization</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9793b4e7b</code> <strong>systemd: Require Linux for journal module</strong> <em><a href="mailto:yorgos.work@proton.me">yorgos.work@proton.me</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">e70850cb3</code> <strong>remote-helper: Add patch.branch option</strong> <em><a href="mailto:mail@defelo.de">mail@defelo.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">6a43e83dd</code> <strong>Release 1.3.1</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">7b00bf2e3</code> <strong>cli/patch/review: Obsoletion Warning</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8dd17e2a6</code> <strong>cli/warning: Add <code class="language-plaintext highlighter-rouge">fn obsolete</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">7d1db6a01</code> <strong>cli/diff: Deprecation Warning</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8558cc223</code> <strong>cli/self: <code class="language-plaintext highlighter-rouge">--nid</code> deprecation warning to stderr</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">3fb04623a</code> <strong>cli/warning: Add <code class="language-plaintext highlighter-rouge">fn deprecate</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">2635562c9</code> <strong>cli/node/status: Add <code class="language-plaintext highlighter-rouge">--only nid</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8afd55ff6</code> <strong>build: update release files location</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d2e10fdef</code> <strong>cli/tests/commands: Clean up test <code class="language-plaintext highlighter-rouge">rad_patch</code></strong> <em><a href="mailto:erik@zirkular.io">erik@zirkular.io</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">19210faab</code> <strong>protocol/service: Change <code class="language-plaintext highlighter-rouge">Routing table updated..</code> from info to debug</strong> <em><a href="mailto:me@sebastinez.dev">me@sebastinez.dev</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">86472fdcc</code> <strong>remote-helper/fetch: Improve error handling</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f542df183</code> <strong>radicle: Use <code class="language-plaintext highlighter-rouge">git fetch-pack</code> for “local fetch”</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">20663a4e3</code> <strong>remote-helper: Use <code class="language-plaintext highlighter-rouge">git send-pack</code> for “internal push”</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f9ff484c9</code> <strong>cli: Make <code class="language-plaintext highlighter-rouge">rad patch show</code> prettier</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">43246fe6c</code> <strong>remote-helper: Parse base revision early</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ef2796186</code> <strong>remote-helper: List <code class="language-plaintext highlighter-rouge">HEAD</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">101fbff80</code> <strong>ci: Deny <code class="language-plaintext highlighter-rouge">cargo doc</code> warnings</strong> <em><a href="mailto:erik@zirkular.io">erik@zirkular.io</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">14fcf5067</code> <strong>docs: fix doc string linking</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ee9e6de5f</code> <strong>remote-helper: Do not assume remote name</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">6b9ff4f99</code> <strong>cli/init: Allow <code class="language-plaintext highlighter-rouge">--setup-signing</code> with bare repos</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">fd93240b9</code> <strong>cli/git: Remove dead code <code class="language-plaintext highlighter-rouge">fn view_diff</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">86ea33b0c</code> <strong>cli/clone: Add flag <code class="language-plaintext highlighter-rouge">--bare</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">766e281d3</code> <strong>radicle: Allow creating bare clones</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">e528c40a0</code> <strong>radicle-cli: Test initializing from bare repos</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">606882f01</code> <strong>remote-helper: Simplify handling of <code class="language-plaintext highlighter-rouge">GIT_DIR</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">354565c57</code> <strong>radicle: Handle <code class="language-plaintext highlighter-rouge">GIT_DIR</code> more uniformly</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">4e6746796</code> <strong>remote-helper: Refactor option handling</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">876d22b07</code> <strong>remote-helper: Remove unused push error variant</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">550fcccc2</code> <strong>remote-helper: Do not hard-code binary name</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">897404164</code> <strong>remote-helper: Make crate binary-only</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">66adbffd6</code> <strong>term: Use static template in spinner initialization</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8fc37e331</code> <strong>term: Move to indicatif spinner</strong> <em><a href="mailto:erik@zirkular.io">erik@zirkular.io</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ee9ecfda7</code> <strong>remote-helper: Remove <code class="language-plaintext highlighter-rouge">SyncWriter</code> in favor of <code class="language-plaintext highlighter-rouge">PaintTarget</code></strong> <em><a href="mailto:erik@zirkular.io">erik@zirkular.io</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">153a8f9fb</code> <strong>node: Remove <code class="language-plaintext highlighter-rouge">SyncWriter</code> in favor of <code class="language-plaintext highlighter-rouge">PaintTarget</code></strong> <em><a href="mailto:erik@zirkular.io">erik@zirkular.io</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">11a109ef4</code> <strong>term: Introduce <code class="language-plaintext highlighter-rouge">PaintTarget</code></strong> <em><a href="mailto:erik@zirkular.io">erik@zirkular.io</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">379037956</code> <strong>remote-helper: Prevent doubly verifying each push</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a0f6cbf5f</code> <strong>radicle: Move interpretation of output to binary</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0a8317c35</code> <strong>remote-helper: Interpret verbosity option</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">11e8b89b2</code> <strong>radicle/src/git: additionally specify pruneTags for remote</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">646d4360e</code> <strong>cli/node: Replace manual pushing with Table::extend()</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">2f2823267</code> <strong>cli/issue: Replace manual pushing with Table::extend()</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8554e996b</code> <strong>cli/diff: Replace manual pushing with Table::extend()</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">fbef60eed</code> <strong>cli/sync: Replace manual pushing with Table::extend()</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">370ae3643</code> <strong>cli/patch: Replace manual iterator partitioning with Itertools::partition_result()</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">3f489354b</code> <strong>cli: Add itertools dependency</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9c2f97abe</code> <strong>cli/remote: Replace manual building table from iterator</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">4bd45cdab</code> <strong>cli/inbox: Replace manual building table from iterator</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">016cab1db</code> <strong>term/table: Add Table::with_opts() to set options after Table obj was constructed</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">fb458537b</code> <strong>cli/patch: Replace manual building table from iterator</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">41a742ed9</code> <strong>term/table: Add impl FromIterator for Table</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ff021d588</code> <strong>cli: Rewrite <code class="language-plaintext highlighter-rouge">#[path="…"]</code> module declarations</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">11fc98c9c</code> <strong>term: Replace manual Extend impl for Table</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f00d1d674</code> <strong>cli/self: Stop printing information about the node</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">e1af550a0</code> <strong>cli/node: Print Node ID</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9b7529baa</code> <strong>hooks: Filter for “radicle.{xyz,zulipchat.com}”</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">b301fa6a0</code> <strong>doc: Mention handling of “radicle.xyz”</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">79505fa90</code> <strong>radicle/test/fixtures: Use “radicle.xyz” as <code class="language-plaintext highlighter-rouge">const</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">1a3fda547</code> <strong>radicle/explorer: Allow overriding default URL</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">e2c476a38</code> <strong>radicle/test: Don’t hard-code “radicle.xyz”</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">2127782b7</code> <strong>term: Remove dependency on <code class="language-plaintext highlighter-rouge">anyhow</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">edd88a59b</code> <strong>term: Remove <code class="language-plaintext highlighter-rouge">mod command</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">79d928551</code> <strong>node: Remove dependency on <code class="language-plaintext highlighter-rouge">anyhow</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">4bf3ab6fb</code> <strong>github/actions: Add a workflow to build</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">55cdd880b</code> <strong>radicle-term: Pass in <code class="language-plaintext highlighter-rouge">mut self</code> rather than rebinding</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">19c484e95</code> <strong>radicle-term: Optimize impl of VStack::children()</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">93388e366</code> <strong>radicle-term: Preallocate in Line::spaced()</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">3036509e4</code> <strong>radicle-term: Add testcase for Line::spaced()</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">23b9d3063</code> <strong>radicle: Remove unnecessary clone()</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">29a95fb1a</code> <strong>radicle-fetch: Replace manual std::matches!() impl</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ded0d19d5</code> <strong>protocol/wire/test: Define <code class="language-plaintext highlighter-rouge">fn roundtrip</code> and macro</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
</ul>

<h2 id="checksums">Checksums</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>d94e3b65d2585c7f7b5e31a5d55af8a7ff156cd4c45a7b728501e6f54353600e  radicle-1.5.0-aarch64-apple-darwin.tar.xz
4c27f2428873d99532337991f977255aa4023beedd6d53178ce3abdc529df8dc  radicle-1.5.0-aarch64-unknown-linux-musl.tar.xz
57523bc4ff575f2cdf94df3f4e3bf814cc46f2fd497fcfdd885e9bcdd7d4fb26  radicle-1.5.0-x86_64-apple-darwin.tar.xz
9c9277df40c0f144e0b5bcde9cfe2e81c0f8a1ee4f2cb9313ef942ab0c811022  radicle-1.5.0-x86_64-unknown-linux-musl.tar.xz
</code></pre></div></div>]]></content><author><name></name></author><summary type="html"><![CDATA[The Radicle team is delighted to announce the release of Radicle 1.5.0 (5fea9ac0), code name Hibiscus. The Hibiscus flower tends to bloom from late spring through autumn, and can be made into a nice warming tea. So grab your cup and take a seat, while we walk through this 1.5.0 release.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://radicle.dev/https://radicle-website.liw.fi/radicle-1.png" /><media:content medium="image" url="https://radicle.dev/https://radicle-website.liw.fi/radicle-1.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Radicle 1.4.0 – Lily</title><link href="https://radicle.dev/https://radicle-website.liw.fi/2025/09/04/radicle-1.4.0.html" rel="alternate" type="text/html" title="Radicle 1.4.0 – Lily" /><published>2025-09-04T00:00:00+03:00</published><updated>2025-09-04T00:00:00+03:00</updated><id>https://radicle.dev/https://radicle-website.liw.fi/2025/09/04/radicle-1.4.0</id><content type="html" xml:base="https://radicle.dev/https://radicle-website.liw.fi/2025/09/04/radicle-1.4.0.html"><![CDATA[<p>The Radicle team is delighted to announce the release of Radicle 1.4.0
(bbd1e2c), code name <em>Lily</em>. Going forward, we want to name our releases after
the abundant flowers and plants of this earth. We chose <em>Lily</em> as the first in
honor of Finland’s national flower, the <em>Lily of the Valley</em>. The team is making
this release from Helsinki 🇫🇮</p>

<p>This release contains 67 commits by 5 contributors. It’s exciting to
see our Zulip community growing and having patches from fresh contributors! 👾</p>

<p>Thanks to the following contributors for providing their time and effort for
this release:</p>
<ul>
  <li>srestegosaurio</li>
  <li>Matthias Beyer</li>
  <li>Sebastian Martinez</li>
</ul>

<h2 id="installation">Installation</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl -sSLf https://radicle.dev/install | sh -s -- --no-modify-path --version=1.4.0
</code></pre></div></div>

<h2 id="canonical-reference-improvements">Canonical Reference Improvements</h2>

<p>The canonical reference calculation was improved internally so that the
developers can better reason about the process. During this, it was noted that
the Radicle storage copy of the repository and the working copy of the
repository were both used during the process. By ensuring that the storage
copy is the only one used, a class of bugs is ruled out. This, however, means
that a <code class="language-plaintext highlighter-rouge">git push</code> will not fail when the pushed commit diverges, but will still
emit a warning that the new commit is diverging away from the other heads. We
weighed this up, and consider it an improvement, since the user is given control
of their own Git history.</p>

<p>Future improvements will provide ways of inspecting and resolving diverging
heads.</p>

<h2 id="fixed-panics">Fixed Panics</h2>

<p>Two instances of panics were fixed in this release.</p>

<p>The first, and most important, was a panic around serializing wire messages.
There is a strict size limit on the protocol messages that we control. However,
this size limit is not intended to be imposed on Git streams, for example during
fetching from other nodes. We incorrectly placed a check for this size limit in
the <code class="language-plaintext highlighter-rouge">serialize</code> function, which meant it would panic for some Git fetches. This
was fixed by moving the check elsewhere, while also improving the code so we do
not make that mistake again.</p>

<p>The second involved using the <code class="language-plaintext highlighter-rouge">read</code> method from the <code class="language-plaintext highlighter-rouge">sqlite</code> crate. This method
calls <code class="language-plaintext highlighter-rouge">try_read</code> and <code class="language-plaintext highlighter-rouge">unwrap</code>s the <code class="language-plaintext highlighter-rouge">Result</code>, which would cause a panic. We have
replaced the calls to <code class="language-plaintext highlighter-rouge">read</code> with <code class="language-plaintext highlighter-rouge">try_read</code> to more gracefully handle the
error.</p>

<h2 id="improvements-towards-windows-compatibility">Improvements Towards Windows Compatibility</h2>

<p>We have continued along the path towards compatibility by fixing some areas that
required some Windows specific handling. These included canonicalization of
paths, and using the correct named pipes location for the control socket.</p>

<h2 id="improved-bootstrapping">Improved Bootstrapping</h2>

<p>Previously, we would use DNS to resolve to the IP address of bootstrap nodes,
which would be used as the bootstrap address. Now, we may also use the IPv4,
IPv6, and Tor addresses directly for bootstrapping.</p>

<h2 id="improvements-to-rad-sync">Improvements to <code class="language-plaintext highlighter-rouge">rad sync</code></h2>

<p>We now use a more suitable symbol in <code class="language-plaintext highlighter-rouge">rad sync status</code> for the status:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✗ Hint:
   ? … Status:
       ✓ … in sync          ✗ … out of sync
       ! … not announced    • … unknown
</code></pre></div></div>

<p>This aligns closer with the <code class="language-plaintext highlighter-rouge">rad node status</code> output. As well as this, the <code class="language-plaintext highlighter-rouge">Tip</code>
column was renamed to <code class="language-plaintext highlighter-rouge">SigRefs</code>, since the term <code class="language-plaintext highlighter-rouge">Tip</code> was too ambiguous.</p>

<p>The internal logic of <code class="language-plaintext highlighter-rouge">rad sync --announce</code> was improved by writing more tests
and finding edge cases to fix. Included in these improvements is changing the
target behavior. Before, the announcements would attempt to reach the preferred
seeds target <em>and</em> the replication factor. Now, it tries to reach the preferred
seeds and falls back to the replication factor.</p>

<h2 id="improvements-to-rad-cob-log">Improvements to <code class="language-plaintext highlighter-rouge">rad cob log</code></h2>

<p>The <code class="language-plaintext highlighter-rouge">rad cob log</code> command learned two new options, <code class="language-plaintext highlighter-rouge">--from</code> and <code class="language-plaintext highlighter-rouge">--to</code>. These
take a commit SHA that correspond to a COB operation, and allows you to limit
the log to start from or end the log at those operations, respectively.</p>

<h2 id="various-improvements">Various Improvements</h2>

<p>We have made the errors that occur in <code class="language-plaintext highlighter-rouge">radicle-fetch</code> more fine-grained so that
we get better error reporting.</p>

<p>Also, thanks to Matthias Beyer for making improvements within our Rust code.
These may not be visible to the user, but they may improve some performance, and
improve the developers lives :)</p>

<h2 id="changelog">Changelog</h2>

<p>This release contains 67 commit(s) by 5 contributor(s).</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">bbd1e2cff</code> <strong>crates: 1.4.0 release</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">de38d9741</code> <strong>build: move to use <code class="language-plaintext highlighter-rouge">releases/</code> prefix</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">819ae5fdf</code> <strong>node/main: Refactor initialization of logging</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">bc4a13902</code> <strong>systemd: Clean up default service configurations</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">25decf161</code> <strong>systemd: Add example service hardening</strong> <em><a href="mailto:lcdt@disroot.org">lcdt@disroot.org</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d7aa2d9da</code> <strong>flake/hooks: Reconfigure Git Hooks</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">7d2f0e387</code> <strong>node: e2e test for canonical ref update</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0d96af5d0</code> <strong>node: update default branch for canonical refs</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c38b9d9e1</code> <strong>node: simplify canonical reference calculation</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a8255a2e0</code> <strong>Introduce a node event for canonical reference updates</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">690f6b02c</code> <strong>remote-helper: remove check for fast-forward</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">119a12489</code> <strong>radicle: the great Canonical rewrite</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8a66e4d04</code> <strong>node/systemd: Check that received sockets are AF_UNIX</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">192cc993a</code> <strong>radicle: Fix panic when reading from SQLite database fails</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a568e7f48</code> <strong>protocol: Refactor decoding</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">cbd2a7070</code> <strong>protocol: Refactor encoding</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a8426dfda</code> <strong>protocol: Fix panic when serializing large frames</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c5b99db10</code> <strong>doc: Oversight when integrating winpipe</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a4d83ec8d</code> <strong>node/control: Please the borrow checker</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">fca96e697</code> <strong>node: Fix test on Windows</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">19a262d3d</code> <strong>node: Use winpipe for control socket on Windows</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ce11f03fe</code> <strong>radicle/profile: Control socket path for Windows</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">fd34b680b</code> <strong>signals: Guard most of the crate for Unix</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">5229fb8a5</code> <strong>fix: Normalize filesystem paths with <code class="language-plaintext highlighter-rouge">dunce</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">31039bbce</code> <strong>radicle-fetch: More fine-grained errors</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d2517c500</code> <strong>radicle-fetch: Fallback to known version</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a670b6e66</code> <strong>radicle: fix stream tests</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0c6ff06c6</code> <strong>radicle: use repository fixture in cob stream tests</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">1d7478cd9</code> <strong>radicle: introduce <code class="language-plaintext highlighter-rouge">cob::common::Title</code></strong> <em><a href="mailto:me@sebastinez.dev">me@sebastinez.dev</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">2a0f6fd3c</code> <strong>cli: extend <code class="language-plaintext highlighter-rouge">rad cob log</code> behaviour</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">044ff8add</code> <strong>radicle: introduce specialised Stream types</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c0ac228c3</code> <strong>radicle: introduce COB stream</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9b59c0e2c</code> <strong>radicle: add Op::load method</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">dbfcf424d</code> <strong>radicle: add Op::manifest_of</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">bfe8c5234</code> <strong>cob: add method for loading entry manifest</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">86119473b</code> <strong>test: add alphanumeric generator</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8953ec4c8</code> <strong>cli/inbox: Clearify “clear” behaviour</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9a7c22536</code> <strong>radicle/config/node: Use newtypes</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c4ff0d8ea</code> <strong>radicle/config/node: Granular Default Values</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">77f63c76d</code> <strong>Replace unit-returning-closure with drop()</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">cb7c748c6</code> <strong>Move destructuring to fn signature</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9486e751f</code> <strong>Simplify impl of Display for some types</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">787cb3a87</code> <strong>Collapse nested if</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">b0af48aa0</code> <strong>To not allocate in good case</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0200e84ae</code> <strong>bootstrap: Add IPv6, IPv4, Onion addresses</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">6a1b13bb6</code> <strong>cli: Use human-panic</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f6f3be437</code> <strong>cli/issue: Optimize how the issues are collected</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">b49ff9e5a</code> <strong>radicle: Implement Iterator::size_hint() for optimizations</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">1e66c5764</code> <strong>refactor: Replace return Err(anyhow!()) with anyhow::bail!()</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">01bed73a6</code> <strong>cli: fix error formatting</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ed5b2659c</code> <strong>cli: Gracefully handle failure to link log file</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">de78cf787</code> <strong>cli: Add verbose printing of authors</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c8b6a13d6</code> <strong>cli/sync/status: Refactor output table</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c089727e9</code> <strong>term, cli, remote-helper: Status Symbols</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">1cd3ad078</code> <strong>node: Remove useless caching of node announcement</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">efa7efacc</code> <strong>radicle: Announcer test set constructions</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c15288a69</code> <strong>radicle: note about Announcer::can_continue</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">1b33229dd</code> <strong>radicle: test Announcer::timed_out on success</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">11156619b</code> <strong>radicle: Announcer test repeated sync</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ce2d3eb07</code> <strong>radicle: Announcer test synced with unknown node</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ca7231e65</code> <strong>radicle: Announcer test adapting the replication target</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">685c84e59</code> <strong>radicle: Announcer with replication factor of 0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">4307eb35b</code> <strong>radicle: Announcer test AlreadySynced for preferred seeds</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">376a5566c</code> <strong>radicle: Announcer test preferred seeds only</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">84f11f5e3</code> <strong>radicle: Announcer ensures local node is ignored</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8a6e55502</code> <strong>radicle: Announcer can exit on preferred seeds or replication factor</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d14709481</code> <strong>fix: upgrade radicle-crypto</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em>
    <h2 id="checksums">Checksums</h2>
  </li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>82ad1e7f0afbf59bc95b6f9996bb5db570ba3661ce9644c370e8140a2364cdb3  radicle-1.4.0-x86_64-apple-darwin.tar.xz
937ddc7016fa0cbd9ce2449294939dcab6802880109ae58a5f4b7a03ae63d5b9  radicle-1.4.0-x86_64-unknown-linux-musl.tar.xz
6b673bae8d2531c07b3e1df853dbc0396397569aae29f5675b3bb4606306735e  radicle-1.4.0-aarch64-apple-darwin.tar.xz
d51ba8ca3b9277e5d06dcafee2ae04d9a4ad697b6bd57b33e436b559e85820e0  radicle-1.4.0-aarch64-unknown-linux-musl.tar.xz
</code></pre></div></div>]]></content><author><name></name></author><summary type="html"><![CDATA[The Radicle team is delighted to announce the release of Radicle 1.4.0 (bbd1e2c), code name Lily. Going forward, we want to name our releases after the abundant flowers and plants of this earth. We chose Lily as the first in honor of Finland’s national flower, the Lily of the Valley. The team is making this release from Helsinki 🇫🇮]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://radicle.dev/https://radicle-website.liw.fi/radicle-1.png" /><media:content medium="image" url="https://radicle.dev/https://radicle-website.liw.fi/radicle-1.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Radicle 1.4.0 – Lily</title><link href="https://radicle.dev/https://radicle-website.liw.fi/2025/09/03/radicle-1.4.0.html" rel="alternate" type="text/html" title="Radicle 1.4.0 – Lily" /><published>2025-09-03T00:00:00+03:00</published><updated>2025-09-03T00:00:00+03:00</updated><id>https://radicle.dev/https://radicle-website.liw.fi/2025/09/03/radicle-1.4.0</id><content type="html" xml:base="https://radicle.dev/https://radicle-website.liw.fi/2025/09/03/radicle-1.4.0.html"><![CDATA[<p>The Radicle team is delighted to announce the release of Radicle 1.4.0
(bbd1e2c), code name <em>Lily</em>. Going forward, we want to name our releases after
the abundant flowers and plants of this earth. We chose Lily as the first in
honor of Finland’s national flower, the <em>Lily of the Valley</em>. The team is making
this release from Helsinki 🇫🇮</p>

<p>This release contains 67 commits by 5 contributors. It’s exciting to
see our Zulip community growing and having patches from fresh contributors! 👾</p>

<p>Thanks to the following contributors for providing their time and effort for
this release:</p>
<ul>
  <li>srestegosaurio</li>
  <li>Matthias Beyer</li>
  <li>Sebastian Martinez</li>
</ul>

<h2 id="installation">Installation</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl -sSLf https://radicle.dev/install | sh -s -- --no-modify-path --version=1.4.0
</code></pre></div></div>

<h2 id="canonical-reference-improvements">Canonical Reference Improvements</h2>

<p>The canonical reference calculation was improved internally so that the
developers can better reason about the process. During this, it was noted that
the Radicle storage copy of the repository and the working copy of the
repository were both used during the process. By ensuring that the storage
copy is the only one used, a class of bugs is ruled out. This, however, means
that a <code class="language-plaintext highlighter-rouge">git push</code> will not fail when the pushed commit diverges, but will still
emit a warning that the new commit is diverging away from the other heads. We
weighed this up, and consider it an improvement, since the user is given control
of their own Git history.</p>

<p>Future improvements will provide ways of inspecting and resolving diverging
heads.</p>

<h2 id="fixed-panics">Fixed Panics</h2>

<p>Two instances of panics were fixed in this release.</p>

<p>The first, and most important, was a panic around serializing wire messages.
There is a strict size limit on the protocol messages that we control. However,
this size limit is not intended to be imposed on Git streams, for example during
fetching from other nodes. We incorrectly placed a check for this size limit in
the <code class="language-plaintext highlighter-rouge">serialize</code> function, which meant it would panic for some Git fetches. This
was fixed by moving the check elsewhere, while also improving the code so we do
not make that mistake again.</p>

<p>The second involved using the <code class="language-plaintext highlighter-rouge">read</code> method from the <code class="language-plaintext highlighter-rouge">sqlite</code> crate. This method
calls <code class="language-plaintext highlighter-rouge">try_read</code> and <code class="language-plaintext highlighter-rouge">unwrap</code>s the <code class="language-plaintext highlighter-rouge">Result</code>, which would cause a panic. We have
replaced the calls to <code class="language-plaintext highlighter-rouge">read</code> with <code class="language-plaintext highlighter-rouge">try_read</code> to more gracefully handle the
error.</p>

<h2 id="improvements-towards-windows-compatibility">Improvements Towards Windows Compatibility</h2>

<p>We have continued along the path towards compatibility by fixing some areas that
required some Windows specific handling. These included canonicalization of
paths, and using the correct named pipes location for the control socket.</p>

<h2 id="improved-bootstrapping">Improved Bootstrapping</h2>

<p>Previously, we would use DNS to resolve to the IP address of bootstrap nodes,
which would be used as the bootstrap address. Now, we may also use the IPv4,
IPv6, and Tor addresses directly for bootstrapping.</p>

<h2 id="improvements-to-rad-sync">Improvements to <code class="language-plaintext highlighter-rouge">rad sync</code></h2>

<p>We now use a more suitable symbol in <code class="language-plaintext highlighter-rouge">rad sync status</code> for the status:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>✗ Hint:
   ? … Status:
       ✓ … in sync          ✗ … out of sync
       ! … not announced    • … unknown
</code></pre></div></div>

<p>This aligns closer with the <code class="language-plaintext highlighter-rouge">rad node status</code> output. As well as this, the <code class="language-plaintext highlighter-rouge">Tip</code>
column was renamed to <code class="language-plaintext highlighter-rouge">SigRefs</code>, since the term <code class="language-plaintext highlighter-rouge">Tip</code> was too ambiguous.</p>

<p>The internal logic of <code class="language-plaintext highlighter-rouge">rad sync --announce</code> was improved by writing more tests
and finding edge cases to fix. Included in these improvements is changing the
target behavior. Before, the announcements would attempt to reach the preferred
seeds target <em>and</em> the replication factor. Now, it tries to reach the preferred
seeds and falls back to the replication factor.</p>

<h2 id="improvements-to-rad-cob-log">Improvements to <code class="language-plaintext highlighter-rouge">rad cob log</code></h2>

<p>The <code class="language-plaintext highlighter-rouge">rad cob log</code> command learned two new options, <code class="language-plaintext highlighter-rouge">--from</code> and <code class="language-plaintext highlighter-rouge">--to</code>. These
take a commit SHA that correspond to a COB operation, and allows you to limit
the log to start from or end the log at those operations, respectively.</p>

<h2 id="various-improvements">Various Improvements</h2>

<p>We have made the errors that occur in <code class="language-plaintext highlighter-rouge">radicle-fetch</code> more fine-grained so that
we get better error reporting.</p>

<p>Also, thanks to Matthias Beyer for making improvements within our Rust code.
These may not be visible to the user, but they may improve some performance, and
improve the developers lives :)</p>

<h2 id="changelog">Changelog</h2>

<p>This release contains 67 commit(s) by 5 contributor(s).</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">bbd1e2cff</code> <strong>crates: 1.4.0 release</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">de38d9741</code> <strong>build: move to use <code class="language-plaintext highlighter-rouge">releases/</code> prefix</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">819ae5fdf</code> <strong>node/main: Refactor initialization of logging</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">bc4a13902</code> <strong>systemd: Clean up default service configurations</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">25decf161</code> <strong>systemd: Add example service hardening</strong> <em><a href="mailto:lcdt@disroot.org">lcdt@disroot.org</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d7aa2d9da</code> <strong>flake/hooks: Reconfigure Git Hooks</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">7d2f0e387</code> <strong>node: e2e test for canonical ref update</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0d96af5d0</code> <strong>node: update default branch for canonical refs</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c38b9d9e1</code> <strong>node: simplify canonical reference calculation</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a8255a2e0</code> <strong>Introduce a node event for canonical reference updates</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">690f6b02c</code> <strong>remote-helper: remove check for fast-forward</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">119a12489</code> <strong>radicle: the great Canonical rewrite</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8a66e4d04</code> <strong>node/systemd: Check that received sockets are AF_UNIX</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">192cc993a</code> <strong>radicle: Fix panic when reading from SQLite database fails</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a568e7f48</code> <strong>protocol: Refactor decoding</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">cbd2a7070</code> <strong>protocol: Refactor encoding</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a8426dfda</code> <strong>protocol: Fix panic when serializing large frames</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c5b99db10</code> <strong>doc: Oversight when integrating winpipe</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a4d83ec8d</code> <strong>node/control: Please the borrow checker</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">fca96e697</code> <strong>node: Fix test on Windows</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">19a262d3d</code> <strong>node: Use winpipe for control socket on Windows</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ce11f03fe</code> <strong>radicle/profile: Control socket path for Windows</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">fd34b680b</code> <strong>signals: Guard most of the crate for Unix</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">5229fb8a5</code> <strong>fix: Normalize filesystem paths with <code class="language-plaintext highlighter-rouge">dunce</code></strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">31039bbce</code> <strong>radicle-fetch: More fine-grained errors</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d2517c500</code> <strong>radicle-fetch: Fallback to known version</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">a670b6e66</code> <strong>radicle: fix stream tests</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0c6ff06c6</code> <strong>radicle: use repository fixture in cob stream tests</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">1d7478cd9</code> <strong>radicle: introduce <code class="language-plaintext highlighter-rouge">cob::common::Title</code></strong> <em><a href="mailto:me@sebastinez.dev">me@sebastinez.dev</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">2a0f6fd3c</code> <strong>cli: extend <code class="language-plaintext highlighter-rouge">rad cob log</code> behaviour</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">044ff8add</code> <strong>radicle: introduce specialised Stream types</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c0ac228c3</code> <strong>radicle: introduce COB stream</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9b59c0e2c</code> <strong>radicle: add Op::load method</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">dbfcf424d</code> <strong>radicle: add Op::manifest_of</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">bfe8c5234</code> <strong>cob: add method for loading entry manifest</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">86119473b</code> <strong>test: add alphanumeric generator</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8953ec4c8</code> <strong>cli/inbox: Clearify “clear” behaviour</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9a7c22536</code> <strong>radicle/config/node: Use newtypes</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c4ff0d8ea</code> <strong>radicle/config/node: Granular Default Values</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">77f63c76d</code> <strong>Replace unit-returning-closure with drop()</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">cb7c748c6</code> <strong>Move destructuring to fn signature</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">9486e751f</code> <strong>Simplify impl of Display for some types</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">787cb3a87</code> <strong>Collapse nested if</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">b0af48aa0</code> <strong>To not allocate in good case</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">0200e84ae</code> <strong>bootstrap: Add IPv6, IPv4, Onion addresses</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">6a1b13bb6</code> <strong>cli: Use human-panic</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">f6f3be437</code> <strong>cli/issue: Optimize how the issues are collected</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">b49ff9e5a</code> <strong>radicle: Implement Iterator::size_hint() for optimizations</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">1e66c5764</code> <strong>refactor: Replace return Err(anyhow!()) with anyhow::bail!()</strong> <em><a href="mailto:mail@beyermatthias.de">mail@beyermatthias.de</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">01bed73a6</code> <strong>cli: fix error formatting</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ed5b2659c</code> <strong>cli: Gracefully handle failure to link log file</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">de78cf787</code> <strong>cli: Add verbose printing of authors</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c8b6a13d6</code> <strong>cli/sync/status: Refactor output table</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c089727e9</code> <strong>term, cli, remote-helper: Status Symbols</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">1cd3ad078</code> <strong>node: Remove useless caching of node announcement</strong> <em><a href="mailto:lorenz.leutgeb@radicle.xyz">lorenz.leutgeb@radicle.xyz</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">efa7efacc</code> <strong>radicle: Announcer test set constructions</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">c15288a69</code> <strong>radicle: note about Announcer::can_continue</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">1b33229dd</code> <strong>radicle: test Announcer::timed_out on success</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">11156619b</code> <strong>radicle: Announcer test repeated sync</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ce2d3eb07</code> <strong>radicle: Announcer test synced with unknown node</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">ca7231e65</code> <strong>radicle: Announcer test adapting the replication target</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">685c84e59</code> <strong>radicle: Announcer with replication factor of 0</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">4307eb35b</code> <strong>radicle: Announcer test AlreadySynced for preferred seeds</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">376a5566c</code> <strong>radicle: Announcer test preferred seeds only</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">84f11f5e3</code> <strong>radicle: Announcer ensures local node is ignored</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">8a6e55502</code> <strong>radicle: Announcer can exit on preferred seeds or replication factor</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em></li>
  <li><code class="language-plaintext highlighter-rouge">d14709481</code> <strong>fix: upgrade radicle-crypto</strong> <em><a href="mailto:fintan.halpenny@gmail.com">fintan.halpenny@gmail.com</a></em>
    <h2 id="checksums">Checksums</h2>
  </li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>8673c488c95fa2bf6e310e39fee54c07b7e15aca4496bf430551d944674cc772  radicle-1.4.0-rc.2-x86_64-apple-darwin.tar.xz
35f157611c30212ffd24a92a7c4b3cb950fe96f95cd3e346657cd8efbee63e7d  radicle-1.4.0-rc.2-x86_64-unknown-linux-musl.tar.xz
0c75447090905f862720fe8d7a549e93b0f815fa11ef7538599e4699f3802cb7  radicle-1.4.0-rc.2-aarch64-apple-darwin.tar.xz
872d156eed2b869038cea1f7711a5de9fca615710e6aba31157ac5052f31d6b4  radicle-1.4.0-rc.2-aarch64-unknown-linux-musl.tar.xz
</code></pre></div></div>]]></content><author><name></name></author><summary type="html"><![CDATA[The Radicle team is delighted to announce the release of Radicle 1.4.0 (bbd1e2c), code name Lily. Going forward, we want to name our releases after the abundant flowers and plants of this earth. We chose Lily as the first in honor of Finland’s national flower, the Lily of the Valley. The team is making this release from Helsinki 🇫🇮]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://radicle.dev/https://radicle-website.liw.fi/radicle-1.png" /><media:content medium="image" url="https://radicle.dev/https://radicle-website.liw.fi/radicle-1.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>