diff --git a/doc/concepts/cable_cell.rst b/doc/concepts/cable_cell.rst
index a1a2bfc35d3e6b79332222cd12a09c90806f8b68..3048a0458ceb9f3311935c6da160ee9d6895b900 100644
--- a/doc/concepts/cable_cell.rst
+++ b/doc/concepts/cable_cell.rst
@@ -9,15 +9,15 @@ channels, synapses, gap junction sites, stimuli and spike detectors.
 
 Cable cells are constructed from three components:
 
-* :ref:`Morphology <morph>`: a decription of the geometry and branching structure of the cell shape.
-* :ref:`Label dictionary <labels>`: a set of rules that refer to regions and locations on the cell.
-* :ref:`Decor <cablecell-decoration>`: a description of the dynamics on the cell, placed according to the named rules in the dictionary.
+* :ref:`Morphology <morph>`: a description of the geometry and branching structure of the cell shape.
+* :ref:`Label dictionary <labels>`: a set of definitions and a :abbr:`DSL (domain specific language)` that refer to regions and locations on the cell morphology.
+* :ref:`Decor <cablecell-decoration>`: a description of the dynamics on the cell, placed according to the named rules in the dictionary. It can reference :ref:`mechanisms` from mechanism catalogues.
 
-When a cable cell is constructued the following steps are performed using the inputs:
+When a cable cell is constructed the following steps are performed using the inputs:
 
-1. Concrete regions and locsets are generated for the morphology for each labeled region and locset in the dictionary
+1. Concrete regions and locsets are generated for the morphology for each labelled region and locset in the dictionary
 2. The default values for parameters specified in the decor, such as ion species concentration, are instantiated.
-3. Dynamics (mechanisms, parameters, synapses, etc.) are instaniated on the regions and locsets as specified by the decor.
+3. Dynamics (mechanisms, parameters, synapses, etc.) are instantiated on the regions and locsets as specified by the decor.
 
 Once constructed, the cable cell can be queried for specific information about the cell, but it can't be modified (it is *immutable*).
 
@@ -34,391 +34,11 @@ Once constructed, the cable cell can be queried for specific information about t
     * all cells of the same type (e.g. Purkinje) have the same dynamics defined on their respective regions.
 
     The basic building blocks required to construct all of the cells for the model would be:
+
     * 6 morphologies (2 for each of purkinje, granule and pyramidal).
     * 3 decors (1 for each of purkinje, granule and pyramidal).
     * 1 label dictionary that defines the region types.
 
