@pharaoh-so/mcp 0.3.14 → 0.3.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/commands/plan.md +142 -0
- package/commands/review.md +5 -0
- package/dist/install-skills.d.ts +6 -2
- package/dist/install-skills.js +156 -42
- package/package.json +2 -1
- package/skills/brainstorm/SKILL.md +1 -1
- package/skills/plan/SKILL.md +26 -24
- package/skills/audit-tests/SKILL.md +0 -89
- package/skills/debt/SKILL.md +0 -34
- package/skills/execute/SKILL.md +0 -58
- package/skills/explore/SKILL.md +0 -33
- package/skills/finish/SKILL.md +0 -80
- package/skills/health/SKILL.md +0 -37
- package/skills/investigate/SKILL.md +0 -35
- package/skills/onboard/SKILL.md +0 -33
- package/skills/orchestrate/SKILL.md +0 -145
- package/skills/pr/SKILL.md +0 -53
- package/skills/review-codex/SKILL.md +0 -81
- package/skills/review-receive/SKILL.md +0 -82
- package/skills/wiring/SKILL.md +0 -35
- package/skills/worktree/SKILL.md +0 -86
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pharaoh",
|
|
3
3
|
"version": "0.2.3",
|
|
4
|
-
"description": "Codebase knowledge graph with
|
|
4
|
+
"description": "Codebase knowledge graph with focused development workflow skills. Query architecture, dependencies, blast radius, and more instead of reading files one at a time.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Pharaoh",
|
|
7
7
|
"email": "hello@pharaoh.so",
|
package/commands/plan.md
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Architecture-aware planning with Pharaoh reconnaissance (adapted from Garry Tan's planning framework)
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Plan Review
|
|
6
|
+
|
|
7
|
+
Architecture-aware plan review before implementation. Adapted from [Garry Tan's planning framework](https://www.youtube.com/watch?v=bMknfKXIFA8) for AI-assisted development.
|
|
8
|
+
|
|
9
|
+
**You are now in plan mode. Do NOT make any code changes. Think, evaluate, and present decisions.**
|
|
10
|
+
|
|
11
|
+
## Document Review
|
|
12
|
+
|
|
13
|
+
If the user provides a document, PRD, prompt, or artifact alongside this command, that IS the plan to review. Apply all review sections to that document. Do not treat it as background context — it is the subject of evaluation.
|
|
14
|
+
|
|
15
|
+
Still run Step 1 (Reconnaissance) even when reviewing a document — always verify the plan against the actual codebase state.
|
|
16
|
+
|
|
17
|
+
## Project Overrides
|
|
18
|
+
|
|
19
|
+
If a `.claude/plan-review.md` file exists in this project, read it now and apply those rules on top of this baseline. Project rules take precedence where they conflict.
|
|
20
|
+
|
|
21
|
+
## Engineering Preferences (guide all recommendations)
|
|
22
|
+
|
|
23
|
+
- DRY: flag repetition aggressively
|
|
24
|
+
- Well-tested: too many tests > too few; mutation score > line coverage
|
|
25
|
+
- "Engineered enough" — not fragile/hacky, not over-abstracted
|
|
26
|
+
- Handle more edge cases, not fewer; thoughtfulness > speed
|
|
27
|
+
- Explicit > clever; simple > complex
|
|
28
|
+
- Subtraction > addition; target zero or negative net LOC
|
|
29
|
+
- Every export must have a caller; unwired code doesn't exist
|
|
30
|
+
|
|
31
|
+
## Step 1: Pharaoh Reconnaissance (Required — do this BEFORE reviewing)
|
|
32
|
+
|
|
33
|
+
Do NOT review from memory or assumptions. Query the actual codebase first.
|
|
34
|
+
|
|
35
|
+
### If Pharaoh MCP tools are available:
|
|
36
|
+
|
|
37
|
+
1. `get_codebase_map` — current modules, hot files, dependency graph
|
|
38
|
+
2. `search_functions` for keywords related to the plan — find existing code to reuse/extend
|
|
39
|
+
3. `get_module_context` on affected modules — entry points, patterns, conventions
|
|
40
|
+
4. `query_dependencies` between affected modules — coupling, circular deps
|
|
41
|
+
5. `get_blast_radius` on the primary target of the change — know what breaks
|
|
42
|
+
6. `check_reachability` on the primary target — verify it's actually reachable from entry points before worrying about it
|
|
43
|
+
|
|
44
|
+
### Without Pharaoh (graceful fallback):
|
|
45
|
+
|
|
46
|
+
1. Search the codebase for files and functions related to the plan (grep, glob)
|
|
47
|
+
2. Read the entry points and module structure of affected areas
|
|
48
|
+
3. Check existing tests for the modules the plan will touch
|
|
49
|
+
4. Trace imports manually to estimate blast radius
|
|
50
|
+
|
|
51
|
+
Ground every recommendation in what actually exists. If you propose adding something, confirm it doesn't already exist. If you propose changing something, know its blast radius.
|
|
52
|
+
|
|
53
|
+
## Step 2: Mode Selection (MANDATORY — ask before proceeding)
|
|
54
|
+
|
|
55
|
+
**STOP and ask the user which mode before starting the review.** This is a hard gate — do not infer, assume, or skip this question even if the user says "yes", "go ahead", or "yes to all". Present both options and wait for an explicit choice:
|
|
56
|
+
|
|
57
|
+
> **BIG CHANGE or SMALL CHANGE?**
|
|
58
|
+
>
|
|
59
|
+
> - **BIG CHANGE**: Full interactive review, all relevant sections, up to 4 top issues per section
|
|
60
|
+
> - **SMALL CHANGE**: One question per section, only sections 2-4
|
|
61
|
+
|
|
62
|
+
If the user's response is ambiguous (e.g. "just do it", "yes to all"), ask again: "I need to know — BIG or SMALL change?" Do not proceed to Step 3 without an answer.
|
|
63
|
+
|
|
64
|
+
## Step 3: Review Sections
|
|
65
|
+
|
|
66
|
+
Adapt depth to change size. Skip sections that don't apply. **After each section, pause and ask for feedback before moving on.**
|
|
67
|
+
|
|
68
|
+
### Section 1 — Architecture (skip for small/single-file changes)
|
|
69
|
+
|
|
70
|
+
- Component boundaries and coupling concerns
|
|
71
|
+
- Dependency graph: does this change shrink or expand surface area?
|
|
72
|
+
- Data flow bottlenecks and single points of failure
|
|
73
|
+
- Does this need new code at all, or can a human process / existing pattern solve it?
|
|
74
|
+
|
|
75
|
+
### Section 2 — Code Quality (always)
|
|
76
|
+
|
|
77
|
+
- Organization, module structure, DRY violations (be aggressive)
|
|
78
|
+
- Error handling gaps and missing edge cases (call out explicitly)
|
|
79
|
+
- Technical debt: shortcuts, hardcoded values, magic strings
|
|
80
|
+
- Over-engineered or under-engineered relative to my preferences
|
|
81
|
+
- Reuse: does code for this already exist somewhere?
|
|
82
|
+
|
|
83
|
+
### Section 3 — Wiring & Integration (always)
|
|
84
|
+
|
|
85
|
+
- Are all new exports called from a production entry point?
|
|
86
|
+
- Run `get_blast_radius` on any new/changed functions — zero callers = not done
|
|
87
|
+
- `check_reachability` on new exports — verify reachable from API handlers, crons, or event handlers
|
|
88
|
+
- Does the plan declare WHERE new code gets called from? If not, flag it
|
|
89
|
+
- Integration points: how does this connect to what already exists?
|
|
90
|
+
|
|
91
|
+
### Section 4 — Tests (always)
|
|
92
|
+
|
|
93
|
+
- Coverage gaps: unit, integration, e2e
|
|
94
|
+
- Test quality: real assertions with hardcoded expected values, not `.toBeDefined()` or computed expectations
|
|
95
|
+
- Missing edge cases and untested failure/error paths
|
|
96
|
+
- One integration test proving wiring > ten isolated unit tests
|
|
97
|
+
|
|
98
|
+
### Section 5 — Performance (only if relevant)
|
|
99
|
+
|
|
100
|
+
- N+1 queries, unnecessary DB round-trips
|
|
101
|
+
- Memory concerns, caching opportunities
|
|
102
|
+
- Slow or high-complexity code paths
|
|
103
|
+
|
|
104
|
+
### Section 6 — Security & Attack Surface (always for new endpoints/routes/APIs; skip for pure refactors)
|
|
105
|
+
|
|
106
|
+
- **Authentication model** — what authenticates requests in this plan? Where is it validated? What happens on auth failure (redirect, 401, silent pass-through)? Use `search_functions` to find existing auth middleware and confirm reuse.
|
|
107
|
+
- **Sensitive data in URLs** — does the design put tokens, session IDs, or tenant identifiers in URL paths or query params? These leak via Referer headers, browser history, logs, and link sharing.
|
|
108
|
+
- **Authorization boundaries** — what prevents User A from accessing User B's data? Is there an ownership check, or just an "is logged in" check? Use `get_blast_radius` on existing ownership-check functions to see where they're already enforced.
|
|
109
|
+
- **Input trust boundary** — does the plan accept user input that flows into shell commands, database queries, HTML rendering, or file paths? Each is an injection vector.
|
|
110
|
+
- **Error and response surface** — will error responses or API payloads expose internals (stack traces, DB schemas, internal IDs) to unauthenticated callers?
|
|
111
|
+
- **New attack surface** — does the plan introduce new public URLs, webhooks, API routes, or WebSocket endpoints? Each needs: rate limiting, authentication, and input validation. Use `get_module_context` on the receiving module to check what protections exist.
|
|
112
|
+
|
|
113
|
+
## For Each Issue Found
|
|
114
|
+
|
|
115
|
+
For every specific issue (bug, smell, design concern, risk, missing wiring):
|
|
116
|
+
|
|
117
|
+
1. **Describe concretely** — file, line/function reference, what's wrong
|
|
118
|
+
2. **Present 2-3 options** including "do nothing" where reasonable
|
|
119
|
+
3. **For each option** — implementation effort, risk, blast radius, maintenance burden
|
|
120
|
+
4. **Recommend one** mapped to my preferences above, and say why
|
|
121
|
+
5. **Ask** whether I agree or want a different direction
|
|
122
|
+
|
|
123
|
+
Number each issue (1, 2, 3...) and letter each option (A, B, C...). Recommended option is always listed first. Use AskUserQuestion with clear labels like "Issue 1 Option A", "Issue 1 Option B".
|
|
124
|
+
|
|
125
|
+
## Pharaoh Checkpoints (use throughout, not just at the end)
|
|
126
|
+
|
|
127
|
+
- **Before reviewing**: recon (Step 1 above)
|
|
128
|
+
- **During review**: `get_blast_radius` when evaluating impact of changes; `search_functions` before suggesting new code
|
|
129
|
+
- **After decisions**: `check_reachability` on all new exports; `get_unused_code` to catch disconnections
|
|
130
|
+
- **Final sweep**: `get_blast_radius` on ALL new exports — zero callers on non-entry-points = plan is incomplete
|
|
131
|
+
|
|
132
|
+
## Workflow Rules
|
|
133
|
+
|
|
134
|
+
- **After each section, pause and ask for feedback before moving on**
|
|
135
|
+
- Do not assume priorities on timeline or scale
|
|
136
|
+
- If you see a better approach to the entire plan, say so BEFORE section-by-section review
|
|
137
|
+
- Challenge the approach if you see a better one — your job is to find problems I'll regret later
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
Here is the task to review:
|
|
141
|
+
|
|
142
|
+
$ARGUMENTS
|
package/dist/install-skills.d.ts
CHANGED
|
@@ -6,8 +6,12 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export declare function detectOpenClaw(home?: string): boolean;
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* Install bundled skills to `~/.openclaw/skills/` with the same `pharaoh-`
|
|
10
|
+
* prefix that Claude Code installs use. Keeps naming consistent across both
|
|
11
|
+
* platforms and avoids collision with other OpenClaw skills that may ship
|
|
12
|
+
* bare names like `plan` or `review`.
|
|
13
|
+
*
|
|
14
|
+
* Overwrites existing skill dirs on reinstall.
|
|
11
15
|
*
|
|
12
16
|
* @param home - Home directory override (defaults to os.homedir()).
|
|
13
17
|
* @returns Number of skill directories copied.
|
package/dist/install-skills.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* OpenClaw's ~/.openclaw/skills/ directory (fallback). Also merges
|
|
6
6
|
* the Pharaoh MCP server config into the target platform.
|
|
7
7
|
*/
|
|
8
|
-
import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync, } from "node:fs";
|
|
9
9
|
import { homedir } from "node:os";
|
|
10
10
|
import { dirname, join } from "node:path";
|
|
11
11
|
import { fileURLToPath } from "node:url";
|
|
@@ -15,6 +15,22 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
15
15
|
const PKG_ROOT = join(__dirname, "..");
|
|
16
16
|
/** Path to the bundled skills directory. */
|
|
17
17
|
const BUNDLED_SKILLS_DIR = join(PKG_ROOT, "skills");
|
|
18
|
+
/** Path to the bundled slash commands directory. */
|
|
19
|
+
const BUNDLED_COMMANDS_DIR = join(PKG_ROOT, "commands");
|
|
20
|
+
/**
|
|
21
|
+
* Namespace prefix applied to every installed skill. Prevents collision with
|
|
22
|
+
* other plugins that ship same-named bare skills (e.g. `plan`, `review`).
|
|
23
|
+
*
|
|
24
|
+
* Why not use `pharaoh:<skill>` colon-form instead? Claude Code's skill
|
|
25
|
+
* resolver only auto-namespaces skills from plugins installed via the
|
|
26
|
+
* marketplace path (`~/.claude/plugins/cache/<marketplace>/...`). Plugins
|
|
27
|
+
* installed directly to `~/.claude/plugins/data/` — where `npx
|
|
28
|
+
* @pharaoh-so/mcp --install-skills` installs this package — get their
|
|
29
|
+
* skills registered as BARE names without any `<plugin>:` prefix. Applying
|
|
30
|
+
* the prefix as part of the skill's own `name:` field is the only way to
|
|
31
|
+
* get collision-safe distinctive names on this install path.
|
|
32
|
+
*/
|
|
33
|
+
const SKILL_PREFIX = "pharaoh-";
|
|
18
34
|
// ── Detection ───────────────────────────────────────────────────────
|
|
19
35
|
/**
|
|
20
36
|
* Detect whether Claude Code is installed by checking for ~/.claude/.
|
|
@@ -37,11 +53,17 @@ export function detectOpenClaw(home = homedir()) {
|
|
|
37
53
|
// ── Claude Code installer ───────────────────────────────────────────
|
|
38
54
|
/**
|
|
39
55
|
* Install Pharaoh as a Claude Code plugin by copying the full plugin
|
|
40
|
-
* structure (`.claude-plugin/`, `skills/`, `.mcp.json`) to a
|
|
41
|
-
* directory under `~/.claude/plugins/data/pharaoh
|
|
56
|
+
* structure (`.claude-plugin/`, `skills/`, `.mcp.json`, `commands/`) to a
|
|
57
|
+
* persistent directory under `~/.claude/plugins/data/pharaoh/`, plus user-
|
|
58
|
+
* level slash command templates under `~/.claude/commands/`.
|
|
59
|
+
*
|
|
60
|
+
* Claude Code auto-discovers skills from the `skills/` subdirectory when
|
|
61
|
+
* the plugin manifest (`.claude-plugin/plugin.json`) is present.
|
|
42
62
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
63
|
+
* Each skill is installed with a `pharaoh-` prefix (see SKILL_PREFIX) to
|
|
64
|
+
* avoid collision with other plugins that may ship same-named bare skills.
|
|
65
|
+
* The source directory keeps its bare name — the prefix is applied
|
|
66
|
+
* mechanically during copy with no drift possible.
|
|
45
67
|
*
|
|
46
68
|
* @param home - Home directory override (defaults to os.homedir()).
|
|
47
69
|
* @returns Number of skill directories installed, or -1 on failure.
|
|
@@ -59,33 +81,14 @@ function installClaudeCodePlugin(home = homedir()) {
|
|
|
59
81
|
process.stderr.write("Pharaoh: .claude-plugin/ manifest not found in package — cannot install.\n");
|
|
60
82
|
return -1;
|
|
61
83
|
}
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
// resolve to the same content. Without this, prefixed copies drift and users
|
|
71
|
-
// get a stripped skeleton when invoking via the pharaoh: prefix.
|
|
72
|
-
for (const dir of skillDirs) {
|
|
73
|
-
if (dir.name === "pharaoh" || dir.name.startsWith("pharaoh-"))
|
|
74
|
-
continue;
|
|
75
|
-
const prefixedName = `pharaoh-${dir.name}`;
|
|
76
|
-
const prefixedDir = join(pluginDir, "skills", prefixedName);
|
|
77
|
-
const srcSkill = join(pluginDir, "skills", dir.name, "SKILL.md");
|
|
78
|
-
if (!existsSync(srcSkill))
|
|
79
|
-
continue;
|
|
80
|
-
mkdirSync(prefixedDir, { recursive: true });
|
|
81
|
-
const content = readFileSync(srcSkill, "utf-8");
|
|
82
|
-
// Rewrite the name field in YAML frontmatter only (between --- delimiters).
|
|
83
|
-
// Using a whole-file /m regex would match `name:` in body content too.
|
|
84
|
-
const rewritten = content.replace(/^(---\n[\s\S]*?)(name:\s*).+(\n[\s\S]*?---)/, `$1$2${prefixedName}$3`);
|
|
85
|
-
writeFileSync(join(prefixedDir, "SKILL.md"), rewritten);
|
|
86
|
-
skillCount++;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
84
|
+
// Install skills under the pharaoh- prefix for collision-safe names.
|
|
85
|
+
const skillsDst = join(pluginDir, "skills");
|
|
86
|
+
const skillCount = installPrefixedSkills(BUNDLED_SKILLS_DIR, skillsDst, SKILL_PREFIX);
|
|
87
|
+
// Migrate: delete any bare-name skill dirs left from prior installs
|
|
88
|
+
// that used the dual bare+prefixed layout. Without this, users who
|
|
89
|
+
// upgrade keep both copies and Claude Code's prompt-name dedupe picks
|
|
90
|
+
// the wrong one.
|
|
91
|
+
cleanupBareNameSkills(BUNDLED_SKILLS_DIR, skillsDst);
|
|
89
92
|
// Copy .mcp.json
|
|
90
93
|
const mcpSrc = join(PKG_ROOT, ".mcp.json");
|
|
91
94
|
if (existsSync(mcpSrc)) {
|
|
@@ -93,6 +96,111 @@ function installClaudeCodePlugin(home = homedir()) {
|
|
|
93
96
|
}
|
|
94
97
|
return skillCount;
|
|
95
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Copy every skill directory from `srcDir` to `dstDir`, prefixing both the
|
|
101
|
+
* target directory name and the `name:` field in its SKILL.md frontmatter
|
|
102
|
+
* with `prefix`.
|
|
103
|
+
*
|
|
104
|
+
* Exception: a source directory whose name equals the prefix stripped of
|
|
105
|
+
* its trailing dash is copied WITHOUT a double-prefix. Example: with
|
|
106
|
+
* `prefix = "pharaoh-"`, the source dir `pharaoh/` is copied to `pharaoh/`
|
|
107
|
+
* unchanged, not `pharaoh-pharaoh/`. This keeps the flagship skill's name
|
|
108
|
+
* clean.
|
|
109
|
+
*
|
|
110
|
+
* @param srcDir - Source skills directory (bundled with the package).
|
|
111
|
+
* @param dstDir - Destination skills directory (inside the plugin path).
|
|
112
|
+
* @param prefix - Namespace prefix to apply (e.g., `"pharaoh-"`).
|
|
113
|
+
* @returns Number of skill directories installed.
|
|
114
|
+
*/
|
|
115
|
+
function installPrefixedSkills(srcDir, dstDir, prefix) {
|
|
116
|
+
if (!existsSync(srcDir))
|
|
117
|
+
return 0;
|
|
118
|
+
mkdirSync(dstDir, { recursive: true });
|
|
119
|
+
// `pharaoh-` → `pharaoh` — the source directory name that's exempt from
|
|
120
|
+
// the prefix to avoid `pharaoh-pharaoh`.
|
|
121
|
+
const exemptName = prefix.replace(/-$/, "");
|
|
122
|
+
const entries = readdirSync(srcDir, { withFileTypes: true });
|
|
123
|
+
let count = 0;
|
|
124
|
+
for (const entry of entries) {
|
|
125
|
+
if (!entry.isDirectory())
|
|
126
|
+
continue;
|
|
127
|
+
const srcSkill = join(srcDir, entry.name);
|
|
128
|
+
const srcSkillMd = join(srcSkill, "SKILL.md");
|
|
129
|
+
if (!existsSync(srcSkillMd))
|
|
130
|
+
continue;
|
|
131
|
+
const dstName = entry.name === exemptName ? entry.name : `${prefix}${entry.name}`;
|
|
132
|
+
const dstSkill = join(dstDir, dstName);
|
|
133
|
+
// Copy the full source tree (SKILL.md + any supporting files).
|
|
134
|
+
cpSync(srcSkill, dstSkill, { recursive: true, force: true });
|
|
135
|
+
// Rewrite the frontmatter `name:` field only if we applied the prefix.
|
|
136
|
+
if (dstName !== entry.name) {
|
|
137
|
+
const dstSkillMd = join(dstSkill, "SKILL.md");
|
|
138
|
+
const content = readFileSync(dstSkillMd, "utf-8");
|
|
139
|
+
const rewritten = content.replace(/^(---\n[\s\S]*?)(name:\s*).+(\n[\s\S]*?---)/, `$1$2${dstName}$3`);
|
|
140
|
+
writeFileSync(dstSkillMd, rewritten);
|
|
141
|
+
}
|
|
142
|
+
count++;
|
|
143
|
+
}
|
|
144
|
+
return count;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Delete bare-name skill directories from prior installs that used the dual
|
|
148
|
+
* bare+prefixed layout. Only removes directories that match the name of a
|
|
149
|
+
* bundled source skill (so we don't accidentally delete user-installed
|
|
150
|
+
* skills from other sources that happen to share the `pharaoh/skills/`
|
|
151
|
+
* install path).
|
|
152
|
+
*
|
|
153
|
+
* @param srcDir - Bundled source skills directory.
|
|
154
|
+
* @param dstDir - Installed skills directory.
|
|
155
|
+
* @returns Number of stale directories removed.
|
|
156
|
+
*/
|
|
157
|
+
function cleanupBareNameSkills(srcDir, dstDir) {
|
|
158
|
+
if (!existsSync(srcDir) || !existsSync(dstDir))
|
|
159
|
+
return 0;
|
|
160
|
+
const exemptName = SKILL_PREFIX.replace(/-$/, "");
|
|
161
|
+
const sourceNames = new Set(readdirSync(srcDir, { withFileTypes: true })
|
|
162
|
+
.filter((e) => e.isDirectory() && e.name !== exemptName)
|
|
163
|
+
.map((e) => e.name));
|
|
164
|
+
let removed = 0;
|
|
165
|
+
for (const name of sourceNames) {
|
|
166
|
+
const staleDir = join(dstDir, name);
|
|
167
|
+
if (existsSync(staleDir)) {
|
|
168
|
+
rmSync(staleDir, { recursive: true, force: true });
|
|
169
|
+
removed++;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return removed;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Copy bundled slash command templates (`.md` files in the package's
|
|
176
|
+
* `commands/` directory) to `~/.claude/commands/`, unconditionally
|
|
177
|
+
* overwriting any existing file with the same name.
|
|
178
|
+
*
|
|
179
|
+
* Overwriting is intentional: the install contract is "slash commands just
|
|
180
|
+
* work out of the box," so the canonical shipped versions take precedence
|
|
181
|
+
* over user customizations. Users who want custom command behavior should
|
|
182
|
+
* use different filenames.
|
|
183
|
+
*
|
|
184
|
+
* @param home - Home directory override (defaults to os.homedir()).
|
|
185
|
+
* @returns Number of commands installed.
|
|
186
|
+
*/
|
|
187
|
+
function installClaudeCodeCommands(home) {
|
|
188
|
+
if (!existsSync(BUNDLED_COMMANDS_DIR))
|
|
189
|
+
return 0;
|
|
190
|
+
const commandsDst = join(home, ".claude", "commands");
|
|
191
|
+
mkdirSync(commandsDst, { recursive: true });
|
|
192
|
+
const entries = readdirSync(BUNDLED_COMMANDS_DIR, { withFileTypes: true });
|
|
193
|
+
let count = 0;
|
|
194
|
+
for (const entry of entries) {
|
|
195
|
+
if (!entry.isFile() || !entry.name.endsWith(".md"))
|
|
196
|
+
continue;
|
|
197
|
+
const src = join(BUNDLED_COMMANDS_DIR, entry.name);
|
|
198
|
+
const dst = join(commandsDst, entry.name);
|
|
199
|
+
cpSync(src, dst, { force: true });
|
|
200
|
+
count++;
|
|
201
|
+
}
|
|
202
|
+
return count;
|
|
203
|
+
}
|
|
96
204
|
/**
|
|
97
205
|
* Register Pharaoh in Claude Code's installed_plugins.json (v2 format).
|
|
98
206
|
* Adds a new entry or updates the version/lastUpdated of an existing one.
|
|
@@ -152,8 +260,12 @@ function registerClaudeCodePlugin(home = homedir()) {
|
|
|
152
260
|
}
|
|
153
261
|
// ── OpenClaw installer ──────────────────────────────────────────────
|
|
154
262
|
/**
|
|
155
|
-
*
|
|
156
|
-
*
|
|
263
|
+
* Install bundled skills to `~/.openclaw/skills/` with the same `pharaoh-`
|
|
264
|
+
* prefix that Claude Code installs use. Keeps naming consistent across both
|
|
265
|
+
* platforms and avoids collision with other OpenClaw skills that may ship
|
|
266
|
+
* bare names like `plan` or `review`.
|
|
267
|
+
*
|
|
268
|
+
* Overwrites existing skill dirs on reinstall.
|
|
157
269
|
*
|
|
158
270
|
* @param home - Home directory override (defaults to os.homedir()).
|
|
159
271
|
* @returns Number of skill directories copied.
|
|
@@ -163,14 +275,11 @@ export function installSkills(home = homedir()) {
|
|
|
163
275
|
if (!existsSync(targetDir)) {
|
|
164
276
|
mkdirSync(targetDir, { recursive: true });
|
|
165
277
|
}
|
|
166
|
-
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
cpSync(src, dst, { recursive: true, force: true });
|
|
172
|
-
}
|
|
173
|
-
return skillDirs.length;
|
|
278
|
+
// Prefix skills for collision safety (same rationale as Claude Code path).
|
|
279
|
+
const count = installPrefixedSkills(BUNDLED_SKILLS_DIR, targetDir, SKILL_PREFIX);
|
|
280
|
+
// Also clean up any bare-name leftovers from prior installs.
|
|
281
|
+
cleanupBareNameSkills(BUNDLED_SKILLS_DIR, targetDir);
|
|
282
|
+
return count;
|
|
174
283
|
}
|
|
175
284
|
/**
|
|
176
285
|
* Read ~/.openclaw/openclaw.json, add the Pharaoh MCP server under `mcpServers`,
|
|
@@ -263,6 +372,7 @@ export function runInstallSkills(home = homedir(), options) {
|
|
|
263
372
|
const count = installClaudeCodePlugin(home);
|
|
264
373
|
if (count >= 0) {
|
|
265
374
|
const regResult = registerClaudeCodePlugin(home);
|
|
375
|
+
const commandCount = installClaudeCodeCommands(home);
|
|
266
376
|
// Silently ensure Pharaoh tools auto-approve (no user prompt on first use)
|
|
267
377
|
configureClaudeCodePermissions(home);
|
|
268
378
|
if (!silent) {
|
|
@@ -272,10 +382,14 @@ export function runInstallSkills(home = homedir(), options) {
|
|
|
272
382
|
current: "Plugin already registered and up-to-date",
|
|
273
383
|
error: "Could not update installed_plugins.json",
|
|
274
384
|
};
|
|
385
|
+
const commandLine = commandCount > 0
|
|
386
|
+
? ` → Installed ${commandCount} slash command${commandCount === 1 ? "" : "s"} to ~/.claude/commands/`
|
|
387
|
+
: null;
|
|
275
388
|
process.stderr.write([
|
|
276
389
|
`Pharaoh: installed ${count} skills as Claude Code plugin`,
|
|
277
390
|
` → ~/.claude/plugins/data/pharaoh/`,
|
|
278
391
|
` → ${regMessages[regResult]}`,
|
|
392
|
+
...(commandLine ? [commandLine] : []),
|
|
279
393
|
"",
|
|
280
394
|
...(regResult === "added" ? ["Restart Claude Code to pick up the new skills.", ""] : []),
|
|
281
395
|
].join("\n"));
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pharaoh-so/mcp",
|
|
3
3
|
"mcpName": "so.pharaoh/pharaoh",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.16",
|
|
5
5
|
"description": "MCP proxy for Pharaoh — maps codebases into queryable knowledge graphs for AI agents. Enables Claude Code in headless environments (VPS, SSH, CI) via device flow auth.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"files": [
|
|
13
13
|
"dist",
|
|
14
14
|
"skills",
|
|
15
|
+
"commands",
|
|
15
16
|
".claude-plugin",
|
|
16
17
|
".mcp.json",
|
|
17
18
|
"inspect-tools.json",
|
|
@@ -56,7 +56,7 @@ Save the validated design to a spec file and commit it. Ask the user to review b
|
|
|
56
56
|
|
|
57
57
|
### 7. Transition
|
|
58
58
|
|
|
59
|
-
Once the spec is approved, move to implementation
|
|
59
|
+
Once the spec is approved, move to implementation. Use the `plan` skill to break the work into verified steps, then build.
|
|
60
60
|
|
|
61
61
|
## Working in Existing Codebases
|
|
62
62
|
|
package/skills/plan/SKILL.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: plan
|
|
3
3
|
prompt-name: plan-with-pharaoh
|
|
4
|
-
description:
|
|
5
|
-
version: 0.
|
|
4
|
+
description: Architecture-aware plan review adapted from Garry Tan's framework for AI-assisted development. Pharaoh reconnaissance, mandatory mode selection, structured six-section review with decision points. Drop-in replacement that supersedes the legacy ~/.claude/skills/plan-review skill — every section of the legacy skill is present here, plus graceful fallback when Pharaoh is unavailable, stronger mode-selection enforcement, and an explicit framework reference.
|
|
5
|
+
version: 0.6.0
|
|
6
6
|
homepage: https://pharaoh.so
|
|
7
7
|
user-invocable: true
|
|
8
8
|
metadata: {"emoji": "☥", "tags": ["planning", "architecture", "blast-radius", "pharaoh", "review", "interactive"]}
|
|
@@ -10,12 +10,16 @@ metadata: {"emoji": "☥", "tags": ["planning", "architecture", "blast-radius",
|
|
|
10
10
|
|
|
11
11
|
# Plan Review
|
|
12
12
|
|
|
13
|
+
Architecture-aware plan review before implementation. Adapted from [Garry Tan's planning framework](https://www.youtube.com/watch?v=bMknfKXIFA8) for AI-assisted development.
|
|
14
|
+
|
|
13
15
|
**You are now in plan mode. Do NOT make any code changes. Think, evaluate, and present decisions.**
|
|
14
16
|
|
|
15
17
|
## Document Review
|
|
16
18
|
|
|
17
19
|
If the user provides a document, PRD, prompt, or artifact alongside this command, that IS the plan to review. Apply all review sections to that document. Do not treat it as background context — it is the subject of evaluation.
|
|
18
20
|
|
|
21
|
+
Still run Step 1 (Reconnaissance) even when reviewing a document — always verify the plan against the actual codebase state.
|
|
22
|
+
|
|
19
23
|
## Project Overrides
|
|
20
24
|
|
|
21
25
|
If a `.claude/plan-review.md` file exists in this project, read it now and apply those rules on top of this baseline. Project rules take precedence where they conflict.
|
|
@@ -32,42 +36,40 @@ If a `.claude/plan-review.md` file exists in this project, read it now and apply
|
|
|
32
36
|
|
|
33
37
|
## Step 1: Pharaoh Reconnaissance (Required — do this BEFORE reviewing)
|
|
34
38
|
|
|
35
|
-
Do NOT review from memory or assumptions. Query the actual codebase first
|
|
39
|
+
Do NOT review from memory or assumptions. Query the actual codebase first.
|
|
40
|
+
|
|
41
|
+
### If Pharaoh MCP tools are available:
|
|
36
42
|
|
|
37
43
|
1. `get_codebase_map` — current modules, hot files, dependency graph
|
|
38
44
|
2. `search_functions` for keywords related to the plan — find existing code to reuse/extend
|
|
39
45
|
3. `get_module_context` on affected modules — entry points, patterns, conventions
|
|
40
46
|
4. `query_dependencies` between affected modules — coupling, circular deps
|
|
47
|
+
5. `get_blast_radius` on the primary target of the change — know what breaks
|
|
48
|
+
6. `check_reachability` on the primary target — verify it's actually reachable from entry points before worrying about it
|
|
41
49
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
## Step 1b: Reconnaissance Dashboard
|
|
45
|
-
|
|
46
|
-
After running recon, present a visual summary before proceeding. This shows the user what Pharaoh found.
|
|
50
|
+
### Without Pharaoh (graceful fallback):
|
|
47
51
|
|
|
48
|
-
|
|
52
|
+
1. Search the codebase for files and functions related to the plan (grep, glob)
|
|
53
|
+
2. Read the entry points and module structure of affected areas
|
|
54
|
+
3. Check existing tests for the modules the plan will touch
|
|
55
|
+
4. Trace imports manually to estimate blast radius
|
|
49
56
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
| Signal | Value | Source |
|
|
53
|
-
|--------|-------|--------|
|
|
54
|
-
| Modules affected | N | get_codebase_map |
|
|
55
|
-
| Blast radius | LOW/MED/HIGH + caller count | get_blast_radius |
|
|
56
|
-
| Existing functions found | N matches | search_functions |
|
|
57
|
-
| Cross-module coupling | deps + circular? | query_dependencies |
|
|
57
|
+
Ground every recommendation in what actually exists. If you propose adding something, confirm it doesn't already exist. If you propose changing something, know its blast radius.
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
## Step 2: Mode Selection (MANDATORY — ask before proceeding)
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
**STOP and ask the user which mode before starting the review.** This is a hard gate — do not infer, assume, or skip this question even if the user says "yes", "go ahead", or "yes to all". Present both options and wait for an explicit choice:
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
> **BIG CHANGE or SMALL CHANGE?**
|
|
64
|
+
>
|
|
65
|
+
> - **BIG CHANGE**: Full interactive review, all relevant sections, up to 4 top issues per section
|
|
66
|
+
> - **SMALL CHANGE**: One question per section, only sections 2-4
|
|
64
67
|
|
|
65
|
-
|
|
66
|
-
**SMALL CHANGE**: One question per section, only sections 2-4.
|
|
68
|
+
If the user's response is ambiguous (e.g. "just do it", "yes to all"), ask again: "I need to know — BIG or SMALL change?" Do not proceed to Step 3 without an answer.
|
|
67
69
|
|
|
68
70
|
## Step 3: Review Sections
|
|
69
71
|
|
|
70
|
-
Adapt depth to change size. Skip sections that don't apply.
|
|
72
|
+
Adapt depth to change size. Skip sections that don't apply. **After each section, pause and ask for feedback before moving on.**
|
|
71
73
|
|
|
72
74
|
### Section 1 — Architecture (skip for small/single-file changes)
|
|
73
75
|
|
|
@@ -135,7 +137,7 @@ Number each issue (1, 2, 3...) and letter each option (A, B, C...). Recommended
|
|
|
135
137
|
|
|
136
138
|
## Workflow Rules
|
|
137
139
|
|
|
138
|
-
- After each section, pause and ask for feedback before moving on
|
|
140
|
+
- **After each section, pause and ask for feedback before moving on**
|
|
139
141
|
- Do not assume priorities on timeline or scale
|
|
140
142
|
- If you see a better approach to the entire plan, say so BEFORE section-by-section review
|
|
141
143
|
- Challenge the approach if you see a better one — your job is to find problems I'll regret later
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: audit-tests
|
|
3
|
-
prompt-name: audit-tests
|
|
4
|
-
description: "Classify tests by real value: ceremony versus protection. Mutation score over line coverage — tests that can't detect mutations are theater. Identify tests that prove nothing, tests that duplicate coverage, and gaps where real protection is missing. Produce an actionable audit with keep, rewrite, and delete verdicts."
|
|
5
|
-
version: 0.2.0
|
|
6
|
-
homepage: https://pharaoh.so
|
|
7
|
-
user-invocable: true
|
|
8
|
-
metadata: {"emoji": "☥", "tags": ["test-audit", "mutation-testing", "test-quality", "coverage", "testing"]}
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
# Test Audit
|
|
12
|
-
|
|
13
|
-
Classify tests by whether they actually protect against regressions. Line coverage is vanity — mutation score is truth. A test that can't detect a mutation in the code it covers is theater.
|
|
14
|
-
|
|
15
|
-
## When to Use
|
|
16
|
-
|
|
17
|
-
- Before refactoring a module — know which tests actually protect you
|
|
18
|
-
- After inheriting a codebase — separate real coverage from ceremony
|
|
19
|
-
- When test suite is slow — find tests to delete without losing protection
|
|
20
|
-
- When coverage numbers are high but bugs still ship
|
|
21
|
-
|
|
22
|
-
## Process
|
|
23
|
-
|
|
24
|
-
### 1. Inventory
|
|
25
|
-
|
|
26
|
-
List all test files for the target module or area. For each test file, note:
|
|
27
|
-
|
|
28
|
-
- What production code it exercises
|
|
29
|
-
- Whether it uses mocks or real implementations
|
|
30
|
-
- Approximate assertion count
|
|
31
|
-
|
|
32
|
-
If Pharaoh tools are available, call `get_test_coverage` to see which modules have tests and which don't.
|
|
33
|
-
|
|
34
|
-
### 2. Classify Each Test
|
|
35
|
-
|
|
36
|
-
| Category | Definition | Action |
|
|
37
|
-
|----------|-----------|--------|
|
|
38
|
-
| **Guardian** | Tests real behavior with real code. Would catch a regression. | Keep |
|
|
39
|
-
| **Ceremony** | Passes regardless of code changes. Tests mocks, not behavior. | Rewrite or delete |
|
|
40
|
-
| **Duplicate** | Same behavior tested multiple times across files. | Keep one, delete rest |
|
|
41
|
-
| **Snapshot** | Records current output without asserting correctness. | Evaluate — keep if output matters, delete if not |
|
|
42
|
-
| **Fragile** | Breaks on irrelevant changes (formatting, ordering, timing). | Rewrite to test behavior, not implementation |
|
|
43
|
-
|
|
44
|
-
### 3. Mutation Check
|
|
45
|
-
|
|
46
|
-
For critical tests, mentally (or actually) apply mutations to the code under test:
|
|
47
|
-
|
|
48
|
-
- Change `>` to `>=`
|
|
49
|
-
- Remove an `if` branch
|
|
50
|
-
- Return early
|
|
51
|
-
- Swap function arguments
|
|
52
|
-
- Delete a line
|
|
53
|
-
|
|
54
|
-
**If the test still passes after any of these mutations, it's not testing what you think.**
|
|
55
|
-
|
|
56
|
-
### 4. Gap Analysis
|
|
57
|
-
|
|
58
|
-
Identify code that has:
|
|
59
|
-
- No tests at all
|
|
60
|
-
- Only ceremony tests (effectively no real coverage)
|
|
61
|
-
- Tests that mock the thing they're supposed to verify
|
|
62
|
-
|
|
63
|
-
Prioritize gaps by risk: code in hot paths, security-sensitive code, and code with high blast radius (use `get_blast_radius` if available) needs real tests first.
|
|
64
|
-
|
|
65
|
-
### 5. Produce Audit Report
|
|
66
|
-
|
|
67
|
-
For each test file:
|
|
68
|
-
|
|
69
|
-
- **Verdict:** KEEP, REWRITE, or DELETE
|
|
70
|
-
- **Reason:** one sentence explaining why
|
|
71
|
-
- **Priority:** if REWRITE, how urgent (based on risk of the code it covers)
|
|
72
|
-
|
|
73
|
-
## What Makes a Test Valuable
|
|
74
|
-
|
|
75
|
-
| Valuable | Not valuable |
|
|
76
|
-
|----------|-------------|
|
|
77
|
-
| Tests behavior through public API | Tests private implementation details |
|
|
78
|
-
| Uses real dependencies | Mocks the thing under test |
|
|
79
|
-
| Has hardcoded expected values | Computes expected values from production code |
|
|
80
|
-
| Fails when behavior changes | Passes regardless of code changes |
|
|
81
|
-
| Describes WHAT should happen | Describes HOW it's currently implemented |
|
|
82
|
-
|
|
83
|
-
## Key Principles
|
|
84
|
-
|
|
85
|
-
- **Mutation score > line coverage** — a test that can't detect mutations is worth zero
|
|
86
|
-
- **One real integration test > ten mock-heavy unit tests** — mocks hide bugs
|
|
87
|
-
- **Hardcoded expectations** — tests that compute their expected output prove nothing
|
|
88
|
-
- **Delete with confidence** — removing a ceremony test loses nothing and speeds up the suite
|
|
89
|
-
- **If you can't describe what makes a test fail, it's worthless**
|