Skip to content

[Split Scope Migration](2) Remind agents to read split-scope on planning prompts - #450

Merged
EdbertChan merged 10 commits into
mainfrom
plan/split-scope-migration-2-remind-agents-to-read-split-scope-on-planning-prompts
Sep 12, 2026
Merged

[Split Scope Migration](2) Remind agents to read split-scope on planning prompts#450
EdbertChan merged 10 commits into
mainfrom
plan/split-scope-migration-2-remind-agents-to-read-split-scope-on-planning-prompts

Conversation

@EdbertChan

@EdbertChan EdbertChan commented Sep 11, 2026

Copy link
Copy Markdown
Owner

Summary

Planning prompts for stacked or multi-slice work now remind agents to read the split-scope skill.

The reminder reaches Claude, Codex, and Cursor through a fail-open hook installed by the repository installer.

Review Claim

The new prompt hook injects a split-scope reminder for multi-PR and migration plans without blocking unrelated prompts.

Review Lane

behavior

Review Unit

engine-runtime

Safety Invariant

The hook is inject-only and fail-open: it never blocks a tool and emits nothing when the prompt does not match.

Slice Rationale

This slice adds the detector, harness entrypoints, installers, and focused tests together so the activation path is reviewable end to end.

The split-scope skill text landed in the preceding slice, so this slice only activates it on planning prompts.

Non-goals

  • Do not change product/skills/split-scope, build-the-lever, playbook-router, or pr-schema-gate.
  • Do not edit the repository README.md or docs/ecosystem.md tables.
  • Do not add blocking behavior or change unrelated prompt handling.

Architecture

Before

graph TD
    A["Planning prompt"] --> B["Harness"]
    B --> C["Agent plans without an automatic split-scope reminder"]
Loading

After

graph TD
    A["Planning prompt"] --> B["Claude, Codex, or Cursor hook"]
    B --> C["Detector checks for multi-PR, slice, or migration language"]
    C -->|"match"| D["Inject split-scope reminder"]
    C -->|"no match or error"| E["Continue silently and fail open"]
    D --> F["Agent plans with split-scope guidance"]
Loading

Test Plan

Test Plan
  • python3 -m unittest discover -s engine/hooks/split-scope/tests -v && python3 scripts/check_hook_test_coverage.py engine/hooks/split-scope && python3 -m unittest discover -s tests -p "test_install.py"
  • bash scripts/scrub-handoff-artifacts.sh

Revert Plan

Revert Plan
  • Safe to revert? Yes.
  • Revert command: git revert <sha>.
  • Post-revert steps: Re-run the hook and installer test commands above.
  • Data migration? No.

Note

Low Risk
Adds optional prompt context only; it does not block tools and follows the same install/merge pattern as other catstack hooks.

Overview
Adds a new split-scope prompt hook that nudges agents to read the split-scope skill before they write multi-slice plans or PR stacks.

When user text matches regex triggers (e.g. PR stack, multiple PRs, migration plan), Claude and Codex inject additionalContext on UserPromptSubmit. Cursor records a pending flag on beforeSubmitPrompt and delivers the same reminder once on the first postToolUse, using TTL state under ~/.cache/catstack-split-scope. Behavior is inject-only and fail-open (no blocking; malformed input logs to stderr).

install.sh symlinks the hook for all three harnesses and runs idempotent merge installers; tests/test_install.py and engine/hooks/split-scope/tests cover detection, entrypoints, and wiring.

Reviewed by Cursor Bugbot for commit 2060337. Bugbot is set up for automated code reviews on this repo. Configure here.

Invoker Bot and others added 9 commits September 11, 2026 21:09
…iew claim:

