From 82aeae2d80252fa98d4edd6d3f89e3dcbb30cc2c Mon Sep 17 00:00:00 2001 From: Ben Lovell Date: Fri, 5 Jun 2026 16:51:19 +0200 Subject: [PATCH 1/3] fix: add name field to generated SKILL.md frontmatter (#287) The skills installer (npx skills add) requires both name and description in SKILL.md frontmatter; ours had only description, so it reported "No skills found". Add name to the generator header and regenerate the checked-in file. --- crates/tower-cmd/src/skill.rs | 1 + skills/tower/SKILL.md | 1 + 2 files changed, 2 insertions(+) diff --git a/crates/tower-cmd/src/skill.rs b/crates/tower-cmd/src/skill.rs index be1ee7b7..62b1430d 100644 --- a/crates/tower-cmd/src/skill.rs +++ b/crates/tower-cmd/src/skill.rs @@ -99,6 +99,7 @@ fn append_command(out: &mut String, cmd: &Command, path: &[&str], depth: usize) } const WORKFLOW_HEADER: &str = r#"--- +name: tower description: Use Tower to build, run, and deploy Python data apps, pipelines, and AI agents. Covers MCP tools, Towerfile setup, local development, cloud deployment, scheduling, and secrets management. --- diff --git a/skills/tower/SKILL.md b/skills/tower/SKILL.md index 13ca2c05..48982434 100644 --- a/skills/tower/SKILL.md +++ b/skills/tower/SKILL.md @@ -1,4 +1,5 @@ --- +name: tower description: Use Tower to build, run, and deploy Python data apps, pipelines, and AI agents. Covers MCP tools, Towerfile setup, local development, cloud deployment, scheduling, and secrets management. --- From 5e359c45db1d4fae19a66ebe9a6da2e0770a8c4f Mon Sep 17 00:00:00 2001 From: Ben Lovell Date: Mon, 8 Jun 2026 19:52:25 +0200 Subject: [PATCH 2/3] feat: make TOWER_ENVIRONMENT ordinary passthrough in local runs (#289) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit make_env_vars injected TOWER_ENVIRONMENT as the last step of building a run's env, unconditionally, so it overwrote any value a caller had already set in the env map. Drop the special case and let the value pass through like any other env var. The local run path now supplies it explicitly from the resolved --environment arg, which defaults to "default" — so a local run with no flag still gets TOWER_ENVIRONMENT=default, as before. The now-unused env parameter and its threading through execute_bash_program go with it. --- crates/tower-cmd/src/run.rs | 1 + crates/tower-runtime/src/local.rs | 14 -------------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/crates/tower-cmd/src/run.rs b/crates/tower-cmd/src/run.rs index 3a3cfa27..19ffdbf7 100644 --- a/crates/tower-cmd/src/run.rs +++ b/crates/tower-cmd/src/run.rs @@ -182,6 +182,7 @@ where env_vars.insert("TOWER_JWT".to_string(), session.token.jwt.to_string()); env_vars.insert("TOWER__RUNTIME__IS_LOCAL".to_string(), "true".to_string()); + env_vars.insert("TOWER_ENVIRONMENT".to_string(), env.to_string()); // Load the Towerfile let towerfile_path = path.join("Towerfile"); diff --git a/crates/tower-runtime/src/local.rs b/crates/tower-runtime/src/local.rs index cafc2bc7..51b0cafa 100644 --- a/crates/tower-runtime/src/local.rs +++ b/crates/tower-runtime/src/local.rs @@ -146,7 +146,6 @@ async fn inner_execute_local_app( ) -> Result { let ctx = opts.ctx.clone(); let package = opts.package; - let environment = opts.environment; let package_path = package.unpacked_path.clone().unwrap().to_path_buf(); // set for later on. @@ -186,7 +185,6 @@ async fn inner_execute_local_app( if is_bash_package(&package) { let child = execute_bash_program( &ctx, - &environment, working_dir, package_path, &manifest, @@ -212,7 +210,6 @@ async fn inner_execute_local_app( let uv = Uv::new(opts.cache_dir, protected_mode).await?; let env_vars = make_env_vars( &ctx, - &environment, &package_path, &secrets, ¶ms, @@ -475,7 +472,6 @@ impl App for LocalApp { async fn execute_bash_program( ctx: &tower_telemetry::Context, - env: &str, cwd: PathBuf, package_path: PathBuf, manifest: &Manifest, @@ -497,7 +493,6 @@ async fn execute_bash_program( .stderr(Stdio::piped()) .envs(make_env_vars( &ctx, - env, &cwd, &secrets, ¶ms, @@ -524,7 +519,6 @@ fn make_env_var_key(src: &str) -> String { fn make_env_vars( ctx: &tower_telemetry::Context, - env: &str, cwd: &PathBuf, secs: &HashMap, params: &HashMap, @@ -566,14 +560,6 @@ fn make_env_vars( .to_string(); res.insert("PYTHONPATH".to_string(), pythonpath); - // Inject a TOWER_ENVIRONMENT parameter so you know what environment you're running in. Empty - // environment is "default" by default. - if env.is_empty() { - res.insert("TOWER_ENVIRONMENT".to_string(), "default".to_string()); - } else { - res.insert("TOWER_ENVIRONMENT".to_string(), env.to_string()); - } - res.insert("PYTHONUNBUFFERED".to_string(), "x".to_string()); res From e356f97eada4819dc7ead5a92c4d24fb477e3bfd Mon Sep 17 00:00:00 2001 From: Ben Lovell Date: Mon, 8 Jun 2026 20:03:19 +0200 Subject: [PATCH 3/3] chore: bump version to v0.3.64 (#290) --- Cargo.lock | 22 +++++++++++----------- Cargo.toml | 2 +- pyproject.toml | 2 +- uv.lock | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c127be68..e278050c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -524,7 +524,7 @@ dependencies = [ [[package]] name = "config" -version = "0.3.63" +version = "0.3.64" dependencies = [ "base64", "chrono", @@ -631,7 +631,7 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crypto" -version = "0.3.63" +version = "0.3.64" dependencies = [ "aes-gcm", "base64", @@ -3331,7 +3331,7 @@ dependencies = [ [[package]] name = "testutils" -version = "0.3.63" +version = "0.3.64" dependencies = [ "pem", "rsa", @@ -3586,7 +3586,7 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "tower" -version = "0.3.63" +version = "0.3.64" dependencies = [ "config", "pyo3", @@ -3614,7 +3614,7 @@ dependencies = [ [[package]] name = "tower-api" -version = "0.3.63" +version = "0.3.64" dependencies = [ "reqwest", "serde", @@ -3626,7 +3626,7 @@ dependencies = [ [[package]] name = "tower-cmd" -version = "0.3.63" +version = "0.3.64" dependencies = [ "axum", "bytes", @@ -3697,7 +3697,7 @@ checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-package" -version = "0.3.63" +version = "0.3.64" dependencies = [ "async-compression", "flate2", @@ -3721,7 +3721,7 @@ dependencies = [ [[package]] name = "tower-runtime" -version = "0.3.63" +version = "0.3.64" dependencies = [ "async-trait", "chrono", @@ -3745,7 +3745,7 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tower-telemetry" -version = "0.3.63" +version = "0.3.64" dependencies = [ "tracing", "tracing-appender", @@ -3754,7 +3754,7 @@ dependencies = [ [[package]] name = "tower-uv" -version = "0.3.63" +version = "0.3.64" dependencies = [ "async-compression", "async_zip", @@ -3774,7 +3774,7 @@ dependencies = [ [[package]] name = "tower-version" -version = "0.3.63" +version = "0.3.64" dependencies = [ "anyhow", "chrono", diff --git a/Cargo.toml b/Cargo.toml index fa80245f..13c474a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ resolver = "2" [workspace.package] edition = "2021" -version = "0.3.63" +version = "0.3.64" description = "Tower is the best way to host Python data apps in production" rust-version = "1.81" authors = ["Brad Heller ", "Ben Lovell "] diff --git a/pyproject.toml b/pyproject.toml index 07c007d1..c4a3b831 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "maturin" [project] name = "tower" -version = "0.3.63" +version = "0.3.64" description = "Tower CLI and runtime environment for Tower." authors = [{ name = "Tower Computing Inc.", email = "brad@tower.dev" }] readme = "README.md" diff --git a/uv.lock b/uv.lock index 9e390c39..3f7fedc9 100644 --- a/uv.lock +++ b/uv.lock @@ -2642,7 +2642,7 @@ wheels = [ [[package]] name = "tower" -version = "0.3.63" +version = "0.3.64" source = { editable = "." } dependencies = [ { name = "attrs" },