Skip to content

Agent Skills Integration

AgentForge supports the Agent Skills specification, enabling agents to discover, activate, and use reusable skill instruction packs at runtime.

Overview

Agent Skills are markdown-based instruction packs that agents load on demand via tool calls. Each skill is a directory containing a SKILL.md file with frontmatter metadata and instructional content.

Trust Boundary

Skills can carry untrusted instructions even when script execution is blocked. Read the repository Security Policy before treating third-party skills as equivalent to trusted system guidance.

.agentskills/
├── code-review/
│   ├── SKILL.md
│   ├── references/
│   │   └── style-guide.md
│   └── scripts/
│       └── setup-linter.sh
└── test-generator/
    ├── SKILL.md
    └── references/
        └── patterns.md

Quick Start

1. Create a Skill Registry

typescript
import { SkillRegistry } from '@agentforge/skills';

const skillRegistry = new SkillRegistry({
  enabled: true,
  skillRoots: [
    { path: '.agentskills', trust: 'workspace' },
  ],
});

2. Generate System Prompt

typescript
const skillsPrompt = skillRegistry.generatePrompt();
// Returns trusted <available_skills> XML and, when present,
// a separate <untrusted_skills> section for discoverable-but-blocked roots

3. Register Activation Tools

typescript
const [activateSkill, readSkillResource] = skillRegistry.toActivationTools();

4. Wire Into Your Agent

typescript
import { createReActAgent } from '@agentforge/patterns';

const agent = createReActAgent({
  model: llm,
  tools: [...yourTools, activateSkill, readSkillResource],
  systemPrompt: `You are a helpful assistant.\n\n${skillsPrompt}`,
});

Configuration

SkillRegistryConfig

OptionTypeDefaultDescription
enabledbooleanfalseFeature flag — generatePrompt() returns '' when disabled
skillRootsArray<string | SkillRootConfig>— (required)Directories to scan for skills (required; pass [] to disable discovery)
maxDiscoveredSkillsnumberundefinedCap on skills included in prompt
allowUntrustedScriptsbooleanfalseAllow script resources from untrusted roots

Skill Root Trust Levels

Each skill root can be assigned a trust level that controls script access and whether activate-skill can expose the full SKILL.md body to the model:

typescript
const registry = new SkillRegistry({
  enabled: true,
  skillRoots: [
    { path: '.agentskills', trust: 'workspace' },   // Full trust — scripts allowed
    { path: '/org/shared', trust: 'trusted' },       // Verified — scripts allowed
    '/community/skills',                              // Untrusted (default) — scripts denied
  ],
});
Trust LevelFull Skill ActivationScript AccessUse Case
workspaceAllowedAllowedProject-local skills
trustedAllowedAllowedVerified shared skill repositories
untrustedBlocked until root promotionDeniedCommunity or unknown skill sources

TIP

Plain string roots default to 'untrusted' for security. Promote roots to 'trusted' or 'workspace' only after reviewing their contents.

Runtime Flow

Startup:
  1. new SkillRegistry({ skillRoots }) → scans folders → parses SKILL.md frontmatter
  2. skillRegistry.generatePrompt() → trusted <available_skills> XML plus optional <untrusted_skills> notice block
  3. XML injected into agent system prompt (~50-100 tokens per skill)

Runtime (agent decides):
  4. Agent reads task → sees relevant skill in prompt
  5. Agent calls activate-skill({ name: "skill-name" })
     → Returns full SKILL.md body content only for workspace/trusted roots
  6. Agent optionally calls read-skill-resource({ name: "skill-name", path: "references/guide.md" })
     → Returns referenced file content
  7. Agent follows skill instructions using its existing tools

Agent Skill Access Tools

Agent Skill access covers both instructions and supporting resources. Skill activation is the narrower operation that makes a trusted Agent Skill's instructions available for active work.

activate-skill

Loads the full body content of a skill's SKILL.md file for workspace and trusted roots.

ParameterTypeDescription
namestringSkill name (must match a discovered skill)

Returns: SKILL.md body content as markdown string for trusted roots. Untrusted roots return a trust-policy message explaining that the operator must promote the root to trusted or workspace after review.

read-skill-resource

Reads a resource file from within a skill directory.

ParameterTypeDescription
namestringSkill name
pathstringRelative path within the skill directory

Returns: File content as string. scripts/ paths and the root SKILL.md are blocked from untrusted roots.

Events

The SkillRegistry emits structured events for observability:

EventWhen
skill:discoveredSkill found and parsed during discovery
skill:warningSkill parse or validation issue
skill:activatedactivate-skill tool successfully loaded a trusted/workspace skill
skill:resource-loadedread-skill-resource tool successfully loaded a resource
trust:policy-deniedSkill activation or script access blocked by trust policy
trust:policy-allowedScript access permitted by trust policy
typescript
registry.on(SkillRegistryEvent.SKILL_ACTIVATED, (data) => {
  if (
    typeof data === 'object' &&
    data !== null &&
    'name' in data &&
    typeof (data as { name: unknown }).name === 'string'
  ) {
    console.log(`Skill activated: ${(data as { name: string }).name}`);
  } else {
    console.log('Skill activated');
  }
});