- The catstack PR-slicing skill gains the one guidance section that only Invoker's copy has.
Review lane:
- docs
Safety invariant:
- Text-only skill change; no hook, script, or test reads this section by name.
Effectiveness measurement:
- `grep -q "^## Proof Must Match the Claim" product/skills/split-scope/SKILL.md` exits 0.
Slice rationale:
- One guidance section in one skill file; the hook that points at this skill is a separate workflow.
Architectural effect:
- None; adds guidance text to one skill file.
Goal:
- Add the "Proof Must Match the Claim" section to product/skills/split-scope/SKILL.md so catstack's copy has every rule Invoker's review-compression has.
Motivation:
- That section is the only rule in Invoker's review-compression with no catstack equivalent.
Alternative considerations:
- Option A (chosen): add it to SKILL.md after Ordering Rules.
- Option B: a new references/ file; rejected because the rule is short and applies to every proof slice.
Implementation details:
- Insert the fetched section text right after the Ordering Rules section of the SKILL.md file named in Goal.
Non-goals:
- No change to playbooks/ or references/ files, hooks, or install scripts.
Layer: domain
Feature state: active
Files:
- product/skills/split-scope/SKILL.md
Change types:
- product/skills/split-scope/SKILL.md: modify
Acceptance criteria:
- Pass condition: `grep -q "^## Proof Must Match the Claim" product/skills/split-scope/SKILL.md` exits 0.
- Pass condition: `grep -q "corpus/skills/principle-prove-it/SKILL.md" product/skills/split-scope/SKILL.md` exits 0.
- Pass condition: `python3 scripts/check_skills_three_harnesses.py` exits 0.

Solution:
  Review claim:
- The catstack PR-slicing skill gains the one guidance section that only Invoker's copy has.
Review lane:
- docs
Safety invariant:
- Text-only skill change; no hook, script, or test reads this section by name.
Effectiveness measurement:
- `grep -q "^## Proof Must Match the Claim" product/skills/split-scope/SKILL.md` exits 0.
Slice rationale:
- One guidance section in one skill file; the hook that points at this skill is a separate workflow.
Architectural effect:
- None; adds guidance text to one skill file.
Goal:
- Add the "Proof Must Match the Claim" section to product/skills/split-scope/SKILL.md so catstack's copy has every rule Invoker's review-compression has.
Motivation:
- That section is the only rule in Invoker's review-compression with no catstack equivalent.
Alternative considerations:
- Option A (chosen): add it to SKILL.md after Ordering Rules.
- Option B: a new references/ file; rejected because the rule is short and applies to every proof slice.
Implementation details:
- Insert the fetched section text right after the Ordering Rules section of the SKILL.md file named in Goal.
Non-goals:
- No change to playbooks/ or references/ files, hooks, or install scripts.
Layer: domain
Feature state: active
Files:
- product/skills/split-scope/SKILL.md
Change types:
- product/skills/split-scope/SKILL.md: modify
Acceptance criteria:
- Pass condition: `grep -q "^## Proof Must Match the Claim" product/skills/split-scope/SKILL.md` exits 0.
- Pass condition: `grep -q "corpus/skills/principle-prove-it/SKILL.md" product/skills/split-scope/SKILL.md` exits 0.
- Pass condition: `python3 scripts/check_skills_three_harnesses.py` exits 0.

Invoker-Finalize-Id: 6d9345ec-208b-418e-9231-3927a90041e2
… claim:

- The new section is present with its catstack cross-reference and the skill still installs for all three harnesses.
Review lane:
- proof
Safety invariant:
- Proof-only; this read-only check changes no files.
Effectiveness measurement:
- The command below exits 0.
Slice rationale:
- One proof step for the one section added.
Architectural effect:
- None; verification only.
Goal:
- Prove the section landed as written.
Motivation:
- A deterministic check beats reading the diff by eye.
Alternative considerations:
- Option A (chosen): grep for the heading and the cross-reference, then run the three-harness check.
Implementation details:
- Run the grep checks and the three-harness script.
Non-goals:
- No product edits here.
Layer: app_regression
Feature state: active

