diff --git a/docs/plans/2026-02-11-skills-infrastructure-plan.md b/docs/plans/2026-02-11-skills-infrastructure-plan.md new file mode 100644 index 0000000..e94412f --- /dev/null +++ b/docs/plans/2026-02-11-skills-infrastructure-plan.md @@ -0,0 +1,710 @@ +# 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 diff --git a/docs/plans/state.json b/docs/plans/state.json index a10a792..1cf8a2c 100644 --- a/docs/plans/state.json +++ b/docs/plans/state.json @@ -1040,27 +1040,53 @@ } } }, - "earlier_plans": { - "plans": [ - { "file": "2026-02-02-flynn-design.md", "status": "completed" }, - { "file": "2026-02-02-flynn-phase1-implementation.md", "status": "completed" }, - { "file": "2026-02-02-flynn-phase2-implementation.md", "status": "completed" }, - { "file": "2026-02-05-flynn-phase3-implementation.md", "status": "completed" }, - { "file": "2026-02-05-tui-redesign.md", "status": "completed" }, - { "file": "2026-02-05-tui-redesign-implementation.md", "status": "completed" }, - { "file": "2026-02-05-llamacpp-integration-design.md", "status": "completed" }, - { "file": "2026-02-05-llamacpp-implementation.md", "status": "completed" }, - { "file": "2026-02-05-backend-switch-design.md", "status": "completed" }, - { "file": "2026-02-05-backend-switch-implementation.md", "status": "completed" }, - { "file": "2026-02-05-openclaw-parity-design.md", "status": "completed" }, - { "file": "2026-02-05-phase1-tool-framework.md", "status": "completed" }, - { "file": "2026-02-05-phase2-websocket-gateway.md", "status": "completed" }, - { "file": "2026-02-05-phase3-channel-adapters.md", "status": "completed" }, - { "file": "2026-02-05-phase5-cli-cron-doctor-design.md", "status": "completed" }, - { "file": "2026-02-05-phase5a-implementation.md", "status": "completed" } - ] + "skills_infrastructure": { + "file": "2026-02-11-skills-infrastructure-plan.md", + "status": "planned", + "date": "2026-02-11", + "summary": "Three-phase plan to improve skills system: Command Dispatch (P0), Skills Watcher (P1), Installer Specs (P1). Infrastructure-first approach before integrating ClawHub skills. Estimated 8-11 hours total. Model strategy: glm-4.7-flash for mechanical tasks, glm-4.7 for complex/orchestration tasks.", + "phases": { + "phase_1_command_dispatch": { + "priority": "P0", + "status": "not_started", + "description": "flynn skills CLI commands (list/info/install/uninstall/refresh) with doctor enhancement", + "effort": "2-3 hours" + }, + "phase_2_skills_watcher": { + "priority": "P1", + "status": "not_started", + "description": "Auto-reload skills with chokidar file watcher, configurable debounce", + "effort": "3-4 hours" + }, + "phase_3_installer_specs": { + "priority": "P1", + "status": "not_started", + "description": "Auto-install dependencies (brew/node/go/download) with package manager detection", + "effort": "3-4 hours" + } } }, + "earlier_plans": { + "plans": [ + { "file": "2026-02-02-flynn-design.md", "status": "completed" }, + { "file": "2026-02-02-flynn-phase1-implementation.md", "status": "completed" }, + { "file": "2026-02-02-flynn-phase2-implementation.md", "status": "completed" }, + { "file": "2026-02-05-flynn-phase3-implementation.md", "status": "completed" }, + { "file": "2026-02-05-tui-redesign.md", "status": "completed" }, + { "file": "2026-02-05-tui-redesign-implementation.md", "status": "completed" }, + { "file": "2026-02-05-llamacpp-integration-design.md", "status": "completed" }, + { "file": "2026-02-05-llamacpp-implementation.md", "status": "completed" }, + { "file": "2026-02-05-backend-switch-design.md", "status": "completed" }, + { "file": "2026-02-05-backend-switch-implementation.md", "status": "completed" }, + { "file": "2026-02-05-openclaw-parity-design.md", "status": "completed" }, + { "file": "2026-02-05-phase1-tool-framework.md", "status": "completed" }, + { "file": "2026-02-05-phase2-websocket-gateway.md", "status": "completed" }, + { "file": "2026-02-05-phase3-channel-adapters.md", "status": "completed" }, + { "file": "2026-02-05-phase5-cli-cron-doctor-design.md", "status": "completed" }, + { "file": "2026-02-05-phase5a-implementation.md", "status": "completed" } + ] + } + }, "overall_progress": { "total_test_count": 1331,