Skip to content

@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-fs

fileSystemSkillProvider

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;
}
OptionTypeDefaultDescription
rootsstring[]Directories scanned for <root>/<skill-name>/SKILL.md.
stalenessCheckCooldownMsnumber2000Minimum interval between root-mtime staleness checks before a possible re-scan.

Behavior

Discovery

  • Scans each root for <root>/<dir>/SKILL.md. A directory with no SKILL.md is skipped.
  • Each SKILL.md is YAML frontmatter (--- … ---) + a markdown body, validated against skillMetadataSchema.
  • The frontmatter name must equal the directory name — a mismatch is logged and the skill is skipped.
  • The open-standard allowed-tools field (string or list) is normalized to string[].
  • 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' mtime against 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.md is 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.

Released under the MIT License.