Issue with getting script to load on start up

Hi there, I am starting to learn how to make my own custom scripts for Blender. I have the following script, but for the life of me, I can’t figure out how to get it to load on start-up.

I have the script placed in a custom folder that Blender points to and I have also tried putting it in the Scripts - Start Up Folder
And I have tried enabling it via the text editor inside of Blender by enabling ‘Register’
Is there an issue with the script?

import bpy

# Operator to change UI type and set cycling options
class CHANGE_UI_TYPE_OPERATOR(bpy.types.Operator):
    bl_idname = "wm.change_ui_type"
    bl_label = "Change UI Type"
    
    ui_type: bpy.props.StringProperty()
    slice_id: bpy.props.IntProperty()

    def execute(self, context):
        global CYCLE_OPTIONS
        area = context.area
        area.ui_type = self.ui_type
        
        # Set up cycling options based on the slice
        CYCLE_OPTIONS_MAP = {
            1: ['FILES', 'ASSETS'],
            2: ['GeometryNodeTree'],
            3: ['CompositorNodeTree', 'TextureNodeTree'],
            4: ['VIEW_3D'],
            5: ['OUTLINER', 'PROPERTIES'],
            6: ['ShaderNodeTree'],
            7: ['UV', 'IMAGE_EDITOR'],
            8: ['SEQUENCE_EDITOR', 'CLIP_EDITOR'],
            9: ['CONSOLE', 'TEXT_EDITOR', 'SPREADSHEET', 'INFO'],
            10: ['FCURVES', 'DRIVERS'],
            11: ['TIMELINE', 'DOPESHEET'],
            12: ['NLA_EDITOR']
        }
        CYCLE_OPTIONS = CYCLE_OPTIONS_MAP.get(self.slice_id, [])

        return {'FINISHED'}

# Operator to cycle through UI types
class CYCLE_UI_TYPE_OPERATOR(bpy.types.Operator):
    bl_idname = "wm.cycle_ui_type"
    bl_label = "Cycle UI Type"

    def execute(self, context):
        global CYCLE_OPTIONS
        area = context.area
        
        if not hasattr(area, "ui_type") or not CYCLE_OPTIONS:
            return {'CANCELLED'}
        
        current_type = area.ui_type
        if current_type in CYCLE_OPTIONS:
            next_index = (CYCLE_OPTIONS.index(current_type) + 1) % len(CYCLE_OPTIONS)
            area.ui_type = CYCLE_OPTIONS[next_index]
        else:
            area.ui_type = CYCLE_OPTIONS[0]
        
        return {'FINISHED'}

# First Pie Menu
class CUSTOM_PIE_MENU(bpy.types.Menu):
    bl_label = "Custom Editor Pie Menu"
    bl_idname = "WM_MT_custom_pie_menu"
    
    def draw(self, context):
        layout = self.layout
        pie = layout.menu_pie()
        
        # Pie menu items
        op = pie.operator("wm.change_ui_type", text="File|Asset Browser", icon='FILE_FOLDER')
        op.ui_type = 'FILES'
        op.slice_id = 1
        op = pie.operator("wm.change_ui_type", text="Geometry Node Editor", icon='NODETREE')
        op.ui_type = 'GeometryNodeTree'
        op.slice_id = 2  
        op = pie.operator("wm.change_ui_type", text="Compositor|Texture Node Editor", icon='NODE_COMPOSITING')
        op.ui_type = 'CompositorNodeTree'
        op.slice_id = 3
        op = pie.operator("wm.change_ui_type", text="3D Viewport", icon='VIEW3D')
        op.ui_type = 'VIEW_3D'
        op.slice_id = 4
        op = pie.operator("wm.change_ui_type", text="Outliner|Properties", icon='OUTLINER')
        op.ui_type = 'OUTLINER'
        op.slice_id = 5
        op = pie.operator("wm.change_ui_type", text="Shader Editor", icon='NODE_MATERIAL')
        op.ui_type = 'ShaderNodeTree'
        op.slice_id = 6 
        

