
# Capabilities

**What a driver supports — declared where it cannot be guessed, inferred from the methods where it can, and never faked.**

```ts
import { resolveCapabilities } from "mountx";
import type { FsCapabilities, MountxExtensions, ResolvedCapabilities } from "mountx";
```

## `FsCapabilities`

```ts
interface FsCapabilities {
  handles?: boolean; // open() returns real per-open state that survives unlink
  hardlinks?: boolean; // link() works and nlink is counted
  symlinks?: boolean; // symlink()/readlink() work; lstat differs from stat
  permissions?: boolean; // mode and ownership bits are stored and returned
  times?: boolean; // utimes() is stored and returned
  truncate?: boolean; // truncate() and FileHandle.truncate() work
  atomicRename?: boolean; // rename() replaces the destination atomically
  caseSensitive?: boolean; // names differing only in case are distinct
  statfs?: boolean; // statfs() returns meaningful numbers
  readOnly?: boolean; // every mutating operation answers EROFS
  extensions?: readonly (keyof MountxExtensions)[];
}
```

**Unset means _infer it_, never _false_.** The inference rules, member by member, are in [Writing a driver](/guide/drivers/custom#capabilities); `handles` and `atomicRename` are the two that cannot be inferred and default to `false`.

An unmet capability answers `ENOSYS`/`ENOTSUP`. It is never silently pretended — that is an invariant of the project, not a default.

## `resolveCapabilities(driver)`

```ts
function resolveCapabilities(driver: FsDriver): ResolvedCapabilities;
```

Declarations win; the presence of a method is the fallback. `ResolvedCapabilities` has every member decided, and it is what [`createLoopback()`](/reference/loopback) exposes as `fs.capabilities`.

## `MountxExtensions`

The optional `driver.mountx` namespace, for what `node:fs` genuinely does not cover: `utimens`, `mknod`, `getxattr`, `setxattr`, `listxattr`, `removexattr`.

**Types only for now** — no transport implements them yet, and transports probe for each member and degrade without it. Deliberately just the path-shaped gaps: locks, `fallocate`, `lseek` and cache-invalidation notifies are per-open-file or session-scoped, so they get designed with the session layer rather than guessed at here.

## Next

- [Loopback harness](/reference/loopback) — where you check what got resolved.
- [Driver interface](/reference/driver-interface) — the methods the inference reads.
