Open-source project
hyphanet/fred avatar
hyphanet/fred

Fred: the reference node for Freenet, where dependencies are fetched over the network itself

Freenet REference Daemon

1,226 stars237 forksJavaGPL-2.0

At a glance

What is it?
Fred, the Freenet REference Daemon, is the Java node implementation behind the Hyphanet peer-to-peer datastore, and its build system is unusual because every dependency has to be fetched through Freenet itself. This looks at how that build works and what it costs.
Who is it for?
Fred fits a developer who wants to work on the Freenet node itself, or to build a site or application on top of the Hyphanet network, and it fits a project that wants its dependencies distributed over the same censorship-resistant network as its content.
Can I use it commercially?
Yes, with conditions. GPL-2.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 34 days ago.
What is it written in?
Mainly Java, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The node, not a client library

Freenet is described as a platform for censorship-resistant communication and publishing, peer-to-peer software that provides a distributed, encrypted, decentralized datastore. Websites and applications providing things like forums and chat are built on top of it.

Fred stands for Freenet REference Daemon, and it is the reference implementation of that node. So the repository is not a client library you import to talk to a Freenet node, it is the node itself: the software that connects to other nodes, stores data, and serves what the network holds.

The distinction matters for anyone reading the documentation cold, because the build instructions in this repository are instructions for building a node, not for adding a dependency to an application.

The project sits under the Hyphanet organisation now, the homepage is hyphanet.org, and the description still reads Freenet REference Daemon. The build history in the release list is labelled both ways, with build01506 and build01505 recorded as Freenet / Hyphanet 0.7.5 builds, which shows the rename landing without a version break.

The licence is GPL, version 2 or later, and the readme is unusually candid about the mixture: some code is under the Apache License 2.0, mostly Apache Commons, and some is modified BSD code from Mantissa. The readme notes that all of this is compatible with the GPL, while arguing that ASL2 is arguably only compatible with GPL3, and that some plugins are GPL3. That is a real detail to read before contributing, because a contribution lands in a codebase with mixed terms.

A Gradle build with a verified download

The primary build path is the Gradle wrapper, and the readme has a point to make about it before you run anything: the wrapper is included, as recommended by the Gradle project, and if you trust the version that has been committed you can build immediately.

On POSIX or in Windows PowerShell:

bash
$ ./gradlew jar

In a Windows command prompt the same thing is:

code
> gradlew jar

The wrapper is configured, in `gradle/wrapper/gradle-wrapper.properties`, to verify the checksum of the archive it downloads from services.gradle.org. That is a small but meaningful detail for a project whose entire premise is that you should be able to trust the pieces you fetch, and it means the build will refuse a tampered Gradle distribution rather than running it.

There is an older Ant path as well, and it is the more interesting of the two:

bash
$ mkdir -p lib; (cd lib && grep -o CHK.* ../dependencies.properties  | xargs -P16 -I {} bash -c 'fcpget -v {} "$(echo {} | sed s,^.*/,,)"')
$ ant -propertyfile build.properties -f build-clean.xml -Dtest.skip=true -Dfindbugs.skip=true

Read the first line carefully. It greps the `CHK` entries out of `dependencies.properties` and fetches each one with `fcpget`, in parallel, sixteen at a time. `fcpget` is a Freenet client tool that downloads by content hash over FCP. So even the legacy build path pulls its dependencies through the Freenet network, from a node you already run.

Every dependency is pinned by content hash

The dependency system is the part of Fred that has no equivalent elsewhere, and it is worth understanding before you judge the project.

The rule is stated flatly: all dependencies must be available via Freenet, so a dependency must be added to `dependencies.properties`. The procedure to add one has five steps. Add it to the `build.gradle` dependencies and to `dependencyVerification`, and run `./gradlew jar --debug` to find the files that fail the verification. Upload the jar with `fcpupload {dependencyfile.jar}`. Add the dependency to all the installers, wininstaller-innosetup, java_installer and mactray, with the hint to search for `jna-platform` to find where to put and register it. And add the dependency and its CHK to `dependencies.properties`. Finally, update `scripts/update.sh` and `res/wrapper.conf` and `res/unix/run.sh` in java_installer to include the dependency.

