Happy new year!
The Radicle team is excited to announce the release of Radicle 1.6.0 (4a5a51e6), code name Amaryllis. The Amaryllis flower blooms late winter and prefers to sit in the window (foreshadowing…)
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!
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:
- ade
- icetan
- defelo
- Johannes K.
- matthias
- Richard L.
- Sebastian M.
- Yaroslav H.
Installation
curl -sSLf {{ site.url }}/install | sh -s -- --no-modify-path --version=1.6.0
Migrating radicle-node to mio
The crates netservices, io-reactor, and popol were crucially valuable
for implementing radicle-node. However, they are not ideal dependencies for
ensuring long-term health of the network I/O layer:
popolis only intended to support Unix-like platforms, and support on other platforms, like Windows, is desired.- Even though
io-reactordefines the traitreactor::poller::Pollto potentially support multiple I/O polling mechanisms, there is only one single implementation wrappingpopol. Issues for other polling crates are open since 2023 without tangible progress: #10 formio, #9 forpolling, #8 forepoll. 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 topopol. - The trait
reactor::poller::Pollcan only be implemented for file descriptors which also implementstd::os::fd::raw::AsRawFd, which is only implemented on Unix-like platforms and WASI. It is believed that this is leaked frompopolas the only known implementation of the trait wraps it. - To benefit from network effects, it would be nice to see others maintaining crates
that depend on
io-reactor. However, according to crates.io, the only dependent isradicle-node(vianetservices). Contrary to that, at the time of writing,miohas 494 dependents according to crates.io, and, notably,tokio, which has 30628 dependents on crates.io, is dependent on [mio]. We therefore think that even ifmiois obsoleted, e.g. bya10(which is based onio_uringon Linux and could potentially build on top of I/O rings on Windows) 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. - One downside of using
miois that it forces the use ofmio::Tokento identify sources (while a type that isEq + Clonemight be enough). Another downside is that it forces the use of the types inmio::netfor sockets, which need to be converted to/fromstd::netif required. These distinctions are also noted by cloudhead. This is acceptable to the team, in order to leverage the benefits of a well-tested and cross-platform network I/O layer.
Building radicle-node on Windows
The efforts to migrate radicle-node to use mio, alongside changes that fixed
path canonicalization and supporting Windows pipes, have allowed developers to
build radicle-node on Windows.
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 radicle-node on Windows. Please report any issues you see via rad issue
or on our Zulip.
Rust MSRV Update to 1.85
For those who are developing on top of the heartwood crates, it is important
to note that the Minimum Supported Rust Version (MSRV) is now 1.85.
Argument Parsing via clap
rad now uses the clap crate for parsing its command-line arguments. This
brings a brand new look to the help output for the rad 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 clap when parsing fails.
Shell Completions
With the introduction of clap, this helped with the introduction of a command
rad completion to emit shell completions for static information.
systemd Credentials for radicle-node
radicle-node now supports systemd Credentials (refer to
https://systemd.io/CREDENTIALS for more information) to load:
1. The secret key, in addition to the commandline argument --secret
(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 RAD_PASSPHRASE (lower priority than the
credential). The identifier of the credential is
“xyz.radicle.node.passphrase”.
Fix Bootstrapping
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.
Changelog
This release contains 153 commit(s) by 12 contributor(s).
4a5a51e6enode: Do not mix monotonic and system time lorenz.leutgeb@radicle.xyz58305cda3protocol/limiter: impl AsTokens for limits fintan.halpenny@gmail.comc675683daprotocol: IntoIterator for BoundedVec fintan.halpenny@gmail.com37d4ae4a9radicle/node: Revisit routeability of IP addresses lorenz.leutgeb@radicle.xyzf9a62e7d8radicle/node:Address::is_localfor DNS names lorenz.leutgeb@radicle.xyzdc624ed51radicle/node/bootstrap: Remove IP addresses lorenz.leutgeb@radicle.xyz45abb881anode: Only consider onion addresses if configured fintan.halpenny@gmail.com93d2ed8c6cli/completion: Static shell completion forradfintan.halpenny@gmail.com7e5a1ababradicle: Skip invalid named folders me@sebastinez.dev0c70e1712remote-helper: inform the user of an empty patch fintan.halpenny@gmail.com28c8c1531cli/sync: filter seeds without an address fintan.halpenny@gmail.com0ec084fc2remote-helper: Support push –force-with-lease mail@defelo.de6d0c571earadicle: Return individual results for repo inrepositories_by_idme@sebastinez.devc268e809echore: Fix mistakes discovered by typos lorenz.leutgeb@radicle.xyz11cbc2e51hooks: Run “pre-push” by default lorenz.leutgeb@radicle.xyz7ccdd4c81ci: Activate all features when building docs erik@zirkular.io32d77641achore: Fix spelling errors with codespell debian@onerussian.comf7e57361dhooks: Add codespell debian@onerussian.com8e331ce18node/reactor/transport: ImplementDebuglorenz.leutgeb@radicle.xyzbc1d9ed49cli: remove lexopt dependency fintan.halpenny@gmail.com83f26abaacli/main: refactor external command fintan.halpenny@gmail.comf60922d12cli/terminal: make args module private fintan.halpenny@gmail.com961301f64cli/terminal: clean up args::Error type fintan.halpenny@gmail.coma75db6a69cli/terminal: remove argument helpers fintan.halpenny@gmail.comfec8a27a3cli/terminal: remove Help struct fintan.halpenny@gmail.come35943504cli/main: move run_command_fn to main fintan.halpenny@gmail.com7533db62fcli/terminal: remove unused parameter fintan.halpenny@gmail.com1f80eb61ecli/terminal: remove unused trait fintan.halpenny@gmail.comd41ac5982cli/help: remove the help module fintan.halpenny@gmail.com23332fa31cli/main: migrate main to use clap fintan.halpenny@gmail.com5053a1aa7cli/unseed: rename options to args fintan.halpenny@gmail.com6ca129235cli/unfollow: rename options to args fintan.halpenny@gmail.com3c8952500cli/sync: migrate to clap fintan.halpenny@gmail.comd1e19a87bcli/patch: migrate patch CLI parsing to clap mail@beyermatthias.de3ea61f0f9cli/patch: move comment actions fintan.halpenny@gmail.come404f1038node: Usestd::timefor reactor and wire lorenz.leutgeb@radicle.xyz9bcdd353ccli/inbox: Use clap me@sebastinez.dev5741bafa3radicle/cob/db: Add index for issues and patches johannes.kuehlewindt@gmail.com990e22acfcli/inspect: use Clap richard@levitte.org5ed1b8e57node: Fix test ‘test_concurrent_fetches’ adrian.duke@gmail.come8f9d21becli/node: Use clap erik@zirkular.iof20c2f215node: Re-exportPeerAddrParseErrorerik@zirkular.io6cfed884bcli/remote: migrate to clap fintan.halpenny@gmail.com93578340dAdd changelog for Radicle 1.4.0 erik@zirkular.iof8fe296ceradicle/rad: Fix typo me@sebastinez.dev8604d3bcccli/config: Use clap me@sebastinez.dev8d90699c3cli/cob: Use clap erik@zirkular.io38ca038a0cli: fix test regression in 27a85987c31ed3002369dfdc434a74797d07d56d fintan.halpenny@gmail.comc1d9f0496cli/self: Use clap me@sebastinez.dev27a85987ccli: Fix argument value names inauthandiniterik@zirkular.io44efdc02fflake: Fix source filtering lorenz@leutgeb.xyzb3f23594dgit: Ignore parent from blame lorenz@leutgeb.xyzb0beef439workspace/rust/clippy: Fix all warnings lorenz@leutgeb.xyze1b406535workspace/rust: 1.88 → 1.90 lorenz@leutgeb.xyz0dd2f3f40workspace/rust/msrv: 1.81 → 1.85 lorenz@leutgeb.xyz407abc6a2cli/follow: Use clap erik@zirkular.iodeaf77e5bcli/unfollow: Use common DID / NID argument parser erik@zirkular.ioe488ddb44cli: Add common value parser for NID / DID erik@zirkular.io06e22434ecli/checkout: use Clap richard@levitte.org28824a312cli/init: Fix argument value names erik@zirkular.io634866889cli/id: Use clap erik@zirkular.iod3ed4bb49radicle/id: IntroducePayloadUpsertlorenz.leutgeb@radicle.xyzec1d75430cli/unblock: Use clap erik@zirkular.iofaf19af9dcli: Share common argument types used in(un)blockerik@zirkular.iocef0ff571oid: usestd::hash::Hasher::hashoverHasher::writefintan.halpenny@gmail.comd9ae29deacli/seed: Use clap erik@zirkular.io80198d68bcli: Share value parser forScopeerik@zirkular.iob7a7f55e7gix: CVE-2025-31130 fintan.halpenny@gmail.com0b3424857node/reactor: Correctly handle error events lorenz.leutgeb@radicle.xyz72cf3d191cli/diff: Use clap lorenz.leutgeb@radicle.xyz532e5a0debuild: Usegit describeto generate a version lorenz.leutgeb@radicle.xyz384c50648cli/auth: use Clap richard@levitte.orgdfd35480bcli/watch: Use clap erik@zirkular.ioefe10f95bworkspace: Enable vendoredlibgit2lorenz.leutgeb@radicle.xyzb7cfcfff7workspace: A Little Lessgit2lorenz.leutgeb@radicle.xyzf4a890872git-metadata: New crate extract fromradicle-gitlorenz.leutgeb@radicle.xyz793f53b5foid: New crate lorenz.leutgeb@radicle.xyz3fcf2a86dgit-ref-format: New crate lorenz.leutgeb@radicle.xyz292befdb3radicle: Addtempfileto dev-dependencies lorenz.leutgeb@radicle.xyz3e98589a7github/build: Fix runner names lorenz.leutgeb@radicle.xyz84dd89180radicle: Fix required features forfastrandlorenz.leutgeb@radicle.xyzf232acda7cli/diff: Print cross-platform line endings lorenz.leutgeb@radicle.xyzd8ab40777radicle/storage: Fix temporary path generation lorenz.leutgeb@radicle.xyz013da67aacli/test: Skiprad_diffon macOS lorenz.leutgeb@radicle.xyzf7af91819cli/test: Fixrad_patch_deletefor macOS lorenz.leutgeb@radicle.xyz7d6d2e51dcli/test: Clean up testing environment lorenz.leutgeb@radicle.xyz3780f908aradicle/identity: Stabilize tests lorenz.leutgeb@radicle.xyz60798cdbcradicle/profile: Canonicalize during test lorenz.leutgeb@radicle.xyz86b7ef23cradicle/git/raw: Limit scope ofRemoteCallbackslorenz.leutgeb@radicle.xyz191c28795cli/ls: use Clap richard@levitte.org8ba3087cbcli/init: use Clap richard@levitte.org10e7b94c3workspace: Add.rustfmtlorenz.leutgeb@radicle.xyzea562215eradicle/git/raw: Introducetrait ErrorExtlorenz.leutgeb@radicle.xyz837f4694dhook: Add check forgit2inradiclelorenz.leutgeb@radicle.xyz880634acdradicle/git/raw: Capture allgit2re-exports lorenz.leutgeb@radicle.xyz633059040node/wire: Refactor precedence lorenz.leutgeb@radicle.xyzcb7bed556node: Remove dependency on amplify lorenz.leutgeb@radicle.xyz3c3d81a08node: Use Mio lorenz.leutgeb@radicle.xyzb25d80d27crypto: Depend ongit-ref-format-coreonly lorenz.leutgeb@radicle.xyzac572e64enode: Support systemd credential for passphrase lorenz.leutgeb@radicle.xyzae39f24b5node: Support systemd credential for secret lorenz.leutgeb@radicle.xyz0c513e981systemd: Support Credentials lorenz.leutgeb@radicle.xyz8c1073b9ccli/publish: Use clap lorenz.leutgeb@radicle.xyz7effa7c64node: Report sync status for given namespaces lorenz.leutgeb@radicle.xyz9689de9afnode: Allow announcing refs for given public keys lorenz.leutgeb@radicle.xyz4dbb022d2radicle/node: Create submodule “command” lorenz.leutgeb@radicle.xyz8e7d19320radicle: UpdateCHANGELOG.mdfor next iteration lorenz.leutgeb@radicle.xyz7b8da0e72cli/fork: Use clap lorenz.leutgeb@radicle.xyz3992d519ccli/clone: Use clap lorenz.leutgeb@radicle.xyz7c89045eacli/debug: Use clap lorenz.leutgeb@radicle.xyz2e77d5ef4cli/block: Improve example values for target argument erik@zirkular.io6d698bb79cli/block: Use clap lorenz.leutgeb@radicle.xyzed5a68c1dnode: mark modules as private fintan.halpenny@gmail.com59e09078bradicle: markCheckoutErrorasnon_exhaustivefintan.halpenny@gmail.com5b260964ccrypto: mark errors asnon_exhaustivefintan.halpenny@gmail.com30908dcf4radicle/git/canonical: Actually use qualified refs lorenz.leutgeb@radicle.xyzee041d8d0crates: bump for release fintan.halpenny@gmail.com2149770a4storage: Rewrite temporary repositories for clones lorenz.leutgeb@radicle.xyz31a7d3bd3fetch: addHandle::into_innerlorenz.leutgeb@radicle.xyze40fe86fffetch: useAsRef<Repository>fintan.halpenny@gmail.coma163f4e93fetch: refactor repository access fintan.halpenny@gmail.com5caa7b302remote-helper: Check base when matching revisions lorenz.leutgeb@radicle.xyz9bb136105remote-helper: Only update patch after evaluating base lorenz.leutgeb@radicle.xyz5cd016b58radicle-systemd: Guardmod listenfor Unix lorenz.leutgeb@radicle.xyz0095fdc58flake: Keepcrates/**/*.txtfiles for build lorenz.leutgeb@radicle.xyz9954a7949flake: Add binary cache configuration lorenz.leutgeb@radicle.xyz9c8ab7fa6fetch: Rewritegit::repository::directlorenz.leutgeb@radicle.xyzd9ce078d5protocol: Decrease log-level for logging ping/pong lorenz.leutgeb@radicle.xyz474b97950node/log: Define syslog identifier lorenz.leutgeb@radicle.xyzee49e2876cli/unfollow: Use clap lorenz.leutgeb@radicle.xyz6fb1ebec4cli/clean: Use clap lorenz.leutgeb@radicle.xyz753b7aef9cli/path: Use clap lorenz.leutgeb@radicle.xyz4787b53b1CHANGELOG: Radicle 1.5.0 fintan.halpenny@gmail.com8bc578bfabuild/release: missed updating the symlink fintan.halpenny@gmail.com01f9f3fcdcli/unseed: Use clap lorenz.leutgeb@radicle.xyz80bc95269cli/stats: Use clap lorenz.leutgeb@radicle.xyzf1c7c9860cli/issue: Move definition of “about” to args lorenz.leutgeb@radicle.xyzc7bff2845cli/issue: Use clap me@icetan.org675a0f81dcli: Depend on clap lorenz.leutgeb@radicle.xyz5a958b5ebcli/test: Output ofrad --helplorenz.leutgeb@radicle.xyz22720e718node: Make location of secret key configurable lorenz.leutgeb@radicle.xyz5887edf93crypto/ssh/keystore: Explicit paths lorenz.leutgeb@radicle.xyz9e1d6b1feradicle: Detect current repository usingjjlorenz.leutgeb@radicle.xyzabc963f2fradicle-cli/tests: Addrad_jj_patchlorenz.leutgeb@radicle.xyz731688d3fflake: Install Jujutsu for testing lorenz.leutgeb@radicle.xyzfd5043d57radicle-cli-test: Prepare testing withjjlorenz.leutgeb@radicle.xyz53522288cradicle-cli/tests:fn program_reports_versionlorenz.leutgeb@radicle.xyzfafb3493dcli: Detect key mismatch lorenz.leutgeb@radicle.xyzed8b08604node: Log Panics fintan.halpenny@gmail.com0441b048fcli: Don’t add newlines for empty descriptions in editor mail@defelo.deae01a4243radicle: Allow to clear issue descriptions and comments mail@defelo.deec22c9432cli/issue: Show previous title inrad issue editeditor mail@defelo.de9f62a82b0radicle: Fixcob::common::Title::newmail@defelo.de
Checksums
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
---
title: "Radicle 1.6.0 – Amaryllis"
image: radicle-1.png
---
Happy new year!
The Radicle team is excited to announce the release of Radicle 1.6.0 (4a5a51e6), code name *Amaryllis*.
The Amaryllis flower blooms late winter and prefers to sit in the *window* (**foreshadowing...**)
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!
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:
- ade
- icetan
- defelo
- Johannes K.
- matthias
- Richard L.
- Sebastian M.
- Yaroslav H.
## Installation
```
curl -sSLf {{ site.url }}/install | sh -s -- --no-modify-path --version=1.6.0
```
## Migrating `radicle-node` to `mio`
The crates [`netservices`], [`io-reactor`], and [`popol`] were crucially valuable
for implementing `radicle-node`. However, they are not ideal dependencies for
ensuring long-term health of the network I/O layer:
- [`popol`] is only intended to support Unix-like platforms, and support on other
platforms, like Windows, is desired.
- Even though [`io-reactor`] defines the trait [`reactor::poller::Poll`] to
potentially support multiple I/O polling mechanisms, there is only one single
implementation wrapping [`popol`]. Issues for other polling crates are open
since 2023 without tangible progress: [#10 for `mio`], [#9 for `polling`],
[#8 for `epoll`]. 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 `popol`.
- The trait [`reactor::poller::Poll`] can only be implemented for file
descriptors which also implement [`std::os::fd::raw::AsRawFd`], which is only
implemented on Unix-like platforms and WASI. It is believed that this is
leaked from `popol` as the only known implementation of the trait wraps it.
- To benefit from network effects, it would be nice to see others maintaining crates
that depend on `io-reactor`. However, according to crates.io, the
[only dependent is `radicle-node`] (via `netservices`). Contrary to that,
at the time of writing, `mio` has 494 dependents according to
[crates.io][mio reverse dependencies], and, notably, `tokio`, which has
30628 dependents on [crates.io][tokio reverse dependencies], is dependent on
[`mio`]. We therefore think that even if `mio` is obsoleted, e.g. by [`a10`]
(which is based on [`io_uring`] on Linux and could potentially build on top of
[I/O rings on Windows]) 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.
- One downside of using `mio` is that it forces the use of [`mio::Token`] to
identify sources (while a type that is `Eq + Clone` might be enough). Another
downside is that it forces the use of the types in [`mio::net`] for sockets,
which need to be converted to/from [`std::net`] if required. These
distinctions are also [noted by cloudhead]. This is acceptable to the team, in
order to leverage the benefits of a well-tested and cross-platform network I/O
layer.
[`netservices`]: https://crates.io/crates/netservices
[`io-reactor`]: https://crates.io/crates/io-reactor
[`popol`]: https://crates.io/crates/popol
[`reactor::poller::Poll`]: https://docs.rs/io-reactor/0.5.2/reactor/poller/trait.Poll.html
[#10 for `mio`]: https://github.com/rust-amplify/io-reactor/issues/10
[#9 for `polling`]: https://github.com/rust-amplify/io-reactor/issues/9
[#8 for `epoll`]: https://github.com/rust-amplify/io-reactor/issues/8
[`std::os::fd::raw::AsRawFd`]: https://doc.rust-lang.org/nightly/std/os/fd/raw/trait.AsRawFd.html
[only dependent is `radicle-node`]: https://crates.io/crates/io-reactor/reverse_dependencies
[mio reverse dependencies]: https://crates.io/crates/mio/reverse_dependencies
[tokio reverse dependencies]: https://crates.io/crates/tokio/reverse_dependencies
[`a10`]: https://crates.io/crates/a10
[`io_uring`]: https://en.wikipedia.org/wiki/Io_uring
[I/O rings on Windows]: https://learn.microsoft.com/en-us/windows/win32/api/ioringapi/
[`mio::Token`]: https://docs.rs/mio/1.0.4/mio/struct.Token.html
[`mio::net`]: https://docs.rs/mio/1.0.4/mio/net/index.html
[`std::net`]: https://doc.rust-lang.org/stable/std/net/index.html
[noted by cloudhead]: https://cloudhead.io/popol/
## Building `radicle-node` on Windows
The efforts to migrate `radicle-node` to use `mio`, alongside changes that fixed
path canonicalization and supporting Windows pipes, have allowed developers to
build `radicle-node` on Windows.
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 `radicle-node` on Windows. Please report any issues you see via `rad issue`
or on our [Zulip](https://radicle.zulipchat.com).
## Rust MSRV Update to 1.85
For those who are developing on top of the `heartwood` crates, it is important
to note that the Minimum Supported Rust Version (MSRV) is now 1.85.
## Argument Parsing via `clap`
`rad` now uses the `clap` crate for parsing its command-line arguments. This
brings a brand new look to the help output for the `rad` 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 `clap` when parsing fails.
### Shell Completions
With the introduction of `clap`, this helped with the introduction of a command
`rad completion` to emit shell completions for static information.
## systemd Credentials for `radicle-node`
`radicle-node` now supports systemd Credentials (refer to
<https://systemd.io/CREDENTIALS> for more information) to load:
1. The secret key, in addition to the commandline argument `--secret`
(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 `RAD_PASSPHRASE` (lower priority than the
credential). The identifier of the credential is
"xyz.radicle.node.passphrase".
## Fix Bootstrapping
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.
## Changelog
This release contains 153 commit(s) by 12 contributor(s).
* `4a5a51e6e` **node: Do not mix monotonic and system time** *<lorenz.leutgeb@radicle.xyz>*
* `58305cda3` **protocol/limiter: impl AsTokens for limits** *<fintan.halpenny@gmail.com>*
* `c675683da` **protocol: IntoIterator for BoundedVec** *<fintan.halpenny@gmail.com>*
* `37d4ae4a9` **radicle/node: Revisit routeability of IP addresses** *<lorenz.leutgeb@radicle.xyz>*
* `f9a62e7d8` **radicle/node: `Address::is_local` for DNS names** *<lorenz.leutgeb@radicle.xyz>*
* `dc624ed51` **radicle/node/bootstrap: Remove IP addresses** *<lorenz.leutgeb@radicle.xyz>*
* `45abb881a` **node: Only consider onion addresses if configured** *<fintan.halpenny@gmail.com>*
* `93d2ed8c6` **cli/completion: Static shell completion for `rad`** *<fintan.halpenny@gmail.com>*
* `7e5a1abab` **radicle: Skip invalid named folders** *<me@sebastinez.dev>*
* `0c70e1712` **remote-helper: inform the user of an empty patch** *<fintan.halpenny@gmail.com>*
* `28c8c1531` **cli/sync: filter seeds without an address** *<fintan.halpenny@gmail.com>*
* `0ec084fc2` **remote-helper: Support push --force-with-lease** *<mail@defelo.de>*
* `6d0c571ea` **radicle: Return individual results for repo in `repositories_by_id`** *<me@sebastinez.dev>*
* `c268e809e` **chore: Fix mistakes discovered by typos** *<lorenz.leutgeb@radicle.xyz>*
* `11cbc2e51` **hooks: Run "pre-push" by default** *<lorenz.leutgeb@radicle.xyz>*
* `7ccdd4c81` **ci: Activate all features when building docs** *<erik@zirkular.io>*
* `32d77641a` **chore: Fix spelling errors with codespell** *<debian@onerussian.com>*
* `f7e57361d` **hooks: Add codespell** *<debian@onerussian.com>*
* `8e331ce18` **node/reactor/transport: Implement `Debug`** *<lorenz.leutgeb@radicle.xyz>*
* `bc1d9ed49` **cli: remove lexopt dependency** *<fintan.halpenny@gmail.com>*
* `83f26abaa` **cli/main: refactor external command** *<fintan.halpenny@gmail.com>*
* `f60922d12` **cli/terminal: make args module private** *<fintan.halpenny@gmail.com>*
* `961301f64` **cli/terminal: clean up args::Error type** *<fintan.halpenny@gmail.com>*
* `a75db6a69` **cli/terminal: remove argument helpers** *<fintan.halpenny@gmail.com>*
* `fec8a27a3` **cli/terminal: remove Help struct** *<fintan.halpenny@gmail.com>*
* `e35943504` **cli/main: move run_command_fn to main** *<fintan.halpenny@gmail.com>*
* `7533db62f` **cli/terminal: remove unused parameter** *<fintan.halpenny@gmail.com>*
* `1f80eb61e` **cli/terminal: remove unused trait** *<fintan.halpenny@gmail.com>*
* `d41ac5982` **cli/help: remove the help module** *<fintan.halpenny@gmail.com>*
* `23332fa31` **cli/main: migrate main to use clap** *<fintan.halpenny@gmail.com>*
* `5053a1aa7` **cli/unseed: rename options to args** *<fintan.halpenny@gmail.com>*
* `6ca129235` **cli/unfollow: rename options to args** *<fintan.halpenny@gmail.com>*
* `3c8952500` **cli/sync: migrate to clap** *<fintan.halpenny@gmail.com>*
* `d1e19a87b` **cli/patch: migrate patch CLI parsing to clap** *<mail@beyermatthias.de>*
* `3ea61f0f9` **cli/patch: move comment actions** *<fintan.halpenny@gmail.com>*
* `e404f1038` **node: Use `std::time` for reactor and wire** *<lorenz.leutgeb@radicle.xyz>*
* `9bcdd353c` **cli/inbox: Use clap** *<me@sebastinez.dev>*
* `5741bafa3` **radicle/cob/db: Add index for issues and patches** *<johannes.kuehlewindt@gmail.com>*
* `990e22acf` **cli/inspect: use Clap** *<richard@levitte.org>*
* `5ed1b8e57` **node: Fix test 'test_concurrent_fetches'** *<adrian.duke@gmail.com>*
* `e8f9d21be` **cli/node: Use clap** *<erik@zirkular.io>*
* `f20c2f215` **node: Re-export `PeerAddrParseError`** *<erik@zirkular.io>*
* `6cfed884b` **cli/remote: migrate to clap** *<fintan.halpenny@gmail.com>*
* `93578340d` **Add changelog for Radicle 1.4.0** *<erik@zirkular.io>*
* `f8fe296ce` **radicle/rad: Fix typo** *<me@sebastinez.dev>*
* `8604d3bcc` **cli/config: Use clap** *<me@sebastinez.dev>*
* `8d90699c3` **cli/cob: Use clap** *<erik@zirkular.io>*
* `38ca038a0` **cli: fix test regression in 27a85987c31ed3002369dfdc434a74797d07d56d** *<fintan.halpenny@gmail.com>*
* `c1d9f0496` **cli/self: Use clap** *<me@sebastinez.dev>*
* `27a85987c` **cli: Fix argument value names in `auth` and `init`** *<erik@zirkular.io>*
* `44efdc02f` **flake: Fix source filtering** *<lorenz@leutgeb.xyz>*
* `b3f23594d` **git: Ignore parent from blame** *<lorenz@leutgeb.xyz>*
* `b0beef439` **workspace/rust/clippy: Fix all warnings** *<lorenz@leutgeb.xyz>*
* `e1b406535` **workspace/rust: 1.88 → 1.90** *<lorenz@leutgeb.xyz>*
* `0dd2f3f40` **workspace/rust/msrv: 1.81 → 1.85** *<lorenz@leutgeb.xyz>*
* `407abc6a2` **cli/follow: Use clap** *<erik@zirkular.io>*
* `deaf77e5b` **cli/unfollow: Use common DID / NID argument parser** *<erik@zirkular.io>*
* `e488ddb44` **cli: Add common value parser for NID / DID** *<erik@zirkular.io>*
* `06e22434e` **cli/checkout: use Clap** *<richard@levitte.org>*
* `28824a312` **cli/init: Fix argument value names** *<erik@zirkular.io>*
* `634866889` **cli/id: Use clap** *<erik@zirkular.io>*
* `d3ed4bb49` **radicle/id: Introduce `PayloadUpsert`** *<lorenz.leutgeb@radicle.xyz>*
* `ec1d75430` **cli/unblock: Use clap** *<erik@zirkular.io>*
* `faf19af9d` **cli: Share common argument types used in `(un)block`** *<erik@zirkular.io>*
* `cef0ff571` **oid: use `std::hash::Hasher::hash` over `Hasher::write`** *<fintan.halpenny@gmail.com>*
* `d9ae29dea` **cli/seed: Use clap** *<erik@zirkular.io>*
* `80198d68b` **cli: Share value parser for `Scope`** *<erik@zirkular.io>*
* `b7a7f55e7` **gix: CVE-2025-31130** *<fintan.halpenny@gmail.com>*
* `0b3424857` **node/reactor: Correctly handle error events** *<lorenz.leutgeb@radicle.xyz>*
* `72cf3d191` **cli/diff: Use clap** *<lorenz.leutgeb@radicle.xyz>*
* `532e5a0de` **build: Use `git describe` to generate a version** *<lorenz.leutgeb@radicle.xyz>*
* `384c50648` **cli/auth: use Clap** *<richard@levitte.org>*
* `dfd35480b` **cli/watch: Use clap** *<erik@zirkular.io>*
* `efe10f95b` **workspace: Enable vendored `libgit2`** *<lorenz.leutgeb@radicle.xyz>*
* `b7cfcfff7` **workspace: A Little Less `git2`** *<lorenz.leutgeb@radicle.xyz>*
* `f4a890872` **git-metadata: New crate extract from `radicle-git`** *<lorenz.leutgeb@radicle.xyz>*
* `793f53b5f` **oid: New crate** *<lorenz.leutgeb@radicle.xyz>*
* `3fcf2a86d` **git-ref-format: New crate** *<lorenz.leutgeb@radicle.xyz>*
* `292befdb3` **radicle: Add `tempfile` to dev-dependencies** *<lorenz.leutgeb@radicle.xyz>*
* `3e98589a7` **github/build: Fix runner names** *<lorenz.leutgeb@radicle.xyz>*
* `84dd89180` **radicle: Fix required features for `fastrand`** *<lorenz.leutgeb@radicle.xyz>*
* `f232acda7` **cli/diff: Print cross-platform line endings** *<lorenz.leutgeb@radicle.xyz>*
* `d8ab40777` **radicle/storage: Fix temporary path generation** *<lorenz.leutgeb@radicle.xyz>*
* `013da67aa` **cli/test: Skip `rad_diff` on macOS** *<lorenz.leutgeb@radicle.xyz>*
* `f7af91819` **cli/test: Fix `rad_patch_delete` for macOS** *<lorenz.leutgeb@radicle.xyz>*
* `7d6d2e51d` **cli/test: Clean up testing environment** *<lorenz.leutgeb@radicle.xyz>*
* `3780f908a` **radicle/identity: Stabilize tests** *<lorenz.leutgeb@radicle.xyz>*
* `60798cdbc` **radicle/profile: Canonicalize during test** *<lorenz.leutgeb@radicle.xyz>*
* `86b7ef23c` **radicle/git/raw: Limit scope of `RemoteCallbacks`** *<lorenz.leutgeb@radicle.xyz>*
* `191c28795` **cli/ls: use Clap** *<richard@levitte.org>*
* `8ba3087cb` **cli/init: use Clap** *<richard@levitte.org>*
* `10e7b94c3` **workspace: Add `.rustfmt`** *<lorenz.leutgeb@radicle.xyz>*
* `ea562215e` **radicle/git/raw: Introduce `trait ErrorExt`** *<lorenz.leutgeb@radicle.xyz>*
* `837f4694d` **hook: Add check for `git2` in `radicle`** *<lorenz.leutgeb@radicle.xyz>*
* `880634acd` **radicle/git/raw: Capture all `git2` re-exports** *<lorenz.leutgeb@radicle.xyz>*
* `633059040` **node/wire: Refactor precedence** *<lorenz.leutgeb@radicle.xyz>*
* `cb7bed556` **node: Remove dependency on amplify** *<lorenz.leutgeb@radicle.xyz>*
* `3c3d81a08` **node: Use Mio** *<lorenz.leutgeb@radicle.xyz>*
* `b25d80d27` **crypto: Depend on `git-ref-format-core` only** *<lorenz.leutgeb@radicle.xyz>*
* `ac572e64e` **node: Support systemd credential for passphrase** *<lorenz.leutgeb@radicle.xyz>*
* `ae39f24b5` **node: Support systemd credential for secret** *<lorenz.leutgeb@radicle.xyz>*
* `0c513e981` **systemd: Support Credentials** *<lorenz.leutgeb@radicle.xyz>*
* `8c1073b9c` **cli/publish: Use clap** *<lorenz.leutgeb@radicle.xyz>*
* `7effa7c64` **node: Report sync status for given namespaces** *<lorenz.leutgeb@radicle.xyz>*
* `9689de9af` **node: Allow announcing refs for given public keys** *<lorenz.leutgeb@radicle.xyz>*
* `4dbb022d2` **radicle/node: Create submodule "command"** *<lorenz.leutgeb@radicle.xyz>*
* `8e7d19320` **radicle: Update `CHANGELOG.md` for next iteration** *<lorenz.leutgeb@radicle.xyz>*
* `7b8da0e72` **cli/fork: Use clap** *<lorenz.leutgeb@radicle.xyz>*
* `3992d519c` **cli/clone: Use clap** *<lorenz.leutgeb@radicle.xyz>*
* `7c89045ea` **cli/debug: Use clap** *<lorenz.leutgeb@radicle.xyz>*
* `2e77d5ef4` **cli/block: Improve example values for target argument** *<erik@zirkular.io>*
* `6d698bb79` **cli/block: Use clap** *<lorenz.leutgeb@radicle.xyz>*
* `ed5a68c1d` **node: mark modules as private** *<fintan.halpenny@gmail.com>*
* `59e09078b` **radicle: mark `CheckoutError` as `non_exhaustive`** *<fintan.halpenny@gmail.com>*
* `5b260964c` **crypto: mark errors as `non_exhaustive`** *<fintan.halpenny@gmail.com>*
* `30908dcf4` **radicle/git/canonical: Actually use qualified refs** *<lorenz.leutgeb@radicle.xyz>*
* `ee041d8d0` **crates: bump for release** *<fintan.halpenny@gmail.com>*
* `2149770a4` **storage: Rewrite temporary repositories for clones** *<lorenz.leutgeb@radicle.xyz>*
* `31a7d3bd3` **fetch: add `Handle::into_inner`** *<lorenz.leutgeb@radicle.xyz>*
* `e40fe86ff` **fetch: use `AsRef<Repository>`** *<fintan.halpenny@gmail.com>*
* `a163f4e93` **fetch: refactor repository access** *<fintan.halpenny@gmail.com>*
* `5caa7b302` **remote-helper: Check base when matching revisions** *<lorenz.leutgeb@radicle.xyz>*
* `9bb136105` **remote-helper: Only update patch after evaluating base** *<lorenz.leutgeb@radicle.xyz>*
* `5cd016b58` **radicle-systemd: Guard `mod listen` for Unix** *<lorenz.leutgeb@radicle.xyz>*
* `0095fdc58` **flake: Keep `crates/**/*.txt` files for build** *<lorenz.leutgeb@radicle.xyz>*
* `9954a7949` **flake: Add binary cache configuration** *<lorenz.leutgeb@radicle.xyz>*
* `9c8ab7fa6` **fetch: Rewrite `git::repository::direct`** *<lorenz.leutgeb@radicle.xyz>*
* `d9ce078d5` **protocol: Decrease log-level for logging ping/pong** *<lorenz.leutgeb@radicle.xyz>*
* `474b97950` **node/log: Define syslog identifier** *<lorenz.leutgeb@radicle.xyz>*
* `ee49e2876` **cli/unfollow: Use clap** *<lorenz.leutgeb@radicle.xyz>*
* `6fb1ebec4` **cli/clean: Use clap** *<lorenz.leutgeb@radicle.xyz>*
* `753b7aef9` **cli/path: Use clap** *<lorenz.leutgeb@radicle.xyz>*
* `4787b53b1` **CHANGELOG: Radicle 1.5.0** *<fintan.halpenny@gmail.com>*
* `8bc578bfa` **build/release: missed updating the symlink** *<fintan.halpenny@gmail.com>*
* `01f9f3fcd` **cli/unseed: Use clap** *<lorenz.leutgeb@radicle.xyz>*
* `80bc95269` **cli/stats: Use clap** *<lorenz.leutgeb@radicle.xyz>*
* `f1c7c9860` **cli/issue: Move definition of "about" to args** *<lorenz.leutgeb@radicle.xyz>*
* `c7bff2845` **cli/issue: Use clap** *<me@icetan.org>*
* `675a0f81d` **cli: Depend on clap** *<lorenz.leutgeb@radicle.xyz>*
* `5a958b5eb` **cli/test: Output of `rad --help`** *<lorenz.leutgeb@radicle.xyz>*
* `22720e718` **node: Make location of secret key configurable** *<lorenz.leutgeb@radicle.xyz>*
* `5887edf93` **crypto/ssh/keystore: Explicit paths** *<lorenz.leutgeb@radicle.xyz>*
* `9e1d6b1fe` **radicle: Detect current repository using `jj`** *<lorenz.leutgeb@radicle.xyz>*
* `abc963f2f` **radicle-cli/tests: Add `rad_jj_patch`** *<lorenz.leutgeb@radicle.xyz>*
* `731688d3f` **flake: Install Jujutsu for testing** *<lorenz.leutgeb@radicle.xyz>*
* `fd5043d57` **radicle-cli-test: Prepare testing with `jj`** *<lorenz.leutgeb@radicle.xyz>*
* `53522288c` **radicle-cli/tests: `fn program_reports_version`** *<lorenz.leutgeb@radicle.xyz>*
* `fafb3493d` **cli: Detect key mismatch** *<lorenz.leutgeb@radicle.xyz>*
* `ed8b08604` **node: Log Panics** *<fintan.halpenny@gmail.com>*
* `0441b048f` **cli: Don't add newlines for empty descriptions in editor** *<mail@defelo.de>*
* `ae01a4243` **radicle: Allow to clear issue descriptions and comments** *<mail@defelo.de>*
* `ec22c9432` **cli/issue: Show previous title in `rad issue edit` editor** *<mail@defelo.de>*
* `9f62a82b0` **radicle: Fix `cob::common::Title::new`** *<mail@defelo.de>*
## Checksums
```
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
```