Skip to content

AirFS

One directory. Many repositories. No copies. ๐Ÿช„

airfs is a Go SDK โ€” and a small CLI โ€” that layers AI resource directories (agents, skills, commands, scripts) from several repositories into a single read-only merged view, served as a FUSE mount written in pure Go.


๐Ÿงฉ The problem

Your agent tooling wants every skill under one directory:

~/.ai-resources/skills/

But skills are authored in the repository that owns them โ€” one per team, per product, per concern. So you have to bridge the gap, and the usual bridges rot:

What doesn't work

  • ๐Ÿ“‹ Copying โ€” the copy drifts from the original the moment someone edits it.
  • ๐Ÿ”— Hand-made symlinks โ€” they drift from the source list instead.
  • ๐Ÿงฑ mergerfs โ€” a system binary your distribution only packages with root.

โœจ The idea

Don't move anything. Merge the directories in place and expose the result as a view. Each resource keeps living in โ€” and is edited in โ€” its own repository.

flowchart LR
    A["๐Ÿ“ฆ ai-resources<br/>skills/"]:::src
    B["๐Ÿ“ฆ ai-tools<br/>skills/"]:::src
    C["๐Ÿ“ฆ ai-maintainer<br/>skills/"]:::src

    M{{"๐Ÿช„ airfs<br/>read-only merge"}}:::mid

    V["๐Ÿ‘€ ~/.ai-resources/skills/<br/><i>merged view</i>"]:::out

    A --> M
    B --> M
    C --> M
    M --> V

    classDef src fill:#e3f2fd,stroke:#1976d2,stroke-width:2px,color:#0d47a1
    classDef mid fill:#fff3e0,stroke:#ef6c00,stroke-width:2px,color:#e65100
    classDef out fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px,color:#1b5e20

Edit a file in its repository โ†’ the change is visible through the view immediately. No sync step, no copy to refresh. ๐Ÿ”„


๐Ÿ—‚๏ธ The vocabulary

Five words carry the whole model.

  • ๐Ÿ“ฆ Source

    One contributing directory tree โ€” normally a git working copy. Sources are an ordered list, and that order is the precedence order.

  • ๐Ÿท๏ธ Kind

    A category of resource = one subdirectory name: agents, skills, commands, scripts. The set is fixed and built in, so unrelated top-level directories can never leak into the view.

  • ๐Ÿ“„ Entry

    One resource inside a kind, named directly under it โ€” a directory like a skill, or a single file like a command. The entry is what collides and what gets shadowed, and it is shadowed whole.

  • ๐Ÿฅž Stratum

    One source's contribution to one kind โ€” <source>/<kind>/. A kind's view is the ordered stack of its strata.

  • ๐ŸŽฏ Target

    The resource folder the view lives under โ€” ~/.ai-resources by default. It holds the configuration file and one mounted subdirectory per kind.


๐Ÿฅ‡ Precedence: latest source wins

Sources are declared from the most general to the most specific โ€” global, then organisation, then project. When two repositories both ship a skill named commit, the one declared last wins, and it wins whole โ€” no half-merged resource assembled from two places.

flowchart TB
    subgraph S["Declared order (last wins)"]
        direction LR
        S1["1๏ธโƒฃ global<br/>commit โŒ shadowed<br/>review โœ…"]:::mix
        S2["2๏ธโƒฃ organization<br/>deploy โœ…"]:::win
        S3["3๏ธโƒฃ project<br/>commit โœ…<br/>audit โœ…"]:::win
    end

    S --> R["๐Ÿ‘€ Merged view<br/>commit ยท review ยท deploy ยท audit"]:::out

    classDef win fill:#e8f5e9,stroke:#2e7d32,color:#1b5e20
    classDef mix fill:#fff8e1,stroke:#f9a825,color:#f57f17
    classDef out fill:#e3f2fd,stroke:#1976d2,stroke-width:2px,color:#0d47a1

Precedence is independent per kind: a source can win commit under skills while losing commit under commands.

Shadowing is always reported, never silent

airfs sources lists every shadowed entry with its winner and its losers. A silent shadow is the failure mode that makes a merged view untrustworthy โ€” you edit a file, nothing happens, and nothing tells you why. ๐Ÿ•ต๏ธ

The view is read-only

Writes are rejected, not routed to a source โ€” and the kernel enforces it, so no process can write through the mount even by mistake. A new file in the merged view belongs to some repository and the view has no basis to pick one; a write that succeeded would bypass that repository's git history, review, and tests. Edit in the source repo. โœ๏ธ


๐Ÿšช How the view is exposed

One FUSE mount per kind, all served by one process:

~/.ai-resources/
  sources.txt     # the ordered layers โ€” never masked by a mount
  agents/         # mountpoint
  skills/         # mountpoint
  commands/       # mountpoint
  scripts/        # mountpoint

airfs mount establishes them together and blocks while serving; --detach runs it as a daemon instead. airfs umount releases them โ€” including a stale mountpoint left behind by a serving process that died.

Mounting needs /dev/fuse and a setuid fusermount3, both of which ship with your distribution's FUSE package. Not sure you have them? Run airfs doctor โ€” it checks the host and names the package to install. ๐Ÿฉบ


โš™๏ธ Configuring it

One plain-text file at the root of the target, one path per line. The most common diff is a single added line.

# ~/.ai-resources/sources.txt โ€” order is precedence, last wins
~/sylvan/ai-resources      # 1st โ€” global
~/sylvan/ai-tools          # 2nd
$WORK/ai-maintainer        # 3rd โ€” wins every collision

Comments, ~, and $VAR are expanded; relative paths resolve against the config file's own directory, never the working directory. An unset variable or a missing source directory is an error, not a shrug โ€” a view quietly missing a repository is the harder failure to diagnose. ๐Ÿšง


๐Ÿ› ๏ธ The commands

Command Does
sources ๐Ÿ” Resolve the config and report it: order, counts per kind, shadowing. Touches nothing.
mount ๐Ÿงต Serve the merged view under the target, one mount per kind. --detach to daemonise.
umount ๐Ÿงน Release the mounts, including stale ones.
status ๐Ÿ“Š Whether the target is served, live or stale โ€” and what's visible through it.
doctor ๐Ÿฉบ Check /dev/fuse and fusermount3, and say what to install.

๐Ÿšง Status

Implemented

Every spec in docs/specs/ is implemented: the library and the airfs command exist, and the merge, the mount, and the CLI are covered by tests. airfs replaces a mergerfs-based Makefile setup in ai-resources.

No implementation change lands without an agreed spec.

๐Ÿ‘‰ Where next

  • ๐Ÿš€ Get started โ€” install and first mount, in five minutes
  • ๐Ÿ“š User guide โ€” layers, precedence, mounting, the Go API
  • ๐Ÿ“ Specs โ€” the model, the merge, the mount, the CLI
  • ๐Ÿค Contribute โ€” setup, targets, and quality gates