Skip to content

feat(control-plane): add extra software step with mise-based runtime installs#2

Open
zackerydev wants to merge 2 commits intomainfrom
codex/extra-software-step3-mise
Open

feat(control-plane): add extra software step with mise-based runtime installs#2
zackerydev wants to merge 2 commits intomainfrom
codex/extra-software-step3-mise

Conversation

@zackerydev
Copy link
Owner

@zackerydev zackerydev commented Feb 28, 2026

What

Add a third install-wizard step for "Extra Software" that accepts raw .tool-versions, installs mise in OpenClaw/IronClaw/PicoClaw images, and runs startup mise install (non-fatal) with cache on persistent bot storage.

Why

Operators need a supported way to add extra CLI tools to bot runtimes without building custom images.

Linear issue: not provided (requested directly).

Scope

  • control-plane/internal/routes.go, control-plane/internal/handler/helm.go
  • control-plane/templates/pages/bot-form-infra.html
  • control-plane/templates/pages/bot-form-config.html
  • control-plane/templates/pages/bot-form-software.html
  • control-plane/charts/{openclaw,ironclaw,picoclaw}/values.yaml
  • control-plane/charts/{openclaw,ironclaw,picoclaw}/templates/startup-configmap.yaml
  • control-plane/charts/openclaw/templates/deployment.yaml (rollout checksums)
  • control-plane/charts/picoclaw/templates/deployment.yaml (startup wiring)
  • docker/{openclaw,ironclaw,picoclaw}/Dockerfile
  • control-plane/e2e/openclaw_extra_software_test.go
  • control-plane/e2e/openclaw_lifecycle_test.go
  • docs updates in docs/content/docs/* and docs/content/tutorials/*

How To Validate

  • mise run test:all -> pass
  • mise run vet -> pass
  • mise run lint -> pass
  • mise run fix -> pass
  • mise run docs:check -> pass
  • source ~/GitHub/zackerydev/.env && export OP_CREDENTIALS_FILE=$HOME/GitHub/zackerydev/1password-credentials.json && .config/scripts/e2e-run.sh -> pass (includes new OpenClaw extra-software E2E)
  • .config/scripts/e2e-teardown.sh -> pass

Required

  • mise run test:all
  • mise run vet
  • mise run lint
  • mise run fix
  • mise run docs:check (if docs or user-facing behavior changed)

Optional / When Relevant

  • mise run e2e:setup && mise run e2e:run (lifecycle/kind changes)
  • mise run e2e:teardown or mise run e2e:cleanup after lifecycle tests

Evidence

  • TestOpenClawExtraSoftwareInstallsClaude:
    • openclaw pod ready: e2e-openclaw-mise-...
    • claude binary found: /root/.local/share/mise/installs/claude/2.1.62/claude
  • TestOpenClawLifecycle Step8/Step10 now pass after model fixture + rollout checksum fixes.
  • Final lifecycle run:
    • PASS
    • ok github.com/zackerydev/clawmachine/control-plane/e2e ...

Checklist

  • Tests added/updated
  • Routes/CLI/docs updated together when contract changed
  • No stale terminology introduced
  • Local validation run (not just compile)

Copilot AI review requested due to automatic review settings February 28, 2026 00:54
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds an “Extra Software” third step to the bot install wizard so operators can provide .tool-versions content that is applied at runtime and triggers a (non-fatal) mise install on bot startup across OpenClaw/IronClaw/PicoClaw.

Changes:

  • Add /bots/new/software wizard step + UI template, route, handler logic, and unit tests.
  • Add extraSoftware.toolVersions Helm values and startup-script logic to write .tool-versions and run mise install.
  • Install mise in runtime images; update docs and E2E coverage for the new flow.

Reviewed changes

Copilot reviewed 26 out of 26 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
docs/content/tutorials/deploy-first-bot.md Updates tutorial to reflect 3-step wizard and extra-software step.
docs/content/docs/getting-started.md Updates getting-started steps to include optional extra-software step.
docs/content/docs/docs-parity-matrix.md Adds /bots/new/software to docs parity matrix.
docs/content/docs/cli.md Documents the new wizard route in CLI docs.
docs/content/docs/bots.md Updates install flow docs to include extra-software step and behavior.
docker/picoclaw/Dockerfile Installs mise in PicoClaw runtime image.
docker/openclaw/Dockerfile Installs mise in OpenClaw runtime image.
docker/ironclaw/Dockerfile Installs mise in IronClaw runtime image.
control-plane/templates/pages/bot-form-software.html New step-3 page to capture .tool-versions input and submit install.
control-plane/templates/pages/bot-form-infra.html Updates wizard step count and carries extraToolVersions forward via hidden field.
control-plane/templates/pages/bot-form-config.html Updates wizard step count and routes “Next” to the new software step.
control-plane/internal/routes_test.go Ensures new /bots/new/software route is registered.
control-plane/internal/routes.go Registers new POST route for wizard step 3.
control-plane/internal/handler/helm_test.go Adds unit tests for rendering step 3 and for parsing/installing extra software values.
control-plane/internal/handler/helm.go Adds handler + renderer for step 3; maps extraToolVersions into Helm extraSoftware.toolVersions.
control-plane/e2e/openclaw_lifecycle_test.go Adjusts lifecycle fixture model value to match current expected runtime config.
control-plane/e2e/openclaw_extra_software_test.go New E2E validating .tool-versions persistence and a tool installed via mise.
control-plane/charts/picoclaw/values.yaml Adds extraSoftware.toolVersions chart value.
control-plane/charts/picoclaw/templates/startup-configmap.yaml Adds startup logic to write .tool-versions and run mise install.
control-plane/charts/picoclaw/templates/deployment.yaml Wires PicoClaw to run the startup script via command/args.
control-plane/charts/openclaw/values.yaml Adds extraSoftware.toolVersions chart value.
control-plane/charts/openclaw/templates/startup-configmap.yaml Adds startup logic for .tool-versions + mise install (and tweaks configFile heredoc).
control-plane/charts/openclaw/templates/deployment.yaml Adds rollout checksum annotations for config/startup ConfigMaps.
control-plane/charts/ironclaw/values.yaml Adds extraSoftware.toolVersions chart value.
control-plane/charts/ironclaw/templates/startup-configmap.yaml Adds startup logic to write .tool-versions and run mise install.
.config/scripts/e2e-run.sh Includes the new extra-software E2E test in the runner regex.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +18 to +20
RUN MISE_VERSION=${MISE_VERSION} MISE_INSTALL_PATH=/usr/local/bin/mise MISE_INSTALL_HELP=0 \
sh -c "$(curl -fsSL https://mise.run)" \
&& /usr/local/bin/mise --version
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

The image installs mise by piping a remote script from https://mise.run directly into sh. This is a supply-chain risk (no checksum/signature verification) and makes builds non-reproducible if the installer changes. Prefer downloading a specific release artifact and verifying its checksum/signature (or installing from a trusted package repository), then placing the binary in /usr/local/bin.

Suggested change
RUN MISE_VERSION=${MISE_VERSION} MISE_INSTALL_PATH=/usr/local/bin/mise MISE_INSTALL_HELP=0 \
sh -c "$(curl -fsSL https://mise.run)" \
&& /usr/local/bin/mise --version
RUN set -eux; \
arch="$(uname -m)"; \
case "${arch}" in \
x86_64) mise_arch="x64" ;; \
*) echo "Unsupported architecture: ${arch}" >&2; exit 1 ;; \
esac; \
mise_url="https://github.com/jdx/mise/releases/download/${MISE_VERSION}/mise-${MISE_VERSION}-linux-${mise_arch}"; \
mise_sha_url="${mise_url}.sha256"; \
curl -fsSL "${mise_url}" -o /tmp/mise; \
curl -fsSL "${mise_sha_url}" -o /tmp/mise.sha256; \
(cd /tmp && sha256sum -c mise.sha256); \
install -m 0755 /tmp/mise /usr/local/bin/mise; \
rm -f /tmp/mise /tmp/mise.sha256; \
/usr/local/bin/mise --version

Copilot uses AI. Check for mistakes.
Comment on lines +15 to +18
RUN apk add --no-cache ca-certificates tzdata wget

RUN MISE_VERSION=${MISE_VERSION} MISE_INSTALL_PATH=/usr/local/bin/mise MISE_INSTALL_HELP=0 \
sh -c "$(wget -qO- https://mise.run)" \
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

This Dockerfile installs mise by piping a remote script from https://mise.run into sh with no checksum/signature verification. That’s a supply-chain risk and can make builds non-reproducible if the installer content changes. Prefer downloading a pinned release artifact and verifying its checksum/signature (or using an Alpine package if available) before installing to /usr/local/bin.

Suggested change
RUN apk add --no-cache ca-certificates tzdata wget
RUN MISE_VERSION=${MISE_VERSION} MISE_INSTALL_PATH=/usr/local/bin/mise MISE_INSTALL_HELP=0 \
sh -c "$(wget -qO- https://mise.run)" \
ARG MISE_INSTALL_SHA256
RUN apk add --no-cache ca-certificates tzdata wget
RUN wget -qO /tmp/mise-installer https://mise.run \
&& echo "${MISE_INSTALL_SHA256} /tmp/mise-installer" | sha256sum -c - \
&& chmod +x /tmp/mise-installer \
&& MISE_VERSION="${MISE_VERSION}" MISE_INSTALL_PATH=/usr/local/bin/mise MISE_INSTALL_HELP=0 \
sh /tmp/mise-installer \
&& rm /tmp/mise-installer \

Copilot uses AI. Check for mistakes.
Comment on lines +99 to 101
command: ["/bin/sh", "/scripts/start-picoclaw.sh"]
args: ["gateway"]
ports:
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

picoclaw now runs a startup script as the container command, and that script may run mise install synchronously before the HTTP server starts when extraSoftware.toolVersions is set. With the current liveness/readiness probes (no startupProbe here and a short initialDelaySeconds in values), longer installs can cause repeated probe failures and container restarts. Consider adding a startupProbe (like ironclaw) and/or increasing liveness/readiness thresholds, or running the mise install step asynchronously/with a timeout.

Copilot uses AI. Check for mistakes.
Comment on lines 33 to 37
echo "Applying managed configFile.content to $CONFIG_FILE"
cat >"$CONFIG_FILE" <<'CLAWMACHINE_OPENCLAW_CONFIG'
{{ .Values.configFile.content | nindent 4 }}
CLAWMACHINE_OPENCLAW_CONFIG
CLAWMACHINE_OPENCLAW_CONFIG
{{- end }}
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

The heredoc terminator is indented ( CLAWMACHINE_OPENCLAW_CONFIG). In POSIX shells the terminator must match exactly at the start of the line (unless using <<- with tabs). With the current indentation the heredoc won’t close, breaking the startup script when configFile is enabled. Align the terminator to column 0 in the rendered script (e.g., remove the extra spaces, or switch to <<- + tabs consistently).

Copilot uses AI. Check for mistakes.
Comment on lines +32 to +34
cat >"$TOOL_VERSIONS_FILE" <<'CLAWMACHINE_TOOL_VERSIONS'
{{ .Values.extraSoftware.toolVersions | nindent 4 }}
CLAWMACHINE_TOOL_VERSIONS
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

The .tool-versions heredoc terminator ( CLAWMACHINE_TOOL_VERSIONS) is indented. In sh, heredoc terminators must match exactly at the start of the line (unless using <<- with tabs), so the heredoc won’t close and the startup script will fail when extraSoftware.toolVersions is set. Remove the extra indentation or change to <<- with tab-indented terminators.

Suggested change
cat >"$TOOL_VERSIONS_FILE" <<'CLAWMACHINE_TOOL_VERSIONS'
{{ .Values.extraSoftware.toolVersions | nindent 4 }}
CLAWMACHINE_TOOL_VERSIONS
cat >"$TOOL_VERSIONS_FILE" <<-'CLAWMACHINE_TOOL_VERSIONS'
{{ .Values.extraSoftware.toolVersions | nindent 4 }}
CLAWMACHINE_TOOL_VERSIONS

Copilot uses AI. Check for mistakes.
Comment on lines +31 to +36
echo "Applying extra software tools from $TOOL_VERSIONS_FILE"
cat >"$TOOL_VERSIONS_FILE" <<'CLAWMACHINE_TOOL_VERSIONS'
{{ .Values.extraSoftware.toolVersions | nindent 4 }}
CLAWMACHINE_TOOL_VERSIONS
sed -i 's/^ //' "$TOOL_VERSIONS_FILE"

Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

The .tool-versions heredoc terminator ( CLAWMACHINE_TOOL_VERSIONS) is indented. Heredoc terminators must be at the start of the line in sh (unless using <<- with tabs), so this will prevent the heredoc from closing and break startup whenever extraSoftware.toolVersions is set. Remove the extra indentation or use <<- with tab-indented terminators.

Copilot uses AI. Check for mistakes.
Comment on lines 31 to +36
ca-certificates tzdata wget postgresql-client \
&& rm -rf /var/lib/apt/lists/*

RUN MISE_VERSION=${MISE_VERSION} MISE_INSTALL_PATH=/usr/local/bin/mise MISE_INSTALL_HELP=0 \
sh -c "$(wget -qO- https://mise.run)" \
&& /usr/local/bin/mise --version
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

The Docker build installs mise by executing a script fetched from https://mise.run without any checksum/signature verification. This introduces a supply-chain risk and can break reproducible builds if the installer changes. Prefer downloading a pinned release binary and verifying a published checksum/signature (or use a distro package) before installing it into /usr/local/bin.

Suggested change
ca-certificates tzdata wget postgresql-client \
&& rm -rf /var/lib/apt/lists/*
RUN MISE_VERSION=${MISE_VERSION} MISE_INSTALL_PATH=/usr/local/bin/mise MISE_INSTALL_HELP=0 \
sh -c "$(wget -qO- https://mise.run)" \
&& /usr/local/bin/mise --version
ca-certificates tzdata wget postgresql-client xz-utils \
&& rm -rf /var/lib/apt/lists/*
# Install mise from a pinned release binary with checksum verification
RUN set -e; \
arch="$(dpkg --print-architecture)"; \
case "$arch" in \
amd64) mise_arch="x64" ;; \
arm64) mise_arch="aarch64" ;; \
*) echo "Unsupported architecture for mise: $arch" >&2; exit 1 ;; \
esac; \
mise_version="${MISE_VERSION}"; \
base_url="https://github.com/jdx/mise/releases/download/${mise_version}"; \
tarball="mise-${mise_version}-linux-${mise_arch}.tar.xz"; \
wget -q "${base_url}/${tarball}" -O "/tmp/${tarball}"; \
wget -q "${base_url}/${tarball}.sha256" -O "/tmp/${tarball}.sha256"; \
(cd /tmp && sha256sum -c "${tarball}.sha256"); \
mkdir -p /tmp/mise; \
tar -xJf "/tmp/${tarball}" -C /tmp/mise; \
install -m 0755 /tmp/mise/bin/mise /usr/local/bin/mise; \
rm -rf /tmp/mise "/tmp/${tarball}" "/tmp/${tarball}.sha256"; \
/usr/local/bin/mise --version

Copilot uses AI. Check for mistakes.
h.renderInstallConfigPage(w, r, botType, allFormValues(r))
}

// NewSoftwarePage renders step 3 after validating step 2.
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

The doc comment says this handler renders step 3 "after validating step 2", but the implementation only parses the form and validates releaseName (same as step 1 validation). Either update the comment to match what is actually validated, or add the missing step-2 validations if they are required before proceeding.

Suggested change
// NewSoftwarePage renders step 3 after validating step 2.
// NewSoftwarePage renders step 3 after validating the release name.

Copilot uses AI. Check for mistakes.
echo "Applying extra software tools from $TOOL_VERSIONS_FILE"
cat >"$TOOL_VERSIONS_FILE" <<'CLAWMACHINE_TOOL_VERSIONS'
{{ .Values.extraSoftware.toolVersions | nindent 4 }}
CLAWMACHINE_TOOL_VERSIONS
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

The .tool-versions heredoc terminator is indented ( CLAWMACHINE_TOOL_VERSIONS). Heredoc terminators must appear at the beginning of the line (unless using <<- with tabs), so this will prevent the heredoc from closing and break startup whenever extraSoftware.toolVersions is set. Remove the extra indentation (or use <<- + tabs) so the terminator matches correctly.

Suggested change
CLAWMACHINE_TOOL_VERSIONS
CLAWMACHINE_TOOL_VERSIONS

Copilot uses AI. Check for mistakes.
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