func application() *cli.App {
	inputFlag := cli.StringFlag{
		Name:  "i",
		Usage: "Specify file input type. Options are gff, gbk/gb, and json. For use with pipes.",
	}
	outputFlag := cli.StringFlag{
		Name:  "o",
		Value: "json",
		Usage: "Specify file output type or path. Defaults to json.",
	}
	app := &cli.App{
		Name:  "poly",
		Usage: "A command line utility for engineering organisms.",
		Flags: []cli.Flag{
			&cli.BoolFlag{
				Name:  "y",
				Usage: "Answers yes for all confirmations before doing something possibly destructive.",
			},
			&inputFlag,
			&outputFlag,
		},
		Commands: []*cli.Command{
			{
				Name:    "convert",
				Aliases: []string{"c"},
				Usage:   "Convert a single file or set of files from one type to another. Genbank to Json, Json to Gff, etc.",
				Flags: []cli.Flag{
					&inputFlag,
					&outputFlag,
				},
				Action: func(c *cli.Context) error {
					err := convertCommand(c)
					return err
				},
			},
			{
				Name:    "hash",
				Aliases: []string{"ha"},
				Usage:   "Hash a sequence while accounting for circularity using SeqhashV1.",
				Flags: []cli.Flag{
					&inputFlag,
				},
				Action: func(c *cli.Context) error {
					err := hashCommand(c)
					return err
				},
			},
		},  
	}  
	return app
}
application is a function that defines instances of our app. it's where we template commands and where initial arg parsing occurs.
package main
import (
	"log"
	"os"
	"github.com/urfave/cli/v2"
)
func main() {
	run(os.Args)
}
func run(args []string) {
	app := application()
	err := app.Run(os.Args)  
	if err != nil {
		log.Fatal(err)
	}
}