Add Docker image bundling SAW + OpenClaw - #13
Conversation
Multi-stage build: Rust 1.85 builder compiles SAW from source (supports amd64 + arm64), Node 22 runtime installs OpenClaw from release tarball. Entrypoint handles idempotent key generation, conservative default policy, and SAW daemon lifecycle. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Use the checkbox below for a quick retry:
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds Docker-based deployment for the Secure Agent Wallet (SAW) with OpenClaw: multi-stage Dockerfile, docker-compose service, entrypoint and setup scripts for containerized initialization/onboarding, plus documentation and ignore rules to support the new Docker workflow. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Setup as setup.sh / docker-compose
participant Container as Container
participant Entrypoint as docker-entrypoint.sh
participant Wallet as SAW Wallet
participant Policy as Policy Manager
participant Daemon as SAW Daemon
participant Socket as SAW Socket
participant OpenClaw as OpenClaw Gateway
User->>Setup: start setup / docker-compose up
Setup->>Container: create & run container
Container->>Entrypoint: invoke entrypoint
Entrypoint->>Entrypoint: validate SAW_CHAIN (evm|sol)
Entrypoint->>Wallet: check/generate keys (idempotent)
Entrypoint->>Policy: check/create conservative policy
Entrypoint->>Daemon: start SAW daemon (background)
Daemon->>Socket: create socket
Entrypoint->>Socket: wait for socket ready
Socket-->>Entrypoint: socket available
Entrypoint->>Entrypoint: fix permissions, install traps
alt first-run onboarding
Entrypoint->>OpenClaw: trigger onboarding flow
OpenClaw-->>Entrypoint: onboarding complete
end
Entrypoint->>Daemon: monitor daemon / wait
Setup-->>User: display status, wallet info
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 6✅ Passed checks (6 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
- Replace exec with direct invocation so SAW daemon survives CMD - Only write default policy when file is empty (don't clobber edits) - Use arithmetic expansion instead of (( )) with set -e - docker-compose overrides CMD to daemon-only mode - README: add volume persistence warning, docker logs tip, fix examples - CLAUDE.md: add Docker commands Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Fix all issues with AI agents
In `@docker-compose.yml`:
- Around line 1-20: The saw service will hit a restart loop because the
Dockerfile's default CMD (openclaw onboard --auth-choice x402) exits after
onboarding while the compose restart policy is unless-stopped; update the saw
service in docker-compose to override the container CMD so it runs the SAW
daemon path instead of interactive onboarding—e.g., add a command override (use
an empty command array to hit the entrypoint's wait "$SAW_PID" branch, or use
command: ["sh","-c","exec sleep infinity"] if your Compose version doesn't
support empty arrays) or add a daemon-only flag to the entrypoint so the service
stays running; reference the saw service definition, the Dockerfile default CMD
(openclaw onboard --auth-choice x402) and the entrypoint wait "$SAW_PID" when
making the change.
In `@docker-entrypoint.sh`:
- Around line 10-18: The key file is created by running saw gen-key as root
(key_file / saw gen-key) so if anything fails before the later chown the file
remains root-owned; modify the entrypoint so key generation runs as the non-root
saw user (e.g., invoke saw gen-key via su-exec/gosu/runuser or sudo -u saw) or,
if you must run as root, ensure ownership is fixed unconditionally by adding a
guaranteed cleanup/trap that always chowns "${key_file%/*}" and "$key_file" to
saw:saw (or run chown on the keys directory) even on failure; update the code
paths around saw gen-key, the key_file variable and the later chown to reflect
this change.
- Around line 68-83: The trap `cleanup` is never run when you use `exec "$@"`
because exec replaces the shell leaving no PID 1 to catch signals and clean up
the background SAW process (`SAW_PID`); change the behavior so the shell remains
PID 1: instead of `exec "$@"` spawn the requested command as a foreground child
(e.g., start it without exec and wait for it), ensuring the shell continues to
own the `trap cleanup` and will forward signals and call `cleanup` to kill
`SAW_PID` and wait; alternatively detect if `--init`/tini` is not present and
fail with a clear message referencing `SAW_PID`, `cleanup`, and `SAW_SOCKET` so
users run the container with an init or add tini.
- Around line 46-66: The trap to clean up the background SAW daemon must be
installed immediately after capturing SAW_PID to avoid leaving an orphan if the
socket wait fails; move the trap registration so it runs right after SAW_PID=$!
and ensure it references SAW_PID to kill the background saw-daemon (and
optionally handle TERM/INT/EXIT) so the trap will kill the process if the script
exits before the socket appears (use the same SAW_PID variable and the
saw-daemon process identifier in the trap command).
- Around line 20-36: The current block uses cat > "$policy_file" which
overwrites the whole policy_file and can destroy other wallets; change the logic
around SAW_POLICY_TEMPLATE/SAW_WALLET so that if the file does not exist create
it with the default policy, and if it exists but the wallet entry is missing
append only the wallet stanza (instead of using cat >) or merge the stanza using
a safe YAML tool (e.g., yq) — update the code paths that reference policy_file
and the cat > "$policy_file" to perform an append-or-merge when grep -q "^
${SAW_WALLET}:" fails.
In `@README.md`:
- Around line 92-97: The README's Docker run example is misleading because the
Dockerfile CMD ["openclaw","onboard","--auth-choice","x402"] causes docker run
-d --name saw saw to execute onboarding (not a daemon); either update the README
to show how to run detached without triggering CMD (e.g., run with an explicit
no-op command like sleep infinity or /bin/sh -c 'exec sleep infinity') or modify
the entrypoint to accept a sentinel argument (e.g., "daemon-only") that triggers
the wait "$SAW_PID" branch for true daemon mode; reference the Dockerfile CMD
and the entrypoint's wait "$SAW_PID" logic and add the sentinel handling or the
corrected README example accordingly.
🧹 Nitpick comments (3)
Dockerfile (3)
1-71: Container runs as root — intentional but worth hardening.Trivy flags DS-0002 (no
USERdirective). The entrypoint needs root forchown/chmod, then drops tosawviasu. This is a common pattern, but consider usinggosutoexecas the unprivileged user for the final command, which avoids leaving a root-owned PID 1 parent process and ensures signal forwarding works correctly.At minimum, add a comment in the Dockerfile explaining the root requirement so future maintainers and security scanners have context.
42-51:npm install -gfrom a URL is fragile — consider pinning the checksum.If the tarball content changes at the same URL (re-tagged release, CDN cache inconsistency), the build silently picks up different code. Consider verifying a SHA-256 checksum after download, or at least documenting the expected digest as an
ARG:Sketch
+ARG OPENCLAW_SHA256="" RUN set -eux; \ tarball_url="${OPENCLAW_RELEASE_REPO}/releases/download/${OPENCLAW_REF}/openclaw-${OPENCLAW_REF}.tgz"; \ if curl -fsSL --head --connect-timeout 5 "$tarball_url" >/dev/null 2>&1; then \ echo "==> Installing OpenClaw from release tarball"; \ - npm install -g "$tarball_url"; \ + curl -fsSL -o /tmp/openclaw.tgz "$tarball_url"; \ + if [ -n "$OPENCLAW_SHA256" ]; then \ + echo "$OPENCLAW_SHA256 /tmp/openclaw.tgz" | sha256sum -c -; \ + fi; \ + npm install -g /tmp/openclaw.tgz; \ + rm /tmp/openclaw.tgz; \ else \
8-13: No Cargo dependency caching layer — rebuilds all deps on any source change.Currently
Cargo.toml,Cargo.lock, andcrates/are all copied beforecargo build, so any source edit invalidates the entire dependency build cache. A common optimization is a "dummy build" step that pre-fetches/compiles only dependencies:This is a nice-to-have for faster iteration; not blocking.
| # ── Key generation (idempotent) ─────────────────────────────────────────── | ||
| key_file="${SAW_ROOT}/keys/${SAW_CHAIN}/${SAW_WALLET}.key" | ||
| if [[ ! -f "$key_file" ]]; then | ||
| echo "==> SAW: generating key (chain=${SAW_CHAIN}, wallet=${SAW_WALLET})" | ||
| saw gen-key --chain "$SAW_CHAIN" --wallet "$SAW_WALLET" --root "$SAW_ROOT" | ||
| echo "" | ||
| echo " IMPORTANT: Fund this wallet before using x402 payments." | ||
| echo "" | ||
| fi |
There was a problem hiding this comment.
Key generation runs as root — resulting key file will be owned by root until line 39.
saw gen-key on line 14 executes as root (the entrypoint user). The key file is created with root ownership and only later chown'd to saw on line 39. If saw gen-key or any step between lines 14-38 fails, the key file remains root-owned inside the saw user's data directory, which could cause permission errors on subsequent runs.
Consider running key generation as the saw user, or at minimum ensure the ownership fix on line 39 can't be skipped.
🤖 Prompt for AI Agents
In `@docker-entrypoint.sh` around lines 10 - 18, The key file is created by
running saw gen-key as root (key_file / saw gen-key) so if anything fails before
the later chown the file remains root-owned; modify the entrypoint so key
generation runs as the non-root saw user (e.g., invoke saw gen-key via
su-exec/gosu/runuser or sudo -u saw) or, if you must run as root, ensure
ownership is fixed unconditionally by adding a guaranteed cleanup/trap that
always chowns "${key_file%/*}" and "$key_file" to saw:saw (or run chown on the
keys directory) even on failure; update the code paths around saw gen-key, the
key_file variable and the later chown to reflect this change.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@docker-entrypoint.sh`:
- Around line 20-38: The current guard uses grep '^wallets:$' which still
matches a wallets: header even when child wallet entries exist, risking
overwrite; update the condition around policy_file (used with
SAW_POLICY_TEMPLATE) to only write the default policy when the file is
missing/empty or when the specific wallet key for ${SAW_WALLET} is absent —
e.g., replace the broad "^wallets:$" check with a test that fails if an indented
child key exists under wallets or, more simply, use grep to look for the exact
wallet entry pattern like "^[[:space:]]{2}${SAW_WALLET}:" and only create the
file if that specific wallet key is not found (reference symbols: policy_file,
SAW_WALLET, SAW_POLICY_TEMPLATE).
Move trap registration before socket wait so the daemon process is cleaned up even if the socket never appears. Fix grep pattern to check for indented wallet entries rather than matching populated policy files, preventing overwrites on restart. Addresses CodeRabbit review feedback on PR #13. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Default CMD now runs `openclaw gateway` instead of interactive onboard - Add .env.example with gateway token, bind, port configuration - Add openclaw-data volume for persistent OpenClaw state - Expose port 18789 (gateway default) instead of 3000 - Bind to loopback only in compose; access via SSH tunnel - Add HOME/XDG_CONFIG_HOME so OpenClaw writes to /home/node/.openclaw - Add .env to .gitignore and .dockerignore Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In `@docker-compose.yml`:
- Around line 8-9: The docker-compose config currently requires env_file: - .env
which will cause docker compose to fail for fresh clones without a .env; update
the compose file to make the env_file optional by using the newer syntax
env_file: - { file: .env, required: false } (Compose ≥ 2.24) or alternatively
add a small bootstrapping step in the repository (e.g., in the entrypoint script
or Makefile) that checks for .env and copies .env.example → .env if missing;
modify the docker-compose.yml's env_file entry or add the entrypoint/Makefile
check so new users can run docker compose up without manually creating .env.
In `@Dockerfile`:
- Line 78: The CMD currently hardcodes "--bind lan --port 18789" which ignores
the environment variables OPENCLAW_GATEWAY_BIND and OPENCLAW_GATEWAY_PORT;
update the Dockerfile CMD that runs "openclaw gateway" to reference those env
vars (e.g., switch to shell form or an exec form that invokes a shell) so the
process uses $OPENCLAW_GATEWAY_BIND and $OPENCLAW_GATEWAY_PORT at runtime;
ensure the CMD still includes the other flags like "--allow-unconfigured" and
"--bind/--port" placeholders are replaced with the env var references.
- Around line 26-30: Remove the OPENCLAW_GATEWAY_TOKEN from the Dockerfile ENV
block (the line containing OPENCLAW_GATEWAY_TOKEN="") so the secret name isn't
baked into the image layers; rely on runtime injection (docker run -e / compose
environment) which your entrypoint/compose already provides, and verify any code
that reads OPENCLAW_GATEWAY_TOKEN handles it being unset (no implicit default)
to avoid regressions.
- Around line 60-67: The Dockerfile leaves the main CMD (openclaw gateway)
running as root; to fix, ensure the container switches to a non-root user before
exec-ing the gateway: either add a USER directive (e.g., set to the 'saw' or
'node' user created earlier) after all root-only setup steps, or update the
entrypoint script so it execs the final command as a non-root user (use gosu or
su-exec to run the "openclaw gateway" process as saw/node, e.g., replace the
current CMD exec path with an exec gouru/su-exec call to drop privileges).
Reference the created system users/groups ('saw', 'node') and the main process
name ("openclaw gateway") and ensure the chosen approach runs PID 1 as that
non-root user.
🧹 Nitpick comments (2)
Dockerfile (1)
30-30:XDG_CONFIG_HOMEpoints to an app-specific path instead of the standard~/.config.
XDG_CONFIG_HOMEis a freedesktop standard that all XDG-aware applications use as their config root. Setting it to/home/node/.openclawmeans every tool in the container (git, npm, etc.) that respects XDG will also write config there, polluting the OpenClaw data volume.If the intent is to control where OpenClaw stores its config, consider a tool-specific env var or leave
XDG_CONFIG_HOMEat the conventional$HOME/.configand configure the volume mount accordingly.docker-compose.yml (1)
20-23: Host port is parameterized but container port is hardcoded — they'll diverge if the env var changes.
${OPENCLAW_GATEWAY_PORT:-18789}:18789means the host port follows the env var but the container port is always 18789. If a user setsOPENCLAW_GATEWAY_PORT=9999expecting the gateway to listen on 9999, only the host mapping changes — the gateway process inside still binds to 18789 (given the current hardcoded CMD). This creates a confusing asymmetry.This is consistent today because the Dockerfile CMD also hardcodes 18789, but if that's fixed to use
$OPENCLAW_GATEWAY_PORT(as suggested in the Dockerfile review), update the container-side port mapping too:- - "127.0.0.1:${OPENCLAW_GATEWAY_PORT:-18789}:18789" + - "127.0.0.1:${OPENCLAW_GATEWAY_PORT:-18789}:${OPENCLAW_GATEWAY_PORT:-18789}"
| CMD test -S "$SAW_SOCKET" || exit 1 | ||
|
|
||
| ENTRYPOINT ["docker-entrypoint.sh"] | ||
| CMD ["openclaw", "gateway", "--bind", "lan", "--port", "18789", "--allow-unconfigured"] |
There was a problem hiding this comment.
CMD hardcodes --bind lan --port 18789, ignoring the env vars defined above.
OPENCLAW_GATEWAY_BIND and OPENCLAW_GATEWAY_PORT are set in the ENV block and can be overridden at runtime, but the CMD uses literal values. A user changing the env vars would get no effect on the gateway's actual bind/port.
Switch to shell-form or reference the variables:
Proposed fix
-CMD ["openclaw", "gateway", "--bind", "lan", "--port", "18789", "--allow-unconfigured"]
+CMD ["sh", "-c", "exec openclaw gateway --bind \"$OPENCLAW_GATEWAY_BIND\" --port \"$OPENCLAW_GATEWAY_PORT\" --allow-unconfigured"]📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| CMD ["openclaw", "gateway", "--bind", "lan", "--port", "18789", "--allow-unconfigured"] | |
| CMD ["sh", "-c", "exec openclaw gateway --bind \"$OPENCLAW_GATEWAY_BIND\" --port \"$OPENCLAW_GATEWAY_PORT\" --allow-unconfigured"] |
🤖 Prompt for AI Agents
In `@Dockerfile` at line 78, The CMD currently hardcodes "--bind lan --port 18789"
which ignores the environment variables OPENCLAW_GATEWAY_BIND and
OPENCLAW_GATEWAY_PORT; update the Dockerfile CMD that runs "openclaw gateway" to
reference those env vars (e.g., switch to shell form or an exec form that
invokes a shell) so the process uses $OPENCLAW_GATEWAY_BIND and
$OPENCLAW_GATEWAY_PORT at runtime; ensure the CMD still includes the other flags
like "--allow-unconfigured" and "--bind/--port" placeholders are replaced with
the env var references.
- Reject placeholder/empty OPENCLAW_GATEWAY_TOKEN on non-loopback bind - Propagate foreground command exit code (prevents silent death with restart: unless-stopped) - Validate SAW_CHAIN is evm or sol before key generation - Verify daemon is alive immediately after spawn (fail-fast on crash) - Verify openclaw install with --version during Docker build - Fix CLAUDE.md Docker examples to match gateway mode - Use explicit file existence checks instead of || true for chmod Addresses review feedback from code-reviewer, silent-failure-hunter, and comment-analyzer agents. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Drop to node user for gateway and openclaw commands (not root) - Add node to saw-agent group for SAW socket access - Remove redundant .env.example and OpenClaw env vars - Add setup.sh for first-time onboarding flow - Rewrite Docker docs: first-time setup, stop/start, helpful notes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@docker-entrypoint.sh`:
- Around line 138-139: The script currently masks the foreground command's exit
status because `wait "$CMD_PID" || true` forces a zero exit code; remove the `||
true` so `wait "$CMD_PID"` returns the actual command status and enable `set -e`
at the top of the script (or just before launching the background task) so the
script will exit with the waited process's non-zero code; keep the existing
`EXIT` trap (and any cleanup logic) intact so cleanup runs on exit.
In `@README.md`:
- Line 42: The link fragment "#docker" is broken because the text "**Docker
(recommended)** — bundles SAW + OpenClaw gateway..." is bold text, not a
heading/anchor; update the README by converting that bold line into a proper
heading (e.g., add "## Docker" or "### Docker" above or replace the bold text)
or add an explicit HTML anchor/id near that section so the fragment "#docker"
resolves; locate the bold fragment line in README.md (the line containing
"**Docker (recommended)** — bundles SAW + OpenClaw gateway...") and apply the
change, ensuring the anchor text matches "#docker".
🧹 Nitpick comments (1)
README.md (1)
126-137: Duplicate "remote access" content.Lines 130 and 132–137 both describe the same SSH tunnel command. Consider removing one.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@docker-entrypoint.sh`:
- Around line 99-129: The hardcoded exit 0 after the "waiting for onboarding"
path hides a non-zero exit from wait "$SAW_PID"; capture the wait return code
and exit with it instead (e.g., rc=$?; exit $rc) so orchestrators see a failure,
and ensure SAW_PID is defined before calling wait to avoid silent errors; update
the block that calls wait "$SAW_PID" to record the wait status and use that
status as the script exit code rather than a fixed 0.
In `@README.md`:
- Around line 44-47: The curl install command uses a branch-pinned URL
containing "sync-openclaw-main-2026-02-11" which will 404 if that branch is
deleted; update the URL in the README's install command to point to a stable ref
(e.g., replace the branch name with "main" or a tagged release) so the curl
command remains valid (the command to update is the curl | bash line that
currently references sync-openclaw-main-2026-02-11).
🧹 Nitpick comments (3)
docker-entrypoint.sh (1)
29-45: Policy idempotency: changingSAW_WALLETacross restarts won't add the new wallet.The guard on line 32 checks for any wallet entry (
^ [a-zA-Z0-9_-]\+:). If a policy file already has a wallet configured, a restart with a differentSAW_WALLETvalue silently skips writing the new wallet's policy. This is a known limitation from prior reviews — acceptable for the initial Docker use case (single wallet), but worth a brief inline comment so future maintainers don't assume multi-wallet support.Add a clarifying comment
if [[ "$SAW_POLICY_TEMPLATE" != "none" ]]; then - if [[ ! -s "$policy_file" ]] || ! grep -q "^ [a-zA-Z0-9_-]\+:" "$policy_file" 2>/dev/null; then + # NOTE: Only writes the default policy if no wallet entries exist at all. + # Changing SAW_WALLET on an existing file won't add the new wallet automatically. + if [[ ! -s "$policy_file" ]] || ! grep -q "^ [a-zA-Z0-9_-]\+:" "$policy_file" 2>/dev/null; then echo "==> SAW: writing conservative default policy"README.md (2)
104-109: Simplify the container exec command using-uflag.
docker compose exec -it saw su -s /bin/bash nodecan be simplified with Docker's built-in user flag, which is more idiomatic and avoids an extrasulayer.Proposed simplification
-docker compose exec -it saw su -s /bin/bash node +docker compose exec -it -u node saw bash
126-137: Remote access is mentioned twice — lines 130 and 132‑137 duplicate the same SSH tunnel command.Consider consolidating into a single block to avoid drift.
| # ── OpenClaw first-run detection ───────────────────────────────────────── | ||
| OPENCLAW_CONFIG="${OPENCLAW_DIR}/openclaw.json" | ||
| export SAW_SOCKET | ||
| if [[ "${1:-}" == "openclaw" && ! -f "$OPENCLAW_CONFIG" ]]; then | ||
| if [[ "${2:-}" == "onboard" ]]; then | ||
| # User explicitly running onboard — let it through below | ||
| : | ||
| elif [[ -t 0 ]]; then | ||
| echo "==> OpenClaw: first run detected, running onboard..." | ||
| su -s /bin/bash node -c "SAW_SOCKET='$SAW_SOCKET' openclaw onboard --auth-choice x402" | ||
| else | ||
| echo "" | ||
| echo "============================================" | ||
| echo " OpenClaw: first-run setup required" | ||
| echo "============================================" | ||
| echo "" | ||
| echo " Run onboarding (interactive, one-time):" | ||
| echo "" | ||
| echo " docker compose exec -it saw openclaw onboard --auth-choice x402" | ||
| echo "" | ||
| echo " Then restart the container:" | ||
| echo "" | ||
| echo " docker compose restart" | ||
| echo "" | ||
| echo "============================================" | ||
| echo "" | ||
| echo "==> SAW daemon running. Waiting for onboarding..." | ||
| wait "$SAW_PID" | ||
| exit 0 | ||
| fi | ||
| fi |
There was a problem hiding this comment.
Hardcoded exit 0 on line 127 masks a daemon crash in the "waiting for onboarding" path.
If the SAW daemon crashes while waiting for the user to complete onboarding via docker compose exec, wait "$SAW_PID" returns non-zero but the script exits 0, hiding the failure from orchestrators.
Proposed fix
echo "==> SAW daemon running. Waiting for onboarding..."
wait "$SAW_PID"
- exit 0
+ exit $?🤖 Prompt for AI Agents
In `@docker-entrypoint.sh` around lines 99 - 129, The hardcoded exit 0 after the
"waiting for onboarding" path hides a non-zero exit from wait "$SAW_PID";
capture the wait return code and exit with it instead (e.g., rc=$?; exit $rc) so
orchestrators see a failure, and ensure SAW_PID is defined before calling wait
to avoid silent errors; update the block that calls wait "$SAW_PID" to record
the wait status and use that status as the script exit code rather than a fixed
0.
| **Bare-metal (SAW + OpenClaw)** — installs prebuilt SAW binaries, OpenClaw via npm, and runs onboarding. Works on macOS and Linux: | ||
| ```bash | ||
| curl -sSL https://raw.githubusercontent.com/daydreamsai/agent-wallet/master/install.sh | sh | ||
| curl -fsSL https://raw.githubusercontent.com/RedBeardEth/clawdbot/sync-openclaw-main-2026-02-11/scripts/install-openclaw-fork.sh | bash | ||
| ``` |
There was a problem hiding this comment.
Branch-pinned URL in the bare-metal install command will break when the branch is deleted.
The URL on line 46 points to a specific branch (sync-openclaw-main-2026-02-11). Once that branch is merged or removed, this curl command will 404. Consider pointing to main or a tagged release.
🤖 Prompt for AI Agents
In `@README.md` around lines 44 - 47, The curl install command uses a
branch-pinned URL containing "sync-openclaw-main-2026-02-11" which will 404 if
that branch is deleted; update the URL in the README's install command to point
to a stable ref (e.g., replace the branch name with "main" or a tagged release)
so the curl command remains valid (the command to update is the curl | bash line
that currently references sync-openclaw-main-2026-02-11).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move reference material (policy schema, API examples, security, production deployment, contributing) into docs/ so the README fits in one viewport. No content lost — just reorganized. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
No clone, no cargo, no repo needed. Users run: curl -sSL .../setup.sh | bash Supports SAW_IMAGE override for dev/testing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prevents script exit when exec fails due to set -euo pipefail. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When run via curl|bash, stdin is not a TTY, so interactive onboarding fails. Now prints manual instructions instead. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
curl|bash now completes fully without manual intervention. Uses --non-interactive with x402 defaults, skips channels. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
openclaw onboard --auth-choice x402for interactive setupTest plan
docker build --no-cachesucceeds/run/saw/saw.sock0660 saw:saw-agent, key files0600openclawinstalled and responds (v2026.2.9)Closes #12
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation
Chores