diff --git a/tkwant/manybody.py b/tkwant/manybody.py
index b85bb0e727b8a1639d8b530b6831ee36095c933e..a958828286d3bc46e7491b7db5a387c96132fd29 100644
--- a/tkwant/manybody.py
+++ b/tkwant/manybody.py
@@ -344,7 +344,12 @@ class Solver:
             region_errors = [(hi - lo) * self.integration_error / Etot
                              for *_, (hi, lo) in self.integration_regions]
 
-            # create integrator coroutines (task producers)
+            # Integrator coroutines.
+            # These produce energies at which to evaluate observables.
+            # '_put_work' takes the energies that the integrators need
+            # and produces triples (energy, lead, mode) that can be
+            # given to a single worker to evaluate. Results are communicated
+            # back to the integrators by Futures.
             integrators = [
                 self.integrator_factory(
                     _put_work(work_queue, lead, mode),
@@ -359,12 +364,20 @@ class Solver:
             integrators = io.gather(*integrators)
             fs.append(integrators)
 
-            # create master coroutine (task consumer)
+            # Master coroutine.
+            # Pulls work (supplied by the integrators) off the queue and
+            # sends it to the appropriate worker. Receives results from
+            # workers and sets the associated future; this will wake
+            # up the appropriate integrator routine, which will fill
+            # the work queue with more work.
             master = self.master(work_queue, integrators)
             fs.append(master)
 
         if mpi_am_worker(self.comm):
-            # Only completes when a "finish" message is received from master.
+            # Worker coroutine.
+            # Receives messages from the master coroutine and evaluates
+            # the observable on a given wavefunction (specified by
+            # the triple (energy, lead, mode)).
             fs.append(self.worker(observable, time))
 
         # run everything