How to make custom "create options" panel in bottom left I want a panel in the bottom left to accept &quot;create options&quot;; like what you get when adding an mesh object.
I've got a panel but no combination of bl_space_type bl_region_type and bl_context I try seems to work

I found the answer to this. Panels down there are associated with the current operation.  https://b3d.interplanety.org/en/calling-functions-by-pressing-buttons-in-blender-custom-ui/
Though I can't figure out the relationship between the operation and the panel e.g. how Blender knows which panel to show for the operation.  I also haven't found a way from python to call the operator and get it to show the UI e.g. if I do bpy.ops.test.test_op() it runs my operator but never shows the UI; I want to show the UI, like it does when run using F3
While mountainstorm's answer is functional, you actually don't need so much to get the redo UI to show up. (At least not in Blender 2.9 - I haven't tried this in earlier versions but the release notes don't indicate any changes around this.)
The requirements are simply:

Your operator's bl_options must include 'REGISTER' and 'UNDO'. (Register indicates to show the redo panel; undo is needed because redo is just an undo of the last operation, followed by re-execution of the operator.)
Your operator needs to have at least one property defined.

That means this is a minimal operator that will display the redo panel when executed:
import bpy

class EXAMPLE_OT_DefaultIntOperator(bpy.types.Operator):
    bl_idname = &quot;example.redo_operator&quot;
    bl_label = &quot;Example Redo Operator&quot;
    bl_options = {'REGISTER', 'UNDO'}

    my_prop: bpy.props.IntProperty(name = &quot;My Property&quot;)

    def execute(self, context):
        self.report({'INFO'}, f&quot;my_prop: {self.my_prop}&quot;)
        return {'FINISHED'}


This uses the default operator drawing logic, with one property per row. If you want, you can also control exactly what's drawn by defining the draw(self, context) method in your operator. The following code defines two operators, one matching the earlier example, and another using a custom draw method to enable/disable a property input based on another property's value.
import bpy

class EXAMPLE_OT_DefaultIntOperator(bpy.types.Operator):
    bl_idname = &quot;example.redo_operator&quot;
    bl_label = &quot;Example Redo Operator&quot;
    bl_options = {'REGISTER', 'UNDO'}

    my_prop: bpy.props.IntProperty(name = &quot;My Property&quot;)

    def execute(self, context):
        self.report({'INFO'}, f&quot;my_prop: {self.my_prop}&quot;)
        return {'FINISHED'}

class EXAMPLE_OT_CustomDrawOperator(bpy.types.Operator):
    bl_idname = &quot;example.redo_operator_with_draw&quot;
    bl_label = &quot;Example Redo With Custom Draw&quot;
    bl_options = {'REGISTER', 'UNDO'}

    dependent_prop: bpy.props.IntProperty(name = &quot;My Property&quot;)
    flag_prop: bpy.props.BoolProperty(name = &quot;Use Int&quot;)

    def execute(self, context):
        msg = f&quot;dependent_prop: {self.dependent_prop}&quot; if self.flag_prop else &quot;Nothing to report&quot;
        self.report({'INFO'}, msg)

        return {'FINISHED'}
    
    def draw(self, context):
        self.layout.use_property_split = True

        row = self.layout.row()
        row.prop(self, &quot;flag_prop&quot;)
        
        sub = row.row()
        sub.enabled = self.flag_prop
        sub.prop(self, &quot;dependent_prop&quot;, text=&quot;&quot;)

bpy.utils.register_class(EXAMPLE_OT_DefaultIntOperator)
bpy.utils.register_class(EXAMPLE_OT_CustomDrawOperator)

# If you're using Blender 2.9, operators only show in search if they're registered in a menu, 
# so you need everything below this point. You can find your ops in the Object menu within the 3D viewport.
# See https://wiki.blender.org/wiki/Reference/Release_Notes/2.90/Python_API#Compatibility
def basic_op_menu_func(self, context):
    self.layout.operator(&quot;example.redo_operator&quot;)

def custom_op_menu_func(self, context):
    self.layout.operator(&quot;example.redo_operator_with_draw&quot;)

bpy.types.VIEW3D_MT_object.append(basic_op_menu_func)
bpy.types.VIEW3D_MT_object.append(custom_op_menu_func)


As mountainstorm noted, you may need to override the execution context if you're calling the operator from a script and still want the redo panel to appear. If you're just creating a UI button via UILayout.operator, or executing your operator from a menu, then this should be unnecessary.