- Three-phase plan for skills system improvements - Phase 1: Command Dispatch (flynn skills CLI commands) - Phase 2: Skills Watcher (auto-reload with chokidar) - Phase 3: Installer Specs (auto-install brew/node/go/download) - Model strategy: glm-4.7-flash for mechanical, glm-4.7 for complex - Estimated 8-11 hours total
19 KiB
Skills Infrastructure Improvement Plan
Created: 2026-02-11
Branch: feature/skills-infrastructure
Goal: Improve Flynn's skills system to match OpenClaw's maintenance capabilities
Model Strategy: Use glm-4.7-flash for mechanical tasks, glm-4.7 for complex tasks/orchestration
Executive Summary
This plan implements three critical infrastructure improvements to Flynn's skills system:
- Command Dispatch Mode - Expose
flynn skillsCLI commands for skill management - Skills Watcher - Auto-reload skills when files change
- Installer Specs - Auto-install dependencies (brew/node/go) when installing skills
Approach: Infrastructure first, then integrate high-value skills from ClawHub in future phases.
Prioritization Rationale
Based on user decisions:
- Feature set: All three P0-P1 features (command dispatch, watcher, installer specs)
- Approach: Infrastructure first - build solid foundation before adding skills
- Skill format: Keep
manifest.json(more explicit than YAML frontmatter) - Agent isolation: Defer - focus on single-agent optimization
- Skill registry: Keep private - no public FlyHub
Phase 1: Command Dispatch Mode (P0)
Impact: High (users can manage skills without manual file operations) Complexity: Low (exposes existing SkillInstaller/SkillRegistry) Estimated effort: 2-3 hours
1.1 Create CLI Skills Module
File: src/cli/skills.ts
Structure:
import { Command } from 'commander';
import { SkillRegistry } from '../skills/registry.js';
import { SkillInstaller } from '../skills/installer.js';
import { loadAllSkills } from '../skills/loader.js';
export const skillsCommand = new Command('skills')
.description('Manage Flynn skills')
.action(async () => {
await skillsCommand.outputHelp();
});
// Subcommands will be registered here
Subcommands to implement:
flynn skills list
- List all registered skills
- Show tier (bundled/managed/workspace)
- Show availability status (available/unavailable with reasons)
- Output format: table (default) or JSON (with
--jsonflag)
flynn skills info <name>
- Show detailed information about a specific skill
- Display: name, description, version, author, tier, requirements, tools
- Show availability status and reasons if unavailable
- Show directory path
flynn skills install <path>
- Install a skill from a local directory or remote URL
- Validate skill structure (manifest.json + SKILL.md)
- Run requirement checks
- Install to
skills.managed_dir(default:~/.flynn/workspace/skills) - Register with SkillRegistry
- Support
--forceflag to overwrite existing
flynn skills uninstall <name>
- Remove skill from managed directory
- Unregister from SkillRegistry
- Confirm before deletion unless
--yesflag - Check if skill is bundled (deny uninstallation of bundled skills)
flynn skills refresh
- Reload all skills from disk
- Update SkillRegistry
- Show count of skills loaded/removed
1.2 Register Skills Command
File: src/cli/index.ts
Add skills command to CLI:
import { skillsCommand } from './skills.js';
program.addCommand(skillsCommand);
1.3 Update Doctor Checks
File: src/cli/doctor.ts
Enhance skills check (line 192-198):
- Show per-skill availability details
- Report missing binaries with
whichoutput - Report missing environment variables
- Suggest installation commands
1.4 Tests
File: src/cli/skills.test.ts
Test coverage for all subcommands:
skills list- output format, filteringskills info- single skill, non-existent skillskills install- local path, remote URL, duplicate, forceskills uninstall- normal, bundled skill denial, non-existentskills refresh- registry update
Phase 2: Skills Watcher (P1)
Impact: Medium (hot-reload skills without daemon restart) Complexity: Medium (integrate file watcher into daemon lifecycle) Estimated effort: 3-4 hours
2.1 Install Dependencies
Add to package.json:
{
"dependencies": {
"chokidar": "^3.5.3"
}
}
2.2 Create Skills Watcher Module
File: src/skills/watcher.ts
Interface:
import { SkillRegistry } from './registry.js';
import type { Skill } from './types.js';
export interface SkillsWatcherConfig {
registry: SkillRegistry;
skillDirs: string[]; // bundled, managed, workspace
debounceMs?: number; // default: 250
onSkillChange?: (skill: Skill, action: 'add' | 'update' | 'remove') => void;
}
export class SkillsWatcher {
constructor(config: SkillsWatcherConfig);
start(): void;
stop(): void;
reloadSkill(path: string): void;
reloadAll(): void;
}
Implementation:
- Use chokidar to watch all three skill directories
- Debounce file changes (configurable, default 250ms)
- Watch for:
SKILL.md,manifest.json, directory add/remove - On change: call
loadSkill()and register/unregister with SkillRegistry - Emit events via callback for logging/debugging
2.3 Integrate Watcher into Daemon
File: src/daemon/services.ts
Modify initSkills():
import { SkillsWatcher } from '../skills/watcher.js';
async function initSkills(config: Config): Promise<void> {
// Existing skill loading code
const skills = loadAllSkills({
bundledDir: config.skills.bundled_dir,
managedDir: config.skills.managed_dir,
workspaceDir: config.skills.workspace_dir,
});
skills.forEach(skill => skillRegistry.register(skill));
// NEW: Start watcher if enabled
if (config.skills.load?.watch) {
const watcher = new SkillsWatcher({
registry: skillRegistry,
skillDirs: [
config.skills.bundled_dir,
config.skills.managed_dir,
config.skills.workspace_dir,
].filter(Boolean) as string[],
debounceMs: config.skills.load.watch_debounce_ms || 250,
onSkillChange: (skill, action) => {
console.log(`Skill ${skill.manifest.name} ${action}d`);
},
});
watcher.start();
// Store watcher reference for cleanup
(global as any).skillsWatcher = watcher;
}
}
Add cleanup in shutdown handler:
process.on('SIGTERM', () => {
const watcher = (global as any).skillsWatcher;
if (watcher) {
watcher.stop();
}
// ... existing cleanup
});
2.4 Add Configuration Schema
File: src/config/schema.ts
Add to SkillsLoadConfig:
skills_load_config: z.object({
watch: z.boolean().default(false),
watch_debounce_ms: z.number().default(250),
})
2.5 Tests
File: src/skills/watcher.test.ts
Test coverage:
- Watcher initialization
- File change detection (add skill)
- File change detection (update skill)
- File change detection (remove skill)
- Debounce behavior
- Multiple skill directories
- Stop/start lifecycle
Phase 3: Installer Specs (P1)
Impact: Medium (automatic dependency installation) Complexity: Medium (detect package managers, run install commands) Estimated effort: 3-4 hours
3.1 Update SkillManifest Type
File: src/skills/types.ts
Add installer specs to manifest:
export interface SkillManifest {
// ... existing fields
/** Installation specifications for automatic dependency installation */
installers?: SkillInstaller[];
}
export type SkillInstallerKind = 'brew' | 'node' | 'go' | 'download' | 'manual';
export interface SkillInstaller {
/** Installer type */
kind: SkillInstallerKind;
/** Display label shown to user */
label: string;
/** For brew: formula name. For node: package name. For go: import path. */
package?: string;
/** For download: URL to download */
url?: string;
/** For download: archive format (tar.gz, zip, etc.) */
archive?: string;
/** For download: extract directory */
extract?: boolean;
/** Binaries to verify after installation */
bins?: string[];
/** OS platforms this installer supports */
os?: string[];
}
3.2 Create Package Manager Detector
File: src/skills/package-manager.ts
Interface:
export type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun';
export interface PackageManagerInfo {
name: PackageManager;
command: string;
available: boolean;
}
export function detectPackageManager(): PackageManagerInfo | null;
export function runPackageInstall(pkgManager: PackageManager, packages: string[]): Promise<void>;
Implementation:
- Detect available package managers (check
npm --version,pnpm --version, etc.) - Prefer
pnpmovernpm,yarn,bun(matching Flynn's runtime preference) - Run install with correct command for detected manager
- Capture output and errors
3.3 Extend SkillInstaller
File: src/skills/installer.ts
Add auto-installation logic:
installDependencies(skill: Skill): Promise<void>
Algorithm:
- Check if skill has
installersin manifest - Filter installers by current OS
- If multiple installers available, ask user to choose (or pick first)
- For each installer:
- brew: Run
brew install <formula> - node: Run
<pm> install <package>(using detected package manager) - go: Check for
gobinary, install viabrewif missing, thengo install <import> - download: Download URL, extract archive, move to
~/.flynn/tools/<skill-name>/
- brew: Run
- After installation, verify binaries (if specified) using
which - Log warnings for failed installations (don't block skill registration)
uninstallDependencies(skill: Skill): Promise<void>
Algorithm:
- Check if skill has
installers - Reverse installation:
- brew: Run
brew uninstall <formula> - node: Run
<pm> uninstall <package> - go: Remove binary from
GOBIN - download: Remove
~/.flynn/tools/<skill-name>/
- brew: Run
- Ask user before removal unless
--yesflag
3.4 Update CLI Install Command
File: src/cli/skills.ts
Enhance flynn skills install:
skillsCommand
.command('install <path>')
.description('Install a skill from path or URL')
.option('--auto-install', 'Automatically install dependencies')
.action(async (path, options) => {
// Load skill from path
const skill = loadSkill(path, 'managed');
if (!skill) {
console.error('Failed to load skill');
return;
}
// Check requirements
const { available, reasons } = checkRequirements(skill.manifest.requirements);
if (!available) {
console.error('Skill requirements not met:');
reasons.forEach(reason => console.error(` - ${reason}`));
return;
}
// Install dependencies
if (options.autoInstall || skill.manifest.installers) {
console.log('Installing dependencies...');
await installDependencies(skill);
}
// Install skill
await skillInstaller.install(path);
});
3.5 Create Example Skills
Create example skills to test installer specs:
Example 1: Skill with brew dependency
~/.flynn/workspace/skills/example-brew/
├── manifest.json
└── SKILL.md
manifest.json:
{
"name": "example-brew",
"description": "Example skill with brew dependency",
"version": "1.0.0",
"tier": "workspace",
"installers": [
{
"kind": "brew",
"label": "Install jq (brew)",
"formula": "jq",
"bins": ["jq"]
}
]
}
Example 2: Skill with node dependency
~/.flynn/workspace/skills/example-node/
├── manifest.json
└── SKILL.md
manifest.json:
{
"name": "example-node",
"description": "Example skill with node dependency",
"version": "1.0.0",
"tier": "workspace",
"installers": [
{
"kind": "node",
"label": "Install typescript (npm)",
"package": "typescript",
"bins": ["tsc"]
}
]
}
3.6 Tests
File: src/skills/package-manager.test.ts
Test coverage:
- Package manager detection (npm, pnpm, yarn, bun)
- Install execution
- Error handling for missing package manager
File: src/skills/installer.test.ts (extend existing tests)
Additional test coverage:
installDependencies()with brew installerinstallDependencies()with node installerinstallDependencies()with go installerinstallDependencies()with download installer- OS filtering for installers
uninstallDependencies()
Configuration Changes
Add Skills Watcher Settings
Default config (~/.flynn/flynn.yaml):
skills:
load:
watch: true # Enable skills watcher
watch_debounce_ms: 250 # Debounce file changes
Add Package Manager Preference
Optional config:
skills:
install:
package_manager: pnpm # Preferred manager: npm | pnpm | yarn | bun
Git Workflow
Branch Setup
# Create feature branch
git checkout -b feature/skills-infrastructure
# Ensure we're up to date
git fetch origin
git rebase origin/main
Commit Strategy
Commit frequently with atomic changes:
-
Initial commit:
git add . git commit -m "feat(skills): add command dispatch mode - Create src/cli/skills.ts with subcommands - Add skills list/info/install/uninstall/refresh - Register skills command in CLI - Enhance doctor with per-skill details - Add CLI tests -
Second commit:
git add src/skills/watcher.ts git add src/daemon/services.ts git add src/config/schema.ts git commit -m "feat(skills): add skills watcher for auto-reload - Implement SkillsWatcher class with chokidar - Watch bundled/managed/workspace directories - Debounce file changes (configurable) - Integrate watcher into daemon lifecycle - Add configuration schema for watcher - Add watcher tests -
Third commit:
git add src/skills/types.ts git add src/skills/package-manager.ts git add src/skills/installer.ts git add src/cli/skills.ts git commit -m "feat(skills): add installer specs for auto-install - Add SkillInstaller type to manifest - Implement package manager detection - Extend installer with dependency installation - Support brew/node/go/download installers - Add CLI --auto-install flag - Add example skills for testing - Add package manager and installer tests -
Final commit:
git add package.json git add package-lock.json git add .flynn/ git add docs/ git commit -m "docs(skills): update documentation and configuration - Add chokidar dependency - Add skills watcher config to default config - Create SKILLS.md documentation - Update CHANGELOG.md"
Documentation Updates
File: docs/plans/2026-02-11-skills-infrastructure-plan.md (this file)
File: CHANGELOG.md (update with new features)
File: README.md (update with skills CLI commands)
Testing Strategy
Unit Tests (already extensive)
src/skills/registry.test.ts- 11 testssrc/skills/loader.test.ts- 21 testssrc/skills/installer.test.ts- 13 tests (extend)- Total: 45+ tests
New Tests Required
src/cli/skills.test.ts- 20+ tests (CLI commands)src/skills/watcher.test.ts- 15+ tests (file watching)src/skills/package-manager.test.ts- 10+ tests (package managers)- Total: ~45 new tests
Integration Tests
- Test skills watcher with real file system changes
- Test installer specs with real package manager (use temp directories)
- Test CLI commands end-to-end (install → list → info → uninstall)
Test Execution
# Run all tests
pnpm test:run
# Run specific test file
pnpm test:run src/skills/watcher.test.ts
# Run tests in watch mode during development
pnpm test
Future Phases (Post-Infrastructure)
After completing these three phases, the foundation will be solid for integrating skills from ClawHub. Suggested next steps:
Phase 4: Integrate Top 3 Skills from ClawHub
-
github skill (12,020 downloads)
- Wrap
ghCLI as a tool - Implement: issues, PRs, CI runs, API queries
- File:
src/tools/github.ts
- Wrap
-
self-improving-agent skill (17,007 downloads)
- Enhance memory extraction hooks
- Capture learnings from errors/corrections
- Extend:
src/backends/native/orchestrator.ts
-
agent-browser skill (12,862 downloads)
- Evaluate Rust-based browser CLI vs current Puppeteer
- Consider performance improvements
- File:
src/tools/browser/(enhance or replace)
Phase 5: Per-Agent Skill Isolation (P2)
Add skills.allow and skills.deny arrays to agent config:
- Allowlist skills per agent
- Modify
getSystemPromptAdditions()to filter by agent - Update CLI to show per-agent skill sets
Phase 6: Session Skill Snapshot (P2)
Cache skill snapshot in session metadata:
- Store
skillNames[]in SessionStore - Use consistent skill set across compaction
- Add
snapshotSkills()method to SkillRegistry
Phase 7: Remote Skills Registry (P3) - Optional
Consider building a private or public skill registry:
- Skill discovery API
- Skill download and install
- Version management
- Requires infrastructure decision (keep private per user preference)
Success Criteria
Phase 1 (Command Dispatch)
flynn skills listshows all registered skillsflynn skills info <name>displays skill detailsflynn skills install <path>installs local skillflynn skills uninstall <name>removes skillflynn skills refreshreloads skills- Doctor shows per-skill availability details
- All CLI commands have test coverage
- Help text is clear and complete
Phase 2 (Skills Watcher)
- Skills reload automatically when SKILL.md changes
- Skills reload automatically when manifest.json changes
- Skills reload when skill directory is added/removed
- File changes are debounced (configurable)
- Watcher stops cleanly on daemon shutdown
- Configuration toggle enables/disables watcher
- All watcher features have test coverage
Phase 3 (Installer Specs)
- Brew dependencies install automatically
- Node dependencies install with detected package manager
- Go dependencies install (including installing go if needed)
- Download installers work (URL fetch + extract)
- Installers respect OS filtering
- Failed installations don't block skill registration
- CLI
--auto-installflag works - Example skills demonstrate all installer types
- All installer features have test coverage
Overall
- All tests pass (
pnpm test:run) - Linting passes (
pnpm lint) - Type checking passes (
pnpm typecheck) - Documentation is updated
- Change log is documented
- Git history is clean (atomic commits)
Risks and Mitigations
| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
| Chokidar file descriptor limits | Low | Medium | Add warning in docs, recommend increasing ulimit |
| Package manager detection conflicts | Low | Low | Prefer pnpm, fall back gracefully |
| Installer execution security | Medium | High | Prompt for user confirmation before running installs |
| Watcher performance with many skills | Low | Low | Debounce by default (250ms), make configurable |
| Circular dependency in installers | Very Low | High | Manual review of manifest.json, no auto-resolution |
References
- OpenClaw Skills Documentation: https://docs.openclaw.ai/tools/skills.md
- ClawHub: https://clawhub.ai
- Chokidar: https://github.com/paulmillr/chokidar
- Flynn Skills System:
/home/will/lab/flynn/src/skills/ - Previous Gap Analysis:
/home/will/lab/flynn/docs/plans/2026-02-06-openclaw-feature-gap-analysis.md
Plan Status: Ready for implementation Estimated Total Effort: 8-11 hours Next Step: Create branch and begin Phase 1