From abcce1e1db3282651a916f5de9193bb4025ff559 Mon Sep 17 00:00:00 2001 From: aiguozhi123456 Date: Tue, 24 Feb 2026 03:18:23 +0000 Subject: [PATCH 1/6] feat(exec): add path_append config to extend PATH for subprocess --- nanobot/agent/tools/shell.py | 7 +++++++ nanobot/config/schema.py | 1 + 2 files changed, 8 insertions(+) diff --git a/nanobot/agent/tools/shell.py b/nanobot/agent/tools/shell.py index e3592a7..c11fa2d 100644 --- a/nanobot/agent/tools/shell.py +++ b/nanobot/agent/tools/shell.py @@ -19,6 +19,7 @@ class ExecTool(Tool): deny_patterns: list[str] | None = None, allow_patterns: list[str] | None = None, restrict_to_workspace: bool = False, + path_append: str = "/usr/sbin:/usr/local/sbin", ): self.timeout = timeout self.working_dir = working_dir @@ -35,6 +36,7 @@ class ExecTool(Tool): ] self.allow_patterns = allow_patterns or [] self.restrict_to_workspace = restrict_to_workspace + self.path_append = path_append @property def name(self) -> str: @@ -67,12 +69,17 @@ class ExecTool(Tool): if guard_error: return guard_error + env = os.environ.copy() + if self.path_append: + env["PATH"] = env.get("PATH", "") + ":" + self.path_append + try: process = await asyncio.create_subprocess_shell( command, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, cwd=cwd, + env=env, ) try: diff --git a/nanobot/config/schema.py b/nanobot/config/schema.py index fe8dd83..dd856fe 100644 --- a/nanobot/config/schema.py +++ b/nanobot/config/schema.py @@ -252,6 +252,7 @@ class ExecToolConfig(Base): """Shell exec tool configuration.""" timeout: int = 60 + path_append: str = "/usr/sbin:/usr/local/sbin" class MCPServerConfig(Base): From 7be278517e8706f61bc2bc3c17b2b01fc4fbff5b Mon Sep 17 00:00:00 2001 From: aiguozhi123456 Date: Tue, 24 Feb 2026 12:13:52 +0000 Subject: [PATCH 2/6] fix(exec): use empty default and os.pathsep for cross-platform --- nanobot/agent/tools/shell.py | 4 ++-- nanobot/config/schema.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/nanobot/agent/tools/shell.py b/nanobot/agent/tools/shell.py index c11fa2d..c3810b2 100644 --- a/nanobot/agent/tools/shell.py +++ b/nanobot/agent/tools/shell.py @@ -19,7 +19,7 @@ class ExecTool(Tool): deny_patterns: list[str] | None = None, allow_patterns: list[str] | None = None, restrict_to_workspace: bool = False, - path_append: str = "/usr/sbin:/usr/local/sbin", + path_append: str = "", ): self.timeout = timeout self.working_dir = working_dir @@ -71,7 +71,7 @@ class ExecTool(Tool): env = os.environ.copy() if self.path_append: - env["PATH"] = env.get("PATH", "") + ":" + self.path_append + env["PATH"] = env.get("PATH", "") + os.pathsep + self.path_append try: process = await asyncio.create_subprocess_shell( diff --git a/nanobot/config/schema.py b/nanobot/config/schema.py index dd856fe..4543ae0 100644 --- a/nanobot/config/schema.py +++ b/nanobot/config/schema.py @@ -252,7 +252,7 @@ class ExecToolConfig(Base): """Shell exec tool configuration.""" timeout: int = 60 - path_append: str = "/usr/sbin:/usr/local/sbin" + path_append: str = "" class MCPServerConfig(Base): From 07ae82583bae300593aa779e0c2a172e2a3c98b3 Mon Sep 17 00:00:00 2001 From: aiguozhi123456 Date: Tue, 24 Feb 2026 12:31:18 +0000 Subject: [PATCH 3/6] fix: pass path_append from config to ExecTool --- nanobot/agent/loop.py | 1 + nanobot/agent/subagent.py | 1 + 2 files changed, 2 insertions(+) diff --git a/nanobot/agent/loop.py b/nanobot/agent/loop.py index 8be8e51..c5e2a00 100644 --- a/nanobot/agent/loop.py +++ b/nanobot/agent/loop.py @@ -110,6 +110,7 @@ class AgentLoop: working_dir=str(self.workspace), timeout=self.exec_config.timeout, restrict_to_workspace=self.restrict_to_workspace, + path_append=self.exec_config.path_append, )) self.tools.register(WebSearchTool(api_key=self.brave_api_key)) self.tools.register(WebFetchTool()) diff --git a/nanobot/agent/subagent.py b/nanobot/agent/subagent.py index d87c61a..7269dee 100644 --- a/nanobot/agent/subagent.py +++ b/nanobot/agent/subagent.py @@ -111,6 +111,7 @@ class SubagentManager: working_dir=str(self.workspace), timeout=self.exec_config.timeout, restrict_to_workspace=self.restrict_to_workspace, + path_append=self.exec_config.path_append, )) tools.register(WebSearchTool(api_key=self.brave_api_key)) tools.register(WebFetchTool()) From e959b13926680b8dc63e3af7c62f05db3534dbe2 Mon Sep 17 00:00:00 2001 From: aiguozhi123456 Date: Wed, 25 Feb 2026 01:49:56 +0000 Subject: [PATCH 4/6] docs: add pathAppend option to exec config docs --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 148c8f4..c3904bd 100644 --- a/README.md +++ b/README.md @@ -804,6 +804,7 @@ MCP tools are automatically discovered and registered on startup. The LLM can us | Option | Default | Description | |--------|---------|-------------| | `tools.restrictToWorkspace` | `false` | When `true`, restricts **all** agent tools (shell, file read/write/edit, list) to the workspace directory. Prevents path traversal and out-of-scope access. | +| `tools.exec.pathAppend` | `""` | Additional paths to append to `PATH` when executing shell commands. Useful for commands in non-standard locations (e.g., `/usr/sbin` for `ufw`). Use `":"` as separator (e.g., `"/usr/sbin:/usr/local/sbin"`). | | `channels.*.allowFrom` | `[]` (allow all) | Whitelist of user IDs. Empty = allow everyone; non-empty = only listed users can interact. | From a50a2c68686128a2dd1f395514501a392988e7e4 Mon Sep 17 00:00:00 2001 From: aiguozhi123456 Date: Wed, 25 Feb 2026 01:53:04 +0000 Subject: [PATCH 5/6] fix(docs): clarify platform-specific path separator --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c3904bd..278b114 100644 --- a/README.md +++ b/README.md @@ -804,7 +804,7 @@ MCP tools are automatically discovered and registered on startup. The LLM can us | Option | Default | Description | |--------|---------|-------------| | `tools.restrictToWorkspace` | `false` | When `true`, restricts **all** agent tools (shell, file read/write/edit, list) to the workspace directory. Prevents path traversal and out-of-scope access. | -| `tools.exec.pathAppend` | `""` | Additional paths to append to `PATH` when executing shell commands. Useful for commands in non-standard locations (e.g., `/usr/sbin` for `ufw`). Use `":"` as separator (e.g., `"/usr/sbin:/usr/local/sbin"`). | +| `tools.exec.pathAppend` | `""` | Additional paths to append to `PATH` when executing shell commands. Useful for commands in non-standard locations (e.g., `/usr/sbin` for `ufw`). Use the platform-specific separator (`:` on Linux/macOS, `;` on Windows). | | `channels.*.allowFrom` | `[]` (allow all) | Whitelist of user IDs. Empty = allow everyone; non-empty = only listed users can interact. | From 9eca7f339e0bce588877c5fe788c5208c1795828 Mon Sep 17 00:00:00 2001 From: Re-bin Date: Wed, 25 Feb 2026 15:57:50 +0000 Subject: [PATCH 6/6] docs: shorten pathAppend description in config table --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index faa2f29..ad81dd6 100644 --- a/README.md +++ b/README.md @@ -807,7 +807,7 @@ MCP tools are automatically discovered and registered on startup. The LLM can us | Option | Default | Description | |--------|---------|-------------| | `tools.restrictToWorkspace` | `false` | When `true`, restricts **all** agent tools (shell, file read/write/edit, list) to the workspace directory. Prevents path traversal and out-of-scope access. | -| `tools.exec.pathAppend` | `""` | Additional paths to append to `PATH` when executing shell commands. Useful for commands in non-standard locations (e.g., `/usr/sbin` for `ufw`). Use the platform-specific separator (`:` on Linux/macOS, `;` on Windows). | +| `tools.exec.pathAppend` | `""` | Extra directories to append to `PATH` when running shell commands (e.g. `/usr/sbin` for `ufw`). | | `channels.*.allowFrom` | `[]` (allow all) | Whitelist of user IDs. Empty = allow everyone; non-empty = only listed users can interact. |