All this is good, but what difference does it make ? Why don't we just use pmnc.execute.on("..._queue") ? The significant difference is in that call chains are undoable.
The question to which this feature is the answer is explained below.
If a request initiates some background processing which is logically organized as a sequence of persistent P2P messages from one cage to another, each step of processing will be independently retried, but once a step succeeds and processing goes on to the next step, this next step is still not guaranteed to succeed. And what do you do if it fails, hitting a fatal failure condition or running out of attempts ? The request processing is then half-done, with no chance of completion.
You thus can't complete the request processing, but you could undo it. Undoing the chain is initiated either when the next step runs out of attempts, or some application module being called explicitly requests an undo, for example
def target_method(*args, **kwargs):
    try:
        ...
    except WhoopsNoWayICanHandleThis, e:
        pmnc_chain.undo(str(e))
This is how it works. Each method you invoke using either of a call chain constructs
pmnc_chain.start("target_cage.target_module.target_method", *args, **kwargs)
pmnc_chain.next("target_cage.target_module.target_method", *args, **kwargs)
can have an undo companion, for example
def target_method(*args, **kwargs):
    ...
def target_method__undo(reason): # always suffixed with __undo
    ...
When a call to target_method succeeds and target_method__undo exists, the chain appends the undo method to its undo list and proceeds to the next call. In case the chain is being undone, it will go through its curent undo list backwards, calling the registered undo methods one by one. Each undo method is called through a separate queued P2P message call and is therefore retried too, having the same semantics as the original forward call.
Notice however that the undo method appears to have no connection to the original call, it has a single string argument reason, presumably the text of the original exception or other problem which has caused the undo. How do you know what to undo then ?
The answer is that the each method which needs something to be undone, should explicitly store the information required for its undo by its own means, presumably using the pmnc_safe facility or some external database. As a key to the undo storage you should use the unique chain identifier available as pmnc_chain.id, for example
def target_method(*args, **kwargs):
    try:
        do_stuff(*args, **kwargs)
    except:
        ...
    else:
        undo_information = ...
        pmnc_safe[pmnc_chain.id] = undo_information
        pmnc_chain.next("next_module.next_method", *next_args, **next_kwargs)

def target_method__undo(reason):
    undo_information = pmnc_safe[pmnc_chain.id]
    undo_stuff(undo_information)
This is simple enough, but keep in mind that there might be more than one target_cage's on the network, and therefore an original call can be executed by one of its instances but the undo call can be redirected to another. Then the undo information will not be available (because pmnc_safe is local not only to a cage, but to a specific module) and for such scenario you need to keep undo information in a shared database.