diff --git a/src/common/serialization/clap.h b/src/common/serialization/clap.h
new file mode 100644
index 00000000..f46db77d
--- /dev/null
+++ b/src/common/serialization/clap.h
@@ -0,0 +1,137 @@
+// yabridge: a Wine plugin bridge
+// Copyright (C) 2020-2022 Robbert van der Helm
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+#pragma once
+
+#include
+
+#include "../bitsery/ext/in-place-variant.h"
+
+#include "../bitsery/ext/message-reference.h"
+#include "../utils.h"
+#include "common.h"
+
+// The CLAP communication strategy is identical to what we do for VST3.
+
+// The messages are defined in the `clap/` directory following the same
+// structure as the CLAP repo.
+
+/**
+ * When we send a control message from the plugin to the Wine plugin host, this
+ * encodes the information we request or the operation we want to perform. A
+ * request of type `ClapControlRequest(T)` should send back a `T::Response`.
+ * These messages are for main thread functions.
+ */
+// TODO: Remove placeholder, add actual types
+using ClapMainThreadControlRequest = std::variant;
+
+template
+void serialize(S& s, ClapMainThreadControlRequest& payload) {
+ // All of the objects in the variant should have their own serialization
+ // function
+ s.ext(payload, bitsery::ext::InPlaceVariant{});
+}
+
+/**
+ * A message type for audio thread functions the host can call on the plugin.
+ * These functions are called from a hot loop every processing cycle, so we'll
+ * have a dedicated socket for these for every plugin instance.
+ *
+ * This is wrapped in a struct so we can use some bitsery magic to deserialize
+ * to a reference. This object is kept around as a thread local, and the
+ * `process_request_` field stores the last process request received. This
+ * allows other functions to be called in between process calls without having
+ * to recreate this object. See `MessageReference` and
+ * `bitsery::ext::MessageReference` for more information.
+ */
+struct ClapAudioThreadControlRequest {
+ ClapAudioThreadControlRequest() {}
+
+ /**
+ * Initialize the variant with an object. In `ClapSockets::send_message()`
+ * the object gets implicitly converted to the this variant.
+ */
+ template
+ ClapAudioThreadControlRequest(T request) : payload(std::move(request)) {}
+
+ // TODO:
+ using Payload = std::variant;
+
+ Payload payload;
+
+ template
+ void serialize(S& s) {
+ s.ext(
+ payload,
+ bitsery::ext::InPlaceVariant{
+ // TODO: Process data
+ // [&](S& s,
+ // MessageReference& request_ref)
+ // {
+ // // When serializing this reference we'll read the data
+ // // directly from the referred to object. During
+ // // deserializing we'll deserialize into the persistent and
+ // // thread local `process_request` object (see
+ // // `ClapSockets::add_audio_processor_and_listen`) and then
+ // // reassign the reference to point to that boject.
+ // s.ext(request_ref,
+ // bitsery::ext::MessageReference(process_request_));
+ // },
+ [](S& s, auto& request) { s.object(request); }});
+ }
+
+ // TODO: Process data, update docstring
+ // /**
+ // * Used for deserializing the
+ // `MessageReference`
+ // * variant. When we encounter this variant, we'll actually deserialize
+ // the
+ // * object into this object, and we'll then reassign the reference to
+ // point
+ // * to this object. That way we can keep it around as a thread local
+ // object
+ // * to prevent unnecessary allocations.
+ // */
+ // std::optional process_request_;
+};
+
+/**
+ * When we do a callback from the Wine plugin host to the plugin, this encodes
+ * the information we want or the operation we want to perform. A request of
+ * type `ClapMainThreadCallbackRequest(T)` should send back a `T::Response`.
+ */
+// TODO: Placeholder
+using ClapMainThreadCallbackRequest = std::variant;
+
+// TODO: Uncomment after changing `ClapMainThreadCallbackRequest`
+// template
+// void serialize(S& s, ClapMainThreadCallbackRequest& payload) {
+// // All of the objects in `ClapMainThreadCallbackRequest` should have their own
+// // serialization function.
+// s.ext(payload, bitsery::ext::InPlaceVariant{});
+// }
+
+/**
+ * Fetch the `std::variant<>` from an audio thread request object. This will
+ * let us use our regular, simple function call dispatch code, but we can still
+ * store the process data in a separate field (to reduce allocations).
+ *
+ * @overload
+ */
+inline ClapAudioThreadControlRequest::Payload& get_request_variant(
+ ClapAudioThreadControlRequest& request) noexcept {
+ return request.payload;
+}