# Second Pie Menu
class CUSTOM_PIE_MENU2(bpy.types.Menu):
    bl_label = "Custom Editor Pie Menu2"
    bl_idname = "WM_MT_custom_pie_menu2"
    
    def draw(self, context):
        layout = self.layout
        pie = layout.menu_pie()
        
        # Pie menu items
        op = pie.operator("wm.change_ui_type", text="UV|Image Editor", icon='UV')
        op.ui_type = 'UV'
        op.slice_id = 7
        op = pie.operator("wm.change_ui_type", text="Video Sequencer|Movie Clip Editor", icon='SEQUENCE')
        op.ui_type = 'SEQUENCE_EDITOR'
        op.slice_id = 8   
        op = pie.operator("wm.change_ui_type", text="Python|Text|Spreadsheet|Info", icon='CONSOLE')
        op.ui_type = 'CONSOLE'
        op.slice_id = 9 
        op = pie.operator("wm.change_ui_type", text="Graph Editor|Drivers", icon='GRAPH')
        op.ui_type = 'FCURVES'
        op.slice_id = 10
        op = pie.operator("wm.change_ui_type", text="Timeline|Dopesheet Editor", icon='TIME')
        op.ui_type = 'TIMELINE'
        op.slice_id = 11 
        op = pie.operator("wm.change_ui_type", text="Non Linear Animation", icon='NLA')
        op.ui_type = 'NLA_EDITOR'
        op.slice_id = 12  
        
        

# Keymap Registration
def register_keymaps():
    wm = bpy.context.window_manager
    kc = wm.keyconfigs.addon
    if kc:
        km = kc.keymaps.new(name="Window", space_type="EMPTY")
        
        # Pie Menu 1 Hotkey
        kmi = km.keymap_items.new("wm.call_menu_pie", "NUMPAD_0", "PRESS", shift=True)
        kmi.properties.name = CUSTOM_PIE_MENU.bl_idname
        
        # Pie Menu 2 Hotkey
        kmi = km.keymap_items.new("wm.call_menu_pie", "NUMPAD_0", "PRESS", shift=True, ctrl=True)
        kmi.properties.name = CUSTOM_PIE_MENU2.bl_idname
        
        # Cycle Operator Hotkey
        km.keymap_items.new("wm.cycle_ui_type", "NUMPAD_PERIOD", "PRESS", shift=True)

# Registration
classes = [
    CHANGE_UI_TYPE_OPERATOR,
    CYCLE_UI_TYPE_OPERATOR,
    CUSTOM_PIE_MENU,
    CUSTOM_PIE_MENU2
]

def register():
    for cls in classes:
        bpy.utils.register_class(cls)
    register_keymaps()

def unregister():
    for cls in reversed(classes):
        bpy.utils.unregister_class(cls)

    # Unregister keymaps
    wm = bpy.context.window_manager
    kc = wm.keyconfigs.addon
    if kc:
        km = kc.keymaps.get("Window")
        if km:
            for kmi in list(km.keymap_items):
                if kmi.idname in {"wm.call_menu_pie", "wm.cycle_ui_type"}:
                    km.keymap_items.remove(kmi)

# Global variable for cycling options
CYCLE_OPTIONS = []

if __name__ == "__main__":
    register()

You have to save it in your default startup file and turn on the Register checkbox in the Text menu

Actually it should work either way (just tested) - either by putting to “startup” directory (then it will run as __main__ any time you open Blender and will register your operators) or by putting to startup file and turn or “Register” checkbox - then it will run every time you open startup file (e.g. when you create a new file in the same session). So using “startup” directory is preferable since there will be no errors registration errors every time you start a new file because operators were registered before.

Are you sure there are no console errors or anything?
You can simplify the entire script with just a print("hello") line for debugging purposes to figure when it’s executed and when it’s not, then put the script to “startup” or use “register” checkbox and check system console to see if there’s any output.