diff --git a/pkg/omf/cli/omf.install_package.fish b/pkg/omf/cli/omf.install_package.fish
deleted file mode 100644
index 846e7785d5fc23776141a47c35eca99c3be4b379..0000000000000000000000000000000000000000
--- a/pkg/omf/cli/omf.install_package.fish
+++ /dev/null
@@ -1,5 +0,0 @@
-function omf.install_package
-  for search in $argv
-    omf.install $search
-  end
-end
diff --git a/pkg/omf/cli/omf.list_installed_packages.fish b/pkg/omf/cli/omf.list_installed_packages.fish
deleted file mode 100644
index a3cc51cca0dd182bfb6645920190f5fe1d2b8703..0000000000000000000000000000000000000000
--- a/pkg/omf/cli/omf.list_installed_packages.fish
+++ /dev/null
@@ -1,5 +0,0 @@
-# Backwards-compatible wrapper function
-# TODO: Remove it after 2015, December 13
-function omf.list_installed_packages
-  omf.packages.list --installed --plugin
-end
diff --git a/pkg/omf/cli/omf.new.fish b/pkg/omf/cli/omf.new.fish
deleted file mode 100644
index 2b226193d4dd7b40428bb0b03492b5426579de52..0000000000000000000000000000000000000000
--- a/pkg/omf/cli/omf.new.fish
+++ /dev/null
@@ -1,39 +0,0 @@
-function omf.new -a option name
-  switch $option
-    case "p" "pkg" "pack" "packg" "package"
-      set option "pkg"
-    case "t" "th" "the" "thm" "theme" "themes"
-      set option "themes"
-    case "*"
-      echo (omf::err)"$option is not a valid option."(omf::off) 1^&2
-      return $OMF_INVALID_ARG
-  end
-
-  if not omf.util_valid_package "$name"
-    echo (omf::err)"$name is not a valid package/theme name"(omf::off) 1^&2
-    return $OMF_INVALID_ARG
-  end
-
-  if set -l dir (omf.util_mkdir "$option/$name")
-    cd $dir
-
-    set -l github (git config github.user)
-    test -z "$github"; and set github "{{USER}}"
-
-    set -l user (git config user.name)
-    test -z "$user"; and set user "{{USER}}"
-
-    omf.new_from_template "$OMF_PATH/pkg/omf/templates/$option" \
-      $github $user $name
-
-    echo (omf::em)"Switched to $dir"(omf::off)
-
-    if test "$option" = themes
-      omf.theme $name
-      refresh
-    end
-  else
-    echo (omf::err)"\$OMF_CONFIG and/or \$OMF_PATH undefined."(omf::off) 1^&2
-    exit $OMF_UNKNOWN_ERR
-  end
-end
diff --git a/pkg/omf/cli/omf.new_from_template.fish b/pkg/omf/cli/omf.new_from_template.fish
deleted file mode 100644
index 77a92041a2aeb3481f8089ec071f99bca28e0080..0000000000000000000000000000000000000000
--- a/pkg/omf/cli/omf.new_from_template.fish
+++ /dev/null
@@ -1,27 +0,0 @@
-function omf.new_from_template -a path github user name
-  for file in $path/*
-    if test -d $file
-      mkdir (basename $file)
-      pushd (basename $file)
-      omf.new_from_template $file $github $user $name
-    else
-      set -l target (begin
-        if test (basename $file) = "{{NAME}}.fish"
-          echo "$name.fish"
-        else
-          echo (basename "$file")
-        end
-      end)
-      sed "s/{{USER_NAME}}/$user/;s/{{GITHUB_USER}}/$github/;s/{{NAME}}/$name/" \
-        $file > $target
-      echo (omf::em)" create "(omf::off)" "(begin
-        if test (basename $PWD) = $name
-          echo ""
-        else
-          echo (basename "$PWD")"/"
-        end
-      end)$target
-    end
-  end
-  popd >/dev/null ^&2
-end
diff --git a/pkg/omf/cli/omf.remove_package.fish b/pkg/omf/cli/omf.remove_package.fish
deleted file mode 100644
index c6730cee0986d3fc701b14c05192a715da461481..0000000000000000000000000000000000000000
--- a/pkg/omf/cli/omf.remove_package.fish
+++ /dev/null
@@ -1,44 +0,0 @@
-function omf.remove_package
-
-  set -l pkg $argv
-  set -l remove_status 1
-
-  if not omf.util_valid_package $pkg
-    if test $pkg = "omf" -o $pkg = "default"
-      echo (omf::err)"You can't remove `$pkg`"(omf::off) 1^&2
-    else
-      echo (omf::err)"$pkg is not a valid package/theme name"(omf::off) 1^&2
-    end
-    return $OMF_INVALID_ARG
-  end
-
-  for path in {$OMF_PATH,$OMF_CONFIG}/{pkg}/$pkg
-    not test -d $path; and continue
-
-    source $path/uninstall.fish ^/dev/null; and emit uninstall_$pkg
-    omf.bundle.remove "package" $pkg
-
-    rm -rf $path
-    set remove_status $status
-  end
-
-  for path in {$OMF_PATH,$OMF_CONFIG}/{themes}/$pkg
-    not test -d $path; and continue
-
-    if test $pkg = (cat $OMF_CONFIG/theme)
-      echo default > $OMF_CONFIG/theme
-    end
-
-    omf.bundle.remove "theme" $pkg
-
-    rm -rf $path
-    set remove_status $status
-  end
-
-  if test $remove_status -eq 0
-    echo (omf::em)"$pkg successfully removed."(omf::off)
-  else
-    echo (omf::err)"$pkg could not be found"(omf::off) 1^&2
-  end
-  return $remove_status
-end
diff --git a/pkg/omf/cli/omf.bundle.add.fish b/pkg/omf/functions/bundle/omf.bundle.add.fish
similarity index 100%
rename from pkg/omf/cli/omf.bundle.add.fish
rename to pkg/omf/functions/bundle/omf.bundle.add.fish
diff --git a/pkg/omf/cli/omf.bundle.install.fish b/pkg/omf/functions/bundle/omf.bundle.install.fish
similarity index 88%
rename from pkg/omf/cli/omf.bundle.install.fish
rename to pkg/omf/functions/bundle/omf.bundle.install.fish
index 94549ebefa7b781701933c80bac4ca23fc1375a7..98a37d4f49501466fd786b7800290034e41db9bd 100644
--- a/pkg/omf/cli/omf.bundle.install.fish
+++ b/pkg/omf/functions/bundle/omf.bundle.install.fish
@@ -16,10 +16,10 @@ function omf.bundle.install
       set name_or_url (echo $record | cut -s -d' ' -f2- | sed 's/ //g')
       test -n "$name_or_url"; or continue
 
-      set name (omf.package_name $name_or_url)
+      set name (omf.packages.name $name_or_url)
 
       if not contains $name $packages
-        omf.install $name_or_url;
+        omf.packages.install $name_or_url;
           and set installed
       end
     end
diff --git a/pkg/omf/cli/omf.bundle.remove.fish b/pkg/omf/functions/bundle/omf.bundle.remove.fish
similarity index 89%
rename from pkg/omf/cli/omf.bundle.remove.fish
rename to pkg/omf/functions/bundle/omf.bundle.remove.fish
index cc2bdadb2c2f68236cab11c0368658bda745886e..b37bae01c4550fe17b1d7fb975d6ff60ebfc0f90 100644
--- a/pkg/omf/cli/omf.bundle.remove.fish
+++ b/pkg/omf/functions/bundle/omf.bundle.remove.fish
@@ -11,7 +11,7 @@ function omf.bundle.remove
       for record in $bundle_contents
         set record_type (echo $record | cut -d' ' -f1)
         set record_name_or_url (echo $record | cut -d' ' -f2-)
-        set record_name (omf.package_name $record_name_or_url)
+        set record_name (omf.packages.name $record_name_or_url)
 
         if not test "$type" = "$record_type" -a "$name" = "$record_name"
           echo "$record_type $record_name_or_url" >> $bundle
diff --git a/pkg/omf/functions/cli/omf.cli.cd.fish b/pkg/omf/functions/cli/omf.cli.cd.fish
new file mode 100644
index 0000000000000000000000000000000000000000..177ee4478bd36507b4618dcbf9f5ab725000f44f
--- /dev/null
+++ b/pkg/omf/functions/cli/omf.cli.cd.fish
@@ -0,0 +1,3 @@
+function omf.cli.cd -a name
+  omf.packages.cd $name
+end
diff --git a/pkg/omf/functions/cli/omf.cli.describe.fish b/pkg/omf/functions/cli/omf.cli.describe.fish
new file mode 100644
index 0000000000000000000000000000000000000000..bf43d37aa88bde80d6ba2c965ec986fa9e5ea967
--- /dev/null
+++ b/pkg/omf/functions/cli/omf.cli.describe.fish
@@ -0,0 +1,10 @@
+function omf.cli.describe -a name
+  switch (count $argv)
+  case 1
+    omf.packages.describe $name
+    return 0
+  case '*'
+    echo (omf::err)"Invalid number of arguments"(omf::off)
+    return 1
+  end
+end
diff --git a/pkg/omf/functions/cli/omf.cli.destroy.fish b/pkg/omf/functions/cli/omf.cli.destroy.fish
new file mode 100644
index 0000000000000000000000000000000000000000..6c97e5c859b87d161aa7b246c42364b7cae11760
--- /dev/null
+++ b/pkg/omf/functions/cli/omf.cli.destroy.fish
@@ -0,0 +1,11 @@
+function omf.cli.destroy
+  echo (omf::err)"This will destroy your Oh My Fish installation!"(omf::off)
+  read -l decision -p 'echo -n "Are you sure you want to continue? (y/N) "'
+
+  switch $decision
+  case 'y' 'Y'
+    omf.destroy
+  case '*'
+    echo (omf::err)"Aborted!"(omf::off)
+  end
+end
diff --git a/pkg/omf/functions/cli/omf.cli.doctor.fish b/pkg/omf/functions/cli/omf.cli.doctor.fish
new file mode 100644
index 0000000000000000000000000000000000000000..d821708150517eaabacab94f709ee19a3feb81ed
--- /dev/null
+++ b/pkg/omf/functions/cli/omf.cli.doctor.fish
@@ -0,0 +1,3 @@
+function omf.cli.doctor
+  omf.doctor
+end
diff --git a/pkg/omf/cli/omf.help.fish b/pkg/omf/functions/cli/omf.cli.help.fish
similarity index 98%
rename from pkg/omf/cli/omf.help.fish
rename to pkg/omf/functions/cli/omf.cli.help.fish
index 0569ae365fa2f9c18348623b52008b5f750c0d62..c176104f13e65720880481c7ae67ed354b93daa1 100644
--- a/pkg/omf/cli/omf.help.fish
+++ b/pkg/omf/functions/cli/omf.cli.help.fish
@@ -1,5 +1,5 @@
-function omf.help -a command
-  switch $command
+function omf.cli.help -a command
+  switch "$command"
     case "c" "cd"
       echo \n"\
       Change directory to root or plugin/theme directory.
diff --git a/pkg/omf/functions/cli/omf.cli.install.fish b/pkg/omf/functions/cli/omf.cli.install.fish
new file mode 100644
index 0000000000000000000000000000000000000000..e20abe2dfe9ff1fea632f95929124cecfda7c1aa
--- /dev/null
+++ b/pkg/omf/functions/cli/omf.cli.install.fish
@@ -0,0 +1,19 @@
+function omf.cli.install
+  set fail_count 0
+
+  switch (count $argv)
+  case 0
+    omf.bundle.install;
+      or set fail_count 1
+  case '*'
+    for package in $argv
+      omf.packages.install $package;
+        and require $package
+
+      test $status != 0;
+        and set fail_count (math $fail_count + 1)
+    end
+  end
+
+  return $fail_count
+end
diff --git a/pkg/omf/functions/cli/omf.cli.list.fish b/pkg/omf/functions/cli/omf.cli.list.fish
new file mode 100644
index 0000000000000000000000000000000000000000..dbabafe251da7e95eec23d4b0f9f13602f1d8e4d
--- /dev/null
+++ b/pkg/omf/functions/cli/omf.cli.list.fish
@@ -0,0 +1,14 @@
+function omf.cli.list -a type
+  test -z "$type"; and set type '--installed'
+
+  if contains -- $type '--available' '-a' '--database' '-d' '--installed' '-i'
+    omf.packages.list $type | column
+  else
+    echo (omf::err)"Invalid arguments"(omf::off)
+    echo 'Usage: omf list [ --available | -a ]'
+    echo '       omf list [ --installed | -i ]'
+    echo '       omf list [ --database  | -d ]'
+    return $OMF_INVALID_ARG
+  end
+
+end
diff --git a/pkg/omf/functions/cli/omf.cli.new.fish b/pkg/omf/functions/cli/omf.cli.new.fish
new file mode 100644
index 0000000000000000000000000000000000000000..ad1cfdca12678ba65fdb405da619c722f52c362f
--- /dev/null
+++ b/pkg/omf/functions/cli/omf.cli.new.fish
@@ -0,0 +1,8 @@
+function omf.cli.new
+  if test (count $argv) -ne 2
+    echo (omf::err)"Package type or name missing"(omf::off) 1^&2
+    echo "Usage: omf new "(omf::em)"(pkg | theme)"(omf::off)" <name>" 1^&2
+    return $OMF_MISSING_ARG
+  end
+  omf.packages.new $argv
+end
diff --git a/pkg/omf/functions/cli/omf.cli.remove.fish b/pkg/omf/functions/cli/omf.cli.remove.fish
new file mode 100644
index 0000000000000000000000000000000000000000..56c12d75fcd114568d5137d3b5830af79c8ecc9a
--- /dev/null
+++ b/pkg/omf/functions/cli/omf.cli.remove.fish
@@ -0,0 +1,23 @@
+function omf.cli.remove -a name
+  switch (count $argv)
+  case 1
+    omf.packages.remove $name
+    set code $status
+
+    switch $code
+    case 0
+      echo (omf::em)"$name successfully removed."(omf::off)
+    case 1
+      echo (omf::err)"$name could not be removed."(omf::off) 1^&2
+    case 2
+      echo (omf::err)"$name could not be found."(omf::off) 1^&2
+    end
+
+    return $code
+
+  case '*'
+    echo (omf::err)"Invalid number of arguments"(omf::off) 1^&2
+    echo "Usage: omf remove "(omf::em)"<name>"(omf::off) 1^&2
+    return $OMF_INVALID_ARG
+  end
+end
diff --git a/pkg/omf/functions/cli/omf.cli.submit.fish b/pkg/omf/functions/cli/omf.cli.submit.fish
new file mode 100644
index 0000000000000000000000000000000000000000..1ed074c6d378a55bb76c6c7a31fab2bec9217967
--- /dev/null
+++ b/pkg/omf/functions/cli/omf.cli.submit.fish
@@ -0,0 +1,10 @@
+function omf.cli.submit
+  switch (count $argv)
+  case 2
+    omf.packages.submit $argv
+  case "*"
+    echo (omf::err)"Argument missing"(omf::off) 1^&2
+    echo "Usage: $_ "(omf::em)"submit"(omf::off)" "(omf::em)"pkg|themes"(omf::off)"/<name> <url>" 1^&2
+    return $OMF_MISSING_ARG
+  end
+end
diff --git a/pkg/omf/functions/cli/omf.cli.theme.fish b/pkg/omf/functions/cli/omf.cli.theme.fish
new file mode 100644
index 0000000000000000000000000000000000000000..82d7ccfa33f2320e4af1d335fb0e38059511ca2a
--- /dev/null
+++ b/pkg/omf/functions/cli/omf.cli.theme.fish
@@ -0,0 +1,12 @@
+function omf.cli.theme -a name
+  switch (count $argv)
+  case 0
+    omf.cli.themes.list
+  case 1
+    omf.theme.set $name
+  case '*'
+    echo (omf::err)"Invalid number of arguments"(omf::off) 1^&2
+    echo "Usage: $_ "(omf::em)"$argv[1]"(omf::off)" [<theme name>]" 1^&2
+    return $OMF_INVALID_ARG
+  end
+end
diff --git a/pkg/omf/functions/cli/omf.cli.themes.list.fish b/pkg/omf/functions/cli/omf.cli.themes.list.fish
new file mode 100644
index 0000000000000000000000000000000000000000..926b244c59bc4ef06f1039c4b7e77c147627919c
--- /dev/null
+++ b/pkg/omf/functions/cli/omf.cli.themes.list.fish
@@ -0,0 +1,11 @@
+function omf.cli.themes.list
+  set -l theme (cat $OMF_CONFIG/theme)
+  set -l regex_current "(^|[[:space:]])($theme)([[:space:]]|\$)"
+  set -l highlight_current s/"$regex_current"/"\1"(omf::em)"\2"(omf::off)"\3"/g
+
+  echo (omf::under)"Installed:"(omf::off)
+  omf.packages.list --installed --theme | column | sed -E "$highlight_current"
+  echo
+  echo (omf::under)"Available:"(omf::off)
+  omf.packages.list --available --theme | column
+end
diff --git a/pkg/omf/functions/cli/omf.cli.update.fish b/pkg/omf/functions/cli/omf.cli.update.fish
new file mode 100644
index 0000000000000000000000000000000000000000..b54b65431323de26bd70141f29fdd8c10a0b3ebc
--- /dev/null
+++ b/pkg/omf/functions/cli/omf.cli.update.fish
@@ -0,0 +1,12 @@
+function omf.cli.update
+  if omf.core.update
+    echo (omf::em)"Oh My Fish is up to date."(omf::off)
+  else
+    echo (omf::err)"Oh My Fish failed to update."(omf::off)
+    echo "Please open a new issue here → "(omf::em)"github.com/oh-my-fish/oh-my-fish/issues"(omf::off)
+  end
+
+  for package in (omf.packages.list --installed)
+    omf.packages.update $package
+  end
+end
diff --git a/pkg/omf/cli/omf.version.fish b/pkg/omf/functions/cli/omf.cli.version.fish
similarity index 60%
rename from pkg/omf/cli/omf.version.fish
rename to pkg/omf/functions/cli/omf.cli.version.fish
index 53e54c708c6b66d869288db76120db1dd9b0284a..61cfc1714bda3ce07cf8291502f263c6330957e3 100644
--- a/pkg/omf/cli/omf.version.fish
+++ b/pkg/omf/functions/cli/omf.cli.version.fish
@@ -1,3 +1,3 @@
-function omf.version
+function omf.cli.version
   echo "Oh My Fish! $OMF_VERSION"
 end
diff --git a/pkg/omf/functions/compat/.gitkeep b/pkg/omf/functions/compat/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/pkg/omf/functions/core/omf.core.update.fish b/pkg/omf/functions/core/omf.core.update.fish
new file mode 100644
index 0000000000000000000000000000000000000000..2cf343af1b0c3890068ae5bcc617bcdf0dbb0a96
--- /dev/null
+++ b/pkg/omf/functions/core/omf.core.update.fish
@@ -0,0 +1,3 @@
+function omf.core.update
+  omf.repo.pull $OMF_PATH
+end
diff --git a/pkg/omf/cli/omf.destroy.fish b/pkg/omf/functions/core/omf.destroy.fish
similarity index 100%
rename from pkg/omf/cli/omf.destroy.fish
rename to pkg/omf/functions/core/omf.destroy.fish
diff --git a/pkg/omf/cli/omf.doctor.fish b/pkg/omf/functions/core/omf.doctor.fish
similarity index 100%
rename from pkg/omf/cli/omf.doctor.fish
rename to pkg/omf/functions/core/omf.doctor.fish
diff --git a/pkg/omf/cli/omf.xdg.config_home.fish b/pkg/omf/functions/core/omf.xdg.config_home.fish
similarity index 100%
rename from pkg/omf/cli/omf.xdg.config_home.fish
rename to pkg/omf/functions/core/omf.xdg.config_home.fish
diff --git a/pkg/omf/functions/omf.fish b/pkg/omf/functions/omf.fish
new file mode 100644
index 0000000000000000000000000000000000000000..dab97cb5e0f45cec3e61e9f590cc57e5d3d3f0cb
--- /dev/null
+++ b/pkg/omf/functions/omf.fish
@@ -0,0 +1,68 @@
+# SYNOPSIS
+#   Oh My Fish! CLI
+#
+# OVERVIEW
+#   Provides options to list, download and remove packages, update
+#   the framework, create / submit a new package, etc.
+
+function omf -d "Oh My Fish"
+
+  if test "x$argv[-1]" = "x--help" -a (count $argv) = 2
+    set command help
+    set arguments $argv[1]
+  else if test (count $argv) -ge 2
+    set command $argv[1]
+    set arguments $argv[2..-1]
+  else if test (count $argv) = 1
+    set command $argv[1]
+    set arguments
+  else
+    set command help
+    set arguments
+  end
+
+  switch "$command"
+    case "-v*" "--v*"
+      omf.cli.version
+
+    case "-h*" "--h*" "help"
+      omf.cli.help $arguments
+
+    case "c" "cd"
+      omf.cli.cd $arguments
+
+    case "d" "describe"
+      omf.cli.describe $arguments
+
+    case "destroy"
+      omf.cli.destroy
+
+    case "doctor"
+      omf.cli.doctor
+
+    case "i" "install" "get"
+      omf.cli.install $arguments
+
+    case "l" "ls" "list"
+      omf.cli.list $arguments
+
+    case "n" "new"
+      omf.cli.new $arguments
+
+    case "r" "rm" "remove" "uninstall"
+      omf.cli.remove $arguments
+
+    case "s" "submit"
+      omf.cli.submit $arguments
+
+    case "t" "theme"
+      omf.cli.theme $arguments
+
+    case "u" "update"
+      omf.cli.update
+
+    case "*"
+      echo (omf::err)"$argv[1] option not recognized"(omf::off) 1^&2
+      return $OMF_UNKNOWN_OPT
+  end
+end
diff --git a/pkg/omf/cli/omf.packages.cd.fish b/pkg/omf/functions/packages/omf.packages.cd.fish
similarity index 100%
rename from pkg/omf/cli/omf.packages.cd.fish
rename to pkg/omf/functions/packages/omf.packages.cd.fish
diff --git a/pkg/omf/cli/omf.describe.fish b/pkg/omf/functions/packages/omf.packages.describe.fish
similarity index 93%
rename from pkg/omf/cli/omf.describe.fish
rename to pkg/omf/functions/packages/omf.packages.describe.fish
index e3862e4841425db49ac2c32807a6d6ef3546a4e4..40bae5d8a045af3623fe4f91d85c3686b14867a3 100644
--- a/pkg/omf/cli/omf.describe.fish
+++ b/pkg/omf/functions/packages/omf.packages.describe.fish
@@ -1,4 +1,4 @@
-function omf.describe -a name
+function omf.packages.describe -a name
   if test (count $argv) -eq 0
     for package in (omf.packages.list --database)
       echo $package - (omf.describe $package)
diff --git a/pkg/omf/cli/omf.install.fish b/pkg/omf/functions/packages/omf.packages.install.fish
similarity index 56%
rename from pkg/omf/cli/omf.install.fish
rename to pkg/omf/functions/packages/omf.packages.install.fish
index ec48524bb43b2a238f81b461a75514a08103cca7..2cb069a585aee720d350d5354f8452e170f44c8c 100644
--- a/pkg/omf/cli/omf.install.fish
+++ b/pkg/omf/functions/packages/omf.packages.install.fish
@@ -1,11 +1,16 @@
-function omf.install -a name_or_url
-  function __omf.install.success
-    echo (omf::em)"✔ $argv successfully installed."(omf::off)
-  end
+function __omf.packages.install.success
+  echo (omf::em)"✔ $argv successfully installed."(omf::off)
+end
 
-  function __omf.install.error
-    echo (omf::err)"Could not install $argv."(omf::off) 1^&2
-  end
+function __omf.packages.install.error
+  echo (omf::err)"Could not install $argv."(omf::off) 1^&2
+end
+
+function __omf.packages.install.error.already
+  echo (omf::err)"Error: $argv already installed."(omf::off) 1^&2
+end
+
+function omf.packages.install -a name_or_url
 
   if test \( -e $OMF_PATH/db/themes/$name_or_url \) -o (echo $name_or_url | grep theme-)
     set install_type "theme"
@@ -19,15 +24,15 @@ function omf.install -a name_or_url
     set name $name_or_url
     set url (cat $OMF_PATH/db/$parent_path/$name)
   else
-    set name (omf.package_name $name_or_url)
+    set name (omf.packages.name $name_or_url)
     set url $name_or_url
   end
 
   if test -e $OMF_PATH/$parent_path/$name
     if test "$install_type" = theme
-      omf.theme $name
+      omf.theme.set $name
     else
-      echo (omf::err)"Error: $name $install_type already installed."(omf::off) 1^&2
+      __omf.packages.install.error.already "$install_type $name_or_url"
       return $OMF_INVALID_ARG
     end
   else
@@ -36,13 +41,13 @@ function omf.install -a name_or_url
     if omf.repo.clone $url $OMF_PATH/$parent_path/$name
       omf.bundle.install $OMF_PATH/$parent_path/$name/bundle
       omf.bundle.add $install_type $name_or_url
-      __omf.install.success "$install_type $name"
+      __omf.packages.install.success "$install_type $name"
 
       if test "$install_type" = theme
-        omf.theme $name
+        omf.theme.set $name
       end
     else
-      __omf.install.error "$install_type $name"
+      __omf.packages.install.error "$install_type $name"
       return $OMF_UNKNOWN_ERR
     end
   end
diff --git a/pkg/omf/cli/omf.packages.list.fish b/pkg/omf/functions/packages/omf.packages.list.fish
similarity index 95%
rename from pkg/omf/cli/omf.packages.list.fish
rename to pkg/omf/functions/packages/omf.packages.list.fish
index 9cc1225a1865951d6544006f5303a6725551bec0..64511b56bebdc30bcba0a577e08d7b0d15dffa25 100644
--- a/pkg/omf/cli/omf.packages.list.fish
+++ b/pkg/omf/functions/packages/omf.packages.list.fish
@@ -4,6 +4,7 @@ end
 
 function __omf.packages.builtin
   echo "omf"
+  echo "fish-spec"
 end
 
 function __omf.packages.list -a type
@@ -64,11 +65,11 @@ end
 
 function omf.packages.list -a option type
   switch "$option"
-  case "--available"
+  case "-a" "--available"
     __omf.packages.list.available $type
-  case "--database"
+  case "-d" "--database"
     __omf.packages.list.database $type
-  case "--installed"
+  case "-i" "--installed"
     __omf.packages.list.installed $type
   case "*"
     __omf.packages.list $type
diff --git a/pkg/omf/util/omf.package_name.fish b/pkg/omf/functions/packages/omf.packages.name.fish
similarity index 66%
rename from pkg/omf/util/omf.package_name.fish
rename to pkg/omf/functions/packages/omf.packages.name.fish
index 77f730c2c0924be5d5e63b6d73b65f7fef323ac7..904c07ec64dea942bb388fb797da0b286d6f3edb 100644
--- a/pkg/omf/util/omf.package_name.fish
+++ b/pkg/omf/functions/packages/omf.packages.name.fish
@@ -1,3 +1,3 @@
-function omf.package_name -a name_or_url
+function omf.packages.name -a name_or_url
   basename $name_or_url | sed -E 's/^(omf-)?((plugin|pkg|theme)-)?//;s/.git$//'
 end
diff --git a/pkg/omf/functions/packages/omf.packages.new.fish b/pkg/omf/functions/packages/omf.packages.new.fish
new file mode 100644
index 0000000000000000000000000000000000000000..856e70e361168801894372402eb5b8f11ce67f51
--- /dev/null
+++ b/pkg/omf/functions/packages/omf.packages.new.fish
@@ -0,0 +1,78 @@
+function __omf.packages.new.mkdir -a name
+  set -l name "$argv[1]"
+  if test -d "$OMF_CONFIG"
+    set name "$OMF_CONFIG/$name"
+  else if test -d "$OMF_PATH"
+    set name "$OMF_PATH/$name"
+  end
+  mkdir -p "$name"
+  echo $name
+end
+
+function __omf.packages.new.from_template -a path github user name
+  for file in $path/*
+    if test -d $file
+      mkdir (basename $file)
+      pushd (basename $file)
+      __omf.packages.new.from_template $file $github $user $name
+    else
+      set -l target (begin
+        if test (basename $file) = "{{NAME}}.fish"
+          echo "$name.fish"
+        else
+          echo (basename "$file")
+        end
+      end)
+      sed "s/{{USER_NAME}}/$user/;s/{{GITHUB_USER}}/$github/;s/{{NAME}}/$name/" \
+        $file > $target
+      echo (omf::em)" create "(omf::off)" "(begin
+        if test (basename $PWD) = $name
+          echo ""
+        else
+          echo (basename "$PWD")"/"
+        end
+      end)$target
+    end
+  end
+  popd >/dev/null ^&2
+end
+
+
+function omf.packages.new -a option name
+  switch $option
+    case "p" "pkg" "pack" "packg" "package"
+      set option "pkg"
+    case "t" "th" "the" "thm" "theme" "themes"
+      set option "themes"
+    case "*"
+      echo (omf::err)"$option is not a valid option."(omf::off) 1^&2
+      return $OMF_INVALID_ARG
+  end
+
+  if not omf.packages.valid_name "$name"
+    echo (omf::err)"$name is not a valid package/theme name"(omf::off) 1^&2
+    return $OMF_INVALID_ARG
+  end
+
+  if set -l dir (__omf.packages.new.mkdir "$option/$name")
+    cd $dir
+
+    set -l github (git config github.user)
+    test -z "$github"; and set github "{{USER}}"
+
+    set -l user (git config user.name)
+    test -z "$user"; and set user "{{USER}}"
+
+    __omf.packages.new.from_template "$OMF_PATH/pkg/omf/templates/$option" \
+      $github $user $name
+
+    echo (omf::em)"Switched to $dir"(omf::off)
+
+    if test "$option" = themes
+      omf.theme.set $name
+    end
+  else
+    echo (omf::err)"\$OMF_CONFIG and/or \$OMF_PATH undefined."(omf::off) 1^&2
+    exit $OMF_UNKNOWN_ERR
+  end
+end
diff --git a/pkg/omf/functions/packages/omf.packages.path.fish b/pkg/omf/functions/packages/omf.packages.path.fish
new file mode 100644
index 0000000000000000000000000000000000000000..cd4988dd1bc8a9a35daec1303630fbc285e0b20d
--- /dev/null
+++ b/pkg/omf/functions/packages/omf.packages.path.fish
@@ -0,0 +1,10 @@
+function omf.packages.path -a name
+  for path in {$OMF_CONFIG,$OMF_PATH}/{themes,pkg}/$name
+    if test -e $path
+      echo $path
+      return 0
+    end
+  end
+
+  return 1
+end
diff --git a/pkg/omf/functions/packages/omf.packages.remove.fish b/pkg/omf/functions/packages/omf.packages.remove.fish
new file mode 100644
index 0000000000000000000000000000000000000000..39f3034e0f79f65b5e56abfeca0327b51026f198
--- /dev/null
+++ b/pkg/omf/functions/packages/omf.packages.remove.fish
@@ -0,0 +1,46 @@
+function omf.packages.remove -a pkg
+
+  if not omf.packages.valid_name $pkg
+    echo (omf::err)"$pkg is not a valid package/theme name"(omf::off) 1>&2
+    return $OMF_INVALID_ARG
+  end
+
+  if test $pkg = "omf" -o $pkg = "default"
+    echo (omf::err)"You can't remove `$pkg`"(omf::off) 1>&2
+    return $OMF_INVALID_ARG
+  end
+
+  for path in {$OMF_PATH,$OMF_CONFIG}/pkg/$pkg
+    test -d $path;
+      and set found;
+      or continue
+
+    source $path/uninstall.fish ^/dev/null;
+      and emit uninstall_$pkg
+
+    if rm -rf $path
+      omf.bundle.remove "package" $pkg
+      return 0
+    else
+      return 1
+    end
+  end
+
+  for path in {$OMF_PATH,$OMF_CONFIG}/themes/$pkg
+    test -d $path;
+      and set found;
+      or continue
+
+    test $pkg = (cat $OMF_CONFIG/theme);
+      and echo default > $OMF_CONFIG/theme
+
+    if rm -rf $path
+      omf.bundle.remove "theme" $pkg
+      return 0
+    else
+      return 1
+    end
+  end
+
+  set -q found; or return 2
+end
diff --git a/pkg/omf/cli/omf.submit.fish b/pkg/omf/functions/packages/omf.packages.submit.fish
similarity index 91%
rename from pkg/omf/cli/omf.submit.fish
rename to pkg/omf/functions/packages/omf.packages.submit.fish
index 9d05d5a40390be859016e95a5969addb533f21cc..a9e0d58ab45244124373c12c3b4a35d4c7cf6f73 100644
--- a/pkg/omf/cli/omf.submit.fish
+++ b/pkg/omf/functions/packages/omf.packages.submit.fish
@@ -5,7 +5,7 @@
 #   name  Name of the package.
 #   [url] URL to the package repository.
 
-function omf.submit -a name url -d "Submit a package to the registry"
+function omf.packages.submit -a name url -d "Submit a package to the registry"
   switch (dirname $name)
     case pkg
     case themes
@@ -15,7 +15,7 @@ function omf.submit -a name url -d "Submit a package to the registry"
   end
 
   set -l pkg (basename $name)
-  if not omf.util_valid_package $pkg
+  if not omf.packages.valid_name $pkg
     echo (omf::err)"$pkg is not a valid package/theme name"(omf::off) 1^&2
     return $OMF_INVALID_ARG
   end
diff --git a/pkg/omf/functions/packages/omf.packages.update.fish b/pkg/omf/functions/packages/omf.packages.update.fish
new file mode 100644
index 0000000000000000000000000000000000000000..f78df81b09178a6f50245ab6014ca928fe37f508
--- /dev/null
+++ b/pkg/omf/functions/packages/omf.packages.update.fish
@@ -0,0 +1,19 @@
+function omf.packages.update -a name
+  if set target_path (omf.packages.path $name)
+    # Skip packages outside version control
+    not test -e $target_path/.git;
+      and return 0
+
+    if omf.repo.pull $target_path
+      omf.bundle.install $target_path/bundle
+      echo (omf::em)"$name successfully updated."(omf::off)
+      return 0
+    else
+      echo (omf::err)"Could not update $name."(omf::off) 1^&2
+    end
+  else
+    echo (omf::err)"Could not find $name."(omf::off) 1^&2
+  end
+
+  return 1
+end
diff --git a/pkg/omf/util/omf.util_valid_package.fish b/pkg/omf/functions/packages/omf.packages.valid_name.fish
similarity index 90%
rename from pkg/omf/util/omf.util_valid_package.fish
rename to pkg/omf/functions/packages/omf.packages.valid_name.fish
index b44c6a644bb5abad28cb53f00d9ea3b84e25a6bd..a14d0a7e5e9b30175a3aa5bbb3e14c0323e6919e 100644
--- a/pkg/omf/util/omf.util_valid_package.fish
+++ b/pkg/omf/functions/packages/omf.packages.valid_name.fish
@@ -1,4 +1,4 @@
-function omf.util_valid_package -a package
+function omf.packages.valid_name -a package
   test (echo "$package" | tr "[:upper:]" "[:lower:]") = "omf"; and return 10
   test (echo "$package" | tr "[:upper:]" "[:lower:]") = "default"; and return 10
   switch $package
diff --git a/pkg/omf/cli/omf.repo.clone.fish b/pkg/omf/functions/repo/omf.repo.clone.fish
similarity index 100%
rename from pkg/omf/cli/omf.repo.clone.fish
rename to pkg/omf/functions/repo/omf.repo.clone.fish
diff --git a/pkg/omf/cli/omf.repo.pull.fish b/pkg/omf/functions/repo/omf.repo.pull.fish
similarity index 100%
rename from pkg/omf/cli/omf.repo.pull.fish
rename to pkg/omf/functions/repo/omf.repo.pull.fish
diff --git a/pkg/omf/cli/omf.theme.fish b/pkg/omf/functions/themes/omf.theme.set.fish
similarity index 96%
rename from pkg/omf/cli/omf.theme.fish
rename to pkg/omf/functions/themes/omf.theme.set.fish
index 4af3a4a3bdb9edb98092a30eef98a0fdc824a110..22e90e42dd1a63064f579c789402505872c3d530 100644
--- a/pkg/omf/cli/omf.theme.fish
+++ b/pkg/omf/functions/themes/omf.theme.set.fish
@@ -1,4 +1,4 @@
-function omf.theme -a target_theme
+function omf.theme.set -a target_theme
   if not contains "$target_theme" (omf.packages.list --installed --theme)
     echo (omf::err)"Theme not installed!"(omf::off)
     echo Install it using (omf::em)omf install $target_theme(omf::off)
diff --git a/pkg/omf/cli/omf.check.fish_prompt.fish b/pkg/omf/functions/util/omf.check.fish_prompt.fish
similarity index 100%
rename from pkg/omf/cli/omf.check.fish_prompt.fish
rename to pkg/omf/functions/util/omf.check.fish_prompt.fish
diff --git a/pkg/omf/init.fish b/pkg/omf/init.fish
index 8d7d70ee3db094abf2efa7354d20e05b61e2ea12..fc016d603fe9587e594ea17b658a54a08d416d99 100644
--- a/pkg/omf/init.fish
+++ b/pkg/omf/init.fish
@@ -1,3 +1,28 @@
 function init -a path --on-event init_omf
-  autoload $path/cli $path/util
+  set -g OMF_MISSING_ARG   1
+  set -g OMF_UNKNOWN_OPT   2
+  set -g OMF_INVALID_ARG   3
+  set -g OMF_UNKNOWN_ERR   4
+
+  function omf::em
+    set_color $fish_color_match ^/dev/null; or set_color cyan
+  end
+
+  function omf::dim
+    set_color $fish_color_autosuggestion ^/dev/null; or set_color 555
+  end
+
+  function omf::err
+    set_color $fish_color_error ^/dev/null; or set_color red --bold
+  end
+
+  function omf::under
+    set_color --underline
+  end
+
+  function omf::off
+    set_color normal
+  end
+
+  autoload $path/functions/{compat,core,packages,themes,bundle,util,repo,cli}
 end
diff --git a/pkg/omf/omf.bundle.install.fish b/pkg/omf/omf.bundle.install.fish
new file mode 120000
index 0000000000000000000000000000000000000000..6fd2e65389c98dbabd7175c60f13473ba1b54a7a
--- /dev/null
+++ b/pkg/omf/omf.bundle.install.fish
@@ -0,0 +1 @@
+functions/bundle/omf.bundle.install.fish
\ No newline at end of file
diff --git a/pkg/omf/omf.fish b/pkg/omf/omf.fish
deleted file mode 100755
index 1fa5a76268a3078be6b46afa62558db08437e9a3..0000000000000000000000000000000000000000
--- a/pkg/omf/omf.fish
+++ /dev/null
@@ -1,160 +0,0 @@
-# SYNOPSIS
-#   Oh My Fish! CLI
-#
-# ENV
-#   OMF_CONFIG    Oh My Fish! configuration
-#
-# OVERVIEW
-#   Provides options to list, download and remove packages, update
-#   the framework, create / submit a new package, etc.
-
-set -g OMF_MISSING_ARG   1
-set -g OMF_UNKNOWN_OPT   2
-set -g OMF_INVALID_ARG   3
-set -g OMF_UNKNOWN_ERR   4
-
-function omf::em
-  set_color $fish_color_match ^/dev/null; or set_color cyan
-end
-
-function omf::dim
-  set_color $fish_color_autosuggestion ^/dev/null; or set_color 555
-end
-
-function omf::under
-  set_color --underline
-end
-
-function omf::err
-  set_color $fish_color_error ^/dev/null; or set_color red --bold
-end
-
-function omf::off
-  set_color normal
-end
-
-function omf -d "Oh My Fish"
-  if test (count $argv) -eq 0
-    omf.help "main"; and return 0
-  else
-    if test "--help" = "$argv[-1]" -a (count $argv) = 2
-      omf.help $argv[1..-2]; and return 0
-    end
-  end
-
-  switch $argv[1]
-    case "-v*" "--v*"
-      omf.version
-
-    case "doctor"
-      omf.doctor
-
-    case "-h*" "--h*" "help"
-      if test (count $argv) -eq 1
-        omf.help "main"
-      else
-        omf.help $argv[2]
-      end
-
-    case "c" "cd"
-      switch (count $argv)
-        case 1
-          omf.packages.cd
-        case 2
-          omf.packages.cd $argv[2]
-        case "*"
-          echo (omf::err)"Invalid number of arguments"(omf::off) 1^&2
-          echo "Usage: $_ "(omf::em)"$argv[1]"(omf::off)" <name>" 1^&2
-          return $OMF_INVALID_ARG
-      end
-
-    case "d" "describe"
-      if test (count $argv) -eq 1
-        omf.describe
-      else
-        omf.describe $argv[2..-1]
-      end
-
-    case "destroy"
-      omf.destroy
-
-    case "i" "install" "get"
-      if test (count $argv) -eq 1
-        omf.bundle.install;
-          and set installed
-      else
-        for package in $argv[2..-1]
-          omf.install $package;
-            and set installed
-        end
-      end
-
-      set -q installed; and refresh
-      return 0
-
-    case "l" "ls" "list"
-      omf.packages.list --installed | column
-
-    case "n" "new"
-      if test (count $argv) -ne 3
-        echo (omf::err)"Package type or name missing"(omf::off) 1^&2
-        echo "Usage: $_ "(omf::em)"$argv[1]"(omf::off)" "(omf::em)"pkg|theme"(omf::off)" <name>" 1^&2
-        return $OMF_MISSING_ARG
-      end
-      omf.new $argv[2..-1]
-
-    case "r" "rm" "remove" "uninstall"
-      if test (count $argv) -ne 2
-        echo (omf::err)"Invalid number of arguments"(omf::off) 1^&2
-        echo "Usage: $_ "(omf::em)"$argv[1]"(omf::off)" <[package|theme] name>" 1^&2
-        return $OMF_INVALID_ARG
-      end
-      omf.remove_package $argv[2] ; and refresh
-
-    case "s" "submit"
-      switch (count $argv)
-        case 3
-          omf.submit $argv[2] $argv[3]
-        case "*"
-          echo (omf::err)"Argument missing"(omf::off) 1^&2
-          echo "Usage: $_ "(omf::em)"$argv[1]"(omf::off)" "(omf::em)"pkg|themes"(omf::off)"/<name> <url>" 1^&2
-          return $OMF_MISSING_ARG
-      end
-
-    case "t" "theme"
-      if test (count $argv) -eq 1
-        set -l theme (cat $OMF_CONFIG/theme)
-        set -l highlight_current "(^|[[:space:]])($theme)([[:space:]]|\$)"
-
-        echo (omf::under)"Installed:"(omf::off)
-        omf.packages.list --installed --theme | column | sed -E s/"$highlight_current"/"\1"(omf::em)"\2"(omf::off)"\3"/g
-        echo
-        echo (omf::under)"Available:"(omf::off)
-        omf.packages.list --available --theme | column
-      else if test (count $argv) -eq 2
-        omf.theme $argv[2]
-      else
-        echo (omf::err)"Invalid number of arguments"(omf::off) 1^&2
-        echo "Usage: $_ "(omf::em)"$argv[1]"(omf::off)" [<theme name>]" 1^&2
-        return $OMF_INVALID_ARG
-      end
-
-    case "u" "update"
-      echo (omf::em)"Updating Oh My Fish..."(omf::off)
-      if omf.repo.pull $OMF_PATH
-        echo (omf::em)"Oh My Fish is up to date."(omf::off)
-      else
-        echo (omf::err)"Oh My Fish failed to update."(omf::off)
-        echo "Please open a new issue here → "(omf::em)"github.com/oh-my-fish/oh-my-fish/issues"(omf::off)
-      end
-
-      for package in (omf.packages.list --installed)
-        omf.update $package
-      end
-
-      refresh
-    case "*"
-      echo (omf::err)"$argv[1] option not recognized"(omf::off) 1^&2
-      return $OMF_UNKNOWN_OPT
-  end
-end
diff --git a/pkg/omf/omf.packages.install.fish b/pkg/omf/omf.packages.install.fish
new file mode 120000
index 0000000000000000000000000000000000000000..a401368a69cbce657f990da7fead5e2b15ef632b
--- /dev/null
+++ b/pkg/omf/omf.packages.install.fish
@@ -0,0 +1 @@
+functions/packages/omf.packages.install.fish
\ No newline at end of file
diff --git a/pkg/omf/omf.packages.list.fish b/pkg/omf/omf.packages.list.fish
new file mode 120000
index 0000000000000000000000000000000000000000..11aa13f8fc51443694c8e075235bea7f814f5784
--- /dev/null
+++ b/pkg/omf/omf.packages.list.fish
@@ -0,0 +1 @@
+functions/packages/omf.packages.list.fish
\ No newline at end of file
diff --git a/pkg/omf/omf.packages.name.fish b/pkg/omf/omf.packages.name.fish
new file mode 120000
index 0000000000000000000000000000000000000000..2bb3cf4d833cead8843ea1d52f042669c7bebd53
--- /dev/null
+++ b/pkg/omf/omf.packages.name.fish
@@ -0,0 +1 @@
+functions/packages/omf.packages.name.fish
\ No newline at end of file
diff --git a/pkg/omf/omf.repo.pull.fish b/pkg/omf/omf.repo.pull.fish
new file mode 120000
index 0000000000000000000000000000000000000000..46c85de5f95afa99f16ffd3580700426ff2b9da7
--- /dev/null
+++ b/pkg/omf/omf.repo.pull.fish
@@ -0,0 +1 @@
+functions/repo/omf.repo.pull.fish
\ No newline at end of file
diff --git a/pkg/omf/cli/omf.update.fish b/pkg/omf/omf.update.fish
similarity index 100%
rename from pkg/omf/cli/omf.update.fish
rename to pkg/omf/omf.update.fish
diff --git a/pkg/omf/util/omf.util_mkdir.fish b/pkg/omf/util/omf.util_mkdir.fish
deleted file mode 100644
index c206cadf99d8a4db332ee9d491c3f8d9f3b5f870..0000000000000000000000000000000000000000
--- a/pkg/omf/util/omf.util_mkdir.fish
+++ /dev/null
@@ -1,10 +0,0 @@
-function omf.util_mkdir -a name
-  set -l name "$argv[1]"
-  if test -d "$OMF_CONFIG"
-    set name "$OMF_CONFIG/$name"
-  else if test -d "$OMF_PATH"
-    set name "$OMF_PATH/$name"
-  end
-  mkdir -p "$name"
-  echo $name
-end