Exit code: 0
Invoker-Finalize-Id: cd5d511d-3ca5-41d1-b388-764bfc916d54
- No ephemeral handoff files are left behind before the PR merge gate.
Review lane:
- proof
Safety invariant:
- This read-only check changes no files.
Effectiveness measurement:
- `bash scripts/scrub-handoff-artifacts.sh` exits 0.
Slice rationale:
- The scrub check runs last and stays separate from implementation.
Architectural effect:
- No architecture change.
Goal:
- Confirm no handoff artifacts remain.
Motivation:
- Uncommitted handoff files do not flow across worktrees.
Alternative considerations:
- Option A (chosen): a read-only absence check.
Implementation details:
- Run the handoff scrub script without --apply.
Non-goals:
- Do not modify source files.
Layer: e2e_regression
Feature state: active

Exit code: 0
Invoker-Finalize-Id: 48fdab14-0298-46c3-b4c5-65fa60aa4610
…9dbda2a5-ea9a636b — Review claim:

- No ephemeral handoff files are left behind before the PR merge gate.
Review lane:
- proof
Safety invariant:
- This read-only check changes no files.
Effectiveness measurement:
- `bash scripts/scrub-handoff-artifacts.sh` exits 0.
Slice rationale:
- The scrub check runs last and stays separate from implementation.
Architectural effect:
- No architecture change.
Goal:
- Confirm no handoff artifacts remain.
Motivation:
- Uncommitted handoff files do not flow across worktrees.
Alternative considerations:
- Option A (chosen): a read-only absence check.
Implementation details:
- Run the handoff scrub script without --apply.
Non-goals:
- Do not modify source files.
Layer: e2e_regression
Feature state: active
The skill test coverage gate requires a tests/ change whenever the skill
changes; this example exercises the section added in this PR.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DtqAxtTmdoRE7CD5BXdGbp
Change-Id: Iec59c35c5b11f48375ac9b6a770faeb2c59785cf
- A new catstack hook injects a reminder to read the PR-slicing skill on prompts that plan multi-PR or multi-slice work, for Claude, Codex, and Cursor.
Review lane:
- behavior
Safety invariant:
- Inject-only and fail-open; the hook never blocks a tool and prints nothing on prompts that do not match.
Effectiveness measurement:
- `python3 -m unittest discover -s engine/hooks/split-scope/tests -v` exits 0 with at least three firing prompts and three silent prompts.
Slice rationale:
- One hook with its detector, entrypoints, installers, and tests; the skill text it points at landed in workflow 1.
Architectural effect:
- Adds one prompt-time injector under engine/hooks/split-scope, registered by install.sh for Claude, Cursor, and Codex.
Goal:
- Make product/skills/split-scope load on planning prompts without relying on the model to choose it.
Motivation:
- The skill is only description-triggered today, so multi-PR plans get written without it.
Alternative considerations:
- Option A (chosen): a new hook shaped like build-the-lever (regex on the prompt, inject a reminder).
- Option B: extend engine/hooks/playbook-router; rejected because it only fires on explicit "run <name>" prompts and its fixtures deliberately keep split-scope silent.
- Option C: remind at PR-publish time via pr-schema-gate; rejected because the commits already exist by then.
Implementation details:
- Create the hook directory named in Files, shaped like engine/hooks/build-the-lever, and wire it into install.sh and tests/test_install.py the same way build-the-lever is wired.
Non-goals:
- No change to product/skills/split-scope, build-the-lever, playbook-router, or pr-schema-gate.
- No edits to the repo-root README.md or docs/ecosystem.md tables.
- No blocking behavior.
Layer: domain
Feature state: active
Files:
- engine/hooks/split-scope/detect.py
- engine/hooks/split-scope/claude_prompt_submit.py
- engine/hooks/split-scope/codex_prompt_submit.py
- engine/hooks/split-scope/cursor_before_submit.py
- engine/hooks/split-scope/cursor_post_tool_use.py
- engine/hooks/split-scope/state.py
- engine/hooks/split-scope/install_claude_hook.py
- engine/hooks/split-scope/install_codex_hook.py
- engine/hooks/split-scope/install_cursor_hook.py
- engine/hooks/split-scope/claude.prompt.hook.json
- engine/hooks/split-scope/codex.hook.json
- engine/hooks/split-scope/README.md
- engine/hooks/split-scope/tests/test_hooks.py
- install.sh
- tests/test_install.py
Change types:
- engine/hooks/split-scope/detect.py: create
- engine/hooks/split-scope/claude_prompt_submit.py: create
- engine/hooks/split-scope/codex_prompt_submit.py: create
- engine/hooks/split-scope/cursor_before_submit.py: create
- engine/hooks/split-scope/cursor_post_tool_use.py: create
- engine/hooks/split-scope/state.py: create
- engine/hooks/split-scope/install_claude_hook.py: create
- engine/hooks/split-scope/install_codex_hook.py: create
- engine/hooks/split-scope/install_cursor_hook.py: create
- engine/hooks/split-scope/claude.prompt.hook.json: create
- engine/hooks/split-scope/codex.hook.json: create
- engine/hooks/split-scope/README.md: create
- engine/hooks/split-scope/tests/test_hooks.py: create
- install.sh: modify
- tests/test_install.py: modify
Acceptance criteria:
- Pass condition: `python3 -m unittest discover -s engine/hooks/split-scope/tests -v` exits 0.
- Pass condition: `python3 scripts/check_hook_test_coverage.py engine/hooks/split-scope` exits 0.
- Pass condition: `python3 -m unittest discover -s tests -p "test_install.py"` exits 0.

