# Filesystem
The `fs/` namespace is the stdlib's whole-file and path layer: read, write,
list, inspect, and watch files and directories. It is compiled into every
runtime and needs no import. Paths whose leading segment names a VFS mount
route to that mount's driver instead of the native filesystem — see
VFS. For line-oriented I/O on an open file (rather
than whole-file reads and writes), use the bare channel functions `open`,
`puts`, `gets`, and `close` from I/O.
Read/stat/list calls also resolve import/package paths: when a path
whose leading segment(s) name an import mount (e.g.
`deft/help/manual/01-Language/...`) doesn't exist as a literal path, it is
resolved through the same probe `import`/`import/resolve` use — including
package-root assets such as `manual/` and `docs/` that sit beside `src/`.
The same logical path therefore works from any working directory, in dev
checkouts and installed package trees; an existing native path always wins.
## Functions
### Reading and writing
| Function | Purpose |
|---|---|
| `fs/read "path"` | Read a file's contents as a string: `%Ok{:value "..."}`; `%Err` on failure |
| `fs/write "path" "content"` | Write a string to a file, creating or truncating it (`%Ok{:value true}` / `%Err`) |
| `fs/append "path" "content"` | Append a string to a file (`%Ok{:value true}` / `%Err`) |
| `fs/read-lines "path"` | Read a file as a vector of lines (`%Ok`; a final newline is not an extra line) |
| `fs/write-lines "path" @{...}` | Write a vector of lines, one newline per line (`%Ok{:value true}` / `%Err`) |
| `fs/copy "from" "to"` | Copy a file; `%Ok{:value true}` on success (read + write, so it composes across VFS mounts) |
| `fs/rename "from" "to"` | Rename or move a file (`%Ok{:value true}` / `%Err`; same mount) |
| `fs/remove "path"` | Remove a file or empty directory (`%Ok{:value true}` / `%Err`) |
| `fs/link "target" "link-path"` | Create a symlink at `link-path` pointing to `target` (`%Ok{:value true}` / `%Err`; native only) |
| `fs/mkdir "path"` | Create a directory and any missing parents; idempotent (`%Ok{:value true}` / `%Err`) |
### Metadata and predicates
| Function | Purpose |
|---|---|
| `fs/exists? "path"` | True when the path exists |
| `fs/file? "path"` | True when the path exists and is not a directory |
| `fs/dir? "path"` | True when the path is a directory |
| `fs/absolute? "path"` | True for absolute paths and mount-anchored paths |
| `fs/stat "path"` | `%Ok` with `%{ :size N :is-dir bool :modified ms }`; mtime in epoch milliseconds |
| `fs/list "path"` | `%Ok` with a vector of `%{ :name str :is-dir bool :kind str }` entries |
| `fs/readdir "path"` | `%Ok` with a vector of entry names (strings) only |
| `fs/glob "path" "pattern" ?opts` | Files whose basename matches `*`/`?`, as `%Ok` with `%{ :path dir :file name }` maps; `%{ :recurse true }` (or `--recurse`) walks subdirectories |
### Path helpers
| Function | Purpose |
|---|---|
| `fs/join "a" "b" ...` | Join components with `/` |
| `fs/abs "path"` | Absolute path; mount-anchored paths pass through unchanged |
| `fs/dir "path"` | Directory portion (`"."` when there is none) |
| `fs/base "path"` | Filename portion |
| `fs/ext "path"` | Extension including the dot (`.txt`), empty when there is none |
### Host and scratch paths
| Function | Purpose |
|---|---|
| `fs/tempdir` | System temp directory (`$TMPDIR`, else `/tmp`) |
| `fs/home` | Home directory (`$HOME`; `nil` when unset) |
| `fs/tmp-dir` | Per-process scratch directory `/tmp/deft-<pid>/`, created on first call |
| `fs/tmp-path ?file` | The scratch directory, or a path inside it when given a filename |
| `fs/local-path "sub" "file"` | Conventional `.deft/local/<sub>/<file>` path; does not create directories |
| `fs/local-dir "sub"` | `.deft/local/<sub>`, created (with parents) if needed; idempotent |
### Watching
| Function | Purpose |
|---|---|
| `fs/watch "path" callback` | Watch a file or directory (recursive) and return `%Ok` with a numeric watch-id |
| `fs/unwatch $id` | Cancel a watch; true when a watch was removed |
Notes:
- The whole-file verbs return `%Ok{:value ...}` on success and
`%Err{:message}` on failure: data verbs wrap their payload
(`%Ok{:value "..."}`, `%Ok{:value list}`), mutation verbs wrap `true`
(`%Ok{:value true}`). Unwrap with `ok!`, `unwrap`, `match`, or `err?` —
or call the predicates (`fs/exists?`, `fs/file?`, `fs/dir?`,
`fs/absolute?`), which return booleans instead.
- `fs/watch` invokes its callback with a flag keyword — `:created`,
`:modified`, or `:removed` — and the changed path. Handlers fire only
while the event loop pumps (`vwait`, `update`, servers), the same
contract as `[after]` and network callbacks.
- VFS routing applies to the whole-file verbs and metadata calls;
`fs/watch`, `fs/link`, and recursive `fs/glob` are local-only. The
host-path helpers (`fs/tempdir`, `fs/home`, `fs/tmp-dir`, `fs/tmp-path`,
`fs/local-path`, `fs/local-dir`) stay host-local by design. Details in
VFS.
## Examples
### Write and read a file
def path "/tmp/deft-notes/notes.txt" fs/mkdir [fs/dir $path] fs/write $path "first line\nsecond line\n" echo "contents:" [unwrap [fs/read $path]] each [unwrap [fs/read-lines $path]] {|line| echo "line:" $line }
### List a directory
each [unwrap [fs/readdir "packages/help/docs"]] {|name| echo $name } for entry in [unwrap [fs/list "packages/help/docs"]] { echo $entry~name "dir?" $entry~is-dir "kind" $entry~kind }
`fs/readdir` gives names only; `fs/list` gives `%{ :name :is-dir :kind }`
maps. `fs/glob` searches by basename and can recurse:
def hits [unwrap [fs/glob "packages/help/manual" "*.md" %{ :recurse true }]] each $hits {|hit| echo [fs/join $hit~path $hit~file] }
### Build paths with fs/join
set root [fs/tempdir] set out [fs/join $root "deft-exports" "report.txt"] echo "dir:" [fs/dir $out] "base:" [fs/base $out] "ext:" [fs/ext $out] # dir: /tmp/deft-exports base: report.txt ext: .txt
### Watch a directory
def wid [unwrap [fs/watch "www" {|flag file| echo $flag $file }]] # ... the event loop runs (vwait / sleep / server) ... [fs/unwatch $wid]
## See Also
- I/O — channels and the bare `open` / `puts` / `gets` / `close` verbs
- VFS — mount routing behind the `fs/` namespace
- OS — subprocess and environment helpers
- Data Formats — `yaml/load` reads through the filesystem