@pharaoh-so/mcp 0.3.1 → 0.3.3

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/README.md CHANGED
@@ -26,7 +26,7 @@ This displays a device code and a URL. Open the URL on **any device** (phone, la
26
26
  ### Step 2 — Add to Claude Code
27
27
 
28
28
  ```bash
29
- npx @pharaoh-so/mcp --setup
29
+ npx @pharaoh-so/mcp
30
30
  ```
31
31
 
32
32
  Verify the connection:
@@ -43,7 +43,7 @@ If you previously added Pharaoh as an SSE server, remove it first:
43
43
 
44
44
  ```bash
45
45
  claude mcp remove pharaoh
46
- npx @pharaoh-so/mcp --setup
46
+ npx @pharaoh-so/mcp
47
47
  ```
48
48
 
49
49
  ## How It Works
@@ -203,7 +203,7 @@ npx @pharaoh-so/mcp
203
203
  Make sure you added it with the correct command:
204
204
 
205
205
  ```bash
206
- npx @pharaoh-so/mcp --setup
206
+ npx @pharaoh-so/mcp
207
207
  ```
208
208
 
209
209
  Note the `--` separator between `pharaoh` and `npx`.
package/dist/helpers.d.ts CHANGED
@@ -4,13 +4,14 @@
4
4
  */
5
5
  import type { TokenResponse } from "./auth.js";
6
6
  import type { Credentials } from "./credentials.js";
7
+ /** The npx command users run to set up Pharaoh. Single source of truth for all output. */
8
+ export declare const NPX_COMMAND = "npx @pharaoh-so/mcp";
7
9
  /** Write one or more lines to stderr. */
8
10
  export declare function printLines(...lines: string[]): void;
9
11
  /** Parse CLI arguments. */
10
12
  export declare function parseArgs(argv?: string[]): {
11
13
  server: string;
12
14
  logout: boolean;
13
- setup: boolean;
14
15
  };
15
16
  export declare function printUsage(): void;
16
17
  /**
@@ -23,11 +24,6 @@ export declare function resolveSseUrl(tokenSseUrl: string | undefined, server: s
23
24
  export declare function tokenToCredentials(token: TokenResponse, sseUrl: string): Credentials;
24
25
  /** Format remaining TTL as human-readable string (e.g. "5d 12h"). */
25
26
  export declare function formatTtl(expiresAt: string): string;
26
- /**
27
- * Print setup instructions for Claude Code. Called in interactive mode
28
- * after auth completes (or when credentials already exist).
29
- */
30
- export declare function printSetupInstructions(): void;
31
27
  /** Format a credential identity string (e.g. "alice (my-org)"). */
32
28
  export declare function formatIdentity(creds: Credentials): string;
33
29
  /**
package/dist/helpers.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import { isExpired } from "./credentials.js";
2
2
  const DEFAULT_SERVER = "https://mcp.pharaoh.so";
3
+ /** The npx command users run to set up Pharaoh. Single source of truth for all output. */
4
+ export const NPX_COMMAND = "npx @pharaoh-so/mcp";
3
5
  /** Write one or more lines to stderr. */
4
6
  export function printLines(...lines) {
5
7
  process.stderr.write(lines.join("\n") + "\n");
@@ -8,7 +10,6 @@ export function printLines(...lines) {
8
10
  export function parseArgs(argv = process.argv.slice(2)) {
9
11
  let server = DEFAULT_SERVER;
10
12
  let logout = false;
11
- let setup = false;
12
13
  for (let i = 0; i < argv.length; i++) {
13
14
  if (argv[i] === "--server" && argv[i + 1]) {
14
15
  server = argv[i + 1];
@@ -17,9 +18,6 @@ export function parseArgs(argv = process.argv.slice(2)) {
17
18
  else if (argv[i] === "--logout") {
18
19
  logout = true;
19
20
  }
20
- else if (argv[i] === "--setup") {
21
- setup = true;
22
- }
23
21
  }
24
22
  // Strip trailing slash
25
23
  server = server.replace(/\/+$/, "");
@@ -41,10 +39,10 @@ export function parseArgs(argv = process.argv.slice(2)) {
41
39
  printLines(`Pharaoh: --server is not a valid URL: ${server}`);
42
40
  process.exit(1);
43
41
  }
44
- return { server, logout, setup };
42
+ return { server, logout };
45
43
  }
46
44
  export function printUsage() {
47
- printLines("Usage: pharaoh-mcp [options]", "", "Options:", " --setup Full install: auth, register MCP, install skills (start here)", " --server <url> Pharaoh server URL (default: https://mcp.pharaoh.so)", " --logout Clear stored credentials and exit", " --install-skills Force reinstall Pharaoh skills (Claude Code + OpenClaw)", " --help, -h Show this help", "", "Get started:", " npx @pharaoh-so/mcp --setup", "");
45
+ printLines("Usage: pharaoh-mcp [options]", "", "Options:", " --server <url> Pharaoh server URL (default: https://mcp.pharaoh.so)", " --logout Clear stored credentials and exit", " --install-skills Force reinstall Pharaoh skills (Claude Code + OpenClaw)", " --help, -h Show this help", "", "Get started:", ` ${NPX_COMMAND}`, "");
48
46
  }
49
47
  /**
50
48
  * Validate that a server-supplied SSE URL shares the same origin as the configured server.
@@ -95,13 +93,6 @@ export function formatTtl(expiresAt) {
95
93
  return `${hours}h`;
96
94
  return `${Math.floor(remainingMs / 60_000)}m`;
97
95
  }
98
- /**
99
- * Print setup instructions for Claude Code. Called in interactive mode
100
- * after auth completes (or when credentials already exist).
101
- */
102
- export function printSetupInstructions() {
103
- printLines("", "┌───────────────────────────────────────────────────────┐", "│ To register Pharaoh in Claude Code, run: │", "│ npx @pharaoh-so/mcp --setup │", "│ │", "│ This removes stale entries, registers the MCP │", "│ server globally, and installs all skills. │", "└───────────────────────────────────────────────────────┘", "");
104
- }
105
96
  /** Format a credential identity string (e.g. "alice (my-org)"). */
106
97
  export function formatIdentity(creds) {
107
98
  return [
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@
12
12
  */
13
13
  import { pollForToken, printActivationPrompt, printAuthSuccess, requestDeviceCode, } from "./auth.js";
14
14
  import { deleteCredentials, isExpired, readCredentials, writeCredentials } from "./credentials.js";
15
- import { formatIdentity, formatTtl, parseArgs, printLines, printSetupInstructions, printUsage, resolveSseUrl, tokenToCredentials, } from "./helpers.js";
15
+ import { NPX_COMMAND, formatTtl, parseArgs, printLines, printUsage, resolveSseUrl, tokenToCredentials, } from "./helpers.js";
16
16
  import { runInstallSkills } from "./install-skills.js";
17
17
  import { startProxy, TenantSuspendedError, TokenExpiredError } from "./proxy.js";
18
18
  async function main() {
@@ -33,7 +33,7 @@ async function main() {
33
33
  runInstallSkills();
34
34
  return;
35
35
  }
36
- const { server, logout, setup } = parseArgs(args);
36
+ const { server, logout } = parseArgs(args);
37
37
  if (logout) {
38
38
  deleteCredentials();
39
39
  printLines("Pharaoh: credentials cleared");
@@ -41,49 +41,13 @@ async function main() {
41
41
  }
42
42
  const creds = readCredentials();
43
43
  const isInteractive = Boolean(process.stdin.isTTY);
44
- // ── Setup mode (--setup): full automated install ──
45
- // Auth → remove stale → register MCP → install skills → done.
46
- if (setup) {
47
- // Authenticate if needed
48
- let activeCreds = creds && !isExpired(creds) ? creds : null;
49
- if (activeCreds) {
50
- printLines(`Pharaoh: authenticated as ${formatIdentity(activeCreds)} — token valid for ${formatTtl(activeCreds.expires_at)}`);
51
- }
52
- else {
53
- printLines("Pharaoh: starting device authorization...");
54
- const deviceCode = await requestDeviceCode(server);
55
- printActivationPrompt(deviceCode.user_code, deviceCode.verification_uri);
56
- const token = await pollForToken(server, deviceCode.device_code, deviceCode.interval);
57
- if (token.provisional) {
58
- printLines(`Pharaoh: provisional access — install the GitHub App to map your repos: ${token.install_url ?? ""}`);
59
- }
60
- const sseUrl = resolveSseUrl(token.sse_url, server);
61
- const newCreds = tokenToCredentials(token, sseUrl);
62
- writeCredentials(newCreds);
63
- activeCreds = newCreds;
64
- printAuthSuccess(token.github_login ?? null, token.tenant_name ?? null, token.repos?.length ?? 0);
65
- }
66
- // Register MCP server in Claude Code
67
- const { runSetup } = await import("./setup.js");
68
- runSetup();
69
- // Install skills
70
- runInstallSkills();
71
- printLines("", "Pharaoh is ready. Start a new Claude Code conversation and ask:", ' "What modules does this codebase have?"', "");
72
- process.exit(0);
73
- }
74
44
  // ── Interactive mode (user running in a terminal) ──
75
- // Authenticate if needed, print setup instructions, and exit.
76
- // The proxy is useless without Claude Code on the other end of stdin.
45
+ // Full setup every time: fresh auth register MCP → install skills → done.
46
+ // Running `npx @pharaoh-so/mcp` is the only command a user needs.
77
47
  if (isInteractive) {
78
- if (creds && !isExpired(creds)) {
79
- printLines(`Pharaoh: authenticated as ${formatIdentity(creds)} — token valid for ${formatTtl(creds.expires_at)}, ${creds.repos.length} repo${creds.repos.length === 1 ? "" : "s"} connected`);
80
- // Ensure skills are installed/up-to-date on every interactive run
81
- runInstallSkills();
82
- printSetupInstructions();
83
- process.exit(0);
84
- }
85
- // No valid credentials — run device flow
86
- printLines("Pharaoh: no valid credentials — starting device authorization");
48
+ // Always re-authenticate for a fresh session
49
+ printLines("Pharaoh: starting device authorization...");
50
+ deleteCredentials();
87
51
  const deviceCode = await requestDeviceCode(server);
88
52
  printActivationPrompt(deviceCode.user_code, deviceCode.verification_uri);
89
53
  const token = await pollForToken(server, deviceCode.device_code, deviceCode.interval);
@@ -94,15 +58,18 @@ async function main() {
94
58
  const newCreds = tokenToCredentials(token, sseUrl);
95
59
  writeCredentials(newCreds);
96
60
  printAuthSuccess(token.github_login ?? null, token.tenant_name ?? null, token.repos?.length ?? 0);
97
- // Auto-install skills to detected platforms (Claude Code, OpenClaw)
61
+ // Register MCP server in Claude Code (remove stale + add fresh)
62
+ const { runSetup } = await import("./setup.js");
63
+ runSetup();
64
+ // Install skills to all detected platforms
98
65
  runInstallSkills();
99
- printSetupInstructions();
66
+ printLines("", "Pharaoh is ready. Start a new Claude Code conversation and ask:", ' "What modules does this codebase have?"', "");
100
67
  process.exit(0);
101
68
  }
102
69
  // ── Proxy mode (Claude Code spawned us as a stdio MCP server) ──
103
70
  // If no credentials, we can't run the device flow (no TTY for user interaction).
104
71
  if (!creds || isExpired(creds)) {
105
- printLines("Pharaoh: no valid credentials — cannot start proxy.", "Run this command first to authenticate:", " npx @pharaoh-so/mcp", "");
72
+ printLines("Pharaoh: no valid credentials — cannot start proxy.", "Run this command first to authenticate:", ` ${NPX_COMMAND}`, "");
106
73
  process.exit(1);
107
74
  }
108
75
  // Valid credentials — ensure skills are installed before starting proxy
@@ -119,7 +86,7 @@ async function main() {
119
86
  }
120
87
  catch (err) {
121
88
  if (err instanceof TokenExpiredError) {
122
- printLines("Pharaoh: token expired or revoked.", "Run this command to re-authenticate:", " npx @pharaoh-so/mcp", "");
89
+ printLines("Pharaoh: token expired or revoked.", "Run this command to re-authenticate:", ` ${NPX_COMMAND}`, "");
123
90
  deleteCredentials();
124
91
  process.exit(1);
125
92
  }
@@ -258,7 +258,7 @@ export function runInstallSkills(home = homedir()) {
258
258
  " • Claude Code — install from https://claude.ai/download",
259
259
  " • OpenClaw — install from https://openclaw.dev/install",
260
260
  "",
261
- "Once installed, re-run: npx @pharaoh-so/mcp --install-skills",
261
+ "Once installed, re-run: npx @pharaoh-so/mcp",
262
262
  "",
263
263
  ].join("\n"));
264
264
  }
package/dist/setup.js CHANGED
@@ -3,10 +3,10 @@
3
3
  *
4
4
  * Full automated install: authenticates via device flow, removes stale MCP
5
5
  * entries, registers Pharaoh as a global stdio MCP server, and installs skills.
6
- * One command does everything: `npx @pharaoh-so/mcp --setup`
6
+ * One command does everything: `npx @pharaoh-so/mcp`
7
7
  */
8
8
  import { execFileSync } from "node:child_process";
9
- import { printLines } from "./helpers.js";
9
+ import { NPX_COMMAND, printLines } from "./helpers.js";
10
10
  /** Check if `claude` CLI is available in PATH. */
11
11
  function hasClaude() {
12
12
  try {
@@ -48,7 +48,7 @@ function runClaude(args) {
48
48
  */
49
49
  export function runSetup() {
50
50
  if (!hasClaude()) {
51
- printLines("Pharaoh: Claude Code CLI not found.", "", "Install Claude Code first: https://claude.ai/download", "Then re-run: npx @pharaoh-so/mcp --setup", "");
51
+ printLines("Pharaoh: Claude Code CLI not found.", "", "Install Claude Code first: https://claude.ai/download", `Then re-run: ${NPX_COMMAND}`, "");
52
52
  return false;
53
53
  }
54
54
  printLines("Pharaoh: setting up...");
@@ -66,7 +66,7 @@ export function runSetup() {
66
66
  "@pharaoh-so/mcp",
67
67
  ]);
68
68
  if (!added) {
69
- printLines("Pharaoh: failed to register MCP server.", "Try manually: npx @pharaoh-so/mcp --setup", "");
69
+ printLines("Pharaoh: failed to register MCP server.", `Try manually: ${NPX_COMMAND}`, "");
70
70
  return false;
71
71
  }
72
72
  printLines("Pharaoh: registered as global MCP server (scope: user)");
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.1",
4
+ "version": "0.3.3",
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",
@@ -73,7 +73,7 @@ Full docs at [pharaoh.so/docs](https://pharaoh.so/docs).
73
73
 
74
74
  **CLI** (Claude Code, OpenClaw — works everywhere):
75
75
  ```
76
- npx @pharaoh-so/mcp --setup
76
+ npx @pharaoh-so/mcp
77
77
  ```
78
78
 
79
79
  **URL** (Claude.ai, Cursor, ChatGPT — paste in settings):
@@ -1,62 +1,287 @@
1
1
  ---
2
2
  name: review
3
3
  prompt-name: review-with-pharaoh
4
- description: "Architecture-aware pre-PR code review using Pharaoh codebase knowledge graph. Four-phase workflow: context gathering with module structure and blast radius, risk assessment with regression scoring and wiring checks, spec alignment against vision docs, and a final verdict of SHIP / SHIP WITH CHANGES / BLOCK. Auto-block rules for unreachable exports, circular dependencies, high regression risk, and spec violations."
5
- version: 0.2.0
4
+ description: "The definitive code review. Five-phase workflow: git context detection (worktree, branch, base, changed files), Pharaoh recon (architecture map, module context, blast radius in one call), parallel specialized agent dispatch (code quality, error handling, test coverage, type design), cross-model adversarial review for security-sensitive changes, and a final synthesized verdict of SHIP / SHIP WITH CHANGES / BLOCK. Always architecture-aware, always branch-aware."
5
+ version: 0.3.0
6
6
  homepage: https://pharaoh.so
7
7
  user-invocable: true
8
- metadata: {"emoji": "☥", "tags": ["code-review", "pull-request", "architecture", "pharaoh", "regression-risk", "spec-alignment"]}
8
+ metadata: {"emoji": "☥", "tags": ["code-review", "pull-request", "architecture", "pharaoh", "multi-agent", "adversarial-review", "regression-risk", "spec-alignment"]}
9
9
  ---
10
10
 
11
11
  # Review with Pharaoh
12
12
 
13
- Architecture-aware pre-PR review. Uses `review-with-pharaoh` a 4-phase workflow that assesses blast radius, regression risk, wiring integrity, duplication, and spec alignment. Produces a final verdict: SHIP, SHIP WITH CHANGES, or BLOCK.
13
+ The definitive code review. Architecture-aware, branch-aware, multi-agent, adversarial. Five phases that combine Pharaoh's knowledge graph with parallel specialized reviewers and an independent cross-model second opinion.
14
+
15
+ Final verdict: **SHIP** / **SHIP WITH CHANGES** / **BLOCK**
14
16
 
15
17
  ## When to Use
16
18
 
17
- Invoke before merging any pull request. Use it when reviewing changes that touch shared modules, export new functions, modify core data flows, or claim to implement a spec.
19
+ Before merging any branch. Before opening any PR. When reviewing changes that touch shared modules, export new functions, modify core data flows, or claim to implement a spec.
18
20
 
19
- ## Workflow
21
+ ---
20
22
 
21
- ### Phase 1 — Context
23
+ ## Phase 0Git Context
22
24
 
23
- 1. For each touched module, call `get_module_context` to understand its structure.
24
- 2. For each touched module, call `get_blast_radius` to identify downstream impact.
25
- 3. Call `query_dependencies` between the touched modules to map coupling.
25
+ **Goal:** Know exactly what changed and where you are. This phase is mandatory and runs before anything else.
26
26
 
27
- ### Phase 2 Risk Assessment
27
+ 1. Detect the current environment:
28
+ ```bash
29
+ git rev-parse --show-toplevel # repo root (may be a worktree)
30
+ git worktree list # detect if running in a worktree
31
+ git branch --show-current # current branch name
32
+ git log --oneline -1 # latest commit
33
+ ```
28
34
 
29
- 4. Call `get_regression_risk` for the target repository to assess overall change risk.
30
- 5. Call `check_reachability` for new exports in the touched modules — are they wired?
31
- 6. Call `get_consolidation_opportunities` for the repository to check for duplicated logic.
35
+ 2. Determine the base branch (what this branch diverged from):
36
+ ```bash
37
+ git merge-base HEAD main # or master, or whatever the default is
38
+ ```
32
39
 
33
- ### Phase 3 Spec Alignment
40
+ 3. Collect the full changeset from the base:
41
+ ```bash
42
+ git diff --name-only $(git merge-base HEAD main)...HEAD # all changed files
43
+ git diff --stat $(git merge-base HEAD main)...HEAD # summary stats
44
+ git log --oneline $(git merge-base HEAD main)..HEAD # all commits on this branch
45
+ ```
34
46
 
35
- 7. Call `get_vision_gaps` for the repository to verify changes align with specs.
47
+ 4. Also check for uncommitted work:
48
+ ```bash
49
+ git diff --name-only # unstaged changes
50
+ git diff --cached --name-only # staged but uncommitted
51
+ ```
36
52
 
37
- ### Phase 4 Verdict
53
+ 5. Extract the **touched modules** from the changed file paths. Group files by their top-level directory or module boundary. These module names feed Phase 1.
38
54
 
39
- Produce a review with:
40
- - **Architecture impact:** modules affected, dependency changes, blast radius
41
- - **Risk assessment:** regression risk level, volatile modules touched
42
- - **Wiring check:** are all new exports reachable from entry points?
43
- - **Duplication check:** does new code duplicate existing logic?
44
- - **Spec alignment:** do changes match or drift from vision specs?
55
+ **Output of Phase 0:** Branch name, base branch, commit count, list of changed files, list of touched modules, and whether there's uncommitted work.
45
56
 
46
- Final verdict: **SHIP** / **SHIP WITH CHANGES** / **BLOCK**
57
+ ---
58
+
59
+ ## Phase 1 — Pharaoh Recon
60
+
61
+ **Goal:** Get the full architectural picture in one call. Do NOT skip this phase — it is what makes this review architecture-aware instead of just a code diff review.
62
+
63
+ Call `pharaoh_recon` with:
64
+ - **repo:** The repository name
65
+ - **include_map:** `true`
66
+ - **modules:** The touched modules from Phase 0 (up to 5)
67
+ - **blast_radius:** The most critical changed files/functions as blast radius targets (up to 3). Pick the files with the most downstream risk — entry points, shared utilities, exported APIs.
68
+ - **dependencies:** Pairs of touched modules to trace coupling between (up to 3)
69
+
70
+ Then call these additional tools for data recon doesn't cover:
71
+ - `get_regression_risk` — overall change risk score for the repo
72
+ - `get_consolidation_opportunities` — duplicate logic the PR may introduce
73
+ - `check_reachability` — are new exports wired to entry points?
74
+ - `get_vision_gaps` — do changes align with or drift from specs?
75
+
76
+ **Output of Phase 1:** Architecture map, module profiles for every touched module, blast radius for high-risk changes, dependency paths between coupled modules, regression risk level, duplication findings, reachability status, and spec alignment.
77
+
78
+ ---
79
+
80
+ ## Phase 2 — Parallel Specialized Review
81
+
82
+ **Goal:** Deep-dive the actual code changes from multiple expert angles simultaneously. Launch these as **parallel subagents** — they are independent and should run concurrently.
83
+
84
+ ### Determine which reviewers to dispatch
85
+
86
+ | Agent | When to dispatch | Focus |
87
+ |-------|-----------------|-------|
88
+ | **Code Reviewer** | Always | Bugs, logic errors, CLAUDE.md compliance, code quality. Confidence-filtered (only issues >= 80/100). |
89
+ | **Security Reviewer** | When changes touch auth, encryption, tokens, tenant isolation, data access, billing, webhooks, Cypher queries, or any security-sensitive surface. Also dispatch when Phase 1 regression risk is HIGH. | OWASP Top 10, injection vectors, access control bypasses, tenant isolation violations, cryptographic misuse, secret exposure, plus project-specific security rules. See checklist below. |
90
+ | **Silent Failure Hunter** | When changes touch error handling, catch blocks, fallback logic, API calls, or any code that could suppress errors | Silent failures, broad catches, swallowed errors, missing user feedback, unjustified fallbacks. |
91
+ | **Test Analyzer** | When test files are changed, or when new functionality lacks corresponding tests | Behavioral coverage gaps, brittle tests, missing edge cases, tests that prove nothing. |
92
+ | **Type Design Analyzer** | When new types/interfaces are introduced or existing types are modified | Encapsulation, invariant expression, invariant enforcement. Rates each type 1-10 on four axes. |
93
+
94
+ ### Security Reviewer — Checklist
95
+
96
+ The Security Reviewer agent runs a systematic audit against two layers: universal web security (OWASP) and project-specific invariants.
97
+
98
+ **Layer 1 — OWASP Top 10 + Common Vulnerabilities:**
99
+ - **Injection:** SQL/Cypher injection, command injection, XSS (reflected/stored/DOM), template injection
100
+ - **Broken auth:** Hardcoded credentials, weak token generation, missing expiry, session fixation
101
+ - **Broken access control:** Missing authorization checks, IDOR, privilege escalation, path traversal
102
+ - **Cryptographic failures:** Weak algorithms, plaintext secrets, missing encryption at rest/transit, key exposure
103
+ - **Security misconfiguration:** Permissive CORS, verbose error messages leaking internals, debug endpoints in production
104
+ - **Vulnerable dependencies:** Known CVEs in direct dependencies (check against changed package.json/lockfile)
105
+ - **SSRF:** Unvalidated URLs in fetch/request calls, redirect chains
106
+ - **Logging & monitoring:** Sensitive data in logs, missing audit trails for privileged operations
107
+
108
+ **Layer 2 — Project-Specific Security Rules (from CLAUDE.md):**
109
+ - Every Cypher query takes `repo` as first parameter — no unanchored MATCH clauses
110
+ - `validateRepoOwnership()` runs before every tool handler
111
+ - No default/fallback repo values — repo always from tenant's Postgres `tenant_repos`
112
+ - Tokens stored as SHA-256 hashes, never plaintext
113
+ - GitHub tokens encrypted at rest (AES-256-GCM with per-tenant HKDF-derived keys)
114
+ - Webhook signatures verified on every request (`PHARAOH_GITHUB_WEBHOOK_SECRET`)
115
+ - Org membership re-checked on every token refresh
116
+ - Tenant Neo4j users get `reader` role only — graph writes use admin connection
117
+ - Rate limiting enforced per tenant, not per user
118
+ - Neo4j admin credentials never leave server-side env vars
119
+
120
+ **Detection triggers (auto-dispatch when changed files match):**
121
+ - `src/auth/**`, `src/crypto/**` — authentication, encryption
122
+ - `src/mcp/server.ts`, `src/mcp/tenant-resolver.ts` — session management, tenant isolation
123
+ - `src/mcp/neo4j-queries.ts` — Cypher query construction
124
+ - `src/stripe/**`, `src/web/routes/billing.ts` — payment flows
125
+ - `src/github/webhooks.ts`, `src/web/routes/webhooks.ts` — webhook verification
126
+ - `src/db/**` — database access, schema changes
127
+ - `src/upload/**` — file upload validation
128
+ - Any file containing `validateRepoOwnership`, `runQuery`, `encryptProperty`, `verifyWebhookSignature`
129
+
130
+ **Output format:** Each finding must include:
131
+ 1. Vulnerability class (e.g., "Cypher Injection", "Missing Ownership Check")
132
+ 2. Severity: CRITICAL / HIGH / MEDIUM
133
+ 3. Affected file:line
134
+ 4. Attack scenario: how an attacker would exploit this
135
+ 5. Remediation: specific code change required
136
+
137
+ ### How to dispatch each agent
138
+
139
+ For each agent, launch a subagent (via the Agent tool) with:
140
+ 1. The **git diff** of the relevant changed files (not the full session history)
141
+ 2. The **Pharaoh context** from Phase 1 (architecture map, blast radius, module profiles) — this is what makes these agents architecture-aware
142
+ 3. The **CLAUDE.md rules** relevant to the review (testing requirements, security non-negotiables, code style)
143
+ 4. A clear instruction to focus ONLY on changed code, not pre-existing issues
144
+ 5. For the **Security Reviewer** specifically: include the full Layer 2 checklist above and the list of security-sensitive file paths so it knows the project's threat model
145
+
146
+ Each agent returns a structured report with findings categorized by severity:
147
+ - **CRITICAL** (90-100): Must fix before merge
148
+ - **IMPORTANT** (80-89): Should fix before merge
149
+ - **SUGGESTION** (70-79): Consider for a follow-up
150
+
151
+ ### What NOT to dispatch
152
+
153
+ - **Comment Analyzer** and **Code Simplifier** are polish agents. Do not include them in the review — they distract from correctness. Run them separately if wanted.
154
+ - Do not dispatch agents for trivial changes (typo fixes, dependency bumps, config changes). If Phase 0 shows < 20 lines changed across non-test files, skip Phase 2 entirely and go straight to Phase 4.
155
+
156
+ ---
157
+
158
+ ## Phase 3 — Adversarial Review
159
+
160
+ **Goal:** Independent second opinion on security-sensitive changes. A different agent evaluates the code fresh, without knowledge of your reasoning.
161
+
162
+ ### When to trigger
163
+
164
+ Trigger Phase 3 when ANY of these are true:
165
+ - Changes touch **auth, encryption, access control, token handling, or session management**
166
+ - Changes touch **tenant isolation, query construction, or data access patterns**
167
+ - Changes touch **billing, subscription management, or payment flows**
168
+ - Changes modify **webhook verification or signature checking**
169
+ - Regression risk from Phase 1 is **HIGH**
170
+ - You are not confident about a specific change's correctness
171
+
172
+ If none of these triggers are met, **skip Phase 3** and proceed to Phase 4.
173
+
174
+ ### How to run
47
175
 
48
- Auto-block triggers (any of these = BLOCK):
49
- - Unreachable exports (new code with zero callers)
176
+ 1. **Prepare a review package** do NOT send your session history:
177
+ - The changed files (full diff or complete file contents)
178
+ - What the code does and why it was changed (1-2 sentences)
179
+ - Security constraints from CLAUDE.md (tenant isolation rules, encryption requirements, etc.)
180
+ - Specific concerns you want the reviewer to focus on
181
+
182
+ 2. **Dispatch to an independent subagent** with instructions to evaluate the code fresh and assign verdicts:
183
+
184
+ | Verdict | Meaning |
185
+ |---------|---------|
186
+ | **AGREE** | Implementation is correct for the stated concern |
187
+ | **DISAGREE** | Concrete issue identified with evidence and suggested fix |
188
+ | **CONTEXT** | Cannot determine correctness — needs more information |
189
+
190
+ 3. **Evaluate findings:**
191
+ - AGREE items: no action
192
+ - DISAGREE items: verify against actual code. If confirmed, it becomes a CRITICAL finding. If the reviewer lacked context, document why the current approach is correct.
193
+ - CONTEXT items: provide the missing information and note it in the review output
194
+
195
+ ---
196
+
197
+ ## Phase 4 — Synthesis & Verdict
198
+
199
+ **Goal:** Merge all findings into a single, actionable review. No raw dumps — synthesize.
200
+
201
+ ### Structure the output as:
202
+
203
+ ```markdown
204
+ # Review: [branch-name] → [base-branch]
205
+
206
+ **[X] commits | [Y] files changed | [Z] modules touched**
207
+ **Worktree:** [path] (or "main repo")
208
+
209
+ ---
210
+
211
+ ## Architecture Impact
212
+ - Modules affected: [list with blast radius numbers]
213
+ - Dependency changes: [new coupling, removed coupling]
214
+ - Highest blast radius: [module/function] → [N downstream callers across M modules]
215
+
216
+ ## Risk Assessment
217
+ - Regression risk: [LOW / MEDIUM / HIGH] — [one-line reason]
218
+ - Volatile modules touched: [list, if any]
219
+ - Wiring status: [all new exports reachable? / N unreachable exports found]
220
+
221
+ ## Code Quality ([N] findings)
222
+
223
+ ### Critical ([count])
224
+ - [finding with file:line, source agent, and fix]
225
+
226
+ ### Important ([count])
227
+ - [finding with file:line, source agent, and fix]
228
+
229
+ ### Suggestions ([count])
230
+ - [finding with file:line]
231
+
232
+ ## Security ([N] findings, or "No security-sensitive changes")
233
+ - [Security reviewer findings with vulnerability class, severity, file:line, attack scenario, and remediation]
234
+ - [Or: "Security reviewer not dispatched — no security-sensitive files in changeset"]
235
+
236
+ ## Test Coverage
237
+ - [Test analyzer summary — gaps, quality issues, positive observations]
238
+
239
+ ## Spec Alignment
240
+ - [Vision gaps introduced or resolved]
241
+
242
+ ## Adversarial Review
243
+ - [Phase 3 results, or "Skipped — no security-sensitive changes detected"]
244
+
245
+ ---
246
+
247
+ ## Verdict: [SHIP / SHIP WITH CHANGES / BLOCK]
248
+
249
+ [If not SHIP: numbered list of specific required changes before merge]
250
+ ```
251
+
252
+ ### Auto-block triggers (any of these = BLOCK)
253
+
254
+ - Any CRITICAL security finding (injection, broken access control, tenant isolation violation, secret exposure)
255
+ - Unreachable exports (new public code with zero callers)
50
256
  - New circular dependencies between modules
51
257
  - HIGH regression risk without corresponding test coverage
52
258
  - Vision spec violations (building against spec intent)
259
+ - Any CRITICAL finding from Phase 2 or Phase 3 that is confirmed and unfixed
260
+ - DISAGREE verdict from adversarial review on security-sensitive code, confirmed after verification
261
+ - Unanchored Cypher query (MATCH without traversing through `Repo {name: $repo}`)
262
+ - Missing `validateRepoOwnership()` on a new tool handler
263
+
264
+ ### SHIP WITH CHANGES triggers
265
+
266
+ - IMPORTANT findings that are confirmed but non-blocking
267
+ - Test coverage gaps for new functionality
268
+ - Duplication that should be consolidated in a follow-up
269
+ - Spec drift that is intentional but should be documented
270
+
271
+ ### SHIP triggers
272
+
273
+ - No CRITICAL or confirmed IMPORTANT findings
274
+ - All new exports are reachable
275
+ - Regression risk is LOW or MEDIUM with adequate test coverage
276
+ - Spec alignment is clean or intentionally divergent with documentation
277
+
278
+ ---
279
+
280
+ ## Quick Mode
53
281
 
54
- ## Output
282
+ For small changes (< 50 lines, single module, no security surface):
283
+ - Run Phase 0 + Phase 1 + Phase 4 only
284
+ - Skip Phase 2 (parallel agents) and Phase 3 (adversarial)
285
+ - Still architecture-aware, just faster
55
286
 
56
- A structured review containing:
57
- - Architecture impact summary with specific modules and blast radius numbers
58
- - Risk level (LOW / MEDIUM / HIGH) with data backing
59
- - Wiring status for all new exports
60
- - Duplication findings with affected modules
61
- - Spec alignment verdict
62
- - Final verdict (SHIP / SHIP WITH CHANGES / BLOCK) with specific required changes if not SHIP
287
+ Explicitly opt in with: `/review quick`