diff --git a/Manifest.cs b/Manifest.cs
index 52f435d60213fc606c8b73a9808b13ed7d366a46..a6fcede1d9b0b7631c8c5a38bf12b0314060c251 100644
--- a/Manifest.cs
+++ b/Manifest.cs
@@ -14,16 +14,33 @@ namespace sunrise_launcher
 
     public class ManifestMetadata
     {
-        [JsonPropertyName("title")]
-        public string Title { get; set; }
         [JsonPropertyName("version")]
         public string Version { get; set; }
-        [JsonPropertyName("launch_path")]
+        [JsonPropertyName("launch_options")]
+        public List<LaunchOption> LaunchOptions { get; set; }
+
+        public bool Verify()
+        {
+            if (LaunchOptions.Count == 0)
+            {
+                Console.WriteLine("need at least one launch config");
+                return false;
+            }
+
+            return LaunchOptions.All(x => x.Verify());
+        }
+    }
+
+    public class LaunchOption
+    {
+        [JsonPropertyName("title")]
+        public string Title { get; set; }
+        [JsonPropertyName("path")]
         public string LaunchPath { get; set; }
-        [JsonPropertyName("launch_env")]
-        public string LaunchEnv { get; set; }
-        [JsonPropertyName("launch_args")]
-        public string LaunchArgs { get; set; }
+        [JsonPropertyName("env")]
+        public string Env { get; set; }
+        [JsonPropertyName("args")]
+        public string Args { get; set; }
 
         public bool Verify()
         {
diff --git a/ManifestFactory.cs b/ManifestFactory.cs
index 31433f7490c7e482b9d140322d99e7e700f3af40..74e9e336636087bcdf3c9e69701ae7622f79d8bd 100644
--- a/ManifestFactory.cs
+++ b/ManifestFactory.cs
@@ -4,23 +4,26 @@ namespace sunrise_launcher
 {
     public interface IManifestFactory
     {
-        public IManifest Get(Server server);
+        public IManifest Get(string manifesturl);
     }
 
     public class ManifestFactory : IManifestFactory
     {
-        const string manifiesta_v1 = "manifiesta-v1";
+        const string sunrise_api = "sunrise-api";
+        const string sunrise_json = "sunrise-json";
         const string tequila_xml = "tequila-xml";
 
-        public IManifest Get(Server server)
+        public IManifest Get(string manifesturl)
         {
-            var schema = getSchema(server.ManifestURL);
+            var schema = getSchema(manifesturl);
             switch (schema)
             {
-                case manifiesta_v1:
-                    return new Manifiesta(server.ManifestURL);
+                case sunrise_api:
+                    return new SunriseApi(manifesturl);
+                case sunrise_json:
+                    return new SunriseJson(manifesturl);
                 case tequila_xml:
-                    return new TequilaXML(server.ManifestURL);
+                    return new TequilaXML(manifesturl);
             }
             return null;
         }
@@ -29,8 +32,10 @@ namespace sunrise_launcher
         {
             if (manifesturl.ToLower().EndsWith(".xml"))
                 return tequila_xml;
+            else if (manifesturl.ToLower().EndsWith(".json"))
+                return sunrise_json;
             else
-                return manifiesta_v1;
+                return sunrise_api;
         }
     }
 }
diff --git a/Server.cs b/Server.cs
index 42c729e70c8245803c2f8f449a7e18805f794bfc..c45baffa482b3a33d792e79c8937087b96930ac8 100644
--- a/Server.cs
+++ b/Server.cs
@@ -1,15 +1,21 @@
 using Qml.Net;
+using System.Collections.Generic;
 using System.Text.Json.Serialization;
 
 namespace sunrise_launcher
 {
-    public class Server : ManifestMetadata
+    public class Server
     {
         [JsonPropertyName("manifest_url")]
         [NotifySignal("manifestUrlChanged")]
         public string ManifestURL { get; set; }
         [JsonPropertyName("install_path")]
         public string InstallPath { get; set; }
+        [JsonPropertyName("metadata")]
+        public ManifestMetadata Metadata { get; set; }
+        [JsonPropertyName("launch")]
+        [NotifySignal("launchChanged")]
+        public string Launch { get; set; }
         [JsonIgnore]
         public State State { get; set; }
         [JsonIgnore]
diff --git a/ServerList.cs b/ServerList.cs
index 2bd396884635a82c5118f04105353623410b7be3..52607e611b778e5545f52198669f2b4b73ce3045 100644
--- a/ServerList.cs
+++ b/ServerList.cs
@@ -68,7 +68,42 @@ namespace sunrise_launcher
             file.Save(path);
         }
 
-        public async Task AddAsync(string manifesturl, string installpath)
+        public async Task<ManifestMetadata> FindMetadataAsync(string manifesturl)
+        {
+            manifesturl = manifesturl.Trim();
+
+            try
+            {
+                var manifest = manifestFactory.Get(manifesturl);
+                if (manifest == null)
+                {
+                    Console.WriteLine("Unknown manifest schema at '{0}'", manifesturl);
+                    return null;
+                }
+
+                var metadata = await manifest.GetMetadataAsync();
+                if (metadata == null)
+                {
+                    Console.WriteLine("Could not retrieve manifest from '{0}'", manifesturl);
+                    return null;
+                }
+
+                if (!metadata.Verify())
+                {
+                    Console.WriteLine("Manifest metadata failed inspection '{0}'", manifesturl);
+                    return null;
+                }
+
+                return metadata;
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("Exception in FindMetadataAsync: {0}", ex.Message);
+                return null;
+            }
+        }
+
+        public async Task AddAsync(string manifesturl, string installpath, string launch)
         {
             manifesturl = manifesturl.Trim();
             if (Servers.Any(x => x.ManifestURL == manifesturl))
@@ -80,11 +115,12 @@ namespace sunrise_launcher
             var server = new Server();
             server.ManifestURL = manifesturl;
             server.InstallPath = CleanInstallPath(installpath);
+            server.Launch = launch;
 
-            await GetInfoAsync(server);
-            if (server.State == State.Error)
+            server.Metadata = await FindMetadataAsync(manifesturl);
+            if (server.Metadata == null)
             {
-                ShowMessage(server.Error);
+                ShowMessage("Server add failed.");
                 return;
             }
 
@@ -97,15 +133,16 @@ namespace sunrise_launcher
             ShowMessage(server.Error);
         }
 
-        public async Task ConfigAsync(string oldmanifesturl, string manifesturl, string installpath)
+        public async Task ConfigAsync(string oldmanifesturl, string manifesturl, string installpath, string launch)
         {
             var server = Get(oldmanifesturl);
             if (server == null) return;
             server.ManifestURL = manifesturl.Trim();
             server.InstallPath = CleanInstallPath(installpath);
+            server.Launch = launch;
 
-            await GetInfoAsync(server);
-            this.ActivateSignal("update");
+            //await GetInfoAsync(server);
+            //this.ActivateSignal("update");
 
             await UpdateAsync(server, false);
             this.ActivateSignal("update");
@@ -161,7 +198,8 @@ namespace sunrise_launcher
             ShowMessage(server.Error);
         }
 
-        //this is called only when a new server is added
+        //this is called only when a new server is added or modified
+        /*
         private async Task GetInfoAsync(Server server)
         {
             if (server.State == State.Updating)
@@ -170,7 +208,7 @@ namespace sunrise_launcher
 
             try
             {
-                var manifest = manifestFactory.Get(server);
+                var manifest = manifestFactory.Get(server.ManifestURL);
                 if (manifest == null)
                 {
                     Console.WriteLine("Unknown manifest schema at '{0}'", server.ManifestURL);
@@ -196,10 +234,16 @@ namespace sunrise_launcher
                     return;
                 }
 
-                server.Title = metadata.Title;
-                server.LaunchPath = metadata.LaunchPath;
-                server.LaunchEnv = metadata.LaunchEnv;
-                server.LaunchArgs = metadata.LaunchArgs;
+                server.Metadata = metadata;
+
+                if (metadata.LaunchOptions.Count == 0)
+                {
+                    server.LaunchConfig = null;
+                }
+                else if (metadata.LaunchOptions.All(x => x.Title != server.LaunchConfig))
+                {
+                    server.LaunchConfig = metadata.LaunchOptions[0].Title;
+                }
             }
             catch (Exception ex)
             {
@@ -208,7 +252,7 @@ namespace sunrise_launcher
                 server.Error = "Unknown Exception";
             }
         }
-
+        */
         private async Task UpdateAsync(Server server, bool force)
         {
             if (server.State == State.Updating)
@@ -220,7 +264,7 @@ namespace sunrise_launcher
             {
                 UpdateProgress(server, "Retrieving Manfiest", 0, 0);
                 
-                var manifest = manifestFactory.Get(server);
+                var manifest = manifestFactory.Get(server.ManifestURL);
                 if (manifest == null)
                 {
                     Console.WriteLine("Unknown manifest schema at '{0}'", server.ManifestURL);
@@ -246,7 +290,7 @@ namespace sunrise_launcher
                     return;
                 }
 
-                if (force || metadata.Version != server.Version)
+                if (force || metadata.Version != server.Metadata.Version)
                 {
                     await updatefiles(server, manifest, server.InstallPath);
                 }
@@ -257,11 +301,13 @@ namespace sunrise_launcher
 
                 if (server.State == State.Ready)
                 {
-                    server.Title = metadata.Title;
-                    server.Version = metadata.Version;
-                    server.LaunchPath = metadata.LaunchPath;
-                    server.LaunchEnv = metadata.LaunchEnv;
-                    server.LaunchArgs = metadata.LaunchArgs;
+                    server.Metadata = metadata;
+                }
+
+                //if update occurs which removes the selected launch option, default to first option available
+                if (metadata.LaunchOptions.All(x => x.Title != server.Launch))
+                {
+                    server.Launch = metadata.LaunchOptions[0].Title;
                 }
             }
             catch (Exception ex)
@@ -436,12 +482,18 @@ namespace sunrise_launcher
 
             try
             {
-                var fullpath = Path.Combine(server.InstallPath, server.LaunchPath);
+                var launch = server.Metadata.LaunchOptions.FirstOrDefault(x => x.Title == server.Launch);
+                if (launch == null)
+                {
+                    Console.WriteLine("ERROR: launch option not found: {0}", server.Launch);
+                }
+
+                var fullpath = Path.Combine(server.InstallPath, launch.LaunchPath);
 
                 var process = new Process();
                 process.StartInfo.WorkingDirectory = Path.GetDirectoryName(fullpath);
                 process.StartInfo.FileName = fullpath;
-                process.StartInfo.Arguments = server.LaunchArgs;
+                process.StartInfo.Arguments = launch.Args;
                 process.StartInfo.WindowStyle = ProcessWindowStyle.Maximized;
                 process.Start();
             }
diff --git a/Manifiesta.cs b/SunriseApi.cs
similarity index 95%
rename from Manifiesta.cs
rename to SunriseApi.cs
index 010258a31c0e8fa4d681fc84bbc0a1b91b5433ee..110ce5ab6603175cb1c4356556e3ca1fa7f645c8 100644
--- a/Manifiesta.cs
+++ b/SunriseApi.cs
@@ -8,12 +8,12 @@ using System.Threading.Tasks;
 
 namespace sunrise_launcher
 {
-    public class Manifiesta : IManifest
+    public class SunriseApi : IManifest
     {
         private static HttpClient client = new HttpClient();
         private string URL;
 
-        public Manifiesta(string url)
+        public SunriseApi(string url)
         {
             URL = url;
         }
diff --git a/SunriseJson.cs b/SunriseJson.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2ed5f80709576d87f2d6ecea07fe4abf5fed13dd
--- /dev/null
+++ b/SunriseJson.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Security.Cryptography;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using System.Threading.Tasks;
+
+namespace sunrise_launcher
+{
+    public class SunriseJson : IManifest
+    {
+        private static HttpClient client = new HttpClient();
+        private string URL;
+        private Manifest Manifest;
+
+        public SunriseJson(string url)
+        {
+            URL = url;
+        }
+
+        private async Task FetchManifest()
+        {
+            if (Manifest != null)
+                return;
+
+            try
+            {
+                var response = await client.GetAsync(URL);
+                if (response.IsSuccessStatusCode)
+                {
+                    using (var reader = await response.Content.ReadAsStreamAsync())
+                    {
+                        Manifest = await JsonSerializer.DeserializeAsync<Manifest>(reader);
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("exception while retrieving manifest: {0}", ex.Message);
+            }
+        }
+
+        public async Task<ManifestMetadata> GetMetadataAsync()
+        {
+            try
+            {
+                await FetchManifest();
+                return Manifest;
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("exception while retrieving manifest: {0}", ex.Message);
+            }
+            return null;
+        }
+
+        public async Task<IList<ManifestFile>> GetFilesAsync()
+        {
+            try
+            {
+                await FetchManifest();
+                if (Manifest == null)
+                    return null;
+
+                return Manifest.Files;
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("exception while retrieving manifest: {0}", ex.Message);
+            }
+            return null;
+        }
+    }
+}
diff --git a/TequilaXML.cs b/TequilaXML.cs
index b3ad3750ef597b316763e84b40694b051b04538d..5292b7a160bd199a714676c54ca47a09a8ca4d1b 100644
--- a/TequilaXML.cs
+++ b/TequilaXML.cs
@@ -54,14 +54,19 @@ namespace sunrise_launcher
             if (TequilaRoot == null)
                 return null;
 
-            if (TequilaRoot.Profiles.Count == 0)
-                return null;
-
             var metadata = new ManifestMetadata();
             metadata.Version = Hash;
-            metadata.Title = TequilaRoot.Profiles[0].Value;
-            metadata.LaunchPath = TequilaRoot.Profiles[0].Exec;
-            metadata.LaunchArgs = TequilaRoot.Profiles[0].Params;
+            metadata.LaunchOptions = new List<LaunchOption>();
+
+            foreach (var profile in TequilaRoot.Profiles)
+            {
+                var config = new LaunchOption();
+                config.Title = profile.Value;
+                config.LaunchPath = profile.Exec;
+                config.Args = profile.Params;
+                metadata.LaunchOptions.Add(config);
+            }
+
             return metadata;
         }
 
diff --git a/main.js b/main.js
index 6248bd1559a52adc0594257dd56d62b61a96dce8..d528225557fc5b2eab36f042c687595340ae0ead 100644
--- a/main.js
+++ b/main.js
@@ -109,25 +109,93 @@ function configOpen(manifestURL) {
 
     textfield_manifesturl.text = server.manifestURL;
     textfield_installpath.text = server.installPath;
+
+    populateLaunchOptions(server.metadata);
+    combobox_launch.currentIndex = combobox_launch.find(server.launch);
+
     dialog_config.manifestURL = manifestURL;
-    dialog_config.title = server.title;
     dialog_config.visible = true;
 }
 
+function populateLaunchOptions(metadata) {
+    var options = [];
+    Net.listForEach(metadata.launchOptions, function (option) {
+        options.push(option.title);
+    });
+    combobox_launch.model = options;
+}
+
+function configUrlChanged() {
+    combobox_launch.currentIndex = -1;
+    combobox_launch.model = [];
+}
+
+function findUrl() {
+    combobox_launch.currentIndex = -1;
+    combobox_launch.model = [];
+
+    if (textfield_manifesturl.text === "") {
+        showInfo("Please enter a URL for the manifest.")
+        return;
+    }
+
+    var task = serverlist.findMetadataAsync(textfield_manifesturl.text);
+    Net.await(task, function (metadata) {
+        if (metadata == null) {
+            showMessage("Could not retrieve manifest at that location.")
+            return;
+        }
+        populateLaunchOptions(metadata);
+        combobox_launch.currentIndex = 0;
+    });
+}
+
 function configNew() {
     textfield_manifesturl.text = "";
     textfield_installpath.text = "";
     dialog_config.manifestURL = "";
+    combobox_launch.currentIndex = -1;
+    combobox_launch.model = [];
     dialog_config.title = "New Server";
     dialog_config.visible = true;
+    
 }
 
-function configSave() {
+function configSave(action) {
+    if (action.button == StandardButton.Cancel)
+        return;
+
+    if (textfield_manifesturl.text === "") {
+        showInfo("Please enter a URL for the manifest.")
+        action.accepted = false;
+        return;
+    }
+
+    //auto "find" and select first launch option
+    if (combobox_launch.currentIndex == -1) {
+        var task = serverlist.findMetadataAsync(textfield_manifesturl.text);
+        Net.await(task, function (metadata) {
+            if (metadata == null) {
+                showMessage("Could not retrieve manifest at that location.")
+                return;
+            }
+            populateLaunchOptions(metadata);
+            combobox_launch.currentIndex = 0;
+
+            if (dialog_config.manifestURL === "") {
+                serverlist.addAsync(textfield_manifesturl.text, textfield_installpath.text, combobox_launch.currentText);
+                return;
+            }
+            serverlist.configAsync(dialog_config.manifestURL, textfield_manifesturl.text, textfield_installpath.text, combobox_launch.currentText);
+        });
+        return;
+    }
+
     if (dialog_config.manifestURL === "") {
-        serverlist.addAsync(textfield_manifesturl.text, textfield_installpath.text);
+        serverlist.addAsync(textfield_manifesturl.text, textfield_installpath.text, combobox_launch.currentText);
         return;
     }
-    serverlist.configAsync(dialog_config.manifestURL, textfield_manifesturl.text, textfield_installpath.text);
+    serverlist.configAsync(dialog_config.manifestURL, textfield_manifesturl.text, textfield_installpath.text, combobox_launch.currentText);
 }
 
 function showError(error) {
@@ -141,6 +209,11 @@ function showMessage(msg) {
     dialogError.visible = true;
 }
 
+function showInfo(msg) {
+    dialogInfo.text = msg;
+    dialogInfo.visible = true;
+}
+
 function refreshProgress(manifestURL, taskName, taskDone, taskCount) {
     if (serverlist.selected == null || taskName == "") {
         paneProgress.visible = false;
diff --git a/main.qml b/main.qml
index 8a5f0e7651c53e0c990a489f37d71f428d112fd7..af7254ea95921d0e4dc1843dba687e5002ea332a 100644
--- a/main.qml
+++ b/main.qml
@@ -159,7 +159,7 @@ ApplicationWindow {
                         RadioButton {
                             id: button_server
                             y: 10
-                            text: modelData.title
+                            text: modelData.launch
                             ButtonGroup.group: buttongroup_servers
                             anchors.verticalCenter: parent.verticalCenter
                             anchors.left: button_remove.right
@@ -384,8 +384,10 @@ ApplicationWindow {
         standardButtons: StandardButton.Save | StandardButton.Cancel
         modality: Qt.WindowModal
         property string manifestURL
-        onAccepted: Main.configSave();
-        width: 500
+        property bool verified
+        onActionChosen: Main.configSave(action);
+        width: 548
+        height: 400
         
         GridLayout {
             
@@ -394,7 +396,22 @@ ApplicationWindow {
             anchors.right: parent.right
             anchors.rightMargin: 0
 
-            columns: 2
+            columns: 3
+
+            Text {
+                text: "Install Path"
+                font.family: fontMont.name
+            }
+
+            TextField {
+                placeholderText: "ex: servername or C:/CoH"
+                font.family: fontMont.name
+                id: textfield_installpath
+                Layout.fillWidth: true
+                selectByMouse: true
+            }
+
+            Text { text: " " }
 
             Text {
                 text: "Manifest URL"
@@ -406,19 +423,25 @@ ApplicationWindow {
                 id: textfield_manifesturl
                 Layout.fillWidth: true
                 selectByMouse: true
+                onTextChanged: Main.configUrlChanged()
+            }
+
+            Button {
+                text: "Find"
+                id: "button_findurl"
+                onClicked: Main.findUrl()
             }
 
             Text {
-                text: "Install Path"
+                text: "Launch"
                 font.family: fontMont.name
             }
 
-            TextField {
-                placeholderText: "ex: servername or C:/CoH"
-                font.family: fontMont.name
-                id: textfield_installpath
+            ComboBox {
+                id: combobox_launch
                 Layout.fillWidth: true
-                selectByMouse: true
+                font.family: fontMont.name
+                palette.highlightedText: "black"
             }
         }
     }
@@ -441,6 +464,12 @@ ApplicationWindow {
         informativeText: "See log.txt for details"
     }
 
+    MessageDialog {
+        id: dialogInfo
+        modality: Qt.WindowModal
+        standardButtons: StandardButton.Ok
+    }
+
     Component.onCompleted: Main.init()
     onClosing: serverlist.save("./servers.json");
 }
\ No newline at end of file
diff --git a/sunrise-launcher.csproj b/sunrise-launcher.csproj
index 87bfcac9ae848daca2fa064c3dbd52c81ed6eeea..a4fbf7b72debb9af393f3688ab9a4069e2bae458 100644
--- a/sunrise-launcher.csproj
+++ b/sunrise-launcher.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <OutputType>WinExe</OutputType>
+    <OutputType>Exe</OutputType>
     <TargetFramework>netcoreapp3.1</TargetFramework>
     <PublishTrimmed>true</PublishTrimmed>
     <PublishReadyToRun>true</PublishReadyToRun>