Summary
In plain English: OpenClaw plugins read their config from plugins.entries.<id>.config in /sandbox/.openclaw/openclaw.json. NemoClaw's sandbox policy makes that whole directory read-only at runtime (Landlock-enforced). So a plugin like <observability-plugin> that requires per-deployment config (OTLP endpoint, service name, etc.) cannot be reconfigured after the sandbox is built — every config change requires a multi-minute image rebuild. NemoClaw should expose a writable overlay path for plugin config so users can iterate without rebuilds.
Companion issue planned against openclaw/openclaw for the OpenClaw-side angle (env-var overrides). This is the NemoClaw-side angle (writable overlay).
Problem
What a user expects (typical OpenClaw deployment):
- Edit
openclaw.json plugins.entries.<id>.config to point at a different OTel endpoint.
- Restart the gateway.
- Done.
What actually happens on NemoClaw:
sed -i against openclaw.json returns Operation not permitted (Landlock RO).
- User has no idea why — no error message, no docs surface mentioning that plugin config is locked.
- User eventually figures out the file is RO, reconfigures by rebuilding the image.
Worse, the bifurcation is unintuitive: NemoClaw's auto-load from /sandbox/.openclaw-data/extensions/ works for the plugin code (writable). But the plugin's CONFIG lives in the read-only openclaw.json next door. Same conceptual asset, two locations, opposite mutability.
Suggested fix (in priority order)
1. Writable overlay for plugin config
Source plugins.entries.<id>.config from a writable overlay path that overlays on top of openclaw.json. e.g.:
/sandbox/.openclaw/openclaw.json (RO — base)
/sandbox/.openclaw-data/plugin-config-overlay.json (RW — overlay)
Plugin loader merges the overlay onto the base at startup. Users can edit the overlay file at runtime, restart the gateway, get new config — no image rebuild.
The overlay file format mirrors the base's plugins.entries.<id>.config structure, only specifying overrides:
{
"plugins": {
"entries": {
"<observability-plugin>": {
"config": {
"endpoint": "https://override.example.com"
}
}
}
}
}
Could also support full overrides (flatten everything) if simpler.
2. Env-var overrides
Allow the sandbox to inject env vars at create time that override plugin config keys:
openshell sandbox create --name foo --env "OTEL_EXPORTER_OTLP_ENDPOINT=https://..." --from <Dockerfile>
Plugin config sources from env-var first, then from openclaw.json. This is the standard OTel ecosystem pattern (OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_SERVICE_NAME are well-known) — leverages established conventions.
This needs OpenClaw-core support (the plugin layer would need to surface env-vars to plugin config); companion issue planned against openclaw/openclaw.
3. (Minimum) document the build-time-only constraint
If neither overlay nor env-var lands quickly, document explicitly:
- "Plugin config in NemoClaw sandboxes is build-time only."
- "To change plugin config, rebuild the sandbox image."
- "EACCES on
openclaw.json is by design — Landlock protects the runtime config directory."
This alone removes the "I edited the file, why didn't it work?" confusion.
Alternatives considered
- Open up
/sandbox/.openclaw/ to writable in dev-mode preset (companion to A3): broader; the overlay approach is more surgical.
- Plugins read config from a different source per plugin (e.g.,
/sandbox/.openclaw-data/<plugin-id>.json): requires changes to every plugin's loader; not portable.
Repro
openshell sandbox exec -n nemoclaw-deepobs -- /bin/bash -c '
sed -i "s|http://172.17.0.1:14318|https://override.example.com|" /sandbox/.openclaw/openclaw.json
'
# Output: sed: cannot rename /sandbox/.openclaw/sed3iy3v: Operation not permitted
# To actually change the config, rebuild the image. ~5–10 min.
Test plan
After fix #1 (overlay):
- Create overlay file in
/sandbox/.openclaw-data/plugin-config-overlay.json with an endpoint override.
- Restart gateway.
- Plugin's exporter URL should reflect the override, not the base config.
- Restart sandbox without changing the overlay → endpoint persists.
After fix #2 (env-vars):
- Set
OTEL_EXPORTER_OTLP_ENDPOINT=https://... at sandbox-create.
- Plugin's exporter URL should be the env-var value.
- This works WITHOUT an image rebuild — just sandbox recreate with new env.
Risk / blast radius
- Overlay path: small; new code path in plugin-config loader, opt-in via overlay file presence.
- Env-var path: requires OpenClaw-core changes (cross-repo coordination).
- Docs-only: zero.
Open questions for maintainers
- Companion: a
openclaw/openclaw issue is filed for env-var overrides. Which side should drive the fix — NemoClaw policy (overlay) or OpenClaw runtime (env-var)? Both?
- Overlay file location — should it live in
/sandbox/.openclaw-data/ (writable, sandbox-scoped) or /sandbox/.nemoclaw/ (writable, NemoClaw-scoped)? .openclaw-data/ matches plugin code's location.
- Multiple overlays: would users want to layer multiple overlay files (e.g.,
dev.json, prod.json, switch via env)? Probably overkill for v1; flag for later.
Tested-against
- NemoClaw v0.0.26 (Landlock RO at
/sandbox/.openclaw/)
- OpenClaw v2026.4.9
Severity
ENHANCEMENT. Workaround (rebuild every change) exists; the iteration cost is the user-pain.
Summary
Problem
What a user expects (typical OpenClaw deployment):
openclaw.jsonplugins.entries.<id>.configto point at a different OTel endpoint.What actually happens on NemoClaw:
sed -iagainstopenclaw.jsonreturnsOperation not permitted(Landlock RO).Worse, the bifurcation is unintuitive: NemoClaw's auto-load from
/sandbox/.openclaw-data/extensions/works for the plugin code (writable). But the plugin's CONFIG lives in the read-onlyopenclaw.jsonnext door. Same conceptual asset, two locations, opposite mutability.Suggested fix (in priority order)
1. Writable overlay for plugin config
Source
plugins.entries.<id>.configfrom a writable overlay path that overlays on top ofopenclaw.json. e.g.:Plugin loader merges the overlay onto the base at startup. Users can edit the overlay file at runtime, restart the gateway, get new config — no image rebuild.
The overlay file format mirrors the base's
plugins.entries.<id>.configstructure, only specifying overrides:{ "plugins": { "entries": { "<observability-plugin>": { "config": { "endpoint": "https://override.example.com" } } } } }Could also support full overrides (flatten everything) if simpler.
2. Env-var overrides
Allow the sandbox to inject env vars at create time that override plugin config keys:
Plugin config sources from env-var first, then from
openclaw.json. This is the standard OTel ecosystem pattern (OTEL_EXPORTER_OTLP_ENDPOINT,OTEL_SERVICE_NAMEare well-known) — leverages established conventions.This needs OpenClaw-core support (the plugin layer would need to surface env-vars to plugin config); companion issue planned against
openclaw/openclaw.3. (Minimum) document the build-time-only constraint
If neither overlay nor env-var lands quickly, document explicitly:
openclaw.jsonis by design — Landlock protects the runtime config directory."This alone removes the "I edited the file, why didn't it work?" confusion.
Alternatives considered
/sandbox/.openclaw/to writable in dev-mode preset (companion to A3): broader; the overlay approach is more surgical./sandbox/.openclaw-data/<plugin-id>.json): requires changes to every plugin's loader; not portable.Repro
Test plan
After fix #1 (overlay):
/sandbox/.openclaw-data/plugin-config-overlay.jsonwith an endpoint override.After fix #2 (env-vars):
OTEL_EXPORTER_OTLP_ENDPOINT=https://...at sandbox-create.Risk / blast radius
Open questions for maintainers
openclaw/openclawissue is filed for env-var overrides. Which side should drive the fix — NemoClaw policy (overlay) or OpenClaw runtime (env-var)? Both?/sandbox/.openclaw-data/(writable, sandbox-scoped) or/sandbox/.nemoclaw/(writable, NemoClaw-scoped)?.openclaw-data/matches plugin code's location.dev.json,prod.json, switch via env)? Probably overkill for v1; flag for later.Tested-against
/sandbox/.openclaw/)Severity
ENHANCEMENT. Workaround (rebuild every change) exists; the iteration cost is the user-pain.