Skip to content

Commit 2a6002d

Browse files
azdolinskiclaude
andcommitted
Release 0.8.0 - OpenClaw AI Gateway integration
Added: - OpenClaw AI Gateway integration via INSTALL_OPENCLAW - init-devcoder-openclaw service for npm installation - svc-devcoder-openclaw service for running gateway - ENV vars: OPENCLAW_PORT, OPENCLAW_BIND, OPENCLAW_TOKEN, OPENCLAW_PASSWORD, OPENCLAW_VERBOSE Fixed: - NVM PATH detection for OpenClaw across Node.js versions - PUID/PGID based user detection instead of CUSTOM_USER - openclaw filtered from INSTALL_NPM_PACKAGES to prevent conflicts Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent ca1a49c commit 2a6002d

16 files changed

Lines changed: 333 additions & 2 deletions

File tree

CHANGELOG.md

100644100755
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,27 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.8.0] - 2026-02-19
9+
10+
### Added 🆕
11+
- 🤖 **OpenClaw AI Gateway integration**: New dedicated init and svc components
12+
- Added `INSTALL_OPENCLAW` ENV to enable OpenClaw installation via npm
13+
- Added `OPENCLAW_PORT`, `OPENCLAW_BIND`, `OPENCLAW_TOKEN`, `OPENCLAW_PASSWORD`, `OPENCLAW_VERBOSE` configuration options
14+
- Added `init-devcoder-openclaw` service for installing openclaw@latest globally
15+
- Added `svc-devcoder-openclaw` service for running the OpenClaw gateway
16+
- OpenClaw automatically detects NVM Node.js installations across versions
17+
- Automatic cleanup of broken OpenClaw installations before reinstall
18+
- `openclaw@latest` is now filtered from `INSTALL_NPM_PACKAGES` to prevent conflicts
19+
20+
### Fixed 🐛
21+
- 🔧 **NVM PATH detection**: Fixed openclaw binary not found issue
22+
- Services now dynamically detect NVM Node.js version directories
23+
- Falls back to `/config/.nvm` when user home .nvm doesn't exist
24+
- Uses PUID/PGID to correctly identify target user instead of CUSTOM_USER
25+
26+
### Changed 🔄
27+
- 📝 **Documentation**: Updated CLAUDE.md and README.md with OpenClaw configuration
28+
829
## [0.7.0] - 2026-02-07
930

1031
### Added 🆕

CLAUDE.md

100644100755
Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,12 @@ Services are located in `src/etc/s6-overlay/s6-rc.d/`:
6565

6666
**Key Services:**
6767
- `init-chown-config`: Sets `/config` ownership based on `PUID`/`PGID` environment variables
68-
- `init-devcoder-*`: Various feature installers (codium-extensions, nodejs, pip3, golang, terraform, syncthing, sshd)
68+
- `init-devcoder-*`: Various feature installers (codium-extensions, nodejs, pip3, golang, terraform, syncthing, sshd, openclaw)
6969
- `init-devcoder-mods`: Orchestrates all mod installers
7070
- `svc-devcoder-syncthing`: Syncthing file synchronization service
7171
- `svc-devcoder-sshd`: SSH server
7272
- `svc-devcoder-ngrok`: Ngrok tunneling
73+
- `svc-devcoder-openclaw`: OpenClaw AI Gateway service (runs `openclaw gateway`)
7374

7475
**Service Dependencies:**
7576
Services can depend on each other using `dependencies.d/` files. Example:
@@ -109,6 +110,9 @@ DevCoder uses ENV vars to replace LinuxServer Docker Mods. Key mappings:
109110
| Syncthing | `SYNCTHING_ENABLED` | false (was true in v0.6.7) |
110111
| Terraform | `INSTALL_TERRAFORM` | false |
111112
| Golang | `INSTALL_GOLANG` | false |
113+
| OpenClaw | `INSTALL_OPENCLAW` | false |
114+
| OpenClaw Port | `OPENCLAW_PORT` | 18789 |
115+
| OpenClaw Bind | `OPENCLAW_BIND` | loopback |
112116
| APT Packages | `APT_PACKAGES` | (empty) |
113117

114118
### Dynamic Package Installation System
@@ -206,3 +210,40 @@ data/ # Persistent volumes (not in git)
206210
### Docker-in-Docker
207211

