arc afs is the command group for AFS file system operations. Every subcommand operates on an AFS path, a mounted location like /src or /data, not a raw filesystem path on your machine.
Captured against arc 2.0.0-beta.50 (commit a99fb2c37, main, 2026-09-11). Run arc --version before you copy dumps; the commit is what pins the command surface.
arc afs <subcommand> [options]Run arc afs --help to see the full subcommand list. Every subcommand also accepts the global --json, --view <default|llm|human|json>, --instance / -i, and --home <dir> flags described in Overview. --yaml was removed (never implemented); use --json or --view json.
An unrecognized flag is now rejected (Unknown argument: <name>, exit 5), not silently ignored — for example arc afs ls --bogus-flag foo fails instead of running with --bogus-flag dropped.
Which instance does this talk to
arc afs needs a live instance to run against. With no flag it attaches to the default background instance (started with a bare arc service start); if none is running, every arc afs subcommand exits non-zero instead of silently falling back to a throwaway ad-hoc AFS:
$ arc afs ls /
ERROR: No AFS daemon is running for instance "default".
Start it with: arc service start
Or use --standalone for ad-hoc mode (no runtime state)--instance <name>/-i: global. Attach to a named instance instead of the default one (seearc service list). Omit fordefault--home <dir>: global. Instance root. Used byarc service start(create),--standalone(ad-hoc), andarc did init. To pick which instance, use--instance. If you pass both and they name different instances, the command fails--standalone: force ad-hoc mode — load AFS straight from the local.afs-config/config.tomlin the current directory instead of connecting to any running daemon. No runtime state (mounts you add elsewhere, live subscriptions, etc. are invisible); prints a[standalone] not attached to any instanceline to stderr as a reminder
arc service start --instance docs-demo --home ~/docs-demo # start a named instance once
arc afs ls / --instance docs-demo # every later afs call names it explicitlyReading and listing
arc afs ls
List directory contents.
Usage
arc afs ls [path] [options][path](optional, default/): the AFS path to list--depth <n>: maximum depth to list (default1)-l: long listing format, shows kind and size-R: list recursively--limit <n>: maximum number of entries to return--max-children <n>: maximum children per directory--pattern <glob>: filter entries by glob pattern
Aliased as arc afs list.
-R and an explicit --depth are mutually exclusive — -R always lists at depth 10, so combining it with --depth is ambiguous about which one wins:
$ arc afs ls /demo -R --depth 2
ERROR: ls: --depth conflicts with -R (recursive always lists at depth 10) — choose one: drop --depth to use -R's depth of 10, or drop -R and pass --depth explicitlyA path that does not exist exits 1 (not 0 with an empty list, and not 5):
$ arc afs ls /demo/does-not-exist
ERROR: No data found for path: /demo/does-not-existExample: recursive, long listing
arc afs ls /demo -l -R└── 📁 demo
├── 📄 notes.txt (fs:file) 15B
└── 📁 reports (fs:directory)
└── 📄 q1.txt (fs:file) 15Barc afs read
Read file content.
Usage
arc afs read [path] [options][path](positional, or--path <path>, one of the two is required): path to read--start-line <n>: start line, 1-indexed, inclusive--end-line <n>: end line, 1-indexed, inclusive;-1for end of file
Aliased as arc afs cat.
Example
$ arc afs read /demo/notes.txt
Hello from AFSA path that does not exist exits 1:
$ arc afs read /demo/does-not-exist.txt
ERROR: No data found for path: /demo/does-not-exist.txtarc afs stat
Get file or directory info.
Usage
arc afs stat [path][path](positional, or--path <path>, one of the two is required): path to inspect
Example
$ arc afs stat /demo/notes.txt
PATH=/demo/notes.txt
KIND=fs:file
SIZE=15
MODIFIED=2026-08-01T04:00:51.508ZA path that does not exist exits 1, same message and exit code as arc afs read:
$ arc afs stat /demo/does-not-exist.txt
ERROR: No data found for path: /demo/does-not-exist.txtarc afs search
Search for content within an AFS path.
Usage
arc afs search [path] [query][path](positional, or--path <path>, one of the two is required): path to search in[query](positional, or--query <text>, one of the two is required): search query
Aliased as arc afs grep. Not aliased as find — find was removed (it searches content, not names; to filter entries by name instead, use arc afs ls --pattern).
Example
$ arc afs search /demo revenue
/demo/reports/q1.txtarc afs explain
Explain AFS concepts or paths. With no argument it prints a general overview (mount / path / uri concepts); with a topic or an actual AFS path it explains that specifically.
Usage
arc afs explain [topic][topic]: a concept name (mount,path,uri) or an AFS path, e.g./src. Can also be passed as--topic <value>instead of positionally
Example
$ arc afs explain
AFS Overview
============
AFS (Agentic File System) is a virtual filesystem that unifies different data sources into a single namespace.
Core Concepts:
- mount: Mount a data source to a virtual path
- path: Virtual path, e.g., /src, /data
- uri: Data source address, e.g., fs://, git://, sqlite://
Data Flow:
User Path -> AFS -> /{mount} -> Provider -> Actual Data
Examples:
$ arc afs mount add /src fs:///path/to/source
$ arc afs ls /src
$ arc afs read /src/file.txtarc afs subscribe
Subscribe to AFS events under a path; prints one JSON event per line until you press Ctrl-C. Useful for watching a mount for changes made by another process (a build tool, another arc afs write, a running blocklet).
Usage
arc afs subscribe [path] [options][path](optional, default/): path prefix to watch, e.g./demoor/dev/code-agents. Can also be passed as--path <value>--type <pattern>: event type filter, e.g.afs:write,afs:*(defaultafs:write, wildcards allowed)
Example (run in one terminal, then arc afs write /demo/hello.txt ... in another)
$ arc afs subscribe /demo
Subscribed to /demo (type=afs:write) — Ctrl-C to stop
{"type":"afs:write","path":"/demo/hello.txt","source":"fs","timestamp":1787870798884}Writing and deleting
arc afs write
Write content to a file.
Usage
arc afs write [path] [content] [options][path](positional, or--path <path>, one of the two is required): path to write--content <text>: content to write--mode <mode>: one ofreplace(default),append,prepend,patch,create,update--patch <json>: JSON array of patch operations, used with--mode patch--meta <key=value>: set a metadata field, repeatable--if-match <version>: optimistic-concurrency token from a priorstat/read/write. Rejects the write withAFS_CONFLICTif the current version differs; providers that don't support it ignore the flag (last-write-wins)
Example: write, then append
$ arc afs write /demo/draft.txt --content 'first draft'
OK /demo/draft.txt
$ arc afs write /demo/draft.txt --content ' plus more' --mode append
OK /demo/draft.txt
$ arc afs read /demo/draft.txt
first draft plus morearc afs delete
Delete a file or directory.
Usage
arc afs delete [path] [options][path](positional, or--path <path>, one of the two is required): path to delete-r, --recursive: delete a directory recursively (defaultfalse)--dry-run: print what would be deleted without deleting it--yes: skip the TTY confirmation prompt (the prompt only appears when stdin is a real TTY; a non-interactivearc afs delete— a script, CI, this doc's own examples — never blocks on it either way)
Aliased as arc afs rm.
Example: preview, then delete
$ arc afs delete /demo/draft.txt --dry-run
Would delete /demo/draft.txt (dry-run)
$ arc afs stat /demo/draft.txt
PATH=/demo/draft.txt
KIND=fs:file
SIZE=21
$ arc afs delete /demo/draft.txt --yes
OK /demo/draft.txtExecuting actions
arc afs exec
Execute an action exposed by a provider at a given path, for example a provider-defined operation that isn't just a plain file read/write.
Usage
arc afs exec <executable_path> [options]executable_path(required): the action path to execute--args <json>: JSON arguments, e.g.--args '{"key": "value"}'
Not every mount exposes actions. Against a plain fs:// mount attached to a running instance, calling an action path currently surfaces as a generic server error, not a specific one — the daemon's HTTP layer doesn't propagate the underlying AFS error text for this case:
$ arc afs exec /demo/.actions/foo
ERROR: Internal server errorIn --standalone mode (no daemon in the loop) the same call gets the specific message instead:
$ arc afs exec /demo/.actions/foo --standalone
ERROR: No actions available for path: /.actions/fooMount management
arc afs mount is its own subcommand group for managing what's mounted where.
arc afs mount <subcommand> [options]arc afs mount add writes to the .afs-config/config.toml found by walking up from your current directory — not to any --instance/--home instance. --home is rejected outright (exit 5) because that flag would imply the change reaches an instance's daemon, and it never does. --instance / -i is the global instance selector: if that instance isn't running, the command fails before mount add runs. Drop --home and run from the right directory instead. To change what a running instance has mounted: cd into that instance's home directory (the one you passed to arc service start --home) before running arc afs mount add, then it takes effect for that instance immediately, no restart needed. (This is the mechanism behind the "mount add is not automatically an acceptance path" caveat on the AFS runtime boundaries page — running mount add from the wrong directory is what makes the mount show up in mount list but not in ls.)
$ arc afs mount add /demo fs:///path/to/a/local/directory --instance docs-demo
ERROR: no instance named "docs-demo". `arc service list` shows 0
$ arc afs mount add /demo fs:///path/to/a/local/directory --home /Users/you
ERROR: --home is not supported by `arc afs mount add`. `arc afs mount` only reads and writes the `.afs-config/config.toml` found by walking up from the current directory; it never reaches an instance's daemon, so the selected instance would silently not see the change. Drop the flag to edit the cwd config, or mount into a running instance at runtime with `arc attach --to <daemon-url> --namespace <ns> --source <dir>`.cd ~/docs-demo # the instance's --home directory
arc afs mount add /demo fs:///path/to/a/local/directory
arc afs ls /demo --instance docs-demo # visible right awayarc afs mount add
Add a mount.
Usage
arc afs mount add <path> <uri> [options]path(required): mount path, e.g./srcuri(required): provider URI, e.g.fs://./src--namespace <name>: mount namespace--description <text>: mount description--sensitive-args <names>: field names to treat as sensitive credentials-s, --set <key=value>: set a credential directly, repeatable, bypasses the interactive prompt--terminal: collect credentials via terminal readline instead of a browser-f, --force: force re-collecting credentials, ignoring cached values
Example
$ arc afs mount add /demo fs:///path/to/a/local/directory
Mounted fs:///path/to/a/local/directory at /demoarc afs mount list
List all mounts.
Usage
arc afs mount list [options]Aliased as arc afs mount ls. There is no --namespace filter — the cwd .afs-config/config.toml is one table with no per-namespace slice to filter by, so passing --namespace is rejected:
$ arc afs mount list --namespace anything
ERROR: --namespace is not supported by `arc afs mount list`. `arc afs mount` reads and writes the cwd `.afs-config/config.toml` as one table; there is no per-namespace slice. Drop --namespace.Example (one entry shown; your actual list will contain every mount you've added)
$ arc afs mount list
/demo -> fs:///path/to/a/local/directoryarc afs mount remove
Unmount a path.
Usage
arc afs mount remove <path> [options]path(required, positional only): mount path to remove.--helpalso lists a--pathoption marked[required], but passing it as a flag instead of positionally does not satisfy the requirement — it still fails withNot enough non-option arguments: got 0, need at least 1. Always pass the path positionally--namespace <name>: not supported —arc afs mounttreats the cwd.afs-config/config.tomlas one table with no per-namespace slice, soremove --namespace foois rejected (ERROR: --namespace is not supported by 'arc afs mount remove'), same as onmount list
Aliased as arc afs mount rm.
Example
$ arc afs mount remove /demo
Unmounted /demoPassing the path as --path instead of positionally does not work, even though --help lists it as a required option:
$ arc afs mount remove --path /demo
ERROR: Not enough non-option arguments: got 0, need at least 1arc afs mount validate
Validate the current mount configuration.
Usage
arc afs mount validateExample
$ arc afs mount validate
Configuration is validNotes on output
When an afs command talks to a running instance — the default — it writes nothing to stderr at all: the result on stdout is the whole output. Boot logging belongs to the daemon, not to your shell.
--standalone is the exception, because there the command boots AFS inside your own process and that boot log goes to your terminal. Three lines are invariant — the one naming the ad-hoc mode, one echoing which .afs-config/config.toml file(s) it read, and, whenever AFS_DID_SPACE_SCOPE_SECRET is unset, a warn record from node:boot reporting that DID Space scope de-identification is off and directory names are stored in plaintext:
[standalone] not attached to any instance — ad-hoc mode (no runtime state)
[standalone] config: /path/to/.afs-config/config.toml
{"ts":"…","level":"warn","service":"arc-node","ns":"node:boot","message":"[afs-loader] AFS_DID_SPACE_SCOPE_SECRET unset — DID Space scope de-identification is OFF (plaintext directories). Set the secret to enable; set AFS_DID_SPACE_REQUIRE_DEID=true to enforce."}Set the secret and the third line is gone; set AFS_DID_SPACE_REQUIRE_DEID=true to make its absence an error instead. Anything further on stderr is node:boot reporting on your own machine — a mount it could not establish, or a [code-agents] recover ok: ... line from the scheduler's own boot, say — so the total line count differs between hosts. Recognise the three above rather than counting them. None of it is part of the command's result, and all of it is omitted from the examples above.