P2P binary substitutes for GNU Guix

guix-p2p is a libp2p daemon and Guix substitute extension. It lets Guix machines discover peers through a Kademlia DHT, download NAR blocks from those peers, verify official Guix nar hashes, and fall back to configured HTTP substitutes when policy allows it.

Get started Configuration reference Deployment guide Benchmarks Source on Codeberg

Proof-of-concept experiment: this project is being developed using Codex GPT-5.5 with maintainer guidance.

What It Does

Uses normal Guix commands

Keep running guix build, guix package, and guix system reconfigure. The extension intercepts the internal guix substitute protocol calls made by guix-daemon.

Verifies official content

Peers serve NAR blocks, but downloaded content is accepted only after Guix nar hash verification against trusted narinfo metadata.

Finds peers over libp2p

Nodes advertise providers in Kademlia, can use bootstrap peers, and persist learned reachable peers between daemon starts.

Get Started

Add the repository as a Guix channel, then run guix pull:

(cons*
 (channel
  (name 'guix-p2p)
  (url "https://codeberg.org/trevarj/guix-p2p")
  (branch "master")
  (introduction
   (make-channel-introduction
    "7d6c023e60cffde9cc63d7c4c2232a3f9c9fca1f"
    (openpgp-fingerprint
     "A6C2 0D0C 2AD8 38F9 4907  0EA3 A52D 6879 4EBE D758"))))
 %default-channels)

The introduction starts at the first signed guix-p2p commit that contains .guix-authorizations, so Guix can authenticate later channel updates.

Import the service module in your operating-system configuration and enable the daemon extension:

(use-modules (guix-p2p services))

(services
  (modify-services
      (cons (service guix-p2p-service-type) %base-services)
    (guix-service-type config =>
      (guix-p2p-enable-guix-daemon-extension config))))

After reconfiguring, use Guix normally:

guix build hello
sudo guix system reconfigure /etc/config.scm

Configure

Runtime config

The daemon reads ~/.config/guix-p2p/config.toml. Configure substitute URLs, bootstrap peers, external addresses, cache paths, provider thresholds, and dashboard settings there.

Bootstrap peers

Use full peer multiaddrs such as /dns4/node.example.org/udp/6881/quic-v1/p2p/12D3KooW... in bootstrap_peers. Do not share /ip4/0.0.0.0/...; that is only a local bind address.

bootstrap_peers = "/dns4/guix-p2p.trevs.site/tcp/443/p2p/12D3KooWDnvPgCuPTPaMbnbLpXP7kCxmXc9F7agJPuAJWXGoDNPT"

Dashboard

Enable the dashboard to inspect daemon state, recent substitute activity, provider discovery, and the full shareable peer address derived from external_addresses plus the node PeerId.

Use

System service

The Guix service starts guix-p2p --daemon, adds the package to the system profile, and prepends the extension directory to GUIX_EXTENSIONS_PATH without clobbering other extensions.

Substitution policy

The daemon answers have and info only when trusted narinfo metadata exists and enough P2P providers are available. HTTP fallback remains policy-controlled.

Benchmarks

Benchmark results are secondary project evidence. The benchmark page renders the latest CI report, CSV, charts, and workflow-run links.

Development

Local shell

Use the manifest for the contributor shell with Rust, Cargo, C toolchain packages, certificates, and test helpers:

guix shell -m manifest.scm

Package shell

Use the local Guix package entrypoint when you want to test the packaged binary and extension exactly as the channel package builds them:

guix shell -f guix.scm

Checks

Inside the contributor shell, run focused Rust checks before sending changes:

cargo fmt
cargo clippy --all-targets --all-features -- -D warnings
cargo test

E2E proof

The VM channel proof is the strict deployment check. Longer benchmarks should run in CI, not on developer workstations.

cargo run -p guix-p2p-e2e -- vm channel-proof

Reference