-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
feat: implement sentinel progress tracking and dynamic skill discovery #458
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
10db57c
32bbfae
3964eba
946c72d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| # Project Progress Tracking (Sentinel) | ||
|
|
||
| | Date & Time | Task Description | Status | Commit / Evidence | | ||
| |-------------|------------------|--------|-------------------| | ||
| | 2026-02-12 17:45 | Initial PR Design & Planning | ✅ COMPLETED | Brainstorming Session | | ||
| | 2026-02-12 17:55 | OS Adaptability Mapping | ✅ COMPLETED | Updated skills/using-superpowers/SKILL.md | | ||
| | 2026-02-12 17:58 | Skill Discovery Indexing | ✅ COMPLETED | Added SKILLS_INDEX.md & Generator | | ||
| | 2026-02-12 18:02 | Sentinel Logic Integration | ✅ COMPLETED | Updated skills/executing-plans/SKILL.md | | ||
| | 2026-02-12 18:05 | Skill Index Verification | ✅ VERIFIED | SKILLS_INDEX.md generated correctly | | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,26 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Progress Sentinel & Dynamic Skill Discovery Implementation Plan | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **Goal:** Enhance Superpowers with automated progress tracking, optimized skill discovery, and native Windows adaptability. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **Architecture:** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 1. **Sentinel**: Inject progress tracking requirements into core execution skills. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 2. **Discovery**: Implement a summary index for all available skills to prevent context overload. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 3. **Adaptability**: Provide a command mapping standard for cross-platform execution. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ### Task 1: Update `using-superpowers` (OS Adaptability) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **Files:** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Modify: `skills/using-superpowers/SKILL.md` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ### Task 2: Implement Skill Discovery Index | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **Files:** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Create: `lib/scripts/generate_skills_index.js` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Create: `skills/SKILLS_INDEX.md` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
18
to
21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Plan omits the JS variant of the generator script. Task 2 lists only 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ### Task 3: Implement Sentinel Logic (Progress Tracking) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **Files:** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Modify: `skills/executing-plans/SKILL.md` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Create: `PROGRESS.md` (template) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+14
to
+26
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Heading level jumps from H1 to H3. For Markdown consistency, use H2 for task sections under the H1. ✏️ Suggested fix-### Task 1: Update `using-superpowers` (OS Adaptability)
+## Task 1: Update `using-superpowers` (OS Adaptability)
...
-### Task 2: Implement Skill Discovery Index
+## Task 2: Implement Skill Discovery Index
...
-### Task 3: Implement Sentinel Logic (Progress Tracking)
+## Task 3: Implement Sentinel Logic (Progress Tracking)📝 Committable suggestion
Suggested change
🧰 Tools🪛 markdownlint-cli2 (0.20.0)[warning] 14-14: Heading levels should only increment by one level at a time (MD001, heading-increment) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| const fs = require('fs'); | ||
| const path = require('path'); | ||
|
|
||
| function generateIndex(skillsDir, outputFile) { | ||
| let indexContent = "# Superpowers Skills Index\n\n"; | ||
| indexContent += "This index provides a lightweight summary of all available skills. Use this to discover relevant skills before loading their full instructions.\n\n"; | ||
| indexContent += "| Skill Name | Description |\n"; | ||
| indexContent += "|------------|-------------|\n"; | ||
|
|
||
| const getFiles = (dir) => { | ||
| let results = []; | ||
| const list = fs.readdirSync(dir); | ||
| list.forEach(file => { | ||
| file = path.join(dir, file); | ||
| const stat = fs.statSync(file); | ||
| if (stat && stat.isDirectory()) { | ||
| results = results.concat(getFiles(file)); | ||
| } else if (file.endsWith('SKILL.md')) { | ||
| results.push(file); | ||
| } | ||
| }); | ||
| return results; | ||
| }; | ||
|
|
||
| const skillFiles = getFiles(skillsDir); | ||
| const skills = []; | ||
|
|
||
| skillFiles.forEach(file => { | ||
| const content = fs.readFileSync(file, 'utf8'); | ||
| const nameMatch = content.match(/^name:\s*(.+)$/m); | ||
| const descMatch = content.match(/^description:\s*(.+)$/m); | ||
|
|
||
| const name = nameMatch ? nameMatch[1].trim() : path.basename(path.dirname(file)); | ||
| const description = descMatch ? descMatch[1].trim().replace(/^"|"$/g, '') : "No description available."; | ||
|
|
||
| skills.push({ name, description }); | ||
| }); | ||
|
|
||
| // Sort skills alphabetically by name | ||
| skills.sort((a, b) => a.name.localeCompare(b.name)); | ||
|
|
||
| skills.forEach(skill => { | ||
| indexContent += `| ${skill.name} | ${skill.description} |\n`; | ||
| }); | ||
|
Comment on lines
10
to
44
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same issues as the Python variant: non-deterministic order and unescaped pipes.
Proposed fix (sorting + escaping) const skillFiles = getFiles(skillsDir);
+ skillFiles.sort();
skillFiles.forEach(file => {
const content = fs.readFileSync(file, 'utf8');
const nameMatch = content.match(/^name:\s*(.+)$/m);
const descMatch = content.match(/^description:\s*(.+)$/m);
- const name = nameMatch ? nameMatch[1].trim() : path.basename(path.dirname(file));
- const description = descMatch ? descMatch[1].trim().replace(/^"|"$/g, '') : "No description available.";
+ const name = (nameMatch ? nameMatch[1].trim() : path.basename(path.dirname(file))).replace(/\|/g, '\\|');
+ const description = (descMatch ? descMatch[1].trim().replace(/^"|"$/g, '') : "No description available.").replace(/\|/g, '\\|');
indexContent += `| ${name} | ${description} |\n`;
});🤖 Prompt for AI Agents |
||
|
|
||
| fs.writeFileSync(outputFile, indexContent); | ||
| console.log(`Generated index at ${outputFile}`); | ||
| } | ||
|
|
||
| const baseDir = path.resolve(__dirname, '../..'); | ||
| const skillsDir = path.join(baseDir, 'skills'); | ||
| const outputFile = path.join(baseDir, 'skills/SKILLS_INDEX.md'); | ||
|
|
||
| generateIndex(skillsDir, outputFile); | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,36 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import os | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import re | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def generate_index(skills_dir, output_file): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| index_content = "# Superpowers Skills Index\n\n" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| index_content += "This index provides a lightweight summary of all available skills. Use this to discover relevant skills before loading their full instructions.\n\n" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| index_content += "| Skill Name | Description |\n" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| index_content += "|------------|-------------|\n" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for root, dirs, files in os.walk(skills_dir): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if "SKILL.md" in files: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| skill_path = os.path.join(root, "SKILL.md") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with open(skill_path, 'r', encoding='utf-8') as f: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content = f.read() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Extract frontmatter name and description | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name_match = re.search(r'^name:\s*(.+)$', content, re.MULTILINE) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| desc_match = re.search(r'^description:\s*(.+)$', content, re.MULTILINE) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name = name_match.group(1).strip() if name_match else os.path.basename(root) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| description = desc_match.group(1).strip().strip('"') if desc_match else "No description available." | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| index_content += f"| {name} | {description} |\n" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+10
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Non-deterministic output order and unescaped pipe characters. Two issues:
Proposed fix- for root, dirs, files in os.walk(skills_dir):
- if "SKILL.md" in files:
- skill_path = os.path.join(root, "SKILL.md")
- with open(skill_path, 'r', encoding='utf-8') as f:
- content = f.read()
-
- # Extract frontmatter name and description
- name_match = re.search(r'^name:\s*(.+)$', content, re.MULTILINE)
- desc_match = re.search(r'^description:\s*(.+)$', content, re.MULTILINE)
-
- name = name_match.group(1).strip() if name_match else os.path.basename(root)
- description = desc_match.group(1).strip().strip('"') if desc_match else "No description available."
-
- index_content += f"| {name} | {description} |\n"
+ skill_files = []
+ for root, _dirs, files in os.walk(skills_dir):
+ if "SKILL.md" in files:
+ skill_files.append(os.path.join(root, "SKILL.md"))
+ skill_files.sort()
+
+ for skill_path in skill_files:
+ with open(skill_path, 'r', encoding='utf-8') as f:
+ content = f.read()
+
+ name_match = re.search(r'^name:\s*(.+)$', content, re.MULTILINE)
+ desc_match = re.search(r'^description:\s*(.+)$', content, re.MULTILINE)
+
+ name = name_match.group(1).strip() if name_match else os.path.basename(os.path.dirname(skill_path))
+ description = desc_match.group(1).strip().strip('"') if desc_match else "No description available."
+
+ # Escape pipes to preserve Markdown table formatting
+ name = name.replace('|', '\\|')
+ description = description.replace('|', '\\|')
+
+ index_content += f"| {name} | {description} |\n"This also addresses the Ruff B007 warning by renaming 📝 Committable suggestion
Suggested change
🧰 Tools🪛 Ruff (0.15.0)[warning] 10-10: Loop control variable Rename unused (B007) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with open(output_file, 'w', encoding='utf-8') as f: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| f.write(index_content) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if __name__ == "__main__": | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Assuming the script runs from the repo root or lib/scripts | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| skills_dir = os.path.join(base_dir, "skills") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| output_file = os.path.join(base_dir, "skills/SKILLS_INDEX.md") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Also handle the awesome-automation if linked | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| generate_index(skills_dir, output_file) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| print(f"Generated index at {output_file}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| # Superpowers Skills Index | ||
|
|
||
| This index provides a lightweight summary of all available skills. Use this to discover relevant skills before loading their full instructions. | ||
|
|
||
| | Skill Name | Description | | ||
| |------------|-------------| | ||
| | brainstorming | You MUST use this before any creative work - creating features, building components, adding functionality, or modifying behavior. Explores user intent, requirements and design before implementation. | | ||
| | dispatching-parallel-agents | Use when facing 2+ independent tasks that can be worked on without shared state or sequential dependencies | | ||
| | executing-plans | Use when you have a written implementation plan to execute in a separate session with review checkpoints | | ||
| | finishing-a-development-branch | Use when implementation is complete, all tests pass, and you need to decide how to integrate the work - guides completion of development work by presenting structured options for merge, PR, or cleanup | | ||
| | receiving-code-review | Use when receiving code review feedback, before implementing suggestions, especially if feedback seems unclear or technically questionable - requires technical rigor and verification, not performative agreement or blind implementation | | ||
| | requesting-code-review | Use when completing tasks, implementing major features, or before merging to verify work meets requirements | | ||
| | subagent-driven-development | Use when executing implementation plans with independent tasks in the current session | | ||
| | systematic-debugging | Use when encountering any bug, test failure, or unexpected behavior, before proposing fixes | | ||
| | test-driven-development | Use when implementing any feature or bugfix, before writing implementation code | | ||
| | using-git-worktrees | Use when starting feature work that needs isolation from current workspace or before executing implementation plans - creates isolated git worktrees with smart directory selection and safety verification | | ||
| | using-superpowers | Use when starting any conversation - establishes how to find and use skills, requiring Skill tool invocation before ANY response including clarifying questions | | ||
| | verification-before-completion | Use when about to claim work is complete, fixed, or passing, before committing or creating PRs - requires running verification commands and confirming output before making any success claims; evidence before assertions always | | ||
| | writing-plans | Use when you have a spec or requirements for a multi-step task, before touching code | | ||
| | writing-skills | Use when creating new skills, editing existing skills, or verifying skills work before deployment | |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -82,6 +82,33 @@ When multiple skills could apply, use this order: | |
|
|
||
| The skill itself tells you which. | ||
|
|
||
| ## Skill Discovery (Handling Scale) | ||
|
|
||
| When dealing with a large library of skills (e.g., automated SaaS skills), do not load all skills into context at once. Instead: | ||
|
|
||
| 1. **Read `skills/SKILLS_INDEX.md`** - This provides a lightweight summary of all available skills. | ||
| 2. **Search for keywords** - Identify 2-3 specific skills that match your current task. | ||
| 3. **Invoke specific skills** - Use the Skill tool (or Read tool in other environments) only on those highly relevant skills. | ||
|
|
||
| --- | ||
|
|
||
| ## Windows & Cross-Platform Adaptability | ||
|
|
||
| When executing commands, adapt to the user's OS. Do not assume a POSIX environment. | ||
|
|
||
| | POSIX / Linux | Windows (CMD/PowerShell) | Purpose | | ||
| |---------------|--------------------------|---------| | ||
| | `ls -la` | `dir` | List files | | ||
| | `rm -rf <dir>` | `rmdir /s /q <dir>` | Delete directory | | ||
| | `cp -r` | `xcopy /e /i /y` | Copy directory | | ||
| | `grep "text"` | `findstr "text"` | Search in files | | ||
| | `cat file` | `type file` | View file content | | ||
| | `touch file` | `type nul > file` | Create empty file (CMD) | | ||
|
|
||
|
Comment on lines
+99
to
+107
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Windows column mixes CMD-only syntax while labeled CMD/PowerShell.
✅ Suggested fix (add PowerShell variant)-| POSIX / Linux | Windows (CMD/PowerShell) | Purpose |
+| POSIX / Linux | Windows (CMD / PowerShell) | Purpose |
...
-| `touch file` | `type nul > file` | Create empty file (CMD) |
+| `touch file` | `type nul > file` / `New-Item file -ItemType File` | Create empty file |🤖 Prompt for AI Agents |
||
| **Pro Tip:** Use the `run_command` tool to check environment before assuming command syntax. | ||
|
|
||
| --- | ||
|
|
||
| ## User Instructions | ||
|
|
||
| Instructions say WHAT, not HOW. "Add X" or "Fix Y" doesn't mean skip workflows. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was intended as a template but contains session-specific data.
The plan (
docs/plans/2026-02-12-sentinel-discovery.md, Task 3) describes this asCreate: PROGRESS.md (template), but it ships with five pre-populated entries from this implementation session. For reuse across future plan executions, consider either shipping an empty template (header + empty table) or clarifying the intended lifecycle — should new sessions append here or start fresh?🤖 Prompt for AI Agents