How to define subcommands for a `@main` command in a Julia app?

Maybe this example can help you to start with:

module SimpleCalcProject

using TOML

const version = TOML.parsefile("Project.toml")["version"]

function print_help()
    println(Core.stdout,
        """
SimpleCalcProject CLI
Usage:
  simplecalc <command> [args...]

Commands:
  add <a> <b>        Add two numbers
  sub <a> <b>        Subtract second number from first
  sum <nums...>      Sum all numbers (sum)

Options:
  -h, --help         Show this help message
  -v, --version      Show version information
""")
end

function print_version()
    println(Core.stdout, "SimpleCalcProject CLI v$(version)")
end

function parse_numbers(remaining)
    try
        tryparse.(Float64, remaining)::Vector{Float64}
    catch 
        println(Core.stdout, "Error: invalid argument(s)")
        Float64[]
    end
end

function print_calculation(cmd, numbers)
    if cmd == "add" && length(numbers) == 2
        println(Core.stdout, "Result: $(numbers[1] + numbers[2])")
    elseif cmd == "sub" && length(numbers) == 2
        println(Core.stdout, "Result: $(numbers[1] - numbers[2])")
    elseif cmd == "sum" && !isempty(numbers)
        println(Core.stdout, "Result: $(sum(numbers))")
    else
        println(Core.stdout, "Invalid command or arguments. Try --help.")
    end
end

function cli(args)

    if isempty(args)
        print_help()
        return 0
    end

    cmd = args[1]

    if cmd in ["--help", "-h"]
        print_help()
        return 0
    elseif cmd in ["--version", "-v"]
        print_version()
        return 0
    end
    
    remaining = args[2:end]
    
    numbers = parse_numbers(remaining)
    
    length(numbers) == 0 && return 1
    
    print_calculation(cmd, numbers)
    
    return 0
end

function @main(ARGS)
    return cli(ARGS)
end

end