diff --git a/git-open b/git-open
index ee5e2a1faf4b7465c348e0e9fe9bff20e3f541e8..31457e82e4caf6eaa3d7e16fb44f460380673d8f 100755
--- a/git-open
+++ b/git-open
@@ -3,6 +3,31 @@
 import sys
 import subprocess
 import argparse
+import re
+import os.path
+try:
+    # package python-pyxdg on Arch
+    from xdg.BaseDirectory import xdg_config_dirs
+except ModuleNotFoundError:
+    print("xdg module not found, defaulting to $HOME/.config", file=sys.stderr)
+    import os
+    home = os.getenv("HOME")
+    xdg_config_dirs = [os.path.join(home, ".config")]
+
+can_load_configuration = False
+try:
+    # package python-yaml on Arch
+    import yaml
+    can_load_configuration = True
+except ModuleNotFoundError:
+    print("yaml module not found, configuration will NOT be loaded",
+          file=sys.stderr)
+
+
+configuration = {
+    # a list of dictionaries, each containing the keys 'i' and 'o'
+    'patterns': []
+}
 
 
 def popen(str):
@@ -23,17 +48,26 @@ def remote_url(remote_name):
     return popen(f'git remote get-url {remote_name}').strip()
 
 def to_http(url):
+    for pattern in configuration['patterns']:
+        if match := re.match(pattern['i'], url):
+            rx = re.compile('[$]([0-9]+)')
+            on = list(pattern['o'])
+            for m in reversed(list(rx.finditer(pattern['o']))):
+                try:
+                    on[m.start():m.end()] = match[int(m[1])]
+                except ValueError as e:
+                    print('All output patterns must be numbers')
+                    # TODO fail catastrophically instead of
+                    # re-raising
+                    raise e
+            return ''.join(on)
+
     if url[0:4] == "http":
-        if "aur.archlinux.org" in url:
-            parts = url.split('/')
-            return '/'.join(parts[0:-1] + ['packages'] + [parts[-1]])
-        else:
-            return url
+        return url
     if url[0:4] == "git@":
         base, path = url[4:].split(":")
         return "https://" + base + "/" + path
     raise Exception("URL doesn't start with either 'http' or 'git@'")
-    # return "http://www.nicememe.website"
 
 def xdg_open(item):
     subprocess.run(["xdg-open", item])
@@ -83,6 +117,18 @@ def main(args):
     else:
         err("All remotes failed")
 
+def load_configuration():
+    global configuration
+    # TODO possibly add ~/.config/git/open.yaml to list
+    for dir in xdg_config_dirs:
+        try:
+            with open(os.path.join(dir, 'git-open.yaml')) as f:
+                conf = yaml.unsafe_load(f)
+                configuration |= conf
+                break
+        except FileNotFoundError:
+            pass
+
 if __name__ == "__main__":
     # Note that argparse gives `--help' and `-h', but git "eats"
     # `--help'. `-h' does however work.
@@ -90,5 +136,9 @@ if __name__ == "__main__":
     parser.add_argument('-n', '--dry-run', action='store_true', dest='dry_run')
     parser.add_argument('remote', action='store', nargs='?')
     args = parser.parse_args()
+
+    if can_load_configuration:
+        load_configuration()
+
     main(args)