Sandboxed coding assistant
The agent can read and write files only inside a workspace directory. Symlink-based escapes are blocked; an HMAC-signed audit log records every file access.
import asyncio
from pathlib import Path
from loomflow import Agent, Mode, StandardPermissions, tool
from loomflow.security import FileAuditLog, FilesystemSandbox
from loomflow.tools import InProcessToolHost
WORKSPACE = Path("./workspace").resolve()
@tool
def read_file(path: str) -> str:
"""Read a file from the workspace."""
return Path(path).read_text()
@tool(destructive=True)
def write_file(path: str, content: str) -> str:
"""Write content to a file (destructive — requires approval)."""
Path(path).write_text(content)
return f"wrote {len(content)} bytes to {path}"
async def main():
inner = InProcessToolHost([read_file, write_file])
sandbox = FilesystemSandbox(inner, roots=[WORKSPACE])
agent = Agent(
"You are a coding assistant. Only touch files inside the workspace.",
model="claude-opus-4-7",
tools=sandbox,
permissions=StandardPermissions(mode=Mode.ACCEPT_EDITS),
audit_log=FileAuditLog("./audit.jsonl", secret="prod-secret"),
)
@agent.before_tool
async def confirm_destructive(call):
if call.tool == "write_file":
answer = input(f"Allow write to {call.args.get('path')}? [y/N] ")
if answer.strip().lower() != "y":
from loomflow.core.types import PermissionDecision
return PermissionDecision.deny_("user declined")
return None
await agent.run("Refactor utils.py to use type hints.")
asyncio.run(main())The sandbox auto-detects path-typed arguments by name (path, file,
directory, etc.) and by value (containing / or \). Any path that
resolves outside the workspace. Including via symlink, is rejected
before the tool runs.
Last updated on