diff --git a/build.gradle.kts b/build.gradle.kts
index b90ab2997514eba538f80946228c4a39ce4aa065..3d042c121cb5041e91e7361414c706ffa1c34f68 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -36,6 +36,7 @@ plugins {
     id("java")
     id("idea")
     id("org.jlleitschuh.gradle.ktlint") version "10.1.0"
+    id("org.briarproject.briar.desktop.build-data-gradle-plugin")
 }
 
 group = "app.briar.desktop"
@@ -50,6 +51,10 @@ allprojects {
     }
 }
 
+buildData {
+    packageName = "org.briarproject.briar.desktop"
+}
+
 dependencies {
     implementation(compose.desktop.currentOs)
     implementation(compose.materialIconsExtended)
diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..bbfeb03c22323e48f71748532b9b1c37d812fc9a
--- /dev/null
+++ b/buildSrc/build.gradle
@@ -0,0 +1 @@
+apply plugin: 'java'
diff --git a/buildSrc/src/main/java/org/briarproject/briar/desktop/builddata/AbstractBuildDataTask.java b/buildSrc/src/main/java/org/briarproject/briar/desktop/builddata/AbstractBuildDataTask.java
new file mode 100644
index 0000000000000000000000000000000000000000..b2a076bf19daba605645311298acd4151c628042
--- /dev/null
+++ b/buildSrc/src/main/java/org/briarproject/briar/desktop/builddata/AbstractBuildDataTask.java
@@ -0,0 +1,22 @@
+package org.briarproject.briar.desktop.builddata;
+
+import org.gradle.api.internal.ConventionTask;
+import org.gradle.api.logging.Logger;
+import org.gradle.api.tasks.Nested;
+
+public abstract class AbstractBuildDataTask extends ConventionTask {
+
+	protected final Logger logger = getLogger();
+
+	@Nested
+	protected BuildDataPluginExtension configuration;
+
+	public BuildDataPluginExtension getConfiguration() {
+		return configuration;
+	}
+
+	public void setConfiguration(BuildDataPluginExtension configuration) {
+		this.configuration = configuration;
+	}
+
+}
diff --git a/buildSrc/src/main/java/org/briarproject/briar/desktop/builddata/BuildDataPlugin.java b/buildSrc/src/main/java/org/briarproject/briar/desktop/builddata/BuildDataPlugin.java
new file mode 100644
index 0000000000000000000000000000000000000000..d35887a79e96d3b7dc3e6953417c97ff0940bf5f
--- /dev/null
+++ b/buildSrc/src/main/java/org/briarproject/briar/desktop/builddata/BuildDataPlugin.java
@@ -0,0 +1,38 @@
+package org.briarproject.briar.desktop.builddata;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.logging.Logger;
+import org.gradle.api.plugins.JavaPluginConvention;
+import org.gradle.api.tasks.SourceSet;
+
+import java.nio.file.Path;
+
+public class BuildDataPlugin implements Plugin<Project> {
+
+	@Override
+	public void apply(final Project project) {
+		Logger logger = project.getLogger();
+		logger.info("applying version access plugin");
+
+		BuildDataPluginExtension extension = project.getExtensions().create(
+				"buildData", BuildDataPluginExtension.class);
+
+		GenerateBuildDataSourceTask task = project.getTasks().create(
+				"buildData", GenerateBuildDataSourceTask.class);
+		task.setConfiguration(extension);
+
+		project.getTasks().findByName("compileJava").dependsOn(task);
+
+		Path pathBuildDir = project.getBuildDir().toPath();
+		Path source = Util.getSourceDir(pathBuildDir);
+
+		SourceSet sourceSets = project.getConvention()
+				.getPlugin(JavaPluginConvention.class).getSourceSets()
+				.findByName("main");
+		sourceSets.java(sourceSet -> {
+			sourceSet.srcDir(source);
+		});
+	}
+
+}
diff --git a/buildSrc/src/main/java/org/briarproject/briar/desktop/builddata/BuildDataPluginExtension.java b/buildSrc/src/main/java/org/briarproject/briar/desktop/builddata/BuildDataPluginExtension.java
new file mode 100644
index 0000000000000000000000000000000000000000..9bb4ada377b7080ceaa56fdbbac991d71347e3ee
--- /dev/null
+++ b/buildSrc/src/main/java/org/briarproject/briar/desktop/builddata/BuildDataPluginExtension.java
@@ -0,0 +1,30 @@
+package org.briarproject.briar.desktop.builddata;
+
+import org.gradle.api.tasks.Input;
+import org.gradle.api.tasks.Optional;
+
+public class BuildDataPluginExtension {
+
+	@Input
+	private String packageName;
+	@Input
+	@Optional
+	private String className;
+
+	public String getPackageName() {
+		return packageName;
+	}
+
+	public void setPackageName(String packageName) {
+		this.packageName = packageName;
+	}
+
+	public String getClassName() {
+		return className;
+	}
+
+	public void setClassName(String className) {
+		this.className = className;
+	}
+
+}
diff --git a/buildSrc/src/main/java/org/briarproject/briar/desktop/builddata/FileBuilder.java b/buildSrc/src/main/java/org/briarproject/briar/desktop/builddata/FileBuilder.java
new file mode 100644
index 0000000000000000000000000000000000000000..eaab26681a891e0f2de082617dad96b87e014c26
--- /dev/null
+++ b/buildSrc/src/main/java/org/briarproject/briar/desktop/builddata/FileBuilder.java
@@ -0,0 +1,26 @@
+package org.briarproject.briar.desktop.builddata;
+
+class FileBuilder {
+
+	private static String nl = System.getProperty("line.separator");
+
+	private StringBuilder buffer = new StringBuilder();
+
+	void append(String string) {
+		buffer.append(string);
+	}
+
+	void line() {
+		buffer.append(nl);
+	}
+
+	void line(String string) {
+		buffer.append(string);
+		buffer.append(nl);
+	}
+
+	public String toString() {
+		return buffer.toString();
+	}
+
+}
diff --git a/buildSrc/src/main/java/org/briarproject/briar/desktop/builddata/GenerateBuildDataSourceTask.java b/buildSrc/src/main/java/org/briarproject/briar/desktop/builddata/GenerateBuildDataSourceTask.java
new file mode 100644
index 0000000000000000000000000000000000000000..4a163d76a996e1e20cfd792076684b920b67217c
--- /dev/null
+++ b/buildSrc/src/main/java/org/briarproject/briar/desktop/builddata/GenerateBuildDataSourceTask.java
@@ -0,0 +1,97 @@
+package org.briarproject.briar.desktop.builddata;
+
+import org.gradle.api.Project;
+import org.gradle.api.tasks.TaskAction;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+
+public class GenerateBuildDataSourceTask extends AbstractBuildDataTask {
+
+	public GenerateBuildDataSourceTask() {
+		setGroup("build");
+	}
+
+	@TaskAction
+	protected void generateSource() throws IOException {
+		Project project = getProject();
+
+		String packageName = configuration.getPackageName();
+		String className = configuration.getClassName();
+		if (className == null) {
+			className = "BuildData";
+		}
+
+		String version = project.getVersion().toString();
+		long buildTime = System.currentTimeMillis();
+		// TODO: fetch correct current git hash using JGit in a platform-independent way
+		String gitHash = "abcdefgh";
+
+		if (packageName == null) {
+			throw new IllegalStateException("Please specify 'packageName'.");
+		}
+
+		String[] parts = packageName.split("\\.");
+
+		Path pathBuildDir = project.getBuildDir().toPath();
+		Path source = Util.getSourceDir(pathBuildDir);
+
+		Path path = source;
+		for (int i = 0; i < parts.length; i++) {
+			path = path.resolve(parts[i]);
+		}
+
+		Files.createDirectories(path);
+		Path file = path.resolve(className + ".java");
+
+		String content =
+				createSource(packageName, className, version, buildTime,
+						gitHash);
+
+		InputStream in = new ByteArrayInputStream(
+				content.getBytes(StandardCharsets.UTF_8));
+		Files.copy(in, file, StandardCopyOption.REPLACE_EXISTING);
+	}
+
+	private String createSource(String packageName, String className,
+			String version, long timestamp, String gitHash) {
+		FileBuilder buffer = new FileBuilder();
+		// // this file is generated, do not edit
+		// package org.briarproject.briar.desktop;
+		//
+		// public class BuildData {
+		buffer.line("// this file is generated, do not edit");
+		buffer.line("package " + packageName + ";");
+		buffer.line();
+		buffer.line("public class " + className + " {");
+		buffer.line();
+		// public static String getVersion() {
+		//     return "0.1";
+		// }
+		buffer.line("    public static String getVersion() {");
+		buffer.line("        return \"" + version + "\";");
+		buffer.line("    }");
+		// public static long getBuildTime() {
+		//		return 1641645802088L;
+		// }
+		buffer.line("    public static long getBuildTime() {");
+		buffer.line("        return " + timestamp + "L;");
+		buffer.line("    }");
+		// public static long getGitHash() {
+		//		return "749dda081c3e7862050255817bc239b9255b1582";
+		// }
+		buffer.line("    public static String getGitHash() {");
+		buffer.line("        return \"" + gitHash + "\";");
+		buffer.line("    }");
+		buffer.line();
+		buffer.line("}");
+
+		return buffer.toString();
+	}
+
+}
diff --git a/buildSrc/src/main/java/org/briarproject/briar/desktop/builddata/Util.java b/buildSrc/src/main/java/org/briarproject/briar/desktop/builddata/Util.java
new file mode 100644
index 0000000000000000000000000000000000000000..4c7f7eb094609789e4742bd21fe8a61eddb76745
--- /dev/null
+++ b/buildSrc/src/main/java/org/briarproject/briar/desktop/builddata/Util.java
@@ -0,0 +1,11 @@
+package org.briarproject.briar.desktop.builddata;
+
+import java.nio.file.Path;
+
+class Util {
+
+	static Path getSourceDir(Path pathBuildDir) {
+		return pathBuildDir.resolve("generatedBuildData");
+	}
+
+}
diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/org.briarproject.briar.desktop.build-data-gradle-plugin.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/org.briarproject.briar.desktop.build-data-gradle-plugin.properties
new file mode 100644
index 0000000000000000000000000000000000000000..f69a478ae9de1eee3e998d8e2039c057835b4622
--- /dev/null
+++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/org.briarproject.briar.desktop.build-data-gradle-plugin.properties
@@ -0,0 +1 @@
+implementation-class=org.briarproject.briar.desktop.builddata.BuildDataPlugin
diff --git a/src/main/kotlin/org/briarproject/briar/desktop/Main.kt b/src/main/kotlin/org/briarproject/briar/desktop/Main.kt
index 36b4aef0766198c2ccee7a75035bb4202c10f253..f45e31ce789b8bab70dd8fc1298b72b05b86e750 100644
--- a/src/main/kotlin/org/briarproject/briar/desktop/Main.kt
+++ b/src/main/kotlin/org/briarproject/briar/desktop/Main.kt
@@ -8,6 +8,7 @@ import com.github.ajalt.clikt.parameters.options.default
 import com.github.ajalt.clikt.parameters.options.flag
 import com.github.ajalt.clikt.parameters.options.option
 import com.github.ajalt.clikt.parameters.types.int
+import mu.KotlinLogging
 import org.briarproject.bramble.BrambleCoreEagerSingletons
 import org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_CONTROL_PORT
 import org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_SOCKS_PORT
@@ -22,6 +23,9 @@ import java.lang.System.getProperty
 import java.nio.file.Files
 import java.nio.file.Path
 import java.nio.file.Paths
+import java.time.Instant
+import java.time.ZoneId
+import java.time.format.DateTimeFormatter
 import java.util.logging.Level.ALL
 import java.util.logging.Level.INFO
 import java.util.logging.Level.WARNING
@@ -32,6 +36,11 @@ private class Main : CliktCommand(
     name = "briar-desktop",
     help = i18n("main.help.title")
 ) {
+
+    companion object {
+        private val LOG = KotlinLogging.logger {}
+    }
+
     private val debug by option("--debug", "-d", help = i18n("main.help.debug")).flag(
         default = false
     )
@@ -65,6 +74,12 @@ private class Main : CliktCommand(
 
         LogUtils.setupLogging(level)
 
+        val buildTime = Instant.ofEpochMilli(BuildData.getBuildTime()).atZone(ZoneId.systemDefault()).toLocalDateTime()
+        val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
+        LOG.info { "This is briar-desktop version ${BuildData.getVersion()}" }
+        LOG.info { "Build time ${formatter.format(buildTime)}" }
+        LOG.info { "Built from Git hash ${BuildData.getGitHash()}" }
+
         val dataDir = getDataDir()
         val app =
             DaggerBriarDesktopApp.builder().desktopModule(