Skip to main content
fs is the same object on every host. Paths are workspace paths: relative ones resolve beside the app or script, and / is the workspace root. On a folder served from disk with arg serve, or one the desktop app opened directly, / is that folder instead.

Reading

Every read method has a ById twin (readById, readJSONById, infoById, assetUrlById, …). Hosts cache one-shot reads for the life of a page run; pass { fresh: true } to bypass the cache after you know a file changed.

Writing

Write, move, copy, mkdir and remove need write authority: Read and write in an app’s grant, a non-read-only turn in an agent script, or an API key that can write. A refused write rejects with read_only.

Conditional writes

Over HTTP - servers, CI, arg serve in account mode and agent scripts - a write can carry a condition, so two writers never silently overwrite each other:
baseRevision writes only if the file still has that revision; createOnly writes only if the path does not exist. A failed condition rejects, and nothing is written. The in-Arg preview bridge does not implement conditions: it rejects them explicitly with unsupported_capability rather than dropping the condition and writing anyway.

Appending

append(path, content) adds text to the end of a file, creating it when it does not exist yet. Use it whenever many people may add to one file at once - an order log, a JSONL of responses, rows of a CSV: unlike reading the file and writing it back, no one’s append is ever lost to someone else’s landing at the same moment. It takes text only, and rejects with conflict if the file keeps changing under it. In an app opened from a share link it works only on files the link lets visitors write to.

Listing, globbing, searching

Listings are bounded by the transport: a server client stops after one storage page and rejects a truncated result rather than returning a partial list as if it were whole; glob walks at most 64 directories or 10,000 entries; a folder served from disk lists at most 1,000 entries. Under a folder-scoped grant, listings never leave the folder.

Moving, copying, removing

Targets are literal file paths, not folders. In a cloud workspace a move keeps the file’s id, its comments and its share links; that is why the SDK exposes a move rather than a read-write-remove sequence.

Sharing with Arg users

permissions grants a user access through the workspace’s own permission system. Pick a user id from users.list() and choose read, write or manage; admin is a workspace-only level and cannot be granted on a file or folder.
The caller must be a user with manage access to the path, and the recipient must belong to the workspace organization. Folder grants flow to descendants. These methods use cloud workspace paths under arg serve, and are unavailable in an embedded app or a disk-only session. permissions.list(path) returns the direct grants on a file or folder, each with an id, the grantee (a user, role or service account, with best-effort display fields) and its permission. Pass that id to permissions.update(id, { permission }) to change the level, which returns the grant under a new id, or to permissions.revoke(id), which is safe to repeat and returns { outcome }: "revoked" when the path exists and no longer carries the grant, or "path-missing" when the file or folder is gone. Grant ids are a branded PermissionGrantId, so a nodeId cannot be passed in their place; brand an id you stored earlier with asPermissionGrantId. A folder grant is listed on the folder, not on each file under it. The same manage rule applies, and the caller must be a user (a session or a user-owned API key); service accounts are refused.

Stable ids

Cloud workspaces give every file an id that survives renames. fs.getId(path) returns it and fs.resolveId(id) returns the current path, or null once the file is gone. Store the id in anything that must outlive a rename - a link between two documents, a bookmark in app state - and read through the ById methods. Disk-only folders have no ids, so these methods report unsupported_capability there.

Watching for changes

watch returns a synchronous stop function. It polls a fresh stat sequentially, every 2500 ms unless intervalMs says otherwise. Over HTTP the interval must be at least 250 ms, and a smaller value is rejected; inside an Arg app preview the floor is 1000 ms, and a smaller value is raised to it. Polling over HTTP lasts as long as the process is alive. The first stat is the baseline, so pass emitInitial: true and do the first read in the callback: reading first and watching afterwards leaves a gap in which a write is never reported. A watcher that throws does not stop the subscription. Dispose watchers on unmount; a client’s dispose() stops every watcher it created.

Opening in Arg

fs.open(path) and fs.openById(id) ask the Arg host to open the file in its own editor (the same call is exported as host.open). Only an Arg application host can do this; a server or an agent script reports unsupported_capability.

Limits worth knowing

  • File content read or written over HTTP is capped at 32 MiB per request; a folder served from disk caps content at 8 MiB. Use the advanced files resource of the server client for large or streamed transfers.
  • A disk-served folder excludes hidden paths, symlinks and anything that is not a regular file; copy needs an unused destination, move may replace one, and remove refuses a non-empty directory.
  • Backslashes and # are never valid in a workspace path.