split the Command runner into pure and IO versions