Skip to content

fix(compile): deduplicate Claude Code instructions (#1138)#1146

Open
tillig wants to merge 23 commits into
microsoft:mainfrom
tillig:feature/double-claude-instructions
Open

fix(compile): deduplicate Claude Code instructions (#1138)#1146
tillig wants to merge 23 commits into
microsoft:mainfrom
tillig:feature/double-claude-instructions

Conversation

@tillig
Copy link
Copy Markdown
Contributor

@tillig tillig commented May 5, 2026

Summary

  • When both apm install (deploys to .claude/rules/) and apm compile --target claude (generates CLAUDE.md) have been run, Claude Code sees every instruction twice. This PR detects when .claude/rules/ already contains .md files and omits the "Project Standards" section from CLAUDE.md, eliminating the duplication.
  • CLAUDE.md is still generated when it carries a constitution block or @import dependency paths — only the instructions section is suppressed.
  • Adds an informational log message when zero CLAUDE.md files are generated (all content already deployed via rules).

Details

Detection heuristic: claude_rules_dir.is_dir() and any(claude_rules_dir.glob("*.md")). This is intentionally simple — if the directory exists and has markdown files, we assume apm install put them there. A future enhancement could cross-check against apm.lock.yaml deployed-file provenance for more precision.

Files changed:

  • src/apm_cli/compilation/agents_compiler.py — detection logic + log messages
  • src/apm_cli/compilation/claude_formatter.pyskip_instructions config plumbing; skips subdirectory placements and the Project Standards section when active
  • tests/unit/compilation/test_agents_compiler_coverage.py — 7 new tests (TestClaudeCompileSkipInstructions)
  • tests/unit/compilation/test_claude_formatter.py — 5 new tests (TestSkipInstructions)
  • docs/src/content/docs/guides/compilation.md — deduplication note + corrected "only instructions" scope
  • docs/src/content/docs/integrations/ide-tool-integration.md — deduplication note + corrected table description
  • CHANGELOG.md — entry under Unreleased/Fixed

Possible follow-up

Lockfile-provenance detection: instead of globbing .claude/rules/*.md, cross-check against deployed_files in apm.lock.yaml to distinguish APM-managed rules from hand-authored ones. Deferred to keep this PR focused.

Test plan

  • All 343 compilation unit tests pass
  • Full unit suite passes (6,952 tests; 1 pre-existing unrelated failure)
  • Linter passes on all modified files
  • Verify apm compile --target claude with .claude/rules/ present → no Project Standards in CLAUDE.md
  • Verify apm compile --target claude without .claude/rules/ → CLAUDE.md includes Project Standards as before
  • Verify constitution + dependencies still appear in CLAUDE.md when instructions are skipped

Closes #1138

tillig and others added 4 commits May 4, 2026 16:23
…opulated

When `apm install` has already deployed instructions to `.claude/rules/`
(Claude Code's native format), `apm compile --target claude` now omits
the "Project Standards" section from CLAUDE.md to avoid duplicating
instructions in Claude Code's context window.

CLAUDE.md is still generated when it carries other non-duplicated content
(constitution block or dependency @import paths). Subdirectory CLAUDE.md
files are suppressed entirely since they would only contain instructions.

Detection: if `.claude/rules/` exists and contains any `.md` files, the
instructions are considered already deployed. An empty `.claude/rules/`
directory does not trigger skipping.

Refs: microsoft#1138

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Log "CLAUDE.md not generated" when skip_instructions results in no
  output, so users understand why no file was produced.
- Strengthen test assertion: assert CLAUDE.md does NOT exist (instead
  of conditional check) when no constitution/deps are present.
- Add test for .claude/rules/ containing only non-.md files (e.g.,
  .gitkeep) — verifies the glob doesn't false-positive.
- Add test for dry-run + skip_instructions combination.
- Add test verifying both log messages are emitted via mock logger.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 5, 2026 15:07
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR prevents Claude Code from seeing duplicated instructions when both apm install (deploys .claude/rules/*.md) and apm compile --target claude (generates CLAUDE.md) are used by detecting a populated .claude/rules/ directory and suppressing the # Project Standards section in CLAUDE.md (while still emitting constitution and dependency imports when present).

Changes:

  • Add .claude/rules/*.md detection in the Claude compile path and plumb a skip_instructions flag into the Claude formatter.
  • Update ClaudeFormatter to omit instruction output (and subdirectory CLAUDE.md placements) when skip_instructions is active, while preserving constitution/dependencies behavior.
  • Add unit tests for the skip behavior and record the fix in CHANGELOG.md.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/apm_cli/compilation/agents_compiler.py Detects populated .claude/rules/, passes skip_instructions, and emits info logs when output is suppressed.
src/apm_cli/compilation/claude_formatter.py Implements conditional suppression of # Project Standards and skips subdirectory/root outputs when only instructions would be emitted.
tests/unit/compilation/test_agents_compiler_coverage.py Adds coverage tests for the .claude/rules/ heuristic and logging behavior.
tests/unit/compilation/test_claude_formatter.py Adds formatter-level tests covering skip behavior across instructions/constitution/dependencies.
CHANGELOG.md Adds an Unreleased/Fixed entry for the deduplication behavior.

Comment thread src/apm_cli/compilation/claude_formatter.py
Comment thread tests/unit/compilation/test_agents_compiler_coverage.py Outdated
Comment thread src/apm_cli/compilation/agents_compiler.py
- Stats now reflect only emitted files (not skipped placements)
- Fix weak test assertion that could pass spuriously
- Add stats accuracy test for skip_instructions path
- Update compilation and IDE integration docs to mention deduplication
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.

Comment thread src/apm_cli/compilation/claude_formatter.py
Comment thread src/apm_cli/compilation/claude_formatter.py Outdated
Comment thread tests/unit/compilation/test_agents_compiler_coverage.py Outdated
Comment thread docs/src/content/docs/guides/compilation.md Outdated
Comment thread docs/src/content/docs/integrations/ide-tool-integration.md Outdated
tillig and others added 2 commits May 5, 2026 09:04
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
- Initialize _skip_instructions in __init__ to avoid AttributeError
- Update misleading comment about CLAUDE.md content scope
- Fix dry-run test to assert on stats (preview doesn't include section headers)
- Fix compilation guide "only instructions" note to exclude CLAUDE.md
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@tillig tillig requested a review from Copilot May 5, 2026 16:53
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@tillig tillig requested a review from Copilot May 5, 2026 18:32
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

- OSError fallback test now exercises real format_distributed() via mock
  placement path that raises on resolve(), triggering the actual fallback
- Symlink test uses unique tempfile.mkdtemp() for external dir to avoid
  collisions in parallel test runs
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

tillig added 3 commits May 11, 2026 15:31
…-instructions

# Conflicts:
#	CHANGELOG.md
#	docs/src/content/docs/guides/compilation.md
#	docs/src/content/docs/integrations/ide-tool-integration.md
The docs were restructured upstream (compilation.md removed,
ide-tool-integration.md rewritten as a hub). Add the Claude Code
deduplication note to the new canonical location for compile docs.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Comment thread src/apm_cli/compilation/claude_formatter.py Outdated
Comment thread src/apm_cli/compilation/claude_formatter.py Outdated
Comment thread src/apm_cli/compilation/claude_formatter.py Outdated
Comment thread src/apm_cli/compilation/claude_formatter.py Outdated
Comment thread tests/unit/compilation/test_agents_compiler_coverage.py Outdated
tillig added 2 commits May 11, 2026 16:10
- Add is_root field to ClaudePlacement dataclass; set it in
  _generate_placements so root detection is computed once and
  used consistently everywhere (no resolve/absolute fallback).
- Remove _skip_instructions mutable instance state from
  ClaudeFormatter; pass skip_instructions as a keyword argument
  to _generate_claude_content instead.
- Hoist read_constitution() call before the placement loop to
  avoid redundant reads on every iteration.
- Fix grammar: "Would generate 1 files" -> "Would generate 1 file".
- Skip message now explains "to avoid duplicate context" so users
  understand the optimization is intentional.
- Zero-file message now reassures users: "Claude Code reads
  .claude/rules/ directly, no further action needed."
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Comment thread src/apm_cli/compilation/claude_formatter.py Outdated
Comment thread src/apm_cli/compilation/agents_compiler.py
Comment thread docs/src/content/docs/producer/compile.md
Comment thread tests/unit/compilation/test_agents_compiler_coverage.py
- Create root placement when dependencies exist (not only when
  constitution exists), fixing dependency-only project edge case.
- Suppress CompilationFormatter output when skip_instructions
  filtered all placements to avoid contradicting the "not generated"
  log message.
- Update "Where instructions land" table to note CLAUDE.md may be
  omitted when .claude/rules/ is populated.
- Convert bare assert statements to self.assert* for consistency
  with the rest of the unittest.TestCase file.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Skip instructions in CLAUDE.md when already deployed to .claude/rules/

3 participants