diff --git a/README.md b/README.md
new file mode 100644
index 0000000..267a773
--- /dev/null
+++ b/README.md
@@ -0,0 +1,67 @@
+# rspc
+
+Proof of concept RPC framework focused on ease of use.
+It works by calling the macro `#[rspc::service]` on an impl block,
+and code is generated for the resulting Server and Client objects.
+
+The Server objects own the original struct data and implements listen functions.
+The Client objects must be provided a connection, and replicates all the functions of the impl block where the macro was called.
+
+The Server implements read-write locking, there can be many reads at once, but only one write.
+Requests are not errored upon write-lock, but instead waited for.
+
+The Client object cannot be cloned. Instead all function calls are immutable, so a reference can be shared to all.
+
+Currently only implements local thread messaging. Serialized TCP transport is unfinished.
+
+Example:
+```rs
+use rspc::transport::{channel, ClientTransporter,ServerTransporter};
+use rspc::service;
+
+use serde::{Deserialize, Serialize};
+
+#[derive(Serialize,Deserialize)]
+pub struct MyStruct {
+ my_vec: Vec,
+}
+
+#[service]
+impl MyStruct
+{
+ pub fn len(&self) -> usize {
+ self.my_vec.len()
+ }
+
+ pub fn push(&mut self, val: String) {
+ self.my_vec.push(val)
+ }
+
+ pub fn pop(&mut self) -> Option {
+ self.my_vec.pop()
+ }
+}
+
+#[tokio::test]
+async fn test() {
+ let my_data = MyStruct {
+ my_vec: Vec::new(),
+ };
+ let (c,s) = channel::new_async();
+
+ let srv_thread = tokio::spawn(async move {
+ let mut server = MyDataServer::from(my_data);
+ server.listen(s).await
+ } );
+
+ let client = MyStructClient::new(c);
+ assert_eq!(client.len().await.unwrap(), 0);
+ client.push("Hello world!".to_string()).await.unwrap();
+ assert_eq!(client.len().await.unwrap(), 1);
+ assert_eq!(client.pop().await.unwrap(), Some("Hello world!".to_string()));
+ client.stop().await.unwrap();
+ srv_thread.await.unwrap().unwrap();
+}
+```
+
+See [example](example) for an more detailed example usage