Workspace Jailing
Workspace jailing restricts all built-in filesystem tools to a designated directory tree. Agents cannot read, write, or execute outside the workspace boundary — even via path traversal or symlinks.
How It Works
Section titled “How It Works”When a workspace is configured, every filesystem operation goes through resolve_path():
- Absolute paths are rejected — agents must use relative paths
- Relative paths are joined to the workspace root and normalized
- Path traversal (
../../etc/passwd) is caught by checking the normalized path stays within the workspace - Symlink escapes are blocked by canonicalizing existing paths and re-checking containment
The workspace root is canonicalized once at startup, so all containment checks use real filesystem paths.
Affected Tools
Section titled “Affected Tools”All built-in filesystem tools enforce the jail:
| Tool | Enforcement |
|---|---|
read_file | Path must resolve inside workspace |
write_file | Path must resolve inside workspace |
edit_file | Path must resolve inside workspace |
patch | Path must resolve inside workspace |
glob | Search rooted in workspace |
grep | Search rooted in workspace |
list_directory | Path must resolve inside workspace |
bash | Working directory set to workspace root |
Tools without filesystem access (web_fetch, web_search, skill, todo_*, question) are unaffected.
Configuration
Section titled “Configuration”Via TOML Config
Section titled “Via TOML Config”[workspace]root = "/home/user/project"If [workspace] is present without a root, it defaults to ~/.heartbit/workspaces.
Via Builder (Programmatic)
Section titled “Via Builder (Programmatic)”use heartbit::tool::builtins::{BuiltinToolsConfig, builtin_tools};use std::path::PathBuf;
let config = BuiltinToolsConfig { workspace: Some(PathBuf::from("/home/user/project")), ..Default::default()};let tools = builtin_tools(config);CLI Standalone Mode
Section titled “CLI Standalone Mode”Without a config file (env-based), the workspace defaults to the current working directory. The bash tool starts in this directory.
Security Properties
Section titled “Security Properties”What Is Blocked
Section titled “What Is Blocked”workspace: /home/user/project
/etc/passwd -> ERROR: Absolute paths not allowed../../etc/passwd -> ERROR: Path escapes workspace rootsymlink -> /etc/ -> ERROR: Resolves outside workspaceWhat Is Allowed
Section titled “What Is Allowed”workspace: /home/user/project
src/main.rs -> /home/user/project/src/main.rssub/../file.txt -> /home/user/project/file.txt (internal .. OK)deeply/nested/file.rs -> /home/user/project/deeply/nested/file.rsTOCTOU Note
Section titled “TOCTOU Note”The symlink check uses canonicalize() before the file operation. A symlink could theoretically be swapped between the check and the actual open. This is acceptable for an agent tool jail. Closing this gap fully would require O_NOFOLLOW or OS-level namespaces.
Daemon Mode
Section titled “Daemon Mode”In daemon mode, workspace jailing is critical for multi-tenant isolation. Each task can be assigned a workspace directory, ensuring agents operating on behalf of different tenants cannot access each other’s files.
[workspace]root = "/var/lib/heartbit/workspaces"Without Jailing
Section titled “Without Jailing”When no workspace is configured:
- Absolute paths pass through unchanged
- Relative paths are returned as-is (resolved by the OS relative to CWD)
- No containment checks are performed
This is the default for CLI standalone mode when no config file is provided.