diff --git a/doc/client-api.txt b/doc/client-api.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8121d92218490a83b5f3c4856b0cc8e9d775599b
--- /dev/null
+++ b/doc/client-api.txt
@@ -0,0 +1,155 @@
+Notes about the client api
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Starting with Ganeti 1.3, the individual commands (gnt-...) do not
+execute code directly, but instead via a master daemon. The
+communication between these commands and the daemon will be language
+agnostic, and we will be providing a python library implementing all
+operations.
+
+TODO: add tags support, add gnt-instance info implementation, document
+all results from query and all opcode fields
+
+Protocol
+========
+
+The protocol for communication will consist of passing JSON-encoded
+messages over a UNIX socket. The protocol will be send message, receive
+message, send message, ..., etc. Each message (either request or
+response) will end (after the JSON message) with a ``ETX`` character
+(ascii decimal 3), which is not a valid character in JSON messages and
+thus can serve as a message delimiter. Quoting from the
+http://www.json.org grammar::
+
+  char: any unicode character except " or \ or control character
+
+There are three request types than can be done:
+
+  - submit job; a job is a sequence of opcodes that modify the cluster
+  - abort a job; in some circumstances, a job can be aborted; the exact
+    conditions depend on the master daemon implementation and clients
+    should not rely on being able to abort jobs
+  - query objects; this is a generic form of query that works for all
+    object types
+
+All requests will be encoded as a JSON object, having three fields:
+
+  - ``request``: string, one of ``submit``, ``abort``, ``query``
+  - ``data``: the payload of the request, variable type based on request
+  - ``version``: the protocol version spoken by the client; we are
+    describing here the version 0
+
+The response to any request will be a JSON object, with two fields:
+
+  - ``success``: either ``true`` or ``false`` denoting whether the
+    request was successful or not
+  - ``result``: the result of the request (depends on request type) if
+    successful, otherwise the error message (describing the failure)
+
+The server has no defined upper-limit on the time it will take to
+respond to a request, so the clients should implement their own timeout
+handling. Note though that most requests should be answered quickly, if
+the cluster is in a normal state.
+
+Submit
+------
+
+The submit ``data`` field will be a JSON object - a (partial) Job
+description. It will have the following fields:
+
+  - ``opcode_list``: a list of opcode objects, see below
+
+The opcode objects supported will mostly be the ones supported by the
+internal Ganeti implementation; currently there is no well-defined
+definition of them (work in progress).
+
+Each opcode will be represented in the message list as an object:
+
+  - ``OP_ID``: an opcode id; this will be equivalent to the ``OP_ID``
+    class attribute on opcodes (in lib/opcodes.py)
+  - other fields: as needed by the opcode in question
+
+Small example, request::
+
+  {
+    "opcode_list": [
+      {
+        "instance_name": "instance1.example.com",
+        "OP_ID": "OP_INSTANCE_SHUTDOWN"
+      }
+    ]
+  }
+
+And response::
+
+  {
+    "result": "1104",
+    "success": true
+  }
+
+The result of the submit request will be if successful, a single JSON
+value denoting the job ID. While the job ID might be (or look like) an
+integer, the clients should not depend on this and treat this ID as an
+opaque identifier.
+
+Abort
+-----
+
+The abort request data will be a single job ID (as returned by submit or
+query jobs). The result will hold no data (i.e. it will be a JSON
+``null`` value), if successful, and will be the error message if it
+fails.
+
+Query
+-----
+
+The ``data`` argument to the query request is a JSON object containing:
+
+  - ``object``: the object type to be queried
+  - ``names``: if querying a list of objects, this can restrict the
+    query to a subset of the entire list
+  - ``fields``: the list of informations that we are interested in
+
+The valid values for the ``object`` field is:
+
+  - ``cluster``
+  - ``node``
+  - ``instance``
+
+For the ``cluster`` object, the ``names`` parameter is unused and must
+be null.
+
+The result value will be a list of lists: each row in the top-level list
+will hold the result for a single object, and each row in the per-object
+results will hold a result field, in the same order as the ``fields``
+value.
+
+Small example, request::
+
+  {
+    "data": {
+      "fields": [
+        "name",
+        "admin_memory"
+      ],
+      "object": "instance"
+    },
+    "request": "query"
+  }
+
+And response::
+
+  {
+    "result": [
+      [
+        "instance1.example.com",
+        "128"
+      ],
+      [
+        "instance2.example.com",
+        "4096"
+      ]
+    ],
+    "success": true
+  }
+