How to use the new render pass API for an external renderer?
Thanks to brecht's explanation in IRC I can now answer my own question:

Custom passes in compositor

update_render_passes is called by the compositor to display the custom passes as output sockets. In this method, register_pass should be used.

Example:

def update_render_passes(self, scene=None, renderlayer=None):
    self.register_pass(scene, renderlayer, "Combined", 4, "RGBA", 'COLOR')

    aovs = scene.luxcore.aovs

    if aovs.samplecount:
        self.register_pass(scene, renderlayer, "Samplecount", 1, "X", 'VALUE')
    if aovs.shading_normal:
        self.register_pass(scene, renderlayer, "Shading_Normal", 3, "XYZ", 'VECTOR')


Custom passes in image editor

add_pass on the other hand should be called at the start of the render method to add custom passes (before writing data into a render_result).

Example:

# Note: the Depth pass is already added by Blender
# If you add it again, it won't be displayed correctly 
# in the "Depth" view mode of the "Combined" pass
# in the image editor.

aovs = scene.luxcore.aovs

if aovs.samplecount:
    self.add_pass("Samplecount", 1, "X")
if aovs.shading_normal:
    self.add_pass("Shading_Normal", 3, "XYZ")


I hope this helps other developers of addons for external render engines.