Skip to content

Get started ๐Ÿš€

Install airfs, declare two layers, and read them as one directory. About five minutes, ending with a working workspace you can keep.

1. Install ๐Ÿ“ฆ

airfs links no C library, so installing is one command and needs no toolchain beyond Go:

go install github.com/sylvanld/airfs/cmd/airfs@latest

Make sure $(go env GOPATH)/bin is on your PATH, then check it runs:

airfs help

No Go on this machine?

Every release ships a prebuilt binary for Linux and macOS on amd64 and arm64. One command picks the right one, checks it against the published SHA-256, and installs it into ~/.local/bin โ€” no toolchain, no root:

curl -fsSL https://raw.githubusercontent.com/sylvanld/airfs/main/scripts/get-airfs.sh | sh

Two environment variables change what it does:

curl -fsSL https://raw.githubusercontent.com/sylvanld/airfs/main/scripts/get-airfs.sh \
  | AIRFS_VERSION=v0.1.0 AIRFS_INSTALL_DIR=/usr/local/bin sh

AIRFS_VERSION installs a specific release tag instead of the latest, and AIRFS_INSTALL_DIR chooses where the binary lands โ€” a system-wide directory needs a sudo you type yourself, since the script never asks for one.

Prefer doing it by hand? The archives and their checksums.txt are on the releases page; unpack the one for your platform and install -m 755 airfs ~/.local/bin/airfs.

2. Check the host ๐Ÿฉบ

Mounting needs two things an unprivileged process cannot provide for itself: /dev/fuse, and a setuid fusermount3. Both ship with your distribution's FUSE package and are already present on a normal desktop Linux.

Now that airfs is installed, ask it โ€” before installing anything else:

airfs doctor
  ok       /dev/fuse      readable and writable by you
  ok       fusermount3    /usr/bin/fusermount3, setuid

Every mount prerequisite is satisfied.

If something is missing, doctor names the package that provides it and exits 2. Install it with your package manager โ€” fuse3 on Debian, Ubuntu, Fedora, and Arch โ€” then run airfs doctor again.

Why airfs will not install it for you

Installing a system package needs root, and a tool that asks you for root to run a package manager is a tool that should have printed the command instead.

3. Create a workspace ๐Ÿ—‚๏ธ

A workspace is an ordinary directory holding one plain-text file. The default is ~/.ai-resources, which is where agent tooling usually looks:

mkdir -p ~/.ai-resources

For this walkthrough, two layers โ€” a personal one and a project one:

mkdir -p ~/ai/personal/skills/commit ~/ai/personal/skills/review
mkdir -p ~/ai/project/skills/commit

echo "personal commit skill" > ~/ai/personal/skills/commit/SKILL.md
echo "personal review skill" > ~/ai/personal/skills/review/SKILL.md
echo "project commit skill"  > ~/ai/project/skills/commit/SKILL.md

In real use these are git working copies you already have โ€” nothing about a layer is airfs-specific, and airfs never writes into one.

4. Declare the layers โœ๏ธ

One path per line, in ~/.ai-resources/sources.txt. The order is the precedence order: the last line wins. Declare from the most general to the most specific.

cat > ~/.ai-resources/sources.txt <<'EOF'
# Layers, most general first โ€” the last declaration wins.
~/ai/personal
~/ai/project
EOF

Now ask airfs what that file means, before mounting anything:

airfs sources
target  /home/you/.ai-resources
config  /home/you/.ai-resources/sources.txt

Sources, in precedence order โ€” the last declaration wins:
  1. ~/ai/personal  agents 0  skills 2  commands 0  scripts 0
  2. ~/ai/project   agents 0  skills 1  commands 0  scripts 0

Empty kinds: agents, commands, scripts

Shadowed entries โ€” the winner is what the view serves:
  skills/commit  wins ~/ai/project  over ~/ai/personal

Both layers ship a commit skill, so one has to lose. The report says which, by name โ€” the point being that shadowing is never silent. sources reads and reports only; it mounts nothing.

Where did the empty kinds come from?

airfs creates the missing agents/, commands/, and scripts/ directories inside each layer, so that every layer contributes every kind and adding a resource of a new kind never needs a mkdir first.

5. Mount it ๐Ÿงต

airfs mount --detach
Serving /home/you/.ai-resources from 2 sources:
  1. ~/ai/personal
  2. ~/ai/project

Serving in the background. Stop it with: airfs umount --target /home/you/.ai-resources

Without --detach, airfs mount blocks in the foreground and unmounts on Ctrl+C โ€” which is what you want from a service manager unit, or while you are still experimenting.

6. Read the merged view ๐Ÿ‘€

ls ~/.ai-resources/skills
commit  review

One directory, both layers. And the winner won whole:

cat ~/.ai-resources/skills/commit/SKILL.md
project commit skill

Now the part that makes this worth doing โ€” edit the file in its repository and read it again through the view:

echo "edited in place" > ~/ai/project/skills/commit/SKILL.md
cat ~/.ai-resources/skills/commit/SKILL.md
edited in place

No sync step, no remount. The view holds no copy and caches nothing; it reads through to the file you just edited. Adding a whole new skill to a layer works the same way โ€” it appears in the listing immediately.

The other direction is refused, by the kernel rather than by convention:

touch ~/.ai-resources/skills/new.md
touch: cannot touch '/home/you/.ai-resources/skills/new.md': Read-only file system

A new file in the merged view would belong to some layer, and the view has no basis to pick one. Create it in the repository that owns it.

7. Check and stop ๐Ÿ“Š

airfs status
target  /home/you/.ai-resources

  agents    served, 0 entries
  skills    served, 2 entries
  commands  served, 0 entries
  scripts   served, 0 entries

status exits 0 when the target is fully served and 2 when it is not, so a shell profile can branch on it without reading the prose.

airfs umount
Released /home/you/.ai-resources/agents
Released /home/you/.ai-resources/skills
Released /home/you/.ai-resources/commands
Released /home/you/.ai-resources/scripts

Where next ๐Ÿ‘‰

  • ๐Ÿ“š User guide โ€” layers, precedence, mounting, the Go API
  • ๐Ÿงญ Declaring layers โ€” the full file format
  • ๐Ÿฉน Troubleshooting โ€” when something is not served
  • ๐Ÿ“ Specs โ€” why it behaves the way it does