Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions PROGRESS.md
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 |
Comment on lines +1 to +9
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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 as Create: 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
In `@PROGRESS.md` around lines 1 - 9, PROGRESS.md was committed with
session-specific rows instead of a reusable template; update the file so it
contains only the header and an empty table (or a clear placeholder row) and
include a short note about lifecycle (whether sessions should append or start
fresh). Locate the PROGRESS.md table (the markdown header and the | Date & Time
| Task Description | Status | Commit / Evidence | row) and remove the five
pre-populated entries, replacing them with either an empty table skeleton or a
one-line placeholder like "No entries yet — append per session" plus a brief
comment explaining expected usage (append vs reset).

26 changes: 26 additions & 0 deletions docs/plans/2026-02-12-sentinel-discovery.md
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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Plan omits the JS variant of the generator script.

Task 2 lists only generate_skills_index.py, but the PR also ships generate_skills_index.js. Update the plan to reflect both files, or document why both exist (e.g., environment flexibility).

🤖 Prompt for AI Agents
In `@docs/plans/2026-02-12-sentinel-discovery.md` around lines 18 - 21, Update
"Task 2: Implement Skill Discovery Index" to mention both generator scripts by
adding `lib/scripts/generate_skills_index.js` alongside
`lib/scripts/generate_skills_index.py` (and keep `skills/SKILLS_INDEX.md`), or
replace the single-file listing with a short note explaining why both variants
are included (e.g., environment flexibility or compatibility), referencing the
filenames `generate_skills_index.py` and `generate_skills_index.js` so readers
can locate the JS and Python implementations.


### Task 3: Implement Sentinel Logic (Progress Tracking)
**Files:**
- Modify: `skills/executing-plans/SKILL.md`
- Create: `PROGRESS.md` (template)
Comment on lines +14 to +26
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
### 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`
### Task 3: Implement Sentinel Logic (Progress Tracking)
**Files:**
- Modify: `skills/executing-plans/SKILL.md`
- Create: `PROGRESS.md` (template)
## 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`
## Task 3: Implement Sentinel Logic (Progress Tracking)
**Files:**
- Modify: `skills/executing-plans/SKILL.md`
- Create: `PROGRESS.md` (template)
🧰 Tools
🪛 markdownlint-cli2 (0.20.0)

[warning] 14-14: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)

🤖 Prompt for AI Agents
In `@docs/plans/2026-02-12-sentinel-discovery.md` around lines 14 - 26, The
document jumps from an H1 to H3 for task sections; update the task headings so
they are H2 instead of H3 (e.g., change "### Task 1: Update
`using-superpowers`..." to "## Task 1: Update `using-superpowers`..." and do the
same for Task 2 and Task 3) across the plan file and ensure corresponding
TOC/links (if any) still resolve; verify related files named SKILL.md,
generate_skills_index.js, SKILLS_INDEX.md, and PROGRESS.md mentioned in the plan
remain referenced consistently after the heading level changes.

54 changes: 54 additions & 0 deletions lib/scripts/generate_skills_index.js
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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Same issues as the Python variant: non-deterministic order and unescaped pipes.

readdirSync order is OS-dependent. Sort skillFiles before iterating, and escape | in name/description to protect the Markdown table. See the Python file comment for rationale.

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
In `@lib/scripts/generate_skills_index.js` around lines 10 - 36, The current
getFiles -> skillFiles loop can produce non-deterministic output and unescaped
Markdown pipes; after computing skillFiles, sort the array (e.g.,
skillFiles.sort()) to make order deterministic, and before appending to
indexContent escape any pipe characters in the parsed name and description
(replace '|' with '\|' and keep the existing trimming/quote-stripping logic).
Update references in the processing block that compute name and description so
the sanitized values are used when building indexContent, preserving the
fallback for name (path.basename(path.dirname(file))) and default description.


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);
36 changes: 36 additions & 0 deletions lib/scripts/generate_skills_index.py
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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Non-deterministic output order and unescaped pipe characters.

Two issues:

  1. os.walk traversal order is filesystem-dependent, so the generated index will vary between runs/platforms, causing noisy diffs. Sort the discovered skill files before iterating.
  2. Pipe characters (|) in skill descriptions will break the Markdown table. Escape them.
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 dirs_dirs.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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"
🧰 Tools
🪛 Ruff (0.15.0)

[warning] 10-10: Loop control variable dirs not used within loop body

Rename unused dirs to _dirs

(B007)

🤖 Prompt for AI Agents
In `@lib/scripts/generate_skills_index.py` around lines 10 - 23, The loop using
os.walk in generate_skills_index.py produces non-deterministic order and leaves
pipe characters unescaped; instead, collect all SKILL.md paths (using the
current os.walk over root, _dirs, files), build a list of skill_path entries,
sort that list, then iterate the sorted list when reading content to append to
index_content; additionally, sanitize description by escaping any '|' characters
(e.g., replace '|' with '\|') before writing into the Markdown table and rename
dirs → _dirs to address the Ruff B007 warning; keep the existing
name_match/desc_match logic (name_match, desc_match, skill_path, index_content)
when implementing these changes.


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}")
20 changes: 20 additions & 0 deletions skills/SKILLS_INDEX.md
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 |
3 changes: 2 additions & 1 deletion skills/executing-plans/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ For each task:
1. Mark as in_progress
2. Follow each step exactly (plan has bite-sized steps)
3. Run verifications as specified
4. Mark as completed
4. **Update `PROGRESS.md` (at project root)** - REQUIRED: Add a line with current timestamp, task status, and commit hash/evidence.
5. Mark as completed

### Step 3: Report
When batch complete:
Expand Down
27 changes: 27 additions & 0 deletions skills/using-superpowers/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Windows column mixes CMD-only syntax while labeled CMD/PowerShell.

type nul > file is CMD-only. Either change the column header to “CMD” or add a PowerShell equivalent (e.g., New-Item file -ItemType File) to avoid misleading guidance.

✅ 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
In `@skills/using-superpowers/SKILL.md` around lines 99 - 107, The Windows column
header "Windows (CMD/PowerShell)" is misleading because the example "type nul >
file" is CMD-only; update the table in SKILL.md to either change the header to
"Windows (CMD)" or add a PowerShell equivalent for the "touch file" row (e.g.,
use New-Item file -ItemType File) so the Windows column content matches the
header; locate the table and the "touch file" / "type nul > file" cell and make
the header or cell change accordingly.

**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.