Radish alpha
r
rad:z371PVmDHdjJucejRoRYJcDEvD5pp
Radicle website including documentation and guides
Radicle
Git
Release 1.3.0
Merged fintohaps opened 8 months ago

Announcement for 1.3.0 including an accompanying post that goes into more detail on canonical references.

3 files changed +374 -0 073f5393 966efc6e
added _posts/2025-08-12-canonical-references.md
@@ -0,0 +1,195 @@
+
---
+
title: "Canonical References"
+
author: "fintohaps"
+
layout: post
+
authorUrl: "https://app.radicle.xyz/nodes/iris.radicle.xyz/users/did:key:z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM"
+
layout: "blog"
+
---
+

+
## Canonical what?
+

+
Most people who use Git are used to referring to things called branches
+
(`refs/heads`). "I pushed the branch", "check out the feature branch to see the
+
work", "Ok, I'll pull your branch", etc. A branch is simply a specific
+
kind of reference in a Git. You're also likely familiar with tags
+
(`refs/tags`), and these are another kind of references, too! A reference,
+
quite simply, is a name that points to a Git object, like a commit object or a
+
tag object. The naming convention and what objects they point to allow us to
+
talk more specifically about branches, remote branches, tags, and notes.
+

+
So what's a canonical reference? In the Radicle protocol, all your references
+
live under your namespace (`refs/namespaces/<nid>/refs/{head,tags,*}`). We want
+
Radicle repositories to also act like more traditional Git repositories that
+
have the typical references `refs/heads/main`, `refs/tags/v1.0.0`,
+
`refs/heads/qa/feature-1`. So we introduced a way to synthesise these references
+
from the references under the set of `refs/namespaces/<nid>/refs`. These
+
references become canon[^4] and can be considered for use, e.g. fetching a
+
specific tag object for building binaries.
+

+
## Git History in the Making
+

+
Since the dawn of the `heartwood` implementation of the Radicle protocol, the
+
concept of the `defaultBranch` was included in the identity document. Alongside
+
this, we have had the `threshold` value. Even more importantly, we have had the
+
`delegates` managing the identity of the identity document, as well. By
+
combining these 3 values we were able to calculate the canonical reference of
+
the `defaultBranch`. The `defaultBranch` becomes a canonical reference when a
+
`threshold` number of `delegates` decide on a commit to use for its canonical
+
form.
+

+
If you have been using Radicle, you'll have noticed that whenever you push Git
+
tags that they get placed under your namespace. Most people who have used `git`
+
would expect these tags to be placed under `refs/tags`. Up until now, we have
+
broken this expectation, because we are working in a decentralised environment
+
using Radicle, protecting the global namespace of the repository. So, we asked
+
ourselves, "Can the `defaultBranch` approach be generalised?" This way, the
+
`refs/tags` namespace can be populated using the canonical form of the tag.
+

+
"It should be easy!", I said – famous last words.
+

+
What ensued was a RIP[^0] and two patches[^1][^2], over a time period that felt
+
like forever. It turned out that evolving things in a protocol can be quite
+
tricky when it comes to compatibility. You may notice that the merged patch and
+
the RIP will differ slightly in the approach recommended. For now, the approach
+
we are using bases itself on the extensible payloads in the identity document.
+

+
After all that, we are proud to announce that **you** can now start using
+
canonical references, so let's go through how to use them.
+

+
## A Quick Guide to Canonical References
+

+
As alluded to above, we need three values to specify a rule for a canonical
+
reference. We need a reference the rule applies to, a set of allowed DIDs
+
(currently always `did:key`s), and a `threshold`. These three values form a
+
canonical reference rule. In fact, we can generalise the reference value to use
+
a Git reference pattern[^3].
+

+
So, where do these new rules go? The new update of Radicle will now interpret a
+
new payload identified by the key `xyz.radicle.crefs`. Under this key, it
+
expects a `rules` key, which in turn can hold a number of canonical reference
+
rules that are identified by their Git reference pattern.
+

+
For each rule, there are two keys: `allow` and `threshold` – these refer to the
+
allowed set of DIDs and the `threshold` value respectively.
+

