---
title: Ops are Fingers
description: Why Mirage treats each filesystem op as a single finger on the Hand, and how commands are compositions of fingers.
icon: hand-point-up
---

## Fingers Are The Primitive Gestures

<Icon icon="hand" /> **[Hands](/home/design/hands)** are how agents act. **Fingers** are the smallest gestures a hand can make.

In Mirage, fingers are ops: `read`, `readdir`, `stat`, `write`, `mkdir`, `unlink`, `rename`. Each one is a single primitive action, and each one maps cleanly to exactly one kind of backend call (S3 `GetObject`, `list_objects_v2`, `HEAD`, `PutObject`, and so on). They are the atoms of filesystem behavior.

A higher-level command like `cat`, `grep`, or `cp` is not itself a finger. It is a *phrase* of fingers the Hand strings together.

## The Finger Set

| Finger | Gesture | Typical backend call |
| ------ | ------- | -------------------- |
| `read` | pull bytes from a path | `GetObject`, file read |
| `readdir` | list children of a directory | `list_objects_v2`, `scandir` |
| `stat` | feel for shape (size, type, mtime) | `HEAD`, `stat` |
| `write` | put bytes at a path | `PutObject`, file write |
| `mkdir` | make a directory | `mkdir`, prefix marker |
| `unlink` | remove a file | `DeleteObject`, `unlink` |
| `rename` | move a path | `CopyObject` + `DeleteObject` |
| `create` | lay down an empty file | zero-byte `PutObject`, `touch` |
| `truncate` | cut a file to zero bytes | `PutObject` empty, `truncate` |
| `append` | add bytes at the end | multipart append, file append |

Each finger's contract is narrow on purpose: a single path, a well-defined input, a well-defined output. Narrow contracts are what let any finger move against any [Eye](/home/design/eyes) without special casing.

## Fingers Are Fundamental Infrastructure

The Fingers layer has two pieces:

- <Icon icon="folder-tree" /> **[Ops](/home/design/vfs)**, the primitive gestures themselves, dispatched through the mount table to the right resource.
- <Icon icon="hard-drive" /> **[FUSE](/home/design/fuse)**, a way to expose those same gestures to any process on the host through POSIX. Any shell, editor, or subprocess becomes a legitimate user of fingers, not just Mirage's own dispatcher.

Both are fundamental in the literal sense: everything above them, every [Gesture](/home/design/gestures), every pipeline, every agent plan, is built on top. Backends only need to implement fingers to become part of Mirage. FUSE then takes those fingers and makes them usable by anything POSIX understands.

## Why This Foundation Matters

A small set of fingers supports an unbounded set of gestures above it. Add a backend: implement the finger contract and every existing [Gesture](/home/design/gestures) in the catalog, `cat`, `grep`, `cp`, `jq`, works against it automatically. Add a gesture: it runs against every existing backend for free. The catalog grows without churning the resources, and the resources grow without changing the catalog.

This is the concrete mechanism behind Mirage's *N + M* promise. Fingers are the small M-side interface every backend speaks. Gestures are the N-side catalog agents draw from. They never multiply into N × M adapters because they don't talk to each other; they both talk to fingers.

## Related

- [Ops](/home/design/vfs), how fingers are dispatched through the mount table to resources.
- [FUSE](/home/design/fuse), how fingers get exposed to external processes via POSIX.
- [Gestures](/home/design/gestures), what Mirage builds on top of fingers.
- [Hands](/home/design/hands), the higher-level metaphor fingers belong to.