Security

Path Traversal Protection

All resource paths are validated:

  • Absolute paths rejected
  • .. path segments rejected
  • Symlink escape attempts blocked
  • Resolved path must stay within the skill directory

Trust Policy Enforcement

Script resources (scripts/ directory) are subject to trust policy checks. Non-script resources (references, assets) remain readable from any discovered root, while SKILL.md itself is protected as the full skill instruction body and is only readable from workspace or trusted roots.

See Trust Policies for the full trust model. See the repository Security Policy for the maintainer boundary on untrusted skill roots versus trusted project-owned skill content.

Feature Flag

Agent Skills uses a feature flag for progressive rollout:

typescript
// Disabled (default) — generatePrompt() returns ''
const registry = new SkillRegistry({
  skillRoots: ['.agentskills'],
});

// Enabled — generatePrompt() returns trusted <available_skills>
// and optional discoverable <untrusted_skills> entries
const registryEnabled = new SkillRegistry({
  enabled: true,
  skillRoots: [{ path: '.agentskills', trust: 'workspace' }],
});

When disabled, skills are still discovered and activation tools still work — only prompt generation is suppressed. This allows gradual rollout.

Rollout Checklist

Use this checklist when enabling Agent Skills in a production or team environment.

1. Feature-Flag Enablement

  1. Start with enabled: false (default) — skills are discovered but not surfaced to the LLM
  2. Verify discovery with registry.size() and registry.getScanErrors() before enabling
  3. Set enabled: true to activate prompt injection for trusted/workspace roots
  4. Set allowUntrustedScripts: false (default) — block untrusted script access
  5. Promote only reviewed roots to trusted or workspace if you want the model to activate their full SKILL.md bodies
typescript
const registry = new SkillRegistry({
  enabled: true,
  skillRoots: [
    { path: '.agentskills', trust: 'workspace' },
    { path: '~/.agentskills', trust: 'untrusted' },
  ],
  allowUntrustedScripts: false,
  maxDiscoveredSkills: 20,
});

2. Observability Checks

Subscribe to registry events for monitoring and alerting:

typescript
import { SkillRegistryEvent } from '@agentforge/skills';

// Log all activations
registry.on(SkillRegistryEvent.SKILL_ACTIVATED, (data) => {
  console.log('Skill activated', data);
});

// Alert on trust policy denials
registry.on(SkillRegistryEvent.TRUST_POLICY_DENIED, (data) => {
  console.warn('Trust policy denied', data);
});

// Track resource loads
registry.on(SkillRegistryEvent.SKILL_RESOURCE_LOADED, (data) => {
  console.log('Skill resource loaded', data);
});

// Monitor scan warnings
registry.on(SkillRegistryEvent.SKILL_WARNING, (data) => {
  console.warn('Skill scan warning', data);
});

TIP

For production, replace console.* calls with structured logging (e.g. createLogger from @agentforge/core) and a metrics library.

Key events to monitor:

Event (enum → emitted string)SeverityAction
SKILL_DISCOVERED (skill:discovered)InfoTrack discovery count per deploy
SKILL_ACTIVATED (skill:activated)InfoMonitor activation frequency
SKILL_RESOURCE_LOADED (skill:resource-loaded)InfoTrack resource access patterns
TRUST_POLICY_DENIED (trust:policy-denied)WarningAlert on unexpected denials
TRUST_POLICY_ALLOWED (trust:policy-allowed)InfoAudit script access from trusted roots
SKILL_WARNING (skill:warning)WarningInvestigate malformed skills

Logging namespaces (set LOG_LEVEL=debug for detailed output):

  • agentforge:skills:registry — Discovery, registration
  • agentforge:skills:activation — Activation, resource loading, trust decisions
  • agentforge:skills:scanner — Directory scanning

3. Rollback Procedure

If issues are detected after enabling Agent Skills:

  1. Immediate — Set enabled: false to suppress prompt injection (agents stop seeing skills)
  2. If activation tools are problematic — Remove activation tools from the agent's tool array
  3. If discovery causes issues — Remove skill root paths from the configuration
  4. Full rollback — Remove the SkillRegistry instantiation entirely

WARNING

Setting enabled: false only suppresses generatePrompt(). If activation tools are registered with the agent, they remain callable. Remove them from the tool array for a complete rollback.

Migration Note

If you previously passed plain string roots such as skillRoots: ['.agentskills'], those roots remain discoverable but are now treated as untrusted for prompt and activation purposes. Migrate reviewed roots to explicit objects such as { path: '.agentskills', trust: 'workspace' } or { path: '/shared/skills', trust: 'trusted' } before expecting activate-skill to expose the full SKILL.md body.

See Also

Released under the MIT License.