fix: keep runtime tools internal

Expose only the openclaw command from the default package while keeping bundled runtime tools on the wrapper PATH. Remove the public openclaw-tools package output and document runtime tools as implementation detail.

Tests: nix build .#packages.aarch64-darwin.openclaw .#checks.aarch64-darwin.bin-surface .#packages.x86_64-linux.openclaw .#checks.x86_64-linux.bin-surface --accept-flake-config --no-link --print-out-paths; nix build .#checks.aarch64-darwin.ci --accept-flake-config --no-link --print-out-paths; git diff --check --cached
This commit is contained in:
joshp123 2026-05-05 18:14:08 +02:00
parent 33f8f87571
commit eb9a52bf96
8 changed files with 138 additions and 42 deletions

View File

@ -58,7 +58,7 @@ Git workflow:
OpenClaw packaging:
- The gateway package must include Control UI assets (run `pnpm ui:build` in the Nix build).
- Product intent: ship a working Nix package for OpenClaw users, not just a pin mirror. `openclaw-gateway` is the source-built runnable gateway for Linux and macOS; `openclaw-app` is the Darwin-only desktop app from upstream's signed/notarized app artifact; `openclaw` is the batteries-included bundle.
- User-facing docs should lead with one package: `openclaw`. Treat `openclaw-gateway`, `openclaw-tools`, and `openclaw-app` as advanced/component outputs for checks, modules, and debugging, not separate product tracks.
- User-facing docs should lead with one package: `openclaw`. Treat `openclaw-gateway` and `openclaw-app` as advanced/component outputs for checks, modules, and debugging, not separate product tracks. Runtime tools are internal implementation detail, not a public package surface.
- README should be agent-first: the main setup path is "tell your coding agent you want OpenClaw using Nix, then let it inspect/interview/configure/verify." Manual commands are reference material, not the primary onboarding path.
- Do not split the repo into separate desktop/server tracks. Segment package outputs, keep one simple user-facing flake.
- DJTBOT deployment freshness is downstream and out of scope unless explicitly requested; fix public packaging first.

View File