Solution:
  Review claim:
- A new catstack hook injects a reminder to read the PR-slicing skill on prompts that plan multi-PR or multi-slice work, for Claude, Codex, and Cursor.
Review lane:
- behavior
Safety invariant:
- Inject-only and fail-open; the hook never blocks a tool and prints nothing on prompts that do not match.
Effectiveness measurement:
- `python3 -m unittest discover -s engine/hooks/split-scope/tests -v` exits 0 with at least three firing prompts and three silent prompts.
Slice rationale:
- One hook with its detector, entrypoints, installers, and tests; the skill text it points at landed in workflow 1.
Architectural effect:
- Adds one prompt-time injector under engine/hooks/split-scope, registered by install.sh for Claude, Cursor, and Codex.
Goal:
- Make product/skills/split-scope load on planning prompts without relying on the model to choose it.
Motivation:
- The skill is only description-triggered today, so multi-PR plans get written without it.
Alternative considerations:
- Option A (chosen): a new hook shaped like build-the-lever (regex on the prompt, inject a reminder).
- Option B: extend engine/hooks/playbook-router; rejected because it only fires on explicit "run <name>" prompts and its fixtures deliberately keep split-scope silent.
- Option C: remind at PR-publish time via pr-schema-gate; rejected because the commits already exist by then.
Implementation details:
- Create the hook directory named in Files, shaped like engine/hooks/build-the-lever, and wire it into install.sh and tests/test_install.py the same way build-the-lever is wired.
Non-goals:
- No change to product/skills/split-scope, build-the-lever, playbook-router, or pr-schema-gate.
- No edits to the repo-root README.md or docs/ecosystem.md tables.
- No blocking behavior.
Layer: domain
Feature state: active
Files:
- engine/hooks/split-scope/detect.py
- engine/hooks/split-scope/claude_prompt_submit.py
- engine/hooks/split-scope/codex_prompt_submit.py
- engine/hooks/split-scope/cursor_before_submit.py
- engine/hooks/split-scope/cursor_post_tool_use.py
- engine/hooks/split-scope/state.py
- engine/hooks/split-scope/install_claude_hook.py
- engine/hooks/split-scope/install_codex_hook.py
- engine/hooks/split-scope/install_cursor_hook.py
- engine/hooks/split-scope/claude.prompt.hook.json
- engine/hooks/split-scope/codex.hook.json
- engine/hooks/split-scope/README.md
- engine/hooks/split-scope/tests/test_hooks.py
- install.sh
- tests/test_install.py
Change types:
- engine/hooks/split-scope/detect.py: create
- engine/hooks/split-scope/claude_prompt_submit.py: create
- engine/hooks/split-scope/codex_prompt_submit.py: create
- engine/hooks/split-scope/cursor_before_submit.py: create
- engine/hooks/split-scope/cursor_post_tool_use.py: create
- engine/hooks/split-scope/state.py: create
- engine/hooks/split-scope/install_claude_hook.py: create
- engine/hooks/split-scope/install_codex_hook.py: create
- engine/hooks/split-scope/install_cursor_hook.py: create
- engine/hooks/split-scope/claude.prompt.hook.json: create
- engine/hooks/split-scope/codex.hook.json: create
- engine/hooks/split-scope/README.md: create
- engine/hooks/split-scope/tests/test_hooks.py: create
- install.sh: modify
- tests/test_install.py: modify
Acceptance criteria:
- Pass condition: `python3 -m unittest discover -s engine/hooks/split-scope/tests -v` exits 0.
- Pass condition: `python3 scripts/check_hook_test_coverage.py engine/hooks/split-scope` exits 0.
- Pass condition: `python3 -m unittest discover -s tests -p "test_install.py"` exits 0.