+
To demonstrate, the maintainers of the `heartwood` repository have prepared a
+
rule already so that we can use release tags. I (@fintohaps) used the command
+
`rad id update --edit` to open up my editor with the identity document
+
pre-populated. I added the new payload with a rule for `refs/tags/releases/*`,
+
the allowed set of the current 3 maintainers of the repository, and a
+
`threshold` of 2. Here is what the document looked like when saving:
+

+
```json
+
{
+
  "payload": {
+
    "xyz.radicle.project": {
+
      "defaultBranch": "master",
+
      "description": "Radicle Heartwood Protocol & Stack",
+
      "name": "heartwood"
+
    },
+
    "xyz.radicle.crefs": {
+
      "rules": {
+
        "refs/tags/releases/*": {
+
          "allow": [
+
            "did:key:z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz",
+
            "did:key:z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz",
+
            "did:key:z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM"
+
          ],
+
          "threshold": 2
+
        }
+
      }
+
    }
+
  },
+
  "delegates": [
+
    "did:key:z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT",
+
    "did:key:z6MktaNvN1KVFMkSRAiN4qK5yvX1zuEEaseeX5sffhzPZRZW",
+
    "did:key:z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM",
+
    "did:key:z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz",
+
    "did:key:z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz"
+
  ],
+
  "threshold": 1
+
}
+
```
+

+
And here's the output of the `rad id` command:
+