@ -58,7 +58,7 @@ Bot: *runs whisper, sends you text*
You talk to Telegram, your machine does things.
**One flake, everything works.** Gateway + tools everywhere; macOS app on macOS.
**One flake, everything works.** Gateway everywhere; runtime dependencies bundled; macOS app on macOS.
**Plugins are self-contained.** Each plugin declares its CLI tools in Nix. You enable it, the build and wiring happens automatically.
@ -132,7 +132,7 @@ Repository: github:openclaw/nix-openclaw
What nix-openclaw is:
- Batteries-included Nix package for OpenClaw (AI assistant gateway)
- Installs gateway + tools everywhere; macOS app only on macOS
- Installs the gateway everywhere; macOS app only on macOS
- Runs as a launchd service on macOS, systemd user service on Linux
What I need you to do:
@ -616,26 +616,6 @@ programs.openclaw = {
Plugins are keyed by their declared `name`. If two plugins declare the same name, the **last entry wins** (use this to override a prod plugin with a local dev one).
### Tool overrides (avoid collisions)
Home Manager auto-excludes `git` when `programs.git.enable = true`.
Drop built-in tools that you already install elsewhere:
```nix
programs.openclaw.excludeTools = [ "git" "jq" "ripgrep" ];
```
Or provide a custom list:
```nix
programs.openclaw.toolNames = [ "nodejs_22" "pnpm_10" "summarize" ];
```
If you override `programs.openclaw.package`, use `pkgs.openclawPackages.withTools { ... }.openclaw` to apply these lists.
---
## Packaging & Updates
**Goal:** `nix-openclaw` is a great Nix package. Automation, promotion, and fleet rollout live elsewhere.
@ -655,11 +635,10 @@ Outputs:
```
.#openclaw
.#openclaw-gateway
.#openclaw-tools
.#openclaw-app # Darwin only
```
`.#openclaw-gateway`, `.#openclaw-tools`, and `.#openclaw-app` are component outputs for modules, CI, debugging, and advanced use. Start with `.#openclaw`.
`.#openclaw-gateway` and `.#openclaw-app` are component outputs for modules, CI, debugging, and advanced use. Start with `.#openclaw`.
Pins live in:
- `nix/sources/openclaw-source.nix`
@ -714,9 +693,8 @@ home-manager switch --rollback # revert
| Package | Contents |
| --- | --- |
| `openclaw` (default) | Canonical package. macOS: gateway + app + tools. Linux: gateway + tools. |
| `openclaw` (default) | Canonical package. Exposes `openclaw`; keeps runtime tools internal. macOS also links the app. |
| `openclaw-gateway` | Component output: gateway CLI/service only |
| `openclaw-tools` | Component output: toolchain bundle |
| `openclaw-app` | Component output: macOS app only |
### What we manage vs what you manage
@ -731,10 +709,12 @@ home-manager switch --rollback # revert
| Anthropic API key | | ✓ |
| Chat IDs | | ✓ |
### Included tools
### Runtime tools
> **Platform note:** the toolchain is filtered per platform. macOS-only tools are skipped on Linux.
The default `openclaw` package uses these tools internally and does not expose them as separate user commands.
**Core**: nodejs, pnpm, git, curl, jq, python3, ffmpeg, sox, ripgrep
**Default first-party tools** come from `nix-openclaw-tools`: gogcli (`gog`), goplaces, summarize, camsnap, sonoscli.

View File

@ -75,6 +75,9 @@
let
baseChecks = {
gateway = packageSetStable.openclaw-gateway;
bin-surface = pkgs.callPackage ./nix/checks/openclaw-bin-surface.nix {
openclawPackage = packageSetStable.openclaw;
};
package-contents = pkgs.callPackage ./nix/checks/openclaw-package-contents.nix {
openclawGateway = packageSetStable.openclaw-gateway;
};
@ -114,7 +117,6 @@
paths = [
packageSetStable.openclaw
packageSetStable.openclaw-gateway
packageSetStable.openclaw-tools
]
++ (builtins.attrValues baseChecks);
};

View File

@ -0,0 +1,22 @@
{
lib,
stdenvNoCC,
openclawPackage,
}:
stdenvNoCC.mkDerivation {
pname = "openclaw-bin-surface";
version = lib.getVersion openclawPackage;
dontUnpack = true;
dontConfigure = true;
dontBuild = true;
env = {
OPENCLAW_PACKAGE = openclawPackage;
};
doCheck = true;
checkPhase = "${../scripts/check-openclaw-bin-surface.sh}";
installPhase = "${../scripts/empty-install.sh}";
}

View File

@ -17,11 +17,6 @@ let
pnpmDepsHash = sourceInfo.pnpmDepsHash or null;
};
openclawApp = if isDarwin then pkgs.callPackage ./openclaw-app.nix { } else null;
openclawTools = pkgs.buildEnv {
name = "openclaw-tools";
paths = toolSets.tools;
pathsToLink = [ "/bin" ];
};
openclawBundle = pkgs.callPackage ./openclaw-batteries.nix {
openclaw-gateway = openclawGateway;
openclaw-app = openclawApp;
@ -32,6 +27,5 @@ in
{
openclaw-gateway = openclawGateway;
openclaw = openclawBundle;
openclaw-tools = openclawTools;
}
// (if isDarwin then { openclaw-app = openclawApp; } else { })

View File

@ -1,6 +1,7 @@
{
lib,
buildEnv,
stdenvNoCC,
makeWrapper,
openclaw-gateway,
openclaw-app ? null,
extendedTools ? [ ],
@ -8,20 +9,34 @@
}:
let
appPaths = lib.optional (openclaw-app != null) openclaw-app;
appLinks = lib.optional (openclaw-app != null) "/Applications";
bundleVersion =
if version != null && version != "" then version else lib.getVersion openclaw-gateway;
toolsPath = lib.makeBinPath extendedTools;
in
buildEnv {
name = "openclaw-${bundleVersion}";
paths = [ openclaw-gateway ] ++ appPaths ++ extendedTools;
pathsToLink = [ "/bin" ] ++ appLinks;
stdenvNoCC.mkDerivation {
pname = "openclaw";
version = bundleVersion;
dontUnpack = true;
dontConfigure = true;
dontBuild = true;
nativeBuildInputs = [ makeWrapper ];
env = {
OPENCLAW_APP_PACKAGE = lib.optionalString (openclaw-app != null) "${openclaw-app}";
OPENCLAW_GATEWAY_BIN = "${openclaw-gateway}/bin/openclaw";
OPENCLAW_TOOLS_PATH = toolsPath;
STDENV_SETUP = "${stdenvNoCC}/setup";
};
installPhase = "${../scripts/openclaw-batteries-install.sh}";
meta = with lib; {
description = "OpenClaw batteries-included bundle (gateway + app + tools)";
homepage = "https://github.com/openclaw/openclaw";
license = licenses.mit;
platforms = platforms.darwin ++ platforms.linux;
mainProgram = "openclaw";
};
}

View File

@ -0,0 +1,35 @@
#!/bin/sh
set -eu
if [ -z "${OPENCLAW_PACKAGE:-}" ]; then
echo "OPENCLAW_PACKAGE is not set" >&2
exit 1
fi
bin_dir="${OPENCLAW_PACKAGE}/bin"
openclaw_bin="${bin_dir}/openclaw"
if [ ! -x "$openclaw_bin" ]; then
echo "Missing executable: $openclaw_bin" >&2
exit 1
fi
extra_bins="$(find "$bin_dir" -mindepth 1 -maxdepth 1 -print | while IFS= read -r entry; do
name="$(basename "$entry")"
if [ "$name" != "openclaw" ]; then
printf '%s\n' "$name"
fi
done)"
if [ -n "$extra_bins" ]; then
echo "openclaw package exposes internal runtime tools in bin:" >&2
printf '%s\n' "$extra_bins" >&2
exit 1
fi
if ! grep -q 'PATH' "$openclaw_bin"; then
echo "openclaw wrapper does not set the internal runtime tool PATH" >&2
exit 1
fi
echo "openclaw bin surface: ok"

View File

@ -0,0 +1,48 @@
#!/bin/sh
set -eu
if [ -z "${OPENCLAW_GATEWAY_BIN:-}" ]; then
echo "OPENCLAW_GATEWAY_BIN is not set" >&2
exit 1
fi
if [ ! -x "$OPENCLAW_GATEWAY_BIN" ]; then
echo "OPENCLAW_GATEWAY_BIN is not executable: $OPENCLAW_GATEWAY_BIN" >&2
exit 1
fi
if [ -z "${STDENV_SETUP:-}" ]; then
echo "STDENV_SETUP is not set" >&2
exit 1
fi
if [ ! -f "$STDENV_SETUP" ]; then
echo "STDENV_SETUP not found: $STDENV_SETUP" >&2
exit 1
fi
mkdir -p "$out/bin"
if [ -n "${OPENCLAW_TOOLS_PATH:-}" ]; then
bash -e -c '. "$STDENV_SETUP"; makeWrapper "$OPENCLAW_GATEWAY_BIN" "$out/bin/openclaw" --prefix PATH : "$OPENCLAW_TOOLS_PATH"'
else
bash -e -c '. "$STDENV_SETUP"; makeWrapper "$OPENCLAW_GATEWAY_BIN" "$out/bin/openclaw"'
fi
if [ -n "${OPENCLAW_APP_PACKAGE:-}" ]; then
app_dir="${OPENCLAW_APP_PACKAGE}/Applications"
if [ ! -d "$app_dir" ]; then
echo "OpenClaw app package has no Applications directory: $OPENCLAW_APP_PACKAGE" >&2
exit 1
fi
mkdir -p "$out/Applications"
found_app=0
for app in "$app_dir"/*.app; do
[ -e "$app" ] || continue
ln -s "$app" "$out/Applications/$(basename "$app")"
found_app=1
done
if [ "$found_app" -ne 1 ]; then
echo "OpenClaw app package has no .app under: $app_dir" >&2
exit 1
fi
fi