-.. _cablecell-decoration:
-
-Decoration
-----------
-
-The distribution and placement of dynamics on a cable cell is called the *decor* of a cell.
-A decor is composed of individual *decorations*, which associate a property or dynamic process
-with a :term:`region` or :term:`locset`.
-The choice of region or locset is reflected in the two broad classes of dynamics on cable cells:
-
-* *Painted dynamics* are applied to regions of a cell, and are associated with
-  an area of the membrane or volume of the cable.
-
-  * :ref:`Cable properties <cablecell-properties>`.
-  * :ref:`Density mechanisms <cablecell-density-mechs>`.
-  * :ref:`Ion species <cablecell-ions>`.
-
-* *Placed dynamics* are applied to locations on the cell, and are associated
-  with entities that can be counted.
-
-  * :ref:`Synapses <cablecell-synapses>`.
-  * :ref:`Gap junction sites <cablecell-gj-sites>`.
-  * :ref:`Threshold detectors <cablecell-threshold-detectors>` (spike detectors).
-  * :ref:`Stimuli <cablecell-stimuli>`.
-  * :ref:`Probes <cablecell-probes>`.
-
-Decorations are described by a **decor** object in Arbor.
-Provides facility for
-* setting properties defined over the whole cell
-* descriptions of dynamics applied to regions and locsets
-
-.. _cablecell-paint:
-
-Painted dynamics
-''''''''''''''''
-
-Painted dynamics are applied to a subset of the surface or volume of cells.
-They can be specified at three different levels:
-
-* *globally*: a global default for all cells in a model.
-* *per-cell*: override the global defaults for a specific cell.
-* *per-region*: specialize on specific cell regions.
-
-This hierarchical approach for resolving parameters and properties allows
-us to, for example, define a global default value for calcium concentration,
-then provide a different values on specific cell regions.
-
-Some dynamics, such as membrane capacitance and the initial concentration of ion species
-must be defined for all CVs. Others need only be applied where they are
-present, for example ion channels.
-The types of dynamics, and where they can be defined, are
-:ref:`tabulated <cablecell-painted-resolution>` below.
-
-.. _cablecell-painted-resolution:
-
-.. csv-table:: Painted property resolution options.
-   :widths: 20, 10, 10, 10
-
-                  ,       **region**, **cell**, **global**
-   cable properties,       ✓, ✓, ✓
-   ion initial conditions, ✓, ✓, ✓
-   density mechanism,       ✓, --, --
-   ion rev pot mechanism,  --, ✓, ✓
-   ion valence,            --, --, ✓
-
-If a property is defined at multiple levels, the most local definition will be chosen:
-a cell-local definition will override a global definition, and a definition on a region
-will override any cell-local or global definition on that region.
-
-.. warning::
-    If a property is defined on two regions that overlap, it is not possible to
-    deterministically choose the correct definition, and an error will be
-    raised during model instantiation.
-
-.. _cablecell-properties:
-
-1. Cable properties
-~~~~~~~~~~~~~~~~~~~
-
-There are four cable properties that must be defined everywhere on a cell:
-
-* *Vm*: Initial membrane voltage [mV].
-* *cm*: Membrane capacitance [F/m²].
-* *rL*: Axial resistivity of cable [Ω·cm].
-* *tempK*: Temperature [Kelvin].
-
-Each of the cable properties can be defined as a cell-wide default, that is then
-specialised on specific regions.
-
-.. note::
-
-    In Python, the :py:class:`decor` interface provides the :py:func:`decor.set_properties` method
-    for setting cell-wide defaults for properties, and the
-    :py:meth:`decor.paint` interface for overriding properties on specific regions.
-
-    .. code-block:: Python
-
-        import arbor
-
-        # Create an empty decor.
-        decor = arbor.decor
-
-        # Set cell-wide properties that will be applied by default to the entire cell.
-        decor.set_properties(Vm=-70, cm=0.02, rL=30, tempK=30+273.5)
-
-        # Override specific values on regions named "soma" and "axon".
-        decor.paint('"soma"', Vm=-50, cm=0.01, rL=35)
-        decor.paint('"axon"', Vm=-60, rL=40)
-
-.. _cablecell-density-mechs:
-
-3. Density mechanisms
-~~~~~~~~~~~~~~~~~~~~~
-
-Regions can have density mechanisms defined over their extents.
-Density mechanisms are :ref:`NMODL mechanisms <nmodl>`
-which describe biophysical processes. These are processes
-that are distributed in space, but whose behaviour is defined purely
-by the state of the cell and the process at any given point.
-
-The most common use for density mechanisms is to describe ion channel dynamics,
-for example the ``hh`` and ``pas`` mechanisms provided by NEURON and Arbor,
-which model classic Hodgkin-Huxley and passive leaky currents respectively.
-
-Mechanisms have two types of parameters that can be set by users
-
-* *Global* parameters are a single scalar value that is the
-  same everywhere a mechanism is defined.
-* *Range* parameters can vary spatially.
-
-Every mechanism is described by a string with its name, and
-an optional list of key-value pairs that define its range parameters.
-
-Because a global parameter is fixed over the entire spatial extent
-of a density mechanism, a new mechanism has to be created for every
-combination of global parameter values.
-
-Take for example a mechanism passive leaky dynamics:
-
-* Name: ``"passive"``.
-* Global variable: reversal potential ``"el"``.
-* Range variable: conductance ``"g"``.
-
-.. code-block:: Python
-
-    # Create pas mechanism with default parameter values (set in NMODL file).
-    m1 = arbor.mechanism('passive')
-
-    # Create default mechanism with custom conductance (range)
-    m2 = arbor.mechanism('passive', {'g': 0.1})
-
-    # Create a new pas mechanism with that changes reversal potential (global)
-    m3 = arbor.mechanism('passive/el=-45')
-
-    # Create an instance of the same mechanism, that also sets conductance (range)
-    m4 = arbor.mechanism('passive/el=-45', {'g': 0.1})
-
-    decor = arbor.decor()
-    decor.paint('"soma"', m1)
-    decor.paint('"soma"', m2) # error: can't place the same mechanism on overlapping regions
-    decor.paint('"soma"', m3) # error: can't have overlap between two instances of a mechanism
-                              #        with different values for a global parameter.
-
-.. _cablecell-ions:
-
-4. Ion species
-~~~~~~~~~~~~~~
-
-Arbor allows arbitrary ion species to be defined, to extend the default
-calcium, potassium and sodium ion species.
-A ion species is defined globally by its name and valence, which
-can't be overridden at cell or region level.
-
-.. csv-table:: Default ion species in Arbor
-   :widths: 15, 10, 10
-
-   **Ion**,     **name**, **Valence**
-   *Calcium*,   ca,       1
-   *Potassium*,  k,       1
-   *Sodium*,    na,       2
-
-Each ion species has the following properties:
-
-1. *internal concentration*: concentration on interior of the membrane [mM].
-2. *external concentration*: concentration on exterior of the membrane [mM].
-3. *reversal potential*: reversal potential [mV].
-4. *reversal potential mechanism*:  method for calculating reversal potential.
-
-Properties 1, 2 and 3 must be defined, and are used as the initial values for
-each quantity at the start of the simulation. They are specified globally,
-then specialized at cell and region level.
-
-The reversal potential of an ion species is calculated by an
-optional *reversal potential mechanism*.
-If no reversal potential mechanism is specified for an ion species, the initial
-reversal potential values are maintained for the course of a simulation.
-Otherwise, the mechanism does the work.
-
-but it is subject to some strict restrictions.
-Specifically, a reversal potential mechanism described in NMODL:
-
-* May not maintain any STATE variables.
-* Can only write to the "eX" value associated with an ion.
-* Can not be a POINT mechanism.
-
-Essentially, reversal potential mechanisms must be pure functions of cellular
-and ionic state.
-
-.. note::
-    Arbor imposes greater restrictions on mechanisms that update ionic reversal potentials
-    than NEURON. Doing so simplifies reasoning about interactions between
-    mechanisms that share ionic species, by virtue of having one mechanism, and one
-    mechanism only, that calculates reversal potentials according to concentrations
-    that the other mechanisms use and modify.
-
-If a reversal potential mechanism that writes to multiple ions,
-it must be given for either no ions, or all of the ions it writes.
-
-Arbor's default catalogue includes a *nernst* reversal potential, which is
-parameterized over a single ion. For example, to bind it to the calcium
-ion at the cell level using the Python interface:
-
-.. code-block:: Python
-
-    decor = arbor.decor()
-
-    # Method 1: create the mechanism explicitly.
-    ca = arbor.mechanism('nernst/x=ca')
-    decor.set_ion(ion='ca', method=ca)
-
-    # Method 2: set directly using a string description.
-    decor.set_ion(ion='ca', method='nernst/x=ca')
-
-    cell = arbor.cable_cell(morph, labels, decor)
-
-
-The NMODL code for the
-`Nernst mechanism  <https://github.com/arbor-sim/arbor/blob/master/mechanisms/mod/nernst.mod>`_
-can be used as a guide for how to calculate reversal potentials.
-
-While the reversal potential mechanism must be the same for a whole cell,
-the initial concentrations and reversal potential can be localized for regions
-using the *paint* interface:
-
-.. code-block:: Python
-
-    # decor is an arbor.decor
-
-    # It is possible to define all of the initial condition values
-    # for a ion species.
-    decor.paint('(tag 1)', arbor.ion('ca', int_con=2e-4, ext_con=2.5, rev_pot=114))
-
-    # Alternatively, one can selectively overwrite the global defaults.
-    decor.paint('(tag 2)', arbor.ion('ca', rev_pot=126)
-
-.. _cablecell-place:
-
-Placed dynamics
-''''''''''''''''
-
-Placed dynamics are discrete countable items that affect or record the dynamics of a cell,
-and are assigned to specific locations.
-
-.. _cablecell-synapses:
-
-1. Connection sites
-~~~~~~~~~~~~~~~~~~~
-
-Connections (synapses) are instances of NMODL POINT mechanisms. See also :ref:`modelconnections`.
-
-.. _cablecell-gj-sites:
-
-2. Gap junction sites
-~~~~~~~~~~~~~~~~~~~~~
-
-See :ref:`modelgapjunctions`.
-
-.. _cablecell-threshold-detectors:
-
-3. Threshold detectors (spike detectors).
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. _cablecell-stimuli:
-
-4. Stimuli
-~~~~~~~~~~
-
-.. _cablecell-probes:
-
-5. Probes
-~~~~~~~~~
-
-.. _cablecell-cv-policies:
-
-Discretisation and CV policies
-------------------------------
-
-.. glossary::
-
-  control volume
-  compartment
-    For the purpose of simulation, Arbor discretises cable cell :term:`morphologies <morphology>`
-    into control volumes, or CVs. Discretising happens through a :term:`CV policy`.
-    The CVs are uniquely determined by a set of *B* :term:`mlocation` boundary points. For each non-terminal
-    point *h* in *B*, there is a CV comprising the points {*x*: *h* ≤ *x* and ¬∃ *y* ∈ *B* s.t *h* < *y* < *x*},
-    where < and ≤ refer to the geometrical partial order of locations on the morphology. A fork
-    point is owned by a CV if and only if all of its corresponding representative locations are
-    in the CV.
-
-    'Compartment' is often used to refer to the substructure in cable cells; the 'compartment' in multi-compartment cells.
-    A compartment is equivalent to a control volume. We avoid using 'compartment' to avoid potential confusion
-    with :term:`segments <segment>` or :term:`branches <branch>`.
-
-.. Note::
-    In NEURON, discretisation is controlled through splitting a NEURON section into a
-    number of NEURON segments or NEURON compartments (`nseg`, `1` by default). Note that a NEURON segment/compartment is
-    not the same as an Arbor :term:`segment`!
-
-.. glossary::
-
-  CV policy
-    Generating the set of boundary points used by the simulator (discretisation) is controlled by a
-    :term:`CV <control volume>` policy. The default policy used to generate the set of boundary points is
-    ``cv_policy_fixed_per_branch(1)``.
-
-Specific CV policies are created by functions that take a ``region`` parameter
-that restrict the domain of applicability of that policy; this facility is useful
-for specifying differing discretisations on different parts of a cell morphology.
-When a CV policy is constrained in this manner, the boundary of the domain will
-always constitute part of the CV boundary point set.
-
-``cv_policy_single``
-''''''''''''''''''''
-
-Use one CV for each connected component of a region. When applied to the whole cell
-will generate single CV for the whole cell.
-
-``cv_policy_explicit``
-''''''''''''''''''''''
-
-Define CV boundaries according to a user-supplied set of locations, optionally
-restricted to a region.
-
-``cv_policy_every_segment``
-'''''''''''''''''''''''''''
-
-Use every segment in the morphology to define CVs, optionally
-restricted to a region. Each fork point in the domain is
-represented by a trivial CV.
-
-``cv_policy_fixed_per_branch``
-''''''''''''''''''''''''''''''
-
-For each branch in each connected component of the region (or the whole cell,
-if no region is specified), evenly distribute boundary points along the branch so
-as to produce an exact number of CVs per branch.
-
-By default, CVs will terminate at branch ends. An optional flag
-``cv_policy_flag::interior_forks`` can be passed to specify that fork points
-will be included in non-trivial, branched CVs and CVs covering terminal points
-in the morphology will be half-sized.
-
-``cv_policy_max_extent``
-''''''''''''''''''''''''
-
-As for ``cv_policy_fixed_per_branch``, save that the number of CVs on any
-given branch will be chosen to be the smallest number that ensures no
-CV will have an extent on the branch longer than a user-provided CV length.
-
-.. _cablecell-cv-composition:
-
-Composition of CV policies
-'''''''''''''''''''''''''''''
-
-CV policies can be combined with ``+`` and ``|`` operators. For two policies
-*A* and *B*, *A* + *B* is a policy which gives boundary points from both *A*
-and *B*, while *A* | *B* is a policy which gives all the boundary points from
-*B* together with those from *A* which do not within the domain of *B*.
-The domain of *A* + *B* and *A* | *B* is the union of the domains of *A* and
-*B*.
-
 
 API
 ---
diff --git a/doc/concepts/decor.rst b/doc/concepts/decor.rst
new file mode 100644
index 0000000000000000000000000000000000000000..f1696e7a6e01d86e0151281ffc28a92d577dea56
--- /dev/null
+++ b/doc/concepts/decor.rst
@@ -0,0 +1,301 @@
+.. _decor:
+
+.. _cablecell-decoration:
+
+Cable cell decoration
+=====================
+
+The distribution and placement of dynamics on a cable cell is called the *decor* of a cell.
+A decor is composed of individual *decorations*, which associate a property or dynamic process
+with a :term:`region` or :term:`locset`.
+The choice of region or locset is reflected in the two broad classes of dynamics on cable cells:
+
+* *Painted dynamics* are applied to regions of a cell, and are associated with
+  an area of the membrane or volume of the cable.
+
+  * :ref:`Cable properties <cablecell-properties>`.
+  * :ref:`Density mechanisms <cablecell-density-mechs>`.
+  * :ref:`Ion species <cablecell-ions>`.
+
+* *Placed dynamics* are applied to locations on the cell, and are associated
+  with entities that can be counted.
+
+  * :ref:`Synapses <cablecell-synapses>`.
+  * :ref:`Gap junction sites <cablecell-gj-sites>`.
+  * :ref:`Threshold detectors <cablecell-threshold-detectors>` (spike detectors).
+  * :ref:`Stimuli <cablecell-stimuli>`.
+  * :ref:`Probes <cablecell-probes>`.
+
+Decorations are described by a **decor** object in Arbor.
+Provides facility for
+* setting properties defined over the whole cell
+* descriptions of dynamics applied to regions and locsets
+
+.. _cablecell-paint:
+
+Painted dynamics
+----------------
+
+Painted dynamics are applied to a subset of the surface or volume of cells.
+They can be specified at three different levels:
+
+* *globally*: a global default for all cells in a model.
+* *per-cell*: override the global defaults for a specific cell.
+* *per-region*: specialize on specific cell regions.
+
+This hierarchical approach for resolving parameters and properties allows
+us to, for example, define a global default value for calcium concentration,
+then provide a different values on specific cell regions.
+
+Some dynamics, such as membrane capacitance and the initial concentration of ion species
+must be defined for all CVs. Others need only be applied where they are
+present, for example ion channels.
+The types of dynamics, and where they can be defined, are
+:ref:`tabulated <cablecell-painted-resolution>` below.
+
+.. _cablecell-painted-resolution:
+
+.. csv-table:: Painted property resolution options.
+   :widths: 20, 10, 10, 10
+
+                  ,       **region**, **cell**, **global**
+   cable properties,       ✓, ✓, ✓
+   ion initial conditions, ✓, ✓, ✓
+   density mechanism,       ✓, --, --
+   ion rev pot mechanism,  --, ✓, ✓
+   ion valence,            --, --, ✓
+
+If a property is defined at multiple levels, the most local definition will be chosen:
+a cell-local definition will override a global definition, and a definition on a region
+will override any cell-local or global definition on that region.
+
+.. warning::
+    If a property is defined on two regions that overlap, it is not possible to
+    deterministically choose the correct definition, and an error will be
+    raised during model instantiation.
+
+.. _cablecell-properties:
+
+1. Cable properties
+~~~~~~~~~~~~~~~~~~~
+
+There are four cable properties that must be defined everywhere on a cell:
+
+* *Vm*: Initial membrane voltage [mV].
+* *cm*: Membrane capacitance [F/m²].
+* *rL*: Axial resistivity of cable [Ω·cm].
+* *tempK*: Temperature [Kelvin].
+
+Each of the cable properties can be defined as a cell-wide default, that is then
+specialised on specific regions.
+
+.. note::
+
+    In Python, the :py:class:`decor` interface provides the :py:func:`decor.set_properties` method
+    for setting cell-wide defaults for properties, and the
+    :py:meth:`decor.paint` interface for overriding properties on specific regions.
+
+    .. code-block:: Python
+
+        import arbor
+
+        # Create an empty decor.
+        decor = arbor.decor
+
+        # Set cell-wide properties that will be applied by default to the entire cell.
+        decor.set_properties(Vm=-70, cm=0.02, rL=30, tempK=30+273.5)
+
+        # Override specific values on regions named "soma" and "axon".
+        decor.paint('"soma"', Vm=-50, cm=0.01, rL=35)
+        decor.paint('"axon"', Vm=-60, rL=40)
+
+.. _cablecell-density-mechs:
+
+3. Density mechanisms
+~~~~~~~~~~~~~~~~~~~~~
+
+Regions can have density mechanisms defined over their extents.
+Density mechanisms are :ref:`NMODL mechanisms <nmodl>`
+which describe biophysical processes. These are processes
+that are distributed in space, but whose behaviour is defined purely
+by the state of the cell and the process at any given point.
+
+The most common use for density mechanisms is to describe ion channel dynamics,
+for example the ``hh`` and ``pas`` mechanisms provided by NEURON and Arbor,
+which model classic Hodgkin-Huxley and passive leaky currents respectively.
+
+Mechanisms have two types of parameters that can be set by users
+
+* *Global* parameters are a single scalar value that is the
+  same everywhere a mechanism is defined.
+* *Range* parameters can vary spatially.
+
+Every mechanism is described by a string with its name, and
+an optional list of key-value pairs that define its range parameters.
+
+Because a global parameter is fixed over the entire spatial extent
+of a density mechanism, a new mechanism has to be created for every
+combination of global parameter values.
+
+Take for example a mechanism passive leaky dynamics:
+
+* Name: ``"passive"``.
+* Global variable: reversal potential ``"el"``.
+* Range variable: conductance ``"g"``.
+
+.. code-block:: Python
+
+    # Create pas mechanism with default parameter values (set in NMODL file).
+    m1 = arbor.mechanism('passive')
+
+    # Create default mechanism with custom conductance (range)
+    m2 = arbor.mechanism('passive', {'g': 0.1})
+
+    # Create a new pas mechanism with that changes reversal potential (global)
+    m3 = arbor.mechanism('passive/el=-45')
+
+    # Create an instance of the same mechanism, that also sets conductance (range)
+    m4 = arbor.mechanism('passive/el=-45', {'g': 0.1})
+
+    decor = arbor.decor()
+    decor.paint('"soma"', m1)
+    decor.paint('"soma"', m2) # error: can't place the same mechanism on overlapping regions
+    decor.paint('"soma"', m3) # error: can't have overlap between two instances of a mechanism
+                              #        with different values for a global parameter.
+
+.. _cablecell-ions:
+
+4. Ion species
+~~~~~~~~~~~~~~
+
+Arbor allows arbitrary ion species to be defined, to extend the default
+calcium, potassium and sodium ion species.
+A ion species is defined globally by its name and valence, which
+can't be overridden at cell or region level.
+
+.. csv-table:: Default ion species in Arbor
+   :widths: 15, 10, 10
+
+   **Ion**,     **name**, **Valence**
+   *Calcium*,   ca,       1
+   *Potassium*,  k,       1
+   *Sodium*,    na,       2
+
+Each ion species has the following properties:
+
+1. *internal concentration*: concentration on interior of the membrane [mM].
+2. *external concentration*: concentration on exterior of the membrane [mM].
+3. *reversal potential*: reversal potential [mV].
+4. *reversal potential mechanism*:  method for calculating reversal potential.
+
+Properties 1, 2 and 3 must be defined, and are used as the initial values for
+each quantity at the start of the simulation. They are specified globally,
+then specialized at cell and region level.
+
+The reversal potential of an ion species is calculated by an
+optional *reversal potential mechanism*.
+If no reversal potential mechanism is specified for an ion species, the initial
+reversal potential values are maintained for the course of a simulation.
+Otherwise, the mechanism does the work.
+
+but it is subject to some strict restrictions.
+Specifically, a reversal potential mechanism described in NMODL:
+
+* May not maintain any STATE variables.
+* Can only write to the "eX" value associated with an ion.
+* Can not be a POINT mechanism.
+
+Essentially, reversal potential mechanisms must be pure functions of cellular
+and ionic state.
+
+.. note::
+    Arbor imposes greater restrictions on mechanisms that update ionic reversal potentials
+    than NEURON. Doing so simplifies reasoning about interactions between
+    mechanisms that share ionic species, by virtue of having one mechanism, and one
+    mechanism only, that calculates reversal potentials according to concentrations
+    that the other mechanisms use and modify.
+
+If a reversal potential mechanism that writes to multiple ions,
+it must be given for either no ions, or all of the ions it writes.
+
+Arbor's default catalogue includes a *nernst* reversal potential, which is
+parameterized over a single ion. For example, to bind it to the calcium
+ion at the cell level using the Python interface:
+
+.. code-block:: Python
+
+    decor = arbor.decor()
+
+    # Method 1: create the mechanism explicitly.
+    ca = arbor.mechanism('nernst/x=ca')
+    decor.set_ion(ion='ca', method=ca)
+
+    # Method 2: set directly using a string description.
+    decor.set_ion(ion='ca', method='nernst/x=ca')
+
+    cell = arbor.cable_cell(morph, labels, decor)
+
+
+The NMODL code for the
+`Nernst mechanism  <https://github.com/arbor-sim/arbor/blob/master/mechanisms/mod/nernst.mod>`_
+can be used as a guide for how to calculate reversal potentials.
+
+While the reversal potential mechanism must be the same for a whole cell,
+the initial concentrations and reversal potential can be localized for regions
+using the *paint* interface:
+
+.. code-block:: Python
+
+    # decor is an arbor.decor
+
+    # It is possible to define all of the initial condition values
+    # for a ion species.
+    decor.paint('(tag 1)', arbor.ion('ca', int_con=2e-4, ext_con=2.5, rev_pot=114))
+
+    # Alternatively, one can selectively overwrite the global defaults.
+    decor.paint('(tag 2)', arbor.ion('ca', rev_pot=126)
+
+.. _cablecell-place:
+
+Placed dynamics
+---------------
+
+Placed dynamics are discrete countable items that affect or record the dynamics of a cell,
+and are assigned to specific locations.
+
+.. _cablecell-synapses:
+
+1. Connection sites
+~~~~~~~~~~~~~~~~~~~
+
+Connections (synapses) are instances of NMODL POINT mechanisms. See also :ref:`modelconnections`.
+
+.. _cablecell-gj-sites:
+
+2. Gap junction sites
+~~~~~~~~~~~~~~~~~~~~~
+
+See :ref:`modelgapjunctions`.
+
+.. _cablecell-threshold-detectors:
+
+3. Threshold detectors (spike detectors).
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. _cablecell-stimuli:
+
+4. Stimuli
+~~~~~~~~~~
+
+.. _cablecell-probes:
+
+5. Probes
+~~~~~~~~~
+
+
+API
+---
+
+* :ref:`Python <pycablecell-decor>`
+* :ref:`C++ <cppcablecell-decor>`
+
diff --git a/doc/concepts/index.rst b/doc/concepts/index.rst
index 4f9391c01512b82ce14898efe3d21086bcd384fe..a19204392d5ae0814fbb427aacfc97193c39435c 100644
--- a/doc/concepts/index.rst
+++ b/doc/concepts/index.rst
@@ -4,9 +4,7 @@ Concepts
 ========
 
 To learn how to use Arbor, it is helpful to understand some of its concepts.
-
 Arbor's design aims to enable scalability through abstraction.
-
 To achieve this, Arbor makes a distinction between the **description** of a model, and the
 **execution** of a model:
 a *recipe* describes a model, and a *simulation* is an executable instantiation of a model.
@@ -17,11 +15,11 @@ To be able to simulate a model, three basic steps need to be considered:
 2. Define the computational resources available to execute the model;
 3. Initiate and execute a simulation of the recipe on the chosen hardware resources.
 
-The python front-end further abstracts away some of these steps for single cell models, where users only need to
+The Python front-end further abstracts away some of these steps for single cell models, where users only need to
 describe the cell and simulation; and the details of the recipe and computational resources construction are
 handled under the hood. Generally speaking though, these 3 steps are the building blocks of an Arbor application.
 
-:ref:`Recipes <modelrecipe>` represent a set of neuron constructions and connections with *mechanisms* specifying
+:ref:`Recipes <modelrecipe>` represent a set of neuron constructions and connections with :ref:`mechanisms <mechanisms>` specifying
 ion channel and synapse dynamics in a cell-oriented manner. This has the advantage that cell data can be initiated
 in parallel.
 
@@ -56,3 +54,4 @@ meter manager is available.
    morphology
    labels
    mechanisms
+   decor
diff --git a/doc/concepts/morphology.rst b/doc/concepts/morphology.rst
index a72f053e41fd71753a243de1d1840a776dc59117..c0bef602605a62fb1fde0e37b07070027f38589b 100644
--- a/doc/concepts/morphology.rst
+++ b/doc/concepts/morphology.rst
@@ -739,8 +739,92 @@ The morphological data includes the actual morphology as well as the named segme
 For example, the above ``m1`` morphology has one named segment ``seg-0`` and one named group ``group-0`` that are
 both represented using Arbor's :ref:`region expressions <labels-expressions>`.
 
+.. _morph-cv-policies:
+
+Discretisation and CV policies
+------------------------------
+
+.. glossary::
+
+  control volume
+  compartment
+    For the purpose of simulation, Arbor discretises cable cell :term:`morphologies <morphology>`
+    into control volumes, or CVs. Discretising happens through a :term:`CV policy`.
+    The CVs are uniquely determined by a set of *B* :term:`mlocation` boundary points. For each non-terminal
+    point *h* in *B*, there is a CV comprising the points {*x*: *h* ≤ *x* and ¬∃ *y* ∈ *B* s.t *h* < *y* < *x*},
+    where < and ≤ refer to the geometrical partial order of locations on the morphology. A fork
+    point is owned by a CV if and only if all of its corresponding representative locations are
+    in the CV.
+
+    'Compartment' is often used to refer to the substructure in cable cells; the 'compartment' in multi-compartment cells.
+    A compartment is equivalent to a control volume. We avoid using 'compartment' to avoid potential confusion
+    with :term:`segments <segment>` or :term:`branches <branch>`.
+
+.. Note::
+    In NEURON, discretisation is controlled through splitting a NEURON section into a
+    number of NEURON segments or NEURON compartments (`nseg`, `1` by default). Note that a NEURON segment/compartment is
+    not the same as an Arbor :term:`segment`!
+
+.. glossary::
+
+  CV policy
+    Generating the set of boundary points used by the simulator (discretisation) is controlled by a
+    :term:`CV <control volume>` policy. The default policy used to generate the set of boundary points is
+    ``cv_policy_fixed_per_branch(1)``.
+
+Specific CV policies are created by functions that take a ``region`` parameter
+that restrict the domain of applicability of that policy; this facility is useful
+for specifying differing discretisations on different parts of a cell morphology.
+When a CV policy is constrained in this manner, the boundary of the domain will
+always constitute part of the CV boundary point set.
+
+.. rubric:: ``cv_policy_single``
+
+Use one CV for each connected component of a region. When applied to the whole cell
+will generate single CV for the whole cell.
+
+.. rubric:: ``cv_policy_explicit``
+
+Define CV boundaries according to a user-supplied set of locations, optionally
+restricted to a region.
+
+.. rubric:: ``cv_policy_every_segment``
+
+Use every segment in the morphology to define CVs, optionally
+restricted to a region. Each fork point in the domain is
+represented by a trivial CV.
+
+.. rubric:: ``cv_policy_fixed_per_branch``
+
+For each branch in each connected component of the region (or the whole cell,
+if no region is specified), evenly distribute boundary points along the branch so
+as to produce an exact number of CVs per branch.
+
+By default, CVs will terminate at branch ends. An optional flag
+``cv_policy_flag::interior_forks`` can be passed to specify that fork points
+will be included in non-trivial, branched CVs and CVs covering terminal points
+in the morphology will be half-sized.
+
+.. rubric:: ``cv_policy_max_extent``
+
+As for ``cv_policy_fixed_per_branch``, save that the number of CVs on any
+given branch will be chosen to be the smallest number that ensures no
+CV will have an extent on the branch longer than a user-provided CV length.
+
+.. _morph-cv-composition:
+
+Composition of CV policies
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+CV policies can be combined with ``+`` and ``|`` operators. For two policies
+*A* and *B*, *A* + *B* is a policy which gives boundary points from both *A*
+and *B*, while *A* | *B* is a policy which gives all the boundary points from
+*B* together with those from *A* which do not within the domain of *B*.
+The domain of *A* + *B* and *A* | *B* is the union of the domains of *A* and
+*B*.
+
 API
 ---
 
 * :ref:`Python <pymorph>`
-* :ref:`C++ <cppcablecell-morphology-construction>`
+* :ref:`C++ <cppmorphology>`
diff --git a/doc/concepts/recipe.rst b/doc/concepts/recipe.rst
index 95250eedff22908b43080378e2f00538f09fc39e..3b2a2edc677e2cfb3c67d39c9dac101d8a2647ad 100644
--- a/doc/concepts/recipe.rst
+++ b/doc/concepts/recipe.rst
@@ -66,7 +66,7 @@ on ``cell 2``. All this information is also registered via the recipe.
 
 There are additional docs on :ref:`cell kinds <modelcellkind>`;
 :ref:`cell descriptions <modelcelldesc>`; :ref:`network connections <modelconnections>`;
-:ref:`gap junction connections <modelgapjunctions>`; :ref:`probes <modelprobes>`
+:ref:`gap junction connections <modelgapjunctions>`; :ref:`probes <cablecell-probes>`
 
 The recipe is used to distribute the model across machines and is used in the simulation.
 Technical details of the recipe class are presented in the  :ref:`Python <pyrecipe>` and
diff --git a/doc/conf.py b/doc/conf.py
index 05d6fe4500788c28175b393d3f8a56ca13ef6a2a..84e772e01142dada33e6bb9957476c6a582f51bf 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -14,8 +14,7 @@ def setup(app):
 extensions = [
     'sphinx.ext.autodoc',
     'sphinx.ext.todo',
-    'sphinx.ext.mathjax',
-    'sphinx.ext.coverage'
+    'sphinx.ext.mathjax'
 ]
 source_suffix = '.rst'
 master_doc = 'index'
diff --git a/doc/cpp/cable_cell.rst b/doc/cpp/cable_cell.rst
index 14a2b412056e4ef823e2162441dca78b2e51b1bc..c8915434e41f814c3cb200a461aafae4238bff63 100644
--- a/doc/cpp/cable_cell.rst
+++ b/doc/cpp/cable_cell.rst
@@ -8,6 +8,8 @@ Cable cells
    has changed significantly; some of the documentation below is
    out of date.
 
+   The C++ cable cell documentation should have the same structure as the Python cable cell documentation.
+
 Cable cells, which use the :cpp:enum:`cell_kind` :cpp:expr:`cable`,
 represent morphologically-detailed neurons as 1-d trees, with
 electrical and biophysical properties mapped onto those trees.
@@ -577,103 +579,3 @@ with which it is associated.
 *  Metadata: ``std::vector<cable_probe_point_info>``. Target metadata for each
    associated target.
 
-
-.. _cv-policies:
-
-Discretisation and CV policies
-------------------------------
-
-The set of boundary points used by the simulator is determined by a
-:ref:`CV policy <cablecell-cv-policies>`. These are objects of type
-:cpp:class:`cv_policy`, which has the following public methods:
-
-.. cpp:class:: cv_policy
-
-   .. cpp:function:: locset cv_boundary_points(const cable_cell&) const
-
-   Return a locset describing the boundary points for CVs on the given cell.
-
-   .. cpp:function:: region domain() const
-
-   Give the subset of a cell morphology on which this policy has been declared,
-   as a morphological ``region`` expression.
-
-Specific CV policy objects are created by functions described below (strictly
-speaking, these are class constructors for classes are implicit converted to
-``cv_policy`` objects). These all take a ``region`` parameter that restrict the
-domain of applicability of that policy; this facility is useful for specifying
-differing discretisations on different parts of a cell morphology. When a CV
-policy is constrained in this manner, the boundary of the domain will always
-constitute part of the CV boundary point set.
-
-CV policies can be :ref:`composed <cablecell-cv-composition>` with ``+`` and ``|`` operators.
-For two policies
-*A* and *B*, *A* + *B* is a policy which gives boundary points from both *A*
-and *B*, while *A* | *B* is a policy which gives all the boundary points from
-*B* together with those from *A* which do not within the domain of *B*.
-The domain of *A* + *B* and *A* | *B* is the union of the domains of *A* and
-*B*.
-
-``cv_policy_single``
-^^^^^^^^^^^^^^^^^^^^
-
-.. code::
-
-    cv_policy_single(region domain = reg::all())
-
-Use one CV for the whole cell, or one for each connected component of the
-supplied domain.
-
-``cv_policy_explicit``
-^^^^^^^^^^^^^^^^^^^^^^
-
-.. code::
-
-   cv_policy_explicit(locset locs, region domain = reg::all())
-
-Use the points given by ``locs`` for CV boundaries, optionally restricted to the
-supplied domain.
-
-``cv_policy_every_segment``
-^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-.. code::
-
-   cv_policy_every_segment(region domain = reg::all())
-
-Use every segment in the morphology as a CV, optionally
-restricted to the supplied domain. Each fork point in the domain is
-represented by a trivial CV.
-
-``cv_policy_fixed_per_branch``
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-.. code::
-
-    cv_policy_fixed_per_branch(unsigned cv_per_branch, region domain, cv_policy_flag::value flags = cv_policy_flag::none);
-
-    cv_policy_fixed_per_branch(unsigned cv_per_branch, cv_policy_flag::value flags = cv_policy_flag::none):
-
-For each branch in each connected component of the domain (or the whole cell,
-if no domain is given), evenly distribute boundary points along the branch so
-as to produce exactly ``cv_per_branch`` CVs.
-
-By default, CVs will terminate at branch ends. If the flag
-``cv_policy_flag::interior_forks`` is given, fork points will be included in
-non-trivial, branched CVs and CVs covering terminal points in the morphology
-will be half-sized.
-
-
-``cv_policy_max_extent``
-^^^^^^^^^^^^^^^^^^^^^^^^
-
-.. code::
-
-    cv_policy_max_extent(double max_extent, region domain, cv_policy_flag::value flags = cv_policy_flag::none);
-
-    cv_policy_max_extent(double max_extent, cv_policy_flag::value flags = cv_policy_flag::none):
-
-As for ``cv_policy_fixed_per_branch``, save that the number of CVs on any
-given branch will be chosen to be the smallest number that ensures no
-CV will have an extent on the branch longer than ``max_extent`` micrometres.
-
diff --git a/doc/cpp/morphology.rst b/doc/cpp/morphology.rst
index 46c939f72a6ec2bf5be115b27190a1fcd6970e88..cc148054df77c5508b1aa84e2be0c033e2fd7a1e 100644
--- a/doc/cpp/morphology.rst
+++ b/doc/cpp/morphology.rst
@@ -1,7 +1,7 @@
 .. _cppmorphology:
 
-Cable cell morphologies
-=======================
+Cable cell morphology
+=====================
 
 Cell morphologies are required to describe a :ref:`cppcablecell`.
 Morphologies can be constructed directly, or read from a number of
@@ -313,4 +313,103 @@ not the absolute co-ordinate axes.
       Compose two isometries to form a new isometry which applies the intrinsic rotation of *b*, and
       then the intrinsic rotation of *a*, together with the translations of both *a* and *b*.
 
+.. _cv-policies:
+
+Discretisation and CV policies
+------------------------------
+
+The set of boundary points used by the simulator is determined by a
+:ref:`CV policy <morph-cv-policies>`. These are objects of type
+:cpp:class:`cv_policy`, which has the following public methods:
+
+.. cpp:class:: cv_policy
+
+   .. cpp:function:: locset cv_boundary_points(const cable_cell&) const
+
+   Return a locset describing the boundary points for CVs on the given cell.
+
+   .. cpp:function:: region domain() const
+
+   Give the subset of a cell morphology on which this policy has been declared,
+   as a morphological ``region`` expression.
+
+Specific CV policy objects are created by functions described below (strictly
+speaking, these are class constructors for classes are implicit converted to
+``cv_policy`` objects). These all take a ``region`` parameter that restrict the
+domain of applicability of that policy; this facility is useful for specifying
+differing discretisations on different parts of a cell morphology. When a CV
+policy is constrained in this manner, the boundary of the domain will always
+constitute part of the CV boundary point set.
+
+CV policies can be :ref:`composed <morph-cv-composition>` with ``+`` and ``|`` operators.
+For two policies
+*A* and *B*, *A* + *B* is a policy which gives boundary points from both *A*
+and *B*, while *A* | *B* is a policy which gives all the boundary points from
+*B* together with those from *A* which do not within the domain of *B*.
+The domain of *A* + *B* and *A* | *B* is the union of the domains of *A* and
+*B*.
+
+``cv_policy_single``
+^^^^^^^^^^^^^^^^^^^^
+
+.. code::
+
+    cv_policy_single(region domain = reg::all())
+
+Use one CV for the whole cell, or one for each connected component of the
+supplied domain.
+
+``cv_policy_explicit``
+^^^^^^^^^^^^^^^^^^^^^^
+
+.. code::
+
+   cv_policy_explicit(locset locs, region domain = reg::all())
+
+Use the points given by ``locs`` for CV boundaries, optionally restricted to the
+supplied domain.
+
+``cv_policy_every_segment``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code::
+
+   cv_policy_every_segment(region domain = reg::all())
+
+Use every segment in the morphology as a CV, optionally
+restricted to the supplied domain. Each fork point in the domain is
+represented by a trivial CV.
+
+``cv_policy_fixed_per_branch``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code::
+
+    cv_policy_fixed_per_branch(unsigned cv_per_branch, region domain, cv_policy_flag::value flags = cv_policy_flag::none);
+
+    cv_policy_fixed_per_branch(unsigned cv_per_branch, cv_policy_flag::value flags = cv_policy_flag::none):
+
+For each branch in each connected component of the domain (or the whole cell,
+if no domain is given), evenly distribute boundary points along the branch so
+as to produce exactly ``cv_per_branch`` CVs.
+
+By default, CVs will terminate at branch ends. If the flag
+``cv_policy_flag::interior_forks`` is given, fork points will be included in
+non-trivial, branched CVs and CVs covering terminal points in the morphology
+will be half-sized.
+
+
+``cv_policy_max_extent``
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code::
+
+    cv_policy_max_extent(double max_extent, region domain, cv_policy_flag::value flags = cv_policy_flag::none);
+
+    cv_policy_max_extent(double max_extent, cv_policy_flag::value flags = cv_policy_flag::none):
+
+As for ``cv_policy_fixed_per_branch``, save that the number of CVs on any
+given branch will be chosen to be the smallest number that ensures no
+CV will have an extent on the branch longer than ``max_extent`` micrometres.
+
 
diff --git a/doc/python/cable_cell.rst b/doc/python/cable_cell.rst
index 8d8f8143edefe0f08d70092f396c0b7cdb5b0888..707bcc0dd4f442274dfbb1bc862161ec696eaa63 100644
--- a/doc/python/cable_cell.rst
+++ b/doc/python/cable_cell.rst
@@ -5,186 +5,6 @@ Cable cells
 
 .. currentmodule:: arbor
 
-.. py:class:: decor
-
-    A decor object contains a description of the cell dynamics, to be applied
-    to a morphology when used to instantiate a :py:class:`cable_cell`
-
-    .. method:: __init__()
-
-        Construct an empty decor description.
-
-    Properties for which defaults can be defined over the entire cell, specifically
-    :ref:`cable properties <cablecell-properties>` and :ref:`ion properties <cablecell-ions>`,
-    are set with ``set_property`` and ``set_ion`` methods.
-
-    .. method:: set_property(Vm=None, cm=None, rL=None, tempK=None)
-
-        Set default values of cable properties on the whole cell.
-        Overrides the default global values, and can be overridden by painting
-        the values onto regions.
-
-        :param str region: description of the region.
-        :param Vm: Initial membrane voltage [mV].
-        :type Vm: float or None
-        :param cm: Membrane capacitance [F/m²].
-        :type cm: float or None
-        :param rL: Axial resistivity of cable [Ω·cm].
-        :type rL: float or None
-        :param tempK: Temperature [Kelvin].
-        :type tempK: float or None
-
-        .. code-block:: Python
-
-            # Set cell-wide values for properties for resistivity and capacitance
-            decor.set_property(rL=100, cm=0.1)
-
-    .. method:: set_ion(ion, int_con=None, ext_con=None, rev_pot=None, method=None)
-
-        Set default value for one or more properties of a specific ion on the whole cell.
-        Set the properties of ion species named ``ion`` that will be applied
-        by default everywhere on the cell. Species concentrations and reversal
-        potential can be overridden on specific regions using the paint interface,
-        while the method for calculating reversal potential is global for all
-        CVs in the cell, and can't be overriden locally.
-
-        :param str ion: description of the ion species.
-        :param float int_con: initial internal concentration [mM].
-        :type int_con: float or None.
-        :param float ext_con: initial external concentration [mM].
-        :type ext_con: float or None.
-        :param float rev_pot: reversal potential [mV].
-        :type rev_pot: float or None
-        :param method: method for calculating reversal potential.
-        :type method: :py:class:`mechanism` or None
-
-        .. code-block:: Python
-
-            # Set nernst reversal potential method for calcium.
-            decor.set_ion('ca', method=mech('nernst/x=ca'))
-
-            # Set reversal potential and concentration for sodium.
-            # The reversal potential is fixed, so we set the method to None.
-            decor.set_ion('na', int_con=5.0, rev_pot=70, method=None)
-
-    Verious specialisations of the ``paint`` method are available for setting properties
-    and mechanisms that are applied to regions.
-
-    .. method:: paint(region, Vm=None, cm=None, rL=None, tempK=None)
-
-        Set cable properties on a region.
-
-        :param str region: description of the region.
-        :param Vm: Initial membrane voltage [mV].
-        :type Vm: float or None
-        :param cm: Membrane capacitance [F/m²].
-        :type cm: float or None
-        :param rL: Axial resistivity of cable [Ω·cm].
-        :type rL: float or None
-        :param tempK: Temperature [Kelvin].
-        :type tempK: float or None
-
-        .. code-block:: Python
-
-            # Specialize resistivity on soma
-            decor.paint('"soma"', rL=100)
-            # Specialize resistivity and capacitance on the axon, where
-            # axon is defined using a region expression.
-            decor.paint('(tag 2)', cm=0.05, rL=80)
-
-    .. method:: paint(region, name, int_con=None, ext_con=None, rev_pot=None)
-        :noindex:
-
-        Set ion species properties initial conditions on a region.
-
-        :param str name: name of the ion species.
-        :param float int_con: initial internal concentration [mM].
-        :type int_con: float or None.
-        :param float ext_con: initial external concentration [mM].
-        :type ext_con: float or None.
-        :param float rev_pot: reversal potential [mV].
-        :type rev_pot: float or None
-
-    .. method:: paint(region, mechanism)
-        :noindex:
-
-        Apply a mechanism with a region.
-        Returns a unique identifier that can be used to query the local indexes (see :gen:`index`) assigned to the placed items on the cable cell.
-
-        :param str region: description of the region.
-        :param mechanism: the mechanism.
-        :type mechanism: :py:class:`mechanism`
-
-    .. method:: paint(region, mech_name)
-        :noindex:
-
-        Apply a mechanism with a region using the name of the mechanism.
-        The mechanism will use the parameter values set in the mechanism catalogue.
-        Returns a unique identifier that can be used to query the local indexes (see :gen:`index`) assigned to the placed items on the cable cell.
-
-        :param str region: description of the region.
-        :param str mechanism: the name of the mechanism.
-
-    .. method:: place(locations, const arb::mechanism_desc& d)
-
-        Place one instance of synapse described by ``mechanism`` to each location in ``locations``.
-        Returns a unique identifier that can be used to query the local indexes (see :gen:`index`) assigned to the placed items on the cable cell.
-
-        :param str locations: description of the locset.
-        :param str mechanism: the name of the mechanism.
-        :rtype: int
-
-    .. method:: place(locations, mechanism)
-        :noindex:
-
-        Place one instance of synapse described by ``mechanism`` to each location in ``locations``.
-        Returns a unique identifier that can be used to query the local indexes (see :gen:`index`) assigned to the placed items on the cable cell.
-
-        :param str locations: description of the locset.
-        :param mechanism: the mechanism.
-        :type mechanism: :py:class:`mechanism`
-        :rtype: int
-
-    .. method:: place(locations, site)
-        :noindex:
-
-        Place one gap junction site at each location in ``locations``.
-        Returns a unique identifier that can be used to query the local indexes (see :gen:`index`) assigned to the placed items on the cable cell.
-
-        :param str locations: description of the locset.
-        :param site: indicates a gap junction site..
-        :type site: :py:class:`gap_junction_site`
-        :rtype: int
-
-    .. method:: place(locations, stim)
-        :noindex:
-
-        Add a current stimulus at each location in ``locations``.
-        Returns a unique identifier that can be used to query the local indexes (see :gen:`index`) assigned to the placed items on the cable cell.
-
-        :param str locations: description of the locset.
-        :param stim: the current stim.
-        :type stim: :py:class:`i_clamp`
-        :rtype: int
-
-    .. method:: place(locations, d)
-        :noindex:
-
-        Add a voltage spike detector at each location in ``locations``.
-        Returns a unique identifier that can be used to query the local indexes (see :gen:`index`) assigned to the placed items on the cable cell.
-
-        :param str locations: description of the locset.
-        :param d: description of the detector.
-        :type d: :py:class:`threshold_detector`
-        :rtype: int
-
-    .. method:: discretization(policy)
-
-        Set the cv_policy used to discretise the cell into control volumes for simulation.
-
-        :param policy: The cv_policy.
-        :type policy: :py:class:`cv_policy`
-
 .. py:class:: cable_cell
 
     A cable cell is constructed from a :ref:`morphology <morph-morphology>`,
@@ -400,79 +220,3 @@ Ionic external concentration
 
    Metadata: the list of corresponding :class:`cable` objects.
 
-
-.. _pycablecell-cv-policies:
-
-Discretisation and CV policies
-------------------------------
-
-The set of boundary points used by the simulator is determined by a
-:ref:`CV policy <cablecell-cv-policies>`. These are objects of type
-:cpp:class:`cv_policy`, which has the following public methods:
-
-.. py:class:: cv_policy
-
-   .. attribute:: domain
-
-       A read only string expression describing the subset of a cell morphology
-       (region) on which this policy has been declared.
-
-   CV policies can be :ref:`composed <cablecell-cv-composition>` with
-   ``+`` and ``|`` operators.
-
-   .. code-block:: Python
-
-       # The plus operator applies 
-       policy = arbor.cv_policy_single('"soma"') + cv_policy('"dend"')
-
-       # The | operator uses CVs of length 10 μm everywhere, except
-       # on the soma, to which a single CV policy is applied.
-       policy = arbor.cv_policy_max_extent(10) | cv_policy_single('"soma"')
-
-Specific CV policy objects are created by functions described below.
-These all take a ``region`` parameter that restrict the
-domain of applicability of that policy; this facility is useful for specifying
-differing discretisations on different parts of a cell morphology. When a CV
-policy is constrained in this manner, the boundary of the domain will always
-constitute part of the CV boundary point set.
-
-.. py:function:: cv_policy_single(domain='(all)')
-
-    Use one CV for the whole cell, or one for each connected component of the
-    supplied domain.
-
-    .. code-block:: Python
-
-        # Use one CV for the entire cell (a single compartment model)
-        single_comp = arbor.cv_policy_single()
-
-        # Use a single CV for the soma.
-        single_comp_soma = arbor.cv_policy_single('"soma"')
-
-    :param str domain: The region on which the policy is applied.
-
-.. py:function:: cv_policy_every_segment(domain='(all)')
-
-    Use every sample point in the morphology definition as a CV boundary, optionally
-    restricted to the supplied domain. Each fork point in the domain is
-    represented by a trivial CV.
-
-    :param str domain: The region on which the policy is applied.
-
-.. py:function:: cv_policy_fixed_per_branch(cv_per_branch, domain='(all)')
-
-    For each branch in each connected component of the domain (or the whole cell,
-    if no domain is given), evenly distribute boundary points along the branch so
-    as to produce exactly ``cv_per_branch`` CVs.
-
-    :param int cv_per_branch: The number of CVs per branch.
-    :param str domain: The region on which the policy is applied.
-
-.. py:function:: cv_policy_max_extent(max_extent, domain='(all)')
-
-    As for :py:func:`cv_policy_fixed_per_branch`, save that the number of CVs on any
-    given branch will be chosen to be the smallest number that ensures no
-    CV will have an extent on the branch longer than ``max_extent`` micrometres.
-
-    :param float max_etent: The maximum length for generated CVs.
-    :param str domain: The region on which the policy is applied.
diff --git a/doc/python/decor.rst b/doc/python/decor.rst
new file mode 100644
index 0000000000000000000000000000000000000000..93ef1be705d3f3982bd3d301d1d73648afcecd50
--- /dev/null
+++ b/doc/python/decor.rst
@@ -0,0 +1,186 @@
+.. pycablecell-decor:
+
+Cable cell decoration
+=====================
+
+.. currentmodule:: arbor
+
+.. py:class:: decor
+
+    A decor object contains a description of the cell dynamics, to be applied
+    to a morphology when used to instantiate a :py:class:`cable_cell`
+
+    .. method:: __init__()
+
+        Construct an empty decor description.
+
+    Properties for which defaults can be defined over the entire cell, specifically
+    :ref:`cable properties <cablecell-properties>` and :ref:`ion properties <cablecell-ions>`,
+    are set with ``set_property`` and ``set_ion`` methods.
+
+    .. method:: set_property(Vm=None, cm=None, rL=None, tempK=None)
+
+        Set default values of cable properties on the whole cell.
+        Overrides the default global values, and can be overridden by painting
+        the values onto regions.
+
+        :param str region: description of the region.
+        :param Vm: Initial membrane voltage [mV].
+        :type Vm: float or None
+        :param cm: Membrane capacitance [F/m²].
+        :type cm: float or None
+        :param rL: Axial resistivity of cable [Ω·cm].
+        :type rL: float or None
+        :param tempK: Temperature [Kelvin].
+        :type tempK: float or None
+
+        .. code-block:: Python
+
+            # Set cell-wide values for properties for resistivity and capacitance
+            decor.set_property(rL=100, cm=0.1)
+
+    .. method:: set_ion(ion, int_con=None, ext_con=None, rev_pot=None, method=None)
+
+        Set default value for one or more properties of a specific ion on the whole cell.
+        Set the properties of ion species named ``ion`` that will be applied
+        by default everywhere on the cell. Species concentrations and reversal
+        potential can be overridden on specific regions using the paint interface,
+        while the method for calculating reversal potential is global for all
+        CVs in the cell, and can't be overriden locally.
+
+        :param str ion: description of the ion species.
+        :param float int_con: initial internal concentration [mM].
+        :type int_con: float or None.
+        :param float ext_con: initial external concentration [mM].
+        :type ext_con: float or None.
+        :param float rev_pot: reversal potential [mV].
+        :type rev_pot: float or None
+        :param method: method for calculating reversal potential.
+        :type method: :py:class:`mechanism` or None
+
+        .. code-block:: Python
+
+            # Set nernst reversal potential method for calcium.
+            decor.set_ion('ca', method=mech('nernst/x=ca'))
+
+            # Set reversal potential and concentration for sodium.
+            # The reversal potential is fixed, so we set the method to None.
+            decor.set_ion('na', int_con=5.0, rev_pot=70, method=None)
+
+    Verious specialisations of the ``paint`` method are available for setting properties
+    and mechanisms that are applied to regions.
+
+    .. method:: paint(region, Vm=None, cm=None, rL=None, tempK=None)
+
+        Set cable properties on a region.
+
+        :param str region: description of the region.
+        :param Vm: Initial membrane voltage [mV].
+        :type Vm: float or None
+        :param cm: Membrane capacitance [F/m²].
+        :type cm: float or None
+        :param rL: Axial resistivity of cable [Ω·cm].
+        :type rL: float or None
+        :param tempK: Temperature [Kelvin].
+        :type tempK: float or None
+
+        .. code-block:: Python
+
+            # Specialize resistivity on soma
+            decor.paint('"soma"', rL=100)
+            # Specialize resistivity and capacitance on the axon, where
+            # axon is defined using a region expression.
+            decor.paint('(tag 2)', cm=0.05, rL=80)
+
+    .. method:: paint(region, name, int_con=None, ext_con=None, rev_pot=None)
+        :noindex:
+
+        Set ion species properties initial conditions on a region.
+
+        :param str name: name of the ion species.
+        :param float int_con: initial internal concentration [mM].
+        :type int_con: float or None.
+        :param float ext_con: initial external concentration [mM].
+        :type ext_con: float or None.
+        :param float rev_pot: reversal potential [mV].
+        :type rev_pot: float or None
+
+    .. method:: paint(region, mechanism)
+        :noindex:
+
+        Apply a mechanism with a region.
+        Returns a unique identifier that can be used to query the local indexes (see :gen:`index`) assigned to the placed items on the cable cell.
+
+        :param str region: description of the region.
+        :param mechanism: the mechanism.
+        :type mechanism: :py:class:`mechanism`
+
+    .. method:: paint(region, mech_name)
+        :noindex:
+
+        Apply a mechanism with a region using the name of the mechanism.
+        The mechanism will use the parameter values set in the mechanism catalogue.
+        Returns a unique identifier that can be used to query the local indexes (see :gen:`index`) assigned to the placed items on the cable cell.
+
+        :param str region: description of the region.
+        :param str mechanism: the name of the mechanism.
+
+    .. method:: place(locations, const arb::mechanism_desc& d)
+
+        Place one instance of synapse described by ``mechanism`` to each location in ``locations``.
+        Returns a unique identifier that can be used to query the local indexes (see :gen:`index`) assigned to the placed items on the cable cell.
+
+        :param str locations: description of the locset.
+        :param str mechanism: the name of the mechanism.
+        :rtype: int
+
+    .. method:: place(locations, mechanism)
+        :noindex:
+
+        Place one instance of synapse described by ``mechanism`` to each location in ``locations``.
+        Returns a unique identifier that can be used to query the local indexes (see :gen:`index`) assigned to the placed items on the cable cell.
+
+        :param str locations: description of the locset.
+        :param mechanism: the mechanism.
+        :type mechanism: :py:class:`mechanism`
+        :rtype: int
+
+    .. method:: place(locations, site)
+        :noindex:
+
+        Place one gap junction site at each location in ``locations``.
+        Returns a unique identifier that can be used to query the local indexes (see :gen:`index`) assigned to the placed items on the cable cell.
+
+        :param str locations: description of the locset.
+        :param site: indicates a gap junction site..
+        :type site: :py:class:`gap_junction_site`
+        :rtype: int
+
+    .. method:: place(locations, stim)
+        :noindex:
+
+        Add a current stimulus at each location in ``locations``.
+        Returns a unique identifier that can be used to query the local indexes (see :gen:`index`) assigned to the placed items on the cable cell.
+
+        :param str locations: description of the locset.
+        :param stim: the current stim.
+        :type stim: :py:class:`i_clamp`
+        :rtype: int
+
+    .. method:: place(locations, d)
+        :noindex:
+
+        Add a voltage spike detector at each location in ``locations``.
+        Returns a unique identifier that can be used to query the local indexes (see :gen:`index`) assigned to the placed items on the cable cell.
+
+        :param str locations: description of the locset.
+        :param d: description of the detector.
+        :type d: :py:class:`threshold_detector`
+        :rtype: int
+
+    .. method:: discretization(policy)
+
+        Set the cv_policy used to discretise the cell into control volumes for simulation.
+
+        :param policy: The cv_policy.
+        :type policy: :py:class:`cv_policy`
diff --git a/doc/python/index.rst b/doc/python/index.rst
index 4aaca8276a1ae0d03eae4f9d03dd5ffae137722d..c45dedcd77d82fffd5068032a52a180f143d5ce8 100644
--- a/doc/python/index.rst
+++ b/doc/python/index.rst
@@ -51,4 +51,5 @@ These details are described and examples are given in the next sections :ref:`py
    morphology
    labels
    mechanisms
+   decor
    single_cell_model
diff --git a/doc/python/labels.rst b/doc/python/labels.rst
index 83ed8d340f4bb335e183a55e1091976f825cb957..3397c424123de3e79cd12a1da253120e60fab63c 100644
--- a/doc/python/labels.rst
+++ b/doc/python/labels.rst
@@ -1,7 +1,7 @@
 .. _pylabels:
 
-Cell labels
-===========
+Cable cell labels
+=================
 
 .. currentmodule:: arbor
 
diff --git a/doc/python/mechanisms.rst b/doc/python/mechanisms.rst
index 079d5ffbdae1a908c5a9fc34aae99a127fcb2ee0..f1825e85136c3e3ced419345a5312ab0d3b2b39c 100644
--- a/doc/python/mechanisms.rst
+++ b/doc/python/mechanisms.rst
@@ -1,7 +1,7 @@
 .. _py_mechanisms:
 
-Cell mechanisms
-===============
+Cable cell mechanisms
+=====================
 
 When :ref:`decorating <cablecell-decoration>` a cable cell, we use a :py:class:`mechanism` type to describe a
 mechanism that is to be painted or placed on the cable cell.
diff --git a/doc/python/morphology.rst b/doc/python/morphology.rst
index 8ffa546686379541589a8527da5df8e598d37965..40f7705e603858ed99310e97a4f95d9a7dc61339 100644
--- a/doc/python/morphology.rst
+++ b/doc/python/morphology.rst
@@ -1,9 +1,7 @@
 .. _pymorph:
 
-   .. 
-
-Cell morphology
-===============
+Cable cell morphology
+=====================
 
 .. currentmodule:: arbor
 
@@ -483,6 +481,81 @@ Cell morphology
        Note that rotations are composed as being with respect to the *intrinsic* coordinate system,
        while translations are always taken to be with respect to the *extrinsic* absolute coordinate system.
 
+.. _pymorph-cv-policies:
+
+Discretisation and CV policies
+------------------------------
+
+The set of boundary points used by the simulator is determined by a
+:ref:`CV policy <morph-cv-policies>`. These are objects of type
+:cpp:class:`cv_policy`, which has the following public methods:
+
+.. py:class:: cv_policy
+
+   .. attribute:: domain
+
+       A read only string expression describing the subset of a cell morphology
+       (region) on which this policy has been declared.
+
+   CV policies can be :ref:`composed <morph-cv-composition>` with
+   ``+`` and ``|`` operators.
+
+   .. code-block:: Python
+
+       # The plus operator applies
+       policy = arbor.cv_policy_single('"soma"') + cv_policy('"dend"')
+
+       # The | operator uses CVs of length 10 μm everywhere, except
+       # on the soma, to which a single CV policy is applied.
+       policy = arbor.cv_policy_max_extent(10) | cv_policy_single('"soma"')
+
+Specific CV policy objects are created by functions described below.
+These all take a ``region`` parameter that restrict the
+domain of applicability of that policy; this facility is useful for specifying
+differing discretisations on different parts of a cell morphology. When a CV
+policy is constrained in this manner, the boundary of the domain will always
+constitute part of the CV boundary point set.
+
+.. py:function:: cv_policy_single(domain='(all)')
+
+    Use one CV for the whole cell, or one for each connected component of the
+    supplied domain.
+
+    .. code-block:: Python
+
+        # Use one CV for the entire cell (a single compartment model)
+        single_comp = arbor.cv_policy_single()
+
+        # Use a single CV for the soma.
+        single_comp_soma = arbor.cv_policy_single('"soma"')
+
+    :param str domain: The region on which the policy is applied.
+
+.. py:function:: cv_policy_every_segment(domain='(all)')
+
+    Use every sample point in the morphology definition as a CV boundary, optionally
+    restricted to the supplied domain. Each fork point in the domain is
+    represented by a trivial CV.
+
+    :param str domain: The region on which the policy is applied.
+
+.. py:function:: cv_policy_fixed_per_branch(cv_per_branch, domain='(all)')
+
+    For each branch in each connected component of the domain (or the whole cell,
+    if no domain is given), evenly distribute boundary points along the branch so
+    as to produce exactly ``cv_per_branch`` CVs.
+
+    :param int cv_per_branch: The number of CVs per branch.
+    :param str domain: The region on which the policy is applied.
+
+.. py:function:: cv_policy_max_extent(max_extent, domain='(all)')
+
+    As for :py:func:`cv_policy_fixed_per_branch`, save that the number of CVs on any
+    given branch will be chosen to be the smallest number that ensures no
+    CV will have an extent on the branch longer than ``max_extent`` micrometres.
+
+    :param float max_etent: The maximum length for generated CVs.
+    :param str domain: The region on which the policy is applied.
 
 .. py:class:: neuroml_morph_data
 
@@ -564,4 +637,4 @@ Cell morphology
       could be found. Parse errors or an inconsistent representation will raise an exception.
 
       :param str morph_id: ID of the cell.
-      :rtype: optional(neuroml_morph_data)
\ No newline at end of file
+      :rtype: optional(neuroml_morph_data)