diff --git a/test/agent/README.md b/test/agent/README.md
index 63be79b074b42494a73922b6cabde6d25a603457..37f6cf2a7340a6b4450f9d741c374324f789f365 100644
--- a/test/agent/README.md
+++ b/test/agent/README.md
@@ -2,13 +2,13 @@
 Last revision: 2021-08-31
 
 # Requirements
-Guile library version 3.0.7 or higher is required. Guile lib may require other 
+Guile library version 3.0.7 or higher is required. Guile lib may require other
 dependencies in particular libunistring-dev and libgc-deb packages.
 
-Guile can be provided by the distro if available, or built locally. Note that 
-Guile v3.0.7 is quite recent and most likely not yet provided by most linux 
+Guile can be provided by the distro if available, or built locally. Note that
+Guile v3.0.7 is quite recent and most likely not yet provided by most linux
 distributions.
-If the required version is available on your distro, just install it using your 
+If the required version is available on your distro, just install it using your
 distro's package manager. Development packages must be installed as well.
 
 # Build Guile library
@@ -16,7 +16,7 @@ To build Guile locally, you first need to enable it when building contrib, then
 recompile contrib:
 
 ```sh
-cd daemon/contribu/native
+cd daemon/contrib/native
 ../bootstrap --enable-guile
 make list
 make fetch
@@ -35,20 +35,34 @@ make check
 ```
 
 # Running the agent
-The agent expects a Scheme file has its first parameter.  This scheme file will
-be interpreted by Guile.  In the script, you can control the agent.
-
-Usage:
-```sh
-./agent ./examples/passive-agent.scm
-```
+The agent is actually a wrapper around Guile's Scheme shell.  By default, you
+enter an interactive prompt that allows you to interact with Jami using the
+primitive bindings or by using the agent helper.  For help for running the
+agent, run `./agent --help`.
 
 # Guile bindings
-In order for Guile to control the agent, bindings have to be added to the global
-environment where the configuration file is being interpreted.  This is done in
-`main.cpp` in the function `install_scheme_primitive()`.  All scheme bindings
-should have the prefix `agent:` to be clear that the procedure is one that
-control the agent.
+Guile needs primitive bindings to communicate with Jami.  Usually, these
+bindings can written in pure Scheme using the foreign function interface (FFI)
+and some dlopen() magics.  However, this method cannot applies here for two main
+reasons:
+
+  1. Jami source code is in C++ not C.
+  2. Dynamic loading is not present on some platform supported by Jami.
+
+The first reason makes it hard to interface C++ container types and other
+standard types to bytevector used by Guile to interface with foreign functions.
+In C, it's trivial to just types and pointers to bytevector.
+
+The second reason is a constraint on the agent.  Since the goal is to have a set
+of bindings that can run on any platform where Jami is supported, bindings
+should be registered in C++.
+
+All bindings can be found under `src/bindings/*`.  Bindings should be decouple
+into module that reflect their common functionnality.  For example,
+`src/bindings/account.h` has all the Jami's bindings for managing accounts.  When
+a set of bindings is to be added to a new module, the latter has to be
+registered into Guile.  In order accomplish this, one has to include the
+bindings and define the module under `src/bindings/bindings.cpp`.
 
 When a binding is called from Guile, the arguments passed are Scheme objects of
 type `SCM`.  This is an opaque type that is generic.  In order to be clear on
@@ -56,26 +70,17 @@ what the underlying type needed by the primitive procedure is, one should add th
 suffix of the type at the end.
 
 For example, `my_primitive_procedure()` expects that `some_variable_str`
-will be of type `string`.  This is enforced by using an assertion:
-```c++
-static SCM my_primitive_procedure(SCM some_variable_str)
-{
-   AGENT_ASSERT(scm_is_string(some_variable_str), "`some_variable_str` must be of type string");
-   ...
-}
-```
+will be of type `string`.
 
-Here is another example where `my_second_primitive()` expects that
-`some_variable_vector_or_str` to be of type `string` or `vector`:
-```c++
-static SCM my_second_primitive(SCM some_variable_vector_or_str)
-{
-   AGENT_ASSERT(scm_is_string(some_variable_vector_or_str) ||
-                scm_is_simple_vector(some_variable_vector_or_str),
-                "`scm_some_variable_vector_or_str` must either be of type vector or string");
-  ...
-}
-```
+There's also a set of utilities that can be used to convert C++ object to Scheme
+and vice versa.  These utilities can be found under `src/utils.h` and are all
+template based and can usually be used without specifying any type thanks to
+type inference.
 
-# Writing scenarios
+For example, to convert `std::string bar` to `SCM baz`, onw would do
+`baz = to_guile(bar)`.  One can also do the oposite like so
+`bar = from_guile(baz)`.
+
+# Examples
 See `examples/`
+