diff --git a/branding/motd-cli/.gitignore b/branding/motd-cli/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..e26717e8d772227ee3abaa186bc5c5e2fd426c8b
--- /dev/null
+++ b/branding/motd-cli/.gitignore
@@ -0,0 +1 @@
+motd-cli
diff --git a/branding/motd-cli/README.md b/branding/motd-cli/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..cfe8a38ae1d9838ad2427829cb5b44a1f0ff33c6
--- /dev/null
+++ b/branding/motd-cli/README.md
@@ -0,0 +1,57 @@
+MOTD (message of the day)
+=========================
+
+This is a stub until a more sophisticated motd mechanism can be implemented in
+the future, with better platform integration.
+
+Providers can opt-in to the motd feature (only riseup is using it at the moment).
+
+If motd is enabled for a given provider, the client will attempt to fetch
+the motd.json file from a well-known URL, and will display the first valid
+message on the splash screen.
+
+The structure of the `motd.json` file is like follows:
+
+```
+{
+    "motd": [{
+        "begin":    "Jan 1 2021 00:00:00",
+        "end":      "Dec 31 2021 23:59:00",
+        "type":     "daily",
+        "platform": "all",
+        "text": [
+          { "lang": "en",
+            "str": "This is a <a href='https://leap.se'>test!</a>"},
+          { "lang": "es",
+            "str": "Esto es una <a href='https://leap.se'>pruebita!</a>"}
+        ]}
+    ]
+}
+```
+
+Valid values are: 
+
+* Begin, End are date strings, like "Jan 1 2021 00:00:00".
+* Type: "once" for a one-shot message, "daily" for a message that is displayed daily during the specified duration.
+* Platform: one of "windows", "linux", "osx" or "all".
+
+The text message can contain links.
+
+You can use the `motd-cli` tool to parse and validate the json:
+
+```
+❯ ./motd-cli
+file: motd-example.json
+count: 1
+
+Message 1 ✓
+-----------
+Type: daily ✓
+Platform: all ✓
+Languages: 2 ✓
+```
+
+Notes: I'm considering adding an explicit layer of verification of the motd
+payload. Please comment on
+[#554](https://0xacab.org/leap/bitmask-vpn/-/issues/554) if you have an opinion
+on this.
diff --git a/branding/motd-cli/main.go b/branding/motd-cli/main.go
new file mode 100644
index 0000000000000000000000000000000000000000..6cfd29ed235b033cbc931c4aed71c97e042b10fd
--- /dev/null
+++ b/branding/motd-cli/main.go
@@ -0,0 +1,120 @@
+package main
+
+import (
+	"encoding/json"
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"os"
+)
+
+const defaultFile = "motd-example.json"
+
+const OK = "✓"
+const WRONG = "☓"
+
+/* TODO move structs to pkg/config/motd module, import from there */
+
+type Messages struct {
+	Messages []Message `json:"motd"`
+}
+
+func (m *Messages) Length() int {
+	return len(m.Messages)
+}
+
+type Message struct {
+	Begin    string          `json:"begin"`
+	End      string          `json:"end"`
+	Type     string          `json:"type"`
+	Platform string          `json:"platform"`
+	Text     []LocalizedText `json:"text"`
+}
+
+func (m *Message) IsValid() bool {
+	valid := (m.IsValidBegin() && m.IsValidEnd() &&
+		m.IsValidType() && m.IsValidPlatform() && m.HasLocalizedText())
+	return valid
+}
+
+func (m *Message) IsValidBegin() bool {
+	return true
+}
+
+func (m *Message) IsValidEnd() bool {
+	return true
+}
+
+func (m *Message) IsValidType() bool {
+	switch m.Type {
+	case "once", "daily":
+		return true
+	default:
+		return false
+	}
+}
+
+func (m *Message) IsValidPlatform() bool {
+	switch m.Platform {
+	case "windows", "linux", "osx", "all":
+		return true
+	default:
+		return false
+	}
+}
+
+func (m *Message) HasLocalizedText() bool {
+	return true
+}
+
+type LocalizedText struct {
+	Lang string `json:"lang"`
+	Str  string `json:"str"`
+}
+
+func main() {
+	// TODO pass url flag too, to fetch and validate remote file
+	file := flag.String("file", "", "file to validate")
+	flag.Parse()
+	f := *file
+	if f == "" {
+		f = defaultFile
+	}
+
+	fmt.Println("file:", f)
+	m := parseFile(f)
+	fmt.Printf("count: %v\n", m.Length())
+	fmt.Println()
+	for i, msg := range m.Messages {
+		fmt.Printf("Message %d %v\n-----------\n", i+1, mark(msg.IsValid()))
+		fmt.Printf("Type: %s %v\n", msg.Type, mark(msg.IsValidType()))
+		fmt.Printf("Platform: %s %v\n", msg.Platform, mark(msg.IsValidPlatform()))
+		fmt.Printf("Languages: %d %v\n", len(msg.Text), mark(msg.HasLocalizedText()))
+		if !msg.IsValid() {
+			os.Exit(1)
+		}
+	}
+}
+
+func parseFile(f string) Messages {
+	jsonFile, err := os.Open(f)
+	if err != nil {
+		panic(err)
+	}
+	defer jsonFile.Close()
+	byteVal, err := ioutil.ReadAll(jsonFile)
+	if err != nil {
+		panic(err)
+	}
+	var m Messages
+	json.Unmarshal(byteVal, &m)
+	return m
+}
+
+func mark(val bool) string {
+	if val {
+		return OK
+	} else {
+		return WRONG
+	}
+}
diff --git a/branding/motd-cli/motd-example.json b/branding/motd-cli/motd-example.json
new file mode 100644
index 0000000000000000000000000000000000000000..47bf6351bc58cf6ab6a7ed420f35b566a7430a03
--- /dev/null
+++ b/branding/motd-cli/motd-example.json
@@ -0,0 +1,14 @@
+{
+    "motd": [{
+        "begin":    "Jan 1 2021 00:00:00",
+        "end":      "Dec 31 2021 23:59:00",
+        "type":     "daily",
+        "platform": "all",
+        "text": [
+          { "lang": "en",
+            "str": "This is a <a href='https://leap.se'>test!</a>"},
+          { "lang": "es",
+            "str": "Esto es una <a href='https://leap.se'>pruebita!</a>"}
+        ]}
+    ]
+}