mirror of
https://github.com/obra/superpowers.git
synced 2026-05-06 17:19:05 +08:00
Compare commits
56 Commits
c61f75030f
...
f/cross-pl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11ad1f4829 | ||
|
|
f02951eafe | ||
|
|
86a474786c | ||
|
|
56bb8bc2df | ||
|
|
b129d28d1d | ||
|
|
f2cbfbefeb | ||
|
|
e7a2d16476 | ||
|
|
6efe32c9e2 | ||
|
|
b55764852a | ||
|
|
9f42444ab1 | ||
|
|
99e4c656bf | ||
|
|
a5dd364e42 | ||
|
|
c4bbe651cb | ||
|
|
34c17aefb2 | ||
|
|
f9b088f7b3 | ||
|
|
bc25777c6a | ||
|
|
bcdd7fa24c | ||
|
|
6149f3635a | ||
|
|
777a9770d8 | ||
|
|
da283df058 | ||
|
|
a569527b89 | ||
|
|
ac1c715ffb | ||
|
|
8c8c5e87ce | ||
|
|
a5d36b1300 | ||
|
|
917e5f53b1 | ||
|
|
a6b1a1fa0c | ||
|
|
b7a8f76985 | ||
|
|
4b1b20f69f | ||
|
|
eeaf2ad15b | ||
|
|
dd237283db | ||
|
|
c0b417e409 | ||
|
|
1f20bef3f5 | ||
|
|
f0df5eca30 | ||
|
|
0a1124ba53 | ||
|
|
65d760f9c2 | ||
|
|
2d942f3b01 | ||
|
|
8b1669269c | ||
|
|
a2964d7a20 | ||
|
|
eafe962b18 | ||
|
|
9f04f06351 | ||
|
|
f076bd3431 | ||
|
|
9e3ed213a0 | ||
|
|
9e6e077d33 | ||
|
|
151cfb16a0 | ||
|
|
a1155f623f | ||
|
|
3f80f1c769 | ||
|
|
4ae1a3d6a6 | ||
|
|
e6221a48c5 | ||
|
|
4fd9aa2dd5 | ||
|
|
2b1bfe5db6 | ||
|
|
bd080e3cc8 | ||
|
|
eb2b44b23f | ||
|
|
80c0a45fcc | ||
|
|
c28b28ffbd | ||
|
|
33e9bea3cc | ||
|
|
74a0c004eb |
@@ -9,7 +9,7 @@
|
||||
{
|
||||
"name": "superpowers",
|
||||
"description": "Core skills library for Claude Code: TDD, debugging, collaboration patterns, and proven techniques",
|
||||
"version": "5.0.6",
|
||||
"version": "5.1.0",
|
||||
"source": "./",
|
||||
"author": {
|
||||
"name": "Jesse Vincent",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "superpowers",
|
||||
"description": "Core skills library for Claude Code: TDD, debugging, collaboration patterns, and proven techniques",
|
||||
"version": "5.0.6",
|
||||
"version": "5.1.0",
|
||||
"author": {
|
||||
"name": "Jesse Vincent",
|
||||
"email": "jesse@fsck.com"
|
||||
|
||||
47
.codex-plugin/plugin.json
Normal file
47
.codex-plugin/plugin.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "superpowers",
|
||||
"version": "5.1.0",
|
||||
"description": "An agentic skills framework & software development methodology that works: planning, TDD, debugging, and collaboration workflows.",
|
||||
"author": {
|
||||
"name": "Jesse Vincent",
|
||||
"email": "jesse@fsck.com",
|
||||
"url": "https://github.com/obra"
|
||||
},
|
||||
"homepage": "https://github.com/obra/superpowers",
|
||||
"repository": "https://github.com/obra/superpowers",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"brainstorming",
|
||||
"subagent-driven-development",
|
||||
"skills",
|
||||
"planning",
|
||||
"tdd",
|
||||
"debugging",
|
||||
"code-review",
|
||||
"workflow"
|
||||
],
|
||||
"skills": "./skills/",
|
||||
"interface": {
|
||||
"displayName": "Superpowers",
|
||||
"shortDescription": "Planning, TDD, debugging, and delivery workflows for coding agents",
|
||||
"longDescription": "Use Superpowers to guide agent work through brainstorming, implementation planning, test-driven development, systematic debugging, parallel execution, code review, and finish-the-branch workflows.",
|
||||
"developerName": "Jesse Vincent",
|
||||
"category": "Coding",
|
||||
"capabilities": [
|
||||
"Interactive",
|
||||
"Read",
|
||||
"Write"
|
||||
],
|
||||
"defaultPrompt": [
|
||||
"I've got an idea for something I'd like to build.",
|
||||
"Let's add a feature to this project."
|
||||
],
|
||||
"websiteURL": "https://github.com/obra/superpowers",
|
||||
"privacyPolicyURL": "https://docs.github.com/en/site-policy/privacy-policies/github-general-privacy-statement",
|
||||
"termsOfServiceURL": "https://docs.github.com/en/site-policy/github-terms/github-terms-of-service",
|
||||
"brandColor": "#F59E0B",
|
||||
"composerIcon": "./assets/superpowers-small.svg",
|
||||
"logo": "./assets/app-icon.png",
|
||||
"screenshots": []
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
# Installing Superpowers for Codex
|
||||
|
||||
Enable superpowers skills in Codex via native skill discovery. Just clone and symlink.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Git
|
||||
|
||||
## Installation
|
||||
|
||||
1. **Clone the superpowers repository:**
|
||||
```bash
|
||||
git clone https://github.com/obra/superpowers.git ~/.codex/superpowers
|
||||
```
|
||||
|
||||
2. **Create the skills symlink:**
|
||||
```bash
|
||||
mkdir -p ~/.agents/skills
|
||||
ln -s ~/.codex/superpowers/skills ~/.agents/skills/superpowers
|
||||
```
|
||||
|
||||
**Windows (PowerShell):**
|
||||
```powershell
|
||||
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.agents\skills"
|
||||
cmd /c mklink /J "$env:USERPROFILE\.agents\skills\superpowers" "$env:USERPROFILE\.codex\superpowers\skills"
|
||||
```
|
||||
|
||||
3. **Restart Codex** (quit and relaunch the CLI) to discover the skills.
|
||||
|
||||
## Migrating from old bootstrap
|
||||
|
||||
If you installed superpowers before native skill discovery, you need to:
|
||||
|
||||
1. **Update the repo:**
|
||||
```bash
|
||||
cd ~/.codex/superpowers && git pull
|
||||
```
|
||||
|
||||
2. **Create the skills symlink** (step 2 above) — this is the new discovery mechanism.
|
||||
|
||||
3. **Remove the old bootstrap block** from `~/.codex/AGENTS.md` — any block referencing `superpowers-codex bootstrap` is no longer needed.
|
||||
|
||||
4. **Restart Codex.**
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
ls -la ~/.agents/skills/superpowers
|
||||
```
|
||||
|
||||
You should see a symlink (or junction on Windows) pointing to your superpowers skills directory.
|
||||
|
||||
## Updating
|
||||
|
||||
```bash
|
||||
cd ~/.codex/superpowers && git pull
|
||||
```
|
||||
|
||||
Skills update instantly through the symlink.
|
||||
|
||||
## Uninstalling
|
||||
|
||||
```bash
|
||||
rm ~/.agents/skills/superpowers
|
||||
```
|
||||
|
||||
Optionally delete the clone: `rm -rf ~/.codex/superpowers`.
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "superpowers",
|
||||
"displayName": "Superpowers",
|
||||
"description": "Core skills library: TDD, debugging, collaboration patterns, and proven techniques",
|
||||
"version": "5.0.6",
|
||||
"version": "5.1.0",
|
||||
"author": {
|
||||
"name": "Jesse Vincent",
|
||||
"email": "jesse@fsck.com"
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,5 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Questions & Help
|
||||
url: https://discord.gg/Jd8Vphy9jq
|
||||
url: https://discord.gg/35wsABTejz
|
||||
about: For usage questions, troubleshooting help, and general discussion, please visit our Discord instead of opening an issue.
|
||||
|
||||
39
.github/PULL_REQUEST_TEMPLATE.md
vendored
39
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -50,6 +50,45 @@ of human involvement will be closed without review.
|
||||
|-------------------------------------|-----------------|-------|------------------|
|
||||
| | | | |
|
||||
|
||||
## New harness support (required if this PR adds a new harness)
|
||||
|
||||
<!-- If this PR adds support for a new harness (IDE, CLI tool, agent
|
||||
runner), you MUST include a session transcript proving the
|
||||
integration actually works.
|
||||
|
||||
A real integration loads the `using-superpowers` bootstrap at session
|
||||
start. The bootstrap is what causes skills to auto-trigger. Without
|
||||
it, the skills are dead weight — present on disk but never invoked
|
||||
at the right moments.
|
||||
|
||||
ACCEPTANCE TEST: Open a clean session in the new harness and send
|
||||
exactly this user message:
|
||||
|
||||
Let's make a react todo list
|
||||
|
||||
A working integration auto-triggers the `brainstorming` skill before
|
||||
any code is written. Paste the complete transcript below.
|
||||
|
||||
These are NOT real integrations and PRs that ship them will be closed:
|
||||
|
||||
- Manually copying skill files into the harness
|
||||
- Wrapping with `npx skills` or similar at-runtime shims
|
||||
- Anything that requires the user to opt in to skills per-session
|
||||
- Anything where brainstorming does not auto-trigger on the test above
|
||||
|
||||
If you are not sure whether your integration loads the bootstrap at
|
||||
session start, it does not.
|
||||
-->
|
||||
|
||||
<details>
|
||||
<summary>Clean-session transcript for "Let's make a react todo list"</summary>
|
||||
|
||||
```
|
||||
paste the complete transcript here
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Evaluation
|
||||
- What was the initial prompt you (or your human partner) used to start
|
||||
the session that led to this change?
|
||||
|
||||
@@ -14,10 +14,14 @@ Add superpowers to the `plugin` array in your `opencode.json` (global or project
|
||||
}
|
||||
```
|
||||
|
||||
Restart OpenCode. That's it — the plugin auto-installs and registers all skills.
|
||||
Restart OpenCode. The plugin installs through OpenCode's plugin manager and
|
||||
registers all skills.
|
||||
|
||||
Verify by asking: "Tell me about your superpowers"
|
||||
|
||||
OpenCode uses its own plugin install. If you also use Claude Code, Codex, or
|
||||
another harness, install Superpowers separately for each one.
|
||||
|
||||
## Migrating from the old symlink-based install
|
||||
|
||||
If you previously installed superpowers using `git clone` and symlinks, remove the old setup:
|
||||
@@ -46,7 +50,10 @@ use skill tool to load superpowers/brainstorming
|
||||
|
||||
## Updating
|
||||
|
||||
Superpowers updates automatically when you restart OpenCode.
|
||||
OpenCode installs Superpowers through a git-backed package spec. Some OpenCode
|
||||
and Bun versions pin that resolved git dependency in a lockfile or cache, so a
|
||||
restart may not pick up the newest Superpowers commit. If updates do not appear,
|
||||
clear OpenCode's package cache or reinstall the plugin.
|
||||
|
||||
To pin a specific version:
|
||||
|
||||
@@ -64,6 +71,26 @@ To pin a specific version:
|
||||
2. Verify the plugin line in your `opencode.json`
|
||||
3. Make sure you're running a recent version of OpenCode
|
||||
|
||||
### Windows install issues
|
||||
|
||||
Some Windows OpenCode builds have upstream installer issues with git-backed
|
||||
plugin specs, including cache paths for `git+https` URLs and Bun not finding
|
||||
`git.exe` even when it works in a normal terminal. If OpenCode cannot install
|
||||
the plugin, try installing with system npm and pointing OpenCode at the local
|
||||
package:
|
||||
|
||||
```powershell
|
||||
npm install superpowers@git+https://github.com/obra/superpowers.git --prefix "$HOME\.config\opencode"
|
||||
```
|
||||
|
||||
Then use the installed package path in `opencode.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"plugin": ["~/.config/opencode/node_modules/superpowers"]
|
||||
}
|
||||
```
|
||||
|
||||
### Skills not found
|
||||
|
||||
1. Use `skill` tool to list what's discovered
|
||||
@@ -71,11 +98,15 @@ To pin a specific version:
|
||||
|
||||
### Tool mapping
|
||||
|
||||
When skills reference Claude Code tools:
|
||||
- `TodoWrite` → `todowrite`
|
||||
- `Task` with subagents → `@mention` syntax
|
||||
- `Skill` tool → OpenCode's native `skill` tool
|
||||
- File operations → your native tools
|
||||
Skills speak in actions ("create a todo", "dispatch a subagent", "read a file"). On OpenCode these resolve to:
|
||||
|
||||
- "Create a todo" / "mark complete in todo list" → `todowrite`
|
||||
- `Subagent (general-purpose):` template → `task` tool with `subagent_type: "general"` (or `"explore"` for codebase exploration)
|
||||
- "Invoke a skill" → OpenCode's native `skill` tool
|
||||
- "Read a file" / "create a file" / "edit a file" → `read`, `write`, `edit`
|
||||
- "Run a shell command" → `bash`
|
||||
- "Search file contents" / "find files by name" → `grep`, `glob`
|
||||
- "Fetch a URL" / "search the web" → `webfetch`, `websearch`
|
||||
|
||||
## Getting Help
|
||||
|
||||
|
||||
@@ -46,17 +46,29 @@ const normalizePath = (p, homeDir) => {
|
||||
return path.resolve(normalized);
|
||||
};
|
||||
|
||||
// Module-level cache for bootstrap content.
|
||||
// The SKILL.md file does not change during a session, so reading + parsing it
|
||||
// once eliminates redundant fs.existsSync + fs.readFileSync + regex work on
|
||||
// every agent step. See #1202 for the full analysis.
|
||||
let _bootstrapCache = undefined; // undefined = not yet loaded, null = file missing
|
||||
|
||||
export const SuperpowersPlugin = async ({ client, directory }) => {
|
||||
const homeDir = os.homedir();
|
||||
const superpowersSkillsDir = path.resolve(__dirname, '../../skills');
|
||||
const envConfigDir = normalizePath(process.env.OPENCODE_CONFIG_DIR, homeDir);
|
||||
const configDir = envConfigDir || path.join(homeDir, '.config/opencode');
|
||||
|
||||
// Helper to generate bootstrap content
|
||||
// Helper to generate bootstrap content (cached after first call)
|
||||
const getBootstrapContent = () => {
|
||||
// Return cached result on subsequent calls
|
||||
if (_bootstrapCache !== undefined) return _bootstrapCache;
|
||||
|
||||
// Try to load using-superpowers skill
|
||||
const skillPath = path.join(superpowersSkillsDir, 'using-superpowers', 'SKILL.md');
|
||||
if (!fs.existsSync(skillPath)) return null;
|
||||
if (!fs.existsSync(skillPath)) {
|
||||
_bootstrapCache = null;
|
||||
return null;
|
||||
}
|
||||
|
||||
const fullContent = fs.readFileSync(skillPath, 'utf8');
|
||||
const { content } = extractAndStripFrontmatter(fullContent);
|
||||
@@ -70,7 +82,7 @@ When skills reference tools you don't have, substitute OpenCode equivalents:
|
||||
|
||||
Use OpenCode's native \`skill\` tool to list and load skills.`;
|
||||
|
||||
return `<EXTREMELY_IMPORTANT>
|
||||
_bootstrapCache = `<EXTREMELY_IMPORTANT>
|
||||
You have superpowers.
|
||||
|
||||
**IMPORTANT: The using-superpowers skill content is included below. It is ALREADY LOADED - you are currently following it. Do NOT use the skill tool to load "using-superpowers" again - that would be redundant.**
|
||||
@@ -79,6 +91,8 @@ ${content}
|
||||
|
||||
${toolMapping}
|
||||
</EXTREMELY_IMPORTANT>`;
|
||||
|
||||
return _bootstrapCache;
|
||||
};
|
||||
|
||||
return {
|
||||
@@ -98,13 +112,22 @@ ${toolMapping}
|
||||
// Using a user message instead of a system message avoids:
|
||||
// 1. Token bloat from system messages repeated every turn (#750)
|
||||
// 2. Multiple system messages breaking Qwen and other models (#894)
|
||||
//
|
||||
// The hook fires on every agent step (not just every turn) because
|
||||
// opencode's prompt.ts reloads messages from DB each step. Fresh message
|
||||
// arrays may need injection again, so getBootstrapContent() must not do
|
||||
// repeated disk work.
|
||||
'experimental.chat.messages.transform': async (_input, output) => {
|
||||
const bootstrap = getBootstrapContent();
|
||||
if (!bootstrap || !output.messages.length) return;
|
||||
const firstUser = output.messages.find(m => m.info.role === 'user');
|
||||
if (!firstUser || !firstUser.parts.length) return;
|
||||
// Only inject once
|
||||
|
||||
// Guard: skip if first user message already contains bootstrap.
|
||||
// This prevents double injection when OpenCode passes an already
|
||||
// transformed in-memory message array through the hook again.
|
||||
if (firstUser.parts.some(p => p.type === 'text' && p.text.includes('EXTREMELY_IMPORTANT'))) return;
|
||||
|
||||
const ref = firstUser.parts[0];
|
||||
firstUser.parts.unshift({ ...ref, type: 'text', text: bootstrap });
|
||||
}
|
||||
|
||||
20
.version-bump.json
Normal file
20
.version-bump.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"files": [
|
||||
{ "path": "package.json", "field": "version" },
|
||||
{ "path": ".claude-plugin/plugin.json", "field": "version" },
|
||||
{ "path": ".cursor-plugin/plugin.json", "field": "version" },
|
||||
{ "path": ".codex-plugin/plugin.json", "field": "version" },
|
||||
{ "path": ".claude-plugin/marketplace.json", "field": "plugins.0.version" },
|
||||
{ "path": "gemini-extension.json", "field": "version" }
|
||||
],
|
||||
"audit": {
|
||||
"exclude": [
|
||||
"CHANGELOG.md",
|
||||
"RELEASE-NOTES.md",
|
||||
"node_modules",
|
||||
".git",
|
||||
".version-bump.json",
|
||||
"scripts/bump-version.sh"
|
||||
]
|
||||
}
|
||||
}
|
||||
13
CHANGELOG.md
13
CHANGELOG.md
@@ -1,13 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
## [5.0.5] - 2026-03-17
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Brainstorm server ESM fix**: Renamed `server.js` → `server.cjs` so the brainstorming server starts correctly on Node.js 22+ where the root `package.json` `"type": "module"` caused `require()` to fail. ([PR #784](https://github.com/obra/superpowers/pull/784) by @sarbojitrana, fixes [#774](https://github.com/obra/superpowers/issues/774), [#780](https://github.com/obra/superpowers/issues/780), [#783](https://github.com/obra/superpowers/issues/783))
|
||||
- **Brainstorm owner-PID on Windows**: Skip `BRAINSTORM_OWNER_PID` lifecycle monitoring on Windows/MSYS2 where the PID namespace is invisible to Node.js. Prevents the server from self-terminating after 60 seconds. The 30-minute idle timeout remains as the safety net. ([#770](https://github.com/obra/superpowers/issues/770), docs from [PR #768](https://github.com/obra/superpowers/pull/768) by @lucasyhzhu-debug)
|
||||
- **stop-server.sh reliability**: Verify the server process actually died before reporting success. Waits up to 2 seconds for graceful shutdown, escalates to `SIGKILL`, and reports failure if the process survives. ([#723](https://github.com/obra/superpowers/issues/723))
|
||||
|
||||
### Changed
|
||||
|
||||
- **Execution handoff**: Restore user choice between subagent-driven-development and executing-plans after plan writing. Subagent-driven is recommended but no longer mandatory. (Reverts `5e51c3e`)
|
||||
106
CLAUDE.md
Normal file
106
CLAUDE.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# Superpowers — Contributor Guidelines
|
||||
|
||||
## If You Are an AI Agent
|
||||
|
||||
Stop. Read this section before doing anything.
|
||||
|
||||
This repo has a 94% PR rejection rate. Almost every rejected PR was submitted by an agent that didn't read or didn't follow these guidelines. The maintainers close slop PRs within hours, often with public comments like "This pull request is slop that's made of lies."
|
||||
|
||||
**Your job is to protect your human partner from that outcome.** Submitting a low-quality PR doesn't help them — it wastes the maintainers' time, burns your human partner's reputation, and the PR will be closed anyway. That is not being helpful. That is being a tool of embarrassment.
|
||||
|
||||
Before you open a PR against this repo, you MUST:
|
||||
|
||||
1. **Read the entire PR template** at `.github/PULL_REQUEST_TEMPLATE.md` and fill in every section with real, specific answers. Not summaries. Not placeholders.
|
||||
2. **Search for existing PRs** — open AND closed — that address the same problem. If duplicates exist, STOP and tell your human partner. Do not open another duplicate.
|
||||
3. **Verify this is a real problem.** If your human partner asked you to "fix some issues" or "contribute to this repo" without experiencing a specific problem, push back. Ask them what broke, what failed, what the user experience was.
|
||||
4. **Confirm the change belongs in core.** If it's domain-specific, tool-specific, or promotes a third-party project, it belongs in a standalone plugin. Tell your human partner.
|
||||
5. **Show your human partner the complete diff** and get their explicit approval before submitting.
|
||||
|
||||
If any of these checks fail, do not open the PR. Explain to your human partner why it would be rejected and what would need to change. They will thank you for saving them the embarrassment.
|
||||
|
||||
## Pull Request Requirements
|
||||
|
||||
**Every PR must fully complete the PR template.** No section may be left blank or filled with placeholder text. PRs that skip sections will be closed without review.
|
||||
|
||||
**Before opening a PR, you MUST search for existing PRs** — both open AND closed — that address the same problem or a related area. Reference what you found in the "Existing PRs" section. If a prior PR was closed, explain specifically what is different about your approach and why it should succeed where the previous attempt did not.
|
||||
|
||||
**PRs that show no evidence of human involvement will be closed.** A human must review the complete proposed diff before submission.
|
||||
|
||||
## What We Will Not Accept
|
||||
|
||||
### Third-party dependencies
|
||||
|
||||
PRs that add optional or required dependencies on third-party projects will not be accepted unless they are adding support for a new harness (e.g., a new IDE or CLI tool). Superpowers is a zero-dependency plugin by design. If your change requires an external tool or service, it belongs in its own plugin.
|
||||
|
||||
### "Compliance" changes to skills
|
||||
|
||||
Our internal skill philosophy differs from Anthropic's published guidance on writing skills. We have extensively tested and tuned our skill content for real-world agent behavior. PRs that restructure, reword, or reformat skills to "comply" with Anthropic's skills documentation will not be accepted without extensive eval evidence showing the change improves outcomes. The bar for modifying behavior-shaping content is very high.
|
||||
|
||||
### Project-specific or personal configuration
|
||||
|
||||
Skills, hooks, or configuration that only benefit a specific project, team, domain, or workflow do not belong in core. Publish these as a separate plugin.
|
||||
|
||||
### Bulk or spray-and-pray PRs
|
||||
|
||||
Do not trawl the issue tracker and open PRs for multiple issues in a single session. Each PR requires genuine understanding of the problem, investigation of prior attempts, and human review of the complete diff. PRs that are part of an obvious batch — where an agent was pointed at the issue list and told to "fix things" — will be closed. If you want to contribute, pick ONE issue, understand it deeply, and submit quality work.
|
||||
|
||||
### Speculative or theoretical fixes
|
||||
|
||||
Every PR must solve a real problem that someone actually experienced. "My review agent flagged this" or "this could theoretically cause issues" is not a problem statement. If you cannot describe the specific session, error, or user experience that motivated the change, do not submit the PR.
|
||||
|
||||
### Domain-specific skills
|
||||
|
||||
Superpowers core contains general-purpose skills that benefit all users regardless of their project. Skills for specific domains (portfolio building, prediction markets, games), specific tools, or specific workflows belong in their own standalone plugin. Ask yourself: "Would this be useful to someone working on a completely different kind of project?" If not, publish it separately.
|
||||
|
||||
### Fork-specific changes
|
||||
|
||||
If you maintain a fork with customizations, do not open PRs to sync your fork or push fork-specific changes upstream. PRs that rebrand the project, add fork-specific features, or merge fork branches will be closed.
|
||||
|
||||
### Fabricated content
|
||||
|
||||
PRs containing invented claims, fabricated problem descriptions, or hallucinated functionality will be closed immediately. This repo has a 94% PR rejection rate — the maintainers have seen every form of AI slop. They will notice.
|
||||
|
||||
### Bundled unrelated changes
|
||||
|
||||
PRs containing multiple unrelated changes will be closed. Split them into separate PRs.
|
||||
|
||||
## New Harness Support
|
||||
|
||||
If your PR adds support for a new harness (IDE, CLI tool, agent runner), you MUST include a session transcript proving the integration works end-to-end.
|
||||
|
||||
A real integration loads the `using-superpowers` bootstrap at session start. The bootstrap is what causes skills to auto-trigger at the right moments. Without it, the skills are dead weight — present on disk but never invoked.
|
||||
|
||||
**The acceptance test.** Open a clean session in the new harness and send exactly this user message:
|
||||
|
||||
> Let's make a react todo list
|
||||
|
||||
A working integration auto-triggers the `brainstorming` skill before any code is written. Paste the complete transcript in the PR.
|
||||
|
||||
**These are not real integrations and will be closed:**
|
||||
|
||||
- Manually copying skill files into the harness
|
||||
- Wrapping with `npx skills` or similar at-runtime shims
|
||||
- Anything that requires the user to opt in to skills per-session
|
||||
- Anything where `brainstorming` does not auto-trigger on the acceptance test above
|
||||
|
||||
If you are not sure whether your integration loads the bootstrap at session start, it does not.
|
||||
|
||||
## Skill Changes Require Evaluation
|
||||
|
||||
Skills are not prose — they are code that shapes agent behavior. If you modify skill content:
|
||||
|
||||
- Use `superpowers:writing-skills` to develop and test changes
|
||||
- Run adversarial pressure testing across multiple sessions
|
||||
- Show before/after eval results in your PR
|
||||
- Do not modify carefully-tuned content (Red Flags tables, rationalization lists, "human partner" language) without evidence the change is an improvement
|
||||
|
||||
## Understand the Project Before Contributing
|
||||
|
||||
Before proposing changes to skill design, workflow philosophy, or architecture, read existing skills and understand the project's design decisions. Superpowers has its own tested philosophy about skill design, agent behavior shaping, and terminology (e.g., "your human partner" is deliberate, not interchangeable with "the user"). Changes that rewrite the project's voice or restructure its approach without understanding why it exists will be rejected.
|
||||
|
||||
## General
|
||||
|
||||
- Read `.github/PULL_REQUEST_TEMPLATE.md` before submitting
|
||||
- One problem per PR
|
||||
- Test on at least one harness and report results in the environment table
|
||||
- Describe the problem you solved, not just what you changed
|
||||
169
README.md
169
README.md
@@ -1,6 +1,10 @@
|
||||
# Superpowers
|
||||
|
||||
Superpowers is a complete software development workflow for your coding agents, built on top of a set of composable "skills" and some initial instructions that make sure your agent uses them.
|
||||
Superpowers is a complete software development methodology for your coding agents, built on top of a set of composable skills and some initial instructions that make sure your agent uses them.
|
||||
|
||||
## Quickstart
|
||||
|
||||
Give your agent Superpowers: [Claude Code](#claude-code), [Codex App](#codex-app), [Codex CLI](#codex-cli), [Cursor](#cursor), [Factory Droid](#factory-droid), [Gemini CLI](#gemini-cli), [GitHub Copilot CLI](#github-copilot-cli), [OpenCode](#opencode).
|
||||
|
||||
## How it works
|
||||
|
||||
@@ -10,7 +14,7 @@ Once it's teased a spec out of the conversation, it shows it to you in chunks sh
|
||||
|
||||
After you've signed off on the design, your agent puts together an implementation plan that's clear enough for an enthusiastic junior engineer with poor taste, no judgement, no project context, and an aversion to testing to follow. It emphasizes true red/green TDD, YAGNI (You Aren't Gonna Need It), and DRY.
|
||||
|
||||
Next up, once you say "go", it launches a *subagent-driven-development* process, having agents work through each engineering task, inspecting and reviewing their work, and continuing forward. It's not uncommon for Claude to be able to work autonomously for a couple hours at a time without deviating from the plan you put together.
|
||||
Next up, once you say "go", it launches a *subagent-driven-development* process, having agents work through each engineering task, inspecting and reviewing their work, and continuing forward. It's not uncommon for your agent to work autonomously for a couple hours at a time without deviating from the plan you put together.
|
||||
|
||||
There's a bunch more to it, but that's the core of the system. And because the skills trigger automatically, you don't need to do anything special. Your coding agent just has Superpowers.
|
||||
|
||||
@@ -26,84 +30,126 @@ Thanks!
|
||||
|
||||
## Installation
|
||||
|
||||
**Note:** Installation differs by platform. Claude Code or Cursor have built-in plugin marketplaces. Codex and OpenCode require manual setup.
|
||||
Installation differs by harness. If you use more than one, install Superpowers separately for each one.
|
||||
|
||||
### Claude Code Official Marketplace
|
||||
### Claude Code
|
||||
|
||||
Superpowers is available via the [official Claude plugin marketplace](https://claude.com/plugins/superpowers)
|
||||
|
||||
Install the plugin from Claude marketplace:
|
||||
#### Official Marketplace
|
||||
|
||||
```bash
|
||||
/plugin install superpowers@claude-plugins-official
|
||||
```
|
||||
- Install the plugin from Anthropic's official marketplace:
|
||||
|
||||
### Claude Code (via Plugin Marketplace)
|
||||
```bash
|
||||
/plugin install superpowers@claude-plugins-official
|
||||
```
|
||||
|
||||
In Claude Code, register the marketplace first:
|
||||
#### Superpowers Marketplace
|
||||
|
||||
```bash
|
||||
/plugin marketplace add obra/superpowers-marketplace
|
||||
```
|
||||
The Superpowers marketplace provides Superpowers and some other related plugins for Claude Code.
|
||||
|
||||
Then install the plugin from this marketplace:
|
||||
- Register the marketplace:
|
||||
|
||||
```bash
|
||||
/plugin install superpowers@superpowers-marketplace
|
||||
```
|
||||
```bash
|
||||
/plugin marketplace add obra/superpowers-marketplace
|
||||
```
|
||||
|
||||
### Cursor (via Plugin Marketplace)
|
||||
- Install the plugin from this marketplace:
|
||||
|
||||
In Cursor Agent chat, install from marketplace:
|
||||
```bash
|
||||
/plugin install superpowers@superpowers-marketplace
|
||||
```
|
||||
|
||||
```text
|
||||
/add-plugin superpowers
|
||||
```
|
||||
### Codex App
|
||||
|
||||
or search for "superpowers" in the plugin marketplace.
|
||||
Superpowers is available via the [official Codex plugin marketplace](https://github.com/openai/plugins).
|
||||
|
||||
### Codex
|
||||
- In the Codex app, click on Plugins in the sidebar.
|
||||
- You should see `Superpowers` in the Coding section.
|
||||
- Click the `+` next to Superpowers and follow the prompts.
|
||||
|
||||
Tell Codex:
|
||||
### Codex CLI
|
||||
|
||||
```
|
||||
Fetch and follow instructions from https://raw.githubusercontent.com/obra/superpowers/refs/heads/main/.codex/INSTALL.md
|
||||
```
|
||||
Superpowers is available via the [official Codex plugin marketplace](https://github.com/openai/plugins).
|
||||
|
||||
**Detailed docs:** [docs/README.codex.md](docs/README.codex.md)
|
||||
- Open the plugin search interface:
|
||||
|
||||
### OpenCode
|
||||
```bash
|
||||
/plugins
|
||||
```
|
||||
|
||||
Tell OpenCode:
|
||||
- Search for Superpowers:
|
||||
|
||||
```
|
||||
Fetch and follow instructions from https://raw.githubusercontent.com/obra/superpowers/refs/heads/main/.opencode/INSTALL.md
|
||||
```
|
||||
```bash
|
||||
superpowers
|
||||
```
|
||||
|
||||
**Detailed docs:** [docs/README.opencode.md](docs/README.opencode.md)
|
||||
- Select `Install Plugin`.
|
||||
|
||||
### GitHub Copilot CLI
|
||||
### Cursor
|
||||
|
||||
```bash
|
||||
copilot plugin marketplace add obra/superpowers-marketplace
|
||||
copilot plugin install superpowers@superpowers-marketplace
|
||||
```
|
||||
- In Cursor Agent chat, install from marketplace:
|
||||
|
||||
```text
|
||||
/add-plugin superpowers
|
||||
```
|
||||
|
||||
- Or search for "superpowers" in the plugin marketplace.
|
||||
|
||||
### Factory Droid
|
||||
|
||||
- Register the marketplace:
|
||||
|
||||
```bash
|
||||
droid plugin marketplace add https://github.com/obra/superpowers
|
||||
```
|
||||
|
||||
- Install the plugin:
|
||||
|
||||
```bash
|
||||
droid plugin install superpowers@superpowers
|
||||
```
|
||||
|
||||
### Gemini CLI
|
||||
|
||||
```bash
|
||||
gemini extensions install https://github.com/obra/superpowers
|
||||
```
|
||||
- Install the extension:
|
||||
|
||||
To update:
|
||||
```bash
|
||||
gemini extensions install https://github.com/obra/superpowers
|
||||
```
|
||||
|
||||
```bash
|
||||
gemini extensions update superpowers
|
||||
```
|
||||
- Update later:
|
||||
|
||||
### Verify Installation
|
||||
```bash
|
||||
gemini extensions update superpowers
|
||||
```
|
||||
|
||||
Start a new session in your chosen platform and ask for something that should trigger a skill (for example, "help me plan this feature" or "let's debug this issue"). The agent should automatically invoke the relevant superpowers skill.
|
||||
### GitHub Copilot CLI
|
||||
|
||||
- Register the marketplace:
|
||||
|
||||
```bash
|
||||
copilot plugin marketplace add obra/superpowers-marketplace
|
||||
```
|
||||
|
||||
- Install the plugin:
|
||||
|
||||
```bash
|
||||
copilot plugin install superpowers@superpowers-marketplace
|
||||
```
|
||||
|
||||
### OpenCode
|
||||
|
||||
OpenCode uses its own plugin install; install Superpowers separately even if you
|
||||
already use it in another harness.
|
||||
|
||||
- Tell OpenCode:
|
||||
|
||||
```
|
||||
Fetch and follow instructions from https://raw.githubusercontent.com/obra/superpowers/refs/heads/main/.opencode/INSTALL.md
|
||||
```
|
||||
|
||||
- Detailed docs: [docs/README.opencode.md](docs/README.opencode.md)
|
||||
|
||||
## The Basic Workflow
|
||||
|
||||
@@ -156,26 +202,23 @@ Start a new session in your chosen platform and ask for something that should tr
|
||||
- **Complexity reduction** - Simplicity as primary goal
|
||||
- **Evidence over claims** - Verify before declaring success
|
||||
|
||||
Read more: [Superpowers for Claude Code](https://blog.fsck.com/2025/10/09/superpowers/)
|
||||
Read [the original release announcement](https://blog.fsck.com/2025/10/09/superpowers/).
|
||||
|
||||
## Contributing
|
||||
|
||||
Skills live directly in this repository. To contribute:
|
||||
The general contribution process for Superpowers is below. Keep in mind that we don't generally accept contributions of new skills and that any updates to skills must work across all of the coding agents we support.
|
||||
|
||||
1. Fork the repository
|
||||
2. Create a branch for your skill
|
||||
3. Follow the `writing-skills` skill for creating and testing new skills
|
||||
4. Submit a PR
|
||||
2. Switch to the 'dev' branch
|
||||
3. Create a branch for your work
|
||||
4. Follow the `writing-skills` skill for creating and testing new and modified skills
|
||||
5. Submit a PR, being sure to fill in the pull request template.
|
||||
|
||||
See `skills/writing-skills/SKILL.md` for the complete guide.
|
||||
|
||||
## Updating
|
||||
|
||||
Skills update automatically when you update the plugin:
|
||||
|
||||
```bash
|
||||
/plugin update superpowers
|
||||
```
|
||||
Superpowers updates are somewhat coding-agent dependent, but are often automatic.
|
||||
|
||||
## License
|
||||
|
||||
@@ -185,10 +228,6 @@ MIT License - see LICENSE file for details
|
||||
|
||||
Superpowers is built by [Jesse Vincent](https://blog.fsck.com) and the rest of the folks at [Prime Radiant](https://primeradiant.com).
|
||||
|
||||
For community support, questions, and sharing what you're building with Superpowers, join us on [Discord](https://discord.gg/Jd8Vphy9jq).
|
||||
|
||||
## Support
|
||||
|
||||
- **Discord**: [Join us on Discord](https://discord.gg/Jd8Vphy9jq)
|
||||
- **Discord**: [Join us](https://discord.gg/35wsABTejz) for community support, questions, and sharing what you're building with Superpowers
|
||||
- **Issues**: https://github.com/obra/superpowers/issues
|
||||
- **Marketplace**: https://github.com/obra/superpowers-marketplace
|
||||
- **Release announcements**: [Sign up](https://primeradiant.com/superpowers/) to get notified about new versions
|
||||
|
||||
@@ -1,6 +1,90 @@
|
||||
# Superpowers Release Notes
|
||||
|
||||
## Unreleased
|
||||
## v5.1.0 (2026-04-30)
|
||||
|
||||
### Removals
|
||||
|
||||
- **Legacy slash commands removed** — `/brainstorm`, `/execute-plan`, and `/write-plan` are gone. They were deprecated stubs that did nothing but tell the user to invoke the corresponding skill. Invoke `superpowers:brainstorming`, `superpowers:executing-plans`, and `superpowers:writing-plans` directly instead. (#1188)
|
||||
- **`superpowers:code-reviewer` named agent removed** — the agent was the plugin's only named agent and was used by exactly two skills, while every other reviewer/implementer subagent in the repo dispatches `general-purpose` with a prompt template alongside its skill. The agent's persona and checklist have been merged into `skills/requesting-code-review/code-reviewer.md` as a self-contained Task-dispatch template. Anyone dispatching `Task (superpowers:code-reviewer)` should switch to `Task (general-purpose)` with the prompt template instead. (PR #1299)
|
||||
- **Integration sections removed from skills** — these were a legacy of the time before agents had native skills systems and didn't help with steering.
|
||||
|
||||
### Worktree Skills Rewrite
|
||||
|
||||
`using-git-worktrees` and `finishing-a-development-branch` now detect when the agent is already running inside an isolated worktree and prefer the harness's native worktree controls before falling back to `git worktree`. Behavior was TDD-validated and cross-platform-checked across five harnesses. (PRI-974, PR #1121)
|
||||
|
||||
- **Environment detection** — both skills check `GIT_DIR != GIT_COMMON` before doing anything; if already in a linked worktree, creation is skipped entirely. A submodule guard prevents false detection.
|
||||
- **Consent before creating worktrees** — `using-git-worktrees` no longer creates worktrees implicitly; the skill asks the user first. Fixes #991 (subagent-driven-development was auto-creating worktrees without consent).
|
||||
- **Native tool preference (Step 1a)** — when the harness exposes its own worktree tool (e.g. Codex), the skill defers to it. The user's stated preference is respected when expressed.
|
||||
- **Provenance-based cleanup** — `finishing-a-development-branch` only cleans up worktrees inside `.worktrees/` (created by superpowers); anything outside is left alone. Fixes #940 (Option 2 was incorrectly cleaning up worktrees), #999 (merge-then-remove ordering), and #238 (`cd` to repo root before `git worktree remove`).
|
||||
- **Detached HEAD handling** — the finishing menu collapses to two options when there is no branch to merge from.
|
||||
- **Hardcoded `/Users/jesse` paths** in skill examples replaced with generic placeholders. (#858, PR #1122)
|
||||
|
||||
### Contributor Guidelines for AI Agents
|
||||
|
||||
Two new sections at the top of `CLAUDE.md` (symlinked to `AGENTS.md`) speak directly to AI agents. An audit of the last 100 closed PRs against this repo showed a 94% rejection rate driven by AI-generated slop: agents that didn't read the PR template, opened duplicates, fabricated problem descriptions, or pushed fork- or domain-specific changes upstream.
|
||||
|
||||
- **Pre-submission checklist** — read the PR template, search for existing PRs, verify a real problem exists, confirm the change belongs in core, and show the human partner the complete diff before submitting.
|
||||
- **What we will not accept** — third-party dependencies, "compliance" rewrites of skill content, project-specific configuration, bulk PRs, speculative fixes, domain-specific skills, fork-specific changes, fabricated content, and bundled unrelated changes.
|
||||
- **New harness PRs require a session transcript** — most past new-harness integrations copied skill files or wrapped with `npx skills` instead of loading the `using-superpowers` bootstrap at session start. The acceptance test ("Let's make a react todo list" must auto-trigger `brainstorming` in a clean session) and a complete transcript are now required.
|
||||
|
||||
### Codex Plugin Mirror Tooling
|
||||
|
||||
New `sync-to-codex-plugin` script mirrors superpowers into the OpenAI Codex plugin marketplace as `prime-radiant-inc/openai-codex-plugins`. Path/user-agnostic so any team member can run it. (PR #1165)
|
||||
|
||||
- Clones the fork fresh into a temp directory per run, regenerates overlays inline, and opens a PR; auto-detects upstream from the script's own location and preflights `rsync`/`git`/`gh auth`/`python3`.
|
||||
- `--bootstrap` flag for first-time setup; `EXCLUDES` patterns anchored to source root; `assets/` excluded.
|
||||
- Mirrors `CODE_OF_CONDUCT.md`; drops the `agents/openai.yaml` overlay.
|
||||
- Seeds `interface.defaultPrompt` in the mirrored `plugin.json`. (PR #1180 by @arittr)
|
||||
- Codex plugin files are committed to the source repo so the sync script uses canonical versions; Codex marketplace metadata is preserved.
|
||||
|
||||
### OpenCode
|
||||
|
||||
- **Bootstrap content cached at module level** — `getBootstrapContent()` was calling `fs.existsSync` + `fs.readFileSync` + frontmatter regex on every agent step (the `experimental.chat.messages.transform` hook fires on every step in OpenCode's agent loop). Now read once, cached for the session lifetime, with a null sentinel for the missing-file case. 15 regression tests cover cache behavior, fs call counts, the injection guard, the missing-file sentinel, and cache reset. (Fixes #1202)
|
||||
- **Integration tests modernized**.
|
||||
- **Install caveats clarified** in the README.
|
||||
|
||||
### Code Review Consolidation
|
||||
|
||||
`requesting-code-review` is now self-contained: the persona, checklist, and dispatch template live in `skills/requesting-code-review/code-reviewer.md` and the skill dispatches `Task (general-purpose)` directly. (PR #1299)
|
||||
|
||||
- **Single source of truth** — the persona/checklist that previously lived in both `agents/code-reviewer.md` and the skill's placeholder template (and drifted independently) is now one file.
|
||||
- **`subagent-driven-development` follows suit** — its `code-quality-reviewer-prompt.md` now dispatches `Task (general-purpose)` instead of the named agent.
|
||||
- **Behavioral test added** — `tests/claude-code/test-requesting-code-review.sh` plants real bugs (SQL injection, plaintext password handling, credential logging) into a tiny project and asserts the dispatched reviewer flags every planted issue at Critical/Important severity and refuses to approve the diff.
|
||||
- **Codex and Copilot workaround docs trimmed** — the "Named agent dispatch" sections in `references/codex-tools.md` and `references/copilot-tools.md` documented how to flatten a named agent into a generic dispatch. With no named agents shipping, the workaround is unnecessary; both sections were dropped.
|
||||
|
||||
### Subagent-Driven Development
|
||||
|
||||
- **No more pause every 3 tasks** — the "review after each batch (3 tasks)" cadence in `requesting-code-review` (originally for `executing-plans`) was leaking into `subagent-driven-development`. Replaced with "each task or at natural checkpoints" plus an explicit continuous-execution directive.
|
||||
- **SDD integration test now runs its assertions** — three independent bugs caused the test to silently bail before printing any verification results: an unresolved `..` segment in the working-dir path, a `set -euo pipefail` interaction with `find | sort | head -1` (SIGPIPE on the producer killed the script), and a missing `--plugin-dir` on the `claude -p` invocation that caused the test to load the installed plugin instead of the working tree. All three fixed; six verification tests now actually run against a real end-to-end SDD run.
|
||||
|
||||
### Cursor
|
||||
|
||||
- **Windows SessionStart hook** routed through `run-hook.cmd` instead of invoking the extensionless `session-start` script directly. Fixes Windows opening the file in an editor instead of running it. Also removed an accidental UTF-8 BOM from `hooks-cursor.json`.
|
||||
|
||||
### Gemini CLI
|
||||
|
||||
- **Subagent dispatch mapping** — Gemini's `Task` dispatch now maps to `@agent-name` / `@generalist`, with parallel subagent dispatch documented for independent tasks.
|
||||
|
||||
### Skills
|
||||
|
||||
- **Terminology cleanups** across skill content.
|
||||
|
||||
### Documentation & Install
|
||||
|
||||
- **Factory Droid installation instructions** added to README.
|
||||
- **Quickstart install links** in README. (PR #1293 by @arittr)
|
||||
- **Codex plugin install guidance** updated. (PR #1288 by @arittr)
|
||||
- **Codex `wait` mapping corrected** to `wait_agent` in the tools reference.
|
||||
- **Install order reorganized**; Codex install instructions cleaned up.
|
||||
- **Removed vestigial `CHANGELOG.md`** in favor of `RELEASE-NOTES.md` as the single source. (PR #1163 by @shaanmajid)
|
||||
- **Discord invite link** fixed; release announcements link and a detailed Discord description added to the Community section.
|
||||
|
||||
### Community
|
||||
|
||||
- @shaanmajid — vestigial `CHANGELOG.md` removal (PR #1163)
|
||||
- @arittr — README quickstart install links (#1293), Codex plugin install guidance (#1288), `sync-to-codex-plugin` `interface.defaultPrompt` seed (#1180)
|
||||
|
||||
## v5.0.7 (2026-03-31)
|
||||
|
||||
### GitHub Copilot CLI Support
|
||||
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
---
|
||||
name: code-reviewer
|
||||
description: |
|
||||
Use this agent when a major project step has been completed and needs to be reviewed against the original plan and coding standards. Examples: <example>Context: The user is creating a code-review agent that should be called after a logical chunk of code is written. user: "I've finished implementing the user authentication system as outlined in step 3 of our plan" assistant: "Great work! Now let me use the code-reviewer agent to review the implementation against our plan and coding standards" <commentary>Since a major project step has been completed, use the code-reviewer agent to validate the work against the plan and identify any issues.</commentary></example> <example>Context: User has completed a significant feature implementation. user: "The API endpoints for the task management system are now complete - that covers step 2 from our architecture document" assistant: "Excellent! Let me have the code-reviewer agent examine this implementation to ensure it aligns with our plan and follows best practices" <commentary>A numbered step from the planning document has been completed, so the code-reviewer agent should review the work.</commentary></example>
|
||||
model: inherit
|
||||
---
|
||||
|
||||
You are a Senior Code Reviewer with expertise in software architecture, design patterns, and best practices. Your role is to review completed project steps against original plans and ensure code quality standards are met.
|
||||
|
||||
When reviewing completed work, you will:
|
||||
|
||||
1. **Plan Alignment Analysis**:
|
||||
- Compare the implementation against the original planning document or step description
|
||||
- Identify any deviations from the planned approach, architecture, or requirements
|
||||
- Assess whether deviations are justified improvements or problematic departures
|
||||
- Verify that all planned functionality has been implemented
|
||||
|
||||
2. **Code Quality Assessment**:
|
||||
- Review code for adherence to established patterns and conventions
|
||||
- Check for proper error handling, type safety, and defensive programming
|
||||
- Evaluate code organization, naming conventions, and maintainability
|
||||
- Assess test coverage and quality of test implementations
|
||||
- Look for potential security vulnerabilities or performance issues
|
||||
|
||||
3. **Architecture and Design Review**:
|
||||
- Ensure the implementation follows SOLID principles and established architectural patterns
|
||||
- Check for proper separation of concerns and loose coupling
|
||||
- Verify that the code integrates well with existing systems
|
||||
- Assess scalability and extensibility considerations
|
||||
|
||||
4. **Documentation and Standards**:
|
||||
- Verify that code includes appropriate comments and documentation
|
||||
- Check that file headers, function documentation, and inline comments are present and accurate
|
||||
- Ensure adherence to project-specific coding standards and conventions
|
||||
|
||||
5. **Issue Identification and Recommendations**:
|
||||
- Clearly categorize issues as: Critical (must fix), Important (should fix), or Suggestions (nice to have)
|
||||
- For each issue, provide specific examples and actionable recommendations
|
||||
- When you identify plan deviations, explain whether they're problematic or beneficial
|
||||
- Suggest specific improvements with code examples when helpful
|
||||
|
||||
6. **Communication Protocol**:
|
||||
- If you find significant deviations from the plan, ask the coding agent to review and confirm the changes
|
||||
- If you identify issues with the original plan itself, recommend plan updates
|
||||
- For implementation problems, provide clear guidance on fixes needed
|
||||
- Always acknowledge what was done well before highlighting issues
|
||||
|
||||
Your output should be structured, actionable, and focused on helping maintain high code quality while ensuring project goals are met. Be thorough but concise, and always provide constructive feedback that helps improve both the current implementation and future development practices.
|
||||
BIN
assets/app-icon.png
Normal file
BIN
assets/app-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
1
assets/superpowers-small.svg
Normal file
1
assets/superpowers-small.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="Calque_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M394.28,207.8c.81,2.41,1.39,4.78,1.8,7.07,1.61,9.03-.93,17.78-5.99,21.74-22.6,17.7-49.85,29.35-75.34,38.6-.59.22-1.09.28-1.4.34-2.22.47-4.95,1.04-7.25,0-1.46-.66-2.25-1.74-2.66-2.3-1.56-2.1-1.59-4.31-1.56-5.13.1-2.67-.01-4.69,0-4.82.45-3.52.91-10.66,1.41-21.28.6-3.87,2.16-9.63,6.94-13.96,4.01-3.62,8.33-4.6,14.59-5.87,10.76-2.19,37.21-8.22,47.42-16.56,1.63-1.33,2.97-2.65,4.19-3.96,3.72-3.99,6.39-7.92,7.93-10.36,3.22,3.22,7.25,8.48,9.92,16.47Z"/><path d="M428.67,185.28c-2.33,11.99-8.91,22.32-15.88,30.38.27-5.5-.05-12.11-1.86-19.08-5.04-19.36-19.74-34.7-37.78-37.78-32.21-9.74-70.59,3.79-99.08,18.29-3.87,1.95-9.52-2.77-11.84-8.16-3.32-7.71-1.63-6.28,2.61-8.49,38.31-20.03,82.01-39.61,123.91-29.7,8.26,1.95,15.96,5.26,23.48,10.54,11.32,7.96,20.21,24.74,16.44,44Z"/><path d="M117.72,304.2c-.81-2.41-1.39-4.78-1.8-7.07-1.61-9.03.93-17.78,5.99-21.74,22.6-17.7,49.85-29.35,75.34-38.6.59-.22,1.09-.28,1.4-.34,2.22-.47,4.95-1.04,7.25,0,1.46.66,2.25,1.74,2.66,2.3,1.56,2.1,1.59,4.31,1.56,5.13-.1,2.67.01,4.69,0,4.82-.45,3.52-.91,10.66-1.41,21.28-.6,3.87-2.16,9.63-6.94,13.96-4.01,3.62-8.33,4.6-14.59,5.87-10.76,2.19-37.21,8.22-47.42,16.56-1.63,1.33-2.97,2.65-4.19,3.96-3.72,3.99-6.39,7.92-7.93,10.36-3.22-3.22-7.25-8.48-9.92-16.47Z"/><path d="M83.33,326.72c2.33-11.99,8.91-22.32,15.88-30.38-.27,5.5.05,12.11,1.86,19.08,5.04,19.36,19.74,34.7,37.78,37.78,32.21,9.74,70.59-3.79,99.08-18.29,3.87-1.95,9.52,2.77,11.84,8.16,3.32,7.71,1.63,6.28-2.61,8.49-38.31,20.03-82.01,39.61-123.91,29.7-8.26-1.95-15.96-5.26-23.48-10.54-11.32-7.96-20.21-24.74-16.44-44Z"/><ellipse cx="255.16" cy="258.86" rx="28.95" ry="28.76"/></svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -1,5 +0,0 @@
|
||||
---
|
||||
description: "Deprecated - use the superpowers:brainstorming skill instead"
|
||||
---
|
||||
|
||||
Tell your human partner that this command is deprecated and will be removed in the next major release. They should ask you to use the "superpowers brainstorming" skill instead.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
description: "Deprecated - use the superpowers:executing-plans skill instead"
|
||||
---
|
||||
|
||||
Tell your human partner that this command is deprecated and will be removed in the next major release. They should ask you to use the "superpowers executing-plans" skill instead.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
description: "Deprecated - use the superpowers:writing-plans skill instead"
|
||||
---
|
||||
|
||||
Tell your human partner that this command is deprecated and will be removed in the next major release. They should ask you to use the "superpowers writing-plans" skill instead.
|
||||
@@ -1,126 +0,0 @@
|
||||
# Superpowers for Codex
|
||||
|
||||
Guide for using Superpowers with OpenAI Codex via native skill discovery.
|
||||
|
||||
## Quick Install
|
||||
|
||||
Tell Codex:
|
||||
|
||||
```
|
||||
Fetch and follow instructions from https://raw.githubusercontent.com/obra/superpowers/refs/heads/main/.codex/INSTALL.md
|
||||
```
|
||||
|
||||
## Manual Installation
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- OpenAI Codex CLI
|
||||
- Git
|
||||
|
||||
### Steps
|
||||
|
||||
1. Clone the repo:
|
||||
```bash
|
||||
git clone https://github.com/obra/superpowers.git ~/.codex/superpowers
|
||||
```
|
||||
|
||||
2. Create the skills symlink:
|
||||
```bash
|
||||
mkdir -p ~/.agents/skills
|
||||
ln -s ~/.codex/superpowers/skills ~/.agents/skills/superpowers
|
||||
```
|
||||
|
||||
3. Restart Codex.
|
||||
|
||||
4. **For subagent skills** (optional): Skills like `dispatching-parallel-agents` and `subagent-driven-development` require Codex's multi-agent feature. Add to your Codex config:
|
||||
```toml
|
||||
[features]
|
||||
multi_agent = true
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
Use a junction instead of a symlink (works without Developer Mode):
|
||||
|
||||
```powershell
|
||||
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.agents\skills"
|
||||
cmd /c mklink /J "$env:USERPROFILE\.agents\skills\superpowers" "$env:USERPROFILE\.codex\superpowers\skills"
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
Codex has native skill discovery — it scans `~/.agents/skills/` at startup, parses SKILL.md frontmatter, and loads skills on demand. Superpowers skills are made visible through a single symlink:
|
||||
|
||||
```
|
||||
~/.agents/skills/superpowers/ → ~/.codex/superpowers/skills/
|
||||
```
|
||||
|
||||
The `using-superpowers` skill is discovered automatically and enforces skill usage discipline — no additional configuration needed.
|
||||
|
||||
## Usage
|
||||
|
||||
Skills are discovered automatically. Codex activates them when:
|
||||
- You mention a skill by name (e.g., "use brainstorming")
|
||||
- The task matches a skill's description
|
||||
- The `using-superpowers` skill directs Codex to use one
|
||||
|
||||
### Personal Skills
|
||||
|
||||
Create your own skills in `~/.agents/skills/`:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.agents/skills/my-skill
|
||||
```
|
||||
|
||||
Create `~/.agents/skills/my-skill/SKILL.md`:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: my-skill
|
||||
description: Use when [condition] - [what it does]
|
||||
---
|
||||
|
||||
# My Skill
|
||||
|
||||
[Your skill content here]
|
||||
```
|
||||
|
||||
The `description` field is how Codex decides when to activate a skill automatically — write it as a clear trigger condition.
|
||||
|
||||
## Updating
|
||||
|
||||
```bash
|
||||
cd ~/.codex/superpowers && git pull
|
||||
```
|
||||
|
||||
Skills update instantly through the symlink.
|
||||
|
||||
## Uninstalling
|
||||
|
||||
```bash
|
||||
rm ~/.agents/skills/superpowers
|
||||
```
|
||||
|
||||
**Windows (PowerShell):**
|
||||
```powershell
|
||||
Remove-Item "$env:USERPROFILE\.agents\skills\superpowers"
|
||||
```
|
||||
|
||||
Optionally delete the clone: `rm -rf ~/.codex/superpowers` (Windows: `Remove-Item -Recurse -Force "$env:USERPROFILE\.codex\superpowers"`).
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Skills not showing up
|
||||
|
||||
1. Verify the symlink: `ls -la ~/.agents/skills/superpowers`
|
||||
2. Check skills exist: `ls ~/.codex/superpowers/skills`
|
||||
3. Restart Codex — skills are discovered at startup
|
||||
|
||||
### Windows junction issues
|
||||
|
||||
Junctions normally work without special permissions. If creation fails, try running PowerShell as administrator.
|
||||
|
||||
## Getting Help
|
||||
|
||||
- Report issues: https://github.com/obra/superpowers/issues
|
||||
- Main documentation: https://github.com/obra/superpowers
|
||||
@@ -12,10 +12,14 @@ Add superpowers to the `plugin` array in your `opencode.json` (global or project
|
||||
}
|
||||
```
|
||||
|
||||
Restart OpenCode. The plugin auto-installs via Bun and registers all skills automatically.
|
||||
Restart OpenCode. The plugin installs through OpenCode's plugin manager and
|
||||
registers all skills.
|
||||
|
||||
Verify by asking: "Tell me about your superpowers"
|
||||
|
||||
OpenCode uses its own plugin install. If you also use Claude Code, Codex, or
|
||||
another harness, install Superpowers separately for each one.
|
||||
|
||||
### Migrating from the old symlink-based install
|
||||
|
||||
If you previously installed superpowers using `git clone` and symlinks, remove the old setup:
|
||||
@@ -78,7 +82,10 @@ Create project-specific skills in `.opencode/skills/` within your project.
|
||||
|
||||
## Updating
|
||||
|
||||
Superpowers updates automatically when you restart OpenCode. The plugin is re-installed from the git repository on each launch.
|
||||
OpenCode installs Superpowers through a git-backed package spec. Some OpenCode
|
||||
and Bun versions pin that resolved git dependency in a lockfile or cache, so a
|
||||
restart may not pick up the newest Superpowers commit. If updates do not appear,
|
||||
clear OpenCode's package cache or reinstall the plugin.
|
||||
|
||||
To pin a specific version, use a branch or tag:
|
||||
|
||||
@@ -97,12 +104,17 @@ The plugin does two things:
|
||||
|
||||
### Tool Mapping
|
||||
|
||||
Skills written for Claude Code are automatically adapted for OpenCode:
|
||||
Skills speak in actions rather than naming any one runtime's tools. On OpenCode these resolve to:
|
||||
|
||||
- `TodoWrite` → `todowrite`
|
||||
- `Task` with subagents → OpenCode's `@mention` system
|
||||
- `Skill` tool → OpenCode's native `skill` tool
|
||||
- File operations → Native OpenCode tools
|
||||
- "Create a todo" / "mark complete in todo list" → `todowrite`
|
||||
- `Subagent (general-purpose):` template → OpenCode's `task` tool with `subagent_type: "general"` (or `"explore"` for codebase exploration)
|
||||
- "Invoke a skill" → OpenCode's native `skill` tool
|
||||
- "Read a file" / "create a file" / "edit a file" → `read`, `write`, `edit`
|
||||
- "Run a shell command" → `bash`
|
||||
- "Search file contents" / "find files by name" → `grep`, `glob`
|
||||
- "Fetch a URL" / "search the web" → `webfetch`, `websearch`
|
||||
|
||||
(Verified against the installed OpenCode CLI's tool inventory.)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
@@ -112,6 +124,26 @@ Skills written for Claude Code are automatically adapted for OpenCode:
|
||||
2. Verify the plugin line in your `opencode.json` is correct
|
||||
3. Make sure you're running a recent version of OpenCode
|
||||
|
||||
### Windows install issues
|
||||
|
||||
Some Windows OpenCode builds have upstream installer issues with git-backed
|
||||
plugin specs, including cache paths for `git+https` URLs and Bun not finding
|
||||
`git.exe` even when it works in a normal terminal. If OpenCode cannot install
|
||||
the plugin, try installing with system npm and pointing OpenCode at the local
|
||||
package:
|
||||
|
||||
```powershell
|
||||
npm install superpowers@git+https://github.com/obra/superpowers.git --prefix "$HOME\.config\opencode"
|
||||
```
|
||||
|
||||
Then use the installed package path in `opencode.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"plugin": ["~/.config/opencode/node_modules/superpowers"]
|
||||
}
|
||||
```
|
||||
|
||||
### Skills not found
|
||||
|
||||
1. Use OpenCode's `skill` tool to list available skills
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
# Platform-neutral config-file references — Phase B design
|
||||
|
||||
## Background
|
||||
|
||||
Phase A (see `2026-05-05-platform-neutral-prose-design.md`) replaced generic third-person "Claude" prose with agent-neutral forms. This phase tackles the next category: references to the per-platform instruction file (CLAUDE.md, AGENTS.md, GEMINI.md) inside skills.
|
||||
|
||||
The plugin runs on multiple harnesses, and each one reads its own instruction file. Where a skill names CLAUDE.md as if it were the only file, that's a Claude-Code-centric assumption that doesn't hold on Codex / Gemini CLI / OpenCode.
|
||||
|
||||
## In scope
|
||||
|
||||
Two specific lines in active skills:
|
||||
|
||||
1. **`skills/writing-skills/SKILL.md:58`** — `Project-specific conventions (put in CLAUDE.md)`
|
||||
2. **`skills/receiving-code-review/SKILL.md:30`** — `"You're absolutely right!" (explicit CLAUDE.md violation)`
|
||||
|
||||
## Out of scope
|
||||
|
||||
- **`skills/using-superpowers/SKILL.md:22, 26`** — instruction-priority list. The list already names all three (CLAUDE.md, GEMINI.md, AGENTS.md) inclusively, which is correct: the section is making a real claim about *what counts as user instruction* on a multi-platform plugin. No change needed.
|
||||
- **Historical / example artifacts**:
|
||||
- `skills/systematic-debugging/CREATION-LOG.md` — attribution path (`~/.claude/CLAUDE.md`) is a historical fact.
|
||||
- `skills/writing-skills/examples/CLAUDE_MD_TESTING.md` — the entire file is a worked example testing CLAUDE.md content variants. The filename, body, and the reference from `testing-skills-with-subagents.md` all stay; normalizing them defeats the example.
|
||||
- **Platform-tooling references** — Phase D candidates:
|
||||
- `skills/using-superpowers/SKILL.md:40` (Gemini CLI tool mapping note about GEMINI.md)
|
||||
- `skills/using-superpowers/references/gemini-tools.md` (`save_memory` persists to GEMINI.md)
|
||||
|
||||
## Substitution rules
|
||||
|
||||
Two distinct calls, one per in-scope line.
|
||||
|
||||
### Rule 1: "where to put project-specific conventions"
|
||||
|
||||
`writing-skills/SKILL.md:58`:
|
||||
|
||||
- **Before:** `Project-specific conventions (put in CLAUDE.md)`
|
||||
- **After:** `Project-specific conventions (put in your instructions file)`
|
||||
|
||||
Use a generic phrase rather than picking one filename. Different harnesses read different files (CLAUDE.md, AGENTS.md, GEMINI.md, etc.) and the skill should not assume one. The platform-tools reference docs (`references/{codex,copilot,gemini}-tools.md`) are the right place to name each platform's preferred file.
|
||||
|
||||
### Rule 2: the "(explicit CLAUDE.md violation)" parenthetical
|
||||
|
||||
`receiving-code-review/SKILL.md:30`:
|
||||
|
||||
- **Before:** `"You're absolutely right!" (explicit CLAUDE.md violation)`
|
||||
- **After:** `"You're absolutely right!" (explicit instruction-file violation)`
|
||||
|
||||
The parenthetical is doing real work — it signals this phrase isn't just stylistically bad, it actively violates rules many users put in their instruction files. "Instruction file" is the natural cross-platform term covering AGENTS.md / CLAUDE.md / GEMINI.md collectively, and keeps the original signal without picking one filename or softening to "common".
|
||||
|
||||
## Commit plan
|
||||
|
||||
Atomic commits, in order:
|
||||
|
||||
1. **`writing-skills/SKILL.md`** — CLAUDE.md → "your instructions file" in the "where to put project conventions" line
|
||||
2. **`receiving-code-review/SKILL.md`** — CLAUDE.md → instruction-file in the violation parenthetical
|
||||
3. **Platform-tools reference docs** — add the preferred per-platform instructions filename (CLAUDE.md, AGENTS.md, GEMINI.md, etc.) to each `references/{codex,copilot,gemini}-tools.md` so readers can resolve "your instructions file" to a real filename.
|
||||
|
||||
Each commit message names "Phase B" and the slice.
|
||||
|
||||
## Verification
|
||||
|
||||
After each commit:
|
||||
|
||||
- Read the surrounding paragraph to confirm grammar and meaning still parse.
|
||||
- `grep -n "CLAUDE\.md" <touched-file>` — no remaining hits in active prose (carve-outs already documented).
|
||||
|
||||
After both commits:
|
||||
|
||||
- `grep -rn "CLAUDE\.md" skills/` should return only the documented carve-outs (CREATION-LOG, CLAUDE_MD_TESTING and its inbound reference, the priority list in using-superpowers).
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Do not touch the priority list ordering in `using-superpowers/SKILL.md`. Reordering CLAUDE.md / GEMINI.md / AGENTS.md is an aesthetic change, not a substitution, and out of scope here.
|
||||
- Do not rename `examples/CLAUDE_MD_TESTING.md` or change its content.
|
||||
- Do not modify Gemini-CLI-specific tooling references (Phase D candidates).
|
||||
|
||||
## Implementation note
|
||||
|
||||
Phase B as written here covered three commits and the three non-Claude-Code platform-tools refs. Implementation went one step further: a fourth ref, `references/claude-code-tools.md`, was added in commit `8505703` for symmetry, so Claude Code's instructions-file conventions and tool-name list live alongside the others rather than implicitly in the surrounding skill prose. That addition wasn't anticipated in this spec but is consistent with its intent.
|
||||
@@ -0,0 +1,94 @@
|
||||
# Platform-neutral prose — Phase A design
|
||||
|
||||
## Background
|
||||
|
||||
Superpowers ships to multiple agent runtimes (Claude Code, Codex, Cursor, OpenCode, Copilot CLI, Gemini CLI). Skill content and supporting docs were written first for Claude Code and use "Claude" in places where any runtime's agent applies. OpenAI's vendored fork (openai/plugins#217) attempted a wholesale rewrite that was actively wrong in places — rewriting historical attribution paths, model names, and platform-specific install instructions — and we want to avoid that mistake while still removing platform-centric prose where it is genuinely incidental.
|
||||
|
||||
The full effort is broken into phases by reference category. **This spec covers Phase A only:** generic third-person prose mentioning "Claude" in non-platform-specific contexts. Later phases (config-file references, marketing copy, tool-name references) are out of scope here and will get their own specs.
|
||||
|
||||
## In scope
|
||||
|
||||
Generic prose mentions of "Claude" in:
|
||||
|
||||
- `skills/*/SKILL.md` and supporting `.md` files in active skill directories
|
||||
- `skills/writing-skills/anthropic-best-practices.md`
|
||||
- `README.md` (only where the mention is generic prose, not platform marketing)
|
||||
|
||||
Plus one coined-term rename: **Claude Search Optimization (CSO) → Skill Discovery Optimization (SDO)** in `skills/writing-skills/SKILL.md`.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- **Platform/runtime statements** — "In Claude Code:", install instructions, tool-mapping references. (Phase D candidate.)
|
||||
- **Config-file references** — CLAUDE.md, AGENTS.md, GEMINI.md priority lists and "where to put project conventions" callouts. (Phase B.)
|
||||
- **Tool-name references** — `Skill`, `Bash`, `Read`, `Task`, `TodoWrite`. Skills are written in Claude Code's tool vocabulary; the existing `references/{codex,copilot,gemini}-tools.md` files map them. (At the time this spec was written, the plan was to defer or skip these. Phase E ended up doing them — replacing tool names with action language across active skills and unifying the platform-tools refs around the same vocabulary.)
|
||||
- **Marketing copy** in README — "Superpowers for Claude Code", platform-named install sections. (Phase C.)
|
||||
- **Historical artifacts** — `docs/plans/*.md`, `docs/superpowers/specs/*.md`, `CREATION-LOG.md`. These are dated, point-in-time documents; rewriting them rewrites history.
|
||||
- **Model identifiers** — Claude Haiku / Sonnet / Opus. These are real product names.
|
||||
- **Filename / URL references** — `CLAUDE.md`, `claude.com`, `claude-plugin/`, paths under `~/.claude/`.
|
||||
- **`anthropic-best-practices.md` filename** — the file remains named after its source even though we rewrite the prose inside it.
|
||||
|
||||
## Replacement style
|
||||
|
||||
Use a mix that reads naturally in English:
|
||||
|
||||
- **Second person — "your agent"** when addressing the skill author about *their* runtime
|
||||
- "your agent reads the description"
|
||||
- **Third person — "the agent" / "agents" / "an agent"** when describing system behavior generically
|
||||
- "Future agents find your skills"
|
||||
- "Use words an agent would search for"
|
||||
- "Agents read SKILL.md only when the skill becomes relevant"
|
||||
|
||||
Pick whichever fits the surrounding sentence; do not force consistency at the cost of awkward phrasing. Pluralize when natural ("future agents", "agents read") rather than always saying "the agent".
|
||||
|
||||
### Carve-outs that stay as "Claude"
|
||||
|
||||
- Model names: Claude Haiku, Claude Sonnet, Claude Opus
|
||||
- Filenames and URLs: `CLAUDE.md`, `claude.com`, `~/.claude/`
|
||||
- Branded platform name "Claude Code" wherever it refers to the runtime as such (handled in later phases)
|
||||
|
||||
### Coined-term rename
|
||||
|
||||
- **Claude Search Optimization (CSO) → Skill Discovery Optimization (SDO)**
|
||||
- Appears in `skills/writing-skills/SKILL.md` as a section heading and in nearby prose. Rename the heading, the acronym, and any in-file cross-references.
|
||||
|
||||
## Files affected
|
||||
|
||||
Approximate counts based on a `grep` filtered to exclude carve-outs:
|
||||
|
||||
| File | Generic-prose mentions |
|
||||
|------|------------------------|
|
||||
| `skills/writing-skills/SKILL.md` | ~12 (includes CSO heading + body) |
|
||||
| `skills/writing-skills/anthropic-best-practices.md` | ~30 |
|
||||
| `skills/writing-skills/examples/CLAUDE_MD_TESTING.md` | ~1 — filename stays (it's a CLAUDE.md test artifact); the "Variant C: Claude.AI Emphatic Style" heading also stays (it's a label naming a specific style) |
|
||||
| `README.md` | ~1 |
|
||||
|
||||
Final list confirmed during implementation by re-running the filtered grep.
|
||||
|
||||
## Commit plan
|
||||
|
||||
Four atomic commits, in order:
|
||||
|
||||
1. **Rename CSO → SDO** in `skills/writing-skills/SKILL.md`. Mechanical, isolated, easy to revert if we change our minds about the term.
|
||||
2. **Active skills prose** — generic "Claude" → "agent" forms across `skills/*/SKILL.md` and supporting `.md`, excluding `anthropic-best-practices.md`.
|
||||
3. **`anthropic-best-practices.md` prose** — same substitution rules. Separate commit because this file is a vendored adaptation of an external doc; isolating the change makes future reconciliation with upstream easier to read.
|
||||
4. **README.md prose** *(only if any generic-prose mentions remain after filtering)*. Skipped if empty.
|
||||
|
||||
Each commit message names the phase ("Phase A") and the slice ("rename CSO to SDO", "agent prose in active skills", etc.) so the series is self-documenting.
|
||||
|
||||
## Verification
|
||||
|
||||
After each commit:
|
||||
|
||||
- `grep -rn "Claude" <touched-paths>` — every remaining hit must fall into a documented carve-out (model name, filename, URL, "Claude Code" platform name, historical artifact).
|
||||
- Read the touched file end-to-end — substitutions should not have broken sentence flow, pronoun agreement, or list parallelism.
|
||||
- No tests to run; this is prose-only.
|
||||
|
||||
After the final commit:
|
||||
|
||||
- Skim each modified skill in a live session to confirm nothing reads awkwardly.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Do not change behavior, structure, headings (other than CSO→SDO), examples, code blocks, or YAML frontmatter.
|
||||
- Do not introduce new sections, callouts, or compatibility notes.
|
||||
- Do not "improve" prose beyond the substitution while editing.
|
||||
@@ -0,0 +1,47 @@
|
||||
# Platform-neutral README ordering — Phase C design
|
||||
|
||||
## Background
|
||||
|
||||
Phases A and B (see `2026-05-05-platform-neutral-prose-design.md` and `2026-05-05-platform-neutral-config-refs-design.md`) already neutralized generic Claude prose and config-file references in the README. The remaining platform-leaning signal is layout: the README's two platform listings put Claude Code first and aren't strictly alphabetical elsewhere.
|
||||
|
||||
This phase fixes the ordering. No prose changes.
|
||||
|
||||
## In scope
|
||||
|
||||
1. **Quickstart platform list** (`README.md:7`) — the inline link list of supported harnesses
|
||||
2. **Installation section ordering** (`README.md:35–152`) — the per-harness install sub-sections
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Prose, marketplace names, plugin IDs, URLs — all factually correct as-is.
|
||||
- Visual weight of the Claude Code section (which has two sub-sections — official Anthropic marketplace and Superpowers marketplace). Both are real install paths; collapsing them would hide accurate info.
|
||||
- Section headings and content within each install block — only the ordering of the blocks changes.
|
||||
|
||||
## Substitution
|
||||
|
||||
Both listings reorder to strict alphabetical:
|
||||
|
||||
| Old order | New order |
|
||||
|-----------|-----------|
|
||||
| Claude Code | Claude Code |
|
||||
| Codex CLI | Codex App |
|
||||
| Codex App | Codex CLI |
|
||||
| Factory Droid | Cursor |
|
||||
| Gemini CLI | Factory Droid |
|
||||
| OpenCode | Gemini CLI |
|
||||
| Cursor | GitHub Copilot CLI |
|
||||
| GitHub Copilot CLI | OpenCode |
|
||||
|
||||
Three moves: Codex App swaps with Codex CLI; Cursor moves up two slots; GitHub Copilot CLI moves up one.
|
||||
|
||||
Claude Code remains first by alphabetical chance (`Cl…` precedes `Co…`).
|
||||
|
||||
## Commit plan
|
||||
|
||||
One atomic commit covering both listings, since changing one without the other would create inconsistency between the quickstart and the installation section.
|
||||
|
||||
## Verification
|
||||
|
||||
- Quickstart anchors (`#claude-code`, `#codex-app`, etc.) still resolve to existing `### …` headings — no headings renamed.
|
||||
- Each install sub-section's body is byte-identical pre/post; only positions changed.
|
||||
- `git diff README.md` shows section moves only, no content edits.
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "superpowers",
|
||||
"description": "Core skills library: TDD, debugging, collaboration patterns, and proven techniques",
|
||||
"version": "5.0.6",
|
||||
"version": "5.1.0",
|
||||
"contextFileName": "GEMINI.md"
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"hooks": {
|
||||
"sessionStart": [
|
||||
{
|
||||
"command": "./hooks/session-start"
|
||||
"command": "./hooks/run-hook.cmd session-start"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "superpowers",
|
||||
"version": "5.0.6",
|
||||
"version": "5.1.0",
|
||||
"type": "module",
|
||||
"main": ".opencode/plugins/superpowers.js"
|
||||
}
|
||||
|
||||
220
scripts/bump-version.sh
Executable file
220
scripts/bump-version.sh
Executable file
@@ -0,0 +1,220 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# bump-version.sh — bump version numbers across all declared files,
|
||||
# with drift detection and repo-wide audit for missed files.
|
||||
#
|
||||
# Usage:
|
||||
# bump-version.sh <new-version> Bump all declared files to new version
|
||||
# bump-version.sh --check Report current versions (detect drift)
|
||||
# bump-version.sh --audit Check + grep repo for old version strings
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
CONFIG="$REPO_ROOT/.version-bump.json"
|
||||
|
||||
if [[ ! -f "$CONFIG" ]]; then
|
||||
echo "error: .version-bump.json not found at $CONFIG" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- helpers ---
|
||||
|
||||
# Read a dotted field path from a JSON file.
|
||||
# Handles both simple ("version") and nested ("plugins.0.version") paths.
|
||||
read_json_field() {
|
||||
local file="$1" field="$2"
|
||||
# Convert dot-path to jq path: "plugins.0.version" -> .plugins[0].version
|
||||
local jq_path
|
||||
jq_path=$(echo "$field" | sed -E 's/\.([0-9]+)/[\1]/g' | sed 's/^/./' | sed 's/\.\././g')
|
||||
jq -r "$jq_path" "$file"
|
||||
}
|
||||
|
||||
# Write a dotted field path in a JSON file, preserving formatting.
|
||||
write_json_field() {
|
||||
local file="$1" field="$2" value="$3"
|
||||
local jq_path
|
||||
jq_path=$(echo "$field" | sed -E 's/\.([0-9]+)/[\1]/g' | sed 's/^/./' | sed 's/\.\././g')
|
||||
local tmp="${file}.tmp"
|
||||
jq "$jq_path = \"$value\"" "$file" > "$tmp" && mv "$tmp" "$file"
|
||||
}
|
||||
|
||||
# Read the list of declared files from config.
|
||||
# Outputs lines of "path<TAB>field"
|
||||
declared_files() {
|
||||
jq -r '.files[] | "\(.path)\t\(.field)"' "$CONFIG"
|
||||
}
|
||||
|
||||
# Read the audit exclude patterns from config.
|
||||
audit_excludes() {
|
||||
jq -r '.audit.exclude[]' "$CONFIG" 2>/dev/null
|
||||
}
|
||||
|
||||
# --- commands ---
|
||||
|
||||
cmd_check() {
|
||||
local has_drift=0
|
||||
local versions=()
|
||||
|
||||
echo "Version check:"
|
||||
echo ""
|
||||
|
||||
while IFS=$'\t' read -r path field; do
|
||||
local fullpath="$REPO_ROOT/$path"
|
||||
if [[ ! -f "$fullpath" ]]; then
|
||||
printf " %-45s MISSING\n" "$path ($field)"
|
||||
has_drift=1
|
||||
continue
|
||||
fi
|
||||
local ver
|
||||
ver=$(read_json_field "$fullpath" "$field")
|
||||
printf " %-45s %s\n" "$path ($field)" "$ver"
|
||||
versions+=("$ver")
|
||||
done < <(declared_files)
|
||||
|
||||
echo ""
|
||||
|
||||
# Check if all versions match
|
||||
local unique
|
||||
unique=$(printf '%s\n' "${versions[@]}" | sort -u | wc -l | tr -d ' ')
|
||||
if [[ "$unique" -gt 1 ]]; then
|
||||
echo "DRIFT DETECTED — versions are not in sync:"
|
||||
printf '%s\n' "${versions[@]}" | sort | uniq -c | sort -rn | while read -r count ver; do
|
||||
echo " $ver ($count files)"
|
||||
done
|
||||
has_drift=1
|
||||
else
|
||||
echo "All declared files are in sync at ${versions[0]}"
|
||||
fi
|
||||
|
||||
return $has_drift
|
||||
}
|
||||
|
||||
cmd_audit() {
|
||||
# First run check
|
||||
cmd_check || true
|
||||
echo ""
|
||||
|
||||
# Determine the current version (most common across declared files)
|
||||
local current_version
|
||||
current_version=$(
|
||||
while IFS=$'\t' read -r path field; do
|
||||
local fullpath="$REPO_ROOT/$path"
|
||||
[[ -f "$fullpath" ]] && read_json_field "$fullpath" "$field"
|
||||
done < <(declared_files) | sort | uniq -c | sort -rn | head -1 | awk '{print $2}'
|
||||
)
|
||||
|
||||
if [[ -z "$current_version" ]]; then
|
||||
echo "error: could not determine current version" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "Audit: scanning repo for version string '$current_version'..."
|
||||
echo ""
|
||||
|
||||
# Build grep exclude args
|
||||
local -a exclude_args=()
|
||||
while IFS= read -r pattern; do
|
||||
exclude_args+=("--exclude=$pattern" "--exclude-dir=$pattern")
|
||||
done < <(audit_excludes)
|
||||
|
||||
# Also always exclude binary files and .git
|
||||
exclude_args+=("--exclude-dir=.git" "--exclude-dir=node_modules" "--binary-files=without-match")
|
||||
|
||||
# Get list of declared paths for comparison
|
||||
local -a declared_paths=()
|
||||
while IFS=$'\t' read -r path _field; do
|
||||
declared_paths+=("$path")
|
||||
done < <(declared_files)
|
||||
|
||||
# Grep for the version string
|
||||
local found_undeclared=0
|
||||
while IFS= read -r match; do
|
||||
local match_file
|
||||
match_file=$(echo "$match" | cut -d: -f1)
|
||||
# Make path relative to repo root
|
||||
local rel_path="${match_file#$REPO_ROOT/}"
|
||||
|
||||
# Check if this file is in the declared list
|
||||
local is_declared=0
|
||||
for dp in "${declared_paths[@]}"; do
|
||||
if [[ "$rel_path" == "$dp" ]]; then
|
||||
is_declared=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$is_declared" -eq 0 ]]; then
|
||||
if [[ "$found_undeclared" -eq 0 ]]; then
|
||||
echo "UNDECLARED files containing '$current_version':"
|
||||
found_undeclared=1
|
||||
fi
|
||||
echo " $match"
|
||||
fi
|
||||
done < <(grep -rn "${exclude_args[@]}" -F "$current_version" "$REPO_ROOT" 2>/dev/null || true)
|
||||
|
||||
if [[ "$found_undeclared" -eq 0 ]]; then
|
||||
echo "No undeclared files contain the version string. All clear."
|
||||
else
|
||||
echo ""
|
||||
echo "Review the above files — if they should be bumped, add them to .version-bump.json"
|
||||
echo "If they should be skipped, add them to the audit.exclude list."
|
||||
fi
|
||||
}
|
||||
|
||||
cmd_bump() {
|
||||
local new_version="$1"
|
||||
|
||||
# Validate semver-ish format
|
||||
if ! echo "$new_version" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+'; then
|
||||
echo "error: '$new_version' doesn't look like a version (expected X.Y.Z)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Bumping all declared files to $new_version..."
|
||||
echo ""
|
||||
|
||||
while IFS=$'\t' read -r path field; do
|
||||
local fullpath="$REPO_ROOT/$path"
|
||||
if [[ ! -f "$fullpath" ]]; then
|
||||
echo " SKIP (missing): $path"
|
||||
continue
|
||||
fi
|
||||
local old_ver
|
||||
old_ver=$(read_json_field "$fullpath" "$field")
|
||||
write_json_field "$fullpath" "$field" "$new_version"
|
||||
printf " %-45s %s -> %s\n" "$path ($field)" "$old_ver" "$new_version"
|
||||
done < <(declared_files)
|
||||
|
||||
echo ""
|
||||
echo "Done. Running audit to check for missed files..."
|
||||
echo ""
|
||||
cmd_audit
|
||||
}
|
||||
|
||||
# --- main ---
|
||||
|
||||
case "${1:-}" in
|
||||
--check)
|
||||
cmd_check
|
||||
;;
|
||||
--audit)
|
||||
cmd_audit
|
||||
;;
|
||||
--help|-h|"")
|
||||
echo "Usage: bump-version.sh <new-version> | --check | --audit"
|
||||
echo ""
|
||||
echo " <new-version> Bump all declared files to the given version"
|
||||
echo " --check Show current versions, detect drift"
|
||||
echo " --audit Check + scan repo for undeclared version references"
|
||||
exit 0
|
||||
;;
|
||||
--*)
|
||||
echo "error: unknown flag '$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
cmd_bump "$1"
|
||||
;;
|
||||
esac
|
||||
462
scripts/sync-to-codex-plugin.sh
Executable file
462
scripts/sync-to-codex-plugin.sh
Executable file
@@ -0,0 +1,462 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# sync-to-codex-plugin.sh
|
||||
#
|
||||
# Sync this superpowers checkout → prime-radiant-inc/openai-codex-plugins.
|
||||
# Clones the fork fresh into a temp dir, rsyncs tracked upstream plugin content
|
||||
# (including committed Codex files under .codex-plugin/ and assets/), preserves
|
||||
# OpenAI-owned marketplace metadata already in the destination plugin, commits,
|
||||
# pushes a sync branch, and opens a PR.
|
||||
# Path/user agnostic — auto-detects upstream from script location.
|
||||
#
|
||||
# Deterministic: running twice against the same upstream SHA produces PRs with
|
||||
# identical diffs, so two back-to-back runs can verify the tool itself.
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/sync-to-codex-plugin.sh # full run
|
||||
# ./scripts/sync-to-codex-plugin.sh -n # dry run
|
||||
# ./scripts/sync-to-codex-plugin.sh -y # skip confirm
|
||||
# ./scripts/sync-to-codex-plugin.sh --local PATH # existing checkout
|
||||
# ./scripts/sync-to-codex-plugin.sh --base BRANCH # default: main
|
||||
# ./scripts/sync-to-codex-plugin.sh --bootstrap # create plugin dir if missing
|
||||
#
|
||||
# Bootstrap mode: skips the "plugin must exist on base" requirement and creates
|
||||
# plugins/superpowers/ when absent, then copies the tracked plugin files from
|
||||
# upstream just like a normal sync.
|
||||
#
|
||||
# Requires: bash, rsync, git, gh (authenticated), python3.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# =============================================================================
|
||||
# Config — edit as upstream or canonical plugin shape evolves
|
||||
# =============================================================================
|
||||
|
||||
FORK="prime-radiant-inc/openai-codex-plugins"
|
||||
DEFAULT_BASE="main"
|
||||
DEST_REL="plugins/superpowers"
|
||||
|
||||
# Paths in upstream that should NOT land in the embedded plugin.
|
||||
# All patterns use a leading "/" to anchor them to the source root.
|
||||
# Unanchored patterns like "scripts/" would match any directory named
|
||||
# "scripts" at any depth — including legitimate nested dirs like
|
||||
# skills/brainstorming/scripts/. Anchoring prevents that.
|
||||
# (.DS_Store is intentionally unanchored — Finder creates them everywhere.)
|
||||
EXCLUDES=(
|
||||
# Dotfiles and infra — top-level only
|
||||
"/.claude/"
|
||||
"/.claude-plugin/"
|
||||
"/.codex/"
|
||||
"/.cursor-plugin/"
|
||||
"/.git/"
|
||||
"/.gitattributes"
|
||||
"/.github/"
|
||||
"/.gitignore"
|
||||
"/.opencode/"
|
||||
"/.version-bump.json"
|
||||
"/.worktrees/"
|
||||
".DS_Store"
|
||||
|
||||
# Root ceremony files
|
||||
"/AGENTS.md"
|
||||
"/CHANGELOG.md"
|
||||
"/CLAUDE.md"
|
||||
"/GEMINI.md"
|
||||
"/RELEASE-NOTES.md"
|
||||
"/gemini-extension.json"
|
||||
"/package.json"
|
||||
|
||||
# Directories not shipped by canonical Codex plugins
|
||||
"/commands/"
|
||||
"/docs/"
|
||||
"/hooks/"
|
||||
"/lib/"
|
||||
"/scripts/"
|
||||
"/tests/"
|
||||
"/tmp/"
|
||||
)
|
||||
|
||||
# =============================================================================
|
||||
# Ignored-path helpers
|
||||
# =============================================================================
|
||||
|
||||
IGNORED_DIR_EXCLUDES=()
|
||||
|
||||
path_has_directory_exclude() {
|
||||
local path="$1"
|
||||
local dir
|
||||
|
||||
if [[ ${#IGNORED_DIR_EXCLUDES[@]} -eq 0 ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
for dir in "${IGNORED_DIR_EXCLUDES[@]}"; do
|
||||
[[ "$path" == "$dir"* ]] && return 0
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
ignored_directory_has_tracked_descendants() {
|
||||
local path="$1"
|
||||
|
||||
[[ -n "$(git -C "$UPSTREAM" ls-files --cached -- "$path/")" ]]
|
||||
}
|
||||
|
||||
append_git_ignored_directory_excludes() {
|
||||
local path
|
||||
local lookup_path
|
||||
|
||||
while IFS= read -r -d '' path; do
|
||||
[[ "$path" == */ ]] || continue
|
||||
|
||||
lookup_path="${path%/}"
|
||||
if ! ignored_directory_has_tracked_descendants "$lookup_path"; then
|
||||
IGNORED_DIR_EXCLUDES+=("$path")
|
||||
RSYNC_ARGS+=(--exclude="/$path")
|
||||
fi
|
||||
done < <(git -C "$UPSTREAM" ls-files --others --ignored --exclude-standard --directory -z)
|
||||
}
|
||||
|
||||
append_git_ignored_file_excludes() {
|
||||
local path
|
||||
|
||||
while IFS= read -r -d '' path; do
|
||||
path_has_directory_exclude "$path" && continue
|
||||
RSYNC_ARGS+=(--exclude="/$path")
|
||||
done < <(git -C "$UPSTREAM" ls-files --others --ignored --exclude-standard -z)
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Args
|
||||
# =============================================================================
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
UPSTREAM="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
BASE="$DEFAULT_BASE"
|
||||
DRY_RUN=0
|
||||
YES=0
|
||||
LOCAL_CHECKOUT=""
|
||||
BOOTSTRAP=0
|
||||
|
||||
usage() {
|
||||
sed -n '/^# Usage:/,/^# Requires:/s/^# \{0,1\}//p' "$0"
|
||||
exit "${1:-0}"
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-n|--dry-run) DRY_RUN=1; shift ;;
|
||||
-y|--yes) YES=1; shift ;;
|
||||
--local) LOCAL_CHECKOUT="$2"; shift 2 ;;
|
||||
--base) BASE="$2"; shift 2 ;;
|
||||
--bootstrap) BOOTSTRAP=1; shift ;;
|
||||
-h|--help) usage 0 ;;
|
||||
*) echo "Unknown arg: $1" >&2; usage 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# =============================================================================
|
||||
# Preflight
|
||||
# =============================================================================
|
||||
|
||||
die() { echo "ERROR: $*" >&2; exit 1; }
|
||||
|
||||
command -v rsync >/dev/null || die "rsync not found in PATH"
|
||||
command -v git >/dev/null || die "git not found in PATH"
|
||||
command -v gh >/dev/null || die "gh not found — install GitHub CLI"
|
||||
command -v python3 >/dev/null || die "python3 not found in PATH"
|
||||
|
||||
gh auth status >/dev/null 2>&1 || die "gh not authenticated — run 'gh auth login'"
|
||||
|
||||
[[ -d "$UPSTREAM/.git" ]] || die "upstream '$UPSTREAM' is not a git checkout"
|
||||
[[ -f "$UPSTREAM/.codex-plugin/plugin.json" ]] || die "committed Codex manifest missing at $UPSTREAM/.codex-plugin/plugin.json"
|
||||
|
||||
# Read the upstream version from the committed Codex manifest.
|
||||
UPSTREAM_VERSION="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))["version"])' "$UPSTREAM/.codex-plugin/plugin.json")"
|
||||
[[ -n "$UPSTREAM_VERSION" ]] || die "could not read 'version' from committed Codex manifest"
|
||||
|
||||
UPSTREAM_BRANCH="$(cd "$UPSTREAM" && git branch --show-current)"
|
||||
UPSTREAM_SHA="$(cd "$UPSTREAM" && git rev-parse HEAD)"
|
||||
UPSTREAM_SHORT="$(cd "$UPSTREAM" && git rev-parse --short HEAD)"
|
||||
|
||||
confirm() {
|
||||
[[ $YES -eq 1 ]] && return 0
|
||||
read -rp "$1 [y/N] " ans
|
||||
[[ "$ans" == "y" || "$ans" == "Y" ]]
|
||||
}
|
||||
|
||||
if [[ "$UPSTREAM_BRANCH" != "main" ]]; then
|
||||
echo "WARNING: upstream is on '$UPSTREAM_BRANCH', not 'main'"
|
||||
confirm "Sync from '$UPSTREAM_BRANCH' anyway?" || exit 1
|
||||
fi
|
||||
|
||||
UPSTREAM_STATUS="$(cd "$UPSTREAM" && git status --porcelain)"
|
||||
if [[ -n "$UPSTREAM_STATUS" ]]; then
|
||||
echo "WARNING: upstream has uncommitted changes:"
|
||||
echo "$UPSTREAM_STATUS" | sed 's/^/ /'
|
||||
echo "Sync will use working-tree state, not HEAD ($UPSTREAM_SHORT)."
|
||||
confirm "Continue anyway?" || exit 1
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Prepare destination (clone fork fresh, or use --local)
|
||||
# =============================================================================
|
||||
|
||||
CLEANUP_DIR=""
|
||||
cleanup() {
|
||||
if [[ -n "$CLEANUP_DIR" ]]; then
|
||||
rm -rf "$CLEANUP_DIR"
|
||||
fi
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
if [[ -n "$LOCAL_CHECKOUT" ]]; then
|
||||
DEST_REPO="$(cd "$LOCAL_CHECKOUT" && pwd)"
|
||||
[[ -d "$DEST_REPO/.git" ]] || die "--local path '$DEST_REPO' is not a git checkout"
|
||||
else
|
||||
echo "Cloning $FORK..."
|
||||
CLEANUP_DIR="$(mktemp -d)"
|
||||
DEST_REPO="$CLEANUP_DIR/openai-codex-plugins"
|
||||
gh repo clone "$FORK" "$DEST_REPO" >/dev/null
|
||||
fi
|
||||
|
||||
DEST="$DEST_REPO/$DEST_REL"
|
||||
PREVIEW_REPO="$DEST_REPO"
|
||||
PREVIEW_DEST="$DEST"
|
||||
SYNC_SOURCE=""
|
||||
|
||||
overlay_destination_paths() {
|
||||
local repo="$1"
|
||||
local path
|
||||
local source_path
|
||||
local preview_path
|
||||
|
||||
while IFS= read -r -d '' path; do
|
||||
source_path="$repo/$path"
|
||||
preview_path="$PREVIEW_REPO/$path"
|
||||
|
||||
if [[ -e "$source_path" ]]; then
|
||||
mkdir -p "$(dirname "$preview_path")"
|
||||
cp -R "$source_path" "$preview_path"
|
||||
else
|
||||
rm -rf "$preview_path"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
copy_local_destination_overlay() {
|
||||
overlay_destination_paths "$DEST_REPO" < <(
|
||||
git -C "$DEST_REPO" diff --name-only -z -- "$DEST_REL"
|
||||
)
|
||||
overlay_destination_paths "$DEST_REPO" < <(
|
||||
git -C "$DEST_REPO" diff --cached --name-only -z -- "$DEST_REL"
|
||||
)
|
||||
overlay_destination_paths "$DEST_REPO" < <(
|
||||
git -C "$DEST_REPO" ls-files --others --exclude-standard -z -- "$DEST_REL"
|
||||
)
|
||||
overlay_destination_paths "$DEST_REPO" < <(
|
||||
git -C "$DEST_REPO" ls-files --others --ignored --exclude-standard -z -- "$DEST_REL"
|
||||
)
|
||||
}
|
||||
|
||||
local_checkout_has_uncommitted_destination_changes() {
|
||||
[[ -n "$(git -C "$DEST_REPO" status --porcelain=1 --untracked-files=all --ignored=matching -- "$DEST_REL")" ]]
|
||||
}
|
||||
|
||||
prepare_preview_checkout() {
|
||||
if [[ -n "$LOCAL_CHECKOUT" ]]; then
|
||||
[[ -n "$CLEANUP_DIR" ]] || CLEANUP_DIR="$(mktemp -d)"
|
||||
PREVIEW_REPO="$CLEANUP_DIR/preview"
|
||||
git clone -q --no-local "$DEST_REPO" "$PREVIEW_REPO"
|
||||
PREVIEW_DEST="$PREVIEW_REPO/$DEST_REL"
|
||||
fi
|
||||
|
||||
git -C "$PREVIEW_REPO" checkout -q "$BASE" 2>/dev/null || die "base branch '$BASE' doesn't exist in $FORK"
|
||||
if [[ -n "$LOCAL_CHECKOUT" ]]; then
|
||||
copy_local_destination_overlay
|
||||
fi
|
||||
if [[ $BOOTSTRAP -ne 1 ]]; then
|
||||
[[ -d "$PREVIEW_DEST" ]] || die "base branch '$BASE' has no '$DEST_REL/' — use --bootstrap, or pass --base <branch>"
|
||||
fi
|
||||
}
|
||||
|
||||
prepare_apply_checkout() {
|
||||
git -C "$DEST_REPO" checkout -q "$BASE" 2>/dev/null || die "base branch '$BASE' doesn't exist in $FORK"
|
||||
if [[ $BOOTSTRAP -ne 1 ]]; then
|
||||
[[ -d "$DEST" ]] || die "base branch '$BASE' has no '$DEST_REL/' — use --bootstrap, or pass --base <branch>"
|
||||
fi
|
||||
}
|
||||
|
||||
apply_to_preview_checkout() {
|
||||
if [[ $BOOTSTRAP -eq 1 ]]; then
|
||||
mkdir -p "$PREVIEW_DEST"
|
||||
fi
|
||||
|
||||
rsync "${RSYNC_ARGS[@]}" "$SYNC_SOURCE/" "$PREVIEW_DEST/"
|
||||
}
|
||||
|
||||
preview_checkout_has_changes() {
|
||||
[[ -n "$(git -C "$PREVIEW_REPO" status --porcelain "$DEST_REL")" ]]
|
||||
}
|
||||
|
||||
prepare_preview_checkout
|
||||
|
||||
TIMESTAMP="$(date -u +%Y%m%d-%H%M%S)"
|
||||
if [[ $BOOTSTRAP -eq 1 ]]; then
|
||||
SYNC_BRANCH="bootstrap/superpowers-${UPSTREAM_SHORT}-${TIMESTAMP}"
|
||||
else
|
||||
SYNC_BRANCH="sync/superpowers-${UPSTREAM_SHORT}-${TIMESTAMP}"
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Build rsync args
|
||||
# =============================================================================
|
||||
|
||||
RSYNC_ARGS=(-av --delete --delete-excluded)
|
||||
for pat in "${EXCLUDES[@]}"; do RSYNC_ARGS+=(--exclude="$pat"); done
|
||||
append_git_ignored_directory_excludes
|
||||
append_git_ignored_file_excludes
|
||||
|
||||
copy_preserved_destination_metadata() {
|
||||
local destination="$1"
|
||||
local source="$2"
|
||||
local path
|
||||
local rel
|
||||
|
||||
[[ -d "$destination/skills" ]] || return 0
|
||||
|
||||
while IFS= read -r -d '' path; do
|
||||
rel="${path#"$destination"/}"
|
||||
mkdir -p "$source/$(dirname "$rel")"
|
||||
cp -p "$path" "$source/$rel"
|
||||
done < <(find "$destination/skills" -path '*/agents/openai.yaml' -type f -print0)
|
||||
}
|
||||
|
||||
prepare_sync_source() {
|
||||
local destination="$1"
|
||||
|
||||
[[ -n "$CLEANUP_DIR" ]] || CLEANUP_DIR="$(mktemp -d)"
|
||||
|
||||
SYNC_SOURCE="$CLEANUP_DIR/source-overlay"
|
||||
rm -rf "$SYNC_SOURCE"
|
||||
mkdir -p "$SYNC_SOURCE"
|
||||
|
||||
rsync "${RSYNC_ARGS[@]}" "$UPSTREAM/" "$SYNC_SOURCE/" >/dev/null
|
||||
copy_preserved_destination_metadata "$destination" "$SYNC_SOURCE"
|
||||
}
|
||||
|
||||
prepare_sync_source "$PREVIEW_DEST"
|
||||
|
||||
# =============================================================================
|
||||
# Dry run preview (always shown)
|
||||
# =============================================================================
|
||||
|
||||
echo ""
|
||||
echo "Upstream: $UPSTREAM ($UPSTREAM_BRANCH @ $UPSTREAM_SHORT)"
|
||||
echo "Version: $UPSTREAM_VERSION"
|
||||
echo "Fork: $FORK"
|
||||
echo "Base: $BASE"
|
||||
echo "Branch: $SYNC_BRANCH"
|
||||
if [[ $BOOTSTRAP -eq 1 ]]; then
|
||||
echo "Mode: BOOTSTRAP (creating plugins/superpowers/ when absent)"
|
||||
fi
|
||||
echo ""
|
||||
echo "=== Preview (rsync --dry-run) ==="
|
||||
rsync "${RSYNC_ARGS[@]}" --dry-run --itemize-changes "$SYNC_SOURCE/" "$PREVIEW_DEST/"
|
||||
echo "=== End preview ==="
|
||||
echo ""
|
||||
|
||||
if [[ $DRY_RUN -eq 1 ]]; then
|
||||
echo ""
|
||||
echo "Dry run only. Nothing was changed or pushed."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Apply
|
||||
# =============================================================================
|
||||
|
||||
echo ""
|
||||
confirm "Apply changes, push branch, and open PR?" || { echo "Aborted."; exit 1; }
|
||||
|
||||
echo ""
|
||||
if [[ -n "$LOCAL_CHECKOUT" ]]; then
|
||||
if local_checkout_has_uncommitted_destination_changes; then
|
||||
die "local checkout has uncommitted changes under '$DEST_REL' — commit, stash, or discard them before syncing"
|
||||
fi
|
||||
|
||||
apply_to_preview_checkout
|
||||
if ! preview_checkout_has_changes; then
|
||||
echo "No changes — embedded plugin was already in sync with upstream $UPSTREAM_SHORT (v$UPSTREAM_VERSION)."
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
prepare_apply_checkout
|
||||
cd "$DEST_REPO"
|
||||
git checkout -q -b "$SYNC_BRANCH"
|
||||
echo "Syncing upstream content..."
|
||||
if [[ $BOOTSTRAP -eq 1 ]]; then
|
||||
mkdir -p "$DEST"
|
||||
fi
|
||||
rsync "${RSYNC_ARGS[@]}" "$SYNC_SOURCE/" "$DEST/"
|
||||
|
||||
# Bail early if nothing actually changed
|
||||
cd "$DEST_REPO"
|
||||
if [[ -z "$(git status --porcelain "$DEST_REL")" ]]; then
|
||||
echo "No changes — embedded plugin was already in sync with upstream $UPSTREAM_SHORT (v$UPSTREAM_VERSION)."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Commit, push, open PR
|
||||
# =============================================================================
|
||||
|
||||
git add "$DEST_REL"
|
||||
|
||||
if [[ $BOOTSTRAP -eq 1 ]]; then
|
||||
COMMIT_TITLE="bootstrap superpowers v$UPSTREAM_VERSION from upstream main @ $UPSTREAM_SHORT"
|
||||
PR_BODY="Initial bootstrap of the superpowers plugin from upstream \`main\` @ \`$UPSTREAM_SHORT\` (v$UPSTREAM_VERSION).
|
||||
|
||||
Creates \`plugins/superpowers/\` by copying the tracked plugin files from upstream, including \`.codex-plugin/plugin.json\` and \`assets/\`.
|
||||
|
||||
Run via: \`scripts/sync-to-codex-plugin.sh --bootstrap\`
|
||||
Upstream commit: https://github.com/obra/superpowers/commit/$UPSTREAM_SHA
|
||||
|
||||
This is a one-time bootstrap. Subsequent syncs will be normal (non-bootstrap) runs using the same tracked upstream plugin files."
|
||||
else
|
||||
COMMIT_TITLE="sync superpowers v$UPSTREAM_VERSION from upstream main @ $UPSTREAM_SHORT"
|
||||
PR_BODY="Automated sync from superpowers upstream \`main\` @ \`$UPSTREAM_SHORT\` (v$UPSTREAM_VERSION).
|
||||
|
||||
Copies the tracked plugin files from upstream, including the committed Codex manifest and assets.
|
||||
|
||||
Run via: \`scripts/sync-to-codex-plugin.sh\`
|
||||
Upstream commit: https://github.com/obra/superpowers/commit/$UPSTREAM_SHA
|
||||
|
||||
Running the sync tool again against the same upstream SHA should produce a PR with an identical diff — use that to verify the tool is behaving."
|
||||
fi
|
||||
|
||||
git commit --quiet -m "$COMMIT_TITLE
|
||||
|
||||
Automated sync via scripts/sync-to-codex-plugin.sh
|
||||
Upstream: https://github.com/obra/superpowers/commit/$UPSTREAM_SHA
|
||||
Branch: $SYNC_BRANCH"
|
||||
|
||||
echo "Pushing $SYNC_BRANCH to $FORK..."
|
||||
git push -u origin "$SYNC_BRANCH" --quiet
|
||||
|
||||
echo "Opening PR..."
|
||||
PR_URL="$(gh pr create \
|
||||
--repo "$FORK" \
|
||||
--base "$BASE" \
|
||||
--head "$SYNC_BRANCH" \
|
||||
--title "$COMMIT_TITLE" \
|
||||
--body "$PR_BODY")"
|
||||
|
||||
PR_NUM="${PR_URL##*/}"
|
||||
DIFF_URL="https://github.com/$FORK/pull/$PR_NUM/files"
|
||||
|
||||
echo ""
|
||||
echo "PR opened: $PR_URL"
|
||||
echo "Diff view: $DIFF_URL"
|
||||
@@ -13,7 +13,7 @@
|
||||
* - Scrollable main content area
|
||||
* - CSS helpers for common UI patterns
|
||||
*
|
||||
* Content is injected via placeholder comment in #claude-content.
|
||||
* Content is injected via placeholder comment in #frame-content.
|
||||
*/
|
||||
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
@@ -77,7 +77,7 @@
|
||||
.header .status::before { content: ''; width: 6px; height: 6px; background: var(--success); border-radius: 50%; }
|
||||
|
||||
.main { flex: 1; overflow-y: auto; }
|
||||
#claude-content { padding: 2rem; min-height: 100%; }
|
||||
#frame-content { padding: 2rem; min-height: 100%; }
|
||||
|
||||
.indicator-bar {
|
||||
background: var(--bg-secondary);
|
||||
@@ -201,7 +201,7 @@
|
||||
</div>
|
||||
|
||||
<div class="main">
|
||||
<div id="claude-content">
|
||||
<div id="frame-content">
|
||||
<!-- CONTENT -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,7 @@ Use this template when dispatching a spec document reviewer subagent.
|
||||
**Dispatch after:** Spec document is written to docs/superpowers/specs/
|
||||
|
||||
```
|
||||
Task tool (general-purpose):
|
||||
Subagent (general-purpose):
|
||||
description: "Review spec document"
|
||||
prompt: |
|
||||
You are a spec document reviewer. Verify this spec is complete and ready for planning.
|
||||
|
||||
@@ -49,20 +49,13 @@ Save `screen_dir` and `state_dir` from the response. Tell user to open the URL.
|
||||
|
||||
**Launching the server by platform:**
|
||||
|
||||
**Claude Code (macOS / Linux):**
|
||||
**Claude Code:**
|
||||
```bash
|
||||
# Default mode works — the script backgrounds the server itself
|
||||
# Default mode works — the script backgrounds the server itself.
|
||||
scripts/start-server.sh --project-dir /path/to/project
|
||||
```
|
||||
|
||||
**Claude Code (Windows):**
|
||||
```bash
|
||||
# Windows auto-detects and uses foreground mode, which blocks the tool call.
|
||||
# Use run_in_background: true on the Bash tool call so the server survives
|
||||
# across conversation turns.
|
||||
scripts/start-server.sh --project-dir /path/to/project
|
||||
```
|
||||
When calling this via the Bash tool, set `run_in_background: true`. Then read `$STATE_DIR/server-info` on the next turn to get the URL and port.
|
||||
On Windows, the script auto-detects and switches to foreground mode (which blocks the tool call). Use `run_in_background: true` on the Bash tool call so the server survives across conversation turns, then read `$STATE_DIR/server-info` on the next turn to get the URL and port.
|
||||
|
||||
**Codex:**
|
||||
```bash
|
||||
@@ -78,6 +71,14 @@ scripts/start-server.sh --project-dir /path/to/project
|
||||
scripts/start-server.sh --project-dir /path/to/project --foreground
|
||||
```
|
||||
|
||||
**Copilot CLI:**
|
||||
```bash
|
||||
# Use --foreground and start the server via the bash tool with mode: "async"
|
||||
# so the process survives across turns. Capture the returned shellId for
|
||||
# read_bash / stop_bash if you need to interact with it later.
|
||||
scripts/start-server.sh --project-dir /path/to/project --foreground
|
||||
```
|
||||
|
||||
**Other environments:** The server must keep running in the background across conversation turns. If your environment reaps detached processes, use `--foreground` and launch the command with your platform's background execution mechanism.
|
||||
|
||||
If the URL is unreachable from your browser (common in remote/containerized setups), bind a non-loopback host:
|
||||
@@ -97,7 +98,7 @@ Use `--url-host` to control what hostname is printed in the returned URL JSON.
|
||||
- Before each write, check that `$STATE_DIR/server-info` exists. If it doesn't (or `$STATE_DIR/server-stopped` exists), the server has shut down — restart it with `start-server.sh` before continuing. The server auto-exits after 30 minutes of inactivity.
|
||||
- Use semantic filenames: `platform.html`, `visual-style.html`, `layout.html`
|
||||
- **Never reuse filenames** — each screen gets a fresh file
|
||||
- Use Write tool — **never use cat/heredoc** (dumps noise into terminal)
|
||||
- Use your file-creation tool — **never use cat/heredoc** (dumps noise into terminal)
|
||||
- Server automatically serves the newest file
|
||||
|
||||
2. **Tell user what to expect and end your turn:**
|
||||
|
||||
@@ -65,14 +65,17 @@ Each agent gets:
|
||||
|
||||
### 3. Dispatch in Parallel
|
||||
|
||||
```typescript
|
||||
// In Claude Code / AI environment
|
||||
Task("Fix agent-tool-abort.test.ts failures")
|
||||
Task("Fix batch-completion-behavior.test.ts failures")
|
||||
Task("Fix tool-approval-race-conditions.test.ts failures")
|
||||
// All three run concurrently
|
||||
Issue all three subagent dispatches in the same response — they run in parallel:
|
||||
|
||||
```text
|
||||
Subagent (general-purpose): "Fix agent-tool-abort.test.ts failures"
|
||||
Subagent (general-purpose): "Fix batch-completion-behavior.test.ts failures"
|
||||
Subagent (general-purpose): "Fix tool-approval-race-conditions.test.ts failures"
|
||||
# All three run concurrently.
|
||||
```
|
||||
|
||||
Multiple dispatch calls in one response = parallel execution. One per response = sequential.
|
||||
|
||||
### 4. Review and Integrate
|
||||
|
||||
When agents return:
|
||||
|
||||
@@ -11,7 +11,7 @@ Load plan, review critically, execute all tasks, report when complete.
|
||||
|
||||
**Announce at start:** "I'm using the executing-plans skill to implement this plan."
|
||||
|
||||
**Note:** Tell your human partner that Superpowers works much better with access to subagents. The quality of its work will be significantly higher if run on a platform with subagent support (such as Claude Code or Codex). If subagents are available, use superpowers:subagent-driven-development instead of this skill.
|
||||
**Note:** Tell your human partner that Superpowers works much better with access to subagents. The quality of its work will be significantly higher if run on a platform with subagent support (Claude Code, Codex CLI, Codex App, Copilot CLI, and Gemini CLI all qualify; see the per-platform tool refs in `../using-superpowers/references/`). If subagents are available, use superpowers:subagent-driven-development instead of this skill.
|
||||
|
||||
## The Process
|
||||
|
||||
@@ -19,7 +19,7 @@ Load plan, review critically, execute all tasks, report when complete.
|
||||
1. Read plan file
|
||||
2. Review critically - identify any questions or concerns about the plan
|
||||
3. If concerns: Raise them with your human partner before starting
|
||||
4. If no concerns: Create TodoWrite and proceed
|
||||
4. If no concerns: Create todos for the plan items and proceed
|
||||
|
||||
### Step 2: Execute Tasks
|
||||
|
||||
|
||||
@@ -249,12 +249,3 @@ git worktree prune # Self-healing: clean up any stale registrations
|
||||
- Clean up worktree for Options 1 & 4 only
|
||||
- `cd` to main repo root before worktree removal
|
||||
- Run `git worktree prune` after removal
|
||||
|
||||
## Integration
|
||||
|
||||
**Called by:**
|
||||
- **subagent-driven-development** (Step 7) - After all tasks complete
|
||||
- **executing-plans** (Step 5) - After all batches complete
|
||||
|
||||
**Pairs with:**
|
||||
- **using-git-worktrees** - Cleans up worktree created by that skill
|
||||
|
||||
@@ -27,7 +27,7 @@ WHEN receiving code review feedback:
|
||||
## Forbidden Responses
|
||||
|
||||
**NEVER:**
|
||||
- "You're absolutely right!" (explicit CLAUDE.md violation)
|
||||
- "You're absolutely right!" (explicit instruction-file violation)
|
||||
- "Great point!" / "Excellent feedback!" (performative)
|
||||
- "Let me implement that now" (before verification)
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ description: Use when completing tasks, implementing major features, or before m
|
||||
|
||||
# Requesting Code Review
|
||||
|
||||
Dispatch superpowers:code-reviewer subagent to catch issues before they cascade. The reviewer gets precisely crafted context for evaluation — never your session's history. This keeps the reviewer focused on the work product, not your thought process, and preserves your own context for continued work.
|
||||
Dispatch a code reviewer subagent to catch issues before they cascade. The reviewer gets precisely crafted context for evaluation — never your session's history. This keeps the reviewer focused on the work product, not your thought process, and preserves your own context for continued work.
|
||||
|
||||
**Core principle:** Review early, review often.
|
||||
|
||||
@@ -29,16 +29,15 @@ BASE_SHA=$(git rev-parse HEAD~1) # or origin/main
|
||||
HEAD_SHA=$(git rev-parse HEAD)
|
||||
```
|
||||
|
||||
**2. Dispatch code-reviewer subagent:**
|
||||
**2. Dispatch code reviewer subagent:**
|
||||
|
||||
Use Task tool with superpowers:code-reviewer type, fill template at `code-reviewer.md`
|
||||
Dispatch a `general-purpose` subagent, filling the template at `code-reviewer.md`
|
||||
|
||||
**Placeholders:**
|
||||
- `{WHAT_WAS_IMPLEMENTED}` - What you just built
|
||||
- `{DESCRIPTION}` - Brief summary of what you built
|
||||
- `{PLAN_OR_REQUIREMENTS}` - What it should do
|
||||
- `{BASE_SHA}` - Starting commit
|
||||
- `{HEAD_SHA}` - Ending commit
|
||||
- `{DESCRIPTION}` - Brief summary
|
||||
|
||||
**3. Act on feedback:**
|
||||
- Fix Critical issues immediately
|
||||
@@ -56,12 +55,11 @@ You: Let me request code review before proceeding.
|
||||
BASE_SHA=$(git log --oneline | grep "Task 1" | head -1 | awk '{print $1}')
|
||||
HEAD_SHA=$(git rev-parse HEAD)
|
||||
|
||||
[Dispatch superpowers:code-reviewer subagent]
|
||||
WHAT_WAS_IMPLEMENTED: Verification and repair functions for conversation index
|
||||
[Dispatch code reviewer subagent]
|
||||
DESCRIPTION: Added verifyIndex() and repairIndex() with 4 issue types
|
||||
PLAN_OR_REQUIREMENTS: Task 2 from docs/superpowers/plans/deployment-plan.md
|
||||
BASE_SHA: a7981ec
|
||||
HEAD_SHA: 3df7661
|
||||
DESCRIPTION: Added verifyIndex() and repairIndex() with 4 issue types
|
||||
|
||||
[Subagent returns]:
|
||||
Strengths: Clean architecture, real tests
|
||||
@@ -82,7 +80,7 @@ You: [Fix progress indicators]
|
||||
- Fix before moving to next task
|
||||
|
||||
**Executing Plans:**
|
||||
- Review after each batch (3 tasks)
|
||||
- Review after each task or at natural checkpoints
|
||||
- Get feedback, apply, continue
|
||||
|
||||
**Ad-Hoc Development:**
|
||||
|
||||
@@ -1,111 +1,133 @@
|
||||
# Code Review Agent
|
||||
# Code Reviewer Prompt Template
|
||||
|
||||
You are reviewing code changes for production readiness.
|
||||
Use this template when dispatching a code reviewer subagent.
|
||||
|
||||
**Your task:**
|
||||
1. Review {WHAT_WAS_IMPLEMENTED}
|
||||
2. Compare against {PLAN_OR_REQUIREMENTS}
|
||||
3. Check code quality, architecture, testing
|
||||
4. Categorize issues by severity
|
||||
5. Assess production readiness
|
||||
**Purpose:** Review completed work against requirements and code quality standards before it cascades into more work.
|
||||
|
||||
## What Was Implemented
|
||||
```
|
||||
Subagent (general-purpose):
|
||||
description: "Review code changes"
|
||||
prompt: |
|
||||
You are a Senior Code Reviewer with expertise in software architecture,
|
||||
design patterns, and best practices. Your job is to review completed work
|
||||
against its plan or requirements and identify issues before they cascade.
|
||||
|
||||
{DESCRIPTION}
|
||||
## What Was Implemented
|
||||
|
||||
## Requirements/Plan
|
||||
{DESCRIPTION}
|
||||
|
||||
{PLAN_REFERENCE}
|
||||
## Requirements / Plan
|
||||
|
||||
## Git Range to Review
|
||||
{PLAN_OR_REQUIREMENTS}
|
||||
|
||||
**Base:** {BASE_SHA}
|
||||
**Head:** {HEAD_SHA}
|
||||
## Git Range to Review
|
||||
|
||||
```bash
|
||||
git diff --stat {BASE_SHA}..{HEAD_SHA}
|
||||
git diff {BASE_SHA}..{HEAD_SHA}
|
||||
**Base:** {BASE_SHA}
|
||||
**Head:** {HEAD_SHA}
|
||||
|
||||
```bash
|
||||
git diff --stat {BASE_SHA}..{HEAD_SHA}
|
||||
git diff {BASE_SHA}..{HEAD_SHA}
|
||||
```
|
||||
|
||||
## What to Check
|
||||
|
||||
**Plan alignment:**
|
||||
- Does the implementation match the plan / requirements?
|
||||
- Are deviations justified improvements, or problematic departures?
|
||||
- Is all planned functionality present?
|
||||
|
||||
**Code quality:**
|
||||
- Clean separation of concerns?
|
||||
- Proper error handling?
|
||||
- Type safety where applicable?
|
||||
- DRY without premature abstraction?
|
||||
- Edge cases handled?
|
||||
|
||||
**Architecture:**
|
||||
- Sound design decisions?
|
||||
- Reasonable scalability and performance?
|
||||
- Security concerns?
|
||||
- Integrates cleanly with surrounding code?
|
||||
|
||||
**Testing:**
|
||||
- Tests verify real behavior, not mocks?
|
||||
- Edge cases covered?
|
||||
- Integration tests where they matter?
|
||||
- All tests passing?
|
||||
|
||||
**Production readiness:**
|
||||
- Migration strategy if schema changed?
|
||||
- Backward compatibility considered?
|
||||
- Documentation complete?
|
||||
- No obvious bugs?
|
||||
|
||||
## Calibration
|
||||
|
||||
Categorize issues by actual severity. Not everything is Critical.
|
||||
Acknowledge what was done well before listing issues — accurate praise
|
||||
helps the implementer trust the rest of the feedback.
|
||||
|
||||
If you find significant deviations from the plan, flag them specifically
|
||||
so the implementer can confirm whether the deviation was intentional.
|
||||
If you find issues with the plan itself rather than the implementation,
|
||||
say so.
|
||||
|
||||
## Output Format
|
||||
|
||||
### Strengths
|
||||
[What's well done? Be specific.]
|
||||
|
||||
### Issues
|
||||
|
||||
#### Critical (Must Fix)
|
||||
[Bugs, security issues, data loss risks, broken functionality]
|
||||
|
||||
#### Important (Should Fix)
|
||||
[Architecture problems, missing features, poor error handling, test gaps]
|
||||
|
||||
#### Minor (Nice to Have)
|
||||
[Code style, optimization opportunities, documentation polish]
|
||||
|
||||
For each issue:
|
||||
- File:line reference
|
||||
- What's wrong
|
||||
- Why it matters
|
||||
- How to fix (if not obvious)
|
||||
|
||||
### Recommendations
|
||||
[Improvements for code quality, architecture, or process]
|
||||
|
||||
### Assessment
|
||||
|
||||
**Ready to merge?** [Yes | No | With fixes]
|
||||
|
||||
**Reasoning:** [1-2 sentence technical assessment]
|
||||
|
||||
## Critical Rules
|
||||
|
||||
**DO:**
|
||||
- Categorize by actual severity
|
||||
- Be specific (file:line, not vague)
|
||||
- Explain WHY each issue matters
|
||||
- Acknowledge strengths
|
||||
- Give a clear verdict
|
||||
|
||||
**DON'T:**
|
||||
- Say "looks good" without checking
|
||||
- Mark nitpicks as Critical
|
||||
- Give feedback on code you didn't actually read
|
||||
- Be vague ("improve error handling")
|
||||
- Avoid giving a clear verdict
|
||||
```
|
||||
|
||||
## Review Checklist
|
||||
**Placeholders:**
|
||||
- `{DESCRIPTION}` — brief summary of what was built
|
||||
- `{PLAN_OR_REQUIREMENTS}` — what it should do (plan file path, task text, or requirements)
|
||||
- `{BASE_SHA}` — starting commit
|
||||
- `{HEAD_SHA}` — ending commit
|
||||
|
||||
**Code Quality:**
|
||||
- Clean separation of concerns?
|
||||
- Proper error handling?
|
||||
- Type safety (if applicable)?
|
||||
- DRY principle followed?
|
||||
- Edge cases handled?
|
||||
|
||||
**Architecture:**
|
||||
- Sound design decisions?
|
||||
- Scalability considerations?
|
||||
- Performance implications?
|
||||
- Security concerns?
|
||||
|
||||
**Testing:**
|
||||
- Tests actually test logic (not mocks)?
|
||||
- Edge cases covered?
|
||||
- Integration tests where needed?
|
||||
- All tests passing?
|
||||
|
||||
**Requirements:**
|
||||
- All plan requirements met?
|
||||
- Implementation matches spec?
|
||||
- No scope creep?
|
||||
- Breaking changes documented?
|
||||
|
||||
**Production Readiness:**
|
||||
- Migration strategy (if schema changes)?
|
||||
- Backward compatibility considered?
|
||||
- Documentation complete?
|
||||
- No obvious bugs?
|
||||
|
||||
## Output Format
|
||||
|
||||
### Strengths
|
||||
[What's well done? Be specific.]
|
||||
|
||||
### Issues
|
||||
|
||||
#### Critical (Must Fix)
|
||||
[Bugs, security issues, data loss risks, broken functionality]
|
||||
|
||||
#### Important (Should Fix)
|
||||
[Architecture problems, missing features, poor error handling, test gaps]
|
||||
|
||||
#### Minor (Nice to Have)
|
||||
[Code style, optimization opportunities, documentation improvements]
|
||||
|
||||
**For each issue:**
|
||||
- File:line reference
|
||||
- What's wrong
|
||||
- Why it matters
|
||||
- How to fix (if not obvious)
|
||||
|
||||
### Recommendations
|
||||
[Improvements for code quality, architecture, or process]
|
||||
|
||||
### Assessment
|
||||
|
||||
**Ready to merge?** [Yes/No/With fixes]
|
||||
|
||||
**Reasoning:** [Technical assessment in 1-2 sentences]
|
||||
|
||||
## Critical Rules
|
||||
|
||||
**DO:**
|
||||
- Categorize by actual severity (not everything is Critical)
|
||||
- Be specific (file:line, not vague)
|
||||
- Explain WHY issues matter
|
||||
- Acknowledge strengths
|
||||
- Give clear verdict
|
||||
|
||||
**DON'T:**
|
||||
- Say "looks good" without checking
|
||||
- Mark nitpicks as Critical
|
||||
- Give feedback on code you didn't review
|
||||
- Be vague ("improve error handling")
|
||||
- Avoid giving a clear verdict
|
||||
**Reviewer returns:** Strengths, Issues (Critical / Important / Minor), Recommendations, Assessment
|
||||
|
||||
## Example Output
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ Execute plan by dispatching fresh subagent per task, with two-stage review after
|
||||
|
||||
**Core principle:** Fresh subagent per task + two-stage review (spec then quality) = high quality, fast iteration
|
||||
|
||||
**Continuous execution:** Do not pause to check in with your human partner between tasks. Execute all tasks from the plan without stopping. The only reasons to stop are: BLOCKED status you cannot resolve, ambiguity that genuinely prevents progress, or all tasks complete. "Should I continue?" prompts and progress summaries waste their time — they asked you to execute the plan, so execute it.
|
||||
|
||||
## When to Use
|
||||
|
||||
```dot
|
||||
@@ -55,15 +57,15 @@ digraph process {
|
||||
"Dispatch code quality reviewer subagent (./code-quality-reviewer-prompt.md)" [shape=box];
|
||||
"Code quality reviewer subagent approves?" [shape=diamond];
|
||||
"Implementer subagent fixes quality issues" [shape=box];
|
||||
"Mark task complete in TodoWrite" [shape=box];
|
||||
"Mark task complete in todo list" [shape=box];
|
||||
}
|
||||
|
||||
"Read plan, extract all tasks with full text, note context, create TodoWrite" [shape=box];
|
||||
"Read plan, extract all tasks with full text, note context, create todos" [shape=box];
|
||||
"More tasks remain?" [shape=diamond];
|
||||
"Dispatch final code reviewer subagent for entire implementation" [shape=box];
|
||||
"Use superpowers:finishing-a-development-branch" [shape=box style=filled fillcolor=lightgreen];
|
||||
|
||||
"Read plan, extract all tasks with full text, note context, create TodoWrite" -> "Dispatch implementer subagent (./implementer-prompt.md)";
|
||||
"Read plan, extract all tasks with full text, note context, create todos" -> "Dispatch implementer subagent (./implementer-prompt.md)";
|
||||
"Dispatch implementer subagent (./implementer-prompt.md)" -> "Implementer subagent asks questions?";
|
||||
"Implementer subagent asks questions?" -> "Answer questions, provide context" [label="yes"];
|
||||
"Answer questions, provide context" -> "Dispatch implementer subagent (./implementer-prompt.md)";
|
||||
@@ -76,8 +78,8 @@ digraph process {
|
||||
"Dispatch code quality reviewer subagent (./code-quality-reviewer-prompt.md)" -> "Code quality reviewer subagent approves?";
|
||||
"Code quality reviewer subagent approves?" -> "Implementer subagent fixes quality issues" [label="no"];
|
||||
"Implementer subagent fixes quality issues" -> "Dispatch code quality reviewer subagent (./code-quality-reviewer-prompt.md)" [label="re-review"];
|
||||
"Code quality reviewer subagent approves?" -> "Mark task complete in TodoWrite" [label="yes"];
|
||||
"Mark task complete in TodoWrite" -> "More tasks remain?";
|
||||
"Code quality reviewer subagent approves?" -> "Mark task complete in todo list" [label="yes"];
|
||||
"Mark task complete in todo list" -> "More tasks remain?";
|
||||
"More tasks remain?" -> "Dispatch implementer subagent (./implementer-prompt.md)" [label="yes"];
|
||||
"More tasks remain?" -> "Dispatch final code reviewer subagent for entire implementation" [label="no"];
|
||||
"Dispatch final code reviewer subagent for entire implementation" -> "Use superpowers:finishing-a-development-branch";
|
||||
@@ -130,7 +132,7 @@ You: I'm using Subagent-Driven Development to execute this plan.
|
||||
|
||||
[Read plan file once: docs/superpowers/plans/feature-plan.md]
|
||||
[Extract all 5 tasks with full text and context]
|
||||
[Create TodoWrite with all tasks]
|
||||
[Create todos for all tasks]
|
||||
|
||||
Task 1: Hook installation script
|
||||
|
||||
|
||||
@@ -7,14 +7,13 @@ Use this template when dispatching a code quality reviewer subagent.
|
||||
**Only dispatch after spec compliance review passes.**
|
||||
|
||||
```
|
||||
Task tool (superpowers:code-reviewer):
|
||||
Subagent (general-purpose):
|
||||
Use template at requesting-code-review/code-reviewer.md
|
||||
|
||||
WHAT_WAS_IMPLEMENTED: [from implementer's report]
|
||||
DESCRIPTION: [task summary, from implementer's report]
|
||||
PLAN_OR_REQUIREMENTS: Task N from [plan-file]
|
||||
BASE_SHA: [commit before task]
|
||||
HEAD_SHA: [current commit]
|
||||
DESCRIPTION: [task summary]
|
||||
```
|
||||
|
||||
**In addition to standard code quality concerns, the reviewer should check:**
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Use this template when dispatching an implementer subagent.
|
||||
|
||||
```
|
||||
Task tool (general-purpose):
|
||||
Subagent (general-purpose):
|
||||
description: "Implement Task N: [task name]"
|
||||
prompt: |
|
||||
You are implementing Task N: [task name]
|
||||
|
||||
@@ -5,7 +5,7 @@ Use this template when dispatching a spec compliance reviewer subagent.
|
||||
**Purpose:** Verify implementer built what was requested (nothing more, nothing less)
|
||||
|
||||
```
|
||||
Task tool (general-purpose):
|
||||
Subagent (general-purpose):
|
||||
description: "Review spec compliance for Task N"
|
||||
prompt: |
|
||||
You are reviewing whether an implementation matches its specification.
|
||||
|
||||
@@ -213,13 +213,3 @@ Ready to implement <feature-name>
|
||||
- Verify directory is ignored for project-local
|
||||
- Auto-detect and run project setup
|
||||
- Verify clean test baseline
|
||||
|
||||
## Integration
|
||||
|
||||
**Called by:**
|
||||
- **subagent-driven-development** - Ensures isolated workspace (creates one or verifies existing)
|
||||
- **executing-plans** - Ensures isolated workspace (creates one or verifies existing)
|
||||
- Any skill needing isolated workspace
|
||||
|
||||
**Pairs with:**
|
||||
- **finishing-a-development-branch** - REQUIRED for cleanup after work complete
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: using-superpowers
|
||||
description: Use when starting any conversation - establishes how to find and use skills, requiring Skill tool invocation before ANY response including clarifying questions
|
||||
description: Use when starting any conversation - establishes how to find and use skills, requiring skill invocation before ANY response including clarifying questions
|
||||
---
|
||||
|
||||
<SUBAGENT-STOP>
|
||||
@@ -27,9 +27,13 @@ If CLAUDE.md, GEMINI.md, or AGENTS.md says "don't use TDD" and a skill says "alw
|
||||
|
||||
## How to Access Skills
|
||||
|
||||
**In Claude Code:** Use the `Skill` tool. When you invoke a skill, its content is loaded and presented to you—follow it directly. Never use the Read tool on skill files.
|
||||
**Never read skill files manually with file tools** — always use your platform's skill-loading mechanism so the skill is properly activated.
|
||||
|
||||
**In Copilot CLI:** Use the `skill` tool. Skills are auto-discovered from installed plugins. The `skill` tool works the same as Claude Code's `Skill` tool.
|
||||
**In Claude Code:** Use the `Skill` tool. When you invoke a skill, its content is loaded and presented to you — follow it directly.
|
||||
|
||||
**In Codex:** Skills load natively. Follow the instructions presented when a skill activates.
|
||||
|
||||
**In Copilot CLI:** Use the `skill` tool. Skills are auto-discovered from installed plugins.
|
||||
|
||||
**In Gemini CLI:** Skills activate via the `activate_skill` tool. Gemini loads skill metadata at session start and activates the full content on demand.
|
||||
|
||||
@@ -37,7 +41,7 @@ If CLAUDE.md, GEMINI.md, or AGENTS.md says "don't use TDD" and a skill says "alw
|
||||
|
||||
## Platform Adaptation
|
||||
|
||||
Skills use Claude Code tool names. Non-CC platforms: see `references/copilot-tools.md` (Copilot CLI), `references/codex-tools.md` (Codex) for tool equivalents. Gemini CLI users get the tool mapping loaded automatically via GEMINI.md.
|
||||
Skills speak in actions ("dispatch a subagent", "create a todo", "read a file") rather than naming any one runtime's tools. For per-platform tool equivalents and instructions-file conventions, see `references/claude-code-tools.md`, `references/codex-tools.md`, `references/copilot-tools.md`, and `references/gemini-tools.md`. Gemini CLI users get the tool mapping loaded automatically via GEMINI.md.
|
||||
|
||||
# Using Skills
|
||||
|
||||
@@ -48,30 +52,30 @@ Skills use Claude Code tool names. Non-CC platforms: see `references/copilot-too
|
||||
```dot
|
||||
digraph skill_flow {
|
||||
"User message received" [shape=doublecircle];
|
||||
"About to EnterPlanMode?" [shape=doublecircle];
|
||||
"About to enter plan mode?" [shape=doublecircle];
|
||||
"Already brainstormed?" [shape=diamond];
|
||||
"Invoke brainstorming skill" [shape=box];
|
||||
"Might any skill apply?" [shape=diamond];
|
||||
"Invoke Skill tool" [shape=box];
|
||||
"Invoke the skill" [shape=box];
|
||||
"Announce: 'Using [skill] to [purpose]'" [shape=box];
|
||||
"Has checklist?" [shape=diamond];
|
||||
"Create TodoWrite todo per item" [shape=box];
|
||||
"Create a todo per item" [shape=box];
|
||||
"Follow skill exactly" [shape=box];
|
||||
"Respond (including clarifications)" [shape=doublecircle];
|
||||
|
||||
"About to EnterPlanMode?" -> "Already brainstormed?";
|
||||
"About to enter plan mode?" -> "Already brainstormed?";
|
||||
"Already brainstormed?" -> "Invoke brainstorming skill" [label="no"];
|
||||
"Already brainstormed?" -> "Might any skill apply?" [label="yes"];
|
||||
"Invoke brainstorming skill" -> "Might any skill apply?";
|
||||
|
||||
"User message received" -> "Might any skill apply?";
|
||||
"Might any skill apply?" -> "Invoke Skill tool" [label="yes, even 1%"];
|
||||
"Might any skill apply?" -> "Invoke the skill" [label="yes, even 1%"];
|
||||
"Might any skill apply?" -> "Respond (including clarifications)" [label="definitely not"];
|
||||
"Invoke Skill tool" -> "Announce: 'Using [skill] to [purpose]'";
|
||||
"Invoke the skill" -> "Announce: 'Using [skill] to [purpose]'";
|
||||
"Announce: 'Using [skill] to [purpose]'" -> "Has checklist?";
|
||||
"Has checklist?" -> "Create TodoWrite todo per item" [label="yes"];
|
||||
"Has checklist?" -> "Create a todo per item" [label="yes"];
|
||||
"Has checklist?" -> "Follow skill exactly" [label="no"];
|
||||
"Create TodoWrite todo per item" -> "Follow skill exactly";
|
||||
"Create a todo per item" -> "Follow skill exactly";
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
50
skills/using-superpowers/references/claude-code-tools.md
Normal file
50
skills/using-superpowers/references/claude-code-tools.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Claude Code Tool Mapping
|
||||
|
||||
Skills speak in actions ("dispatch a subagent", "create a todo", "read a file"). On Claude Code these resolve to the tools below.
|
||||
|
||||
## Tools
|
||||
|
||||
| Action skills request | Claude Code tool |
|
||||
|----------------------|------------------|
|
||||
| Read a file | `Read` |
|
||||
| Create a new file | `Write` |
|
||||
| Edit a file | `Edit` |
|
||||
| Run a shell command | `Bash` |
|
||||
| Search file contents | `Grep` |
|
||||
| Find files by name | `Glob` |
|
||||
| Fetch a URL | `WebFetch` |
|
||||
| Search the web | `WebSearch` |
|
||||
| Invoke a skill | `Skill` |
|
||||
| Dispatch a subagent (`Subagent (general-purpose):` template) | `Agent` (older releases named this `Task`) |
|
||||
| Multiple parallel dispatches | Multiple `Agent` calls in one response |
|
||||
| Task tracking ("create a todo", "mark complete") | `TaskCreate`, `TaskUpdate`, `TaskList`, `TaskGet` (was a single tool named `TodoWrite` in older releases) |
|
||||
| Background-process / subagent lifecycle (read output, cancel) | `TaskOutput`, `TaskStop` — these are distinct from the todo tools above and apply to running shells, agents, and remote sessions |
|
||||
|
||||
## Instructions file
|
||||
|
||||
When a skill mentions "your instructions file", on Claude Code this is **`CLAUDE.md`**. Claude Code walks up the directory tree from the current working directory and concatenates every `CLAUDE.md` and `CLAUDE.local.md` it finds along the way. Standard locations:
|
||||
|
||||
| Scope | Location |
|
||||
|-------|----------|
|
||||
| Project (team-shared) | `./CLAUDE.md` or `./.claude/CLAUDE.md` |
|
||||
| User global | `~/.claude/CLAUDE.md` |
|
||||
| Local-private (gitignored) | `./CLAUDE.local.md` |
|
||||
| Managed policy (org-wide) | `/Library/Application Support/ClaudeCode/CLAUDE.md` (macOS), `/etc/claude-code/CLAUDE.md` (Linux/WSL), `C:\Program Files\ClaudeCode\CLAUDE.md` (Windows) |
|
||||
|
||||
CLAUDE.md files can pull in additional content with `@path/to/file` imports (relative or absolute, max five hops deep). Subdirectory `CLAUDE.md` files are also discovered automatically and loaded on-demand when Claude Code reads files in those subdirectories.
|
||||
|
||||
Claude Code does **not** read `AGENTS.md` directly. If a project already maintains `AGENTS.md` for other agents, import it from `CLAUDE.md` so both runtimes share the same instructions:
|
||||
|
||||
```markdown
|
||||
@AGENTS.md
|
||||
|
||||
## Claude Code
|
||||
|
||||
(Claude-Code-specific instructions go here.)
|
||||
```
|
||||
|
||||
For path-scoped rules and larger-project organization, see `.claude/rules/` (rules can be scoped to specific files via `paths` frontmatter and load on demand).
|
||||
|
||||
## Personal skills directory
|
||||
|
||||
User-level skills live at **`~/.claude/skills/`**. Each skill is a subdirectory containing a `SKILL.md` (with `name` and `description` frontmatter) plus any supporting files. Claude Code does not currently recognize the cross-runtime `~/.agents/skills/` path that Codex, Copilot CLI, and Gemini CLI read; if you're relying on cross-runtime support in the future, verify against the [official skills docs](https://code.claude.com/docs/en/skills).
|
||||
@@ -1,17 +1,30 @@
|
||||
# Codex Tool Mapping
|
||||
|
||||
Skills use Claude Code tool names. When you encounter these in a skill, use your platform equivalent:
|
||||
Skills speak in actions ("dispatch a subagent", "create a todo", "read a file"). On Codex these resolve to the tools below.
|
||||
|
||||
| Skill references | Codex equivalent |
|
||||
|-----------------|------------------|
|
||||
| `Task` tool (dispatch subagent) | `spawn_agent` (see [Named agent dispatch](#named-agent-dispatch)) |
|
||||
| Multiple `Task` calls (parallel) | Multiple `spawn_agent` calls |
|
||||
| Task returns result | `wait` |
|
||||
| Task completes automatically | `close_agent` to free slot |
|
||||
| `TodoWrite` (task tracking) | `update_plan` |
|
||||
| `Skill` tool (invoke a skill) | Skills load natively — just follow the instructions |
|
||||
| `Read`, `Write`, `Edit` (files) | Use your native file tools |
|
||||
| `Bash` (run commands) | Use your native shell tools |
|
||||
| Action skills request | Codex equivalent |
|
||||
|----------------------|------------------|
|
||||
| Read a file | `shell` (e.g., `cat`, `head`, `tail`) — Codex reads files via shell |
|
||||
| Create / edit / delete a file | `apply_patch` (structured diff for create, update, delete) |
|
||||
| Run a shell command | `shell` |
|
||||
| Search file contents | `shell` (e.g., `grep`, `rg`) |
|
||||
| Find files by name | `shell` (e.g., `find`, `ls`) |
|
||||
| Fetch a URL | `shell` with `curl` / `wget` — Codex has no native fetch tool |
|
||||
| Search the web | `web_search` (enabled by default; configurable in `config.toml` via the top-level `web_search` setting — `live`, `cached`, or `disabled`) |
|
||||
| Invoke a skill | Skills load natively — just follow the instructions |
|
||||
| Dispatch a subagent (`Subagent (general-purpose):` template) | `spawn_agent` (see [Subagent dispatch requires multi-agent support](#subagent-dispatch-requires-multi-agent-support)) |
|
||||
| Multiple parallel dispatches | Multiple `spawn_agent` calls in one response |
|
||||
| Wait for subagent result | `wait_agent` |
|
||||
| Free up subagent slot when done | `close_agent` |
|
||||
| Task tracking ("create a todo", "mark complete") | `update_plan` |
|
||||
|
||||
## Instructions file
|
||||
|
||||
When a skill mentions "your instructions file", on Codex this is **`AGENTS.md`** at the project root. Codex also reads `~/.codex/AGENTS.md` for global context, and an `AGENTS.override.md` (in the project tree or `~/.codex/`) takes precedence when present. Codex walks from the project root down to the current working directory, concatenating `AGENTS.md` files it finds along the way, up to `project_doc_max_bytes` (32 KiB by default).
|
||||
|
||||
## Personal skills directory
|
||||
|
||||
User-level skills live at **`$CODEX_HOME/skills/`** (default `~/.codex/skills/`). Codex also reads the cross-runtime path **`~/.agents/skills/`** (shared with Copilot CLI and Gemini CLI). When both directories exist at the same scope, Codex loads them both as separate skill catalogs — Codex's docs don't currently document a precedence between them. Each skill is a subdirectory containing a `SKILL.md` (with `name` and `description` frontmatter).
|
||||
|
||||
## Subagent dispatch requires multi-agent support
|
||||
|
||||
@@ -22,53 +35,12 @@ Add to your Codex config (`~/.codex/config.toml`):
|
||||
multi_agent = true
|
||||
```
|
||||
|
||||
This enables `spawn_agent`, `wait`, and `close_agent` for skills like `dispatching-parallel-agents` and `subagent-driven-development`.
|
||||
This enables `spawn_agent`, `wait_agent`, and `close_agent` for skills like `dispatching-parallel-agents` and `subagent-driven-development`.
|
||||
|
||||
## Named agent dispatch
|
||||
|
||||
Claude Code skills reference named agent types like `superpowers:code-reviewer`.
|
||||
Codex does not have a named agent registry — `spawn_agent` creates generic agents
|
||||
from built-in roles (`default`, `explorer`, `worker`).
|
||||
|
||||
When a skill says to dispatch a named agent type:
|
||||
|
||||
1. Find the agent's prompt file (e.g., `agents/code-reviewer.md` or the skill's
|
||||
local prompt template like `code-quality-reviewer-prompt.md`)
|
||||
2. Read the prompt content
|
||||
3. Fill any template placeholders (`{BASE_SHA}`, `{WHAT_WAS_IMPLEMENTED}`, etc.)
|
||||
4. Spawn a `worker` agent with the filled content as the `message`
|
||||
|
||||
| Skill instruction | Codex equivalent |
|
||||
|-------------------|------------------|
|
||||
| `Task tool (superpowers:code-reviewer)` | `spawn_agent(agent_type="worker", message=...)` with `code-reviewer.md` content |
|
||||
| `Task tool (general-purpose)` with inline prompt | `spawn_agent(message=...)` with the same prompt |
|
||||
|
||||
### Message framing
|
||||
|
||||
The `message` parameter is user-level input, not a system prompt. Structure it
|
||||
for maximum instruction adherence:
|
||||
|
||||
```
|
||||
Your task is to perform the following. Follow the instructions below exactly.
|
||||
|
||||
<agent-instructions>
|
||||
[filled prompt content from the agent's .md file]
|
||||
</agent-instructions>
|
||||
|
||||
Execute this now. Output ONLY the structured response following the format
|
||||
specified in the instructions above.
|
||||
```
|
||||
|
||||
- Use task-delegation framing ("Your task is...") rather than persona framing ("You are...")
|
||||
- Wrap instructions in XML tags — the model treats tagged blocks as authoritative
|
||||
- End with an explicit execution directive to prevent summarization of the instructions
|
||||
|
||||
### When this workaround can be removed
|
||||
|
||||
This approach compensates for Codex's plugin system not yet supporting an `agents`
|
||||
field in `plugin.json`. When `RawPluginManifest` gains an `agents` field, the
|
||||
plugin can symlink to `agents/` (mirroring the existing `skills/` symlink) and
|
||||
skills can dispatch named agent types directly.
|
||||
Legacy note: Codex builds before `rust-v0.115.0` exposed spawned-agent
|
||||
waiting as `wait`. Current Codex uses `wait_agent` for spawned agents. The
|
||||
`wait` name now belongs to code-mode `exec/wait`, which resumes a yielded exec
|
||||
cell by `cell_id`; it is not the spawned-agent result tool.
|
||||
|
||||
## Environment Detection
|
||||
|
||||
|
||||
@@ -1,41 +1,38 @@
|
||||
# Copilot CLI Tool Mapping
|
||||
|
||||
Skills use Claude Code tool names. When you encounter these in a skill, use your platform equivalent:
|
||||
Skills speak in actions ("dispatch a subagent", "create a todo", "read a file"). On Copilot CLI these resolve to the tools below.
|
||||
|
||||
| Skill references | Copilot CLI equivalent |
|
||||
|-----------------|----------------------|
|
||||
| `Read` (file reading) | `view` |
|
||||
| `Write` (file creation) | `create` |
|
||||
| `Edit` (file editing) | `edit` |
|
||||
| `Bash` (run commands) | `bash` |
|
||||
| `Grep` (search file content) | `grep` |
|
||||
| `Glob` (search files by name) | `glob` |
|
||||
| `Skill` tool (invoke a skill) | `skill` |
|
||||
| `WebFetch` | `web_fetch` |
|
||||
| `Task` tool (dispatch subagent) | `task` (see [Agent types](#agent-types)) |
|
||||
| Multiple `Task` calls (parallel) | Multiple `task` calls |
|
||||
| Task status/output | `read_agent`, `list_agents` |
|
||||
| `TodoWrite` (task tracking) | `sql` with built-in `todos` table |
|
||||
| `WebSearch` | No equivalent — use `web_fetch` with a search engine URL |
|
||||
| `EnterPlanMode` / `ExitPlanMode` | No equivalent — stay in the main session |
|
||||
| Action skills request | Copilot CLI equivalent |
|
||||
|----------------------|----------------------|
|
||||
| Read a file | `view` |
|
||||
| Create / edit / delete a file | `apply_patch` (Copilot CLI has no separate create/edit/write tools) |
|
||||
| Run a shell command | `bash` |
|
||||
| Search file contents | `rg` (ripgrep; Copilot CLI does not expose a `grep` tool) |
|
||||
| Find files by name | `glob` |
|
||||
| Fetch a URL | `web_fetch` |
|
||||
| Search the web | `web_search` |
|
||||
| Invoke a skill | `skill` |
|
||||
| Dispatch a subagent (`Subagent (general-purpose):` template) | `task` with `agent_type: "general-purpose"` (other accepted types: `explore`, `task`, `code-review`, `research`, `configure-copilot`) |
|
||||
| Multiple parallel dispatches | Multiple `task` calls in one response (or wrap with the `parallel` tool) |
|
||||
| Subagent status/output/control | `read_agent`, `list_agents`, `write_agent` |
|
||||
| Task tracking ("create a todo", "mark complete") | `sql` with the built-in `todos` table |
|
||||
| Enter / exit plan mode | No equivalent — stay in the main session |
|
||||
|
||||
## Agent types
|
||||
## Instructions file
|
||||
|
||||
Copilot CLI's `task` tool accepts an `agent_type` parameter:
|
||||
When a skill mentions "your instructions file", on Copilot CLI this is **`AGENTS.md`** at the repository root. If both `AGENTS.md` and `.github/copilot-instructions.md` are present, Copilot reads both.
|
||||
|
||||
| Claude Code agent | Copilot CLI equivalent |
|
||||
|-------------------|----------------------|
|
||||
| `general-purpose` | `"general-purpose"` |
|
||||
| `Explore` | `"explore"` |
|
||||
| Named plugin agents (e.g. `superpowers:code-reviewer`) | Discovered automatically from installed plugins |
|
||||
## Personal skills directory
|
||||
|
||||
User-level skills live at **`~/.copilot/skills/`**. Copilot CLI also recognizes the cross-runtime alias **`~/.agents/skills/`**, which is shared with Codex and Gemini CLI. Each skill is a subdirectory containing a `SKILL.md` (with `name` and `description` frontmatter).
|
||||
|
||||
## Async shell sessions
|
||||
|
||||
Copilot CLI supports persistent async shell sessions, which have no direct Claude Code equivalent:
|
||||
Copilot CLI supports persistent async shell sessions:
|
||||
|
||||
| Tool | Purpose |
|
||||
|------|---------|
|
||||
| `bash` with `async: true` | Start a long-running command in the background |
|
||||
| `bash` with `mode: "async"` (and optionally `detach: true`) | Start a long-running command in the background; returns a `shellId` |
|
||||
| `write_bash` | Send input to a running async session |
|
||||
| `read_bash` | Read output from an async session |
|
||||
| `stop_bash` | Terminate an async session |
|
||||
|
||||
@@ -1,33 +1,63 @@
|
||||
# Gemini CLI Tool Mapping
|
||||
|
||||
Skills use Claude Code tool names. When you encounter these in a skill, use your platform equivalent:
|
||||
Skills speak in actions ("dispatch a subagent", "create a todo", "read a file"). On Gemini CLI these resolve to the tools below.
|
||||
|
||||
| Skill references | Gemini CLI equivalent |
|
||||
|-----------------|----------------------|
|
||||
| `Read` (file reading) | `read_file` |
|
||||
| `Write` (file creation) | `write_file` |
|
||||
| `Edit` (file editing) | `replace` |
|
||||
| `Bash` (run commands) | `run_shell_command` |
|
||||
| `Grep` (search file content) | `grep_search` |
|
||||
| `Glob` (search files by name) | `glob` |
|
||||
| `TodoWrite` (task tracking) | `write_todos` |
|
||||
| `Skill` tool (invoke a skill) | `activate_skill` |
|
||||
| `WebSearch` | `google_web_search` |
|
||||
| `WebFetch` | `web_fetch` |
|
||||
| `Task` tool (dispatch subagent) | No equivalent — Gemini CLI does not support subagents |
|
||||
| Action skills request | Gemini CLI equivalent |
|
||||
|----------------------|----------------------|
|
||||
| Read a file | `read_file` |
|
||||
| Read multiple files at once | `read_many_files` |
|
||||
| Create a new file | `write_file` |
|
||||
| Edit a file | `replace` |
|
||||
| Run a shell command | `run_shell_command` |
|
||||
| Search file contents | `grep_search` |
|
||||
| Find files by name | `glob` |
|
||||
| List files and subdirectories | `list_directory` |
|
||||
| Fetch a URL | `web_fetch` |
|
||||
| Search the web | `google_web_search` |
|
||||
| Invoke a skill | `activate_skill` |
|
||||
| Dispatch a subagent (`Subagent (general-purpose):` template) | `invoke_agent` with `agent_name: "generalist"` (invocable via `@generalist` chat syntax — see [Subagent support](#subagent-support)) |
|
||||
| Multiple parallel dispatches | Multiple `invoke_agent` calls in the same response |
|
||||
| Task tracking ("create a todo", "mark complete") | `write_todos` (statuses: pending, in_progress, completed, cancelled, blocked) |
|
||||
|
||||
## No subagent support
|
||||
## Instructions file
|
||||
|
||||
Gemini CLI has no equivalent to Claude Code's `Task` tool. Skills that rely on subagent dispatch (`subagent-driven-development`, `dispatching-parallel-agents`) will fall back to single-session execution via `executing-plans`.
|
||||
When a skill mentions "your instructions file", on Gemini CLI this is **`GEMINI.md`**. Gemini CLI loads `GEMINI.md` hierarchically: global at `~/.gemini/GEMINI.md`, project-level files in workspace directories and their ancestors, and sub-directory `GEMINI.md` files when a tool accesses files in those directories.
|
||||
|
||||
## Personal skills directory
|
||||
|
||||
User-level skills live at **`~/.gemini/skills/`**, with **`~/.agents/skills/`** as a cross-runtime alias (shared with Codex and Copilot CLI). When both directories exist at the same scope, `.agents/skills/` takes precedence. Each skill is a subdirectory containing a `SKILL.md` (with `name` and `description` frontmatter).
|
||||
|
||||
## Subagent support
|
||||
|
||||
Gemini CLI dispatches subagents through the `invoke_agent` tool, which takes `agent_name` and `prompt` parameters. The same dispatch is also surfaced as a chat-syntax shortcut: typing `@generalist <prompt>` is equivalent to calling `invoke_agent` with `agent_name: "generalist"`. Built-in agent names include `generalist`, `cli_help`, `codebase_investigator`, and (with browser tooling enabled) the browser agent.
|
||||
|
||||
Skills dispatch with `Subagent (general-purpose):` and either reference a prompt-template file (e.g., `subagent-driven-development/implementer-prompt.md`) or supply an inline prompt. On Gemini CLI:
|
||||
|
||||
| Skill dispatch form | Gemini CLI equivalent |
|
||||
|---------------------|----------------------|
|
||||
| References a `*-prompt.md` template (implementer, spec-reviewer, code-quality-reviewer, code-reviewer, etc.) | Fill the template, then `invoke_agent` with `agent_name: "generalist"` and the filled prompt |
|
||||
| References `requesting-code-review/code-reviewer.md` | `invoke_agent` with `agent_name: "generalist"` and the filled review template |
|
||||
| Inline prompt (no template referenced) | `invoke_agent` with `agent_name: "generalist"` and your inline prompt |
|
||||
|
||||
### Prompt filling
|
||||
|
||||
Skills provide prompt templates with placeholders like `{WHAT_WAS_IMPLEMENTED}` or `[FULL TEXT of task]`. Fill all placeholders before passing the complete prompt to `invoke_agent`. The prompt template itself contains the agent's role, review criteria, and expected output format — the subagent will follow it.
|
||||
|
||||
### Parallel dispatch
|
||||
|
||||
Gemini CLI supports parallel subagent dispatch. Issue multiple `invoke_agent` calls in the same response (or multiple `@generalist` invocations in one prompt) to run independent subagent work in parallel. Keep dependent tasks sequential, but do not serialize independent subagent tasks just to preserve a simpler history.
|
||||
|
||||
## Additional Gemini CLI tools
|
||||
|
||||
These tools are available in Gemini CLI but have no Claude Code equivalent:
|
||||
These tools are unique to Gemini CLI:
|
||||
|
||||
| Tool | Purpose |
|
||||
|------|---------|
|
||||
| `list_directory` | List files and subdirectories |
|
||||
| `save_memory` | Persist facts to GEMINI.md across sessions |
|
||||
| `ask_user` | Request structured input from the user |
|
||||
| `tracker_create_task` | Rich task management (create, update, list, visualize) |
|
||||
| `enter_plan_mode` / `exit_plan_mode` | Switch to read-only research mode before making changes |
|
||||
| `get_internal_docs` | Look up Gemini CLI's bundled documentation |
|
||||
| `ask_user` | Pose structured questions to the user (text / single-select / multi-select) |
|
||||
| `enter_plan_mode` / `exit_plan_mode` | Switch into and out of read-only plan mode |
|
||||
| `update_topic` | Update the current conversation's topic / strategic-intent metadata |
|
||||
| `complete_task` | Signal completion of the current top-level task |
|
||||
| `tracker_create_task`, `tracker_update_task`, `tracker_get_task`, `tracker_list_tasks`, `tracker_add_dependency`, `tracker_visualize` | Rich task tracker with dependency and visualization support |
|
||||
| `read_mcp_resource`, `list_mcp_resources` | MCP resource access |
|
||||
|
||||
@@ -7,7 +7,7 @@ Use this template when dispatching a plan document reviewer subagent.
|
||||
**Dispatch after:** The complete plan is written.
|
||||
|
||||
```
|
||||
Task tool (general-purpose):
|
||||
Subagent (general-purpose):
|
||||
description: "Review plan document"
|
||||
prompt: |
|
||||
You are a plan document reviewer. Verify this plan is complete and ready for implementation.
|
||||
|
||||
@@ -9,7 +9,7 @@ description: Use when creating new skills, editing existing skills, or verifying
|
||||
|
||||
**Writing skills IS Test-Driven Development applied to process documentation.**
|
||||
|
||||
**Personal skills live in agent-specific directories (`~/.claude/skills` for Claude Code, `~/.agents/skills/` for Codex)**
|
||||
**Personal skills live in your runtime's skills directory** — see `../using-superpowers/references/<platform>-tools.md` (where `<platform>` is `claude-code`, `codex`, `copilot`, or `gemini`) for the path on your runtime. Codex, Copilot CLI, and Gemini CLI all also recognize `~/.agents/skills/` as a cross-runtime alias.
|
||||
|
||||
You write test cases (pressure scenarios with subagents), watch them fail (baseline behavior), write the skill (documentation), watch tests pass (agents comply), and refactor (close loopholes).
|
||||
|
||||
@@ -21,7 +21,7 @@ You write test cases (pressure scenarios with subagents), watch them fail (basel
|
||||
|
||||
## What is a Skill?
|
||||
|
||||
A **skill** is a reference guide for proven techniques, patterns, or tools. Skills help future Claude instances find and apply effective approaches.
|
||||
A **skill** is a reference guide for proven techniques, patterns, or tools. Skills help future agents find and apply effective approaches.
|
||||
|
||||
**Skills are:** Reusable techniques, patterns, tools, reference guides
|
||||
|
||||
@@ -55,7 +55,7 @@ The entire skill creation process follows RED-GREEN-REFACTOR.
|
||||
**Don't create for:**
|
||||
- One-off solutions
|
||||
- Standard practices well-documented elsewhere
|
||||
- Project-specific conventions (put in CLAUDE.md)
|
||||
- Project-specific conventions (put in your instructions file)
|
||||
- Mechanical constraints (if it's enforceable with regex/validation, automate it—save documentation for judgment calls)
|
||||
|
||||
## Skill Types
|
||||
@@ -99,7 +99,7 @@ skills/
|
||||
- `description`: Third-person, describes ONLY when to use (NOT what it does)
|
||||
- Start with "Use when..." to focus on triggering conditions
|
||||
- Include specific symptoms, situations, and contexts
|
||||
- **NEVER summarize the skill's process or workflow** (see CSO section for why)
|
||||
- **NEVER summarize the skill's process or workflow** (see SDO section for why)
|
||||
- Keep under 500 characters if possible
|
||||
|
||||
```markdown
|
||||
@@ -137,13 +137,13 @@ Concrete results
|
||||
```
|
||||
|
||||
|
||||
## Claude Search Optimization (CSO)
|
||||
## Skill Discovery Optimization (SDO)
|
||||
|
||||
**Critical for discovery:** Future Claude needs to FIND your skill
|
||||
**Critical for discovery:** Future agents need to FIND your skill
|
||||
|
||||
### 1. Rich Description Field
|
||||
|
||||
**Purpose:** Claude reads description to decide which skills to load for a given task. Make it answer: "Should I read this skill right now?"
|
||||
**Purpose:** Your agent reads the description to decide which skills to load for a given task. Make it answer: "Should I read this skill right now?"
|
||||
|
||||
**Format:** Start with "Use when..." to focus on triggering conditions
|
||||
|
||||
@@ -151,14 +151,14 @@ Concrete results
|
||||
|
||||
The description should ONLY describe triggering conditions. Do NOT summarize the skill's process or workflow in the description.
|
||||
|
||||
**Why this matters:** Testing revealed that when a description summarizes the skill's workflow, Claude may follow the description instead of reading the full skill content. A description saying "code review between tasks" caused Claude to do ONE review, even though the skill's flowchart clearly showed TWO reviews (spec compliance then code quality).
|
||||
**Why this matters:** Testing revealed that when a description summarizes the skill's workflow, an agent may follow the description instead of reading the full skill content. A description saying "code review between tasks" caused an agent to do ONE review, even though the skill's flowchart clearly showed TWO reviews (spec compliance then code quality).
|
||||
|
||||
When the description was changed to just "Use when executing implementation plans with independent tasks" (no workflow summary), Claude correctly read the flowchart and followed the two-stage review process.
|
||||
When the description was changed to just "Use when executing implementation plans with independent tasks" (no workflow summary), the agent correctly read the flowchart and followed the two-stage review process.
|
||||
|
||||
**The trap:** Descriptions that summarize workflow create a shortcut Claude will take. The skill body becomes documentation Claude skips.
|
||||
**The trap:** Descriptions that summarize workflow create a shortcut agents will take. The skill body becomes documentation agents skip.
|
||||
|
||||
```yaml
|
||||
# ❌ BAD: Summarizes workflow - Claude may follow this instead of reading skill
|
||||
# ❌ BAD: Summarizes workflow - agents may follow this instead of reading skill
|
||||
description: Use when executing plans - dispatches subagent per task with code review between tasks
|
||||
|
||||
# ❌ BAD: Too much process detail
|
||||
@@ -198,7 +198,7 @@ description: Use when using React Router and handling authentication redirects
|
||||
|
||||
### 2. Keyword Coverage
|
||||
|
||||
Use words Claude would search for:
|
||||
Use words an agent would search for:
|
||||
- Error messages: "Hook timed out", "ENOTEMPTY", "race condition"
|
||||
- Symptoms: "flaky", "hanging", "zombie", "pollution"
|
||||
- Synonyms: "timeout/hang/freeze", "cleanup/teardown/afterEach"
|
||||
@@ -275,7 +275,7 @@ wc -w skills/path/SKILL.md
|
||||
- `creating-skills`, `testing-skills`, `debugging-with-logs`
|
||||
- Active, describes the action you're taking
|
||||
|
||||
### 4. Cross-Referencing Other Skills
|
||||
### 5. Cross-Referencing Other Skills
|
||||
|
||||
**When writing documentation that references other skills:**
|
||||
|
||||
@@ -313,7 +313,7 @@ digraph when_flowchart {
|
||||
- Linear instructions → Numbered lists
|
||||
- Labels without semantic meaning (step1, helper2)
|
||||
|
||||
See @graphviz-conventions.dot for graphviz style rules.
|
||||
See `graphviz-conventions.dot` in this directory for graphviz style rules.
|
||||
|
||||
**Visualizing for your human partner:** Use `render-graphs.js` in this directory to render a skill's flowcharts to SVG:
|
||||
```bash
|
||||
@@ -522,7 +522,7 @@ Make it easy for agents to self-check when rationalizing:
|
||||
**All of these mean: Delete code. Start over with TDD.**
|
||||
```
|
||||
|
||||
### Update CSO for Violation Symptoms
|
||||
### Update SDO for Violation Symptoms
|
||||
|
||||
Add to description: symptoms of when you're ABOUT to violate the rule:
|
||||
|
||||
@@ -595,7 +595,7 @@ Deploying untested skills = deploying untested code. It's a violation of quality
|
||||
|
||||
## Skill Creation Checklist (TDD Adapted)
|
||||
|
||||
**IMPORTANT: Use TodoWrite to create todos for EACH checklist item below.**
|
||||
**IMPORTANT: Create a todo for EACH checklist item below.**
|
||||
|
||||
**RED Phase - Write Failing Test:**
|
||||
- [ ] Create pressure scenarios (3+ combined pressures for discipline skills)
|
||||
@@ -634,9 +634,10 @@ Deploying untested skills = deploying untested code. It's a violation of quality
|
||||
|
||||
## Discovery Workflow
|
||||
|
||||
How future Claude finds your skill:
|
||||
How future agents find your skill:
|
||||
|
||||
1. **Encounters problem** ("tests are flaky")
|
||||
2. **Searches skills** (greps descriptions, browses categories)
|
||||
3. **Finds SKILL** (description matches)
|
||||
4. **Scans overview** (is this relevant?)
|
||||
5. **Reads patterns** (quick reference table)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Skill authoring best practices
|
||||
|
||||
> Learn how to write effective Skills that Claude can discover and use successfully.
|
||||
> Learn how to write effective Skills that agents can discover and use successfully.
|
||||
|
||||
Good Skills are concise, well-structured, and tested with real usage. This guide provides practical authoring decisions to help you write Skills that Claude can discover and use effectively.
|
||||
Good Skills are concise, well-structured, and tested with real usage. This guide provides practical authoring decisions to help you write Skills that agents can discover and use effectively.
|
||||
|
||||
For conceptual background on how Skills work, see the [Skills overview](/en/docs/agents-and-tools/agent-skills/overview).
|
||||
|
||||
@@ -10,21 +10,21 @@ For conceptual background on how Skills work, see the [Skills overview](/en/docs
|
||||
|
||||
### Concise is key
|
||||
|
||||
The [context window](https://platform.claude.com/docs/en/build-with-claude/context-windows) is a public good. Your Skill shares the context window with everything else Claude needs to know, including:
|
||||
The [context window](https://platform.claude.com/docs/en/build-with-claude/context-windows) is a public good. Your Skill shares the context window with everything else your agent needs to know, including:
|
||||
|
||||
* The system prompt
|
||||
* Conversation history
|
||||
* Other Skills' metadata
|
||||
* Your actual request
|
||||
|
||||
Not every token in your Skill has an immediate cost. At startup, only the metadata (name and description) from all Skills is pre-loaded. Claude reads SKILL.md only when the Skill becomes relevant, and reads additional files only as needed. However, being concise in SKILL.md still matters: once Claude loads it, every token competes with conversation history and other context.
|
||||
Not every token in your Skill has an immediate cost. At startup, only the metadata (name and description) from all Skills is pre-loaded. Agents read SKILL.md only when the Skill becomes relevant, and read additional files only as needed. However, being concise in SKILL.md still matters: once an agent loads it, every token competes with conversation history and other context.
|
||||
|
||||
**Default assumption**: Claude is already very smart
|
||||
**Default assumption**: Agents are already very smart
|
||||
|
||||
Only add context Claude doesn't already have. Challenge each piece of information:
|
||||
Only add context agents don't already have. Challenge each piece of information:
|
||||
|
||||
* "Does Claude really need this explanation?"
|
||||
* "Can I assume Claude knows this?"
|
||||
* "Does the agent really need this explanation?"
|
||||
* "Can I assume the agent knows this?"
|
||||
* "Does this paragraph justify its token cost?"
|
||||
|
||||
**Good example: Concise** (approximately 50 tokens):
|
||||
@@ -54,7 +54,7 @@ recommend pdfplumber because it's easy to use and handles most cases well.
|
||||
First, you'll need to install it using pip. Then you can use the code below...
|
||||
```
|
||||
|
||||
The concise version assumes Claude knows what PDFs are and how libraries work.
|
||||
The concise version assumes the agent knows what PDFs are and how libraries work.
|
||||
|
||||
### Set appropriate degrees of freedom
|
||||
|
||||
@@ -124,10 +124,10 @@ python scripts/migrate.py --verify --backup
|
||||
Do not modify the command or add additional flags.
|
||||
````
|
||||
|
||||
**Analogy**: Think of Claude as a robot exploring a path:
|
||||
**Analogy**: Think of the agent as a robot exploring a path:
|
||||
|
||||
* **Narrow bridge with cliffs on both sides**: There's only one safe way forward. Provide specific guardrails and exact instructions (low freedom). Example: database migrations that must run in exact sequence.
|
||||
* **Open field with no hazards**: Many paths lead to success. Give general direction and trust Claude to find the best route (high freedom). Example: code reviews where context determines the best approach.
|
||||
* **Open field with no hazards**: Many paths lead to success. Give general direction and trust the agent to find the best route (high freedom). Example: code reviews where context determines the best approach.
|
||||
|
||||
### Test with all models you plan to use
|
||||
|
||||
@@ -196,7 +196,7 @@ The `description` field enables Skill discovery and should include both what the
|
||||
|
||||
**Be specific and include key terms**. Include both what the Skill does and specific triggers/contexts for when to use it.
|
||||
|
||||
Each Skill has exactly one description field. The description is critical for skill selection: Claude uses it to choose the right Skill from potentially 100+ available Skills. Your description must provide enough detail for Claude to know when to select this Skill, while the rest of SKILL.md provides the implementation details.
|
||||
Each Skill has exactly one description field. The description is critical for skill selection: agents use it to choose the right Skill from potentially 100+ available Skills. Your description must provide enough detail for an agent to know when to select this Skill, while the rest of SKILL.md provides the implementation details.
|
||||
|
||||
Effective examples:
|
||||
|
||||
@@ -234,7 +234,7 @@ description: Does stuff with files
|
||||
|
||||
### Progressive disclosure patterns
|
||||
|
||||
SKILL.md serves as an overview that points Claude to detailed materials as needed, like a table of contents in an onboarding guide. For an explanation of how progressive disclosure works, see [How Skills work](/en/docs/agents-and-tools/agent-skills/overview#how-skills-work) in the overview.
|
||||
SKILL.md serves as an overview that points agents to detailed materials as needed, like a table of contents in an onboarding guide. For an explanation of how progressive disclosure works, see [How Skills work](/en/docs/agents-and-tools/agent-skills/overview#how-skills-work) in the overview.
|
||||
|
||||
**Practical guidance:**
|
||||
|
||||
@@ -248,7 +248,7 @@ A basic Skill starts with just a SKILL.md file containing metadata and instructi
|
||||
|
||||
<img src="https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-simple-file.png?fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=87782ff239b297d9a9e8e1b72ed72db9" alt="Simple SKILL.md file showing YAML frontmatter and markdown body" data-og-width="2048" width="2048" data-og-height="1153" height="1153" data-path="images/agent-skills-simple-file.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-simple-file.png?w=280&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=c61cc33b6f5855809907f7fda94cd80e 280w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-simple-file.png?w=560&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=90d2c0c1c76b36e8d485f49e0810dbfd 560w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-simple-file.png?w=840&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=ad17d231ac7b0bea7e5b4d58fb4aeabb 840w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-simple-file.png?w=1100&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=f5d0a7a3c668435bb0aee9a3a8f8c329 1100w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-simple-file.png?w=1650&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=0e927c1af9de5799cfe557d12249f6e6 1650w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-simple-file.png?w=2500&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=46bbb1a51dd4c8202a470ac8c80a893d 2500w" />
|
||||
|
||||
As your Skill grows, you can bundle additional content that Claude loads only when needed:
|
||||
As your Skill grows, you can bundle additional content that agents load only when needed:
|
||||
|
||||
<img src="https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-bundling-content.png?fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=a5e0aa41e3d53985a7e3e43668a33ea3" alt="Bundling additional reference files like reference.md and forms.md." data-og-width="2048" width="2048" data-og-height="1327" height="1327" data-path="images/agent-skills-bundling-content.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-bundling-content.png?w=280&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=f8a0e73783e99b4a643d79eac86b70a2 280w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-bundling-content.png?w=560&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=dc510a2a9d3f14359416b706f067904a 560w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-bundling-content.png?w=840&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=82cd6286c966303f7dd914c28170e385 840w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-bundling-content.png?w=1100&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=56f3be36c77e4fe4b523df209a6824c6 1100w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-bundling-content.png?w=1650&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=d22b5161b2075656417d56f41a74f3dd 1650w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-bundling-content.png?w=2500&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=3dd4bdd6850ffcc96c6c45fcb0acd6eb 2500w" />
|
||||
|
||||
@@ -292,11 +292,11 @@ with pdfplumber.open("file.pdf") as pdf:
|
||||
**Examples**: See [EXAMPLES.md](EXAMPLES.md) for common patterns
|
||||
````
|
||||
|
||||
Claude loads FORMS.md, REFERENCE.md, or EXAMPLES.md only when needed.
|
||||
Agents load FORMS.md, REFERENCE.md, or EXAMPLES.md only when needed.
|
||||
|
||||
#### Pattern 2: Domain-specific organization
|
||||
|
||||
For Skills with multiple domains, organize content by domain to avoid loading irrelevant context. When a user asks about sales metrics, Claude only needs to read sales-related schemas, not finance or marketing data. This keeps token usage low and context focused.
|
||||
For Skills with multiple domains, organize content by domain to avoid loading irrelevant context. When a user asks about sales metrics, the agent only needs to read sales-related schemas, not finance or marketing data. This keeps token usage low and context focused.
|
||||
|
||||
```
|
||||
bigquery-skill/
|
||||
@@ -348,13 +348,13 @@ For simple edits, modify the XML directly.
|
||||
**For OOXML details**: See [OOXML.md](OOXML.md)
|
||||
```
|
||||
|
||||
Claude reads REDLINING.md or OOXML.md only when the user needs those features.
|
||||
Agents read REDLINING.md or OOXML.md only when the user needs those features.
|
||||
|
||||
### Avoid deeply nested references
|
||||
|
||||
Claude may partially read files when they're referenced from other referenced files. When encountering nested references, Claude might use commands like `head -100` to preview content rather than reading entire files, resulting in incomplete information.
|
||||
Agents may partially read files when they're referenced from other referenced files. When encountering nested references, an agent might use commands like `head -100` to preview content rather than reading entire files, resulting in incomplete information.
|
||||
|
||||
**Keep references one level deep from SKILL.md**. All reference files should link directly from SKILL.md to ensure Claude reads complete files when needed.
|
||||
**Keep references one level deep from SKILL.md**. All reference files should link directly from SKILL.md to ensure agents read complete files when needed.
|
||||
|
||||
**Bad example: Too deep**:
|
||||
|
||||
@@ -382,7 +382,7 @@ Here's the actual information...
|
||||
|
||||
### Structure longer reference files with table of contents
|
||||
|
||||
For reference files longer than 100 lines, include a table of contents at the top. This ensures Claude can see the full scope of available information even when previewing with partial reads.
|
||||
For reference files longer than 100 lines, include a table of contents at the top. This ensures agents can see the full scope of available information even when previewing with partial reads.
|
||||
|
||||
**Example**:
|
||||
|
||||
@@ -403,7 +403,7 @@ For reference files longer than 100 lines, include a table of contents at the to
|
||||
...
|
||||
```
|
||||
|
||||
Claude can then read the complete file or jump to specific sections as needed.
|
||||
Agents can then read the complete file or jump to specific sections as needed.
|
||||
|
||||
For details on how this filesystem-based architecture enables progressive disclosure, see the [Runtime environment](#runtime-environment) section in the Advanced section below.
|
||||
|
||||
@@ -411,7 +411,7 @@ For details on how this filesystem-based architecture enables progressive disclo
|
||||
|
||||
### Use workflows for complex tasks
|
||||
|
||||
Break complex operations into clear, sequential steps. For particularly complex workflows, provide a checklist that Claude can copy into its response and check off as it progresses.
|
||||
Break complex operations into clear, sequential steps. For particularly complex workflows, provide a checklist that the agent can copy into its response and check off as it progresses.
|
||||
|
||||
**Example 1: Research synthesis workflow** (for Skills without code):
|
||||
|
||||
@@ -498,7 +498,7 @@ Run: `python scripts/verify_output.py output.pdf`
|
||||
If verification fails, return to Step 2.
|
||||
````
|
||||
|
||||
Clear steps prevent Claude from skipping critical validation. The checklist helps both Claude and you track progress through multi-step workflows.
|
||||
Clear steps prevent agents from skipping critical validation. The checklist helps both you and the agent track progress through multi-step workflows.
|
||||
|
||||
### Implement feedback loops
|
||||
|
||||
@@ -524,7 +524,7 @@ This pattern greatly improves output quality.
|
||||
5. Finalize and save the document
|
||||
```
|
||||
|
||||
This shows the validation loop pattern using reference documents instead of scripts. The "validator" is STYLE\_GUIDE.md, and Claude performs the check by reading and comparing.
|
||||
This shows the validation loop pattern using reference documents instead of scripts. The "validator" is STYLE\_GUIDE.md, and the agent performs the check by reading and comparing.
|
||||
|
||||
**Example 2: Document editing process** (for Skills with code):
|
||||
|
||||
@@ -593,7 +593,7 @@ Choose one term and use it throughout the Skill:
|
||||
* Mix "field", "box", "element", "control"
|
||||
* Mix "extract", "pull", "get", "retrieve"
|
||||
|
||||
Consistency helps Claude understand and follow instructions.
|
||||
Consistency helps agents understand and follow instructions.
|
||||
|
||||
## Common patterns
|
||||
|
||||
@@ -688,11 +688,11 @@ chore: update dependencies and refactor error handling
|
||||
Follow this style: type(scope): brief description, then detailed explanation.
|
||||
````
|
||||
|
||||
Examples help Claude understand the desired style and level of detail more clearly than descriptions alone.
|
||||
Examples help agents understand the desired style and level of detail more clearly than descriptions alone.
|
||||
|
||||
### Conditional workflow pattern
|
||||
|
||||
Guide Claude through decision points:
|
||||
Guide agents through decision points:
|
||||
|
||||
```markdown theme={null}
|
||||
## Document modification workflow
|
||||
@@ -715,7 +715,7 @@ Guide Claude through decision points:
|
||||
```
|
||||
|
||||
<Tip>
|
||||
If workflows become large or complicated with many steps, consider pushing them into separate files and tell Claude to read the appropriate file based on the task at hand.
|
||||
If workflows become large or complicated with many steps, consider pushing them into separate files and tell the agent to read the appropriate file based on the task at hand.
|
||||
</Tip>
|
||||
|
||||
## Evaluation and iteration
|
||||
@@ -726,9 +726,9 @@ Guide Claude through decision points:
|
||||
|
||||
**Evaluation-driven development:**
|
||||
|
||||
1. **Identify gaps**: Run Claude on representative tasks without a Skill. Document specific failures or missing context
|
||||
1. **Identify gaps**: Run your agent on representative tasks without a Skill. Document specific failures or missing context
|
||||
2. **Create evaluations**: Build three scenarios that test these gaps
|
||||
3. **Establish baseline**: Measure Claude's performance without the Skill
|
||||
3. **Establish baseline**: Measure the agent's performance without the Skill
|
||||
4. **Write minimal instructions**: Create just enough content to address the gaps and pass evaluations
|
||||
5. **Iterate**: Execute evaluations, compare against baseline, and refine
|
||||
|
||||
@@ -753,51 +753,51 @@ This approach ensures you're solving actual problems rather than anticipating re
|
||||
This example demonstrates a data-driven evaluation with a simple testing rubric. We do not currently provide a built-in way to run these evaluations. Users can create their own evaluation system. Evaluations are your source of truth for measuring Skill effectiveness.
|
||||
</Note>
|
||||
|
||||
### Develop Skills iteratively with Claude
|
||||
### Develop Skills iteratively with the agent
|
||||
|
||||
The most effective Skill development process involves Claude itself. Work with one instance of Claude ("Claude A") to create a Skill that will be used by other instances ("Claude B"). Claude A helps you design and refine instructions, while Claude B tests them in real tasks. This works because Claude models understand both how to write effective agent instructions and what information agents need.
|
||||
The most effective Skill development process involves the agent itself. Work with one instance ("Agent A") to create a Skill that will be used by other instances ("Agent B"). Agent A helps you design and refine instructions, while Agent B tests them in real tasks. This works because the underlying models understand both how to write effective agent instructions and what information agents need.
|
||||
|
||||
**Creating a new Skill:**
|
||||
|
||||
1. **Complete a task without a Skill**: Work through a problem with Claude A using normal prompting. As you work, you'll naturally provide context, explain preferences, and share procedural knowledge. Notice what information you repeatedly provide.
|
||||
1. **Complete a task without a Skill**: Work through a problem with Agent A using normal prompting. As you work, you'll naturally provide context, explain preferences, and share procedural knowledge. Notice what information you repeatedly provide.
|
||||
|
||||
2. **Identify the reusable pattern**: After completing the task, identify what context you provided that would be useful for similar future tasks.
|
||||
|
||||
**Example**: If you worked through a BigQuery analysis, you might have provided table names, field definitions, filtering rules (like "always exclude test accounts"), and common query patterns.
|
||||
|
||||
3. **Ask Claude A to create a Skill**: "Create a Skill that captures this BigQuery analysis pattern we just used. Include the table schemas, naming conventions, and the rule about filtering test accounts."
|
||||
3. **Ask Agent A to create a Skill**: "Create a Skill that captures this BigQuery analysis pattern we just used. Include the table schemas, naming conventions, and the rule about filtering test accounts."
|
||||
|
||||
<Tip>
|
||||
Claude models understand the Skill format and structure natively. You don't need special system prompts or a "writing skills" skill to get Claude to help create Skills. Simply ask Claude to create a Skill and it will generate properly structured SKILL.md content with appropriate frontmatter and body content.
|
||||
Modern agents understand the Skill format and structure natively. You don't need special system prompts or a "writing skills" skill to get help creating Skills. Simply ask the agent to create a Skill and it will generate properly structured SKILL.md content with appropriate frontmatter and body content.
|
||||
</Tip>
|
||||
|
||||
4. **Review for conciseness**: Check that Claude A hasn't added unnecessary explanations. Ask: "Remove the explanation about what win rate means - Claude already knows that."
|
||||
4. **Review for conciseness**: Check that Agent A hasn't added unnecessary explanations. Ask: "Remove the explanation about what win rate means - the agent already knows that."
|
||||
|
||||
5. **Improve information architecture**: Ask Claude A to organize the content more effectively. For example: "Organize this so the table schema is in a separate reference file. We might add more tables later."
|
||||
5. **Improve information architecture**: Ask Agent A to organize the content more effectively. For example: "Organize this so the table schema is in a separate reference file. We might add more tables later."
|
||||
|
||||
6. **Test on similar tasks**: Use the Skill with Claude B (a fresh instance with the Skill loaded) on related use cases. Observe whether Claude B finds the right information, applies rules correctly, and handles the task successfully.
|
||||
6. **Test on similar tasks**: Use the Skill with Agent B (a fresh instance with the Skill loaded) on related use cases. Observe whether Agent B finds the right information, applies rules correctly, and handles the task successfully.
|
||||
|
||||
7. **Iterate based on observation**: If Claude B struggles or misses something, return to Claude A with specifics: "When Claude used this Skill, it forgot to filter by date for Q4. Should we add a section about date filtering patterns?"
|
||||
7. **Iterate based on observation**: If Agent B struggles or misses something, return to Agent A with specifics: "When the agent used this Skill, it forgot to filter by date for Q4. Should we add a section about date filtering patterns?"
|
||||
|
||||
**Iterating on existing Skills:**
|
||||
|
||||
The same hierarchical pattern continues when improving Skills. You alternate between:
|
||||
|
||||
* **Working with Claude A** (the expert who helps refine the Skill)
|
||||
* **Testing with Claude B** (the agent using the Skill to perform real work)
|
||||
* **Observing Claude B's behavior** and bringing insights back to Claude A
|
||||
* **Working with Agent A** (the expert who helps refine the Skill)
|
||||
* **Testing with Agent B** (the agent using the Skill to perform real work)
|
||||
* **Observing Agent B's behavior** and bringing insights back to Agent A
|
||||
|
||||
1. **Use the Skill in real workflows**: Give Claude B (with the Skill loaded) actual tasks, not test scenarios
|
||||
1. **Use the Skill in real workflows**: Give Agent B (with the Skill loaded) actual tasks, not test scenarios
|
||||
|
||||
2. **Observe Claude B's behavior**: Note where it struggles, succeeds, or makes unexpected choices
|
||||
2. **Observe Agent B's behavior**: Note where it struggles, succeeds, or makes unexpected choices
|
||||
|
||||
**Example observation**: "When I asked Claude B for a regional sales report, it wrote the query but forgot to filter out test accounts, even though the Skill mentions this rule."
|
||||
**Example observation**: "When I asked Agent B for a regional sales report, it wrote the query but forgot to filter out test accounts, even though the Skill mentions this rule."
|
||||
|
||||
3. **Return to Claude A for improvements**: Share the current SKILL.md and describe what you observed. Ask: "I noticed Claude B forgot to filter test accounts when I asked for a regional report. The Skill mentions filtering, but maybe it's not prominent enough?"
|
||||
3. **Return to Agent A for improvements**: Share the current SKILL.md and describe what you observed. Ask: "I noticed Agent B forgot to filter test accounts when I asked for a regional report. The Skill mentions filtering, but maybe it's not prominent enough?"
|
||||
|
||||
4. **Review Claude A's suggestions**: Claude A might suggest reorganizing to make rules more prominent, using stronger language like "MUST filter" instead of "always filter", or restructuring the workflow section.
|
||||
4. **Review Agent A's suggestions**: Agent A might suggest reorganizing to make rules more prominent, using stronger language like "MUST filter" instead of "always filter", or restructuring the workflow section.
|
||||
|
||||
5. **Apply and test changes**: Update the Skill with Claude A's refinements, then test again with Claude B on similar requests
|
||||
5. **Apply and test changes**: Update the Skill with Agent A's refinements, then test again with Agent B on similar requests
|
||||
|
||||
6. **Repeat based on usage**: Continue this observe-refine-test cycle as you encounter new scenarios. Each iteration improves the Skill based on real agent behavior, not assumptions.
|
||||
|
||||
@@ -807,18 +807,18 @@ The same hierarchical pattern continues when improving Skills. You alternate bet
|
||||
2. Ask: Does the Skill activate when expected? Are instructions clear? What's missing?
|
||||
3. Incorporate feedback to address blind spots in your own usage patterns
|
||||
|
||||
**Why this approach works**: Claude A understands agent needs, you provide domain expertise, Claude B reveals gaps through real usage, and iterative refinement improves Skills based on observed behavior rather than assumptions.
|
||||
**Why this approach works**: Agent A understands agent needs, you provide domain expertise, Agent B reveals gaps through real usage, and iterative refinement improves Skills based on observed behavior rather than assumptions.
|
||||
|
||||
### Observe how Claude navigates Skills
|
||||
### Observe how agents navigate Skills
|
||||
|
||||
As you iterate on Skills, pay attention to how Claude actually uses them in practice. Watch for:
|
||||
As you iterate on Skills, pay attention to how agents actually use them in practice. Watch for:
|
||||
|
||||
* **Unexpected exploration paths**: Does Claude read files in an order you didn't anticipate? This might indicate your structure isn't as intuitive as you thought
|
||||
* **Missed connections**: Does Claude fail to follow references to important files? Your links might need to be more explicit or prominent
|
||||
* **Overreliance on certain sections**: If Claude repeatedly reads the same file, consider whether that content should be in the main SKILL.md instead
|
||||
* **Ignored content**: If Claude never accesses a bundled file, it might be unnecessary or poorly signaled in the main instructions
|
||||
* **Unexpected exploration paths**: Does the agent read files in an order you didn't anticipate? This might indicate your structure isn't as intuitive as you thought
|
||||
* **Missed connections**: Does the agent fail to follow references to important files? Your links might need to be more explicit or prominent
|
||||
* **Overreliance on certain sections**: If the agent repeatedly reads the same file, consider whether that content should be in the main SKILL.md instead
|
||||
* **Ignored content**: If the agent never accesses a bundled file, it might be unnecessary or poorly signaled in the main instructions
|
||||
|
||||
Iterate based on these observations rather than assumptions. The 'name' and 'description' in your Skill's metadata are particularly critical. Claude uses these when deciding whether to trigger the Skill in response to the current task. Make sure they clearly describe what the Skill does and when it should be used.
|
||||
Iterate based on these observations rather than assumptions. The 'name' and 'description' in your Skill's metadata are particularly critical. Agents use these when deciding whether to trigger the Skill in response to the current task. Make sure they clearly describe what the Skill does and when it should be used.
|
||||
|
||||
## Anti-patterns to avoid
|
||||
|
||||
@@ -854,7 +854,7 @@ The sections below focus on Skills that include executable scripts. If your Skil
|
||||
|
||||
### Solve, don't punt
|
||||
|
||||
When writing scripts for Skills, handle error conditions rather than punting to Claude.
|
||||
When writing scripts for Skills, handle error conditions rather than punting to the agent.
|
||||
|
||||
**Good example: Handle errors explicitly**:
|
||||
|
||||
@@ -876,15 +876,15 @@ def process_file(path):
|
||||
return ''
|
||||
```
|
||||
|
||||
**Bad example: Punt to Claude**:
|
||||
**Bad example: Punt to the agent**:
|
||||
|
||||
```python theme={null}
|
||||
def process_file(path):
|
||||
# Just fail and let Claude figure it out
|
||||
# Just fail and let the agent figure it out
|
||||
return open(path).read()
|
||||
```
|
||||
|
||||
Configuration parameters should also be justified and documented to avoid "voodoo constants" (Ousterhout's law). If you don't know the right value, how will Claude determine it?
|
||||
Configuration parameters should also be justified and documented to avoid "voodoo constants" (Ousterhout's law). If you don't know the right value, how will the agent determine it?
|
||||
|
||||
**Good example: Self-documenting**:
|
||||
|
||||
@@ -907,7 +907,7 @@ RETRIES = 5 # Why 5?
|
||||
|
||||
### Provide utility scripts
|
||||
|
||||
Even if Claude could write a script, pre-made scripts offer advantages:
|
||||
Even if your agent could write a script, pre-made scripts offer advantages:
|
||||
|
||||
**Benefits of utility scripts**:
|
||||
|
||||
@@ -918,9 +918,9 @@ Even if Claude could write a script, pre-made scripts offer advantages:
|
||||
|
||||
<img src="https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-executable-scripts.png?fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=4bbc45f2c2e0bee9f2f0d5da669bad00" alt="Bundling executable scripts alongside instruction files" data-og-width="2048" width="2048" data-og-height="1154" height="1154" data-path="images/agent-skills-executable-scripts.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-executable-scripts.png?w=280&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=9a04e6535a8467bfeea492e517de389f 280w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-executable-scripts.png?w=560&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=e49333ad90141af17c0d7651cca7216b 560w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-executable-scripts.png?w=840&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=954265a5df52223d6572b6214168c428 840w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-executable-scripts.png?w=1100&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=2ff7a2d8f2a83ee8af132b29f10150fd 1100w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-executable-scripts.png?w=1650&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=48ab96245e04077f4d15e9170e081cfb 1650w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-executable-scripts.png?w=2500&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=0301a6c8b3ee879497cc5b5483177c90 2500w" />
|
||||
|
||||
The diagram above shows how executable scripts work alongside instruction files. The instruction file (forms.md) references the script, and Claude can execute it without loading its contents into context.
|
||||
The diagram above shows how executable scripts work alongside instruction files. The instruction file (forms.md) references the script, and the agent can execute it without loading its contents into context.
|
||||
|
||||
**Important distinction**: Make clear in your instructions whether Claude should:
|
||||
**Important distinction**: Make clear in your instructions whether the agent should:
|
||||
|
||||
* **Execute the script** (most common): "Run `analyze_form.py` to extract fields"
|
||||
* **Read it as reference** (for complex logic): "See `analyze_form.py` for the field extraction algorithm"
|
||||
@@ -962,7 +962,7 @@ python scripts/fill_form.py input.pdf fields.json output.pdf
|
||||
|
||||
### Use visual analysis
|
||||
|
||||
When inputs can be rendered as images, have Claude analyze them:
|
||||
When inputs can be rendered as images, have the agent analyze them:
|
||||
|
||||
````markdown theme={null}
|
||||
## Form layout analysis
|
||||
@@ -973,20 +973,20 @@ When inputs can be rendered as images, have Claude analyze them:
|
||||
```
|
||||
|
||||
2. Analyze each page image to identify form fields
|
||||
3. Claude can see field locations and types visually
|
||||
3. The agent can see field locations and types visually
|
||||
````
|
||||
|
||||
<Note>
|
||||
In this example, you'd need to write the `pdf_to_images.py` script.
|
||||
</Note>
|
||||
|
||||
Claude's vision capabilities help understand layouts and structures.
|
||||
Agent vision capabilities help understand layouts and structures.
|
||||
|
||||
### Create verifiable intermediate outputs
|
||||
|
||||
When Claude performs complex, open-ended tasks, it can make mistakes. The "plan-validate-execute" pattern catches errors early by having Claude first create a plan in a structured format, then validate that plan with a script before executing it.
|
||||
When agents perform complex, open-ended tasks, they can make mistakes. The "plan-validate-execute" pattern catches errors early by having the agent first create a plan in a structured format, then validate that plan with a script before executing it.
|
||||
|
||||
**Example**: Imagine asking Claude to update 50 form fields in a PDF based on a spreadsheet. Without validation, Claude might reference non-existent fields, create conflicting values, miss required fields, or apply updates incorrectly.
|
||||
**Example**: Imagine asking the agent to update 50 form fields in a PDF based on a spreadsheet. Without validation, it might reference non-existent fields, create conflicting values, miss required fields, or apply updates incorrectly.
|
||||
|
||||
**Solution**: Use the workflow pattern shown above (PDF form filling), but add an intermediate `changes.json` file that gets validated before applying changes. The workflow becomes: analyze → **create plan file** → **validate plan** → execute → verify.
|
||||
|
||||
@@ -994,12 +994,12 @@ When Claude performs complex, open-ended tasks, it can make mistakes. The "plan-
|
||||
|
||||
* **Catches errors early**: Validation finds problems before changes are applied
|
||||
* **Machine-verifiable**: Scripts provide objective verification
|
||||
* **Reversible planning**: Claude can iterate on the plan without touching originals
|
||||
* **Reversible planning**: The agent can iterate on the plan without touching originals
|
||||
* **Clear debugging**: Error messages point to specific problems
|
||||
|
||||
**When to use**: Batch operations, destructive changes, complex validation rules, high-stakes operations.
|
||||
|
||||
**Implementation tip**: Make validation scripts verbose with specific error messages like "Field 'signature\_date' not found. Available fields: customer\_name, order\_total, signature\_date\_signed" to help Claude fix issues.
|
||||
**Implementation tip**: Make validation scripts verbose with specific error messages like "Field 'signature\_date' not found. Available fields: customer\_name, order\_total, signature\_date\_signed" to help the agent fix issues.
|
||||
|
||||
### Package dependencies
|
||||
|
||||
@@ -1016,24 +1016,24 @@ Skills run in a code execution environment with filesystem access, bash commands
|
||||
|
||||
**How this affects your authoring:**
|
||||
|
||||
**How Claude accesses Skills:**
|
||||
**How agents access Skills:**
|
||||
|
||||
1. **Metadata pre-loaded**: At startup, the name and description from all Skills' YAML frontmatter are loaded into the system prompt
|
||||
2. **Files read on-demand**: Claude uses bash Read tools to access SKILL.md and other files from the filesystem when needed
|
||||
2. **Files read on-demand**: Agents use their file-reading tools to access SKILL.md and other files from the filesystem when needed
|
||||
3. **Scripts executed efficiently**: Utility scripts can be executed via bash without loading their full contents into context. Only the script's output consumes tokens
|
||||
4. **No context penalty for large files**: Reference files, data, or documentation don't consume context tokens until actually read
|
||||
|
||||
* **File paths matter**: Claude navigates your skill directory like a filesystem. Use forward slashes (`reference/guide.md`), not backslashes
|
||||
* **File paths matter**: Agents navigate your skill directory like a filesystem. Use forward slashes (`reference/guide.md`), not backslashes
|
||||
* **Name files descriptively**: Use names that indicate content: `form_validation_rules.md`, not `doc2.md`
|
||||
* **Organize for discovery**: Structure directories by domain or feature
|
||||
* Good: `reference/finance.md`, `reference/sales.md`
|
||||
* Bad: `docs/file1.md`, `docs/file2.md`
|
||||
* **Bundle comprehensive resources**: Include complete API docs, extensive examples, large datasets; no context penalty until accessed
|
||||
* **Prefer scripts for deterministic operations**: Write `validate_form.py` rather than asking Claude to generate validation code
|
||||
* **Prefer scripts for deterministic operations**: Write `validate_form.py` rather than asking the agent to generate validation code
|
||||
* **Make execution intent clear**:
|
||||
* "Run `analyze_form.py` to extract fields" (execute)
|
||||
* "See `analyze_form.py` for the extraction algorithm" (read as reference)
|
||||
* **Test file access patterns**: Verify Claude can navigate your directory structure by testing with real requests
|
||||
* **Test file access patterns**: Verify the agent can navigate your directory structure by testing with real requests
|
||||
|
||||
**Example:**
|
||||
|
||||
@@ -1046,7 +1046,7 @@ bigquery-skill/
|
||||
└── product.md (usage analytics)
|
||||
```
|
||||
|
||||
When the user asks about revenue, Claude reads SKILL.md, sees the reference to `reference/finance.md`, and invokes bash to read just that file. The sales.md and product.md files remain on the filesystem, consuming zero context tokens until needed. This filesystem-based model is what enables progressive disclosure. Claude can navigate and selectively load exactly what each task requires.
|
||||
When the user asks about revenue, the agent reads SKILL.md, sees the reference to `reference/finance.md`, and invokes bash to read just that file. The sales.md and product.md files remain on the filesystem, consuming zero context tokens until needed. This filesystem-based model is what enables progressive disclosure. Agents can navigate and selectively load exactly what each task requires.
|
||||
|
||||
For complete details on the technical architecture, see [How Skills work](/en/docs/agents-and-tools/agent-skills/overview#how-skills-work) in the Skills overview.
|
||||
|
||||
@@ -1068,7 +1068,7 @@ Where:
|
||||
* `BigQuery` and `GitHub` are MCP server names
|
||||
* `bigquery_schema` and `create_issue` are the tool names within those servers
|
||||
|
||||
Without the server prefix, Claude may fail to locate the tool, especially when multiple MCP servers are available.
|
||||
Without the server prefix, agents may fail to locate the tool, especially when multiple MCP servers are available.
|
||||
|
||||
### Avoid assuming tools are installed
|
||||
|
||||
@@ -1117,7 +1117,7 @@ Before sharing a Skill, verify:
|
||||
|
||||
### Code and scripts
|
||||
|
||||
* [ ] Scripts solve problems rather than punt to Claude
|
||||
* [ ] Scripts solve problems rather than punt to the agent
|
||||
* [ ] Error handling is explicit and helpful
|
||||
* [ ] No "voodoo constants" (all values justified)
|
||||
* [ ] Required packages listed in instructions and verified as available
|
||||
|
||||
@@ -33,7 +33,7 @@ LLMs respond to the same persuasion principles as humans. Understanding this psy
|
||||
**How it works in skills:**
|
||||
- Require announcements: "Announce skill usage"
|
||||
- Force explicit choices: "Choose A, B, or C"
|
||||
- Use tracking: TodoWrite for checklists
|
||||
- Use tracking: todos for checklists
|
||||
|
||||
**When to use:**
|
||||
- Ensuring skills are actually followed
|
||||
@@ -80,8 +80,8 @@ LLMs respond to the same persuasion principles as humans. Understanding this psy
|
||||
|
||||
**Example:**
|
||||
```markdown
|
||||
✅ Checklists without TodoWrite tracking = steps get skipped. Every time.
|
||||
❌ Some people find TodoWrite helpful for checklists.
|
||||
✅ Checklists without todo tracking = steps get skipped. Every time.
|
||||
❌ Some people find a todo list helpful for checklists.
|
||||
```
|
||||
|
||||
### 5. Unity
|
||||
|
||||
@@ -406,7 +406,7 @@ async function runTests() {
|
||||
assert(template.includes('indicator-bar'), 'Should have indicator bar');
|
||||
assert(template.includes('indicator-text'), 'Should have indicator text');
|
||||
assert(template.includes('<!-- CONTENT -->'), 'Should have content placeholder');
|
||||
assert(template.includes('claude-content'), 'Should have content container');
|
||||
assert(template.includes('frame-content'), 'Should have content container');
|
||||
return Promise.resolve();
|
||||
});
|
||||
|
||||
|
||||
@@ -115,6 +115,18 @@ Full workflow execution test (~10-30 minutes):
|
||||
- Subagents follow the skill correctly
|
||||
- Final code is functional and tested
|
||||
|
||||
#### test-requesting-code-review.sh
|
||||
Behavioral test for the code reviewer subagent (~5 minutes):
|
||||
- Builds a tiny project with a baseline commit
|
||||
- Adds a second commit that plants two real bugs (SQL injection, plaintext password handling)
|
||||
- Dispatches the code reviewer via the requesting-code-review skill
|
||||
- Verifies the reviewer flags the planted bugs at Critical/Important severity and refuses to approve
|
||||
|
||||
**What it tests:**
|
||||
- The skill actually dispatches a working code reviewer subagent
|
||||
- The reviewer template produces reviewers that catch obvious security bugs
|
||||
- The reviewer is not sycophantic — it does not approve a diff with planted Critical issues
|
||||
|
||||
## Adding New Tests
|
||||
|
||||
1. Create new test file: `test-<skill-name>.sh`
|
||||
|
||||
@@ -79,6 +79,7 @@ tests=(
|
||||
# Integration tests (slow, full execution)
|
||||
integration_tests=(
|
||||
"test-subagent-driven-development-integration.sh"
|
||||
"test-requesting-code-review.sh"
|
||||
)
|
||||
|
||||
# Add integration tests if requested
|
||||
|
||||
214
tests/claude-code/test-requesting-code-review.sh
Executable file
214
tests/claude-code/test-requesting-code-review.sh
Executable file
@@ -0,0 +1,214 @@
|
||||
#!/usr/bin/env bash
|
||||
# Integration Test: requesting-code-review skill
|
||||
# Verifies the code reviewer dispatched via the skill catches a planted bug
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
PLUGIN_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
source "$SCRIPT_DIR/test-helpers.sh"
|
||||
|
||||
echo "========================================"
|
||||
echo " Integration Test: requesting-code-review"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
echo "This test verifies the code reviewer subagent by:"
|
||||
echo " 1. Setting up a tiny project with a baseline commit"
|
||||
echo " 2. Adding a second commit that plants an obvious bug"
|
||||
echo " 3. Dispatching the code reviewer via the requesting-code-review skill"
|
||||
echo " 4. Verifying the reviewer flags the planted bug as Critical/Important"
|
||||
echo ""
|
||||
|
||||
TEST_PROJECT=$(create_test_project)
|
||||
echo "Test project: $TEST_PROJECT"
|
||||
trap "cleanup_test_project $TEST_PROJECT" EXIT
|
||||
|
||||
cd "$TEST_PROJECT"
|
||||
|
||||
# Baseline: a small "safe" implementation
|
||||
mkdir -p src
|
||||
cat > src/db.js <<'EOF'
|
||||
import { Database } from "./database-driver.js";
|
||||
|
||||
const db = new Database();
|
||||
|
||||
export async function findUserByEmail(email) {
|
||||
if (typeof email !== "string" || !email) {
|
||||
throw new Error("email required");
|
||||
}
|
||||
return db.query(
|
||||
"SELECT id, email, created_at FROM users WHERE email = ?",
|
||||
[email],
|
||||
);
|
||||
}
|
||||
EOF
|
||||
|
||||
cat > package.json <<'EOF'
|
||||
{ "name": "test-codereview", "version": "1.0.0", "type": "module" }
|
||||
EOF
|
||||
|
||||
git init --quiet
|
||||
git config user.email "test@test.com"
|
||||
git config user.name "Test User"
|
||||
git add .
|
||||
git commit -m "Initial: parameterized findUserByEmail" --quiet
|
||||
BASE_SHA=$(git rev-parse HEAD)
|
||||
|
||||
# Second commit: plant two real bugs
|
||||
# 1. SQL injection — switch from parameterized to string concatenation
|
||||
# 2. Logs the user's password hash on every successful login
|
||||
cat > src/db.js <<'EOF'
|
||||
import { Database } from "./database-driver.js";
|
||||
|
||||
const db = new Database();
|
||||
|
||||
export async function findUserByEmail(email) {
|
||||
return db.query(
|
||||
"SELECT id, email, password_hash, created_at FROM users WHERE email = '" + email + "'",
|
||||
);
|
||||
}
|
||||
|
||||
export async function login(email, password) {
|
||||
const user = await findUserByEmail(email);
|
||||
if (user && user.password_hash === hash(password)) {
|
||||
console.log("login success", { email, password_hash: user.password_hash });
|
||||
return user;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function hash(s) { return s; }
|
||||
EOF
|
||||
|
||||
git add .
|
||||
git commit -m "Refactor user lookup, add login" --quiet
|
||||
HEAD_SHA=$(git rev-parse HEAD)
|
||||
|
||||
echo ""
|
||||
echo "Planted bugs in $BASE_SHA..$HEAD_SHA:"
|
||||
echo " - SQL injection (string concat instead of parameterized query)"
|
||||
echo " - Password hash logged in plaintext on every successful login"
|
||||
echo " - hash() is the identity function (passwords stored & compared in plaintext)"
|
||||
echo ""
|
||||
|
||||
OUTPUT_FILE="$TEST_PROJECT/claude-output.txt"
|
||||
|
||||
PROMPT="I just finished a refactor. The change is between commits $BASE_SHA and $HEAD_SHA on the current branch.
|
||||
|
||||
Use the superpowers:requesting-code-review skill to review these changes before I merge. Follow the skill exactly: dispatch the code reviewer subagent with the template, give the subagent the SHA range, and report back what it found.
|
||||
|
||||
Print the reviewer's full output."
|
||||
|
||||
# Run claude from inside the test project so its session JSONL lands in a
|
||||
# project-specific directory under ~/.claude/projects/, isolated from any
|
||||
# other concurrent claude sessions.
|
||||
echo "Running Claude (plugin-dir: $PLUGIN_DIR, cwd: $TEST_PROJECT)..."
|
||||
echo "================================================================================"
|
||||
cd "$TEST_PROJECT" && timeout 600 claude -p "$PROMPT" \
|
||||
--plugin-dir "$PLUGIN_DIR" \
|
||||
--permission-mode bypassPermissions 2>&1 | tee "$OUTPUT_FILE" || {
|
||||
echo ""
|
||||
echo "================================================================================"
|
||||
echo "EXECUTION FAILED (exit code: $?)"
|
||||
exit 1
|
||||
}
|
||||
echo "================================================================================"
|
||||
|
||||
echo ""
|
||||
echo "Analyzing reviewer output..."
|
||||
echo ""
|
||||
|
||||
# Find the session transcript. Because we ran claude from $TEST_PROJECT (a
|
||||
# unique tmp dir), its sessions live in their own ~/.claude/projects/ folder.
|
||||
# Resolve the real path (macOS mktemp returns /var/... but claude normalizes
|
||||
# it to /private/var/...) and replicate claude's normalization (every
|
||||
# non-alphanumeric char becomes `-`).
|
||||
TEST_PROJECT_REAL=$(cd "$TEST_PROJECT" && pwd -P)
|
||||
SESSION_DIR="$HOME/.claude/projects/$(echo "$TEST_PROJECT_REAL" | sed 's|[^a-zA-Z0-9]|-|g')"
|
||||
# `|| true` prevents pipefail killing the script if ls gets SIGPIPE'd by head.
|
||||
SESSION_FILE=$(ls -t "$SESSION_DIR"/*.jsonl 2>/dev/null | head -1 || true)
|
||||
|
||||
FAILED=0
|
||||
|
||||
echo "=== Verification Tests ==="
|
||||
echo ""
|
||||
|
||||
# Test 1: Skill was actually invoked, and a subagent was actually dispatched
|
||||
echo "Test 1: requesting-code-review skill invoked + reviewer subagent dispatched..."
|
||||
if [ -z "$SESSION_FILE" ] || [ ! -f "$SESSION_FILE" ]; then
|
||||
echo " [FAIL] Could not locate session transcript in $SESSION_DIR"
|
||||
FAILED=$((FAILED + 1))
|
||||
elif ! grep -q '"skill":"superpowers:requesting-code-review"' "$SESSION_FILE"; then
|
||||
echo " [FAIL] requesting-code-review skill was not invoked"
|
||||
echo " Session: $SESSION_FILE"
|
||||
FAILED=$((FAILED + 1))
|
||||
elif ! grep -q '"name":"Agent"' "$SESSION_FILE"; then
|
||||
echo " [FAIL] Skill ran but no subagent was dispatched"
|
||||
FAILED=$((FAILED + 1))
|
||||
else
|
||||
echo " [PASS] Skill invoked and subagent dispatched"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Test 2: Reviewer caught the SQL injection
|
||||
echo "Test 2: SQL injection flagged..."
|
||||
if grep -qiE "sql injection|injection|string concat|parameterize|prepared statement|sanitiz" "$OUTPUT_FILE"; then
|
||||
echo " [PASS] Reviewer flagged the SQL injection vector"
|
||||
else
|
||||
echo " [FAIL] Reviewer missed the SQL injection — most obvious planted bug"
|
||||
FAILED=$((FAILED + 1))
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Test 3: Reviewer caught the credential / password issue (either logging or no real hashing)
|
||||
echo "Test 3: Credential handling issue flagged..."
|
||||
if grep -qiE "password|credential|secret|plaintext|log.*hash|hash.*log|sensitive" "$OUTPUT_FILE"; then
|
||||
echo " [PASS] Reviewer flagged a credential / password handling issue"
|
||||
else
|
||||
echo " [FAIL] Reviewer missed the password/credential issues"
|
||||
FAILED=$((FAILED + 1))
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Test 4: Reviewer marked at least one issue as Critical or Important (not just Minor)
|
||||
echo "Test 4: Severity classification..."
|
||||
if grep -qiE "critical|important|severe|high.*risk|security" "$OUTPUT_FILE"; then
|
||||
echo " [PASS] Reviewer classified findings at Critical/Important severity"
|
||||
else
|
||||
echo " [FAIL] Reviewer did not classify findings as Critical or Important"
|
||||
FAILED=$((FAILED + 1))
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Test 5: Reviewer did NOT approve the diff for merge
|
||||
echo "Test 5: Reviewer verdict..."
|
||||
# A correct reviewer says No or "With fixes". A broken/sycophantic reviewer says Yes/Ready.
|
||||
if grep -qiE "ready to merge.*yes|approved.*for merge|^\s*yes\s*$|safe to merge" "$OUTPUT_FILE" \
|
||||
&& ! grep -qiE "ready to merge.*no|with fixes|do not merge|not ready|block.*merge" "$OUTPUT_FILE"; then
|
||||
echo " [FAIL] Reviewer approved a diff with planted Critical bugs"
|
||||
FAILED=$((FAILED + 1))
|
||||
else
|
||||
echo " [PASS] Reviewer did not approve the diff"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "========================================"
|
||||
echo " Test Summary"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
if [ $FAILED -eq 0 ]; then
|
||||
echo "STATUS: PASSED"
|
||||
echo "The code reviewer correctly:"
|
||||
echo " ✓ Was dispatched via the requesting-code-review skill"
|
||||
echo " ✓ Flagged the SQL injection"
|
||||
echo " ✓ Flagged the credential handling issues"
|
||||
echo " ✓ Classified findings at Critical/Important severity"
|
||||
echo " ✓ Did not approve the diff for merge"
|
||||
exit 0
|
||||
else
|
||||
echo "STATUS: FAILED"
|
||||
echo "Failed $FAILED verification tests"
|
||||
echo ""
|
||||
echo "Output saved to: $OUTPUT_FILE"
|
||||
exit 1
|
||||
fi
|
||||
@@ -135,8 +135,7 @@ EOF
|
||||
|
||||
# Note: We use a longer timeout since this is integration testing
|
||||
# Use --allowed-tools to enable tool usage in headless mode
|
||||
# IMPORTANT: Run from superpowers directory so local dev skills are available
|
||||
PROMPT="Change to directory $TEST_PROJECT and then execute the implementation plan at docs/superpowers/plans/implementation-plan.md using the subagent-driven-development skill.
|
||||
PROMPT="Execute the implementation plan at docs/superpowers/plans/implementation-plan.md using the subagent-driven-development skill.
|
||||
|
||||
IMPORTANT: Follow the skill exactly. I will be verifying that you:
|
||||
1. Read the plan once at the beginning
|
||||
@@ -147,9 +146,14 @@ IMPORTANT: Follow the skill exactly. I will be verifying that you:
|
||||
|
||||
Begin now. Execute the plan."
|
||||
|
||||
echo "Running Claude (output will be shown below and saved to $OUTPUT_FILE)..."
|
||||
PLUGIN_DIR=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
|
||||
# Run claude from inside the test project so its session JSONL lands in a
|
||||
# project-specific directory under ~/.claude/projects/, isolated from any
|
||||
# other concurrent claude sessions.
|
||||
echo "Running Claude (plugin-dir: $PLUGIN_DIR, cwd: $TEST_PROJECT)..."
|
||||
echo "================================================================================"
|
||||
cd "$SCRIPT_DIR/../.." && timeout 1800 claude -p "$PROMPT" --allowed-tools=all --add-dir "$TEST_PROJECT" --permission-mode bypassPermissions 2>&1 | tee "$OUTPUT_FILE" || {
|
||||
cd "$TEST_PROJECT" && timeout 1800 claude -p "$PROMPT" --plugin-dir "$PLUGIN_DIR" --allowed-tools=all --permission-mode bypassPermissions 2>&1 | tee "$OUTPUT_FILE" || {
|
||||
echo ""
|
||||
echo "================================================================================"
|
||||
echo "EXECUTION FAILED (exit code: $?)"
|
||||
@@ -161,13 +165,17 @@ echo ""
|
||||
echo "Execution complete. Analyzing results..."
|
||||
echo ""
|
||||
|
||||
# Find the session transcript
|
||||
# Session files are in ~/.claude/projects/-<working-dir>/<session-id>.jsonl
|
||||
WORKING_DIR_ESCAPED=$(echo "$SCRIPT_DIR/../.." | sed 's/\//-/g' | sed 's/^-//')
|
||||
SESSION_DIR="$HOME/.claude/projects/$WORKING_DIR_ESCAPED"
|
||||
|
||||
# Find the most recent session file (created during this test run)
|
||||
SESSION_FILE=$(find "$SESSION_DIR" -name "*.jsonl" -type f -mmin -60 2>/dev/null | sort -r | head -1)
|
||||
# Find the session transcript. Because we ran claude from $TEST_PROJECT (a
|
||||
# unique tmp dir), its sessions live in their own ~/.claude/projects/ folder
|
||||
# and we can pick the most-recent one without racing other concurrent sessions.
|
||||
# Resolve the real path because macOS mktemp returns /var/... but claude
|
||||
# normalizes it to /private/var/... when naming the project dir.
|
||||
TEST_PROJECT_REAL=$(cd "$TEST_PROJECT" && pwd -P)
|
||||
# Claude normalizes the cwd to a directory name by replacing every non-alphanumeric
|
||||
# character with `-` (so `_`, `.`, `/` all become `-`).
|
||||
SESSION_DIR="$HOME/.claude/projects/$(echo "$TEST_PROJECT_REAL" | sed 's|[^a-zA-Z0-9]|-|g')"
|
||||
# `|| true` prevents pipefail killing the script if ls gets SIGPIPE'd by head.
|
||||
SESSION_FILE=$(ls -t "$SESSION_DIR"/*.jsonl 2>/dev/null | head -1 || true)
|
||||
|
||||
if [ -z "$SESSION_FILE" ]; then
|
||||
echo "ERROR: Could not find session transcript file"
|
||||
@@ -194,9 +202,9 @@ else
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Test 2: Subagents were used (Task tool)
|
||||
# Test 2: Subagents were used (Agent / Task tool — name varies by harness version)
|
||||
echo "Test 2: Subagents dispatched..."
|
||||
task_count=$(grep -c '"name":"Task"' "$SESSION_FILE" || echo "0")
|
||||
task_count=$(grep -cE '"name":"(Agent|Task)"' "$SESSION_FILE" || echo "0")
|
||||
if [ "$task_count" -ge 2 ]; then
|
||||
echo " [PASS] $task_count subagents dispatched"
|
||||
else
|
||||
|
||||
615
tests/codex-plugin-sync/test-sync-to-codex-plugin.sh
Executable file
615
tests/codex-plugin-sync/test-sync-to-codex-plugin.sh
Executable file
@@ -0,0 +1,615 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
SYNC_SCRIPT_SOURCE="$REPO_ROOT/scripts/sync-to-codex-plugin.sh"
|
||||
BASH_UNDER_TEST="/bin/bash"
|
||||
PACKAGE_VERSION="1.2.3"
|
||||
MANIFEST_VERSION="9.8.7"
|
||||
|
||||
FAILURES=0
|
||||
TEST_ROOT=""
|
||||
|
||||
pass() {
|
||||
echo " [PASS] $1"
|
||||
}
|
||||
|
||||
fail() {
|
||||
echo " [FAIL] $1"
|
||||
FAILURES=$((FAILURES + 1))
|
||||
}
|
||||
|
||||
assert_equals() {
|
||||
local actual="$1"
|
||||
local expected="$2"
|
||||
local description="$3"
|
||||
|
||||
if [[ "$actual" == "$expected" ]]; then
|
||||
pass "$description"
|
||||
else
|
||||
fail "$description"
|
||||
echo " expected: $expected"
|
||||
echo " actual: $actual"
|
||||
fi
|
||||
}
|
||||
|
||||
assert_contains() {
|
||||
local haystack="$1"
|
||||
local needle="$2"
|
||||
local description="$3"
|
||||
|
||||
if printf '%s' "$haystack" | grep -Fq -- "$needle"; then
|
||||
pass "$description"
|
||||
else
|
||||
fail "$description"
|
||||
echo " expected to find: $needle"
|
||||
fi
|
||||
}
|
||||
|
||||
assert_not_contains() {
|
||||
local haystack="$1"
|
||||
local needle="$2"
|
||||
local description="$3"
|
||||
|
||||
if printf '%s' "$haystack" | grep -Fq -- "$needle"; then
|
||||
fail "$description"
|
||||
echo " did not expect to find: $needle"
|
||||
else
|
||||
pass "$description"
|
||||
fi
|
||||
}
|
||||
|
||||
assert_matches() {
|
||||
local haystack="$1"
|
||||
local pattern="$2"
|
||||
local description="$3"
|
||||
|
||||
if printf '%s' "$haystack" | grep -Eq -- "$pattern"; then
|
||||
pass "$description"
|
||||
else
|
||||
fail "$description"
|
||||
echo " expected to match: $pattern"
|
||||
fi
|
||||
}
|
||||
|
||||
assert_not_matches() {
|
||||
local haystack="$1"
|
||||
local pattern="$2"
|
||||
local description="$3"
|
||||
|
||||
if printf '%s' "$haystack" | grep -Eq -- "$pattern"; then
|
||||
fail "$description"
|
||||
echo " did not expect to match: $pattern"
|
||||
else
|
||||
pass "$description"
|
||||
fi
|
||||
}
|
||||
|
||||
assert_path_absent() {
|
||||
local path="$1"
|
||||
local description="$2"
|
||||
|
||||
if [[ ! -e "$path" ]]; then
|
||||
pass "$description"
|
||||
else
|
||||
fail "$description"
|
||||
echo " did not expect path to exist: $path"
|
||||
fi
|
||||
}
|
||||
|
||||
assert_branch_absent() {
|
||||
local repo="$1"
|
||||
local pattern="$2"
|
||||
local description="$3"
|
||||
local branches
|
||||
|
||||
branches="$(git -C "$repo" branch --list "$pattern")"
|
||||
|
||||
if [[ -z "$branches" ]]; then
|
||||
pass "$description"
|
||||
else
|
||||
fail "$description"
|
||||
echo " did not expect matching branches:"
|
||||
echo "$branches" | sed 's/^/ /'
|
||||
fi
|
||||
}
|
||||
|
||||
assert_current_branch() {
|
||||
local repo="$1"
|
||||
local expected="$2"
|
||||
local description="$3"
|
||||
local actual
|
||||
|
||||
actual="$(git -C "$repo" branch --show-current)"
|
||||
assert_equals "$actual" "$expected" "$description"
|
||||
}
|
||||
|
||||
assert_file_equals() {
|
||||
local path="$1"
|
||||
local expected="$2"
|
||||
local description="$3"
|
||||
local actual
|
||||
|
||||
actual="$(cat "$path")"
|
||||
assert_equals "$actual" "$expected" "$description"
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
if [[ -n "$TEST_ROOT" && -d "$TEST_ROOT" ]]; then
|
||||
rm -rf "$TEST_ROOT"
|
||||
fi
|
||||
}
|
||||
|
||||
configure_git_identity() {
|
||||
local repo="$1"
|
||||
|
||||
git -C "$repo" config user.name "Test Bot"
|
||||
git -C "$repo" config user.email "test@example.com"
|
||||
}
|
||||
|
||||
init_repo() {
|
||||
local repo="$1"
|
||||
|
||||
git init -q -b main "$repo"
|
||||
configure_git_identity "$repo"
|
||||
}
|
||||
|
||||
commit_fixture() {
|
||||
local repo="$1"
|
||||
local message="$2"
|
||||
|
||||
git -C "$repo" commit -q -m "$message"
|
||||
}
|
||||
|
||||
checkout_fixture_branch() {
|
||||
local repo="$1"
|
||||
local branch="$2"
|
||||
|
||||
git -C "$repo" checkout -q -b "$branch"
|
||||
}
|
||||
|
||||
write_upstream_fixture() {
|
||||
local repo="$1"
|
||||
local with_pure_ignored="${2:-1}"
|
||||
|
||||
mkdir -p \
|
||||
"$repo/.codex-plugin" \
|
||||
"$repo/.private-journal" \
|
||||
"$repo/assets" \
|
||||
"$repo/scripts" \
|
||||
"$repo/skills/example"
|
||||
|
||||
if [[ "$with_pure_ignored" == "1" ]]; then
|
||||
mkdir -p "$repo/ignored-cache/tmp"
|
||||
fi
|
||||
|
||||
cp "$SYNC_SCRIPT_SOURCE" "$repo/scripts/sync-to-codex-plugin.sh"
|
||||
|
||||
cat > "$repo/package.json" <<EOF
|
||||
{
|
||||
"name": "fixture-upstream",
|
||||
"version": "$PACKAGE_VERSION"
|
||||
}
|
||||
EOF
|
||||
|
||||
cat > "$repo/.gitignore" <<'EOF'
|
||||
.private-journal/
|
||||
EOF
|
||||
|
||||
if [[ "$with_pure_ignored" == "1" ]]; then
|
||||
cat >> "$repo/.gitignore" <<'EOF'
|
||||
ignored-cache/
|
||||
EOF
|
||||
fi
|
||||
|
||||
cat > "$repo/.codex-plugin/plugin.json" <<EOF
|
||||
{
|
||||
"name": "superpowers",
|
||||
"version": "$MANIFEST_VERSION"
|
||||
}
|
||||
EOF
|
||||
|
||||
cat > "$repo/assets/superpowers-small.svg" <<'EOF'
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1 1"></svg>
|
||||
EOF
|
||||
|
||||
printf 'png fixture\n' > "$repo/assets/app-icon.png"
|
||||
|
||||
cat > "$repo/skills/example/SKILL.md" <<'EOF'
|
||||
# Example Skill
|
||||
|
||||
Fixture content.
|
||||
EOF
|
||||
|
||||
printf 'tracked keep\n' > "$repo/.private-journal/keep.txt"
|
||||
printf 'ignored leak\n' > "$repo/.private-journal/leak.txt"
|
||||
if [[ "$with_pure_ignored" == "1" ]]; then
|
||||
printf 'ignored cache state\n' > "$repo/ignored-cache/tmp/state.json"
|
||||
fi
|
||||
|
||||
git -C "$repo" add \
|
||||
.codex-plugin/plugin.json \
|
||||
.gitignore \
|
||||
assets/app-icon.png \
|
||||
assets/superpowers-small.svg \
|
||||
package.json \
|
||||
scripts/sync-to-codex-plugin.sh \
|
||||
skills/example/SKILL.md
|
||||
git -C "$repo" add -f .private-journal/keep.txt
|
||||
|
||||
commit_fixture "$repo" "Initial upstream fixture"
|
||||
}
|
||||
|
||||
write_destination_fixture() {
|
||||
local repo="$1"
|
||||
|
||||
mkdir -p "$repo/plugins/superpowers/skills/example"
|
||||
printf 'fixture keep\n' > "$repo/plugins/superpowers/.fixture-keep"
|
||||
cat > "$repo/plugins/superpowers/skills/example/SKILL.md" <<'EOF'
|
||||
# Example Skill
|
||||
|
||||
Fixture content.
|
||||
EOF
|
||||
git -C "$repo" add plugins/superpowers/.fixture-keep
|
||||
git -C "$repo" add plugins/superpowers/skills/example/SKILL.md
|
||||
|
||||
commit_fixture "$repo" "Initial destination fixture"
|
||||
}
|
||||
|
||||
add_openai_agent_metadata_fixture() {
|
||||
local repo="$1"
|
||||
|
||||
mkdir -p "$repo/plugins/superpowers/skills/example/agents"
|
||||
|
||||
cat > "$repo/plugins/superpowers/skills/example/agents/openai.yaml" <<'EOF'
|
||||
interface:
|
||||
display_name: "Example"
|
||||
short_description: "Destination-owned OpenAI metadata"
|
||||
EOF
|
||||
|
||||
git -C "$repo" add plugins/superpowers/skills/example/agents/openai.yaml
|
||||
|
||||
commit_fixture "$repo" "Add OpenAI agent metadata fixture"
|
||||
}
|
||||
|
||||
dirty_tracked_destination_skill() {
|
||||
local repo="$1"
|
||||
|
||||
cat > "$repo/plugins/superpowers/skills/example/SKILL.md" <<'EOF'
|
||||
# Example Skill
|
||||
|
||||
Locally modified fixture content.
|
||||
EOF
|
||||
}
|
||||
|
||||
write_synced_destination_fixture() {
|
||||
local repo="$1"
|
||||
|
||||
mkdir -p \
|
||||
"$repo/plugins/superpowers/.codex-plugin" \
|
||||
"$repo/plugins/superpowers/.private-journal" \
|
||||
"$repo/plugins/superpowers/assets" \
|
||||
"$repo/plugins/superpowers/skills/example/agents" \
|
||||
"$repo/plugins/superpowers/skills/example"
|
||||
|
||||
cat > "$repo/plugins/superpowers/.codex-plugin/plugin.json" <<EOF
|
||||
{
|
||||
"name": "superpowers",
|
||||
"version": "$MANIFEST_VERSION"
|
||||
}
|
||||
EOF
|
||||
|
||||
cat > "$repo/plugins/superpowers/assets/superpowers-small.svg" <<'EOF'
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1 1"></svg>
|
||||
EOF
|
||||
|
||||
printf 'png fixture\n' > "$repo/plugins/superpowers/assets/app-icon.png"
|
||||
|
||||
cat > "$repo/plugins/superpowers/skills/example/SKILL.md" <<'EOF'
|
||||
# Example Skill
|
||||
|
||||
Fixture content.
|
||||
EOF
|
||||
|
||||
cat > "$repo/plugins/superpowers/skills/example/agents/openai.yaml" <<'EOF'
|
||||
interface:
|
||||
display_name: "Example"
|
||||
short_description: "Destination-owned OpenAI metadata"
|
||||
EOF
|
||||
|
||||
printf 'tracked keep\n' > "$repo/plugins/superpowers/.private-journal/keep.txt"
|
||||
|
||||
git -C "$repo" add \
|
||||
plugins/superpowers/.codex-plugin/plugin.json \
|
||||
plugins/superpowers/assets/app-icon.png \
|
||||
plugins/superpowers/assets/superpowers-small.svg \
|
||||
plugins/superpowers/skills/example/agents/openai.yaml \
|
||||
plugins/superpowers/skills/example/SKILL.md \
|
||||
plugins/superpowers/.private-journal/keep.txt
|
||||
|
||||
commit_fixture "$repo" "Initial synced destination fixture"
|
||||
}
|
||||
|
||||
write_stale_ignored_destination_fixture() {
|
||||
local repo="$1"
|
||||
|
||||
mkdir -p "$repo/plugins/superpowers/.private-journal"
|
||||
printf 'fixture keep\n' > "$repo/plugins/superpowers/.fixture-keep"
|
||||
printf 'stale ignored leak\n' > "$repo/plugins/superpowers/.private-journal/leak.txt"
|
||||
git -C "$repo" add plugins/superpowers/.fixture-keep
|
||||
|
||||
commit_fixture "$repo" "Initial stale ignored destination fixture"
|
||||
}
|
||||
|
||||
write_fake_gh() {
|
||||
local bin_dir="$1"
|
||||
|
||||
mkdir -p "$bin_dir"
|
||||
|
||||
cat > "$bin_dir/gh" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ "${1:-}" == "auth" && "${2:-}" == "status" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "unexpected gh invocation: $*" >&2
|
||||
exit 1
|
||||
EOF
|
||||
|
||||
chmod +x "$bin_dir/gh"
|
||||
}
|
||||
|
||||
run_preview() {
|
||||
local upstream="$1"
|
||||
local dest="$2"
|
||||
local fake_bin="$3"
|
||||
|
||||
PATH="$fake_bin:$PATH" "$BASH_UNDER_TEST" "$upstream/scripts/sync-to-codex-plugin.sh" -n --local "$dest" 2>&1
|
||||
}
|
||||
|
||||
run_bootstrap_preview() {
|
||||
local upstream="$1"
|
||||
local dest="$2"
|
||||
local fake_bin="$3"
|
||||
|
||||
PATH="$fake_bin:$PATH" "$BASH_UNDER_TEST" "$upstream/scripts/sync-to-codex-plugin.sh" -n --bootstrap --local "$dest" 2>&1
|
||||
}
|
||||
|
||||
run_preview_without_manifest() {
|
||||
local upstream="$1"
|
||||
local dest="$2"
|
||||
local fake_bin="$3"
|
||||
|
||||
rm -f "$upstream/.codex-plugin/plugin.json"
|
||||
PATH="$fake_bin:$PATH" "$BASH_UNDER_TEST" "$upstream/scripts/sync-to-codex-plugin.sh" -n --local "$dest" 2>&1
|
||||
}
|
||||
|
||||
run_preview_with_stale_ignored_destination() {
|
||||
local upstream="$1"
|
||||
local dest="$2"
|
||||
local fake_bin="$3"
|
||||
|
||||
PATH="$fake_bin:$PATH" "$BASH_UNDER_TEST" "$upstream/scripts/sync-to-codex-plugin.sh" -n --local "$dest" 2>&1
|
||||
}
|
||||
|
||||
run_apply() {
|
||||
local upstream="$1"
|
||||
local dest="$2"
|
||||
local fake_bin="$3"
|
||||
|
||||
PATH="$fake_bin:$PATH" "$BASH_UNDER_TEST" "$upstream/scripts/sync-to-codex-plugin.sh" -y --local "$dest" 2>&1
|
||||
}
|
||||
|
||||
run_help() {
|
||||
local upstream="$1"
|
||||
local fake_bin="$2"
|
||||
|
||||
PATH="$fake_bin:$PATH" "$BASH_UNDER_TEST" "$upstream/scripts/sync-to-codex-plugin.sh" --help 2>&1
|
||||
}
|
||||
|
||||
write_bootstrap_destination_fixture() {
|
||||
local repo="$1"
|
||||
|
||||
printf 'bootstrap fixture\n' > "$repo/README.md"
|
||||
git -C "$repo" add README.md
|
||||
|
||||
commit_fixture "$repo" "Initial bootstrap destination fixture"
|
||||
}
|
||||
|
||||
main() {
|
||||
local upstream
|
||||
local mixed_only_upstream
|
||||
local dest
|
||||
local dest_branch
|
||||
local mixed_only_dest
|
||||
local stale_dest
|
||||
local dirty_apply_dest
|
||||
local dirty_apply_dest_branch
|
||||
local noop_apply_dest
|
||||
local noop_apply_dest_branch
|
||||
local fake_bin
|
||||
local bootstrap_dest
|
||||
local bootstrap_dest_branch
|
||||
local preview_status
|
||||
local preview_output
|
||||
local preview_section
|
||||
local bootstrap_status
|
||||
local bootstrap_output
|
||||
local missing_manifest_status
|
||||
local missing_manifest_output
|
||||
local mixed_only_status
|
||||
local mixed_only_output
|
||||
local stale_preview_status
|
||||
local stale_preview_output
|
||||
local stale_preview_section
|
||||
local dirty_apply_status
|
||||
local dirty_apply_output
|
||||
local noop_apply_status
|
||||
local noop_apply_output
|
||||
local help_output
|
||||
local script_source
|
||||
local dirty_skill_path
|
||||
local noop_openai_metadata_path
|
||||
|
||||
echo "=== Test: sync-to-codex-plugin dry-run regression ==="
|
||||
|
||||
TEST_ROOT="$(mktemp -d)"
|
||||
trap cleanup EXIT
|
||||
|
||||
upstream="$TEST_ROOT/upstream"
|
||||
mixed_only_upstream="$TEST_ROOT/mixed-only-upstream"
|
||||
dest="$TEST_ROOT/destination"
|
||||
mixed_only_dest="$TEST_ROOT/mixed-only-destination"
|
||||
stale_dest="$TEST_ROOT/stale-destination"
|
||||
dirty_apply_dest="$TEST_ROOT/dirty-apply-destination"
|
||||
dirty_apply_dest_branch="fixture/dirty-apply-target"
|
||||
noop_apply_dest="$TEST_ROOT/noop-apply-destination"
|
||||
noop_apply_dest_branch="fixture/noop-apply-target"
|
||||
bootstrap_dest="$TEST_ROOT/bootstrap-destination"
|
||||
dest_branch="fixture/preview-target"
|
||||
bootstrap_dest_branch="fixture/bootstrap-preview-target"
|
||||
fake_bin="$TEST_ROOT/bin"
|
||||
|
||||
init_repo "$upstream"
|
||||
write_upstream_fixture "$upstream"
|
||||
|
||||
init_repo "$mixed_only_upstream"
|
||||
write_upstream_fixture "$mixed_only_upstream" 0
|
||||
|
||||
init_repo "$dest"
|
||||
write_destination_fixture "$dest"
|
||||
add_openai_agent_metadata_fixture "$dest"
|
||||
checkout_fixture_branch "$dest" "$dest_branch"
|
||||
dirty_tracked_destination_skill "$dest"
|
||||
|
||||
init_repo "$mixed_only_dest"
|
||||
write_destination_fixture "$mixed_only_dest"
|
||||
|
||||
init_repo "$stale_dest"
|
||||
write_stale_ignored_destination_fixture "$stale_dest"
|
||||
|
||||
init_repo "$dirty_apply_dest"
|
||||
write_synced_destination_fixture "$dirty_apply_dest"
|
||||
checkout_fixture_branch "$dirty_apply_dest" "$dirty_apply_dest_branch"
|
||||
dirty_tracked_destination_skill "$dirty_apply_dest"
|
||||
|
||||
init_repo "$noop_apply_dest"
|
||||
write_synced_destination_fixture "$noop_apply_dest"
|
||||
checkout_fixture_branch "$noop_apply_dest" "$noop_apply_dest_branch"
|
||||
|
||||
init_repo "$bootstrap_dest"
|
||||
write_bootstrap_destination_fixture "$bootstrap_dest"
|
||||
checkout_fixture_branch "$bootstrap_dest" "$bootstrap_dest_branch"
|
||||
|
||||
write_fake_gh "$fake_bin"
|
||||
|
||||
# This regression test is about dry-run content, so capture the preview
|
||||
# output even if the current script exits nonzero in --local mode.
|
||||
set +e
|
||||
preview_output="$(run_preview "$upstream" "$dest" "$fake_bin")"
|
||||
preview_status=$?
|
||||
bootstrap_output="$(run_bootstrap_preview "$upstream" "$bootstrap_dest" "$fake_bin")"
|
||||
bootstrap_status=$?
|
||||
mixed_only_output="$(run_preview "$mixed_only_upstream" "$mixed_only_dest" "$fake_bin")"
|
||||
mixed_only_status=$?
|
||||
stale_preview_output="$(run_preview_with_stale_ignored_destination "$upstream" "$stale_dest" "$fake_bin")"
|
||||
stale_preview_status=$?
|
||||
dirty_apply_output="$(run_apply "$upstream" "$dirty_apply_dest" "$fake_bin")"
|
||||
dirty_apply_status=$?
|
||||
noop_apply_output="$(run_apply "$upstream" "$noop_apply_dest" "$fake_bin")"
|
||||
noop_apply_status=$?
|
||||
missing_manifest_output="$(run_preview_without_manifest "$upstream" "$dest" "$fake_bin")"
|
||||
missing_manifest_status=$?
|
||||
set -e
|
||||
help_output="$(run_help "$upstream" "$fake_bin")"
|
||||
script_source="$(cat "$upstream/scripts/sync-to-codex-plugin.sh")"
|
||||
preview_section="$(printf '%s\n' "$preview_output" | sed -n '/^=== Preview (rsync --dry-run) ===$/,/^=== End preview ===$/p')"
|
||||
stale_preview_section="$(printf '%s\n' "$stale_preview_output" | sed -n '/^=== Preview (rsync --dry-run) ===$/,/^=== End preview ===$/p')"
|
||||
dirty_skill_path="$dirty_apply_dest/plugins/superpowers/skills/example/SKILL.md"
|
||||
noop_openai_metadata_path="$noop_apply_dest/plugins/superpowers/skills/example/agents/openai.yaml"
|
||||
|
||||
echo ""
|
||||
echo "Preview assertions..."
|
||||
assert_equals "$preview_status" "0" "Preview exits successfully"
|
||||
assert_contains "$preview_output" "Version: $MANIFEST_VERSION" "Preview uses manifest version"
|
||||
assert_not_contains "$preview_output" "Version: $PACKAGE_VERSION" "Preview does not use package.json version"
|
||||
assert_contains "$preview_section" ".codex-plugin/plugin.json" "Preview includes manifest path"
|
||||
assert_contains "$preview_section" "assets/superpowers-small.svg" "Preview includes SVG asset"
|
||||
assert_contains "$preview_section" "assets/app-icon.png" "Preview includes PNG asset"
|
||||
assert_contains "$preview_section" ".private-journal/keep.txt" "Preview includes tracked ignored file"
|
||||
assert_not_contains "$preview_section" ".private-journal/leak.txt" "Preview excludes ignored untracked file"
|
||||
assert_not_contains "$preview_section" "ignored-cache/" "Preview excludes pure ignored directories"
|
||||
assert_not_contains "$preview_output" "Overlay file (.codex-plugin/plugin.json) will be regenerated" "Preview omits overlay regeneration note"
|
||||
assert_not_contains "$preview_output" "Assets (superpowers-small.svg, app-icon.png) will be seeded from" "Preview omits assets seeding note"
|
||||
assert_contains "$preview_section" "skills/example/SKILL.md" "Preview reflects dirty tracked destination file"
|
||||
assert_not_matches "$preview_section" "\\*deleting +skills/example/agents/openai\\.yaml" "Preview preserves destination-owned OpenAI agent metadata"
|
||||
assert_current_branch "$dest" "$dest_branch" "Preview leaves destination checkout on its original branch"
|
||||
assert_branch_absent "$dest" "sync/superpowers-*" "Preview does not create sync branch in destination checkout"
|
||||
|
||||
echo ""
|
||||
echo "Mixed-directory assertions..."
|
||||
assert_equals "$mixed_only_status" "0" "Mixed ignored directory preview exits successfully under /bin/bash"
|
||||
assert_contains "$mixed_only_output" ".private-journal/keep.txt" "Mixed ignored directory preview still includes tracked ignored file"
|
||||
assert_not_contains "$mixed_only_output" "ignored-cache/" "Mixed ignored directory preview has no pure ignored directory fixture"
|
||||
|
||||
echo ""
|
||||
echo "Convergence assertions..."
|
||||
assert_equals "$stale_preview_status" "0" "Stale ignored destination preview exits successfully"
|
||||
assert_matches "$stale_preview_section" "\\*deleting +\\.private-journal/leak\\.txt" "Preview deletes stale ignored destination file"
|
||||
|
||||
echo ""
|
||||
echo "Bootstrap assertions..."
|
||||
assert_equals "$bootstrap_status" "0" "Bootstrap preview exits successfully"
|
||||
assert_contains "$bootstrap_output" "Mode: BOOTSTRAP (creating plugins/superpowers/ when absent)" "Bootstrap preview describes directory creation"
|
||||
assert_not_contains "$bootstrap_output" "Assets:" "Bootstrap preview omits external assets path"
|
||||
assert_contains "$bootstrap_output" "Dry run only. Nothing was changed or pushed." "Bootstrap preview remains dry-run only"
|
||||
assert_path_absent "$bootstrap_dest/plugins/superpowers" "Bootstrap preview does not create destination plugin directory"
|
||||
assert_current_branch "$bootstrap_dest" "$bootstrap_dest_branch" "Bootstrap preview leaves destination checkout on its original branch"
|
||||
assert_branch_absent "$bootstrap_dest" "bootstrap/superpowers-*" "Bootstrap preview does not create bootstrap branch in destination checkout"
|
||||
|
||||
echo ""
|
||||
echo "Apply assertions..."
|
||||
assert_equals "$dirty_apply_status" "1" "Dirty local apply exits with failure"
|
||||
assert_contains "$dirty_apply_output" "ERROR: local checkout has uncommitted changes under 'plugins/superpowers'" "Dirty local apply reports protected destination path"
|
||||
assert_current_branch "$dirty_apply_dest" "$dirty_apply_dest_branch" "Dirty local apply leaves destination checkout on its original branch"
|
||||
assert_branch_absent "$dirty_apply_dest" "sync/superpowers-*" "Dirty local apply does not create sync branch in destination checkout"
|
||||
assert_file_equals "$dirty_skill_path" "# Example Skill
|
||||
|
||||
Locally modified fixture content." "Dirty local apply preserves tracked working-tree file content"
|
||||
assert_equals "$noop_apply_status" "0" "Clean no-op local apply exits successfully"
|
||||
assert_contains "$noop_apply_output" "No changes — embedded plugin was already in sync with upstream" "Clean no-op local apply reports no changes"
|
||||
assert_current_branch "$noop_apply_dest" "$noop_apply_dest_branch" "Clean no-op local apply leaves destination checkout on its original branch"
|
||||
assert_branch_absent "$noop_apply_dest" "sync/superpowers-*" "Clean no-op local apply does not create sync branch in destination checkout"
|
||||
assert_file_equals "$noop_openai_metadata_path" "interface:
|
||||
display_name: \"Example\"
|
||||
short_description: \"Destination-owned OpenAI metadata\"" "Clean no-op local apply preserves OpenAI agent metadata"
|
||||
|
||||
echo ""
|
||||
echo "Missing manifest assertions..."
|
||||
assert_equals "$missing_manifest_status" "1" "Missing manifest exits with failure"
|
||||
assert_contains "$missing_manifest_output" "ERROR: committed Codex manifest missing at" "Missing manifest reports committed manifest path"
|
||||
|
||||
echo ""
|
||||
echo "Help assertions..."
|
||||
assert_not_contains "$help_output" "--assets-src" "Help omits --assets-src"
|
||||
|
||||
echo ""
|
||||
echo "Source assertions..."
|
||||
assert_not_contains "$script_source" "regenerated inline" "Source drops regenerated inline phrasing"
|
||||
assert_not_contains "$script_source" "Brand Assets directory" "Source drops Brand Assets directory phrasing"
|
||||
assert_not_contains "$script_source" "--assets-src" "Source drops --assets-src"
|
||||
|
||||
if [[ $FAILURES -ne 0 ]]; then
|
||||
echo ""
|
||||
echo "FAILED: $FAILURES assertion(s) failed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "PASS"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -44,6 +44,7 @@ while [[ $# -gt 0 ]]; do
|
||||
echo ""
|
||||
echo "Tests:"
|
||||
echo " test-plugin-loading.sh Verify plugin installation and structure"
|
||||
echo " test-bootstrap-caching.sh Verify bootstrap content caching"
|
||||
echo " test-tools.sh Test use_skill and find_skills tools (integration)"
|
||||
echo " test-priority.sh Test skill priority resolution (integration)"
|
||||
exit 0
|
||||
@@ -59,6 +60,7 @@ done
|
||||
# List of tests to run (no external dependencies)
|
||||
tests=(
|
||||
"test-plugin-loading.sh"
|
||||
"test-bootstrap-caching.sh"
|
||||
)
|
||||
|
||||
# Integration tests (require OpenCode)
|
||||
|
||||
124
tests/opencode/test-bootstrap-caching.mjs
Normal file
124
tests/opencode/test-bootstrap-caching.mjs
Normal file
@@ -0,0 +1,124 @@
|
||||
import fs from 'fs';
|
||||
import { pathToFileURL } from 'url';
|
||||
|
||||
const [, , pluginPath, scenario] = process.argv;
|
||||
|
||||
if (!pluginPath || !['present', 'missing'].includes(scenario)) {
|
||||
console.error('Usage: node test-bootstrap-caching.mjs PLUGIN_PATH present|missing');
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
let existsCount = 0;
|
||||
let readCount = 0;
|
||||
|
||||
const originalExistsSync = fs.existsSync;
|
||||
const originalReadFileSync = fs.readFileSync;
|
||||
|
||||
fs.existsSync = function (...args) {
|
||||
if (isBootstrapSkillPath(args[0])) {
|
||||
existsCount += 1;
|
||||
}
|
||||
return originalExistsSync.apply(this, args);
|
||||
};
|
||||
|
||||
fs.readFileSync = function (...args) {
|
||||
if (isBootstrapSkillPath(args[0])) {
|
||||
readCount += 1;
|
||||
}
|
||||
return originalReadFileSync.apply(this, args);
|
||||
};
|
||||
|
||||
const mod = await import(pathToFileURL(pluginPath).href);
|
||||
const plugin = await mod.SuperpowersPlugin({ client: {}, directory: '.' });
|
||||
const transform = plugin['experimental.chat.messages.transform'];
|
||||
|
||||
const firstOutput = makeOutput(`${scenario} bootstrap first step`);
|
||||
await transform({}, firstOutput);
|
||||
const afterFirst = { existsCount, readCount };
|
||||
|
||||
const secondOutput = makeOutput(`${scenario} bootstrap second step`);
|
||||
await transform({}, secondOutput);
|
||||
const afterSecond = { existsCount, readCount };
|
||||
|
||||
const result = {
|
||||
scenario,
|
||||
firstBootstrapParts: countBootstrapParts(firstOutput),
|
||||
secondBootstrapParts: countBootstrapParts(secondOutput),
|
||||
firstReadCount: afterFirst.readCount,
|
||||
secondReadCount: afterSecond.readCount,
|
||||
firstExistsCount: afterFirst.existsCount,
|
||||
secondExistsCount: afterSecond.existsCount,
|
||||
};
|
||||
|
||||
const failures = scenario === 'present'
|
||||
? assertPresentBootstrap(result)
|
||||
: assertMissingBootstrap(result);
|
||||
|
||||
if (failures.length > 0) {
|
||||
console.error(JSON.stringify(result, null, 2));
|
||||
for (const failure of failures) {
|
||||
console.error(`FAIL: ${failure}`);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(JSON.stringify(result, null, 2));
|
||||
|
||||
function isBootstrapSkillPath(filePath) {
|
||||
return String(filePath).replaceAll('\\', '/').includes('using-superpowers/SKILL.md');
|
||||
}
|
||||
|
||||
function makeOutput(text) {
|
||||
return {
|
||||
messages: [{
|
||||
info: { role: 'user' },
|
||||
parts: [{ type: 'text', text }],
|
||||
}],
|
||||
};
|
||||
}
|
||||
|
||||
function countBootstrapParts(output) {
|
||||
return output.messages[0].parts.filter(
|
||||
(part) => part.type === 'text' && part.text.includes('EXTREMELY_IMPORTANT')
|
||||
).length;
|
||||
}
|
||||
|
||||
function assertPresentBootstrap(result) {
|
||||
const failures = [];
|
||||
if (result.firstBootstrapParts !== 1) {
|
||||
failures.push(`expected first transform to inject one bootstrap part, got ${result.firstBootstrapParts}`);
|
||||
}
|
||||
if (result.secondBootstrapParts !== 1) {
|
||||
failures.push(`expected second transform to inject one bootstrap part, got ${result.secondBootstrapParts}`);
|
||||
}
|
||||
if (result.firstReadCount !== 1) {
|
||||
failures.push(`expected first transform to read SKILL.md once, got ${result.firstReadCount}`);
|
||||
}
|
||||
if (result.secondReadCount !== result.firstReadCount) {
|
||||
failures.push(`expected cached second transform to do no additional reads, got ${result.secondReadCount - result.firstReadCount}`);
|
||||
}
|
||||
if (result.secondExistsCount !== result.firstExistsCount) {
|
||||
failures.push(`expected cached second transform to do no additional exists checks, got ${result.secondExistsCount - result.firstExistsCount}`);
|
||||
}
|
||||
return failures;
|
||||
}
|
||||
|
||||
function assertMissingBootstrap(result) {
|
||||
const failures = [];
|
||||
if (result.firstBootstrapParts !== 0) {
|
||||
failures.push(`expected no bootstrap when SKILL.md is missing, got ${result.firstBootstrapParts}`);
|
||||
}
|
||||
if (result.secondBootstrapParts !== 0) {
|
||||
failures.push(`expected no bootstrap on second missing-file transform, got ${result.secondBootstrapParts}`);
|
||||
}
|
||||
if (result.firstReadCount !== 0 || result.secondReadCount !== 0) {
|
||||
failures.push(`expected missing file path to avoid reads, got ${result.secondReadCount}`);
|
||||
}
|
||||
if (result.firstExistsCount < 1) {
|
||||
failures.push('expected first transform to check whether SKILL.md exists');
|
||||
}
|
||||
if (result.secondExistsCount !== result.firstExistsCount) {
|
||||
failures.push(`expected missing-file result to be cached, got ${result.secondExistsCount - result.firstExistsCount} extra exists checks`);
|
||||
}
|
||||
return failures;
|
||||
}
|
||||
32
tests/opencode/test-bootstrap-caching.sh
Executable file
32
tests/opencode/test-bootstrap-caching.sh
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
# Test: Bootstrap Content Caching (#1202)
|
||||
# Verifies the OpenCode transform caches bootstrap content between agent steps.
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
echo "=== Test: Bootstrap Content Caching (#1202) ==="
|
||||
|
||||
source "$SCRIPT_DIR/setup.sh"
|
||||
trap cleanup_test_env EXIT
|
||||
|
||||
run_present_file_check() {
|
||||
node "$SCRIPT_DIR/test-bootstrap-caching.mjs" "$SUPERPOWERS_PLUGIN_FILE" present
|
||||
}
|
||||
|
||||
run_missing_file_check() {
|
||||
mv "$SUPERPOWERS_SKILLS_DIR/using-superpowers/SKILL.md" "$TEST_HOME/using-superpowers.SKILL.md.bak"
|
||||
|
||||
node "$SCRIPT_DIR/test-bootstrap-caching.mjs" "$SUPERPOWERS_PLUGIN_FILE" missing
|
||||
}
|
||||
|
||||
echo "Test 1: Caches bootstrap after the first successful transform..."
|
||||
run_present_file_check
|
||||
echo " [PASS] Bootstrap content is cached while fresh message arrays still receive injection"
|
||||
|
||||
echo "Test 2: Caches missing SKILL.md result..."
|
||||
run_missing_file_check
|
||||
echo " [PASS] Missing bootstrap file is cached and not re-probed every transform"
|
||||
|
||||
echo ""
|
||||
echo "=== All bootstrap caching tests passed ==="
|
||||
@@ -1,10 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
# Test: Skill Priority Resolution
|
||||
# Verifies that skills are resolved with correct priority: project > personal > superpowers
|
||||
# Documents current OpenCode duplicate-name behavior for local and bundled
|
||||
# skills. The desired local-shadowing behavior is tracked separately; this
|
||||
# test keeps the integration suite honest without adding a plugin workaround.
|
||||
# NOTE: These tests require OpenCode to be installed and configured
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
OPENCODE_TEST_TIMEOUT_SECONDS="${OPENCODE_TEST_TIMEOUT_SECONDS:-120}"
|
||||
|
||||
echo "=== Test: Skill Priority Resolution ==="
|
||||
|
||||
@@ -96,103 +99,119 @@ if ! command -v opencode &> /dev/null; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Test 2: Test that personal overrides superpowers
|
||||
run_opencode() {
|
||||
local result_var="$1"
|
||||
local dir="$2"
|
||||
local prompt="$3"
|
||||
local command_output
|
||||
local exit_code
|
||||
|
||||
set +e
|
||||
command_output=$(cd "$dir" && timeout "${OPENCODE_TEST_TIMEOUT_SECONDS}s" opencode run --print-logs --format json "$prompt" 2>&1)
|
||||
exit_code=$?
|
||||
set -e
|
||||
|
||||
if [ $exit_code -eq 124 ]; then
|
||||
echo " [FAIL] OpenCode timed out after ${OPENCODE_TEST_TIMEOUT_SECONDS}s"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $exit_code -ne 0 ]; then
|
||||
echo " [FAIL] OpenCode returned non-zero exit code: $exit_code"
|
||||
echo " Output was:"
|
||||
awk 'NR <= 80 { print }' <<<"$command_output"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf -v "$result_var" '%s' "$command_output"
|
||||
}
|
||||
|
||||
assert_contains() {
|
||||
local output="$1"
|
||||
local needle="$2"
|
||||
local message="$3"
|
||||
|
||||
if [[ "$output" == *"$needle"* ]]; then
|
||||
echo " [PASS] $message"
|
||||
else
|
||||
echo " [FAIL] $message"
|
||||
echo " Expected to find: $needle"
|
||||
echo " Output was:"
|
||||
awk 'NR <= 80 { print }' <<<"$output"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
first_skill_tool_event() {
|
||||
awk '/"type":"tool_use"/ && /"tool":"skill"/ { print; exit }' <<<"$1"
|
||||
}
|
||||
|
||||
describe_priority_result() {
|
||||
local output="$1"
|
||||
local expected_marker="$2"
|
||||
local fallback_marker="$3"
|
||||
local pass_message="$4"
|
||||
local known_bug_message="$5"
|
||||
local loaded_skill
|
||||
|
||||
loaded_skill="$(first_skill_tool_event "$output")"
|
||||
|
||||
if [[ "$loaded_skill" == *"$expected_marker"* ]]; then
|
||||
echo " [PASS] $pass_message"
|
||||
elif [[ "$loaded_skill" == *"$fallback_marker"* ]]; then
|
||||
echo " [INFO] $known_bug_message"
|
||||
echo " [INFO] Tracked separately: OpenCode bundled skills can shadow local skills with duplicate native names"
|
||||
else
|
||||
echo " [FAIL] Could not verify priority marker in native skill tool output"
|
||||
echo " Output was:"
|
||||
awk 'NR <= 80 { print }' <<<"$output"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Test 2: Document personal vs bundled superpowers priority
|
||||
echo ""
|
||||
echo "Test 2: Testing personal > superpowers priority..."
|
||||
echo "Test 2: Documenting personal vs superpowers priority..."
|
||||
echo " Running from outside project directory..."
|
||||
|
||||
# Run from HOME (not in project) - should get personal version
|
||||
cd "$HOME"
|
||||
output=$(timeout 60s opencode run --print-logs "Use the use_skill tool to load the priority-test skill. Show me the exact content including any PRIORITY_MARKER text." 2>&1) || {
|
||||
exit_code=$?
|
||||
if [ $exit_code -eq 124 ]; then
|
||||
echo " [FAIL] OpenCode timed out after 60s"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
run_opencode output "$HOME" "Call the skill tool with name \"priority-test\". Show the exact content including any PRIORITY_MARKER text."
|
||||
describe_priority_result \
|
||||
"$output" \
|
||||
"PRIORITY_MARKER_PERSONAL_VERSION" \
|
||||
"PRIORITY_MARKER_SUPERPOWERS_VERSION" \
|
||||
"Personal version loaded for duplicate native skill name" \
|
||||
"Current OpenCode behavior loaded bundled superpowers version instead of personal version"
|
||||
|
||||
if echo "$output" | grep -qi "PRIORITY_MARKER_PERSONAL_VERSION"; then
|
||||
echo " [PASS] Personal version loaded (overrides superpowers)"
|
||||
elif echo "$output" | grep -qi "PRIORITY_MARKER_SUPERPOWERS_VERSION"; then
|
||||
echo " [FAIL] Superpowers version loaded instead of personal"
|
||||
exit 1
|
||||
else
|
||||
echo " [WARN] Could not verify priority marker in output"
|
||||
echo " Output snippet:"
|
||||
echo "$output" | grep -i "priority\|personal\|superpowers" | head -10
|
||||
fi
|
||||
|
||||
# Test 3: Test that project overrides both personal and superpowers
|
||||
# Test 3: Document project vs bundled superpowers priority
|
||||
echo ""
|
||||
echo "Test 3: Testing project > personal > superpowers priority..."
|
||||
echo "Test 3: Documenting project vs personal/superpowers priority..."
|
||||
echo " Running from project directory..."
|
||||
|
||||
# Run from project directory - should get project version
|
||||
cd "$TEST_HOME/test-project"
|
||||
output=$(timeout 60s opencode run --print-logs "Use the use_skill tool to load the priority-test skill. Show me the exact content including any PRIORITY_MARKER text." 2>&1) || {
|
||||
exit_code=$?
|
||||
if [ $exit_code -eq 124 ]; then
|
||||
echo " [FAIL] OpenCode timed out after 60s"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
run_opencode output "$TEST_HOME/test-project" "Call the skill tool with name \"priority-test\". Show the exact content including any PRIORITY_MARKER text."
|
||||
describe_priority_result \
|
||||
"$output" \
|
||||
"PRIORITY_MARKER_PROJECT_VERSION" \
|
||||
"PRIORITY_MARKER_SUPERPOWERS_VERSION" \
|
||||
"Project version loaded for duplicate native skill name" \
|
||||
"Current OpenCode behavior loaded bundled superpowers version instead of project version"
|
||||
|
||||
if echo "$output" | grep -qi "PRIORITY_MARKER_PROJECT_VERSION"; then
|
||||
echo " [PASS] Project version loaded (highest priority)"
|
||||
elif echo "$output" | grep -qi "PRIORITY_MARKER_PERSONAL_VERSION"; then
|
||||
echo " [FAIL] Personal version loaded instead of project"
|
||||
exit 1
|
||||
elif echo "$output" | grep -qi "PRIORITY_MARKER_SUPERPOWERS_VERSION"; then
|
||||
echo " [FAIL] Superpowers version loaded instead of project"
|
||||
exit 1
|
||||
else
|
||||
echo " [WARN] Could not verify priority marker in output"
|
||||
echo " Output snippet:"
|
||||
echo "$output" | grep -i "priority\|project\|personal" | head -10
|
||||
fi
|
||||
|
||||
# Test 4: Test explicit superpowers: prefix bypasses priority
|
||||
# Test 4: Test a non-colliding bundled superpowers skill is still available
|
||||
echo ""
|
||||
echo "Test 4: Testing superpowers: prefix forces superpowers version..."
|
||||
echo "Test 4: Testing non-colliding superpowers skill remains available..."
|
||||
|
||||
cd "$TEST_HOME/test-project"
|
||||
output=$(timeout 60s opencode run --print-logs "Use the use_skill tool to load superpowers:priority-test specifically. Show me the exact content including any PRIORITY_MARKER text." 2>&1) || {
|
||||
exit_code=$?
|
||||
if [ $exit_code -eq 124 ]; then
|
||||
echo " [FAIL] OpenCode timed out after 60s"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
mkdir -p "$SUPERPOWERS_SKILLS_DIR/superpowers-only-test"
|
||||
cat > "$SUPERPOWERS_SKILLS_DIR/superpowers-only-test/SKILL.md" <<'EOF'
|
||||
---
|
||||
name: superpowers-only-test
|
||||
description: Superpowers-only priority test skill
|
||||
---
|
||||
# Superpowers Only Test Skill
|
||||
|
||||
if echo "$output" | grep -qi "PRIORITY_MARKER_SUPERPOWERS_VERSION"; then
|
||||
echo " [PASS] superpowers: prefix correctly forces superpowers version"
|
||||
elif echo "$output" | grep -qi "PRIORITY_MARKER_PROJECT_VERSION\|PRIORITY_MARKER_PERSONAL_VERSION"; then
|
||||
echo " [FAIL] superpowers: prefix did not force superpowers version"
|
||||
exit 1
|
||||
else
|
||||
echo " [WARN] Could not verify priority marker in output"
|
||||
fi
|
||||
PRIORITY_MARKER_SUPERPOWERS_ONLY_VERSION
|
||||
EOF
|
||||
|
||||
# Test 5: Test explicit project: prefix
|
||||
echo ""
|
||||
echo "Test 5: Testing project: prefix forces project version..."
|
||||
|
||||
cd "$HOME" # Run from outside project but with project: prefix
|
||||
output=$(timeout 60s opencode run --print-logs "Use the use_skill tool to load project:priority-test specifically. Show me the exact content." 2>&1) || {
|
||||
exit_code=$?
|
||||
if [ $exit_code -eq 124 ]; then
|
||||
echo " [FAIL] OpenCode timed out after 60s"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Note: This may fail since we're not in the project directory
|
||||
# The project: prefix only works when in a project context
|
||||
if echo "$output" | grep -qi "not found\|error"; then
|
||||
echo " [PASS] project: prefix correctly fails when not in project context"
|
||||
else
|
||||
echo " [INFO] project: prefix behavior outside project context may vary"
|
||||
fi
|
||||
run_opencode output "$TEST_HOME/test-project" "Call the skill tool with name \"superpowers-only-test\". Show the exact content including any PRIORITY_MARKER text."
|
||||
assert_contains "$output" "PRIORITY_MARKER_SUPERPOWERS_ONLY_VERSION" "Non-colliding superpowers skill is still registered"
|
||||
|
||||
echo ""
|
||||
echo "=== All priority tests passed ==="
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
# Test: Tools Functionality
|
||||
# Verifies that use_skill and find_skills tools work correctly
|
||||
# Test: Native Skill Tool Functionality
|
||||
# Verifies that OpenCode's native skill tool can load personal, project,
|
||||
# and bundled superpowers skills.
|
||||
# NOTE: These tests require OpenCode to be installed and configured
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
OPENCODE_TEST_TIMEOUT_SECONDS="${OPENCODE_TEST_TIMEOUT_SECONDS:-120}"
|
||||
|
||||
echo "=== Test: Tools Functionality ==="
|
||||
|
||||
@@ -21,84 +23,73 @@ if ! command -v opencode &> /dev/null; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Test 1: Test find_skills tool via direct invocation
|
||||
echo "Test 1: Testing find_skills tool..."
|
||||
echo " Running opencode with find_skills request..."
|
||||
run_opencode() {
|
||||
local result_var="$1"
|
||||
local dir="$2"
|
||||
local prompt="$3"
|
||||
local command_output
|
||||
local exit_code
|
||||
|
||||
# Use timeout to prevent hanging, capture both stdout and stderr
|
||||
output=$(timeout 60s opencode run --print-logs "Use the find_skills tool to list available skills. Just call the tool and show me the raw output." 2>&1) || {
|
||||
set +e
|
||||
command_output=$(cd "$dir" && timeout "${OPENCODE_TEST_TIMEOUT_SECONDS}s" opencode run --print-logs --format json "$prompt" 2>&1)
|
||||
exit_code=$?
|
||||
set -e
|
||||
|
||||
if [ $exit_code -eq 124 ]; then
|
||||
echo " [FAIL] OpenCode timed out after 60s"
|
||||
echo " [FAIL] OpenCode timed out after ${OPENCODE_TEST_TIMEOUT_SECONDS}s"
|
||||
exit 1
|
||||
fi
|
||||
echo " [WARN] OpenCode returned non-zero exit code: $exit_code"
|
||||
}
|
||||
|
||||
# Check for expected patterns in output
|
||||
if echo "$output" | grep -qi "superpowers:brainstorming\|superpowers:using-superpowers\|Available skills"; then
|
||||
echo " [PASS] find_skills tool discovered superpowers skills"
|
||||
else
|
||||
echo " [FAIL] find_skills did not return expected skills"
|
||||
echo " Output was:"
|
||||
echo "$output" | head -50
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if personal test skill was found
|
||||
if echo "$output" | grep -qi "personal-test"; then
|
||||
echo " [PASS] find_skills found personal test skill"
|
||||
else
|
||||
echo " [WARN] personal test skill not found in output (may be ok if tool returned subset)"
|
||||
fi
|
||||
|
||||
# Test 2: Test use_skill tool
|
||||
echo ""
|
||||
echo "Test 2: Testing use_skill tool..."
|
||||
echo " Running opencode with use_skill request..."
|
||||
|
||||
output=$(timeout 60s opencode run --print-logs "Use the use_skill tool to load the personal-test skill and show me what you get." 2>&1) || {
|
||||
exit_code=$?
|
||||
if [ $exit_code -eq 124 ]; then
|
||||
echo " [FAIL] OpenCode timed out after 60s"
|
||||
if [ $exit_code -ne 0 ]; then
|
||||
echo " [FAIL] OpenCode returned non-zero exit code: $exit_code"
|
||||
echo " Output was:"
|
||||
awk 'NR <= 80 { print }' <<<"$command_output"
|
||||
exit 1
|
||||
fi
|
||||
echo " [WARN] OpenCode returned non-zero exit code: $exit_code"
|
||||
|
||||
printf -v "$result_var" '%s' "$command_output"
|
||||
}
|
||||
|
||||
# Check for the skill marker we embedded
|
||||
if echo "$output" | grep -qi "PERSONAL_SKILL_MARKER_12345\|Personal Test Skill\|Launching skill"; then
|
||||
echo " [PASS] use_skill loaded personal-test skill content"
|
||||
else
|
||||
echo " [FAIL] use_skill did not load personal-test skill correctly"
|
||||
echo " Output was:"
|
||||
echo "$output" | head -50
|
||||
exit 1
|
||||
fi
|
||||
assert_contains() {
|
||||
local output="$1"
|
||||
local needle="$2"
|
||||
local message="$3"
|
||||
|
||||
# Test 3: Test use_skill with superpowers: prefix
|
||||
echo ""
|
||||
echo "Test 3: Testing use_skill with superpowers: prefix..."
|
||||
echo " Running opencode with superpowers:brainstorming skill..."
|
||||
|
||||
output=$(timeout 60s opencode run --print-logs "Use the use_skill tool to load superpowers:brainstorming and tell me the first few lines of what you received." 2>&1) || {
|
||||
exit_code=$?
|
||||
if [ $exit_code -eq 124 ]; then
|
||||
echo " [FAIL] OpenCode timed out after 60s"
|
||||
if [[ "$output" == *"$needle"* ]]; then
|
||||
echo " [PASS] $message"
|
||||
else
|
||||
echo " [FAIL] $message"
|
||||
echo " Expected to find: $needle"
|
||||
echo " Output was:"
|
||||
awk 'NR <= 80 { print }' <<<"$output"
|
||||
exit 1
|
||||
fi
|
||||
echo " [WARN] OpenCode returned non-zero exit code: $exit_code"
|
||||
}
|
||||
|
||||
# Check for expected content from brainstorming skill
|
||||
if echo "$output" | grep -qi "brainstorming\|Launching skill\|skill.*loaded"; then
|
||||
echo " [PASS] use_skill loaded superpowers:brainstorming skill"
|
||||
else
|
||||
echo " [FAIL] use_skill did not load superpowers:brainstorming correctly"
|
||||
echo " Output was:"
|
||||
echo "$output" | head -50
|
||||
exit 1
|
||||
fi
|
||||
# Test 1: Test personal skill loading via OpenCode's native skill tool
|
||||
echo "Test 1: Testing native skill tool with a personal skill..."
|
||||
echo " Running opencode with personal-test request..."
|
||||
|
||||
run_opencode output "$TEST_HOME/test-project" "Call the skill tool with name \"personal-test\". Then print the PERSONAL_SKILL_MARKER_12345 marker."
|
||||
assert_contains "$output" '"tool":"skill"' "OpenCode called the native skill tool"
|
||||
assert_contains "$output" "PERSONAL_SKILL_MARKER_12345" "native skill tool loaded personal-test skill content"
|
||||
|
||||
# Test 2: Test project skill loading
|
||||
echo ""
|
||||
echo "Test 2: Testing native skill tool with a project skill..."
|
||||
echo " Running opencode with project-test request..."
|
||||
|
||||
run_opencode output "$TEST_HOME/test-project" "Call the skill tool with name \"project-test\". Then print the PROJECT_SKILL_MARKER_67890 marker."
|
||||
assert_contains "$output" "PROJECT_SKILL_MARKER_67890" "native skill tool loaded project-test skill content"
|
||||
|
||||
# Test 3: Test bundled superpowers skill loading
|
||||
echo ""
|
||||
echo "Test 3: Testing native skill tool with a superpowers skill..."
|
||||
echo " Running opencode with brainstorming skill..."
|
||||
|
||||
run_opencode output "$TEST_HOME/test-project" "Call the skill tool with name \"brainstorming\". Then tell me the loaded skill title."
|
||||
assert_contains "$output" '"name":"brainstorming"' "native skill tool loaded bundled brainstorming skill"
|
||||
assert_contains "$output" "Brainstorming Ideas Into Designs" "brainstorming skill content was returned"
|
||||
|
||||
echo ""
|
||||
echo "=== All tools tests passed ==="
|
||||
echo "=== All native skill tool tests passed ==="
|
||||
|
||||
Reference in New Issue
Block a user