208212
Requires `privileged: true` in docker-compose.yaml. Not fully migrated from LinuxServer mods yet.
213+
214+
### OpenClaw Integration
215+
216+
[OpenClaw](https://github.com/openclaw/openclaw) is a personal, open-source AI assistant that can be self-hosted.
217+
218+
**Installation:**
219+
220+
Set `INSTALL_OPENCLAW=true` to install the OpenClaw CLI globally via npm.
221+
222+
```yaml
223+
environment:
224+
- INSTALL_OPENCLAW=true
225+
```
226+
227+
**Configuration:**
228+
229+
After installation, OpenClaw requires initialization (`openclaw onboard`) which creates the `~/.openclaw` directory with configuration. The `svc-devcoder-openclaw` service will only start the gateway once this directory exists.
230+
231+
```yaml
232+
environment:
233+
- INSTALL_OPENCLAW=true
234+
- OPENCLAW_PORT=18789 # Gateway port (default: 18789)
235+
- OPENCLAW_BIND=lan # Bind address: loopback, lan, tailnet, auto
236+
- OPENCLAW_TOKEN=xxx # Optional: authentication token
237+
- OPENCLAW_PASSWORD=xxx # Optional: authentication password
238+
- OPENCLAW_VERBOSE=true # Optional: enable verbose logging
239+
```
240+
241+
**Services:**
242+
243+
- `init-devcoder-openclaw`: Installs OpenClaw globally via npm (oneshot)
244+
- `svc-devcoder-openclaw`: Runs the OpenClaw gateway (longrun)
245+
246+
**Gateway Access:**
247+
248+
Once running, the Control UI is available at `http://<host>:18789/` (or configured port).
249+

README.md

100644100755
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,15 @@ SYNCTHING_PASSWORD= # Syncthing GUI password
8383
RUSTDESK_INSTALL=false # Possible values: false/proot/system
8484
```
8585

86+
#### OpenClaw
87+
```bash
88+
INSTALL_OPENCLAW=false # Set to "true" to install OpenClaw AI Gateway
89+
OPENCLAW_PORT=18789 # Gateway port
90+
OPENCLAW_BIND=loopback # Bind address: loopback, lan, tailnet, auto
91+
OPENCLAW_TOKEN= # Optional: authentication token
92+
OPENCLAW_PASSWORD= # Optional: authentication password
93+
OPENCLAW_VERBOSE=false # Enable verbose logging
94+
```
95+
96+
OpenClaw is a personal, open-source AI assistant. When enabled, it installs via npm and runs a gateway service. Requires `openclaw onboard` to be run first to create configuration.
8697

docker-compose.yaml

100644100755
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ services:
5454
# -- init-devcoder-npm-installer --
5555
INSTALL_NPM_PACKAGES: |
5656
@anthropic-ai/claude-code
57-
openclaw@latest
57+
INSTALL_OPENCLAW: true
5858
volumes:
5959
- ./data/config:/config # SUGGEST: /config is default home directory for user abc (uid: 911)
6060
- ./data/root:/root # EXAMPLE: /root is default home directory for root (uid: 0)

src/etc/s6-overlay/s6-rc.d/init-devcoder-nodejs/run

100644100755
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,17 @@ if [ -n "$NVM_DIR" ] && [ -d "$NVM_DIR/versions/node" ]; then
181181
fi
182182

183183

184+
# Filter out openclaw - it should be installed via init-devcoder-openclaw instead
185+
if [ -n "$INSTALL_NPM_PACKAGES_TO_INSTALL" ]; then
186+
INSTALL_NPM_PACKAGES_TO_INSTALL=$(echo "$INSTALL_NPM_PACKAGES_TO_INSTALL" | tr ' ' '\n' | grep -v '^openclaw' | grep -v '^openclaw@' | tr '\n' ' ' | xargs)
187+
if [ -z "$INSTALL_NPM_PACKAGES_TO_INSTALL" ]; then
188+
say "◾ No NPM packages to install (openclaw filtered out, use INSTALL_OPENCLAW=true)."
189+
exit 0
190+
fi
191+
fi
192+
193+
say "📦 Installing npm packages: $INSTALL_NPM_PACKAGES_TO_INSTALL"
194+
184195
for pkg in $INSTALL_NPM_PACKAGES_TO_INSTALL; do
185196
if run_as_user npm list -g "$pkg" >/dev/null 2>&1; then
186197
say "$pkg is already installed, skipping..."

src/etc/s6-overlay/s6-rc.d/init-devcoder-openclaw/dependencies.d/init-devcoder-mods

Whitespace-only changes.

src/etc/s6-overlay/s6-rc.d/init-devcoder-openclaw/dependencies.d/init-devcoder-nodejs

Whitespace-only changes.
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#!/usr/bin/with-contenv bash
2+
# shellcheck shell=bash
3+
source /etc/s6-overlay/s6-rc.d/echo_module.sh
4+
set_module_name "init-devcoder-openclaw"
5+
6+
say "▶️ Start openclaw installer"
7+
8+
# Check if openclaw installation is requested
9+
if [ "${INSTALL_OPENCLAW:-}" != "true" ]; then
10+
say "◾ INSTALL_OPENCLAW not set to true; skipping."
11+
exit 0
12+
fi
13+
14+
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH"
15+
16+
# Get target user info
17+
TARGET_USER="${CUSTOM_USER:-abc}"
18+
if id "$TARGET_USER" >/dev/null 2>&1; then
19+
TARGET_UID=$(id -u "$TARGET_USER")
20+
TARGET_GID=$(id -g "$TARGET_USER")
21+
TARGET_HOME=$(getent passwd "$TARGET_USER" | cut -d: -f6)
22+
else
23+
TARGET_UID=911
24+
TARGET_GID=911
25+
TARGET_HOME="$HOME"
26+
fi
27+
28+
# Add NVM to PATH - it may be in different versions
29+
NVM_DIR="$TARGET_HOME/.nvm"
30+
if [ -d "$NVM_DIR/versions/node" ]; then
31+
# Find the latest node version
32+
NODE_VERSION_DIR=$(find "$NVM_DIR/versions/node" -maxdepth 1 -type d ! -name node | sort -V | tail -1)
33+
if [ -n "$NODE_VERSION_DIR" ] && [ -d "$NODE_VERSION_DIR/bin" ]; then
34+
export PATH="$NODE_VERSION_DIR/bin:$PATH"
35+
export NVM_DIR="$NVM_DIR"
36+
say "✅ Added NVM Node.js to PATH: $NODE_VERSION_DIR"
37+
fi
38+
fi
39+
40+
run_as_root() {
41+
if [ "$(id -u)" = "0" ]; then
42+
"$@"
43+
return
44+
fi
45+
if command -v sudo >/dev/null 2>&1; then
46+
/usr/bin/sudo -E "$@"
47+
return
48+
fi
49+
if command -v su >/dev/null 2>&1; then
50+
su -s /bin/bash root -c "$(printf '%q ' "$@")"
51+
return
52+
fi
53+
"$@"
54+
}
55+
56+
run_as_user() {
57+
if id "$TARGET_USER" >/dev/null 2>&1; then
58+
if [ "$(id -u)" = "$(id -u "$TARGET_USER")" ]; then
59+
"$@"
60+
return
61+
fi
62+
if command -v sudo >/dev/null 2>&1; then
63+
/usr/bin/sudo -E -u "$TARGET_USER" env PATH="$PATH" NVM_DIR="$NVM_DIR" "$@"
64+
return
65+
fi
66+
if command -v su >/dev/null 2>&1; then
67+
su -s /bin/bash "$TARGET_USER" -c "$(printf '%q ' "$@")"
68+
return
69+
fi
70+
if command -v s6-setuidgid >/dev/null 2>&1; then
71+
s6-setuidgid "$TARGET_USER" "$@"
72+
return
73+
fi
74+
fi
75+
"$@"
76+
}
77+
78+
wait_for_npm() {
79+
local waited=0
80+
say "⏳ Waiting for npm to become available..."
81+
while ! command -v npm >/dev/null 2>&1; do
82+
if (( waited >= 60 )); then
83+
say "⚠️ npm not available after 60 seconds."
84+
return 1
85+
fi
86+
sleep 1
87+
((waited++))
88+
done
89+
say "✅ npm is available"
90+
return 0
91+
}
92+
93+
install_openclaw() {
94+
say "📦 Installing openclaw@latest globally..."
95+
96+
if run_as_user npm install -g openclaw@latest; then
97+
say "✅ OpenClaw installation command completed"
98+
return 0
99+
else
100+
say "⚠️ OpenClaw installation failed"
101+
return 1
102+
fi
103+
}
104+
105+
verify_openclaw() {
106+
local waited=0
107+
say "🔍 Verifying openclaw installation..."
108+
while (( waited < 60 )); do
109+
if command -v openclaw >/dev/null 2>&1; then
110+
local version
111+
version=$(openclaw --version 2>/dev/null || echo "unknown")
112+
say "✅ OpenClaw installed: version $version"
113+
return 0
114+
fi
115+
sleep 1
116+
((waited++))
117+
done
118+
say "⚠️ OpenClaw not detected after 60 seconds."
119+
return 1
120+
}
121+
122+
# Main execution
123+
wait_for_npm || exit 1
124+
125+
# Clean up any broken openclaw installation BEFORE attempting install
126+
say "🧹 Checking for broken openclaw installation..."
127+
if [ -d "$NVM_DIR/versions/node" ]; then
128+
for node_dir in "$NVM_DIR/versions/node"/v*; do
129+
if [ -d "$node_dir/lib/node_modules/openclaw" ]; then
130+
say "🧹 Removing broken openclaw from $node_dir"
131+
run_as_root rm -rf "$node_dir/lib/node_modules/openclaw"
132+
fi
133+
run_as_root rm -rf "$node_dir/lib/node_modules/.openclaw-"* 2>/dev/null || true
134+
done
135+
fi
136+
137+
install_openclaw || exit 1
138+
verify_openclaw || exit 1
139+
140+
say "🎉 OpenClaw setup complete"
141+
exit 0
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
oneshot
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/usr/bin/with-contenv bash
2+
# shellcheck shell=bash

0 commit comments

Comments
 (0)