diff --git a/docs/source/usage/api_modelling.md b/docs/source/usage/api_modelling.md
index 24591ef25ecfc53aae6ff5675d9788d23f4bcb87..4ba552aec22a7c720d218ea72f236325db5481a0 100644
--- a/docs/source/usage/api_modelling.md
+++ b/docs/source/usage/api_modelling.md
@@ -229,3 +229,10 @@ b = lang.AugExpr("double").var("b")
 expr = MyClass(T1="int", T2="double").ctor(a, b)
 expr, lang.depends(expr), lang.includes(expr)
 ```
+
+(field_data_structure_reflection)=
+## Reflecting Field Data Structures
+
+:::{admonition} To Do
+
+:::
diff --git a/docs/source/usage/how_to_composer.md b/docs/source/usage/how_to_composer.md
index 709d72a7e06aae81569eb2714837673f94f49c13..7f08829605abad35f5603b502e2cc454df90124a 100644
--- a/docs/source/usage/how_to_composer.md
+++ b/docs/source/usage/how_to_composer.md
@@ -236,6 +236,7 @@ with SourceFileGenerator() as sfg:
     )
 ```
 
+(how_to_namespaces)=
 ## Namespaces
 
 C++ uses namespaces to structure code and group entities.
@@ -267,9 +268,132 @@ with SourceFileGenerator() as sfg:
     sfg.code("/* More code in the outer namespace */")
 ```
 
-## Kernels and Kernel Parameter Mappings
+## Kernels and Parameter Mappings
 
+The original purpose of pystencils-sfg is to simplify the embedding of *pystencils*-generated
+numerical kernels into C++ applications.
+This section discusses how to register kernels with the source file generator,
+how to call them in wrapper code,
+and how to automatically map symbolic pystencils fields onto nd-array data structures.
 
+### Registering Kernels
+
+In the generated files, kernels are organized in *kernel namespaces*.
+The composer gives us access to the default kernel namespace (`<current_namespace>::kernels`)
+via `sfg.kernels`.
+
+To add a kernel,
+ - either pass its assignments and the pystencils code generator configuration directly to {any}`kernels.reate() <KernelsAdder.create>`,
+ - or create the kernel separately through {any}`pystencils.create_kernel <pystencils.codegen.create_kernel>` and register it using
+   {any}`kernels.add() <KernelsAdder.add>`.
+
+Both functions return a kernel handle, through which the kernel may later be invoked.
+
+You may create and access custom-named kernel namespaces using {any}`sfg.kernel_namespace() <SfgBasicComposer.kernel_namespace>`.
+This gives you a {any}`KernelsAdder` object with the same interface as `sfg.kernels`.
+
+:::{note}
+
+A kernel namespace is not a regular namespace; if you attempt to create both a regular and a kernel namespace with the same name,
+the composer will raise an error.
+:::
+
+Here's an example with two kernels being registered in different kernel namespace,
+once using `add`, and once using `create`.
+
+```{code-cell} ipython3
+import pystencils as ps
+
+with SourceFileGenerator() as sfg:
+    #   Create symbolic fields
+    f, g = ps.fields("f, g: double[2D]")
+
+    #   Define and create the first kernel
+    asm1 = ps.Assignment(f(0), g(0))
+    cfg1 = ps.CreateKernelConfig()
+    cfg1.cpu.openmp.enable = True
+    khandle_1 = sfg.kernels.create(asm1, "first_kernel", cfg1)
+
+    #   Define the second kernel and its codegen configuration
+    asm2 = ps.Assignment(f(0), 3.0 * g(0))
+    cfg2 = ps.CreateKernelConfig(target=ps.Target.CUDA)
+
+    #   Create and register the second kernel at a custom namespace
+    kernel2 = ps.create_kernel(asm2, cfg2)
+    khandle_2 = sfg.kernel_namespace("gpu_kernels").add(kernel2, "second_kernel")
+```
+
+### Writing Kernel Wrapper Functions
+
+By default, kernel definitions are only visible in the generated implementation file;
+kernels are supposed to not be called directly, but through wrapper functions.
+This serves to hide their fairly lenghty and complicated low-level function interface.
+
+#### Invoking CPU Kernels
+
+To call a CPU kernel from a function, use `sfg.call` on a kernel handle:
+
+```{code-block} python
+sfg.function("kernel_wrapper")(
+    sfg.call(khandle)
+)
+```
+
+This will expose all parameters of the kernel into the wrapper function and, in turn,
+cause them to be added to its signature.
+We don't want to expose this complexity, but instead hide it by using appropriate data structures.
+The next section explains how that is achieved in pystencils-sfg.
+
+#### Mapping Fields to Data Structures
+
+Pystencils kernels operate on n-dimensional contiguous or strided arrays,
+There exist many classes with diverse APIs modelling such arrays throughout the scientific
+computing landscape, including [Kokkos Views][kokkos_view], [C++ std::mdspan][mdspan],
+[SYCL buffers][sycl_buffer], and many framework-specific custom-built classes.
+Using the protocols behind {any}`sfg.map_field <SfgBasicComposer.map_field>`,
+it is possible to automatically emit code
+that extracts the indexing information required by a kernel from any of these classes
+- provided a suitable API reflection is available.
+
+:::{seealso}
+[](#field_data_structure_reflection) for instructions on how to set up field API
+reflection for a custom nd-array data structure.
+:::
+
+Pystencils-sfg natively provides field extraction for a number of C++ STL-classes,
+such as `std::vector` and `std::span` (for 1D fields) and `std::mdspan`.
+Import any of them from `pystencilssfg.lang.cpp.std` and create an instance for a given
+field using `.from_field()`.
+Then, inside the wrapper function, pass the symbolic field and its associated data structure to
+{any}`sfg.map_field <SfgBasicComposer.map_field>`.
+before calling the kernel:
+
+```{code-cell} ipython3
+import pystencils as ps
+from pystencilssfg.lang.cpp import std
+
+with SourceFileGenerator() as sfg:
+    #   Create symbolic fields
+    f, g = ps.fields("f, g: double[1D]")
+
+    #   Create data structure reflections
+    f_vec = std.vector.from_field(f)
+    g_span = std.span.from_field(g)
+
+    #   Create the kernel
+    asm = ps.Assignment(f(0), g(0))
+    khandle = sfg.kernels.create(asm, "my_kernel")
+
+    #   Create the wrapper function
+    sfg.function("call_my_kernel")(
+        sfg.map_field(f, f_vec),
+        sfg.map_field(g, g_span),
+        sfg.call(khandle)
+    )
+```
+
+(exposed_inline_kernels)=
+### Exposed and Inline Kernels
 
 :::{admonition} To Do
 
@@ -279,3 +403,7 @@ with SourceFileGenerator() as sfg:
 
 :::
 
+
+[kokkos_view]: https://kokkos.org/kokkos-core-wiki/ProgrammingGuide/View.html
+[mdspan]: https://en.cppreference.com/w/cpp/container/mdspan
+[sycl_buffer]: https://registry.khronos.org/SYCL/specs/sycl-2020/html/sycl-2020.html#subsec:buffers
diff --git a/src/pystencilssfg/composer/basic_composer.py b/src/pystencilssfg/composer/basic_composer.py
index 7c61b61e2940b3c05227005380de8f7d151f4763..6a7802f26d86a4ae251344aca6e304de45339ca9 100644
--- a/src/pystencilssfg/composer/basic_composer.py
+++ b/src/pystencilssfg/composer/basic_composer.py
@@ -5,7 +5,13 @@ import sympy as sp
 from functools import reduce
 from warnings import warn
 
-from pystencils import Field, CreateKernelConfig, create_kernel
+from pystencils import (
+    Field,
+    CreateKernelConfig,
+    create_kernel,
+    Assignment,
+    AssignmentCollection,
+)
 from pystencils.codegen import Kernel
 from pystencils.types import create_type, UserTypeSpec, PsType
 
@@ -79,6 +85,8 @@ SequencerArg: TypeAlias = tuple | ExprLike | SfgCallTreeNode | SfgNodeBuilder
 
 
 class KernelsAdder:
+    """Handle on a kernel namespace that permits registering kernels."""
+
     def __init__(self, ctx: SfgContext, loc: SfgNamespaceBlock):
         self._ctx = ctx
         self._loc = loc
@@ -115,7 +123,7 @@ class KernelsAdder:
 
     def create(
         self,
-        assignments,
+        assignments: Assignment | Sequence[Assignment] | AssignmentCollection,
         name: str | None = None,
         config: CreateKernelConfig | None = None,
     ):
@@ -135,7 +143,6 @@ class KernelsAdder:
 
             config.function_name = name
 
-        # type: ignore
         kernel = create_kernel(assignments, config=config)
         return self.add(kernel)
 
@@ -263,10 +270,10 @@ class SfgBasicComposer(SfgIComposer):
         return self.kernel_namespace("kernels")
 
     def kernel_namespace(self, name: str) -> KernelsAdder:
-        """Return the kernel namespace of the given name, creating it if it does not exist yet."""
-        kns = self._cursor.get_entity("kernels")
+        """Return a view on a kernel namespace in order to add kernels to it."""
+        kns = self._cursor.get_entity(name)
         if kns is None:
-            kns = SfgKernelNamespace("kernels", self._cursor.current_namespace)
+            kns = SfgKernelNamespace(name, self._cursor.current_namespace)
             self._cursor.add_entity(kns)
         elif not isinstance(kns, SfgKernelNamespace):
             raise ValueError(
@@ -511,7 +518,7 @@ class SfgBasicComposer(SfgIComposer):
 
         Args:
             field: The pystencils field to be mapped
-            src_object: An object representing a field data structure.
+            index_provider: An expression representing a field, or a field extraction provider instance
             cast_indexing_symbols: Whether to always introduce explicit casts for indexing symbols
         """
         return SfgDeferredFieldMapping(