@helix-agents/skill-fs
Filesystem skill provider for Helix Agents. Reads Anthropic-format SKILL.md directories from disk and exposes them as a SkillProvider. Node only — uses node:fs/promises and yaml, so it is not usable on Cloudflare Workers (use inCodeSkillProvider from @helix-agents/core there).
For the conceptual overview and the 3-level progressive-disclosure model, see the Skills guide.
Installation
bash
npm install @helix-agents/skill-fsfileSystemSkillProvider
typescript
import { fileSystemSkillProvider } from '@helix-agents/skill-fs';
import { defineAgent } from '@helix-agents/core';
const agent = defineAgent({
name: 'assistant',
systemPrompt: 'You are a helpful assistant.',
llmConfig: { model },
skills: fileSystemSkillProvider({ roots: ['./skills'] }),
});FileSystemSkillProviderOptions
typescript
interface FileSystemSkillProviderOptions {
/** Directories scanned for <root>/<skill-name>/SKILL.md. */
roots: string[];
/** mtime staleness re-scan cooldown in ms. Default 2000. */
stalenessCheckCooldownMs?: number;
}| Option | Type | Default | Description |
|---|---|---|---|
roots | string[] | — | Directories scanned for <root>/<skill-name>/SKILL.md. |
stalenessCheckCooldownMs | number | 2000 | Minimum interval between root-mtime staleness checks before a possible re-scan. |
Behavior
Discovery
- Scans each
rootfor<root>/<dir>/SKILL.md. A directory with noSKILL.mdis skipped. - Each
SKILL.mdis YAML frontmatter (--- … ---) + a markdown body, validated againstskillMetadataSchema. - The frontmatter
namemust equal the directory name — a mismatch is logged and the skill is skipped. - The open-standard
allowed-toolsfield (string or list) is normalized tostring[]. - A skill that fails to parse is logged and skipped (one bad skill never breaks the rest). On a duplicate name across roots, the last root wins.
Caching & staleness
- The provider scans lazily on first use and caches the discovered skills.
- At most once per
stalenessCheckCooldownMs, it compares the roots'mtimeagainst the last scan; if a root changed, it re-scans. - The re-scan detects root-entry add/remove (a skill directory added or removed), not in-place edits to an existing skill's files. In-place edits are not picked up until restart or a touch of the root directory.
Resource reads (readResource / read_skill_file)
- Any file under the skill directory other than
SKILL.mdis surfaced as a Level-3 resource, with its skill-relative path (POSIX-style separators). - Path-traversal guard (lexical): absolute paths are rejected, and the resolved target must stay under the skill directory. The guard does NOT follow symlinks — safe for operator-provisioned skill directories.
- Binary refusal: files containing a NUL byte return
null. - Size cap: reads are capped at 64 KB; larger files are truncated with a
[... truncated, N bytes omitted; refine your range]marker. - Line ranges: optional
startLine/endLine(1-indexed, inclusive) slice the returned text.
SkillProvider interface
fileSystemSkillProvider returns the standard SkillProvider (defined in @helix-agents/core):
typescript
interface SkillProvider {
listSkills(): Promise<SkillMetadata[]>; // Level 1 — catalog
getSkill(name: string): Promise<Skill | null>; // Level 2 — body + resource listing
readResource(name: string, path: string, range?: ReadResourceRange): Promise<string | null>; // Level 3
}See the @helix-agents/core Skills reference for SkillMetadata, Skill, and ReadResourceRange.