SkillFS is a local FUSE filesystem for agent skills. It parses SKILL.md,
organizes skills with views, and exposes compiled SKILL.md content through a
mounted filesystem while ordinary skill files remain backed by the source tree.
- Parses standard
SKILL.mdfiles. - Loads both flat skill directories and categorized directory layouts.
- Uses
skillfs-views.tomlto choose the default view and secondary views. - Shows default-view skills directly in the mounted agent view.
- Always exposes the virtual
skill-discoverskill so agents can discover skills from secondary views and their source paths. - Compiles
SKILL.mdon read, including conditional blocks and command normalization. - Passes ordinary files and subdirectories through to the physical source tree.
- Supports normal mounts and in-place mounts.
- Supports physical write passthrough while mounted;
SKILL.mdchanges reparse and update the in-memory store. - Provides a Linux POSIX compatibility baseline for ordinary passthrough paths:
fd-backed I/O, create/mkdir mode handling, long-path fallback,
open-after-unlink handles, restricted symlink/hardlink policy, FIFO creation,
and conservative
user.*xattr passthrough. - Provides optional external security integration surfaces: decision-command activation, activation file/xattr consumption, notify socket events, protocol JSONL events, active-mapping reload, startup reconcile, trusted writer identity checks, trusted control socket writes, and managed mount recovery.
| Operation | Normal mount | In-place mount | Notes |
|---|---|---|---|
readdir |
Virtual view | Virtual view | Visibility comes from views plus the store. |
Read SKILL.md |
Compiled output | Compiled output | Uses compiler::compile. |
| Read other files | Passthrough | Passthrough | Reads the physical source file. |
Write SKILL.md |
Passthrough + store reparse | Passthrough + store reparse | Directory name is the authoritative store key. |
create ordinary file |
Passthrough | Passthrough | Does not update the store. |
mkdir skill directory |
Immediately visible | Immediately visible | Inserts a degraded placeholder before async reparse. |
rename skill directory |
Visibility switches immediately | Visibility switches immediately | Old name is removed without a visibility gap. |
unlink SKILL.md |
Removes from store | Removes from store | Skill disappears from the virtual view. |
rmdir skill directory |
Removes from store | Removes from store | Also clears inode mappings. |
setattr(size) |
Truncate supported | Truncate supported | Other metadata operations are conservative passthrough where allowed. |
symlink |
Restricted passthrough | Restricted passthrough | Allows relative same-skill targets only. |
link |
Restricted passthrough | Restricted passthrough | Allows same-skill regular files only. |
mkfifo |
Passthrough | Passthrough | FIFO only; device/socket nodes are rejected. |
xattr user.* |
Passthrough | Passthrough | Ordinary passthrough paths only. |
- Public CLI commands are
mount,stop,classify,validate, andlist. - Skill visibility is controlled by
skillfs-views.toml. - FUSE write passthrough is supported while mounted, but only
SKILL.mdchanges trigger store synchronization. - The authoritative skill key is the directory name, not a stale frontmatter
name:after rename. - In-place mounting over-mounts the source directory. Controlled skill writes through SkillFS are supported, but tools that rename or replace the mounted directory itself, such as workspace checkpoint/init/rollback tools, must run before mounting or after unmounting.
physical skills dir
└─ skill-name/SKILL.md
│
▼
skillfs-core
- parser
- store
- views
- compiler
│
▼
skillfs-fuse
│
▼
mounted /skills view
SkillFS is a hybrid filesystem: a virtual directory view plus physical passthrough writes.
readdiris still controlled by the virtual view.- Reading
SKILL.mdreturns compiled content, not the raw source file. - Other files read and write directly against the underlying filesystem.
- Writing, creating, or writing after renaming
SKILL.mdreparses the file and updatesSharedSkillStore. mkdirand skill-directoryrenametake an immediate-consistency path by synchronously updating the store, with async reparse later replacing the placeholder with the real entry.- In-place mounts use
/proc/self/fd/{n}to reach the underlying source and avoid recursively entering the FUSE over-mount.
cargo build --release# Validate skills.
cargo run -p skillfs -- validate /path/to/skills
# List skills.
cargo run -p skillfs -- list /path/to/skills
# Generate or inspect skillfs-views.toml.
cargo run -p skillfs -- classify /path/to/skills
# Mount the FUSE filesystem.
cargo run -p skillfs -- mount /path/to/skills /path/to/mountpoint
# Opt-in managed mount: a detached supervisor keeps the mount alive.
cargo run -p skillfs -- mount /path/to/skills /path/to/mountpoint --managed
# Stop a managed mount and clear desired mounted state.
cargo run -p skillfs -- stop /path/to/mountpointDefault mount, including --foreground, keeps the original foreground
behavior: the process blocks, and SIGTERM or Ctrl+C cleanly unmounts. If the
launcher process, such as a gateway, restarts and terminates its child
processes, the mount disappears with it.
--managed is opt-in and is intended for mounts that should survive gateway
restarts:
- The client writes managed state, starts a detached supervisor in its own
session with
setsid, waits for readiness, and then returns. - The supervisor starts a foreground FUSE worker with the same source, mountpoint, config, security, audit, activation, trusted-writer, control socket, and logging options.
- If the worker exits unexpectedly while desired state remains
mounted, the supervisor remounts after bounded backoff. - Only
skillfs stop <MOUNTPOINT>clears desired mounted state, terminates the supervisor/worker, and unmounts.stopis idempotent and can be run safely on an already-unmounted path. - If the supervisor is killed with
kill -9, an orphan worker may continue to serve the mount without monitoring. Runskillfs stop <MOUNTPOINT>to clean residual state, processes, and mounts before startingmount --managedagain.
Managed state is stored in a user-isolated runtime directory: first
$XDG_RUNTIME_DIR/skillfs/, then /run/user/<uid>/skillfs/, and when neither
is available it falls back to /tmp/skillfs-<uid>/. The instance id is derived
from the normalized mountpoint, so mount and stop always resolve the same
mountpoint to the same instance.
When SkillFS is mounted in-place, tools that replace the mountpoint directory
itself must run before mounting or after unmounting. For example,
ws-ckpt checkpoint -w <MOUNTPOINT> may fail with Device or resource busy if
<MOUNTPOINT> is an active SkillFS mount.
Writes through SkillFS, including skill install/update/remove, remain supported while mounted.
Skill selection is controlled by skillfs-views.toml:
[[view]]
name = "major"
default = true
description = "Skills shown directly in /skills"
skills = ["github", "notion", "slack"]
[[view]]
name = "other"
default = false
description = "Skills exposed via skill-discover"
skills = ["apple-notes", "blogwatcher"]After mounting:
/skillsshows skills from the default view.skill-discover/SKILL.mdlists skills from secondary views and theirsource_path.
---
name: my-skill
description: Brief description
version: 1.0.0
tags: [tooling, example]
enabled: true
---
# My Skill
Detailed instructions.
## Parameters
- `input` (string, required): Input value
- `options` (object, optional): Extra options
## Returns
- `result` (string, required): Result valueWhen FUSE reads SKILL.md, SkillFS runs compiler::compile and supports:
<!-- @if os == darwin --><!-- @if has_command("uv") --><!-- @else --><!-- @endif -->
When there are no conditional blocks, SkillFS also applies a small set of heuristic command normalizations, for example:
pip install->uv pip installpython -m venv->uv venvnpm install->pnpm install/yarn install
crates/
skillfs-core/ parser, store, views, compiler, env, watcher
skillfs-fuse/ FUSE filesystem and POSIX passthrough layer
skillfs-cli/ mount / stop / classify / validate / list
docs/specs/ implementation specifications
docs/security/ external decision and runtime activation docs
docs/testing/ POSIX acceptance and external harness docs
docs/skills/ bundled agent-facing SkillFS skill
scripts/ build.sh, test.sh, and optional POSIX harness
- scripts/build.sh
- Runs the workspace build.
- scripts/test.sh
- Creates a temporary skill source directory and
skillfs-views.toml. - Verifies that the FUSE mount starts.
- Verifies that
/skillsexposes default-view skills. - Verifies that
skill-discoverlists secondary views andsource_path. - Verifies passthrough reads for physical files inside a skill directory.
- Verifies clean unmount through
SIGTERM.
- Creates a temporary skill source directory and
- scripts/posix/run_pjdfstest.sh
- Optional external POSIX harness; normal
cargo testdoes not depend on it.
- Optional external POSIX harness; normal
crates/skillfs-fuse/tests/ covers:
- compiled
SKILL.mdreads, write passthrough, store reparse, mkdir/rename/unlink/rmdir visibility, and stale-frontmatter regressions for normal and in-place mounts; - POSIX open/create, metadata, directory streams, long-path fallback,
open-after-unlink, safe symlink/link/FIFO, and
user.*xattrs; .skill-meta, lifecycle namespaces, security mode, audit runtime, source drift, install inbox, staging/direct install flows, trusted writer, trusted metadata view, activation consumer, control socket server behavior, notify, runtime reload, startup reconcile, and post-publish grace paths.
crates/skillfs-cli/tests/ covers CLI parsing and startup gates, including
managed mount supervision, activation/notify option compatibility, backing-root
requirements, trusted writer executable validation, and control-socket trusted
peer configuration.
skillfs-core covers parser, store, compiler, and watcher behavior with unit
and integration tests.
- Virtual views are decoupled from the physical filesystem: directory visibility is view-controlled while file content still comes from the real source tree.
SKILL.mdreads and writes are intentionally split: agents read compiled content, while writes update the raw source file.- Directory name is the unified authoritative skill key after rename, avoiding stale frontmatter reinjection under the old skill name.
- In-place mounts use a pre-opened source dir fd so SkillFS can write through without recursively entering its own FUSE mount.
- Active mapping can expose
/skills/<name>as current source, trusted snapshot, or hidden, and open file handles keep their open-time target pinned.
SkillFS does not perform scanning, signing, or risk decisions inside the filesystem core. An external provider decides whether a skill is exposed as:
current: serve the live source tree;fallback: serve a trusted.skill-meta/versions/*.snapshot;hidden: hide the skill from the agent-facing view.
Two integration paths are supported:
- Legacy decision-command mode:
--security --decision-command <COMMAND>runs<COMMAND> scan <skill_dir> --jsonand then<COMMAND> resolve <skill_dir> --json. - Activation-file mode:
--security --activation-mode fileconsumes.skill-meta/activation.jsonoruser.agent_sec.skill_ledger.activation, sends notify events to an external daemon when configured, and reloads active mappings when activation changes.
Related security surfaces:
.skill-meta/**is hidden from untrusted lookup/list/read paths and ordinary mutation attempts are rejected. Trusted exact-path access can route to the live source for metadata operations.--audit-log <PATH>writes stable JSONL audit events.--security-moderequiresSOURCEandMOUNTPOINTto resolve to the same directory so normal userspace access goes through FUSE policy and audit./.skillfs-inbox/<skill>/...is an install/repair entry point for hidden or new skills; writes land in the source tree and completion can trigger the external security flow.--notify-socket <PATH>sends debounced skill mutation notifications to an external daemon.--activation-events-log <PATH>writes activation protocol events as JSONL.--activation-reload-mode pollre-reads activation state after notify events and updates the resolver without a remount.- Startup reconcile sends best-effort notifications for known skills after mount startup.
--ledger-backing-root <PATH>provides a daemon-visible source view for in-place activation/notify mounts, because the public source path is a FUSE over-mount. Use/run/user/$UID/skillfs-ledger/...or/run/skillfs-ledger/...for daemon-facing roots. Do not use/tmpor/var/tmp: packagedagent-sec-core.serviceruns withPrivateTmp=true, so host tmp paths are invisible to the daemon and are rejected at startup.--trusted-writer-exe <PATH>is the recommended mount-path trusted writer gate. It verifies/proc/<tgid>/exe,(dev, ino), and process start time to reduce PID-reuse and process-name spoofing risk.--trusted-writer <NAME>is a deprecated compatibility gate based on Linux TGIDcomm; process names can be spoofed and this should not be used for production trust.--control-socket <PATH>with--trusted-peer-exe <PATH>starts a trusted Unix socket control plane. Trusted peers can write activation JSON or xattr through methods such asmeta.writeActivationandmeta.setActivationXattr.
- docs/specs/skillfs-spec.md - Architecture, runtime consistency boundaries, and deployment scenarios.
- docs/specs/core-spec.md -
skillfs-coreimplementation. - docs/specs/fuse-spec.md -
skillfs-fuseimplementation. - docs/specs/posix-phase1-spec.md - POSIX passthrough baseline.
- docs/testing/posix-phase1-acceptance.md
- POSIX acceptance checklist.
- docs/testing/posix-external-harness.md
- External POSIX harness usage.
- docs/security/external-decision-protocol.md
- Decision-command JSON protocol.
- docs/security/runtime-activation-implementation-plan.md
- Activation, notify, reload, and backing-root integration.
- docs/skillfs-filesystem-capability-record.md
- Long-lived filesystem capability record.
- POSIX_FS_TEST_MATRIX.csv - POSIX test matrix and current coverage.
- POSIX_FS_REFERENCES.md - POSIX, FUSE, and project references.
These commands are CI-equivalent checks. Run them before PR submission when touching SkillFS code.
# 1. Formatting: must produce no diff.
cargo fmt --all --check
# 2. Clippy: must be warning-free under -D warnings.
cargo clippy --workspace --all-targets -- -D warnings
# 3. Unit and integration tests in the workspace.
cargo test --workspace
# 4. End-to-end FUSE mount test. Requires fuse3 and /dev/fuse; skips itself
# on macOS or containers without /dev/fuse.
scripts/test.sh
# 5. Rustdoc. Required when changing public API or doc comments; useful for
# catching broken intra-doc links early.
cargo doc --workspace --no-depsContributor conventions for comments, module layout, dependencies, error handling, and commits are documented in AGENTS.md.