Skip to content

Latest commit

 

History

History

README.md

SkillFS

中文版

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.

Rust License

Capabilities

  • Parses standard SKILL.md files.
  • Loads both flat skill directories and categorized directory layouts.
  • Uses skillfs-views.toml to choose the default view and secondary views.
  • Shows default-view skills directly in the mounted agent view.
  • Always exposes the virtual skill-discover skill so agents can discover skills from secondary views and their source paths.
  • Compiles SKILL.md on 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.md changes 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.

Behavior Matrix

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.

Scope

  • Public CLI commands are mount, stop, classify, validate, and list.
  • Skill visibility is controlled by skillfs-views.toml.
  • FUSE write passthrough is supported while mounted, but only SKILL.md changes 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.

Architecture

physical skills dir
  └─ skill-name/SKILL.md
            │
            ▼
    skillfs-core
      - parser
      - store
      - views
      - compiler
            │
            ▼
      skillfs-fuse
            │
            ▼
     mounted /skills view

Write Path And Consistency

SkillFS is a hybrid filesystem: a virtual directory view plus physical passthrough writes.

  • readdir is still controlled by the virtual view.
  • Reading SKILL.md returns compiled content, not the raw source file.
  • Other files read and write directly against the underlying filesystem.
  • Writing, creating, or writing after renaming SKILL.md reparses the file and updates SharedSkillStore.
  • mkdir and skill-directory rename take 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.

Quick Start

Build

cargo build --release

Common Commands

# 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/mountpoint

Managed Mount Mode

Default 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. stop is 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. Run skillfs stop <MOUNTPOINT> to clean residual state, processes, and mounts before starting mount --managed again.

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.

In-place Mount And Workspace Snapshots

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.

skillfs-views.toml

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:

  • /skills shows skills from the default view.
  • skill-discover/SKILL.md lists skills from secondary views and their source_path.

SKILL.md Format

---
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 value

Conditional Compilation

When 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 install
  • python -m venv -> uv venv
  • npm install -> pnpm install / yarn install

Project Layout

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

Test Scripts

  • 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 /skills exposes default-view skills.
    • Verifies that skill-discover lists secondary views and source_path.
    • Verifies passthrough reads for physical files inside a skill directory.
    • Verifies clean unmount through SIGTERM.
  • scripts/posix/run_pjdfstest.sh
    • Optional external POSIX harness; normal cargo test does not depend on it.

Test Coverage

crates/skillfs-fuse/tests/ covers:

  • compiled SKILL.md reads, 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.

Highlights

  • Virtual views are decoupled from the physical filesystem: directory visibility is view-controlled while file content still comes from the real source tree.
  • SKILL.md reads 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.

Security Integration

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> --json and then <COMMAND> resolve <skill_dir> --json.
  • Activation-file mode: --security --activation-mode file consumes .skill-meta/activation.json or user.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-mode requires SOURCE and MOUNTPOINT to 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 poll re-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 /tmp or /var/tmp: packaged agent-sec-core.service runs with PrivateTmp=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 TGID comm; 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 as meta.writeActivation and meta.setActivationXattr.

Documentation

Validation

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-deps

Contributor conventions for comments, module layout, dependencies, error handling, and commits are documented in AGENTS.md.