openclaw - 💡(How to fix) Fix [Feature]: add system.read / system.write to node protocol for remote file I/O [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#61500Fetched 2026-04-08 02:57:55
View on GitHub
Comments
0
Participants
1
Timeline
1
Reactions
0
Participants
Timeline (top)
labeled ×1

Add system.read and system.write commands to the node protocol so that file I/O tools (read, write, edit) can route to the node host when tools.exec.host=node, enabling a coding agent to read and write files on the same machine where it executes code.

Error Message

Error handling is degraded — exec failures are harder to parse than structured tool errors

Root Cause

Add system.read and system.write commands to the node protocol so that file I/O tools (read, write, edit) can route to the node host when tools.exec.host=node, enabling a coding agent to read and write files on the same machine where it executes code.

Fix Action

Fix / Workaround

This means that while you can execute code on the remote machine, you cannot read or write files there through the standard file tools. The only workaround is to construct file operations as shell commands via exec:

cat > /tmp/patch.py << 'EOF'

... script contents ...

EOF python3 /tmp/patch.py

Node side Add command handlers in the node's invoke dispatcher (src/node-host/invoke.ts):

RAW_BUFFERClick to expand / collapse

Summary

Add system.read and system.write commands to the node protocol so that file I/O tools (read, write, edit) can route to the node host when tools.exec.host=node, enabling a coding agent to read and write files on the same machine where it executes code.

Problem to solve

Problem When using a two-machine setup (gateway on one host, compute node on another) with tools.exec.host=node, all shell commands route to the node correctly via system.run. However, the read, write, and edit tools are hardcoded to use the gateway's local filesystem (node:fs). There is no mechanism to route file I/O to the node.

This means that while you can execute code on the remote machine, you cannot read or write files there through the standard file tools. The only workaround is to construct file operations as shell commands via exec:

cat > /tmp/patch.py << 'EOF'

... script contents ...

EOF python3 /tmp/patch.py

This is:

Fragile — heredoc quoting issues, path escaping, multi-step operations that can partially fail Token-expensive — file contents must be serialized into shell commands instead of passed as structured tool parameters UX-hostile — triggers the obfuscation detection heuristic for anything non-trivial, producing large approval modals Inconsistent — exec routes to the node, but the file tools that a coding agent uses most heavily do not

Proposed solution

Add system.read and system.write commands to the node protocol, following the same pattern as system.run.

Node side Add command handlers in the node's invoke dispatcher (src/node-host/invoke.ts):

system.read: Receives { filePath: string, cwd?: string }, reads the file, returns { content: string, encoding: "utf-8", path: string }. Validates the resolved path against allowed directories (e.g., user home + /tmp) to prevent traversal.

system.write: Receives { filePath: string, content: string, cwd?: string, mkdir?: boolean }, writes the file (optionally creating parent directories), returns { ok: true, path: string }. Same path validation.

These commands would be advertised alongside system.run in the node's capability registration, and gated by gateway.nodes.allowCommands like existing commands.

Gateway side Route read/write/edit tool operations through the node when tools.exec.host=node, using callGatewayTool("node.invoke", { command: "system.read" }) instead of local fs. The existing operations interface (readFile, writeFile, mkdir, access) used by createReadTool, createWriteTool, and createEditTool is already abstracted — the sandbox bridge (createSandboxedReadTool, createSandboxedWriteTool, createSandboxedEditTool) uses this exact pattern to route file I/O through a bridge instead of local fs.

A parallel set of operations factories (createNodeReadOperations, createNodeWriteOperations, createNodeEditOperations) would follow the same bridge pattern but target the node.

Design question: split routing The main architectural decision is which paths route to the node and which stay on the gateway. Workspace files (MEMORY.md, SOUL.md, AGENTS.md, etc.) live on the gateway filesystem and are injected into the system prompt by the gateway framework. If all file I/O routes to the node, these workspace files become unreachable.

Possible approaches:

Path-prefix routing: Paths under the gateway's workspaceRoot stay local; all other paths route to the node Explicit config: A separate tools.fs.host config (independent of tools.exec.host) that defaults to "gateway" but can be set to "node" or "split" Workspace-aware routing: The tool creation pipeline already distinguishes workspace vs. non-workspace paths (via workspaceOnly, wrapToolWorkspaceRootGuard). The routing decision could hook into this existing boundary

Alternatives considered

No response

Impact

Affected users: Anyone running OpenClaw in a split-host configuration — gateway on a low-power always-on machine (e.g. Mac Mini, Raspberry Pi, small VPS) with a separate compute node for heavy workloads (workstation, GPU machine, cloud instance). This is a natural deployment pattern for the node architecture and becomes increasingly common as people use OpenClaw for coding agents and ML workflows.

Severity: Blocks workflow. The read/write/edit tools are the primary interface for a coding agent to interact with files. Without node routing, every file operation on the remote host requires a workaround through exec — making the agent effectively unable to use its core file tools on the machine where it actually runs code.

Frequency: Every single file operation on the node host. This is not an edge case — it affects every read, write, and edit call when tools.exec.host=node.

Practical consequences:

Writing files requires constructing shell heredocs via exec, which triggers the obfuscation detection heuristic and produces approval modals for routine operations Reading files back after writing requires another exec roundtrip (cat) The edit tool is completely unusable on node-hosted files — there is no workaround that doesn't involve exec Agents working on code on the remote machine spend significant token budget on exec scaffolding instead of actual work Error handling is degraded — exec failures are harder to parse than structured tool errors

Evidence/examples

No response

Additional information

No response

extent analysis

TL;DR

Add system.read and system.write commands to the node protocol to enable file I/O routing to the node host when tools.exec.host=node.

Guidance

  • Implement system.read and system.write command handlers in the node's invoke dispatcher (src/node-host/invoke.ts) to handle file reading and writing on the node host.
  • Update the gateway to route read/write/edit tool operations through the node when tools.exec.host=node by using callGatewayTool("node.invoke", { command: "system.read" }) instead of local fs.
  • Consider implementing path-prefix routing, explicit config, or workspace-aware routing to determine which paths route to the node and which stay on the gateway.
  • Create parallel operations factories (createNodeReadOperations, createNodeWriteOperations, createNodeEditOperations) to target the node for file I/O operations.

Example

// src/node-host/invoke.ts
const systemReadHandler = async ({ filePath, cwd }: { filePath: string, cwd?: string }) => {
  // Validate resolved path against allowed directories
  const content = await readFile(filePath, 'utf8');
  return { content, encoding: 'utf-8', path: filePath };
};

const systemWriteHandler = async ({ filePath, content, cwd, mkdir }: { filePath: string, content: string, cwd?: string, mkdir?: boolean }) => {
  // Validate resolved path against allowed directories
  await writeFile(filePath, content, { mkdir });
  return { ok: true, path: filePath };
};

Notes

The implementation details may vary depending on the specific requirements and constraints of the OpenClaw system. The proposed solution assumes that the system.read and system.write commands will be gated by gateway.nodes.allowCommands like existing commands.

Recommendation

Apply the proposed solution by adding system.read and system.write commands to the node protocol and updating the gateway to route file I/O operations through the node when tools.exec.host=node. This will enable coding agents to read and write files on the remote host without relying on workarounds through exec.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix [Feature]: add system.read / system.write to node protocol for remote file I/O [1 participants]