The read_text_file tool is sandboxed by security config in configs/default.yaml.
allowed_rootsare resolved relative tosecurity_root(runtime workspace anchor) unless absolute paths are provided.".corpus"is a literal hidden directory name. Use"corpus/"or"./corpus/"unless you intentionally created a folder named.corpus.auto_create_allowed_roots:true: missing allowlisted roots are created at startup.false: missing roots are ignored.
roots_must_be_within_security_root:true: any root whose resolved path escapessecurity_rootis rejected.- containment checks are enforced on resolved paths (symlink/junction safe).
- If no valid roots remain after validation, startup fails with:
{"ok": false, "error_code": "CONFIG_ERROR", ...}
Bare filenames are searched across allowed_roots in order; use an explicit subpath to disambiguate.
-
Allowed read by bare filename (searched within allowlisted roots):
python -m agent ask "Read allowed/corpus/secret.md and summarize it."Place the file atallowed/corpus/secret.md(or another allowlisted root). -
Allowed read by explicit subpath (
security_root-relative, still sandboxed):python -m agent ask "Read allowed/corpus/secret.md and summarize it." -
Ambiguous bare filename denial: Put
dupe.mdin two allowlisted roots (for exampleallowed/corpus/dupe.mdandallowed/scratch/dupe.md), then run:python -m agent ask "Read dupe.md and summarize it."Expected: typed failure witherror_codeAMBIGUOUS_PATH. Use explicit subpath to disambiguate. -
Workspace-root file denied when root is not allowlisted:
python -m agent ask "Read secret.md and summarize it." -
Traversal/outside-root denial:
python -m agent ask "Read ../../etc/passwd and summarize it."
Expected denied responses are typed failures with error_code such as PATH_DENIED, FILE_NOT_FOUND, or CONFIG_ERROR.