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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cc",
"version": "1.0.7",
"version": "1.0.8",
"description": "Claude Code Plugin for Codex. Delegate code reviews, investigations, and tracked tasks to Claude Code from inside Codex.",
"author": {
"name": "Sendbird, Inc.",
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## v1.0.8

- Clarify the routing boundary between `$cc:review`, `$cc:adversarial-review`, and `$cc:rescue`, including the rule that ordinary code-review requests default to `review`, stronger scrutiny plus custom focus text belongs to `adversarial-review`, and rescue is only for Claude-owned follow-through work.
- Add E2E coverage that injects both review skills together and verifies the focus-text distinction is surfaced to the parent turn while the adversarial focus path still reaches Claude end to end.
- Refresh the macOS integration concurrency test so aggressive concurrent polling no longer flakes when some jobs finish slightly later than the initial polling window.
- Update development dependencies with the merged Dependabot patch bumps for `@types/node` and `globals`.

## v1.0.7

- Add GitHub CI coverage across Windows, macOS, and Linux, with a portable cross-platform test suite plus Linux-only full integration/E2E coverage.
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cc-plugin-codex",
"version": "1.0.7",
"version": "1.0.8",
"description": "Claude Code Plugin for Codex by Sendbird",
"type": "module",
"author": {
Expand Down
8 changes: 5 additions & 3 deletions skills/adversarial-review/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
---
name: adversarial-review
description: 'Run a design-challenging Claude Code review of local git changes in this repository. Args: --wait, --background, --base <ref>, --scope <auto|working-tree|branch>, --model <model>, [focus text]. Use when the user wants stronger scrutiny, tradeoff analysis, risky-change review, or custom review focus text.'
description: 'Run a design-challenging Claude Code review of local git changes in this repository. Args: --wait, --background, --base <ref>, --scope <auto|working-tree|branch>, --model <model>, [focus text]. Use only when the user wants stronger scrutiny than a normal review, such as explicit tradeoff challenge, risky-change review, or custom focus text.'
---

# Claude Code Adversarial Review

Use this skill when the user wants Claude Code to challenge the implementation approach, design choices, assumptions, or tradeoffs in this repository.

Prefer `$cc:adversarial-review` over `$cc:review` when the change touches configuration, infrastructure, templating, rollout mechanics, migrations, safety controls, or "this should remove mismatch/drift" style refactors.
Use it even without extra focus text when the real question is "did this actually eliminate the risk or just move it around?"
Do not treat `$cc:adversarial-review` as the default review path. Use it only when the user explicitly wants stronger scrutiny than a normal code review.
Good triggers include requests to challenge the design, challenge tradeoffs, pressure-test a risky change, question whether a migration/config/template change really removed the risk, or honor custom focus text that asks for harsher review.
If the user wants Claude Code to go beyond review and perform investigation, validation edits, or implementation work, route to `$cc:rescue` instead.
If the user asks for a local review plus a separate Claude background review and then wants the main Codex thread to aggregate the findings and apply fixes, keep the delegated Claude portion on `$cc:review` unless the user explicitly asks for the adversarial angle.
Unlike `$cc:review`, this skill accepts custom focus text after the flags. The moment the user wants to steer Claude toward a specific angle or risk question, prefer `$cc:adversarial-review`.

Do not derive the companion path from this skill file or any cache directory. Always run the installed copy:
`node "<installed-plugin-root>/scripts/claude-companion.mjs" adversarial-review ...`
Expand Down
1 change: 1 addition & 0 deletions skills/rescue/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Use this skill when the user wants Claude Code to investigate, implement, or con

Prefer `$cc:rescue` when the user wants Claude Code to diagnose the issue, validate a risky change by actually editing or testing, apply fixes from a prior review, or carry a task forward across multiple steps.
Do not use rescue for "just review this diff" unless the user also wants follow-through work beyond review findings.
Do not use rescue merely because the main Codex thread plans to fix things after combining its own review with a separate Claude review. Rescue is only the right delegation when Claude itself is supposed to investigate, edit, test, or otherwise own the follow-through work.

Do not derive the companion path from this skill file or any cache directory. Always run the installed copy:
`node "<installed-plugin-root>/scripts/claude-companion.mjs" task ...`
Expand Down
8 changes: 5 additions & 3 deletions skills/review/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
---
name: review
description: 'Run a standard Claude Code review of local git changes in this repository. Args: --wait, --background, --base <ref>, --scope <auto|working-tree|branch>, --model <model>. Use for straightforward correctness-oriented diff review when the user wants findings only, not custom focus text, adversarial framing, or implementation work.'
description: 'Run a standard Claude Code review of local git changes in this repository. Args: --wait, --background, --base <ref>, --scope <auto|working-tree|branch>, --model <model>. Use as the default path for ordinary code-review requests when the user did not explicitly ask for stronger adversarial scrutiny or for Claude to own the implementation work.'
---

# Claude Code Review

Use this skill when the user wants Claude Code to review the current working tree or a branch diff in this repository.

Choose `$cc:review` only for straightforward review requests where the user mainly wants correctness findings on the current diff.
If the user wants stronger challenge on design, rollout risk, migration risk, configuration behavior, template mismatch elimination, or any custom focus text, route to `$cc:adversarial-review` instead.
Use `$cc:review` as the default when the user asks for code review, asks you to have Claude review something, or wants a second review pass without explicitly asking for stronger adversarial scrutiny.
If the user asks for stronger challenge on design, tradeoffs, rollout risk, migration risk, configuration behavior, or provides custom review focus text, route to `$cc:adversarial-review` instead.
If the user wants Claude Code to investigate, validate by changing code, or actually fix/implement something, route to `$cc:rescue` instead.
If the overall request is "you review it too, also ask Claude to review in the background, then you aggregate and fix it", keep the delegated Claude part on `$cc:review` unless the user explicitly asks for a harsher or more adversarial review.
`$cc:review` does not accept custom focus text. If the user wants to steer Claude toward a particular angle, question, subsystem, or risk area, that is a signal to use `$cc:adversarial-review` instead.

Do not derive the companion path from this skill file or any cache directory. Always run the installed copy:
`node "<installed-plugin-root>/scripts/claude-companion.mjs" review ...`
Expand Down
79 changes: 79 additions & 0 deletions tests/e2e/codex-skills-e2e.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,23 @@ function buildSkillPrompt(name, skillPath, userRequest) {
].join("\n");
}

function buildMultiSkillPrompt(skills, userRequest) {
return [
...skills.flatMap(({ name, path: skillPath }) => {
const skillBody = fs.readFileSync(skillPath, "utf8").trim();
return [
"<skill>",
`<name>${name}</name>`,
`<path>${skillPath}</path>`,
skillBody,
"</skill>",
"",
];
}),
userRequest,
].join("\n");
}

function eventCreated(id) {
return {
type: "response.created",
Expand Down Expand Up @@ -1846,6 +1863,68 @@ describe("Codex direct-skill E2E", () => {
}
});

it("injects review-versus-adversarial focus routing guidance when both skills are available", async (t) => {
if (!codexAvailable()) {
t.skip("codex CLI is not available in this environment");
return;
}

const testEnv = createEnvironment();
const workspaceDir = path.join(testEnv.rootDir, "focus-routing-workspace");
fs.mkdirSync(workspaceDir, { recursive: true });
setupGitWorkspace(workspaceDir);
fs.writeFileSync(
path.join(workspaceDir, "app.js"),
"export function value() {\n return 7;\n}\n",
"utf8"
);

const userRequest =
"$cc:review --wait --scope working-tree --model haiku focus on race conditions";
const provider = startDirectSkillProvider({
userRequest,
expectedNeedles: [
"`$cc:review` does not accept custom focus text",
"Unlike `$cc:review`, this skill accepts custom focus text after the flags",
"keep the delegated Claude part on `$cc:review`",
],
shellCommands: [
`node ${JSON.stringify(COMPANION_SCRIPT)} adversarial-review --view-state on-success --scope working-tree --model haiku focus on race conditions`,
],
cwd: workspaceDir,
});
testEnv.providerPort = await provider.listen();
installHooks(testEnv);
writeConfigToml(testEnv, testEnv.providerPort);

try {
const execResult = await runCodexExec(
testEnv,
buildMultiSkillPrompt(
[
{ name: "cc:review", path: REVIEW_SKILL_PATH },
{ name: "cc:adversarial-review", path: ADVERSARIAL_REVIEW_SKILL_PATH },
],
userRequest
),
{ cwd: workspaceDir }
);

assert.equal(execResult.status, 0, execResult.stderr || execResult.stdout);
const finalMessage = fs.readFileSync(testEnv.outputFile, "utf8");
assert.match(finalMessage, /Adversarial Review/);

const claudeInvocations = readClaudeInvocations(testEnv.claudeLogFile);
assert.ok(
claudeInvocations.some((entry) => entry.prompt.includes("focus on race conditions")),
"focus-routing e2e should preserve the user focus text when the adversarial path is selected"
);
} finally {
await provider.close();
cleanupEnvironment(testEnv);
}
});

it("routes $cc:adversarial-review --background through the built-in path with notification steering", async (t) => {
if (!codexAvailable()) {
t.skip("codex CLI is not available in this environment");
Expand Down
13 changes: 9 additions & 4 deletions tests/skills-contracts.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ test("review skills keep background execution outside the companion command", ()
const installedRootPattern = /<installed-plugin-root>\/scripts\/claude-companion\.mjs/i;

assert.match(review, /Do not derive the companion path from this skill file or any cache directory/i);
assert.match(review, /Choose `\$cc:review` only for straightforward review requests where the user mainly wants correctness findings on the current diff/i);
assert.match(review, /If the user wants stronger challenge on design, rollout risk, migration risk, configuration behavior, template mismatch elimination, or any custom focus text, route to `\$cc:adversarial-review` instead/i);
assert.match(review, /Use `\$cc:review` as the default when the user asks for code review, asks you to have Claude review something, or wants a second review pass without explicitly asking for stronger adversarial scrutiny/i);
assert.match(review, /If the user asks for stronger challenge on design, tradeoffs, rollout risk, migration risk, configuration behavior, or provides custom review focus text, route to `\$cc:adversarial-review` instead/i);
assert.match(review, /If the user wants Claude Code to investigate, validate by changing code, or actually fix\/implement something, route to `\$cc:rescue` instead/i);
assert.match(review, /If the overall request is "you review it too, also ask Claude to review in the background, then you aggregate and fix it", keep the delegated Claude part on `\$cc:review` unless the user explicitly asks for a harsher or more adversarial review/i);
assert.match(review, /`\$cc:review` does not accept custom focus text/i);
assert.match(review, installedRootPattern);
assert.match(review, /Treat `--wait` and `--background` as Codex-side execution controls only/i);
assert.match(review, /Strip them before calling the companion command/i);
Expand Down Expand Up @@ -63,9 +65,11 @@ test("review skills keep background execution outside the companion command", ()
assert.doesNotMatch(review, /claude-companion\.mjs" review \$ARGUMENTS/i);

assert.match(adversarial, /Do not derive the companion path from this skill file or any cache directory/i);
assert.match(adversarial, /Prefer `\$cc:adversarial-review` over `\$cc:review` when the change touches configuration, infrastructure, templating, rollout mechanics, migrations, safety controls, or "this should remove mismatch\/drift" style refactors/i);
assert.match(adversarial, /Use it even without extra focus text when the real question is "did this actually eliminate the risk or just move it around\?"/i);
assert.match(adversarial, /Do not treat `\$cc:adversarial-review` as the default review path/i);
assert.match(adversarial, /Good triggers include requests to challenge the design, challenge tradeoffs, pressure-test a risky change, question whether a migration\/config\/template change really removed the risk, or honor custom focus text that asks for harsher review/i);
assert.match(adversarial, /If the user wants Claude Code to go beyond review and perform investigation, validation edits, or implementation work, route to `\$cc:rescue` instead/i);
assert.match(adversarial, /If the user asks for a local review plus a separate Claude background review and then wants the main Codex thread to aggregate the findings and apply fixes, keep the delegated Claude portion on `\$cc:review` unless the user explicitly asks for the adversarial angle/i);
assert.match(adversarial, /Unlike `\$cc:review`, this skill accepts custom focus text after the flags/i);
assert.match(adversarial, installedRootPattern);
assert.match(adversarial, /Treat `--wait` and `--background` as Codex-side execution controls only/i);
assert.match(adversarial, /Strip them before calling the companion command/i);
Expand Down Expand Up @@ -111,6 +115,7 @@ test("rescue skill keeps --background and --wait as host-side controls only", ()
assert.match(rescue, /Do not derive the companion path from this skill file or any cache directory/i);
assert.match(rescue, /Prefer `\$cc:rescue` when the user wants Claude Code to diagnose the issue, validate a risky change by actually editing or testing, apply fixes from a prior review, or carry a task forward across multiple steps/i);
assert.match(rescue, /Do not use rescue for "just review this diff" unless the user also wants follow-through work beyond review findings/i);
assert.match(rescue, /Do not use rescue merely because the main Codex thread plans to fix things after combining its own review with a separate Claude review/i);
assert.match(rescue, installedRootPattern);
assert.match(rescue, /`--background` and `--wait` are Codex-side execution controls only/i);
assert.match(rescue, /Never satisfy background rescue by launching `claude-companion\.mjs task` itself as a detached shell process/i);
Expand Down