+
```
+
╭───────────────────────────────────────────────────────────────────────────────────╮
+
│ Title    Add Release Tag Canonical Refs Rule                                      │
+
│ Revision 45e43cc54284f579deb7ae64e4d162274c04fa3b                                 │
+
│ Blob     def6df9a842e68525b371462200b6d5454269601                                 │
+
│ Author   did:key:z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM                 │
+
│ State    active                                                                   │
+
│ Quorum   no                                                                       │
+
│                                                                                   │
+
│ Adding the `xyz.radicle.crefs` payload that starts with a single for the          │
+
│ `refs/tags/releases/*` rules that uses Erik, Fintan, and Lorenz as the allowed    │
+
│ delegates, and a threshold of 2.                                                  │
+
├───────────────────────────────────────────────────────────────────────────────────┤
+
│ ✓ did:key:z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM fintohaps        (you) │
+
│ ? did:key:z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT cloudhead              │
+
│ ? did:key:z6MktaNvN1KVFMkSRAiN4qK5yvX1zuEEaseeX5sffhzPZRZW cloudhead-laptop       │
+
│ ? did:key:z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz erikli                 │
+
│ ✓ did:key:z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz lorenz                 │
+
╰───────────────────────────────────────────────────────────────────────────────────╯
+

+
@@ -1,17 +1,29 @@
+
 {
+
   "payload": {
+
+    "xyz.radicle.crefs": {
+
+      "rules": {
+
+        "refs/tags/releases/*": {
+
+          "allow": [
+
+            "did:key:z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz",
+
+            "did:key:z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz",
+
+            "did:key:z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM"
+
+          ],
+
+          "threshold": 2
+
+        }
+
+      }
+
+    },
+
     "xyz.radicle.project": {
+
       "defaultBranch": "master",
+
       "description": "Radicle Heartwood Protocol & Stack",
+
       "name": "heartwood"
+
     }
+
   },
+
   "delegates": [
+
     "did:key:z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT",
+
     "did:key:z6MktaNvN1KVFMkSRAiN4qK5yvX1zuEEaseeX5sffhzPZRZW",
+
     "did:key:z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM",
+
     "did:key:z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz",
+
     "did:key:z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz"
+
   ],
+
   "threshold": 1
+
 }
+
```
+

+
You can look at the evolution of the proposal by using `rad id show
+
45e43cc54284f579deb7ae64e4d162274c04fa3b` in the `heartwood` repository.
+

+
Note that since the rules are being added to the identity document, it is
+
necessary to reach a majority quorum for proposing these changes.
+

+
Once the rules are in place, any time you push or fetch a reference that matches
+
a rule, it will compute the canonical form for that reference. In the case
+
above, if any of the 2 allowed `did:key`s agree on a tag that lives under their
+
namespace as `refs/tags/releases`, then a corresponding `refs/tags` will be
+
computed.
+

+
This means that there will be more top-level references appearing in Radicle
+
repositories, and importantly, tooling and processes that require Git tags can
+
now take advantage of Radicle repositories!
+

+
Now, it's time to go try out this feature and report back to us! Release tags to
+
your hearts content ❤️🌱
+

+
[^0]: RIP-4 Canonical References https://app.radicle.xyz/nodes/seed.radicle.xyz/rad:z3trNYnLWS11cJWC6BbxDs5niGo82/patches/1d1ce874f7c39ecdcd8c318bbae46ffd02fe1ea8?tab=changes
+

+
[^1]: First patch attempting to implement canonical references https://app.radicle.xyz/nodes/seed.radicle.xyz/rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5/patches/c54883e5ffb1f8a99f432e3ac79c0b728cd0dab3
+

+
[^2]: Second patch implementing canonical references using the identity payload https://app.radicle.xyz/nodes/seed.radicle.xyz/rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5/patches/bea09df15505cfcebc72ad40f629747d2e82f670
+

+
[^3]: Git ref format and reference patterns https://git-scm.com/docs/git-check-ref-format
+

+
[^4]: Here we are using the term in the sense that some content made may not be considered part of the canon of some story or universe. For example, some Star Wars content may be considered as canon by George Lucas, but some may not be.
added _posts/2025-08-12-radicle-1.3.0.md
@@ -0,0 +1,177 @@
+
---
+
title: "Radicle 1.3.0"
+
layout: post
+
image: radicle-1.png
+
---
+

+
The Radicle team is delighted to announce the release of Radicle 1.3.0
+
(29043134a). This release contains 48 commits by 7 contributors. We would like
+
to thank everyone for their continued effort in helping us improve the Radicle
+
protocol and tooling via their contributions and usage reports 👾
+

+
## Installation
+

+
```
+
curl -sSf https://radicle.xyz/install | sh -s -- --no-modify-path --version=1.3.0
+
```
+

+
## Canonical References
+

+
This feature has been under way for quite some time, and we are proud to
+
announce that it's ready for you to use!
+

+
Canonical reference rules have been introduced via an identity payload entry
+
under the identifier `xyz.radicle.crefs`. Here's an example of the payload that
+
includes a single rule for tags that live under `refs/tags/releases/*`:
+

+
```
+
"xyz.radicle.crefs": {
+
  "rules": {
+
    "refs/tags/releases/*": {
+
      "allow": [
+
        "did:key:z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz",
+
        "did:key:z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz",
+
        "did:key:z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM"
+
      ],
+
      "threshold": 2
+
    }
+
  }
+
}
+
```
+

+
The canonical reference rules are now used to check for canonical updates. The
+
rule for the `defaultBranch` of an `xyz.radicle.project` is synthesized from the
+
identity document fields: `threshold` and `delegates`. This means that a rule
+
for that reference is not allowed within the rule set. This is checked when
+
performing a `rad id update`.
+

+
For a more detailed history and usage of canonical references, check out the
+
accompanying [post](/2025/08/12/canonical-references.html).
+

+
## Introducing `radicle-protocol`
+

+
This set of changes is mostly cosmetic for the time being. A new crate,
+
`radicle-protocol`, was introduced to provide a home for a sans-IO[sans-io]
+
implementation of the Radicle protocol. The crate currently defines the inner
+
workings of the protocol, and `radicle-node` depends on this.
+

+
Note here that we switched to use the `bytes` crate, and we witnessed a panic
+
from this crate while using a pre-release. It has not showed up again, but we
+
introduced the use of backtraces to help identify the issue further. So, please
+
report a backtrace if the `radicle-node` stops due to this issue.
+

+
## Path to Windows
+

+
We made an effort to start paving some of the way to being able to use Radicle
+
on Windows. The first step was taken for this, and you can now use the `rad` CLI
+
on a Windows machine – without WSL.
+

+
Currently, `git-remote-rad` and `radicle-node` are blockers for full Windows
+
support. However, the sans-IO approach mentioned above will provide a way
+
forward for implementing a `radicle-node` that works on Windows, and we will
+
continue to look into other fixes required for getting full Windows support.
+

+
## Improved Log Rotation
+

+
The rotation of logs under `.radicle/node` now works using a numbered system,
+
i.e. `node.log.1`, `node.log.2`, etc. The current running node will log to
+
`node.log`, which is a symlink to most recent number.
+

+
This means that logs will be persisted between runs, which will require
+
occasional cleanup.
+

+
## Display Full Node ID
+

+
We have improved the formatting for Node IDs and node addresses. The CLI
+
will output shortened forms of NIDs and addresses when the output is transient,
+
and the full form where it is presented to the user. This will allow you to be
+
able to copy and paste these identifiers.
+

+
## Stable Order for Pinned Repositories
+

+
The pinned repositories now maintain their insertion order, meaning that they
+
should not be reordered by any other factors other than the user's decision on
+
which repositories should appear first.
+

+
## Relax Pushes for `git-remote-rad`
+

+
The `git-remote-rad` would always expect a working copy and a reference when
+
performing pushes. These constraints are relaxed to allow a bare Git repository
+
and any kind of Git revision. This should improve the experience for users of
+
`jj`.
+

+
## Connect Attempts will Error
+

+
If a connection attempt would not happen due to an error, the result of the
+
error was never returned. This would often lead to timeouts when using `rad node
+
connect`. We now return the error and can report it instead of waiting for a
+
timeout.
+

+
## Default Branch Picker
+

+
When running `rad init` the default value for the `defaultBranch` of the
+
repository is now by provided the branch you are on or the Git configuration
+
option `init.defaultBranch`.
+

+
## Changelog
+

+
For a full list of changes, see below:
+

+
* `7a9d4512f` **radicle: fix Canonical::quorum doc link** *<fintan.halpenny@gmail.com>*
+
* `5d467418b` **term: Revert using inquire to spawn editor** *<lorenz.leutgeb@radicle.xyz>*
+
* `4934473b8` **cli/node: Improve log rotation** *<lorenz.leutgeb@radicle.xyz>*
+
* `3d352f23e` **canonical: Support Annotated Tags** *<lorenz.leutgeb@radicle.xyz>*
+
* `54fd8c40a` **node: clean up logging** *<erik@zirkular.io>*
+
* `174792813` **node: register backtrace** *<fintan.halpenny@gmail.com>*
+
* `0aaa81f82` **cli: mention binary names as part of unknown** *<fintan.halpenny@gmail.com>*
+
* `fdb1ac4e3` **radicle: Fix clippy::result_large_err** *<lorenz.leutgeb@radicle.xyz>*
+
* `5bab3f9cc` **clippy: Allow doc_overindented_list_items** *<lorenz.leutgeb@radicle.xyz>*
+
* `906803378` **chore: Automated fixes generated by clippy** *<lorenz.leutgeb@radicle.xyz>*
+
* `586eefc3e` **rust-toolchain: 1.85 → 1.88** *<lorenz.leutgeb@radicle.xyz>*
+
* `efeefd0da` **chore(debian/changelog): update package version to match upstream** *<me@sebastinez.dev>*
+
* `2a47bc0c7` **term: provide default HELP message** *<fintan.halpenny@gmail.com>*
+
* `a998ce691` **ssh: provide path on connect error** *<fintan.halpenny@gmail.com>*
+
* `8224819fe` **radicle/profile: Enable home detection on Windows** *<lorenz.leutgeb@radicle.xyz>*
+
* `1e0a14ddc` **ssh: Remove dependency on log** *<lorenz.leutgeb@radicle.xyz>*
+
* `8e6279a38` **ssh: Remove dependency on byteorder** *<lorenz.leutgeb@radicle.xyz>*
+
* `95b3303eb` **term: Remove unused dependency shlex** *<lorenz.leutgeb@radicle.xyz>*
+
* `009436efa` **ssh: Use winpipe for SSH agent on Windows** *<lorenz.leutgeb@radicle.xyz>*
+
* `070550153` **radicle: Depend on winpipe for Windows support** *<lorenz.leutgeb@radicle.xyz>*
+
* `08b535d56` **radicle: Only set file limits on Unix** *<lorenz.leutgeb@radicle.xyz>*
+
* `e7fb5647a` **term: Remove dependency on libc** *<lorenz.leutgeb@radicle.xyz>*
+
* `70fb0d3fe` **term: Use inquire for spawning the editor** *<lorenz.leutgeb@radicle.xyz>*
+
* `a28fd65e8` **term/ansi: Remove unused Windows module** *<lorenz.leutgeb@radicle.xyz>*
+
* `d46d36ece` **term/spinner: Only handle signals on Unix** *<lorenz.leutgeb@radicle.xyz>*
+
* `92d77f9ec` **crypto/ssh/keystore: Reduce scope of DirBuilderExt** *<lorenz.leutgeb@radicle.xyz>*
+
* `37ea81766` **cli: improve default branch pick** *<sekhat@temporus.me>*
+
* `85ddcace0` **docs: fix installation instructions in README.md** *<istankovic@posteo.net>*
+
* `7c4b71ab8` **radicle: Keep pinned repos ordered in config** *<tobias.hunger@gmail.com>*
+
* `1fa30e2e8` **cli: test missing commits for canonical quorum** *<fintan.halpenny@gmail.com>*
+
* `afe64d517` **remote-helper: improve canonical handling** *<fintan.halpenny@gmail.com>*
+
* `14444a43e` **remote-helper: refactor pushing action** *<fintan.halpenny@gmail.com>*
+
* `a9f75d47e` **remote-helper: allow any revision in push src** *<tobias.hunger@gmail.com>*
+
* `da72557cf` **git-remote-rad: Allow pushing from bare repositories** *<tobias.hunger@gmail.com>*
+
* `271ef497d` **crypto: Fix scope of `ssh-key` dependency** *<lorenz.leutgeb@radicle.xyz>*
+
* `0e3f3f03d` **cli: Improve formatting of Node IDs and addresses** *<lorenz.leutgeb@radicle.xyz>*
+
* `010d5134e` **protocol: fix `Frame` docstring** *<fintan.halpenny@gmail.com>*
+
* `3c5668edd` **protocol: Reimplement encoding on top of `bytes`** *<lorenz.leutgeb@radicle.xyz>*
+
* `1c20f64a2` **node, protocol: Refactor** *<lorenz.leutgeb@radicle.xyz>*
+
* `61c468778` **protocol: Create skeleton by moving from radicle-node** *<lorenz.leutgeb@radicle.xyz>*
+
* `b9759c586` **radicle: Make `node::Link` copy and add `is_*`** *<lorenz.leutgeb@radicle.xyz>*
+
* `408d4f27e` **chore: add canonical references to CHANGELOG** *<fintan.halpenny@gmail.com>*
+
* `820122516` **cli: test canonical tags** *<fintan.halpenny@gmail.com>*
+
* `ff365e2d8` **radicle: disallow default branch** *<fintan.halpenny@gmail.com>*
+
* `a69397386` **cli: extract document update logic** *<fintan.halpenny@gmail.com>*
+
* `7f646666b` **radicle: canonical references payload** *<fintan.halpenny@gmail.com>*
+
* `af6cf03ac` **radicle: canonical reference rules** *<fintan.halpenny@gmail.com>*
+
* `fb8681f5b` **radicle: `connect` returns `ConnectError`** *<fintan.halpenny@gmail.com>*
+

+
## Checksums
+

+
```
+
f09b4203a47611e1e6a78ea9087b5cae2f94cacc649ed195840a0869d821c861  radicle-1.3.0-x86_64-apple-darwin.tar.xz
+
a25c67276a86c9fbadadbacbd2ea9763202e99701aa85cf7fe5815662696988d  radicle-1.3.0-x86_64-unknown-linux-musl.tar.xz
+
3a615bb99bc998b3fca5ad8582599c8dfb3cffb0beec291f5939d4b559270227  radicle-1.3.0-aarch64-unknown-linux-musl.tar.xz
+
7939e1d1bce232730843d8975f205558b0885479c6666b630abb1500b67756db  radicle-1.3.0-aarch64-apple-darwin.tar.xz
+

+
[sans-io]: https://sans-io.readthedocs.io
modified index.md
@@ -115,6 +115,8 @@ updated, join our community on 💬 [Zulip][zulip], or <a href="{{ site.feed.pat
  Subscribe <img src="/assets/images/rss.svg" alt="RSS logo" style="width:15px;"/>
</a>

+
- 12.08.2025 [Radicle 1.3.0](/2025/08/12/radicle-1.3.0.html) released. ✨
+
- 12.08.2025 [Canonical References](/2025/08/12/canonical-references.html) released. ✨
- 17.07.2025 [Radicle 1.2.1](/2025/07/17/radicle-1.2.1.html) released. ✨
- 13.06.2025 [Radicle Desktop](/2025/06/13/radicle-desktop.html) is out. 🖥️
- 02.06.2025 [Radicle 1.2](/2025/06/02/radicle-1.2.html) released. ✨