diff --git a/.gitignore b/.gitignore
index d4785d9c..941e4d46 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
 .DS_Store
 .vscode
+.idea
 .env
 .venv
 .swp
diff --git a/README.md b/README.md
index 1f5cf8fd..bfb66d53 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,18 @@ curl -fsSL https://ollama.com/install.sh | sh
 
 The official [Ollama Docker image](https://hub.docker.com/r/ollama/ollama) `ollama/ollama` is available on Docker Hub.
 
+### Autocompletion
+To enable autocompletion generate completion script for your shell (`bash`, `zsh`, `fish`):
+```
+echo "source <(./ollama completion bash)" >> ~/.bashrc # Required bash-completion package installed
+```
+```
+echo '[[ $commands[ollama] ]] && source <(ollama completion zsh)' >> ~/.zshrc
+```
+```
+ollama completion fish > ~/.config/fish/completions/ollama.fish
+```
+
 ### Libraries
 
 - [ollama-python](https://github.com/ollama/ollama-python)
diff --git a/cmd/cmd.go b/cmd/cmd.go
index b8c9c640..0feffde8 100644
--- a/cmd/cmd.go
+++ b/cmd/cmd.go
@@ -1279,6 +1279,52 @@ func checkServerHeartbeat(cmd *cobra.Command, _ []string) error {
 	return nil
 }
 
+func completionHandler(cmd *cobra.Command, args []string) error {
+	var err error
+	switch args[0] {
+	case "bash":
+		err = cmd.Root().GenBashCompletion(os.Stdout)
+	case "zsh":
+		err = cmd.Root().GenZshCompletion(os.Stdout)
+	case "fish":
+		err = cmd.Root().GenFishCompletion(os.Stdout, true)
+	default:
+		err = errors.New("unsupported shell. Supported shells: zsh, fish, bash")
+	}
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "error: %s\n", err)
+	}
+	return nil
+}
+
+func autocompleteModelName(_ *cobra.Command, _ []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+	log.Printf("autocomplete: %s", toComplete)
+	client, err := api.ClientFromEnvironment()
+	if err != nil {
+		return nil, cobra.ShellCompDirectiveError
+	}
+
+	models, err := client.List(context.Background())
+	if err != nil {
+		return nil, cobra.ShellCompDirectiveError
+	}
+
+	var data []string
+
+	for _, m := range models.Models {
+		log.Printf("model: %s", m.Name)
+		if strings.HasPrefix(m.Name, toComplete) {
+			data = append(data, m.Name[:strings.IndexByte(m.Name, ':')])
+		}
+	}
+
+	return data, cobra.ShellCompDirectiveNoFileComp
+}
+
+func doNotAutocomplete(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
+	return []string{}, cobra.ShellCompDirectiveNoFileComp
+}
+
 func versionHandler(cmd *cobra.Command, _ []string) {
 	client, err := api.ClientFromEnvironment()
 	if err != nil {
@@ -1343,22 +1389,24 @@ func NewCLI() *cobra.Command {
 	rootCmd.Flags().BoolP("version", "v", false, "Show version information")
 
 	createCmd := &cobra.Command{
-		Use:     "create MODEL",
-		Short:   "Create a model from a Modelfile",
-		Args:    cobra.ExactArgs(1),
-		PreRunE: checkServerHeartbeat,
-		RunE:    CreateHandler,
+		Use:               "create MODEL",
+		Short:             "Create a model from a Modelfile",
+		Args:              cobra.ExactArgs(1),
+		PreRunE:           checkServerHeartbeat,
+		RunE:              CreateHandler,
+		ValidArgsFunction: doNotAutocomplete,
 	}
 
 	createCmd.Flags().StringP("file", "f", "", "Name of the Modelfile (default \"Modelfile\"")
 	createCmd.Flags().StringP("quantize", "q", "", "Quantize model to this level (e.g. q4_0)")
 
 	showCmd := &cobra.Command{
-		Use:     "show MODEL",
-		Short:   "Show information for a model",
-		Args:    cobra.ExactArgs(1),
-		PreRunE: checkServerHeartbeat,
-		RunE:    ShowHandler,
+		Use:               "show MODEL",
+		Short:             "Show information for a model",
+		Args:              cobra.ExactArgs(1),
+		PreRunE:           checkServerHeartbeat,
+		RunE:              ShowHandler,
+		ValidArgsFunction: autocompleteModelName,
 	}
 
 	showCmd.Flags().Bool("license", false, "Show license of a model")
@@ -1368,11 +1416,12 @@ func NewCLI() *cobra.Command {
 	showCmd.Flags().Bool("system", false, "Show system message of a model")
 
 	runCmd := &cobra.Command{
-		Use:     "run MODEL [PROMPT]",
-		Short:   "Run a model",
-		Args:    cobra.MinimumNArgs(1),
-		PreRunE: checkServerHeartbeat,
-		RunE:    RunHandler,
+		Use:               "run MODEL [PROMPT]",
+		Short:             "Run a model",
+		Args:              cobra.MinimumNArgs(1),
+		PreRunE:           checkServerHeartbeat,
+		RunE:              RunHandler,
+		ValidArgsFunction: autocompleteModelName,
 	}
 
 	runCmd.Flags().String("keepalive", "", "Duration to keep a model loaded (e.g. 5m)")
@@ -1390,39 +1439,43 @@ func NewCLI() *cobra.Command {
 	}
 
 	serveCmd := &cobra.Command{
-		Use:     "serve",
-		Aliases: []string{"start"},
-		Short:   "Start ollama",
-		Args:    cobra.ExactArgs(0),
-		RunE:    RunServer,
+		Use:               "serve",
+		Aliases:           []string{"start"},
+		Short:             "Start ollama",
+		Args:              cobra.ExactArgs(0),
+		RunE:              RunServer,
+		ValidArgsFunction: doNotAutocomplete,
 	}
 
 	pullCmd := &cobra.Command{
-		Use:     "pull MODEL",
-		Short:   "Pull a model from a registry",
-		Args:    cobra.ExactArgs(1),
-		PreRunE: checkServerHeartbeat,
-		RunE:    PullHandler,
+		Use:               "pull MODEL",
+		Short:             "Pull a model from a registry",
+		Args:              cobra.ExactArgs(1),
+		PreRunE:           checkServerHeartbeat,
+		RunE:              PullHandler,
+		ValidArgsFunction: doNotAutocomplete,
 	}
 
 	pullCmd.Flags().Bool("insecure", false, "Use an insecure registry")
 
 	pushCmd := &cobra.Command{
-		Use:     "push MODEL",
-		Short:   "Push a model to a registry",
-		Args:    cobra.ExactArgs(1),
-		PreRunE: checkServerHeartbeat,
-		RunE:    PushHandler,
+		Use:               "push MODEL",
+		Short:             "Push a model to a registry",
+		Args:              cobra.ExactArgs(1),
+		PreRunE:           checkServerHeartbeat,
+		RunE:              PushHandler,
+		ValidArgsFunction: autocompleteModelName,
 	}
 
 	pushCmd.Flags().Bool("insecure", false, "Use an insecure registry")
 
 	listCmd := &cobra.Command{
-		Use:     "list",
-		Aliases: []string{"ls"},
-		Short:   "List models",
-		PreRunE: checkServerHeartbeat,
-		RunE:    ListHandler,
+		Use:               "list",
+		Aliases:           []string{"ls"},
+		Short:             "List models",
+		PreRunE:           checkServerHeartbeat,
+		RunE:              ListHandler,
+		ValidArgsFunction: doNotAutocomplete,
 	}
 
 	psCmd := &cobra.Command{
@@ -1433,19 +1486,33 @@ func NewCLI() *cobra.Command {
 	}
 
 	copyCmd := &cobra.Command{
-		Use:     "cp SOURCE DESTINATION",
-		Short:   "Copy a model",
-		Args:    cobra.ExactArgs(2),
-		PreRunE: checkServerHeartbeat,
-		RunE:    CopyHandler,
+		Use:               "cp SOURCE DESTINATION",
+		Short:             "Copy a model",
+		Args:              cobra.ExactArgs(2),
+		PreRunE:           checkServerHeartbeat,
+		RunE:              CopyHandler,
+		ValidArgsFunction: autocompleteModelName,
 	}
 
 	deleteCmd := &cobra.Command{
-		Use:     "rm MODEL [MODEL...]",
-		Short:   "Remove a model",
-		Args:    cobra.MinimumNArgs(1),
-		PreRunE: checkServerHeartbeat,
-		RunE:    DeleteHandler,
+		Use:               "rm MODEL [MODEL...]",
+		Short:             "Remove a model",
+		Args:              cobra.MinimumNArgs(1),
+		PreRunE:           checkServerHeartbeat,
+		RunE:              DeleteHandler,
+		ValidArgsFunction: autocompleteModelName,
+	}
+
+	completionCmd := &cobra.Command{
+		Use:                   "completion [bash|zsh|fish]",
+		Short:                 "Generate completion scripts",
+		DisableFlagsInUseLine: true,
+		Hidden:                true,
+		Args:                  cobra.ExactArgs(1),
+		RunE:                  completionHandler,
+		ValidArgsFunction: func(_ *cobra.Command, _ []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+			return []string{"bash", "zsh", "fish"}, cobra.ShellCompDirectiveNoFileComp
+		},
 	}
 
 	envVars := envconfig.AsMap()
@@ -1503,6 +1570,7 @@ func NewCLI() *cobra.Command {
 		psCmd,
 		copyCmd,
 		deleteCmd,
+		completionCmd,
 	)
 
 	return rootCmd