Every export of agentc_fs for Python components.
from agentc_fs import Directory, NotFoundErroragentc_fs provides asynchronous access to the filesystem through checked directory objects. See
fs for the semantics that hold in every language.
The base class for every filesystem failure.
A path that must exist does not.
A path that must not exist does.
A path that must be a directory is not.
An operation on a file was given a directory.
The mode bits, or a read-only mount, refused the operation.
A path resolves outside the authority the mount grants.
A rename would move a path from one backend to another.
A path, or a seek position, is invalid.
The backend, or the state of the file, does not support the operation.
The operation failed for a reason no other class describes.
Directory.root() returns the directory the runtime bound for this component. A Directory is a
working directory rather than a sandbox: paths resolve against it, "." names the directory
itself, and ".." names its parent. What limits reach is the authority the mount grants, and a
path that resolves outside it raises PathEscapesAuthorityError.
from agentc_fs import Directory
async def save(project: str, contents: str) -> None:
projects = await Directory.root().mkdir(
f"projects/{project}",
parents=True,
exist_ok=True,
)
await projects.write_text("notes.md", contents)open_dir, mkdir, and mkdtemp return a Directory, so reaching a subdirectory means opening
it. scandir and walk list the directory they are called on and take no path.
Every path argument accepts str | os.PathLike[str], so pathlib.PurePosixPath joins paths
without touching the filesystem. Paths come back as str, with each byte that is not valid UTF-8
replaced by U+FFFD.
Directory.open returns a File with its own cursor. Use async with so the file is flushed and
closed when the block exits.
from os import SEEK_END
from agentc_fs import Directory
async def tail(logs: Directory, name: str, size: int) -> bytes:
async with await logs.open(name) as file:
await file.seek(-size, SEEK_END)
return await file.read()Calls on one File run one at a time, in the order they started. Separate files have independent
cursors and run concurrently. After close, closed is True, another close does nothing, and
every other method raises UnsupportedError.
FilesystemError
├── NotFoundError
├── AlreadyExistsError
├── NotDirectoryError
├── IsDirectoryError
├── PermissionDeniedError
├── PathEscapesAuthorityError
├── CrossBackendRenameError
├── InvalidPathError
├── UnsupportedError
└── UnexpectedErrorFailures that concern one path retain that path. A rename across backends retains both. Catch
FilesystemError for all filesystem failures, or catch the narrower class when recovery depends on
the failure type.
A directory reached through the authority the runtime granted the component. Directory objects are
obtained from root, open_dir, mkdir, and mkdtemp.
The path of this directory.
The path no operation through this directory may escape.
def root() -> DirectoryReturns the directory the runtime bound for this component.
The component's root directory.
async def open(
path: StrPath,
/,
*,
read: bool = True,
write: bool = False,
append: bool = False,
truncate: bool = False,
create: bool = False,
create_new: bool = False,
follow_symlinks: bool = True,
) -> FileOpens a file. Each keyword sets one open option, and the file is opened for reading unless read
is turned off.
The path to open.
Whether the file may be read.
Whether the file may be written.
Whether every write goes to the end of the file.
Whether the file is emptied when it is opened.
Whether the file is created when it does not exist.
Whether the file must not already exist.
Whether a symbolic link at the final path component is followed.
The open file.
async def read_bytes(path: StrPath, /) -> bytesReads the entire contents of a file.
The path to read.
The file contents.
async def read_text(path: StrPath, /) -> strReads the entire contents of a file and decodes it as UTF-8.
The path to read.
The decoded file contents.
async def write_bytes(path: StrPath, data: bytes, /) -> NoneWrites bytes to a file, creating it when it does not exist and replacing any contents it already had.
The path to write.
The bytes to write.
Nothing.
async def write_text(path: StrPath, data: str, /) -> NoneEncodes text as UTF-8 and writes it like write_bytes.
The path to write.
The text to write.
Nothing.
async def truncate(path: StrPath, length: int, /) -> NoneResizes a file to a given length.
The path to resize.
The length to resize to.
Nothing.
async def open_dir(path: StrPath, /) -> DirectoryOpens an existing directory. A symbolic link at the final path component is not followed.
The path to open.
The directory at that path, with the same authority root.
async def mkdir(
path: StrPath,
/,
*,
parents: bool = False,
exist_ok: bool = False,
) -> DirectoryCreates a directory and returns it.
The path to create.
Whether missing parent directories are created as well.
Whether an existing directory is opened instead of being an error.
The directory that was created, or the existing one when exist_ok was set.
async def mkdtemp(*, prefix: StrPath) -> DirectoryCreates a uniquely named directory from a prefix, with mode 0o700, and returns it.
The path prefix to create beneath.
The directory that was created.
def scandir() -> AsyncIterator[Entry]Iterates the entries directly inside this directory, sorted by name. The directory is opened at the first iteration, so a failure to open it is raised there.
The entries of this directory.
def walk() -> AsyncIterator[Entry]Iterates every entry below this directory in pre-order, depth first. Subdirectories that cannot be listed are skipped, and the directory is opened at the first iteration.
Every entry below this directory.
async def entry(path: StrPath, /) -> EntryReturns one entry. A symbolic link at the final path component is not followed.
The path to describe.
The entry at that path.
async def stat(path: StrPath, /, *, follow_symlinks: bool = True) -> StatReads metadata about a path.
The path to describe.
Whether a symbolic link at the final path component is followed.
The metadata for that path.
async def exists(path: StrPath, /, *, follow_symlinks: bool = True) -> boolChecks whether a path exists. Only a missing path returns False, and every other failure is
raised.
The path to check.
Whether a symbolic link at the final path component is followed.
True when the path exists.
async def access(
path: StrPath,
/,
*,
read: bool = False,
write: bool = False,
execute: bool = False,
follow_symlinks: bool = True,
) -> boolChecks that a path is reachable with the requested access. Only a refusal returns False, and
every other failure is raised.
The path to check.
Whether read access is required.
Whether write access is required.
Whether execute access is required.
Whether a symbolic link at the final path component is followed.
True when the path is reachable with the requested access.
async def chmod(path: StrPath, mode: int, /) -> NoneReplaces the permission bits on a path.
The path to change.
The permission bits to set.
Nothing.
async def chown(
path: StrPath,
/,
*,
uid: int | None = None,
gid: int | None = None,
follow_symlinks: bool = True,
) -> NoneReplaces the owning user or group on a path. An owner left as None is unchanged.
The path to change.
The user identifier to set.
The group identifier to set.
Whether a symbolic link at the final path component is followed.
Nothing.
async def symlink(target: StrPath, link: StrPath, /) -> NoneCreates a symbolic link. Both paths resolve against this directory.
The path the link points at.
The path of the link to create.
Nothing.
async def readlink(path: StrPath, /) -> strReads the target of a symbolic link, which is absolute.
The link to read.
The absolute target of the link.
async def rename(source: StrPath, destination: StrPath, /) -> NoneMoves a path to a new location. Both paths resolve against this directory.
The path to move.
The path to move it to.
Nothing.
async def remove(path: StrPath, /) -> NoneRemoves a file, or a symbolic link itself rather than its target.
The path to remove.
Nothing.
async def rmdir(path: StrPath, /) -> NoneRemoves an empty directory.
The directory to remove.
Nothing.
async def rmtree(path: StrPath, /) -> NoneRemoves a directory and everything below it.
The directory to remove.
Nothing.
An open file, returned by Directory.open. It supports async with, which closes the file when the
block exits.
Whether the file has been closed.
async def read(size: int = -1, /) -> bytesReads from the current position. A negative size reads to the end of the file, and a positive size reads fewer bytes only when the end is reached.
The number of bytes to read.
The bytes that were read, empty at the end of the file.
async def read_text() -> strReads from the current position to the end of the file and decodes it as UTF-8.
The decoded contents.
async def write(data: bytes, /) -> NoneWrites all of data at the current position.
The bytes to write.
Nothing.
async def seek(offset: int, whence: int = 0, /) -> intMoves the current position and returns where it landed. whence accepts os.SEEK_SET,
os.SEEK_CUR, and os.SEEK_END.
The offset to move by, relative to whence.
The position the offset is relative to.
The new position.
async def tell() -> intReturns the current position.
The current position.
async def truncate(size: int, /) -> NoneResizes the file. The size is required, and the current position does not move.
The size to resize to.
Nothing.
async def flush() -> NoneFlushes buffered writes.
Nothing.
async def fsync() -> NoneFlushes file data and metadata.
Nothing.
async def fdatasync() -> NoneFlushes file data.
Nothing.
async def close() -> NoneFlushes and closes the file. The file is closed even when the flush fails, and closing an already closed file does nothing.
Nothing.
One entry, returned by scandir, walk, and entry. Every property describes the entry itself
and does not follow a symbolic link.
The name of the entry within its directory.
The path of the entry.
The kind of entry.
Whether the entry is a regular file.
Whether the entry is a directory.
Whether the entry is a symbolic link.
The entry's metadata, or None when the listing did not carry it.
Metadata about a path, returned by Directory.stat and carried by Entry.stat. The names are
os.stat_result fields without the st_ prefix, and mode holds the permission bits only.
Timestamps are timezone-aware UTC datetime values, and are None when the backend does not keep
them.
type StrPath = str | os.PathLike[str]What every path argument accepts. Paths are always returned as str.
type EntryType = Literal[
"file",
"directory",
"symlink",
"fifo",
"socket",
"block_device",
"character_device",
"other",
]The kind of a filesystem entry.
class FilesystemError(Exception): ...The base class for every filesystem failure.
The description of the failure.
class NotFoundError(FilesystemError): ...A path that must exist does not.
The path that was not found.
class AlreadyExistsError(FilesystemError): ...A path that must not exist does.
The path that already exists.
class NotDirectoryError(FilesystemError): ...A path that must be a directory is another kind of entry.
The path that is not a directory.
class IsDirectoryError(FilesystemError): ...An operation on a file was given a directory.
The path that is a directory.
class PermissionDeniedError(FilesystemError): ...The mode bits, or a read-only mount, refused the operation.
The path the operation was refused on.
class PathEscapesAuthorityError(FilesystemError): ...A path resolves outside the authority the mount grants.
The path that escapes the authority.
class CrossBackendRenameError(FilesystemError): ...A rename would move a path from one backend to another.
The path that was to be moved.
The path it was to be moved to.
class InvalidPathError(FilesystemError): ...A path, or a seek position, is invalid.
class UnsupportedError(FilesystemError): ...The backend does not implement the operation, or the file is closed.
class UnexpectedError(FilesystemError): ...The operation failed for a reason no other class describes.
See fs for the path, mount, and error semantics shared by every language, and filesystem for how the mounts are declared.
© 2026 pogue.dev. All rights reserved.
CC BY 4.0