Files in a directory of the host, opt-in: the agent sees root as / (design ยง4.40).
'''One writer per root.''' HostFileBackend.open takes an exclusive OS lock on the root, held until close: a second open of the same root, or of one containing it or inside it, from this JVM or another process, is refused with HostRootInUse. The lock excludes other backends that share the lock directory, not an editor or a build writing the directory; a replay still sees such a change, by its digests.
'''One path, one file.''' A path the model sees is the only way to reach its file: symbolic links, files with other hard links, other file systems mounted inside the root, names ending in a dot or a space and the backend's own temporary names are refused and never listed. open refuses a root whose file system makes 8.3 short names, and one it cannot check (no hard-link counts, as on NTFS, or a root it cannot probe) unless allowUncheckedIdentity.
'''Not a security boundary.''' It is a convenience for a trusted directory. Never give it a root an untrusted process can write, a sandboxed command included: such a process can swap a directory for a link between the backend's check and its open. Untrusted commands belong in the workspace sandbox (F2).
'''Replay.''' Its target is Verifiable (C4): each mutation runs through ReplayGuard.verifiable under ctx.effectKey("file.write" | "file.edit" | "file.delete", path), and its effect is a compare-and-set under the backend's own effect lock, so a run that lost its claim cannot overwrite its successor's change.
'''Atomic.''' A write or edit moves a flushed temporary file over its target, keeping the target's POSIX permissions, owner, group, ACL and DOS flags, or is refused where it cannot keep them.
'''Order.''' Every mutation locks files/host/<root>: a batch's mutations through one backend apply one at a time, in call order.
'''Bounds.''' A file over maxFileBytes cannot be read, written or edited, and search skips it. ls, find and search read at most maxScanEntries directory entries, never a stream past it, and report a cut scan as truncated: a directory over the bound lists as empty, and a walk stops at the first directory it cannot read whole, so a cut result is a prefix of the full one.
'''Tenant.''' Not scoped: one root is one tenant's. Build one per tenant with FileBackend.resolved.
'''Snapshot.''' Reads see the file as it is now, not as the batch's thread state.
Closes the backend; idempotent, and never blocks. Every operation that starts after it is refused. One already running finishes as it would have, and the root's lock is released when the last of them ends (at once if none is running), so no other backend can open the root while this one still writes to it. Safe to call from inside one of this backend's operations.
Closes the backend; idempotent, and never blocks. Every operation that starts after it is refused. One already running finishes as it would have, and the root's lock is released when the last of them ends (at once if none is running), so no other backend can open the root while this one still writes to it. Safe to call from inside one of this backend's operations.
Replaces old with replacement in the file path: the one occurrence, or every occurrence when replaceAll. Refused when old is empty or absent, or occurs more than once and not replaceAll.
Replaces old with replacement in the file path: the one occurrence, or every occurrence when replaceAll. Refused when old is empty or absent, or occurs more than once and not replaceAll.
The files within under that accept takes, in path order, at most limit: accept is applied before the limit, so a file it refuses never takes a place (a composite passes a predicate that refuses the paths a mount shadows, and relies on this to fill its limit with visible files). search likewise.
The files within under that accept takes, in path order, at most limit: accept is applied before the limit, so a file it refuses never takes a place (a composite passes a predicate that refuses the paths a mount shadows, and relies on this to fill its limit with visible files). search likewise.
One key for every path: a backend's mutations apply one at a time, so two names a case-insensitive or normalising file system takes for one file are ordered whatever they are.
One key for every path: a backend's mutations apply one at a time, so two names a case-insensitive or normalising file system takes for one file are ordered whatever they are.
The entries of the directory path, in name order, at most limit. A directory with more than maxScanEntries entries lists as empty and truncated: the backend never reads past its bound, and any part of such a directory would depend on the file system's order.
The entries of the directory path, in name order, at most limit. A directory with more than maxScanEntries entries lists as empty and truncated: the backend never reads past its bound, and any part of such a directory would depend on the file system's order.
The lines matching regex of the files within under that accept takes, in path then line order. regex is the model's: match it with org.llm4s.security.RegexSafetyManager.safeFind, never a bare matcher, so a catastrophic pattern is bounded and cannot overflow the stack.
The lines matching regex of the files within under that accept takes, in path then line order. regex is the model's: match it with org.llm4s.security.RegexSafetyManager.safeFind, never a bare matcher, so a catastrophic pattern is bounded and cannot overflow the stack.
The lines matching regex in the files within under. include filters the files: a pattern with no / matches a file's name, one with a / its path relative to under (as ripgrep's --glob).
The lines matching regex in the files within under. include filters the files: a pattern with no / matches a file's name, one with a / its path relative to under (as ripgrep's --glob).