The example makes the format concrete:

code
pebble.version=3.1.5
pebble.filename=pebble-3.1.5.jar
pebble.filename-regex=pebble-*.jar
pebble.key=CHK@y~p8HMUVxmVgfSnrmUyu2UNXMO9uMDHS5nwo2YuOKvw,yzwLFP0GXa8RjwRpicQCPFKNggDXLkTQKH8nISe0qUY,AAMC--8/pebble-3.1.5.jar
pebble.size=318169
pebble.sha256=85e77f9fd64c0a1f85569db8f95c1fb8e6ef8b296f4d6206440dc6306140c1a1
pebble.type=CLASSPATH
pebble.order=4

The filename is just the jar file, the key is what `fcpupload` returns, the size is `wc -c filename.jar`, the sha256 is `sha256sum filename.jar`, and the order is where it should be placed in the `wrapper.conf` classpath. The CHK is a Freenet content hash, which means the dependency is addressed by what it is rather than by where it lives.

The same file carries the sha256, so there are two independent integrity mechanisms, the Gradle dependency verification and the hash recorded in the properties file, and the network path between them is the Freenet one.

Installers are built in three other repositories

The installers are not built from this repository, and the readme says so plainly: they are built from specialized repositories.

The GNU/Linux, macOS and other Unix installer comes from hyphanet/java_installer. The Windows installer comes from hyphanet/wininstaller-innosetup, and it is signed with hyphanet/sign-windows-installer. Free code signing for the Windows installer is provided by SignPath.io, with the certificate provided by the SignPath Foundation.

That arrangement is a direct consequence of the dependency rule. A dependency added to Fred has to be added to all the installers, and the readme's instructions say exactly that, with the search hint for `jna-platform`. The installers are therefore part of the same dependency management story rather than a separate packaging concern, and a change to a library version ripples into three other codebases.

The release artefacts in the repository history are named for builds rather than versions, with entries such as build01507 described as Freenet 0.7.5 build 1507 and build01506 as Freenet / Hyphanet 0.7.5 build 1506. So the versioning scheme a user sees is the 0.7.5 line plus a monotonically increasing build number, which is a good fit for a network node where the build identity matters more than a semantic version.

Running your own build as a node

The workflow for a contributor who wants to test a change in a real node is short and pragmatic.

The readme says to build with `./gradlew jar`, stop your node, replace `freenet.jar` in your Freenet directory with `build/libs/freenet.jar`, and start your node again. That is the whole loop, and it works because the node is a single jar in a directory.

The build itself is tunable, and the readme shows the format. To override values set in `build.gradle`, put them into `gradle.properties` in the `variable = value` format. The example given is:

code
org.gradle.parallel = true
org.gradle.daemon = true
org.gradle.jvmargs=-Xms256m -Xmx1024m
org.gradle.configureondemand=true

tasks.withType(Test)  {
  maxParallelForks = Runtime.runtime.availableProcessors()
}

Parallel execution, a persistent daemon, a heap between 256 and 1024 megabytes, and test forking matched to the number of processors. For a project that is often built on a shared machine or a small container, those knobs are the difference between a usable iteration time and a slow one.

The repository also carries `build-offline.sh` and `test-offline.sh`, plus a `stats/` directory and a `test/` directory, and the root has `build.properties`, `build-clean.xml` and a `debian/` directory for the Debian packaging.

Unit tests run, integration tests are a TODO

The testing section is brief and has one honest gap in it.

To run all unit tests:

bash
./gradlew --parallel test

And to run specific tests, a filter such as this:

bash
./gradlew --parallel test --tests *M3UFilterTest

The filter example is a good sign about the codebase. An M3U filter test is a unit test on a playlist parser, which is the kind of code that has well defined edges and benefits from being tested in isolation. The fact that the readme can name a concrete test class as the example suggests the test suite is at the granularity of components rather than only end to end scenarios.

The gap is stated literally: `TODO: how to run integration tests`. That is worth weighing when you evaluate the project, because for a distributed node the interesting failures are the ones where two nodes disagree, and those are exactly what unit tests do not cover. The `test-offline.sh` and `build-offline.sh` scripts in the repository root suggest work in that direction, but the documentation does not claim a supported procedure.

