Pinned, verified launcher
lw bootstrap commits lw.sh, lw.cmd and lw.pin. A clean checkout runs the exact pinned release, with every download checked against the pinned SHA-256. No prior install is needed.
lw bootstrap · lw update
lw turns your CMake, Meson and shell build variants into named, fully resolved profiles, then configures, builds, runs and tests them through one command line. It behaves the same on your laptop as on a CI runner, and it never rewrites your build system.
$ lw init
$ lw project add ./app # type auto-detected (cmake, meson, …)
$ lw configset create Debug app=Debug
$ lw tools # toolchains found on this machine
$ lw profile create Debug ninja-gcc-14
created profile: Debug:ninja-gcc-14.2.0 [local]
$ lw build Debug:ninja-gcc-14 # configures if needed, then builds
$ lw test Debug:ninja-gcc-14 --junit results.xml
$ lw publish # write the shared loomworks.json
CMakePresets.json and CMakeUserPresets.json with full inheritanceToolchains are detected automatically: GCC, Clang, MSVC (via vswhere) and clang-cl, paired with the Ninja or Visual Studio generators. Compilers that detection can't find are declared once with lw sdk add.
You describe what a build variant means across your projects. lw pairs that with a toolchain it found on the machine, producing a profile: a fully resolved, buildable unit you can name in a script, a CI matrix or a teammate's terminal.
Your existing CMake, Meson or shell projects, read as-is.
Debug means Debug for the app and development for the frontend.
Detected per machine: ninja-clang-18, msvc-17, …
Debug:ninja-gcc-14.2.0
one isolated build directory per toolchain
lw build · run · test · clean · reset
Projects and configuration sets are the portable contract. They live in loomworks.json, which you can commit. Profiles pin a toolchain that exists on this machine, so they stay local by default, and each developer or CI cell creates its own from the shared sets.
ninja-clang-18 picks the highest installed 18.x; msvc-17 matches Visual Studio 17 without naming the edition.lw prints why it ran.lw profile set. Builds refuse to run while one is unfilled.{
"projects": {
"MyApp": { "cmake": {} },
"MyLib": { "cmake": {} },
"Frontend": { "typescript": {} }
},
"configuration_sets": {
"Debug": { "MyApp": "Debug", "MyLib": "Debug", "Frontend": "development" },
"Release": { "MyApp": "Release", "MyLib": "Release", "Frontend": "production" }
}
}
Every capability below ships in lw today.
lw bootstrap commits lw.sh, lw.cmd and lw.pin. A clean checkout runs the exact pinned release, with every download checked against the pinned SHA-256. No prior install is needed.
lw bootstrap · lw update
Each release publishes a signed SHA256SUMS, and every binary carries GitHub build provenance recorded in Sigstore's public transparency log. A bundle whose signature or hash doesn't match is never executed.
gh attestation verify · openssl dgst -verify
--no-input (or LW_NO_INPUT / CI) never prompts: a missing value fails with the exact command to run. Results go to stdout, diagnostics to stderr, and exit codes are real.
lw --no-input build <profile>
Ask for one machine-readable fact (build directory, configuration, state, tool, compiler cache or a variable) instead of parsing build logs. The build directory is known before you build.
lw profile query <profile> <project> build-dir
lw reads your CMakeLists.txt, presets and Meson files and drives the build system's own configure and build. It never modifies project files, and collaborators don't need to know it exists.
Keep everything in the gitignored working copy (.nvim/loomworks.user.json), or lw publish a shared loomworks.json for your team and CI. Each item carries an intent, so private and shared settings never mix.
lw publish · --local · --shared
Create a worktree and seed it with the main checkout's config in one step, or pull config into an existing one. The merge is non-destructive and never touches build state.
lw worktree add <branch> · lw pull
ccache or sccache is wired into CMake and Meson builds automatically for GCC and Clang, and on request for MSVC, where lw switches debug info to /Z7 and flags leftover /Zi targets.
lw help cache · lw status --cache-stats
lw health and self-updateActionable, advisory checks for the workspace and the lw release itself. lw self-update verifies, then atomically replaces the bundle and binary, on a stable or unstable channel.
lw health · lw self-update --channel stable
If building one profile would overwrite a binary that another built profile still owns, lw refuses instead of silently clobbering it. --force proceeds and marks the other profile stale.
Build, deploy and launch a target, or run it under valgrind or gdb with its resolved working directory and environment. --print=json reports the exact invocation without running it.
lw run --prefix valgrind · lw run --print=json
CMake, Meson, shell and TypeScript ship inside lw. Platform modules, such as HarmonyOS / OpenHarmony, install on demand, each checked against a pinned SHA-256 and the plugin-interface version.
lw module install harmony
lw on every runner, pinned and verifiedCommit the launcher once. Every matrix cell then fetches the exact pinned release, checks its hash, creates its own profile from the shared configuration sets, and builds by explicit key.
name: build
on: [push, pull_request]
jobs:
build:
strategy:
matrix:
include:
- { os: ubuntu-latest, tool: ninja-gcc }
- { os: windows-latest, tool: msvc-17 }
runs-on: ${{ matrix.os }}
env:
LW_NO_INPUT: "1" # never prompt
PROFILE: Debug:${{ matrix.tool }}
defaults:
run: { shell: bash } # Git Bash on Windows
steps:
- uses: actions/checkout@v4
- if: runner.os == 'Linux'
run: sudo apt-get install -y ninja-build
# lw.sh fetches the pinned lw and verifies its sha256
- run: ./lw.sh profile create Debug ${{ matrix.tool }}
- run: ./lw.sh build "$PROFILE"
- run: ./lw.sh test "$PROFILE" --junit results.xml
- name: Locate the build directory
run: echo "BUILD_DIR=$(./lw.sh profile query "$PROFILE" app build-dir)" >> "$GITHUB_ENV"
- uses: actions/upload-artifact@v4
with:
name: app-${{ matrix.os }}
path: |
${{ env.BUILD_DIR }}
results.xml
./lw.sh (or lw.cmd on Windows) downloads the pinned host binary into .nvim/cache/, verifies its SHA-256 against lw.pin every time, and runs it. The host then provisions the pinned bundle.lw build ignores the active profile and never guesses; you name the profile, or it fails with the exact command to run.lw test --junit writes JUnit XML and exits non-zero when a test fails. lw status --check and lw migrate --check fail the job on diagnostics or outdated workspace files.HTTPS_PROXY; point LOOMWORKS_RELEASE_URL at a local mirror for offline runners. Hash verification is always enforced.$ lw bootstrap # pin this release (or --version x.y.z)
$ git add lw.sh lw.cmd lw.pin
$ lw update # later: move the pin forward
lw bootstrap commits| File | Purpose |
|---|---|
lw.pin | The pinned release version plus the SHA-256 of every host binary and of the release bundle, taken from the release's signed SHA256SUMS after its signature is verified. |
lw.sh | POSIX launcher for Linux, macOS, and Git Bash / MSYS on Windows. |
lw.cmd | Native Windows launcher for cmd and PowerShell. |
A globally installed lw also honours the pin inside a bootstrapped repo, so developers get the pinned behaviour too. Use --no-pin to bypass it.
lw is the product; the editor integration is an optional extra. loomworks.nvim reads the same workspace files, so switching between the terminal, the editor and CI never means maintaining two configurations.
:LoomworksInfo): profiles, build state, diagnostics and running tasks, with build, configure and clean actions.{
"samienne/loomworks.nvim",
event = "VeryLazy",
}
lw installs itself. Download the binary for your platform, verify it with GitHub build provenance, and let the verified binary put itself on your PATH and fetch its first signed bundle. You don't pipe an unread script into a shell, and you don't need admin rights.
No gh? The docs show the release-key signature route using openssl or PowerShell 7.
$ gh release download --repo samienne/loomworks.nvim -p lw-linux-x86_64
$ gh attestation verify lw-linux-x86_64 --repo samienne/loomworks.nvim
$ chmod +x lw-linux-x86_64 && ./lw-linux-x86_64 install -y
$ gh release download --repo samienne/loomworks.nvim -p lw-macos-arm64
$ gh attestation verify lw-macos-arm64 --repo samienne/loomworks.nvim
$ chmod +x lw-macos-arm64 && ./lw-macos-arm64 install -y
> gh release download --repo samienne/loomworks.nvim -p lw-windows-x86_64.exe
> gh attestation verify lw-windows-x86_64.exe --repo samienne/loomworks.nvim
> .\lw-windows-x86_64.exe install -y
Describe your variants once. Build them the same way on any developer machine or CI runner, from one pinned, verified lw.