diff --git a/Cargo.lock b/Cargo.lock
index 4c9b8ce4a36..d8469af6d49 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1407,6 +1407,17 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
+[[package]]
+name = "displaydoc"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.64",
+]
+
 [[package]]
 name = "distance"
 version = "0.4.0"
@@ -6579,6 +6590,7 @@ dependencies = [
  "wasmer-wasix",
  "wasmer-wast",
  "webc",
+ "zip",
 ]
 
 [[package]]
@@ -7671,3 +7683,18 @@ name = "zeroize"
 version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
+
+[[package]]
+name = "zip"
+version = "1.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c700ea425e148de30c29c580c1f9508b93ca57ad31c9f4e96b83c194c37a7a8f"
+dependencies = [
+ "arbitrary",
+ "crc32fast",
+ "crossbeam-utils 0.8.19",
+ "displaydoc",
+ "flate2",
+ "indexmap 2.2.6",
+ "thiserror",
+]
diff --git a/lib/backend-api/src/query.rs b/lib/backend-api/src/query.rs
index 8a76b27b5ad..8ac41cdc69c 100644
--- a/lib/backend-api/src/query.rs
+++ b/lib/backend-api/src/query.rs
@@ -12,7 +12,8 @@ use wasmer_config::package::PackageIdent;
 use crate::{
     types::{
         self, CreateNamespaceVars, DeployApp, DeployAppConnection, DeployAppVersion,
-        DeployAppVersionConnection, DnsDomain, GetCurrentUserWithAppsVars, GetDeployAppAndVersion,
+        DeployAppVersionConnection, DnsDomain, GetAppTemplateFromSlugVariables,
+        GetAppTemplatesQueryVariables, GetCurrentUserWithAppsVars, GetDeployAppAndVersion,
         GetDeployAppVersionsVars, GetNamespaceAppsVars, GetSignedUrlForPackageUploadVariables, Log,
         LogStream, PackageVersionConnection, PublishDeployAppVars, PushPackageReleasePayload,
         SignedUrl, TagPackageReleasePayload, UpsertDomainFromZoneFileVars,
@@ -55,6 +56,36 @@ pub async fn fetch_webc_package(
     webc::compat::Container::from_bytes(data).context("failed to parse webc package")
 }
 
+/// Fetch app templates.
+pub async fn fetch_app_template_from_slug(
+    client: &WasmerClient,
+    slug: String,
+) -> Result<Option<types::AppTemplate>, anyhow::Error> {
+    client
+        .run_graphql_strict(types::GetAppTemplateFromSlug::build(
+            GetAppTemplateFromSlugVariables { slug },
+        ))
+        .await
+        .map(|v| v.get_app_template)
+}
+
+/// Fetch app templates.
+pub async fn fetch_app_templates(
+    client: &WasmerClient,
+    category_slug: String,
+    first: i32,
+) -> Result<Option<types::AppTemplateConnection>, anyhow::Error> {
+    client
+        .run_graphql_strict(types::GetAppTemplatesQuery::build(
+            GetAppTemplatesQueryVariables {
+                category_slug,
+                first,
+            },
+        ))
+        .await
+        .map(|r| r.get_app_templates)
+}
+
 /// Get a signed URL to upload packages.
 pub async fn get_signed_url_for_package_upload(
     client: &WasmerClient,
diff --git a/lib/backend-api/src/types.rs b/lib/backend-api/src/types.rs
index 9c6b408a22b..45869eb7370 100644
--- a/lib/backend-api/src/types.rs
+++ b/lib/backend-api/src/types.rs
@@ -121,11 +121,75 @@ mod queries {
         pub version: String,
         pub created_at: DateTime,
         pub pirita_manifest: Option<JSONString>,
-        pub distribution: PackageDistribution,
-
         pub package: Package,
+
+        #[arguments(version: "V3")]
+        #[cynic(rename = "distribution")]
+        pub distribution_v3: PackageDistribution,
+
+        #[arguments(version: "V2")]
+        #[cynic(rename = "distribution")]
+        pub distribution_v2: PackageDistribution,
+    }
+
+    #[derive(cynic::QueryVariables, Debug)]
+    pub struct GetAppTemplateFromSlugVariables {
+        pub slug: String,
+    }
+
+    #[derive(cynic::QueryFragment, Debug)]
+    #[cynic(graphql_type = "Query", variables = "GetAppTemplateFromSlugVariables")]
+    pub struct GetAppTemplateFromSlug {
+        #[arguments(slug: $slug)]
+        pub get_app_template: Option<AppTemplate>,
+    }
+    #[derive(cynic::QueryVariables, Debug)]
+    pub struct GetAppTemplatesQueryVariables {
+        pub category_slug: String,
+        pub first: i32,
+    }
+
+    #[derive(cynic::QueryFragment, Debug)]
+    #[cynic(graphql_type = "Query", variables = "GetAppTemplatesQueryVariables")]
+    pub struct GetAppTemplatesQuery {
+        #[arguments(categorySlug: $category_slug, first: $first)]
+        pub get_app_templates: Option<AppTemplateConnection>,
+    }
+
+    #[derive(cynic::QueryFragment, Debug)]
+    pub struct AppTemplateConnection {
+        pub edges: Vec<Option<AppTemplateEdge>>,
+        pub page_info: PageInfo,
     }
 
+    #[derive(cynic::QueryFragment, Debug)]
+    pub struct AppTemplateEdge {
+        pub node: Option<AppTemplate>,
+        pub cursor: String,
+    }
+
+    #[derive(cynic::QueryFragment, Debug)]
+    pub struct AppTemplate {
+        pub demo_url: String,
+        pub language: String,
+        pub name: String,
+        pub framework: String,
+        pub created_at: DateTime,
+        pub description: String,
+        pub id: cynic::Id,
+        pub is_public: bool,
+        pub repo_license: String,
+        pub readme: String,
+        pub repo_url: String,
+        pub slug: String,
+        pub updated_at: DateTime,
+        pub use_cases: Jsonstring,
+    }
+
+    #[derive(cynic::Scalar, Debug, Clone)]
+    #[cynic(graphql_type = "JSONString")]
+    pub struct Jsonstring(pub String);
+
     #[derive(cynic::QueryVariables, Debug)]
     pub struct GetPackageReleaseVars {
         pub hash: String,
diff --git a/lib/cli/Cargo.toml b/lib/cli/Cargo.toml
index 3388ffbeee6..8ffb36fcfc5 100644
--- a/lib/cli/Cargo.toml
+++ b/lib/cli/Cargo.toml
@@ -118,7 +118,7 @@ wasmer-compiler-singlepass = { version = "=4.3.0", path = "../compiler-singlepas
 wasmer-compiler-llvm = { version = "=4.3.0", path = "../compiler-llvm", optional = true }
 wasmer-emscripten = { version = "=4.3.0", path = "../emscripten" }
 wasmer-vm = { version = "=4.3.0", path = "../vm", optional = true }
-wasmer-wasix = { path = "../wasix", version="=0.20.0" , features = [
+wasmer-wasix = { path = "../wasix", version = "=0.20.0", features = [
 	"logging",
 	"webc_runner_rt_wcgi",
 	"webc_runner_rt_dcgi",
@@ -185,7 +185,7 @@ tldextract = "0.6.0"
 hex = "0.4.3"
 flate2 = "1.0.25"
 cargo_metadata = "0.15.2"
-tar = "0.4.38"
+tar = "0.4.40"
 bytes = "1"
 thiserror = "1.0.37"
 log = "0.4.17"
@@ -229,6 +229,7 @@ tun-tap = { version = "0.1.3", features = ["tokio"], optional = true }
 
 clap_complete = "4.5.2"
 clap_mangen = "0.2.20"
+zip = { version = "1.2.3", default-features = false, features = ["deflate"] }
 
 # NOTE: Must use different features for clap because the "color" feature does not
 # work on wasi due to the anstream dependency not compiling.
diff --git a/lib/cli/src/commands/app/create.rs b/lib/cli/src/commands/app/create.rs
index 4a3299b1cf8..5a6668a4290 100644
--- a/lib/cli/src/commands/app/create.rs
+++ b/lib/cli/src/commands/app/create.rs
@@ -3,23 +3,17 @@
 use crate::{
     commands::AsyncCliCommand,
     opts::{ApiOpts, ItemFormatOpts, WasmerEnv},
-    utils::{
-        load_package_manifest,
-        package_wizard::{CreateMode, PackageType, PackageWizard},
-    },
+    utils::{load_package_manifest, prompts::PackageCheckMode},
 };
 use anyhow::Context;
 use colored::Colorize;
 use dialoguer::{theme::ColorfulTheme, Confirm, Select};
 use is_terminal::IsTerminal;
-use std::{collections::HashMap, env, path::PathBuf, str::FromStr};
-use wasmer_api::{types::UserWithNamespaces, WasmerClient};
-use wasmer_config::{
-    app::AppConfigV1,
-    package::{NamedPackageIdent, PackageSource, Tag},
-};
+use std::{collections::HashMap, env, io::Cursor, path::PathBuf, str::FromStr};
+use wasmer_api::{types::AppTemplate, WasmerClient};
+use wasmer_config::{app::AppConfigV1, package::PackageSource};
 
-use super::deploy::CmdAppDeploy;
+use super::{deploy::CmdAppDeploy, util::login_user};
 
 async fn write_app_config(app_config: &AppConfigV1, dir: Option<PathBuf>) -> anyhow::Result<()> {
     let raw_app_config = app_config.clone().to_yaml()?;
@@ -41,8 +35,30 @@ async fn write_app_config(app_config: &AppConfigV1, dir: Option<PathBuf>) -> any
 /// Create a new Edge app.
 #[derive(clap::Parser, Debug)]
 pub struct CmdAppCreate {
-    #[clap(name = "type", short = 't', long)]
-    pub template: Option<AppType>,
+    /// A reference to the template to use.
+    ///
+    /// It can be either an URL to a github repository - like
+    /// `https://github.com/wasmer-examples/php-wasmer-starter` -  or the name of a template that
+    /// will be searched for in the selected registry, like `astro-starter`.
+    #[clap(
+        long,
+        conflicts_with = "package",
+        conflicts_with = "use_local_manifest"
+    )]
+    pub template: Option<String>,
+
+    /// Name of the package to use.
+    #[clap(
+        long,
+        conflicts_with = "template",
+        conflicts_with = "use_local_manifest"
+    )]
+    pub package: Option<String>,
+
+    /// Whether or not to search (and use) a local manifest.
+    #[clap(long, conflicts_with = "template", conflicts_with = "package")]
+    pub use_local_manifest: bool,
+
     /// Whether or not to deploy the application once it is created.
     ///
     /// If selected, this might entail the step of publishing the package related to the
@@ -71,7 +87,7 @@ pub struct CmdAppCreate {
     pub app_name: Option<String>,
 
     /// The path to the directory where the config file for the application will be written to.
-    #[clap(long = "path")]
+    #[clap(long = "dir")]
     pub app_dir_path: Option<PathBuf>,
 
     /// Do not wait for the app to become reachable if deployed.
@@ -90,17 +106,13 @@ pub struct CmdAppCreate {
     #[allow(missing_docs)]
     pub fmt: ItemFormatOpts,
 
-    /// Name of the package to use.
-    #[clap(long, short = 'p')]
-    pub package: Option<String>,
-
-    /// Whether or not to search (and use) a local manifest.
-    #[clap(long)]
-    pub use_local_manifest: bool,
-
     /// Name to use when creating a new package from a template.
     #[clap(long)]
     pub new_package_name: Option<String>,
+
+    /// Don't print any message.
+    #[clap(long)]
+    pub quiet: bool,
 }
 
 impl CmdAppCreate {
@@ -134,18 +146,25 @@ impl CmdAppCreate {
             anyhow::bail!("No app name specified: use --name <app_name>");
         }
 
-        let default_name = env::current_dir().ok().and_then(|dir| {
-            dir.file_name()
+        let default_name = match &self.app_dir_path {
+            Some(path) => path
+                .file_name()
                 .and_then(|f| f.to_str())
-                .map(|s| s.to_owned())
-        });
+                .map(|s| s.to_owned()),
+            None => env::current_dir().ok().and_then(|dir| {
+                dir.file_name()
+                    .and_then(|f| f.to_str())
+                    .map(|s| s.to_owned())
+            }),
+        };
+
         crate::utils::prompts::prompt_for_ident(
             "What should be the name of the app?",
             default_name.as_deref(),
         )
     }
 
-    async fn get_owner(&self) -> anyhow::Result<String> {
+    async fn get_owner(&self, client: Option<&WasmerClient>) -> anyhow::Result<String> {
         if let Some(owner) = &self.owner {
             return Ok(owner.clone());
         }
@@ -155,28 +174,12 @@ impl CmdAppCreate {
             anyhow::bail!("No owner specified: use --owner <owner>");
         }
 
-        if !self.offline {
-            match self.api.client() {
-                Ok(client) => {
-                    let user =
-                        wasmer_api::query::current_user_with_namespaces(&client, None).await?;
-                    crate::utils::prompts::prompt_for_namespace(
-                        "Who should own this app?",
-                        None,
-                        Some(&user),
-                    )
-                }
-                Err(e) => anyhow::bail!(
-                "Can't determine user info: {e}. Please, user `wasmer login` before deploying an
-                app or use the --owner <owner> flag to specify the owner of the app to deploy."
-            ),
-            }
+        let user = if let Some(client) = client {
+            Some(wasmer_api::query::current_user_with_namespaces(client, None).await?)
         } else {
-            anyhow::bail!(
-                "Please, user `wasmer login` before deploying an app or use the --owner <owner>
-                flag to specify the owner of the app to deploy."
-            )
-        }
+            None
+        };
+        crate::utils::prompts::prompt_for_namespace("Who should own this app?", None, user.as_ref())
     }
 
     async fn create_from_local_manifest(
@@ -184,7 +187,10 @@ impl CmdAppCreate {
         owner: &str,
         app_name: &str,
     ) -> anyhow::Result<bool> {
-        if !self.use_local_manifest && self.non_interactive {
+        if (!self.use_local_manifest && self.non_interactive)
+            || self.template.is_some()
+            || self.package.is_some()
+        {
             return Ok(false);
         }
 
@@ -213,17 +219,21 @@ impl CmdAppCreate {
         };
 
         if self.use_local_manifest || ask_confirmation()? {
-            let app_config =
-                self.get_app_config(owner, app_name, manifest_path.to_string_lossy().as_ref());
+            let app_config = self.get_app_config(owner, app_name, ".");
             write_app_config(&app_config, self.app_dir_path.clone()).await?;
-            self.try_deploy(owner).await?;
+            self.try_deploy(owner, app_name).await?;
             return Ok(true);
         }
 
         Ok(false)
     }
 
-    async fn create_from_package(&self, owner: &str, app_name: &str) -> anyhow::Result<bool> {
+    async fn create_from_package(
+        &self,
+        client: Option<&WasmerClient>,
+        owner: &str,
+        app_name: &str,
+    ) -> anyhow::Result<bool> {
         if self.template.is_some() {
             return Ok(false);
         }
@@ -231,17 +241,24 @@ impl CmdAppCreate {
         if let Some(pkg) = &self.package {
             let app_config = self.get_app_config(owner, app_name, pkg);
             write_app_config(&app_config, self.app_dir_path.clone()).await?;
-            self.try_deploy(owner).await?;
+            self.try_deploy(owner, app_name).await?;
             return Ok(true);
         } else if !self.non_interactive {
-            let theme = ColorfulTheme::default();
-            let package_name: String = dialoguer::Input::with_theme(&theme)
-                .with_prompt("What is the name of the package?")
-                .interact()?;
+            let (package_id, _) = crate::utils::prompts::prompt_for_package(
+                "Enter the name of the package",
+                Some("wasmer/hello"),
+                if client.is_some() {
+                    Some(PackageCheckMode::MustExist)
+                } else {
+                    None
+                },
+                client,
+            )
+            .await?;
 
-            let app_config = self.get_app_config(owner, app_name, &package_name);
+            let app_config = self.get_app_config(owner, app_name, &package_id.to_string());
             write_app_config(&app_config, self.app_dir_path.clone()).await?;
-            self.try_deploy(owner).await?;
+            self.try_deploy(owner, app_name).await?;
             return Ok(true);
         } else {
             eprintln!(
@@ -253,109 +270,227 @@ impl CmdAppCreate {
         Ok(false)
     }
 
-    async fn create_from_template(&self, owner: &str, app_name: &str) -> anyhow::Result<bool> {
-        let template = match self.template {
-            Some(t) => t,
-            None => {
-                if !self.non_interactive {
-                    let theme = ColorfulTheme::default();
-                    let index = dialoguer::Select::with_theme(&theme)
-                        .with_prompt("App type")
-                        .default(0)
-                        .items(&[
-                            "Static website",
-                            "HTTP server",
-                            "Browser shell",
-                            "JS Worker (WinterJS)",
-                            "Python Application",
-                        ])
-                        .interact()?;
-                    match index {
-                        0 => AppType::StaticWebsite,
-                        1 => AppType::HttpServer,
-                        2 => AppType::BrowserShell,
-                        3 => AppType::JsWorker,
-                        4 => AppType::PyApplication,
-                        x => panic!("unhandled app type index '{x}'"),
-                    }
-                } else {
-                    return Ok(false);
-                }
+    // A utility function used to fetch the URL of the template to use.
+    async fn get_template_url(&self, client: &WasmerClient) -> anyhow::Result<url::Url> {
+        let mut url = if let Some(template) = &self.template {
+            if let Ok(url) = url::Url::parse(template) {
+                url
+            } else if let Some(template) =
+                wasmer_api::query::fetch_app_template_from_slug(client, template.clone()).await?
+            {
+                url::Url::parse(&template.repo_url)?
+            } else {
+                anyhow::bail!("Template '{}' not found in the registry", template)
+            }
+        } else {
+            if self.non_interactive {
+                anyhow::bail!("No template selected")
             }
-        };
-
-        let allow_local_package = match template {
-            AppType::HttpServer => true,
-            AppType::StaticWebsite => true,
-            AppType::BrowserShell => false,
-            AppType::JsWorker => true,
-            AppType::PyApplication => true,
-        };
 
-        let app_dir_path = match &self.app_dir_path {
-            Some(dir) => dir.clone(),
-            None => std::env::current_dir()?,
-        };
+            let templates: Vec<AppTemplate> =
+                wasmer_api::query::fetch_app_templates(client, String::new(), 10)
+                    .await?
+                    .ok_or(anyhow::anyhow!("No template received from the backend"))?
+                    .edges
+                    .into_iter()
+                    .flatten()
+                    .filter_map(|v| v.node)
+                    .collect();
 
-        let local_package = if allow_local_package {
-            match crate::utils::load_package_manifest(&app_dir_path) {
-                Ok(Some(p)) => Some(p),
-                Ok(None) => None,
-                Err(err) => {
-                    eprintln!(
-                        "{warning}: could not load package manifest: {err}",
-                        warning = "Warning".yellow(),
-                    );
-                    None
-                }
+            let theme = ColorfulTheme::default();
+            let items = templates
+                .iter()
+                .map(|t| {
+                    format!(
+                        "{}{}\n  {} {}",
+                        t.name.bold(),
+                        if t.language.is_empty() {
+                            String::new()
+                        } else {
+                            format!(" {}", t.language.dimmed())
+                        },
+                        "demo:".bold().dimmed(),
+                        t.demo_url.dimmed()
+                    )
+                })
+                .collect::<Vec<_>>();
+
+            let dialog = dialoguer::Select::with_theme(&theme)
+                .with_prompt(format!("Select a template ({} available)", items.len()))
+                .items(&items)
+                .max_length(6)
+                .clear(true)
+                .report(false)
+                .default(0);
+
+            let selection = dialog.interact()?;
+
+            let selected_template = templates
+                .get(selection)
+                .ok_or(anyhow::anyhow!("Invalid selection!"))?;
+
+            if !self.quiet {
+                eprintln!(
+                    "{} {} {} {} ({} {})",
+                    "✔".green().bold(),
+                    "Selected template".bold(),
+                    "·".dimmed(),
+                    selected_template.name.green().bold(),
+                    "demo url".dimmed().bold(),
+                    selected_template.demo_url.dimmed()
+                )
             }
-        } else {
-            None
+
+            url::Url::parse(&selected_template.repo_url)?
         };
 
-        let user = if self.offline {
-            None
-        } else if let Ok(client) = &self.api.client() {
-            let u = wasmer_api::query::current_user_with_namespaces(
-                client,
-                Some(wasmer_api::types::GrapheneRole::Admin),
-            )
-            .await?;
-            Some(u)
+        let url = if url.path().contains("archive/refs/heads") || url.path().contains("/zipball/") {
+            url
         } else {
-            None
+            let old_path = url.path();
+            url.set_path(&format!("{old_path}/zipball/main"));
+            url
         };
-        let creator = AppCreator {
-            app_name: String::from(app_name),
-            new_package_name: self.new_package_name.clone(),
-            package: self.package.clone(),
-            template,
-            interactive: !self.non_interactive,
-            app_dir_path,
-            owner: String::from(owner),
-            api: if self.offline {
-                None
-            } else {
-                self.api.client().ok()
-            },
-            user,
-            local_package,
+
+        Ok(url)
+    }
+
+    async fn create_from_template(
+        &self,
+        client: Option<&WasmerClient>,
+        owner: &str,
+        app_name: &str,
+    ) -> anyhow::Result<bool> {
+        let client = match client {
+            Some(client) => client,
+            None => anyhow::bail!("Cannot"),
         };
 
-        match template {
-            AppType::HttpServer
-            | AppType::StaticWebsite
-            | AppType::JsWorker
-            | AppType::PyApplication => creator.build_app().await?,
-            AppType::BrowserShell => creator.build_browser_shell_app().await?,
+        let url = self.get_template_url(client).await?;
+
+        tracing::info!("Downloading template from url {url}");
+
+        let output_path = if let Some(path) = &self.app_dir_path {
+            path.clone()
+        } else {
+            PathBuf::from(".").canonicalize()?
         };
 
-        self.try_deploy(owner).await?;
+        if output_path.is_dir() && output_path.read_dir()?.next().is_some() {
+            if !self.quiet {
+                eprintln!("The current directory is not empty.");
+                eprintln!("Use the `--dir` flag to specify another directory, or remove files from the currently selected one.")
+            }
+            anyhow::bail!("Stopping as the directory is not empty")
+        }
+
+        let pb = indicatif::ProgressBar::new_spinner();
+
+        pb.enable_steady_tick(std::time::Duration::from_millis(500));
+        pb.set_style(
+            indicatif::ProgressStyle::with_template("{spinner:.magenta} {msg}")
+                .unwrap()
+                .tick_strings(&["✶", "✸", "✹", "✺", "✹", "✷"]),
+        );
+
+        pb.set_message("Downloading package..");
+
+        let response = reqwest::get(url).await?;
+        let bytes = response.bytes().await?;
+        pb.set_message("Unpacking the template..");
+
+        let cursor = Cursor::new(bytes);
+        let mut archive = zip::ZipArchive::new(cursor)?;
+
+        // Extract the files to the output path
+        for entry in 0..archive.len() {
+            let mut entry = archive
+                .by_index(entry)
+                .context(format!("Getting the archive entry #{entry}"))?;
+
+            let path = entry.mangled_name();
+
+            let path: PathBuf = {
+                let mut components = path.components();
+                components.next();
+                components.collect()
+            };
+
+            if path.to_str().unwrap_or_default().contains(".github") {
+                continue;
+            }
+
+            let path = output_path.join(path);
+
+            if let Some(parent) = path.parent() {
+                if !parent.exists() {
+                    std::fs::create_dir_all(parent)?;
+                }
+            }
+
+            if !path.exists() {
+                // AsyncRead not implemented for entry..
+                if entry.is_file() {
+                    let mut outfile = std::fs::OpenOptions::new()
+                        .create(true)
+                        .truncate(true)
+                        .write(true)
+                        .open(&path)?;
+                    std::io::copy(&mut entry, &mut outfile)?;
+                } else {
+                    std::fs::create_dir(path)?;
+                }
+            }
+        }
+        pb.set_style(
+            indicatif::ProgressStyle::with_template(&format!("{} {{msg}}", "✔".green().bold()))
+                .unwrap(),
+        );
+        pb.finish_with_message(format!("{}", "Unpacked template".bold()));
+
+        pb.finish();
+
+        let app_yaml_path = output_path.join(AppConfigV1::CANONICAL_FILE_NAME);
+
+        if app_yaml_path.exists() && app_yaml_path.is_file() {
+            let contents = tokio::fs::read_to_string(&app_yaml_path).await?;
+            let contents = format!("{contents}\nname: {app_name}");
+            let mut app_config = AppConfigV1::parse_yaml(&contents)?;
+            app_config.owner = Some(owner.to_string());
+            let raw_app = serde_yaml::to_string(&app_config)?;
+            tokio::fs::write(&app_yaml_path, raw_app).await?;
+        }
+
+        let build_md_path = output_path.join("BUILD.md");
+        if build_md_path.exists() {
+            let contents = tokio::fs::read_to_string(build_md_path).await?;
+            eprintln!(
+                "{}: {} 
+{}",
+                "NOTE".bold(),
+                "The selected template has a `BUILD.md` file.
+This means there are likely additional build 
+steps that you need to perform before deploying
+the app:\n"
+                    .bold(),
+                contents
+            );
+            let bin_name = match std::env::args().nth(0) {
+                Some(n) => n,
+                None => String::from("wasmer"),
+            };
+            eprintln!(
+                "After taking the necessary steps to build your application, re-run `{}`",
+                format!("{bin_name} deploy").bold()
+            )
+        } else {
+            self.try_deploy(owner, app_name).await?;
+        }
 
         Ok(true)
     }
 
-    async fn try_deploy(&self, owner: &str) -> anyhow::Result<()> {
+    async fn try_deploy(&self, owner: &str, app_name: &str) -> anyhow::Result<()> {
         let interactive = !self.non_interactive;
         let theme = dialoguer::theme::ColorfulTheme::default();
 
@@ -375,13 +510,16 @@ impl CmdAppCreate {
                 no_validate: false,
                 non_interactive: self.non_interactive,
                 publish_package: true,
-                path: self.app_dir_path.clone(),
+                dir: self.app_dir_path.clone(),
                 no_wait: self.no_wait,
                 no_default: false,
                 no_persist_id: false,
                 owner: Some(String::from(owner)),
-                app_name: None,
+                app_name: Some(app_name.into()),
                 bump: false,
+                template: None,
+                package: None,
+                use_local_manifest: self.use_local_manifest,
             };
             cmd_deploy.run_async().await?;
         }
@@ -395,446 +533,62 @@ impl AsyncCliCommand for CmdAppCreate {
     type Output = ();
 
     async fn run_async(self) -> Result<Self::Output, anyhow::Error> {
+        let client = if self.offline {
+            None
+        } else {
+            Some(
+                login_user(
+                    &self.api,
+                    &self.env,
+                    !self.non_interactive,
+                    "retrieve informations about the owner of the app",
+                )
+                .await?,
+            )
+        };
+
         // Get the future owner of the app.
-        let owner = self.get_owner().await?;
+        let owner = self.get_owner(client.as_ref()).await?;
 
         // Get the name of the app.
         let app_name = self.get_app_name().await?;
 
         if !self.create_from_local_manifest(&owner, &app_name).await? {
             if self.template.is_some() {
-                self.create_from_template(&owner, &app_name).await?;
+                self.create_from_template(client.as_ref(), &owner, &app_name)
+                    .await?;
             } else if self.package.is_some() {
-                self.create_from_package(&owner, &app_name).await?;
+                self.create_from_package(client.as_ref(), &owner, &app_name)
+                    .await?;
             } else if !self.non_interactive {
-                let theme = ColorfulTheme::default();
-                let choice = Select::with_theme(&theme)
-                    .with_prompt("What would you like to deploy?")
-                    .items(&["Start with a template", "Choose an existing package"])
-                    .default(0)
-                    .interact()?;
-                match choice {
-                    0 => self.create_from_template(&owner, &app_name).await?,
-                    1 => self.create_from_package(&owner, &app_name).await?,
-                    x => panic!("unhandled selection {x}"),
-                };
-            } else {
-                eprintln!("Warning: the creation process did not produce any result.");
-            }
-        }
-
-        Ok(())
-    }
-}
-
-/// App type.
-#[derive(clap::ValueEnum, Clone, Copy, Debug)]
-pub enum AppType {
-    /// A HTTP server.
-    #[clap(name = "http")]
-    HttpServer,
-    /// A static website.
-    #[clap(name = "static-website")]
-    StaticWebsite,
-    /// Wraps another package to run in the browser.
-    #[clap(name = "browser-shell")]
-    BrowserShell,
-    /// Winter-js based JS-Worker
-    #[clap(name = "js-worker")]
-    JsWorker,
-    /// Python worker
-    #[clap(name = "py-application")]
-    PyApplication,
-}
-
-struct AppCreator {
-    package: Option<String>,
-    new_package_name: Option<String>,
-    app_name: String,
-    template: AppType,
-    interactive: bool,
-    app_dir_path: PathBuf,
-    owner: String,
-    api: Option<WasmerClient>,
-    user: Option<UserWithNamespaces>,
-    local_package: Option<(PathBuf, wasmer_config::package::Manifest)>,
-}
-
-impl AppCreator {
-    async fn build_browser_shell_app(self) -> Result<(), anyhow::Error> {
-        const WASM_BROWSER_CONTAINER_PACKAGE: &str = "wasmer/wasmer-sh";
-        const WASM_BROWSER_CONTAINER_VERSION: &str = "0.2";
-
-        eprintln!("A browser web shell wraps another package and runs it in the browser");
-        eprintln!("Select the package to wrap.");
-
-        let (inner_pkg, _inner_pkg_api) = crate::utils::prompt_for_package(
-            "Package",
-            None,
-            Some(crate::utils::PackageCheckMode::MustExist),
-            self.api.as_ref(),
-        )
-        .await?;
-
-        let app_name = self.app_name;
-        eprintln!("What should be the name of the package?");
-
-        let default_name = format!(
-            "{}-{}-webshell",
-            self.owner,
-            inner_pkg.to_string().replace('/', "-")
-        );
-
-        let outer_pkg_name =
-            crate::utils::prompts::prompt_for_ident("Package name", Some(&default_name))?;
-        let outer_pkg_full_name = format!("{}/{}", self.owner, outer_pkg_name);
-
-        // Build the package.
-
-        let public_dir = self.app_dir_path.join("public");
-        if !public_dir.exists() {
-            std::fs::create_dir_all(&public_dir)?;
-        }
-
-        let init = serde_json::json!({
-            "init": format!("{}/{}", inner_pkg.namespace.as_ref().unwrap(), inner_pkg.name),
-            "prompt": inner_pkg.name,
-            "no_welcome": true,
-            "connect": format!("wss://{app_name}.wasmer.app/.well-known/edge-vpn"),
-        });
-        let init_path = public_dir.join("init.json");
-        std::fs::write(&init_path, init.to_string())
-            .with_context(|| format!("Failed to write to '{}'", init_path.display()))?;
-
-        let package = wasmer_config::package::PackageBuilder::new(
-            outer_pkg_full_name,
-            "0.1.0".parse().unwrap(),
-            format!("{} web shell", inner_pkg.name),
-        )
-        .rename_commands_to_raw_command_name(false)
-        .build()?;
-
-        let manifest = wasmer_config::package::ManifestBuilder::new(package)
-            .with_dependency(
-                WASM_BROWSER_CONTAINER_PACKAGE,
-                WASM_BROWSER_CONTAINER_VERSION.to_string().parse().unwrap(),
-            )
-            .map_fs("public", PathBuf::from("public"))
-            .build()?;
-
-        let manifest_path = self.app_dir_path.join("wasmer.toml");
-
-        let raw = manifest.to_string()?;
-        eprintln!(
-            "Writing wasmer.toml package to '{}'",
-            manifest_path.display()
-        );
-        std::fs::write(&manifest_path, raw)?;
-
-        let app_config = AppConfigV1 {
-            name: app_name,
-            app_id: None,
-            owner: Some(self.owner.clone()),
-            package: PackageSource::Path(".".into()),
-            domains: None,
-            env: Default::default(),
-            cli_args: None,
-            capabilities: None,
-            scheduled_tasks: None,
-            volumes: None,
-            health_checks: None,
-            debug: Some(false),
-            scaling: None,
-            extra: Default::default(),
-        };
-
-        write_app_config(&app_config, Some(self.app_dir_path.clone())).await?;
-
-        Ok(())
-    }
-
-    async fn build_app(self) -> Result<(), anyhow::Error> {
-        let package_opt: Option<NamedPackageIdent> = if let Some(package) = self.package {
-            Some(NamedPackageIdent::from_str(&package)?)
-        } else if let Some((_, local)) = self.local_package.as_ref() {
-            let pkg = match &local.package {
-                Some(pkg) => pkg.clone(),
-                None => anyhow::bail!(
-                    "Error while building app: template manifest has no package field!"
-                ),
-            };
-
-            if let (Some(name), Some(version)) = (pkg.name, pkg.version) {
-                let full = format!("{}@{}", name, version);
-                let mut pkg_ident = NamedPackageIdent::from_str(&name).with_context(|| {
-                    format!("local package manifest has invalid name: '{full}'")
-                })?;
-
-                // Pin the version.
-                pkg_ident.tag = Some(Tag::from_str(&version.to_string()).unwrap());
-
-                if self.interactive {
-                    eprintln!("Found local package: '{}'", full.green());
-
-                    let msg = format!("Use package '{pkg_ident}'");
-
-                    let theme = dialoguer::theme::ColorfulTheme::default();
-                    let should_use = Confirm::with_theme(&theme)
-                        .with_prompt(&msg)
-                        .interact_opt()?
-                        .unwrap_or_default();
-
-                    if should_use {
-                        Some(pkg_ident)
-                    } else {
-                        None
-                    }
+                if self.offline {
+                    eprintln!("Creating app from a package name running in offline mode");
+                    self.create_from_package(client.as_ref(), &owner, &app_name)
+                        .await?;
                 } else {
-                    Some(pkg_ident)
+                    let theme = ColorfulTheme::default();
+                    let choice = Select::with_theme(&theme)
+                        .with_prompt("What would you like to deploy?")
+                        .items(&["Start with a template", "Choose an existing package"])
+                        .default(0)
+                        .interact()?;
+                    match choice {
+                        0 => {
+                            self.create_from_template(client.as_ref(), &owner, &app_name)
+                                .await?
+                        }
+                        1 => {
+                            self.create_from_package(client.as_ref(), &owner, &app_name)
+                                .await?
+                        }
+                        x => panic!("unhandled selection {x}"),
+                    };
                 }
             } else {
-                None
-            }
-        } else {
-            None
-        };
-
-        let (package, _api_pkg, _local_package) = if let Some(pkg) = package_opt {
-            if let Some(api) = &self.api {
-                let p2 = wasmer_api::query::get_package(
-                    api,
-                    format!("{}/{}", pkg.namespace.as_ref().unwrap(), pkg.name),
-                )
-                .await?;
-
-                (
-                    PackageSource::Ident(wasmer_config::package::PackageIdent::Named(pkg)),
-                    p2,
-                    self.local_package,
-                )
-            } else {
-                (
-                    PackageSource::Ident(wasmer_config::package::PackageIdent::Named(pkg)),
-                    None,
-                    self.local_package,
-                )
+                eprintln!("Warning: the creation process did not produce any result.");
             }
-        } else {
-            let ty = match self.template {
-                AppType::HttpServer => None,
-                AppType::StaticWebsite => Some(PackageType::StaticWebsite),
-                AppType::BrowserShell => None,
-                AppType::JsWorker => Some(PackageType::JsWorker),
-                AppType::PyApplication => Some(PackageType::PyApplication),
-            };
-
-            let create_mode = match ty {
-                Some(PackageType::StaticWebsite)
-                | Some(PackageType::JsWorker)
-                | Some(PackageType::PyApplication) => CreateMode::Create,
-                // Only static website creation is currently supported.
-                _ => CreateMode::SelectExisting,
-            };
-
-            let w = PackageWizard {
-                path: self.app_dir_path.clone(),
-                name: self.new_package_name.clone(),
-                type_: ty,
-                create_mode,
-                namespace: Some(self.owner.clone()),
-                namespace_default: self.user.as_ref().map(|u| u.username.clone()),
-                user: self.user.clone(),
-            };
-
-            let output = w.run(self.api.as_ref()).await?;
-            (
-                PackageSource::Path(".".into()),
-                output.api,
-                output
-                    .local_path
-                    .and_then(move |x| Some((x, output.local_manifest?))),
-            )
-        };
-
-        let name = self.app_name;
-
-        let cli_args = match self.template {
-            AppType::PyApplication => Some(vec!["/src/main.py".to_string()]),
-            AppType::JsWorker => Some(vec!["/src/index.js".to_string()]),
-            _ => None,
-        };
-
-        // TODO: check if name already exists.
-        let app_config = AppConfigV1 {
-            name,
-            app_id: None,
-            owner: Some(self.owner.clone()),
-            package,
-            domains: None,
-            env: Default::default(),
-            // CLI args are only set for JS and Py workers for now.
-            cli_args,
-            // TODO: allow setting the description.
-            // description: Some("".to_string()),
-            capabilities: None,
-            scheduled_tasks: None,
-            volumes: None,
-            health_checks: None,
-            debug: Some(false),
-            scaling: None,
-            extra: Default::default(),
-        };
-
-        write_app_config(&app_config, Some(self.app_dir_path.clone())).await?;
+        }
 
         Ok(())
     }
 }
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[tokio::test]
-    async fn test_app_create_static_site_offline() {
-        let dir = tempfile::tempdir().unwrap();
-
-        let cmd = CmdAppCreate {
-            template: Some(AppType::StaticWebsite),
-            deploy_app: false,
-            no_validate: false,
-            non_interactive: true,
-            offline: true,
-            owner: Some("testuser".to_string()),
-            app_name: Some("static-site-1".to_string()),
-            app_dir_path: Some(dir.path().to_owned()),
-            no_wait: true,
-            api: ApiOpts::default(),
-            fmt: ItemFormatOpts::default(),
-            package: Some("testuser/static-site-1@0.1.0".to_string()),
-            use_local_manifest: false,
-            new_package_name: None,
-            env: WasmerEnv::default(),
-        };
-        cmd.run_async().await.unwrap();
-
-        let app = std::fs::read_to_string(dir.path().join("app.yaml")).unwrap();
-        assert_eq!(
-            app,
-            r#"kind: wasmer.io/App.v0
-name: static-site-1
-owner: testuser
-package: testuser/static-site-1@^0.1.0
-debug: false
-"#,
-        );
-    }
-
-    #[tokio::test]
-    async fn test_app_create_offline_with_package() {
-        let dir = tempfile::tempdir().unwrap();
-
-        let cmd = CmdAppCreate {
-            template: Some(AppType::HttpServer),
-            deploy_app: false,
-            no_validate: false,
-            non_interactive: true,
-            offline: true,
-            owner: Some("wasmer".to_string()),
-            app_name: Some("testapp".to_string()),
-            app_dir_path: Some(dir.path().to_owned()),
-            no_wait: true,
-            api: ApiOpts::default(),
-            fmt: ItemFormatOpts::default(),
-            package: Some("wasmer/testpkg".to_string()),
-            use_local_manifest: false,
-            new_package_name: None,
-            env: WasmerEnv::default(),
-        };
-        cmd.run_async().await.unwrap();
-
-        let app = std::fs::read_to_string(dir.path().join("app.yaml")).unwrap();
-        assert_eq!(
-            app,
-            r#"kind: wasmer.io/App.v0
-name: testapp
-owner: wasmer
-package: wasmer/testpkg
-debug: false
-"#,
-        );
-    }
-    #[tokio::test]
-    async fn test_app_create_js_worker() {
-        let dir = tempfile::tempdir().unwrap();
-
-        let cmd = CmdAppCreate {
-            template: Some(AppType::JsWorker),
-            deploy_app: false,
-            no_validate: false,
-            non_interactive: true,
-            offline: true,
-            owner: Some("wasmer".to_string()),
-            app_name: Some("test-js-worker".to_string()),
-            app_dir_path: Some(dir.path().to_owned()),
-            no_wait: true,
-            api: ApiOpts::default(),
-            fmt: ItemFormatOpts::default(),
-            package: Some("wasmer/test-js-worker".to_string()),
-            use_local_manifest: false,
-            new_package_name: None,
-            env: WasmerEnv::default(),
-        };
-        cmd.run_async().await.unwrap();
-
-        let app = std::fs::read_to_string(dir.path().join("app.yaml")).unwrap();
-        assert_eq!(
-            app,
-            r#"kind: wasmer.io/App.v0
-name: test-js-worker
-owner: wasmer
-package: wasmer/test-js-worker
-cli_args:
-- /src/index.js
-debug: false
-"#,
-        );
-    }
-
-    #[tokio::test]
-    async fn test_app_create_py_worker() {
-        let dir = tempfile::tempdir().unwrap();
-
-        let cmd = CmdAppCreate {
-            template: Some(AppType::PyApplication),
-            deploy_app: false,
-            no_validate: false,
-            non_interactive: true,
-            offline: true,
-            owner: Some("wasmer".to_string()),
-            app_name: Some("test-py-worker".to_string()),
-            app_dir_path: Some(dir.path().to_owned()),
-            no_wait: true,
-            api: ApiOpts::default(),
-            fmt: ItemFormatOpts::default(),
-            package: Some("wasmer/test-py-worker".to_string()),
-            use_local_manifest: false,
-            new_package_name: None,
-            env: WasmerEnv::default(),
-        };
-        cmd.run_async().await.unwrap();
-
-        let app = std::fs::read_to_string(dir.path().join("app.yaml")).unwrap();
-        assert_eq!(
-            app,
-            r#"kind: wasmer.io/App.v0
-name: test-py-worker
-owner: wasmer
-package: wasmer/test-py-worker
-cli_args:
-- /src/main.py
-debug: false
-"#,
-        );
-    }
-}
diff --git a/lib/cli/src/commands/app/deploy.rs b/lib/cli/src/commands/app/deploy.rs
index f4d82a36107..7cf55daff71 100644
--- a/lib/cli/src/commands/app/deploy.rs
+++ b/lib/cli/src/commands/app/deploy.rs
@@ -45,9 +45,9 @@ pub struct CmdAppDeploy {
     #[clap(long)]
     pub publish_package: bool,
 
-    /// The path to the app.yaml file.
+    /// The path to the directory containing the `app.yaml` file.
     #[clap(long)]
-    pub path: Option<PathBuf>,
+    pub dir: Option<PathBuf>,
 
     /// Do not wait for the app to become reachable.
     #[clap(long)]
@@ -76,7 +76,7 @@ pub struct CmdAppDeploy {
     /// If specified via this flag, the app_name will be overridden. Otherwise, the `app.yaml` is
     /// inspected and, if there is no `name` field in the spec file, if running interactive the
     /// user will be prompted to insert an app name, otherwise the deployment will fail.
-    #[clap(long)]
+    #[clap(long, name = "name")]
     pub app_name: Option<String>,
 
     /// Whether or not to automatically bump the package version if publishing.
@@ -89,6 +89,31 @@ pub struct CmdAppDeploy {
     /// operation.
     #[clap(long)]
     pub quiet: bool,
+
+    // - App creation -
+    /// A reference to the template to use when creating an app to deploy.
+    ///
+    /// It can be either an URL to a github repository - like
+    /// `https://github.com/wasmer-examples/php-wasmer-starter` -  or the name of a template that
+    /// will be searched for in the selected registry, like `astro-starter`.
+    #[clap(
+        long,
+        conflicts_with = "package",
+        conflicts_with = "use_local_manifest"
+    )]
+    pub template: Option<String>,
+
+    /// Name of the package to use when creating an app to deploy.
+    #[clap(
+        long,
+        conflicts_with = "template",
+        conflicts_with = "use_local_manifest"
+    )]
+    pub package: Option<String>,
+
+    /// Whether or not to search (and use) a local manifest when creating an app to deploy.
+    #[clap(long, conflicts_with = "template", conflicts_with = "package")]
+    pub use_local_manifest: bool,
 }
 
 impl CmdAppDeploy {
@@ -169,22 +194,23 @@ impl CmdAppDeploy {
         eprintln!("It seems you are trying to create a new app!");
 
         let create_cmd = CmdAppCreate {
-            template: None,
+            quiet: self.quiet,
             deploy_app: false,
             no_validate: false,
             non_interactive: false,
             offline: false,
-            owner: None,
-            app_name: None,
+            owner: self.owner.clone(),
+            app_name: self.app_name.clone(),
             no_wait: self.no_wait,
             api: self.api.clone(),
             env: self.env.clone(),
             fmt: ItemFormatOpts {
                 format: self.fmt.format,
             },
-            package: None,
-            app_dir_path: None,
-            use_local_manifest: false,
+            package: self.package.clone(),
+            template: self.template.clone(),
+            app_dir_path: self.dir.clone(),
+            use_local_manifest: self.use_local_manifest,
             new_package_name: None,
         };
 
@@ -200,7 +226,7 @@ impl AsyncCliCommand for CmdAppDeploy {
         let client =
             login_user(&self.api, &self.env, !self.non_interactive, "deploy an app").await?;
 
-        let base_dir_path = self.path.clone().unwrap_or(std::env::current_dir()?);
+        let base_dir_path = self.dir.clone().unwrap_or(std::env::current_dir()?);
         let (app_config_path, base_dir_path) = {
             if base_dir_path.is_file() {
                 (
@@ -216,16 +242,13 @@ impl AsyncCliCommand for CmdAppDeploy {
             }
         };
 
-        if !app_config_path.is_file() {
-            if !self.non_interactive {
-                // Create already points back to deploy.
-                return self.create().await;
-            } else {
-                anyhow::bail!(
-                    "Cannot deploy app as no app.yaml was found in path '{}'",
-                    app_config_path.display()
-                )
-            }
+        if !app_config_path.is_file()
+            || self.template.is_some()
+            || self.package.is_some()
+            || self.use_local_manifest
+        {
+            // Create already points back to deploy.
+            return self.create().await;
         }
 
         assert!(app_config_path.is_file());
@@ -645,10 +668,7 @@ pub async fn wait_app(
                             if !quiet {
                                 eprintln!();
                             }
-                            eprintln!(
-                                "{} Deployment complete, new version reachable at {check_url}",
-                                "𖥔".yellow().bold()
-                            );
+                            eprintln!("{} Deployment complete", "𖥔".yellow().bold());
                             break;
                         }
 
diff --git a/lib/cli/src/commands/login.rs b/lib/cli/src/commands/login.rs
index 7986dbd2a9f..a917de52304 100644
--- a/lib/cli/src/commands/login.rs
+++ b/lib/cli/src/commands/login.rs
@@ -2,6 +2,7 @@ use std::{net::TcpListener, path::PathBuf, str::FromStr, time::Duration};
 
 use anyhow::Ok;
 use clap::Parser;
+use colored::Colorize;
 #[cfg(not(test))]
 use dialoguer::{console::style, Input};
 use hyper::{
@@ -302,7 +303,7 @@ impl Login {
                 match res {
                     Some(s) => {
                         print!("Done!");
-                        println!("\n✅ Login for Wasmer user {:?} saved", s)
+                        println!("\n{} Login for Wasmer user {:?} saved","✔".green().bold(), s)
                     }
                     None => print!(
                         "Warning: no user found on {:?} with the provided token.\nToken saved regardless.",
diff --git a/lib/cli/src/commands/package/build.rs b/lib/cli/src/commands/package/build.rs
index d87d25a469f..28860967e07 100644
--- a/lib/cli/src/commands/package/build.rs
+++ b/lib/cli/src/commands/package/build.rs
@@ -54,8 +54,13 @@ impl PackageBuild {
                 manifest_path.display()
             )
         };
-        let pkg = webc::wasmer_package::Package::from_manifest(manifest_path)?;
-        let data = pkg.serialize()?;
+        let pkg = webc::wasmer_package::Package::from_manifest(manifest_path.clone()).context(
+            format!(
+                "While parsing the manifest (loaded from {})",
+                manifest_path.canonicalize()?.display()
+            ),
+        )?;
+        let data = pkg.serialize().context("While validating the package")?;
         let hash = sha2::Sha256::digest(&data).into();
         let pkg_hash = PackageHash::from_sha256_bytes(hash);
 
diff --git a/lib/cli/src/commands/package/common/mod.rs b/lib/cli/src/commands/package/common/mod.rs
index 16254b7b91a..7b08047ac67 100644
--- a/lib/cli/src/commands/package/common/mod.rs
+++ b/lib/cli/src/commands/package/common/mod.rs
@@ -5,6 +5,7 @@ use crate::{
 };
 use colored::Colorize;
 use dialoguer::Confirm;
+use hyper::Body;
 use indicatif::{ProgressBar, ProgressStyle};
 use std::{
     collections::BTreeMap,
@@ -42,12 +43,12 @@ pub(super) async fn upload(
     hash: &PackageHash,
     timeout: humantime::Duration,
     package: &Package,
-    pb: &ProgressBar,
+    pb: ProgressBar,
 ) -> anyhow::Result<String> {
     let hash_str = hash.to_string();
     let hash_str = hash_str.trim_start_matches("sha256:");
 
-    let url = {
+    let session_uri = {
         let default_timeout_secs = Some(60 * 30);
         let q = wasmer_api::query::get_signed_url_for_package_upload(
             client,
@@ -65,7 +66,7 @@ pub(super) async fn upload(
         }
     };
 
-    tracing::info!("signed url is: {url}");
+    tracing::info!("signed url is: {session_uri}");
 
     let client = reqwest::Client::builder()
         .default_headers(reqwest::header::HeaderMap::default())
@@ -74,7 +75,7 @@ pub(super) async fn upload(
         .unwrap();
 
     let res = client
-        .post(&url)
+        .post(&session_uri)
         .header(reqwest::header::CONTENT_LENGTH, "0")
         .header(reqwest::header::CONTENT_TYPE, "application/octet-stream")
         .header("x-goog-resumable", "start");
@@ -117,44 +118,50 @@ pub(super) async fn upload(
 
     let total_bytes = bytes.len();
     pb.set_length(total_bytes.try_into().unwrap());
-    pb.set_style(ProgressStyle::with_template("{spinner:.green} [{elapsed_precise}] [{bar:.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta})")
+    pb.set_style(ProgressStyle::with_template("{spinner:.yellow} [{elapsed_precise}] [{bar:.white}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta})")
                  .unwrap()
                  .progress_chars("█▉▊▋▌▍▎▏  ")
                  .tick_strings(&["✶", "✸", "✹", "✺", "✹", "✷"]));
     tracing::info!("webc is {total_bytes} bytes long");
 
-    let chunk_size = 1_048_576; // 1MB - 315s / 100MB
-    let chunks = bytes.chunks(chunk_size);
-    let mut total_bytes_sent = 0;
+    let chunk_size = (total_bytes / 20).min(10485760);
 
-    let client = reqwest::Client::builder().build().unwrap();
+    let stream = futures::stream::unfold(0, move |offset| {
+        let pb = pb.clone();
+        let bytes = bytes.clone();
+        async move {
+            if offset >= total_bytes {
+                return None;
+            }
 
-    for chunk in chunks {
-        let n = chunk.len();
+            let start = offset;
 
-        let start = total_bytes_sent;
-        let end = start + chunk.len().saturating_sub(1);
-        let content_range = format!("bytes {start}-{end}/{total_bytes}");
+            let end = if (start + chunk_size) >= total_bytes {
+                total_bytes
+            } else {
+                start + chunk_size
+            };
 
-        let res = client
-            .put(&session_uri)
-            .header(reqwest::header::CONTENT_TYPE, "application/octet-stream")
-            .header(reqwest::header::CONTENT_LENGTH, format!("{}", chunk.len()))
-            .header("Content-Range".to_string(), content_range)
-            .body(chunk.to_vec());
+            let n = end - start;
+            let next_chunk = bytes.slice(start..end);
+            pb.inc(n as u64);
 
-        res.send()
-            .await
-            .map(|response| response.error_for_status())
-            .map_err(|e| {
-                anyhow::anyhow!("cannot send request to {session_uri} (chunk {start}..{end}): {e}",)
-            })??;
+            Some((Ok::<_, std::io::Error>(next_chunk), offset + n))
+        }
+    });
 
-        total_bytes_sent += n;
-        pb.set_position(total_bytes_sent.try_into().unwrap());
-    }
+    let res = client
+        .put(&session_uri)
+        .header(reqwest::header::CONTENT_TYPE, "application/octet-stream")
+        .header(reqwest::header::CONTENT_LENGTH, format!("{}", total_bytes))
+        .body(Body::wrap_stream(stream));
+
+    res.send()
+        .await
+        .map(|response| response.error_for_status())
+        .map_err(|e| anyhow::anyhow!("error uploading package to {session_uri}: {e}",))??;
 
-    Ok(url)
+    Ok(session_uri)
 }
 
 /// Read and return a manifest given a path.
diff --git a/lib/cli/src/commands/package/common/wait.rs b/lib/cli/src/commands/package/common/wait.rs
index cf661a30c72..30bb410f310 100644
--- a/lib/cli/src/commands/package/common/wait.rs
+++ b/lib/cli/src/commands/package/common/wait.rs
@@ -1,7 +1,4 @@
-use super::macros::spinner_ok;
-use colored::Colorize;
 use futures_util::StreamExt;
-use indicatif::ProgressBar;
 use wasmer_api::WasmerClient;
 
 /// Different conditions that can be "awaited" when publishing a package.
@@ -83,14 +80,12 @@ pub async fn wait_package(
     client: &WasmerClient,
     to_wait: PublishWait,
     package_version_id: wasmer_api::types::Id,
-    pb: &ProgressBar,
     timeout: humantime::Duration,
 ) -> anyhow::Result<()> {
     if let PublishWait::None = to_wait {
         return Ok(());
     }
 
-    pb.set_message("Waiting for package to become available...");
     let registry_url = client.graphql_endpoint().to_string();
     let login_token = client.auth_token().unwrap_or_default().to_string();
     let package_version_id = package_version_id.into_inner();
@@ -146,6 +141,5 @@ pub async fn wait_package(
         }
     }
 
-    spinner_ok!(pb, "Package is available in the registry");
     Ok(())
 }
diff --git a/lib/cli/src/commands/package/publish.rs b/lib/cli/src/commands/package/publish.rs
index 0a2a23867f0..798bd98fcaf 100644
--- a/lib/cli/src/commands/package/publish.rs
+++ b/lib/cli/src/commands/package/publish.rs
@@ -149,10 +149,13 @@ impl AsyncCliCommand for PackagePublish {
         match ident {
             PackageIdent::Named(ref n) => {
                 let url = make_package_url(&client, n);
-                eprintln!("{} Package URL: {url}", "𖥔".yellow().bold());
+                eprintln!("\n{} Package URL: {url}", "𖥔".yellow().bold());
             }
             PackageIdent::Hash(ref h) => {
-                eprintln!("{} Succesfully published package ({h})", "✔".green().bold());
+                eprintln!(
+                    "\n{} Succesfully published package ({h})",
+                    "✔".green().bold()
+                );
             }
         }
 
diff --git a/lib/cli/src/commands/package/push.rs b/lib/cli/src/commands/package/push.rs
index 9ac40a345f3..c7f2caf7ad3 100644
--- a/lib/cli/src/commands/package/push.rs
+++ b/lib/cli/src/commands/package/push.rs
@@ -3,6 +3,7 @@ use crate::{
     commands::{AsyncCliCommand, PackageBuild},
     opts::{ApiOpts, WasmerEnv},
 };
+use anyhow::Context;
 use colored::Colorize;
 use is_terminal::IsTerminal;
 use std::path::{Path, PathBuf};
@@ -117,10 +118,12 @@ impl PackagePush {
         package_hash: &PackageHash,
         private: bool,
     ) -> anyhow::Result<()> {
-        let pb = make_spinner!(self.quiet, "Uploading the package to the registry..");
+        let pb = make_spinner!(self.quiet, "Uploading the package..");
 
-        let signed_url = upload(client, package_hash, self.timeout, package, &pb).await?;
+        let signed_url = upload(client, package_hash, self.timeout, package, pb.clone()).await?;
+        spinner_ok!(pb, "Package correctly uploaded");
 
+        let pb = make_spinner!(self.quiet, "Waiting for package to become available...");
         let id = match wasmer_api::query::push_package_release(
             client,
             None,
@@ -132,10 +135,6 @@ impl PackagePush {
         {
             Some(r) => {
                 if r.success {
-                    let msg = format!(
-                        "Succesfully pushed release to namespace {namespace} on the registry"
-                    );
-                    spinner_ok!(pb, msg);
                     r.package_webc.unwrap().id
                 } else {
                     anyhow::bail!("An unidentified error occurred while publishing the package. (response had success: false)")
@@ -144,7 +143,10 @@ impl PackagePush {
             None => anyhow::bail!("An unidentified error occurred while publishing the package."), // <- This is extremely bad..
         };
 
-        wait_package(client, self.wait, id, &pb, self.timeout).await?;
+        wait_package(client, self.wait, id, self.timeout).await?;
+        let msg = format!("Succesfully pushed release to namespace {namespace} on the registry");
+        spinner_ok!(pb, msg);
+
         Ok(())
     }
 
@@ -156,7 +158,9 @@ impl PackagePush {
     ) -> anyhow::Result<(String, PackageHash)> {
         tracing::info!("Building package");
         let pb = make_spinner!(self.quiet, "Creating the package locally...");
-        let (package, hash) = PackageBuild::check(manifest_path.to_path_buf()).execute()?;
+        let (package, hash) = PackageBuild::check(manifest_path.to_path_buf())
+            .execute()
+            .context("While trying to build the package locally")?;
 
         spinner_ok!(pb, "Correctly built package locally");
         tracing::info!("Package has hash: {hash}");
diff --git a/lib/cli/src/commands/package/tag.rs b/lib/cli/src/commands/package/tag.rs
index d49c1c4e0ab..b74eb563aa5 100644
--- a/lib/cli/src/commands/package/tag.rs
+++ b/lib/cli/src/commands/package/tag.rs
@@ -374,8 +374,6 @@ impl PackageTag {
                             .interact()? {
                             user_version = new_version.clone();
                             self.update_manifest_version(manifest_path, manifest, &user_version).await?;
-                       } else {
-                           eprintln!("{}: if version {user_version} of {full_pkg_name} already exists tagging will fail.", "WARN".bold().yellow());
                        }
                 }
             }
@@ -465,12 +463,34 @@ impl PackageTag {
             None => return Ok(PackageIdent::Hash(self.package_hash.clone())),
         };
 
-        self.do_tag(client, &id, manifest, &package_id)
-            .await
-            .map_err(on_error)?;
+        if self.should_tag(client, &id).await? {
+            self.do_tag(client, &id, manifest, &package_id)
+                .await
+                .map_err(on_error)?;
+        }
 
         Ok(PackageIdent::Named(id.into()))
     }
+
+    // Check if a package with the same hash, namespace, name and version already exists. In such a
+    // case, don't tag the package again.
+    async fn should_tag(&self, client: &WasmerClient, id: &NamedPackageId) -> anyhow::Result<bool> {
+        if let Some(pkg) = wasmer_api::query::get_package_version(
+            client,
+            id.full_name.clone(),
+            id.version.to_string(),
+        )
+        .await?
+        {
+            if let Some(hash) = pkg.distribution_v3.pirita_sha256_hash {
+                let registry_package_hash = PackageHash::from_str(&format!("sha256:{hash}"))?;
+                if registry_package_hash == self.package_hash {
+                    return Ok(false);
+                }
+            }
+        }
+        Ok(true)
+    }
 }
 
 #[async_trait::async_trait]
diff --git a/lib/cli/src/utils/mod.rs b/lib/cli/src/utils/mod.rs
index 14c001e8717..7cd7550963d 100644
--- a/lib/cli/src/utils/mod.rs
+++ b/lib/cli/src/utils/mod.rs
@@ -10,11 +10,8 @@ use std::{
 };
 
 use anyhow::{bail, Context as _, Result};
-use dialoguer::theme::ColorfulTheme;
 use once_cell::sync::Lazy;
 use regex::Regex;
-use wasmer_api::WasmerClient;
-use wasmer_config::package::NamedPackageIdent;
 use wasmer_wasix::runners::MappedDirectory;
 
 fn retrieve_alias_pathbuf(alias: &str, real_dir: &str) -> Result<MappedDirectory> {
@@ -111,294 +108,6 @@ pub fn load_package_manifest(
     Ok(Some((file_path, manifest)))
 }
 
-/// Ask a user for a package name.
-///
-/// Will continue looping until the user provides a valid name.
-pub fn prompt_for_package_name(
-    message: &str,
-    default: Option<&str>,
-) -> Result<NamedPackageIdent, anyhow::Error> {
-    loop {
-        let theme = ColorfulTheme::default();
-        let raw: String = dialoguer::Input::with_theme(&theme)
-            .with_prompt(message)
-            .with_initial_text(default.unwrap_or_default())
-            .interact_text()
-            .context("could not read user input")?;
-
-        match raw.parse::<NamedPackageIdent>() {
-            Ok(p) => break Ok(p),
-            Err(err) => {
-                eprintln!("invalid package name: {err}");
-            }
-        }
-    }
-}
-
-/// Defines how to check for a package.
-pub enum PackageCheckMode {
-    /// The package must exist in the registry.
-    MustExist,
-    /// The package must NOT exist in the registry.
-    #[allow(dead_code)]
-    MustNotExist,
-}
-
-/// Ask for a package name.
-///
-/// Will continue looping until the user provides a valid name.
-///
-/// If an API is provided, will check if the package exists.
-pub async fn prompt_for_package(
-    message: &str,
-    default: Option<&str>,
-    check: Option<PackageCheckMode>,
-    client: Option<&WasmerClient>,
-) -> Result<(NamedPackageIdent, Option<wasmer_api::types::Package>), anyhow::Error> {
-    loop {
-        let name = prompt_for_package_name(message, default)?;
-
-        if let Some(check) = &check {
-            let api = client.expect("Check mode specified, but no API provided");
-
-            let pkg = wasmer_api::query::get_package(api, name.to_string())
-                .await
-                .context("could not query backend for package")?;
-
-            match check {
-                PackageCheckMode::MustExist => {
-                    if let Some(pkg) = pkg {
-                        break Ok((name, Some(pkg)));
-                    } else {
-                        eprintln!("Package '{name}' does not exist");
-                    }
-                }
-                PackageCheckMode::MustNotExist => {
-                    if pkg.is_none() {
-                        break Ok((name, None));
-                    } else {
-                        eprintln!("Package '{name}' already exists");
-                    }
-                }
-            }
-        }
-    }
-}
-
-// /// Republish the package described by the [`wasmer_config::package::Manifest`] given as argument and return a
-// /// [`Result<wasmer_config::package::Manifest>`].
-// ///
-// /// If the package described is named (i.e. has name, namespace and version), the returned manifest
-// /// will have its minor version bumped. If the package is unnamed, the returned manifest will be
-// /// equal to the one given as input.
-// pub async fn republish_package(
-//     client: &WasmerClient,
-//     manifest_path: &Path,
-//     manifest: wasmer_config::package::Manifest,
-//     patch_owner: Option<String>,
-// ) -> Result<(wasmer_config::package::Manifest, Option<PackageIdent>), anyhow::Error> {
-//     let manifest_path = if manifest_path.is_file() {
-//         manifest_path.to_owned()
-//     } else {
-//         manifest_path.join(DEFAULT_PACKAGE_MANIFEST_FILE)
-//     };
-//
-//     let dir = manifest_path
-//         .parent()
-//         .context("could not determine wasmer.toml parent directory")?
-//         .to_owned();
-//
-//     let new_manifest = match &manifest.package {
-//         None => manifest.clone(),
-//         Some(pkg) => {
-//             let mut pkg = pkg.clone();
-//             let name = pkg.name.clone();
-//
-//             let current_opt = wasmer_api::query::get_package(client, pkg.name.clone())
-//                 .await
-//                 .context("could not load package info from backend")?
-//                 .and_then(|x| x.last_version);
-//
-//             let new_version = if let Some(current) = &current_opt {
-//                 let mut v = semver::Version::parse(&current.version).with_context(|| {
-//                     format!("Could not parse package version: '{}'", current.version)
-//                 })?;
-//
-//                 v.patch += 1;
-//
-//                 // The backend does not have a reliable way to return the latest version,
-//                 // so we have to check each version in a loop.
-//                 loop {
-//                     let version = format!("={}", v);
-//                     let version = wasmer_api::query::get_package_version(
-//                         client,
-//                         name.clone(),
-//                         version.clone(),
-//                     )
-//                     .await
-//                     .context("could not load package info from backend")?;
-//
-//                     if version.is_some() {
-//                         v.patch += 1;
-//                     } else {
-//                         break;
-//                     }
-//                 }
-//
-//                 v
-//             } else {
-//                 pkg.version
-//             };
-//
-//             pkg.version = new_version;
-//
-//             let mut manifest = manifest.clone();
-//             manifest.package = Some(pkg);
-//
-//             let contents = toml::to_string(&manifest).with_context(|| {
-//                 format!(
-//                     "could not persist manifest to '{}'",
-//                     manifest_path.display()
-//                 )
-//             })?;
-//
-//             std::fs::write(manifest_path.clone(), contents).with_context(|| {
-//                 format!("could not write manifest to '{}'", manifest_path.display())
-//             })?;
-//
-//             manifest
-//         }
-//     };
-//
-//     let registry = client.graphql_endpoint().to_string();
-//     let token = client
-//         .auth_token()
-//         .context("no auth token configured - run 'wasmer login'")?
-//         .to_string();
-//
-//     let publish = wasmer_registry::package::builder::Publish {
-//         registry: Some(registry),
-//         dry_run: false,
-//         quiet: false,
-//         package_name: None,
-//         version: None,
-//         wait: wasmer_registry::publish::PublishWait::new_none(),
-//         token,
-//         no_validate: true,
-//         package_path: Some(dir.to_str().unwrap().to_string()),
-//         // Use a high timeout to prevent interrupting uploads of
-//         // large packages.
-//         timeout: std::time::Duration::from_secs(60 * 60 * 12),
-//         package_namespace: patch_owner,
-//     };
-//
-//     // Publish uses a blocking http client internally, which leads to a
-//     // "can't drop a runtime within an async context" error, so this has
-//     // to be run in a separate thread.
-//     let maybe_hash = std::thread::spawn(move || publish.execute())
-//         .join()
-//         .map_err(|e| anyhow::format_err!("failed to publish package: {:?}", e))??;
-//
-//     Ok((new_manifest.clone(), maybe_hash))
-// }
-
-///// Re-publish a package with an increased minor version.
-//pub async fn republish_package_with_bumped_version(
-//    client: &WasmerClient,
-//    manifest_path: &Path,
-//    mut manifest: wasmer_config::package::Manifest,
-//) -> Result<wasmer_config::package::Manifest, anyhow::Error> {
-//    // Try to load existing version.
-//    // If it does not exist yet, we don't need to increment.
-//
-//    let current_opt = wasmer_api::query::get_package(client, manifest.package.name.clone())
-//        .await
-//        .context("could not load package info from backend")?
-//        .and_then(|x| x.last_version);
-//
-//    let new_version = if let Some(current) = &current_opt {
-//        let mut v = semver::Version::parse(&current.version)
-//            .with_context(|| format!("Could not parse package version: '{}'", current.version))?;
-//
-//        v.patch += 1;
-//
-//        // The backend does not have a reliable way to return the latest version,
-//        // so we have to check each version in a loop.
-//        loop {
-//            let version = format!("={}", v);
-//            let version = wasmer_api::query::get_package_version(
-//                client,
-//                manifest.package.name.clone(),
-//                version.clone(),
-//            )
-//            .await
-//            .context("could not load package info from backend")?;
-//
-//            if version.is_some() {
-//                v.patch += 1;
-//            } else {
-//                break;
-//            }
-//        }
-//
-//        v
-//    } else {
-//        manifest.package.version
-//    };
-//
-//    manifest.package.version = new_version;
-//    let contents = toml::to_string(&manifest).with_context(|| {
-//        format!(
-//            "could not persist manifest to '{}'",
-//            manifest_path.display()
-//        )
-//    })?;
-//
-//    let manifest_path = if manifest_path.is_file() {
-//        manifest_path.to_owned()
-//    } else {
-//        manifest_path.join(DEFAULT_PACKAGE_MANIFEST_FILE)
-//    };
-//
-//    std::fs::write(manifest_path.clone(), contents)
-//        .with_context(|| format!("could not write manifest to '{}'", manifest_path.display()))?;
-//
-//    let dir = manifest_path
-//        .parent()
-//        .context("could not determine wasmer.toml parent directory")?
-//        .to_owned();
-//
-//    let registry = client.graphql_endpoint().to_string();
-//    let token = client
-//        .auth_token()
-//        .context("no auth token configured - run 'wasmer login'")?
-//        .to_string();
-//
-//    let publish = wasmer_registry::package::builder::Publish {
-//        registry: Some(registry),
-//        dry_run: false,
-//        quiet: false,
-//        package_name: None,
-//        version: None,
-//        wait: wasmer_registry::publish::PublishWait::new_none(),
-//        token,
-//        no_validate: true,
-//        package_path: Some(dir.to_str().unwrap().to_string()),
-//        // Use a high timeout to prevent interrupting uploads of
-//        // large packages.
-//        timeout: std::time::Duration::from_secs(60 * 60 * 12),
-//    };
-//
-//    // Publish uses a blocking http client internally, which leads to a
-//    // "can't drop a runtime within an async context" error, so this has
-//    // to be run in a separate thread.
-//    std::thread::spawn(move || publish.execute())
-//        .join()
-//        .map_err(|e| anyhow::format_err!("failed to publish package: {:?}", e))??;
-//
-//    Ok(manifest)
-//}
-
 /// The identifier for an app or package in the form, `owner/package@version`,
 /// where the `owner` and `version` are optional.
 #[derive(Debug, Clone, PartialEq)]
diff --git a/lib/cli/src/utils/package_wizard/mod.rs b/lib/cli/src/utils/package_wizard/mod.rs
index ddc55e18c0e..08383cf4584 100644
--- a/lib/cli/src/utils/package_wizard/mod.rs
+++ b/lib/cli/src/utils/package_wizard/mod.rs
@@ -1,426 +1,426 @@
-use std::path::{Path, PathBuf};
-
-use anyhow::Context;
-use dialoguer::{theme::ColorfulTheme, Select};
-use wasmer_api::{types::UserWithNamespaces, WasmerClient};
-
-use super::prompts::PackageCheckMode;
-
-const WASM_STATIC_SERVER_PACKAGE: &str = "wasmer/static-web-server";
-const WASM_STATIC_SERVER_VERSION: &str = "1";
-
-const WASMER_WINTER_JS_PACKAGE: &str = "wasmer/winterjs";
-const WASMER_WINTER_JS_VERSION: &str = "*";
-
-const WASM_PYTHON_PACKAGE: &str = "wasmer/python";
-const WASM_PYTHON_VERSION: &str = "3.12.6";
-
-const SAMPLE_INDEX_HTML: &str = include_str!("./templates/static-site/index.html");
-const SAMPLE_JS_WORKER: &str = include_str!("./templates/js-worker/index.js");
-const SAMPLE_PY_APPLICATION: &str = include_str!("./templates/py-application/main.py");
-
-#[derive(clap::ValueEnum, Clone, Copy, Debug)]
-pub enum PackageType {
-    #[clap(name = "regular")]
-    Regular,
-    /// A static website.
-    #[clap(name = "static-website")]
-    StaticWebsite,
-    /// A js-worker
-    #[clap(name = "js-worker")]
-    JsWorker,
-    /// A py-worker
-    #[clap(name = "py-application")]
-    PyApplication,
-}
-
-#[derive(Clone, Copy, Debug)]
-pub enum CreateMode {
-    Create,
-    SelectExisting,
-    #[allow(dead_code)]
-    CreateOrSelect,
-}
-
-fn prompt_for_package_type() -> Result<PackageType, anyhow::Error> {
-    let theme = ColorfulTheme::default();
-    Select::with_theme(&theme)
-        .with_prompt("What type of package do you want to create?")
-        .items(&["Basic pacakge", "Static website"])
-        .interact()
-        .map(|idx| match idx {
-            0 => PackageType::Regular,
-            1 => PackageType::StaticWebsite,
-            _ => unreachable!(),
-        })
-        .map_err(anyhow::Error::from)
-}
-
-#[derive(Debug)]
-pub struct PackageWizard {
-    pub path: PathBuf,
-    pub type_: Option<PackageType>,
-
-    pub create_mode: CreateMode,
-
-    /// Namespace to use.
-    pub namespace: Option<String>,
-    /// Default namespace to use.
-    /// Will still show a prompt, with this as the default value.
-    /// Ignored if [`Self::namespace`] is set.
-    pub namespace_default: Option<String>,
-
-    /// Pre-configured package name.
-    pub name: Option<String>,
-
-    pub user: Option<UserWithNamespaces>,
-}
-
-pub struct PackageWizardOutput {
-    pub api: Option<wasmer_api::types::Package>,
-    pub local_path: Option<PathBuf>,
-    pub local_manifest: Option<wasmer_config::package::Manifest>,
-}
-
-impl PackageWizard {
-    fn build_new_package(&self) -> Result<PackageWizardOutput, anyhow::Error> {
-        let ty = match self.type_ {
-            Some(t) => t,
-            None => prompt_for_package_type()?,
-        };
-
-        if !self.path.is_dir() {
-            std::fs::create_dir_all(&self.path).with_context(|| {
-                format!("Failed to create directory: '{}'", self.path.display())
-            })?;
-        }
-
-        let manifest = match ty {
-            PackageType::Regular => todo!(),
-            PackageType::StaticWebsite => initialize_static_site(&self.path)?,
-            PackageType::JsWorker => initialize_js_worker(&self.path)?,
-            PackageType::PyApplication => initialize_py_worker(&self.path)?,
-        };
-
-        let manifest_path = self.path.join("wasmer.toml");
-        let manifest_raw = manifest
-            .to_string()
-            .context("could not serialize package manifest")?;
-        std::fs::write(manifest_path, manifest_raw)
-            .with_context(|| format!("Failed to write manifest to '{}'", self.path.display()))?;
-
-        Ok(PackageWizardOutput {
-            api: None,
-            local_path: Some(self.path.clone()),
-            local_manifest: Some(manifest),
-        })
-    }
-
-    async fn prompt_existing_package(
-        &self,
-        api: Option<&WasmerClient>,
-    ) -> Result<PackageWizardOutput, anyhow::Error> {
-        // Existing package
-        let check = if api.is_some() {
-            Some(PackageCheckMode::MustExist)
-        } else {
-            None
-        };
-
-        eprintln!("Enter the name of an existing package:");
-        let (_ident, api) = super::prompts::prompt_for_package("Package", None, check, api).await?;
-        Ok(PackageWizardOutput {
-            api,
-            local_path: None,
-            local_manifest: None,
-        })
-    }
-
-    pub async fn run(
-        self,
-        api: Option<&WasmerClient>,
-    ) -> Result<PackageWizardOutput, anyhow::Error> {
-        match self.create_mode {
-            CreateMode::Create => self.build_new_package(),
-            CreateMode::SelectExisting => self.prompt_existing_package(api).await,
-            CreateMode::CreateOrSelect => {
-                let theme = ColorfulTheme::default();
-                let index = Select::with_theme(&theme)
-                    .with_prompt("What package do you want to use?")
-                    .items(&["Create new package", "Use existing package"])
-                    .default(0)
-                    .interact()?;
-
-                match index {
-                    0 => self.build_new_package(),
-                    1 => self.prompt_existing_package(api).await,
-                    other => {
-                        unreachable!("Unexpected index: {other}");
-                    }
-                }
-            }
-        }
-    }
-}
-
-fn initialize_static_site(path: &Path) -> Result<wasmer_config::package::Manifest, anyhow::Error> {
-    let pubdir_name = "public";
-    let pubdir = path.join(pubdir_name);
-    if !pubdir.is_dir() {
-        std::fs::create_dir_all(&pubdir)
-            .with_context(|| format!("Failed to create directory: '{}'", pubdir.display()))?;
-    }
-    let index = pubdir.join("index.html");
-
-    let static_html = SAMPLE_INDEX_HTML.replace("{{title}}", "My static website");
-
-    if !index.is_file() {
-        std::fs::write(&index, static_html.as_str())
-            .with_context(|| "Could not write index.html file".to_string())?;
-    } else {
-        // The index.js file already exists, so we can ask the user if they want to overwrite it
-        let theme = dialoguer::theme::ColorfulTheme::default();
-        let should_overwrite = dialoguer::Confirm::with_theme(&theme)
-            .with_prompt("index.html already exists. Do you want to overwrite it?")
-            .interact()
-            .unwrap();
-        if should_overwrite {
-            std::fs::write(&index, static_html.as_str())
-                .with_context(|| "Could not write index.html file".to_string())?;
-        }
-    }
-
-    let raw_static_site_toml = format!(
-        r#"
-[dependencies]
-"{}" = "{}"
-
-[fs]
-public = "{}"
-"#,
-        WASM_STATIC_SERVER_PACKAGE, WASM_STATIC_SERVER_VERSION, pubdir_name
-    );
-
-    let manifest = wasmer_config::package::Manifest::parse(raw_static_site_toml.as_str())
-        .map_err(|e| anyhow::anyhow!("Could not parse js worker manifest: {}", e))?;
-
-    Ok(manifest)
-}
-
-fn initialize_js_worker(path: &Path) -> Result<wasmer_config::package::Manifest, anyhow::Error> {
-    let srcdir_name = "src";
-    let srcdir = path.join(srcdir_name);
-    if !srcdir.is_dir() {
-        std::fs::create_dir_all(&srcdir)
-            .with_context(|| format!("Failed to create directory: '{}'", srcdir.display()))?;
-    }
-
-    let index_js = srcdir.join("index.js");
-
-    let sample_js = SAMPLE_JS_WORKER.replace("{{package}}", "My JS worker");
-
-    if !index_js.is_file() {
-        std::fs::write(&index_js, sample_js.as_str())
-            .with_context(|| "Could not write index.js file".to_string())?;
-    }
-
-    // get the remote repository if it exists
-    // Todo: add this to the manifest
-    // let remote_repo_url = Command::new("git")
-    //     .arg("remote")
-    //     .arg("get-url")
-    //     .arg("origin")
-    //     .output()
-    //     .map_or("".to_string(), |f| String::from_utf8(f.stdout).unwrap());
-
-    let raw_js_worker_toml = format!(
-        r#"
-[dependencies]
-"{winterjs_pkg}" = "{winterjs_version}"
-
-[fs]
-"/src" = "./src"
-
-[[command]]
-name = "script"
-module = "{winterjs_pkg}:winterjs"
-runner = "https://webc.org/runner/wasi"
-
-[command.annotations.wasi]
-main-args = ["/src/index.js"]
-env = ["JS_PATH=/src/index.js"]
-"#,
-        winterjs_pkg = WASMER_WINTER_JS_PACKAGE,
-        winterjs_version = WASMER_WINTER_JS_VERSION,
-    );
-
-    let manifest = wasmer_config::package::Manifest::parse(raw_js_worker_toml.as_str())
-        .map_err(|e| anyhow::anyhow!("Could not parse js worker manifest: {}", e))?;
-
-    Ok(manifest)
-}
-
-fn initialize_py_worker(path: &Path) -> Result<wasmer_config::package::Manifest, anyhow::Error> {
-    let appdir_name = "src";
-    let appdir = path.join(appdir_name);
-    if !appdir.is_dir() {
-        std::fs::create_dir_all(&appdir)
-            .with_context(|| format!("Failed to create directory: '{}'", appdir.display()))?;
-    }
-    let main_py = appdir.join("main.py");
-
-    let sample_main = SAMPLE_PY_APPLICATION.replace("{{package}}", "My Python Worker");
-
-    if !main_py.is_file() {
-        std::fs::write(&main_py, sample_main.as_str())
-            .with_context(|| "Could not write main.py file".to_string())?;
-    }
-
-    // Todo: add this to the manifest
-    // let remote_repo_url = Command::new("git")
-    //     .arg("remote")
-    //     .arg("get-url")
-    //     .arg("origin")
-    //     .output()
-    //     .map_or("".to_string(), |f| String::from_utf8(f.stdout).unwrap());
-
-    let raw_py_worker_toml = format!(
-        r#"
-[dependencies]
-"{}" = "{}"
-
-[fs]
-"/src" = "./src"
-# "/.env" = "./.env/" # Bundle the virtualenv
-
-[[command]]
-name = "script"
-module = "{}:python" # The "python" atom from "wasmer/python"
-runner = "wasi"
-
-[command.annotations.wasi]
-main-args = ["/src/main.py"]
-# env = ["PYTHON_PATH=/app/.env:/etc/python3.12/site-packages"] # Make our virtualenv accessible    
-"#,
-        WASM_PYTHON_PACKAGE, WASM_PYTHON_VERSION, WASM_PYTHON_PACKAGE
-    );
-
-    let manifest = wasmer_config::package::Manifest::parse(raw_py_worker_toml.as_str())
-        .map_err(|e| anyhow::anyhow!("Could not parse py worker manifest: {}", e))?;
-
-    Ok(manifest)
-}
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[tokio::test]
-    async fn test_package_wizard_create_static_site() {
-        let dir = tempfile::tempdir().unwrap();
-
-        PackageWizard {
-            path: dir.path().to_owned(),
-            type_: Some(PackageType::StaticWebsite),
-            create_mode: CreateMode::Create,
-            namespace: None,
-            namespace_default: None,
-            name: None,
-            user: None,
-        }
-        .run(None)
-        .await
-        .unwrap();
-
-        let manifest = std::fs::read_to_string(dir.path().join("wasmer.toml")).unwrap();
-        pretty_assertions::assert_eq!(
-            manifest,
-            r#"[dependencies]
-"wasmer/static-web-server" = "^1"
-
-[fs]
-public = "public"
-"#,
-        );
-
-        assert!(dir.path().join("public").join("index.html").is_file());
-    }
-
-    #[tokio::test]
-    async fn test_package_wizard_create_js_worker() {
-        let dir = tempfile::tempdir().unwrap();
-
-        PackageWizard {
-            path: dir.path().to_owned(),
-            type_: Some(PackageType::JsWorker),
-            create_mode: CreateMode::Create,
-            namespace: None,
-            namespace_default: None,
-            name: None,
-            user: None,
-        }
-        .run(None)
-        .await
-        .unwrap();
-        let manifest = std::fs::read_to_string(dir.path().join("wasmer.toml")).unwrap();
-
-        pretty_assertions::assert_eq!(
-            manifest,
-            r#"[dependencies]
-"wasmer/winterjs" = "*"
-
-[fs]
-"/src" = "./src"
-
-[[command]]
-name = "script"
-module = "wasmer/winterjs:winterjs"
-runner = "https://webc.org/runner/wasi"
-
-[command.annotations.wasi]
-env = ["JS_PATH=/src/index.js"]
-main-args = ["/src/index.js"]
-"#,
-        );
-
-        assert!(dir.path().join("src").join("index.js").is_file());
-    }
-
-    #[tokio::test]
-    async fn test_package_wizard_create_py_worker() {
-        let dir = tempfile::tempdir().unwrap();
-
-        PackageWizard {
-            path: dir.path().to_owned(),
-            type_: Some(PackageType::PyApplication),
-            create_mode: CreateMode::Create,
-            namespace: None,
-            namespace_default: None,
-            name: None,
-            user: None,
-        }
-        .run(None)
-        .await
-        .unwrap();
-        let manifest = std::fs::read_to_string(dir.path().join("wasmer.toml")).unwrap();
-
-        pretty_assertions::assert_eq!(
-            manifest,
-            r#"[dependencies]
-"wasmer/python" = "^3.12.6"
-
-[fs]
-"/src" = "./src"
-
-[[command]]
-name = "script"
-module = "wasmer/python:python"
-runner = "wasi"
-
-[command.annotations.wasi]
-main-args = ["/src/main.py"]
-"#,
-        );
-
-        assert!(dir.path().join("src").join("main.py").is_file());
-    }
-}
+// use std::path::{Path, PathBuf};
+//
+// use anyhow::Context;
+// use dialoguer::{theme::ColorfulTheme, Select};
+// use wasmer_api::{types::UserWithNamespaces, WasmerClient};
+//
+// use super::prompts::PackageCheckMode;
+//
+// const WASM_STATIC_SERVER_PACKAGE: &str = "wasmer/static-web-server";
+// const WASM_STATIC_SERVER_VERSION: &str = "1";
+//
+// const WASMER_WINTER_JS_PACKAGE: &str = "wasmer/winterjs";
+// const WASMER_WINTER_JS_VERSION: &str = "*";
+//
+// const WASM_PYTHON_PACKAGE: &str = "wasmer/python";
+// const WASM_PYTHON_VERSION: &str = "3.12.6";
+//
+// const SAMPLE_INDEX_HTML: &str = include_str!("./templates/static-site/index.html");
+// const SAMPLE_JS_WORKER: &str = include_str!("./templates/js-worker/index.js");
+// const SAMPLE_PY_APPLICATION: &str = include_str!("./templates/py-application/main.py");
+//
+// #[derive(clap::ValueEnum, Clone, Copy, Debug)]
+// pub enum PackageType {
+//     #[clap(name = "regular")]
+//     Regular,
+//     /// A static website.
+//     #[clap(name = "static-website")]
+//     StaticWebsite,
+//     /// A js-worker
+//     #[clap(name = "js-worker")]
+//     JsWorker,
+//     /// A py-worker
+//     #[clap(name = "py-application")]
+//     PyApplication,
+// }
+//
+// #[derive(Clone, Copy, Debug)]
+// pub enum CreateMode {
+//     Create,
+//     SelectExisting,
+//     #[allow(dead_code)]
+//     CreateOrSelect,
+// }
+//
+// fn prompt_for_package_type() -> Result<PackageType, anyhow::Error> {
+//     let theme = ColorfulTheme::default();
+//     Select::with_theme(&theme)
+//         .with_prompt("What type of package do you want to create?")
+//         .items(&["Basic pacakge", "Static website"])
+//         .interact()
+//         .map(|idx| match idx {
+//             0 => PackageType::Regular,
+//             1 => PackageType::StaticWebsite,
+//             _ => unreachable!(),
+//         })
+//         .map_err(anyhow::Error::from)
+// }
+//
+// #[derive(Debug)]
+// pub struct PackageWizard {
+//     pub path: PathBuf,
+//     pub type_: Option<PackageType>,
+//
+//     pub create_mode: CreateMode,
+//
+//     /// Namespace to use.
+//     pub namespace: Option<String>,
+//     /// Default namespace to use.
+//     /// Will still show a prompt, with this as the default value.
+//     /// Ignored if [`Self::namespace`] is set.
+//     pub namespace_default: Option<String>,
+//
+//     /// Pre-configured package name.
+//     pub name: Option<String>,
+//
+//     pub user: Option<UserWithNamespaces>,
+// }
+//
+// pub struct PackageWizardOutput {
+//     pub api: Option<wasmer_api::types::Package>,
+//     pub local_path: Option<PathBuf>,
+//     pub local_manifest: Option<wasmer_config::package::Manifest>,
+// }
+//
+// impl PackageWizard {
+//     fn build_new_package(&self) -> Result<PackageWizardOutput, anyhow::Error> {
+//         let ty = match self.type_ {
+//             Some(t) => t,
+//             None => prompt_for_package_type()?,
+//         };
+//
+//         if !self.path.is_dir() {
+//             std::fs::create_dir_all(&self.path).with_context(|| {
+//                 format!("Failed to create directory: '{}'", self.path.display())
+//             })?;
+//         }
+//
+//         let manifest = match ty {
+//             PackageType::Regular => todo!(),
+//             PackageType::StaticWebsite => initialize_static_site(&self.path)?,
+//             PackageType::JsWorker => initialize_js_worker(&self.path)?,
+//             PackageType::PyApplication => initialize_py_worker(&self.path)?,
+//         };
+//
+//         let manifest_path = self.path.join("wasmer.toml");
+//         let manifest_raw = manifest
+//             .to_string()
+//             .context("could not serialize package manifest")?;
+//         std::fs::write(manifest_path, manifest_raw)
+//             .with_context(|| format!("Failed to write manifest to '{}'", self.path.display()))?;
+//
+//         Ok(PackageWizardOutput {
+//             api: None,
+//             local_path: Some(self.path.clone()),
+//             local_manifest: Some(manifest),
+//         })
+//     }
+//
+//     async fn prompt_existing_package(
+//         &self,
+//         api: Option<&WasmerClient>,
+//     ) -> Result<PackageWizardOutput, anyhow::Error> {
+//         // Existing package
+//         let check = if api.is_some() {
+//             Some(PackageCheckMode::MustExist)
+//         } else {
+//             None
+//         };
+//
+//         eprintln!("Enter the name of an existing package:");
+//         let (_ident, api) = super::prompts::prompt_for_package("Package", None, check, api).await?;
+//         Ok(PackageWizardOutput {
+//             api,
+//             local_path: None,
+//             local_manifest: None,
+//         })
+//     }
+//
+//     pub async fn run(
+//         self,
+//         api: Option<&WasmerClient>,
+//     ) -> Result<PackageWizardOutput, anyhow::Error> {
+//         match self.create_mode {
+//             CreateMode::Create => self.build_new_package(),
+//             CreateMode::SelectExisting => self.prompt_existing_package(api).await,
+//             CreateMode::CreateOrSelect => {
+//                 let theme = ColorfulTheme::default();
+//                 let index = Select::with_theme(&theme)
+//                     .with_prompt("What package do you want to use?")
+//                     .items(&["Create new package", "Use existing package"])
+//                     .default(0)
+//                     .interact()?;
+//
+//                 match index {
+//                     0 => self.build_new_package(),
+//                     1 => self.prompt_existing_package(api).await,
+//                     other => {
+//                         unreachable!("Unexpected index: {other}");
+//                     }
+//                 }
+//             }
+//         }
+//     }
+// }
+//
+// fn initialize_static_site(path: &Path) -> Result<wasmer_config::package::Manifest, anyhow::Error> {
+//     let pubdir_name = "public";
+//     let pubdir = path.join(pubdir_name);
+//     if !pubdir.is_dir() {
+//         std::fs::create_dir_all(&pubdir)
+//             .with_context(|| format!("Failed to create directory: '{}'", pubdir.display()))?;
+//     }
+//     let index = pubdir.join("index.html");
+//
+//     let static_html = SAMPLE_INDEX_HTML.replace("{{title}}", "My static website");
+//
+//     if !index.is_file() {
+//         std::fs::write(&index, static_html.as_str())
+//             .with_context(|| "Could not write index.html file".to_string())?;
+//     } else {
+//         // The index.js file already exists, so we can ask the user if they want to overwrite it
+//         let theme = dialoguer::theme::ColorfulTheme::default();
+//         let should_overwrite = dialoguer::Confirm::with_theme(&theme)
+//             .with_prompt("index.html already exists. Do you want to overwrite it?")
+//             .interact()
+//             .unwrap();
+//         if should_overwrite {
+//             std::fs::write(&index, static_html.as_str())
+//                 .with_context(|| "Could not write index.html file".to_string())?;
+//         }
+//     }
+//
+//     let raw_static_site_toml = format!(
+//         r#"
+// [dependencies]
+// "{}" = "{}"
+//
+// [fs]
+// public = "{}"
+// "#,
+//         WASM_STATIC_SERVER_PACKAGE, WASM_STATIC_SERVER_VERSION, pubdir_name
+//     );
+//
+//     let manifest = wasmer_config::package::Manifest::parse(raw_static_site_toml.as_str())
+//         .map_err(|e| anyhow::anyhow!("Could not parse js worker manifest: {}", e))?;
+//
+//     Ok(manifest)
+// }
+//
+// fn initialize_js_worker(path: &Path) -> Result<wasmer_config::package::Manifest, anyhow::Error> {
+//     let srcdir_name = "src";
+//     let srcdir = path.join(srcdir_name);
+//     if !srcdir.is_dir() {
+//         std::fs::create_dir_all(&srcdir)
+//             .with_context(|| format!("Failed to create directory: '{}'", srcdir.display()))?;
+//     }
+//
+//     let index_js = srcdir.join("index.js");
+//
+//     let sample_js = SAMPLE_JS_WORKER.replace("{{package}}", "My JS worker");
+//
+//     if !index_js.is_file() {
+//         std::fs::write(&index_js, sample_js.as_str())
+//             .with_context(|| "Could not write index.js file".to_string())?;
+//     }
+//
+//     // get the remote repository if it exists
+//     // Todo: add this to the manifest
+//     // let remote_repo_url = Command::new("git")
+//     //     .arg("remote")
+//     //     .arg("get-url")
+//     //     .arg("origin")
+//     //     .output()
+//     //     .map_or("".to_string(), |f| String::from_utf8(f.stdout).unwrap());
+//
+//     let raw_js_worker_toml = format!(
+//         r#"
+// [dependencies]
+// "{winterjs_pkg}" = "{winterjs_version}"
+//
+// [fs]
+// "/src" = "./src"
+//
+// [[command]]
+// name = "script"
+// module = "{winterjs_pkg}:winterjs"
+// runner = "https://webc.org/runner/wasi"
+//
+// [command.annotations.wasi]
+// main-args = ["/src/index.js"]
+// env = ["JS_PATH=/src/index.js"]
+// "#,
+//         winterjs_pkg = WASMER_WINTER_JS_PACKAGE,
+//         winterjs_version = WASMER_WINTER_JS_VERSION,
+//     );
+//
+//     let manifest = wasmer_config::package::Manifest::parse(raw_js_worker_toml.as_str())
+//         .map_err(|e| anyhow::anyhow!("Could not parse js worker manifest: {}", e))?;
+//
+//     Ok(manifest)
+// }
+//
+// fn initialize_py_worker(path: &Path) -> Result<wasmer_config::package::Manifest, anyhow::Error> {
+//     let appdir_name = "src";
+//     let appdir = path.join(appdir_name);
+//     if !appdir.is_dir() {
+//         std::fs::create_dir_all(&appdir)
+//             .with_context(|| format!("Failed to create directory: '{}'", appdir.display()))?;
+//     }
+//     let main_py = appdir.join("main.py");
+//
+//     let sample_main = SAMPLE_PY_APPLICATION.replace("{{package}}", "My Python Worker");
+//
+//     if !main_py.is_file() {
+//         std::fs::write(&main_py, sample_main.as_str())
+//             .with_context(|| "Could not write main.py file".to_string())?;
+//     }
+//
+//     // Todo: add this to the manifest
+//     // let remote_repo_url = Command::new("git")
+//     //     .arg("remote")
+//     //     .arg("get-url")
+//     //     .arg("origin")
+//     //     .output()
+//     //     .map_or("".to_string(), |f| String::from_utf8(f.stdout).unwrap());
+//
+//     let raw_py_worker_toml = format!(
+//         r#"
+// [dependencies]
+// "{}" = "{}"
+//
+// [fs]
+// "/src" = "./src"
+// # "/.env" = "./.env/" # Bundle the virtualenv
+//
+// [[command]]
+// name = "script"
+// module = "{}:python" # The "python" atom from "wasmer/python"
+// runner = "wasi"
+//
+// [command.annotations.wasi]
+// main-args = ["/src/main.py"]
+// # env = ["PYTHON_PATH=/app/.env:/etc/python3.12/site-packages"] # Make our virtualenv accessible
+// "#,
+//         WASM_PYTHON_PACKAGE, WASM_PYTHON_VERSION, WASM_PYTHON_PACKAGE
+//     );
+//
+//     let manifest = wasmer_config::package::Manifest::parse(raw_py_worker_toml.as_str())
+//         .map_err(|e| anyhow::anyhow!("Could not parse py worker manifest: {}", e))?;
+//
+//     Ok(manifest)
+// }
+// #[cfg(test)]
+// mod tests {
+//     use super::*;
+//
+//     #[tokio::test]
+//     async fn test_package_wizard_create_static_site() {
+//         let dir = tempfile::tempdir().unwrap();
+//
+//         PackageWizard {
+//             path: dir.path().to_owned(),
+//             type_: Some(PackageType::StaticWebsite),
+//             create_mode: CreateMode::Create,
+//             namespace: None,
+//             namespace_default: None,
+//             name: None,
+//             user: None,
+//         }
+//         .run(None)
+//         .await
+//         .unwrap();
+//
+//         let manifest = std::fs::read_to_string(dir.path().join("wasmer.toml")).unwrap();
+//         pretty_assertions::assert_eq!(
+//             manifest,
+//             r#"[dependencies]
+// "wasmer/static-web-server" = "^1"
+//
+// [fs]
+// public = "public"
+// "#,
+//         );
+//
+//         assert!(dir.path().join("public").join("index.html").is_file());
+//     }
+//
+//     #[tokio::test]
+//     async fn test_package_wizard_create_js_worker() {
+//         let dir = tempfile::tempdir().unwrap();
+//
+//         PackageWizard {
+//             path: dir.path().to_owned(),
+//             type_: Some(PackageType::JsWorker),
+//             create_mode: CreateMode::Create,
+//             namespace: None,
+//             namespace_default: None,
+//             name: None,
+//             user: None,
+//         }
+//         .run(None)
+//         .await
+//         .unwrap();
+//         let manifest = std::fs::read_to_string(dir.path().join("wasmer.toml")).unwrap();
+//
+//         pretty_assertions::assert_eq!(
+//             manifest,
+//             r#"[dependencies]
+// "wasmer/winterjs" = "*"
+//
+// [fs]
+// "/src" = "./src"
+//
+// [[command]]
+// name = "script"
+// module = "wasmer/winterjs:winterjs"
+// runner = "https://webc.org/runner/wasi"
+//
+// [command.annotations.wasi]
+// env = ["JS_PATH=/src/index.js"]
+// main-args = ["/src/index.js"]
+// "#,
+//         );
+//
+//         assert!(dir.path().join("src").join("index.js").is_file());
+//     }
+//
+//     #[tokio::test]
+//     async fn test_package_wizard_create_py_worker() {
+//         let dir = tempfile::tempdir().unwrap();
+//
+//         PackageWizard {
+//             path: dir.path().to_owned(),
+//             type_: Some(PackageType::PyApplication),
+//             create_mode: CreateMode::Create,
+//             namespace: None,
+//             namespace_default: None,
+//             name: None,
+//             user: None,
+//         }
+//         .run(None)
+//         .await
+//         .unwrap();
+//         let manifest = std::fs::read_to_string(dir.path().join("wasmer.toml")).unwrap();
+//
+//         pretty_assertions::assert_eq!(
+//             manifest,
+//             r#"[dependencies]
+// "wasmer/python" = "^3.12.6"
+//
+// [fs]
+// "/src" = "./src"
+//
+// [[command]]
+// name = "script"
+// module = "wasmer/python:python"
+// runner = "wasi"
+//
+// [command.annotations.wasi]
+// main-args = ["/src/main.py"]
+// "#,
+//         );
+//
+//         assert!(dir.path().join("src").join("main.py").is_file());
+//     }
+// }
diff --git a/lib/cli/src/utils/prompts.rs b/lib/cli/src/utils/prompts.rs
index ef3618a6880..c5ab5da3020 100644
--- a/lib/cli/src/utils/prompts.rs
+++ b/lib/cli/src/utils/prompts.rs
@@ -97,9 +97,16 @@ pub async fn prompt_for_package(
         if let Some(check) = &check {
             let api = client.expect("Check mode specified, but no API provided");
 
-            let pkg = wasmer_api::query::get_package(api, ident.to_string())
-                .await
-                .context("could not query backend for package")?;
+            let pkg = if let Some(v) = ident.version_opt() {
+                wasmer_api::query::get_package_version(api, ident.full_name(), v.to_string())
+                    .await
+                    .context("could not query backend for package")?
+                    .map(|p| p.package)
+            } else {
+                wasmer_api::query::get_package(api, ident.to_string())
+                    .await
+                    .context("could not query backend for package")?
+            };
 
             match check {
                 PackageCheckMode::MustExist => {
@@ -122,6 +129,8 @@ pub async fn prompt_for_package(
                     }
                 }
             }
+        } else {
+            break Ok((ident, None));
         }
     }
 }
diff --git a/tests/wasmer-argus/src/argus/mod.rs b/tests/wasmer-argus/src/argus/mod.rs
index 073dc460e65..648da747108 100644
--- a/tests/wasmer-argus/src/argus/mod.rs
+++ b/tests/wasmer-argus/src/argus/mod.rs
@@ -95,7 +95,7 @@ impl Argus {
         p.enable_steady_tick(Duration::from_millis(100));
 
         let package_name = Argus::get_package_id(package);
-        let webc_url: Url = match &package.distribution.pirita_download_url {
+        let webc_url: Url = match &package.distribution_v2.pirita_download_url {
             Some(url) => url.parse().unwrap(),
             None => {
                 info!("package {} has no download url, skipping", package_name);
@@ -172,7 +172,7 @@ impl Argus {
             return true;
         }
 
-        if pkg.distribution.pirita_sha256_hash.is_none() {
+        if pkg.distribution_v2.pirita_sha256_hash.is_none() {
             info!("skipping test for {name} as it has no hash");
             return false;
         }
diff --git a/tests/wasmer-argus/src/argus/packages.rs b/tests/wasmer-argus/src/argus/packages.rs
index 5768e7ac258..0fd0d48546e 100644
--- a/tests/wasmer-argus/src/argus/packages.rs
+++ b/tests/wasmer-argus/src/argus/packages.rs
@@ -188,7 +188,7 @@ impl Argus {
     /// Return the complete path to the folder of the test for the package, from the outdir to the
     /// hash
     pub async fn get_path(config: Arc<ArgusConfig>, pkg: &PackageVersionWithPackage) -> PathBuf {
-        let hash = match &pkg.distribution.pirita_sha256_hash {
+        let hash = match &pkg.distribution_v2.pirita_sha256_hash {
             Some(hash) => hash,
             None => {
                 unreachable!("no package without an hash should reach this function!")