This feature is introduced in PraisonAI PR #2575. The
workspace_root parameter is set on PermissionManager directly. When workspace_root=None (the default), no boundary check runs and existing behaviour is unchanged.Quick Start
Enable workspace boundary
Create a When the manager checks
PermissionManager with workspace_root and the boundary gate activates automatically:cat /etc/passwd, it returns needs_approval=True — even if a broad bash:cat * → allow rule is set.How It Works
| Step | Action |
|---|---|
| 1 | Tool call arrives as bash:<cmd> or file tool target |
| 2 | CommandParser extracts path-like arguments from the command |
| 3 | Each path is checked with path_safety.is_within_root(path, workspace_root) |
| 4 | Out-of-workspace paths emit an external_dir:<parent>/* sub-target |
| 5 | Sub-target evaluated — defaults to ask unless a rule pre-authorises or denies it |
What Triggers the Gate
Any path that resolves outsideworkspace_root triggers an external_dir: approval request.
| Path form | Example | Outcome |
|---|---|---|
| Absolute path | /etc/hosts | external_dir:/etc/* → ask |
| Home-relative | ~/.bashrc | external_dir:<home>/* → ask |
| Explicit relative | ../../etc/passwd | external_dir:/etc/* → ask |
| Env-prefixed | $HOME/.config/x | external_dir:<home>/* → ask |
| Bare traversal | sub/../../etc/passwd | external_dir:/etc/* → ask |
| Joined flag value | --config=/etc/x | external_dir:/etc/* → ask |
| Short-getopt attached | curl -o/tmp/file | external_dir:/tmp/* → ask |
| Redirect write-target | echo x > ~/.bashrc | external_dir:<home>/* → ask |
| External executable | /tmp/tool.sh | external_dir:/tmp/* → ask |
Bare PATH-resolved command names like
ls, rm, cat are not boundary-checked — only tokens that reference the filesystem by path. An executable named /tmp/tool.sh is checked; a bare ls is not.Aggregation with Existing Rules
The workspace boundary fits into the same deny→ask→allow aggregation as all other permission checks.| Rule state | Command touches external path | Outcome |
|---|---|---|
bash:cat * → allow | cat /etc/passwd | ask (boundary gate fires) |
external_dir:/data/* → allow | cat /data/x.csv | allow (pre-authorised) |
external_dir:* → deny | cat /etc/passwd | deny (hard block) |
bash:rm * → deny | rm -rf /etc/other | deny (explicit deny wins first) |
bash:rm * or external_dir:* beats the boundary ask, and an explicit deny cannot be overridden by a boundary allow.
Backward Compatibility
Whenworkspace_root is None (the default), no boundary check runs and behaviour is 100% unchanged. Only opting in to workspace_root activates the gate — no existing code breaks.
Fail-Closed Behaviour
Pre-Authorising External Directories
- CLI
- YAML
- Python
Best Practices
Set workspace_root to your project root in CI runners
Set workspace_root to your project root in CI runners
Point
workspace_root at your checked-out repository path. The agent can freely read and write within the project; anything outside requires explicit pre-authorisation.Combine with external_dir:* → deny for maximum safety
Combine with external_dir:* → deny for maximum safety
Set
external_dir:* → deny to hard-block all out-of-workspace access. No ask prompt appears — the operation is immediately rejected. Use this in high-security CI pipelines.Deny still wins over the boundary gate
Deny still wins over the boundary gate
A
bash:rm * → deny rule fires before the boundary check. You can still hard-block destructive commands regardless of whether the path is inside or outside the workspace.Related
Permissions Module
Programmatic PermissionManager API and configuration options
Command-Aware Permissions
How compound shell commands are decomposed and checked
Declarative Permissions
YAML, CLI, and Python permission policies
Interactive Approval
User-facing approval prompts and backends