Invoker-Finalize-Id: e5fb4ad0-5685-4eb6-bffb-64b4ae990aff
- The hook's own tests, the hook-coverage gate, and the install tests all pass.
Review lane:
- proof
Safety invariant:
- Proof-only; this read-only check changes no files.
Effectiveness measurement:
- The command below exits 0.
Slice rationale:
- One proof step for the one hook added.
Architectural effect:
- None; verification only.
Goal:
- Prove the hook fires and stays silent as specified and installs cleanly.
Motivation:
- The tests run the real entrypoint, so a pass means the reminder really reaches the agent.
Alternative considerations:
- Option A (chosen): run the hook tests, the coverage gate, and the install tests together.
Implementation details:
- Run the three checks in order.
Non-goals:
- No product edits here.
Layer: app_regression
Feature state: active

Exit code: 0
Invoker-Finalize-Id: de2b9576-c043-4ebd-900b-3b6f8c0767a5
- No ephemeral handoff files are left behind before the PR merge gate.
Review lane:
- proof
Safety invariant:
- This read-only check changes no files.
Effectiveness measurement:
- `bash scripts/scrub-handoff-artifacts.sh` exits 0.
Slice rationale:
- The scrub check runs last and stays separate from implementation.
Architectural effect:
- No architecture change.
Goal:
- Confirm no handoff artifacts remain.
Motivation:
- Uncommitted handoff files do not flow across worktrees.
Alternative considerations:
- Option A (chosen): a read-only absence check.
Implementation details:
- Run the handoff scrub script without --apply.
Non-goals:
- Do not modify source files.
Layer: e2e_regression
Feature state: active

Exit code: 0
Invoker-Finalize-Id: 5f7e27db-a80d-42ca-ae0b-1264aef879ba
…d283c122-0c4efa8b — Review claim:

- No ephemeral handoff files are left behind before the PR merge gate.
Review lane:
- proof
Safety invariant:
- This read-only check changes no files.
Effectiveness measurement:
- `bash scripts/scrub-handoff-artifacts.sh` exits 0.
Slice rationale:
- The scrub check runs last and stays separate from implementation.
Architectural effect:
- No architecture change.
Goal:
- Confirm no handoff artifacts remain.
Motivation:
- Uncommitted handoff files do not flow across worktrees.
Alternative considerations:
- Option A (chosen): a read-only absence check.
Implementation details:
- Run the handoff scrub script without --apply.
Non-goals:
- Do not modify source files.
Layer: e2e_regression
Feature state: active
@cursor

cursor Bot commented Sep 11, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_9747c2a9-e994-427b-ad91-32f1dfab3df7)

@EdbertChan
EdbertChan changed the base branch from plan/split-scope-migration-1-add-proof-must-match-the-claim-to-split-scope to main September 12, 2026 01:00
@mergify

mergify Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

Change-Id: I19b067f3f9bae7d7812d490594a0842423ff273a

# Conflicts:
#	tests/test_install.py
@cursor

cursor Bot commented Sep 12, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_65b34f51-ccf7-4082-819c-a533b86554ba)

@EdbertChan
EdbertChan merged commit 316ffb5 into main Sep 12, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant