diff --git a/codex/SKILL.md b/codex/SKILL.md
index 4d98da6138..a6bae60aa5 100644
--- a/codex/SKILL.md
+++ b/codex/SKILL.md
@@ -1092,7 +1092,7 @@ assumptions, catches things you might miss. Present its output faithfully, not s
## Step 0: Check codex binary
```bash
-CODEX_BIN=$(which codex 2>/dev/null || echo "")
+CODEX_BIN=$(command -v codex || echo "")
[ -z "$CODEX_BIN" ] && echo "NOT_FOUND" || echo "FOUND: $CODEX_BIN"
```
diff --git a/codex/SKILL.md.tmpl b/codex/SKILL.md.tmpl
index c311fc80b7..f265062cff 100644
--- a/codex/SKILL.md.tmpl
+++ b/codex/SKILL.md.tmpl
@@ -42,7 +42,7 @@ assumptions, catches things you might miss. Present its output faithfully, not s
## Step 0: Check codex binary
```bash
-CODEX_BIN=$(which codex 2>/dev/null || echo "")
+CODEX_BIN=$(command -v codex || echo "")
[ -z "$CODEX_BIN" ] && echo "NOT_FOUND" || echo "FOUND: $CODEX_BIN"
```
diff --git a/design-consultation/SKILL.md b/design-consultation/SKILL.md
index 20c0fc1a55..ef7c1fb950 100644
--- a/design-consultation/SKILL.md
+++ b/design-consultation/SKILL.md
@@ -1345,7 +1345,7 @@ If user chooses B, skip this step and continue.
**Check Codex availability:**
```bash
-which codex 2>/dev/null && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
+command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
```
**If Codex is available**, launch both voices simultaneously:
diff --git a/design-review/SKILL.md b/design-review/SKILL.md
index c58ce6719d..ee8d1673df 100644
--- a/design-review/SKILL.md
+++ b/design-review/SKILL.md
@@ -1965,7 +1965,7 @@ Record baseline design score and AI slop score at end of Phase 6.
**Check Codex availability:**
```bash
-which codex 2>/dev/null && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
+command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
```
**If Codex is available**, launch both voices simultaneously:
diff --git a/office-hours/SKILL.md b/office-hours/SKILL.md
index ece2ab89df..ec4f2eb150 100644
--- a/office-hours/SKILL.md
+++ b/office-hours/SKILL.md
@@ -1470,7 +1470,7 @@ Use AskUserQuestion to confirm. If the user disagrees with a premise, revise und
**Binary check first:**
```bash
-which codex 2>/dev/null && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
+command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
```
Use AskUserQuestion (regardless of codex availability):
@@ -1740,7 +1740,7 @@ The screenshot file at `/tmp/gstack-sketch.png` can be referenced by downstream
After the wireframe is approved, offer outside design perspectives:
```bash
-which codex 2>/dev/null && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
+command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
```
If Codex is available, use AskUserQuestion:
diff --git a/plan-ceo-review/SKILL.md b/plan-ceo-review/SKILL.md
index 0791beeb0c..aba93691ed 100644
--- a/plan-ceo-review/SKILL.md
+++ b/plan-ceo-review/SKILL.md
@@ -1865,7 +1865,7 @@ thorough review.
**Check tool availability:**
```bash
-which codex 2>/dev/null && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
+command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
```
Use AskUserQuestion:
diff --git a/plan-design-review/SKILL.md b/plan-design-review/SKILL.md
index 396df1217b..76b00775ea 100644
--- a/plan-design-review/SKILL.md
+++ b/plan-design-review/SKILL.md
@@ -1519,7 +1519,7 @@ If user chooses B, skip this step and continue.
**Check Codex availability:**
```bash
-which codex 2>/dev/null && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
+command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
```
**If Codex is available**, launch both voices simultaneously:
diff --git a/plan-devex-review/SKILL.md b/plan-devex-review/SKILL.md
index 3869d47d8c..5110937073 100644
--- a/plan-devex-review/SKILL.md
+++ b/plan-devex-review/SKILL.md
@@ -1861,7 +1861,7 @@ thorough review.
**Check tool availability:**
```bash
-which codex 2>/dev/null && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
+command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
```
Use AskUserQuestion:
diff --git a/plan-eng-review/SKILL.md b/plan-eng-review/SKILL.md
index 06fbf7b805..d62a32f118 100644
--- a/plan-eng-review/SKILL.md
+++ b/plan-eng-review/SKILL.md
@@ -1478,7 +1478,7 @@ thorough review.
**Check tool availability:**
```bash
-which codex 2>/dev/null && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
+command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
```
Use AskUserQuestion:
diff --git a/review/SKILL.md b/review/SKILL.md
index a2092af9e1..c7d63508c3 100644
--- a/review/SKILL.md
+++ b/review/SKILL.md
@@ -1818,7 +1818,7 @@ Every diff gets adversarial review from both Claude and Codex. LOC is not a prox
DIFF_INS=$(git diff origin/ --stat | tail -1 | grep -oE '[0-9]+ insertion' | grep -oE '[0-9]+' || echo "0")
DIFF_DEL=$(git diff origin/ --stat | tail -1 | grep -oE '[0-9]+ deletion' | grep -oE '[0-9]+' || echo "0")
DIFF_TOTAL=$((DIFF_INS + DIFF_DEL))
-which codex 2>/dev/null && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
+command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
# Legacy opt-out — only gates Codex passes, Claude always runs
OLD_CFG=$(~/.claude/skills/gstack/bin/gstack-config get codex_reviews 2>/dev/null || true)
echo "DIFF_SIZE: $DIFF_TOTAL"
diff --git a/scripts/resolvers/design.ts b/scripts/resolvers/design.ts
index fc6d6ecee6..33247aab5e 100644
--- a/scripts/resolvers/design.ts
+++ b/scripts/resolvers/design.ts
@@ -10,7 +10,7 @@ export function generateDesignReviewLite(ctx: TemplateContext): string {
7. **Codex design voice** (optional, automatic if available):
\`\`\`bash
-which codex 2>/dev/null && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
+command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
\`\`\`
If Codex is available, run a lightweight design check on the diff:
@@ -512,7 +512,7 @@ The screenshot file at \`/tmp/gstack-sketch.png\` can be referenced by downstrea
After the wireframe is approved, offer outside design perspectives:
\`\`\`bash
-which codex 2>/dev/null && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
+command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
\`\`\`
If Codex is available, use AskUserQuestion:
@@ -688,7 +688,7 @@ ${optInSection}
**Check Codex availability:**
\`\`\`bash
-which codex 2>/dev/null && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
+command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
\`\`\`
**If Codex is available**, launch both voices simultaneously:
diff --git a/scripts/resolvers/review.ts b/scripts/resolvers/review.ts
index a0f29e1746..9a2194e011 100644
--- a/scripts/resolvers/review.ts
+++ b/scripts/resolvers/review.ts
@@ -266,7 +266,7 @@ export function generateCodexSecondOpinion(ctx: TemplateContext): string {
**Binary check first:**
\`\`\`bash
-which codex 2>/dev/null && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
+command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
\`\`\`
Use AskUserQuestion (regardless of codex availability):
@@ -425,7 +425,7 @@ Every diff gets adversarial review from both Claude and Codex. LOC is not a prox
DIFF_INS=$(git diff origin/ --stat | tail -1 | grep -oE '[0-9]+ insertion' | grep -oE '[0-9]+' || echo "0")
DIFF_DEL=$(git diff origin/ --stat | tail -1 | grep -oE '[0-9]+ deletion' | grep -oE '[0-9]+' || echo "0")
DIFF_TOTAL=$((DIFF_INS + DIFF_DEL))
-which codex 2>/dev/null && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
+command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
# Legacy opt-out — only gates Codex passes, Claude always runs
OLD_CFG=$(~/.claude/skills/gstack/bin/gstack-config get codex_reviews 2>/dev/null || true)
echo "DIFF_SIZE: $DIFF_TOTAL"
@@ -554,7 +554,7 @@ thorough review.
**Check tool availability:**
\`\`\`bash
-which codex 2>/dev/null && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
+command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
\`\`\`
Use AskUserQuestion:
diff --git a/ship/SKILL.md b/ship/SKILL.md
index 7548415246..5f8ac7bbc4 100644
--- a/ship/SKILL.md
+++ b/ship/SKILL.md
@@ -2191,7 +2191,7 @@ Substitute: TIMESTAMP = ISO 8601 datetime, STATUS = "clean" if 0 findings or "is
7. **Codex design voice** (optional, automatic if available):
```bash
-which codex 2>/dev/null && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
+command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
```
If Codex is available, run a lightweight design check on the diff:
@@ -2544,7 +2544,7 @@ Every diff gets adversarial review from both Claude and Codex. LOC is not a prox
DIFF_INS=$(git diff origin/ --stat | tail -1 | grep -oE '[0-9]+ insertion' | grep -oE '[0-9]+' || echo "0")
DIFF_DEL=$(git diff origin/ --stat | tail -1 | grep -oE '[0-9]+ deletion' | grep -oE '[0-9]+' || echo "0")
DIFF_TOTAL=$((DIFF_INS + DIFF_DEL))
-which codex 2>/dev/null && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
+command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
# Legacy opt-out — only gates Codex passes, Claude always runs
OLD_CFG=$(~/.claude/skills/gstack/bin/gstack-config get codex_reviews 2>/dev/null || true)
echo "DIFF_SIZE: $DIFF_TOTAL"
diff --git a/test/fixtures/golden/claude-ship-SKILL.md b/test/fixtures/golden/claude-ship-SKILL.md
index 7548415246..5f8ac7bbc4 100644
--- a/test/fixtures/golden/claude-ship-SKILL.md
+++ b/test/fixtures/golden/claude-ship-SKILL.md
@@ -2191,7 +2191,7 @@ Substitute: TIMESTAMP = ISO 8601 datetime, STATUS = "clean" if 0 findings or "is
7. **Codex design voice** (optional, automatic if available):
```bash
-which codex 2>/dev/null && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
+command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
```
If Codex is available, run a lightweight design check on the diff:
@@ -2544,7 +2544,7 @@ Every diff gets adversarial review from both Claude and Codex. LOC is not a prox
DIFF_INS=$(git diff origin/ --stat | tail -1 | grep -oE '[0-9]+ insertion' | grep -oE '[0-9]+' || echo "0")
DIFF_DEL=$(git diff origin/ --stat | tail -1 | grep -oE '[0-9]+ deletion' | grep -oE '[0-9]+' || echo "0")
DIFF_TOTAL=$((DIFF_INS + DIFF_DEL))
-which codex 2>/dev/null && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
+command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
# Legacy opt-out — only gates Codex passes, Claude always runs
OLD_CFG=$(~/.claude/skills/gstack/bin/gstack-config get codex_reviews 2>/dev/null || true)
echo "DIFF_SIZE: $DIFF_TOTAL"
diff --git a/test/fixtures/golden/factory-ship-SKILL.md b/test/fixtures/golden/factory-ship-SKILL.md
index 9a5e09b6ad..6d71afc1ad 100644
--- a/test/fixtures/golden/factory-ship-SKILL.md
+++ b/test/fixtures/golden/factory-ship-SKILL.md
@@ -2182,7 +2182,7 @@ Substitute: TIMESTAMP = ISO 8601 datetime, STATUS = "clean" if 0 findings or "is
7. **Codex design voice** (optional, automatic if available):
```bash
-which codex 2>/dev/null && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
+command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
```
If Codex is available, run a lightweight design check on the diff:
@@ -2535,7 +2535,7 @@ Every diff gets adversarial review from both Claude and Codex. LOC is not a prox
DIFF_INS=$(git diff origin/ --stat | tail -1 | grep -oE '[0-9]+ insertion' | grep -oE '[0-9]+' || echo "0")
DIFF_DEL=$(git diff origin/ --stat | tail -1 | grep -oE '[0-9]+ deletion' | grep -oE '[0-9]+' || echo "0")
DIFF_TOTAL=$((DIFF_INS + DIFF_DEL))
-which codex 2>/dev/null && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
+command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
# Legacy opt-out — only gates Codex passes, Claude always runs
OLD_CFG=$($GSTACK_ROOT/bin/gstack-config get codex_reviews 2>/dev/null || true)
echo "DIFF_SIZE: $DIFF_TOTAL"
diff --git a/test/skill-e2e-plan.test.ts b/test/skill-e2e-plan.test.ts
index 269c889c39..b6d8c3f0d4 100644
--- a/test/skill-e2e-plan.test.ts
+++ b/test/skill-e2e-plan.test.ts
@@ -776,7 +776,7 @@ Write your summary to ${testDir}/${testName}-summary.md`,
const summary = fs.readFileSync(summaryPath, 'utf-8').toLowerCase();
// All skills should have codex availability check
- expect(summary).toMatch(/which codex/);
+ expect(summary).toMatch(/command -v codex/);
// All skills should have fallback behavior
expect(summary).toMatch(/fallback|subagent|unavailable|not available|skip/);
// All skills should show it's optional/non-blocking
diff --git a/test/skill-validation.test.ts b/test/skill-validation.test.ts
index 625bc0a169..b7d696c39d 100644
--- a/test/skill-validation.test.ts
+++ b/test/skill-validation.test.ts
@@ -1315,9 +1315,9 @@ describe('Codex skill', () => {
expect(content).toContain('gstack-review-log');
});
- test('codex/SKILL.md uses which for binary discovery, not hardcoded path', () => {
+ test('codex/SKILL.md uses command -v for binary discovery, not hardcoded path', () => {
const content = fs.readFileSync(path.join(ROOT, 'codex', 'SKILL.md'), 'utf-8');
- expect(content).toContain('which codex');
+ expect(content).toContain('command -v codex');
expect(content).not.toContain('/opt/homebrew/bin/codex');
});