# 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: 1. **Command Dispatch Mode** - Expose `flynn skills` CLI commands for skill management 2. **Skills Watcher** - Auto-reload skills when files change 3. **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:** ```typescript 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 `--json` flag) #### `flynn skills info ` - 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 ` - 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 `--force` flag to overwrite existing #### `flynn skills uninstall ` - Remove skill from managed directory - Unregister from SkillRegistry - Confirm before deletion unless `--yes` flag - 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: ```typescript 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 `which` output - 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, filtering - `skills info` - single skill, non-existent skill - `skills install` - local path, remote URL, duplicate, force - `skills uninstall` - normal, bundled skill denial, non-existent - `skills 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`: ```json { "dependencies": { "chokidar": "^3.5.3" } } ``` ### 2.2 Create Skills Watcher Module **File:** `src/skills/watcher.ts` **Interface:** ```typescript 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()`: ```typescript import { SkillsWatcher } from '../skills/watcher.js'; async function initSkills(config: Config): Promise { // 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: ```typescript 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: ```typescript 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: ```typescript 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:** ```typescript 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; ``` **Implementation:** - Detect available package managers (check `npm --version`, `pnpm --version`, etc.) - Prefer `pnpm` over `npm`, `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` **Algorithm:** 1. Check if skill has `installers` in manifest 2. Filter installers by current OS 3. If multiple installers available, ask user to choose (or pick first) 4. For each installer: - **brew**: Run `brew install ` - **node**: Run ` install ` (using detected package manager) - **go**: Check for `go` binary, install via `brew` if missing, then `go install ` - **download**: Download URL, extract archive, move to `~/.flynn/tools//` 5. After installation, verify binaries (if specified) using `which` 6. Log warnings for failed installations (don't block skill registration) #### `uninstallDependencies(skill: Skill): Promise` **Algorithm:** 1. Check if skill has `installers` 2. Reverse installation: - **brew**: Run `brew uninstall ` - **node**: Run ` uninstall ` - **go**: Remove binary from `GOBIN` - **download**: Remove `~/.flynn/tools//` 3. Ask user before removal unless `--yes` flag ### 3.4 Update CLI Install Command **File:** `src/cli/skills.ts` Enhance `flynn skills install`: ```typescript skillsCommand .command('install ') .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:** ```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:** ```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 installer - `installDependencies()` with node installer - `installDependencies()` with go installer - `installDependencies()` with download installer - OS filtering for installers - `uninstallDependencies()` --- ## Configuration Changes ### Add Skills Watcher Settings **Default config (`~/.flynn/flynn.yaml`):** ```yaml skills: load: watch: true # Enable skills watcher watch_debounce_ms: 250 # Debounce file changes ``` ### Add Package Manager Preference **Optional config:** ```yaml skills: install: package_manager: pnpm # Preferred manager: npm | pnpm | yarn | bun ``` --- ## Git Workflow ### Branch Setup ```bash # 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: 1. **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 ``` 2. **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 ``` 3. **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 ``` 4. **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 tests - `src/skills/loader.test.ts` - 21 tests - `src/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 ```bash # 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 1. **github** skill (12,020 downloads) - Wrap `gh` CLI as a tool - Implement: issues, PRs, CI runs, API queries - File: `src/tools/github.ts` 2. **self-improving-agent** skill (17,007 downloads) - Enhance memory extraction hooks - Capture learnings from errors/corrections - Extend: `src/backends/native/orchestrator.ts` 3. **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 list` shows all registered skills - [ ] `flynn skills info ` displays skill details - [ ] `flynn skills install ` installs local skill - [ ] `flynn skills uninstall ` removes skill - [ ] `flynn skills refresh` reloads 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-install` flag 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