First pass on observer API