There is also a static analysis story. The readme carries a Coverity status badge pointing at the Freenet Fred project on scan.coverity.com, and the Ant build path passes `-Dfindbugs.skip=true`, so the older build had FindBugs integration. The Gradle path adds `dependencyVerification`, which is the supply chain piece rather than the code quality piece.

Where Fred is the wrong tool

The limits follow from the project's premise, and they are worth stating plainly for anyone who arrives looking for a library.

The first is that this is a node implementation. If you want to build a forum or a chat application on Freenet, you are looking for the client and publishing APIs rather than this repository, and the cost of building the node yourself is only justified if you are changing the node. The readme's own loop, replace the jar and restart, is a node operator's loop.

The second is that the dependency story has a hard prerequisite. Because the dependencies are fetched over Freenet by content hash, a build environment needs a working node and a usable connection to the network, and the Ant path makes that explicit with `fcpget`. An offline or firewalled CI runner cannot simply resolve Maven coordinates, and the `build-offline.sh` script exists because of that. For a project whose distribution model is about resisting censorship, requiring the network to build is a coherent trade, and it is still a trade.

The third is that the build identity is a build number. With artefacts named build01507 and the release line at 0.7.5, a deployment has to pin a specific build rather than a semantic version.

The fourth is the licence mixture. GPL2 or later for the project, Apache 2.0 for some components, modified BSD for Mantissa, and GPL3 for some plugins, with the readme itself noting that ASL2 is arguably only compatible with GPL3. Nothing here is a blocker for use, and the compatibility argument the project makes is reasonable, but a corporate legal review should read that paragraph rather than assume a single licence file covers everything.

The fifth is the development branch. The default branch here is `next`, which is where unreleased work lands, and the last push to the repository was on 2026-09-19.

Editorial conclusion

Fred fits a developer who wants to work on the Freenet node itself, or to build a site or application on top of the Hyphanet network, and it fits a project that wants its dependencies distributed over the same censorship-resistant network as its content. It does not fit an application team that just wants a library to talk to a Freenet node, since this repository is the node, and it is the wrong choice if your build environment cannot reach a Freenet node, because the dependency step fetches over FCP. Before you build, read `dependencies.properties` and the `pebble` example, and expect to run the node locally, since the release artefacts are build-numbered jars rather than versioned releases.

Frequently asked questions

How do I build Fred, the Freenet node?

Use the bundled Gradle wrapper, which verifies the checksum of the Gradle distribution it downloads. On POSIX or PowerShell run `$ ./gradlew jar`, and in a Windows command prompt run `> gradlew jar`. There is also an older Ant path that fetches dependencies with `fcpget` before running `ant -propertyfile build.properties -f build-clean.xml`.

How does the Freenet dependency system work?

All dependencies must be available via Freenet and are recorded in `dependencies.properties` with a CHK content hash, a size and a sha256. To add one you add it to `build.gradle` and to `dependencyVerification`, run `./gradlew jar --debug` to find the files failing verification, upload the jar with `fcpupload`, and register it in the installers and in the java_installer wrapper configuration.

How do I run the unit tests in Fred?

Run `./gradlew --parallel test` for all of them, or filter with a pattern such as `./gradlew --parallel test --tests *M3UFilterTest`. The readme does note a TODO for how to run integration tests, and the repository has `test-offline.sh` and `build-offline.sh` for the offline path.

How do I test my own build of Fred as a node?

Build with `./gradlew jar`, stop your node, replace `freenet.jar` in your Freenet directory with `build/libs/freenet.jar`, and start the node again. Build settings can be overridden in `gradle.properties` in the `variable = value` format.

Where are the Freenet installers built?

In separate repositories: the Unix, macOS and GNU/Linux installer from hyphanet/java_installer, the Windows installer from hyphanet/wininstaller-innosetup signed with hyphanet/sign-windows-installer, with free code signing from SignPath.io and the certificate from the SignPath Foundation.

Official sources

  1. hyphanet/fred on GitHub
  2. License: GPL-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/hyphanet-fred.svg)](https://hysenlabs.com/projects/hyphanet-fred)

Was this useful?