Skip to content

feat: add a runtime Towerfile field and a bun runtime - #380

Open
migueltheduck wants to merge 3 commits into
developfrom
feat/bun-runtime
Open

migueltheduck wants to merge 3 commits into
developfrom
feat/bun-runtime

Conversation

@migueltheduck

@migueltheduck migueltheduck commented Nov 10, 2026 •

Copy link
Copy Markdown

Why

The runtime starts every app with uv, so there's no way to run a JavaScript or TypeScript app. The bundle also doesn't say which runtime an app needs, so the server can't send its runs to a runner that has it.

What

  • [app] runtime: python or bun. Other values are rejected, bash included, and bun needs a JavaScript or TypeScript script. Without the field, apps run as before.
  • MANIFEST: the value is copied only when it's set. It stays a string, so a runtime this CLI doesn't know fails the run with UnsupportedRuntime instead of failing to parse.
  • Bun runtime: when the app has a package.json, bun install runs first, frozen when there's a lockfile. Then bun run <script> runs in its own process group, with a cleared environment in protected mode, like uv. If bun isn't installed, the run fails with MissingBun.
  • import_paths go on NODE_PATH, as Python's go on PYTHONPATH, so ../shared/helpers.ts is imported as "helpers". The app's node_modules goes on it too, so shared code gets the versions the app pinned; otherwise bun would quietly auto-install the latest.
  • Packaging leaves node_modules out of bundles, as it does .venv.
  • Agents:
    • tower_file_update takes runtime.
    • When there's no pyproject.toml, tower_file_generate writes a bun Towerfile from package.json. It takes the script from module, main or the start script, then falls back to common entry points.
    • The workflow help and the skill cover bun init.
  • CI installs bun on Linux, so the bun tests run there.

Compatibility

Apps that don't set runtime are unaffected: no new key in the MANIFEST, still version 3, and the same runtime choice as before. Servers and runners that don't know the key ignore it. tower_file_generate still prefers pyproject.toml; with no pyproject.toml and no package.json, the error now names both files.

@coderabbitai

coderabbitai Bot commented Nov 10, 2026 •

Copy link
Copy Markdown
Pre-merge checks: Passed 1 · Inconclusive 1

Failed Failed checks: 1 inconclusive

Check name Status Explanation Resolution
Title check Pending This assessment has not completed. The check will be retried on the next pre-merge check run.
Passed Passed checks: 1 passed

Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

@github-actions

Copy link
Copy Markdown
Contributor


Thank you for your submission, we really appreciate it. Like many open-source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution. You can sign the CLA by just posting a Pull Request Comment same as the below format.


I have read the CLA Document and I hereby sign the CLA


You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

@migueltheduck
migueltheduck requested a review from bradhe November 11, 2026 10:01
Comment on lines 198 to 221
@@ -206,6 +219,38 @@ async fn inner_execute_local_app(
return Err(Error::Cancelled);
}
Ok(code)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably want to remove this.

@migueltheduck migueltheduck Nov 12, 2026 •

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, but leaving it out of this PR.

migueltheduck and others added 3 commits November 11, 2026 18:54
`[app] runtime` declares what starts the script: python (uv) or bun.
It is copied into the MANIFEST only when set, so existing bundles are
unchanged, and apps without it run exactly as before. The manifest keeps
the value as a string, so a runtime this version doesn't know still
parses and fails the run with UnsupportedRuntime instead.

Bun apps run `bun install` (frozen when there's a lockfile) when they
have a package.json, on the setup channel, then `bun run` on the script.
Like uv, bun runs in its own process group and with a cleared
environment in protected mode, and installs into the runtime's cache dir
when it has one. Bun scripts must be JavaScript or TypeScript, and
import_paths aren't supported with bun yet.

The packager now leaves node_modules out of bundles, and the MCP
tower_file_update tool and the agent skill cover the new key.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The runtime puts a bun app's import paths on NODE_PATH, as it puts a
Python app's on PYTHONPATH, so `import_paths = ["../shared"]` makes
`../shared/helpers.ts` importable as "helpers".

Shared code is packaged under modules/, outside the app directory, so
it never walks up into the app's node_modules. Bun would then quietly
auto-install the latest version of whatever the shared code imports.
The app's node_modules goes on NODE_PATH after the import paths, so
shared code gets the versions the app pinned.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tower_file_generate still reads pyproject.toml when there is one.
Without it, it reads package.json and writes a bun Towerfile: the name
without its npm scope, and the script from `module` (what `bun init`
writes), `main` or the `start` script, then common entry points. A
`main` that names a build output that doesn't exist yet is skipped.

The workflow help and the skill gain a `bun init -y` step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@migueltheduck
migueltheduck changed the base branch from fix/bash-runtime to develop November 11, 2026 17:56

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants