diff --git a/CLAUDE.md b/CLAUDE.md index 0434b4b..e11f0fd 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -51,7 +51,7 @@ Console scripts in `pyproject.toml`: `whygraph` → `cli:main`, `whygraph-mcp` WhyGraph installs **per project**, per agent: 1. `uv tool install whygraph` (or `pipx install whygraph`) so `whygraph` and `whygraph-mcp` are on `PATH`. -2. From the target repo: `whygraph init --agent ` — `--agent claude` writes `.mcp.json` and copies the bundled assets into `.claude/`; other agents (cursor / vscode / codex / claude-desktop) just wire their MCP config. +2. From the target repo: `whygraph init --agent ` — `--agent claude` writes `.mcp.json` and copies the bundled assets into `.claude/`; other agents (cursor / vscode / codex / claude-desktop) just wire their MCP config. Every agent's asset install also drops a **CodeGraph usage-guidance block** into that agent's always-on instructions (`.claude/CLAUDE.md`, `AGENTS.md`, `.github/copilot-instructions.md` via append-merge; an `alwaysApply: true` rule for Cursor) so the agent prefers the `codegraph_*` tools over grep without the user running CodeGraph's own installer. There is no Claude Code marketplace install; `whygraph init --agent claude` is the only path. The bundled assets are version-controlled in this repo under `src/whygraph/assets/claude-code/` — that is the source of truth, the wheel ships them, and a re-run of `whygraph init` brings a project's `.claude/` up to date (use `--force` to overwrite local edits). diff --git a/src/whygraph/agents.py b/src/whygraph/agents.py index 913ce92..46f6282 100644 --- a/src/whygraph/agents.py +++ b/src/whygraph/agents.py @@ -118,6 +118,7 @@ def has_assets(self) -> bool: description="Claude Code (project-scoped .mcp.json at repo root)", assets_subdir="claude-code", assets_dest=(".claude",), + assets_merge_files=("CLAUDE.md",), ) _CURSOR = AgentTarget( diff --git a/src/whygraph/assets/claude-code/CLAUDE.md b/src/whygraph/assets/claude-code/CLAUDE.md new file mode 100644 index 0000000..f5c5c3d --- /dev/null +++ b/src/whygraph/assets/claude-code/CLAUDE.md @@ -0,0 +1,31 @@ +## CodeGraph + +CodeGraph builds a semantic knowledge graph of codebases for faster, smarter code exploration. + +### If `.codegraph/` exists in the project + +**NEVER call `codegraph_explore` or `codegraph_context` directly in the main session.** These tools return large amounts of source code that fills up main session context. Instead, ALWAYS spawn an Explore agent for any exploration question (e.g., "how does X work?", "explain the Y system", "where is Z implemented?"). + +**When spawning Explore agents**, include this instruction in the prompt: + +> This project has CodeGraph initialized (.codegraph/ exists). Use `codegraph_explore` as your PRIMARY tool — it returns full source code sections from all relevant files in one call. +> +> **Rules:** +> 1. Follow the explore call budget in the `codegraph_explore` tool description — it scales automatically based on project size. +> 2. Do NOT re-read files that codegraph_explore already returned source code for. The source sections are complete and authoritative. +> 3. Only fall back to grep/glob/read for files listed under "Additional relevant files" if you need more detail, or if codegraph returned no results. + +**The main session may only use these lightweight tools directly** (for targeted lookups before making edits, not for exploration): + +| Tool | Use For | +|------|---------| +| `codegraph_search` | Find symbols by name | +| `codegraph_callers` / `codegraph_callees` | Trace call flow | +| `codegraph_impact` | Check what's affected before editing | +| `codegraph_node` | Get a single symbol's details | + +### If `.codegraph/` does NOT exist + +At the start of a session, ask the user if they'd like to initialize CodeGraph: + +"I notice this project doesn't have CodeGraph initialized. Would you like me to run `codegraph init -i` to build a code knowledge graph?" diff --git a/src/whygraph/assets/codex/AGENTS.md b/src/whygraph/assets/codex/AGENTS.md index 269b4e5..1b29e18 100644 --- a/src/whygraph/assets/codex/AGENTS.md +++ b/src/whygraph/assets/codex/AGENTS.md @@ -58,6 +58,23 @@ COMMIT_EACH_STEP: **Skip when**: no plan markdown exists, the "plan" is an informal chat-message bullet list (not a `# Plan:` markdown file with the standard schema), the change is trivial, the user is asking you to *review* the plan rather than execute it, or the plan has unresolved blockers. +## Using CodeGraph for structural questions + +This project ships a CodeGraph index (`.codegraph/`) and the `codegraph_*` MCP tools — a tree-sitter knowledge graph of every symbol, edge, and file. Reach for them on **structural** questions; use grep/read only for literal text (string contents, comments, log messages) or once a file is already open. + +| Question | Tool | +|---|---| +| Where is X defined? / find a symbol by name | `codegraph_search` | +| What calls Y? / what does Y call? | `codegraph_callers` / `codegraph_callees` | +| What would break if I change Z? | `codegraph_impact` | +| Show me Y's signature / source | `codegraph_node` | + +- **Trust the results** — they come from a full AST parse. Don't re-verify them with grep. +- **Don't pull large `codegraph_explore` / `codegraph_context` output into your working context** for simple questions — those return whole source sections and bloat the conversation. Use the lightweight tools above for targeted lookups, and reserve the bulk-source tools for genuine deep dives. +- **Index lag**: the watcher debounces ~500ms behind writes; don't re-query immediately after editing a file in the same turn. + +If `.codegraph/` doesn't exist, the MCP server reports "not initialized" — ask the user whether to run `whygraph scan` (which builds / refreshes the index) before relying on these tools. + ## What NOT to do - Don't call `whygraph_rationale_brief` for brand-new code with no predecessor — there's no history to summarize. @@ -65,3 +82,4 @@ COMMIT_EACH_STEP: - Don't treat the brief as authoritative if the code clearly diverges from what it describes — flag the divergence. - Don't dispatch `whygraph-planner` or `whygraph-implementor` for trivial changes. - Don't draft your own plan or implementation in parallel "as a preview" while waiting on a subagent — pick one path. +- Don't grep for a symbol you could find with `codegraph_search`, or re-verify codegraph results with grep. diff --git a/src/whygraph/assets/cursor/rules/whygraph-codegraph.mdc b/src/whygraph/assets/cursor/rules/whygraph-codegraph.mdc new file mode 100644 index 0000000..bec9d03 --- /dev/null +++ b/src/whygraph/assets/cursor/rules/whygraph-codegraph.mdc @@ -0,0 +1,27 @@ +--- +description: Always-on guidance for using the CodeGraph (`codegraph_*`) MCP tools. Prefer them over grep for structural questions; don't pull large explore output into context; trust their AST-parsed results. +alwaysApply: true +--- + +# Use CodeGraph for structural code questions + +This project ships a CodeGraph index (`.codegraph/`) and the `codegraph_*` MCP tools — a tree-sitter knowledge graph of every symbol, edge, and file. Reach for them on **structural** questions; use grep/read only for literal text (string contents, comments, log messages) or once a file is already open. + +## Prefer codegraph over grep + +| Question | Tool | +|---|---| +| Where is X defined? / find a symbol by name | `codegraph_search` | +| What calls Y? / what does Y call? | `codegraph_callers` / `codegraph_callees` | +| What would break if I change Z? | `codegraph_impact` | +| Show me Y's signature / source | `codegraph_node` | + +## Rules + +- **Trust the results** — they come from a full AST parse. Don't re-verify them with grep; that's slower, less accurate, and wastes context. +- **Don't pull large `codegraph_explore` / `codegraph_context` output into your working context** for simple questions — those return whole source sections and bloat the conversation. Use the lightweight tools above for targeted lookups, and reserve the bulk-source tools for genuine deep dives. +- **Index lag**: the watcher debounces ~500ms behind writes; don't re-query immediately after editing a file in the same turn. + +## If `.codegraph/` does not exist + +The MCP server reports "not initialized." Ask the user whether to run `whygraph scan` (which builds / refreshes the CodeGraph index) before relying on these tools. diff --git a/src/whygraph/assets/vscode/copilot-instructions.md b/src/whygraph/assets/vscode/copilot-instructions.md index 2fd3443..9673016 100644 --- a/src/whygraph/assets/vscode/copilot-instructions.md +++ b/src/whygraph/assets/vscode/copilot-instructions.md @@ -32,9 +32,27 @@ Do not draft a parallel plan yourself — that defeats the cost gate. Either inv If the user has a WhyGraph plan markdown (typically under `.whygraph/plans/.md`) and wants to apply it, use the `/whygraph-implement` prompt. It hands off to an implementor subagent that reads the plan as a strict contract, runs Verify after each step, and halts on the first failure. +## Using CodeGraph for structural questions + +This project ships a CodeGraph index (`.codegraph/`) and the `codegraph_*` MCP tools — a tree-sitter knowledge graph of every symbol, edge, and file. Reach for them on **structural** questions; use grep/read only for literal text (string contents, comments, log messages) or once a file is already open. + +| Question | Tool | +|---|---| +| Where is X defined? / find a symbol by name | `codegraph_search` | +| What calls Y? / what does Y call? | `codegraph_callers` / `codegraph_callees` | +| What would break if I change Z? | `codegraph_impact` | +| Show me Y's signature / source | `codegraph_node` | + +- **Trust the results** — they come from a full AST parse. Don't re-verify them with grep. +- **Don't pull large `codegraph_explore` / `codegraph_context` output into your working context** for simple questions — those return whole source sections and bloat the conversation. Use the lightweight tools above for targeted lookups, and reserve the bulk-source tools for genuine deep dives. +- **Index lag**: the watcher debounces ~500ms behind writes; don't re-query immediately after editing a file in the same turn. + +If `.codegraph/` doesn't exist, the MCP server reports "not initialized" — ask the user whether to run `whygraph scan` (which builds / refreshes the index) before relying on these tools. + ## What NOT to do - Don't call `whygraph_rationale_brief` for brand-new code with no predecessor — there's no history to summarize. - Don't call it repeatedly for the same symbol in one conversation. - Don't treat the brief as authoritative if the code clearly diverges from what it describes — flag the divergence. - Don't run `/whygraph-plan` automatically for trivial changes (1–3 lines, single file). Just do the edit. +- Don't grep for a symbol you could find with `codegraph_search`, or re-verify codegraph results with grep. diff --git a/tests/test_assets.py b/tests/test_assets.py index 160b06c..308663b 100644 --- a/tests/test_assets.py +++ b/tests/test_assets.py @@ -13,7 +13,7 @@ def test_packaged_claude_assets_present() -> None: - """All 8 bundled .md files are reachable via importlib.resources. + """All 9 bundled .md files are reachable via importlib.resources. Guards against a packaging regression: if hatch stopped shipping ``src/whygraph/assets/claude-code/`` for any reason, this test @@ -21,6 +21,7 @@ def test_packaged_claude_assets_present() -> None: """ root = assets.packaged_assets_for(agents.resolve_agent("claude")) expected = ( + "CLAUDE.md", "agents/planner.md", "agents/researcher.md", "agents/synthesizer.md", @@ -53,6 +54,7 @@ def test_packaged_cursor_assets_present() -> None: "commands/rationale.md", "commands/whygraph-plan.md", "commands/whygraph-implement.md", + "rules/whygraph-codegraph.mdc", "agents/planner.md", "agents/researcher.md", "agents/synthesizer.md", @@ -262,8 +264,8 @@ def test_install_from_packaged_source(tmp_path: Path) -> None: assert (project / ".claude" / "agents" / "planner.md").is_file() assert (project / ".claude" / "skills" / "rationale" / "SKILL.md").is_file() assert (project / ".claude" / "skills" / "pre-edit" / "SKILL.md").is_file() - # 4 agents + 4 skills = 8 files. - assert len(result.written) == 8 + # 4 agents + 4 skills + CLAUDE.md (merge file, written fresh) = 9 files. + assert len(result.written) == 9 # ---- install_assets: defensive guard ------------------------------------- diff --git a/tests/test_init_agents.py b/tests/test_init_agents.py index 301c3e2..38bc873 100644 --- a/tests/test_init_agents.py +++ b/tests/test_init_agents.py @@ -350,6 +350,10 @@ def test_init_agent_claude_writes_mcp_json_and_installs_assets( assert (cwd / ".claude" / "agents" / "planner.md").is_file() assert (cwd / ".claude" / "skills" / "rationale" / "SKILL.md").is_file() assert (cwd / ".claude" / "skills" / "pre-edit" / "SKILL.md").is_file() + # CodeGraph guidance is merged into .claude/CLAUDE.md (forcing block). + claude_md = (cwd / ".claude" / "CLAUDE.md").read_text(encoding="utf-8") + assert "" in claude_md + assert "## CodeGraph" in claude_md assert "Installed assets for claude" in result.output @@ -391,6 +395,29 @@ def test_init_agent_claude_default_skips_existing(stub_init, tmp_path: Path) -> assert text == "USER EDIT" +def test_init_agent_claude_merges_existing_claude_md(stub_init, tmp_path: Path) -> None: + """User-authored .claude/CLAUDE.md is preserved; the WhyGraph block appends.""" + runner = CliRunner() + with runner.isolated_filesystem(temp_dir=tmp_path): + cwd = Path.cwd() + (cwd / ".claude").mkdir() + (cwd / ".claude" / "CLAUDE.md").write_text( + "# Our team rules\n\nWrite tests for everything.\n", + encoding="utf-8", + ) + result = runner.invoke(whygraph_main, ["init", "--agent", "claude"]) + assert result.exit_code == 0, result.output + merged = (cwd / ".claude" / "CLAUDE.md").read_text(encoding="utf-8") + # User content preserved verbatim. + assert "# Our team rules" in merged + assert "Write tests for everything." in merged + # WhyGraph block (CodeGraph guidance) appended after user content. + assert "" in merged + assert "" in merged + assert "## CodeGraph" in merged + assert merged.find("Our team rules") < merged.find("") + + def test_init_agent_cursor_writes_mcp_json_and_installs_rules( stub_init, tmp_path: Path ) -> None: @@ -409,6 +436,11 @@ def test_init_agent_cursor_writes_mcp_json_and_installs_rules( # Bundled MDC rules land in .cursor/rules/. assert (cwd / ".cursor" / "rules" / "whygraph-pre-edit.mdc").is_file() assert (cwd / ".cursor" / "rules" / "whygraph-ask-why.mdc").is_file() + # The CodeGraph forcing rule lands and is always-applied. + codegraph_rule = (cwd / ".cursor" / "rules" / "whygraph-codegraph.mdc").read_text( + encoding="utf-8" + ) + assert "alwaysApply: true" in codegraph_rule # Slash commands and subagents land in their respective subdirs. assert (cwd / ".cursor" / "commands" / "whygraph-plan.md").is_file() assert (cwd / ".cursor" / "agents" / "planner.md").is_file()