Summary
When a project has a CLAUDE.md file (strong signal that Claude Code is in use) but no .claude/ directory, apm install and apm compile --targets all silently skip Claude skill deployment. No warning is emitted, and the user has no indication that Claude was excluded from skill integration.
To Reproduce
-
Start with a repo that has CLAUDE.md and .github/ but no .claude/ directory:
CLAUDE.md ← exists (file)
.github/ ← exists (directory)
apm.yml ← no explicit target: field
-
Run apm install followed by apm compile --targets all
-
Observe that .agents/skills/ is populated (for Copilot, Cursor, Codex, etc.) but .claude/skills/ is never created.
Expected behavior
One of:
.claude/skills/ is created and populated (since CLAUDE.md indicates Claude Code usage), OR
- A warning is emitted explaining that Claude skill deployment was skipped because
.claude/ does not exist, with guidance on how to enable it (e.g., "create .claude/ or set target: claude in apm.yml")
Root cause
Three factors combine to produce the silent skip:
-
Auto-detection doesn't see Claude. target_detection.py:167 checks (project_root / ".claude").exists() — this looks for a path literally named .claude, not for CLAUDE.md. A project with only CLAUDE.md (no .claude/ directory) does not register Claude as a detected target.
-
auto_create=False for Claude. Even when --targets all resolves and includes Claude in the target list, the directory-creation loop in install/phases/targets.py:161 skips it:
if not _t.auto_create and not _explicit:
continue
The --targets all value from auto-detection (triggered by ≥2 detected folders) is not considered "explicit" in the _explicit variable sense (which tracks --target CLI flag or apm.yml target: field).
-
Skill integrator bails out. skill_integrator.py:341 independently guards on the directory:
if not target.auto_create and not target_root_dir.is_dir():
continue
So even if Claude somehow ends up in the resolved target set, skills aren't deployed.
Relationship to existing issues
Workarounds
Any of:
mkdir .claude before running apm install
- Add
target: claude (or target: all) to apm.yml
Neither is documented, and the behavior is surprising for users who expect CLAUDE.md to be sufficient signal.
Possible approaches
A few options (not prescriptive — just thinking out loud):
- Expand auto-detection: Treat the existence of
CLAUDE.md as equivalent to .claude/ for target detection purposes.
- Emit a warning: When Claude is in the resolved target set but
.claude/ doesn't exist, log a message suggesting the user create it or set an explicit target.
- Treat
--targets all as explicit: When the user passes --targets all on the CLI, treat it the same as an explicit target for the auto_create guard (distinct from auto-detected "all").
Environment
- APM: v0.12.2 (2b1fb6b)
- OS: macOS 15.5 (Darwin 25.4.0)
- Claude Code: 1.0.33
Summary
When a project has a
CLAUDE.mdfile (strong signal that Claude Code is in use) but no.claude/directory,apm installandapm compile --targets allsilently skip Claude skill deployment. No warning is emitted, and the user has no indication that Claude was excluded from skill integration.To Reproduce
Start with a repo that has
CLAUDE.mdand.github/but no.claude/directory:Run
apm installfollowed byapm compile --targets allObserve that
.agents/skills/is populated (for Copilot, Cursor, Codex, etc.) but.claude/skills/is never created.Expected behavior
One of:
.claude/skills/is created and populated (sinceCLAUDE.mdindicates Claude Code usage), OR.claude/does not exist, with guidance on how to enable it (e.g., "create.claude/or settarget: claudein apm.yml")Root cause
Three factors combine to produce the silent skip:
Auto-detection doesn't see Claude.
target_detection.py:167checks(project_root / ".claude").exists()— this looks for a path literally named.claude, not forCLAUDE.md. A project with onlyCLAUDE.md(no.claude/directory) does not register Claude as a detected target.auto_create=Falsefor Claude. Even when--targets allresolves and includes Claude in the target list, the directory-creation loop ininstall/phases/targets.py:161skips it:The
--targets allvalue from auto-detection (triggered by ≥2 detected folders) is not considered "explicit" in the_explicitvariable sense (which tracks--targetCLI flag orapm.yml target:field).Skill integrator bails out.
skill_integrator.py:341independently guards on the directory:So even if Claude somehow ends up in the resolved target set, skills aren't deployed.
Relationship to existing issues
[BUG] apm install never deploys local .apm/ primitives to .claude/ because claude isn't a registered runtime #751 (closed): Described
apm install --target claudesilently skipping deployment. Fixed by PR fix: create target dir for explicit --target claude; content hash fallback when .git absent #763, which gates directory creation on_explicit— so explicit--target claudeortarget: claudeinapm.ymlnow works correctly. The scenario here is different: no explicit target is set, and the user relies on auto-detection.Scope-awareness gaps: hook integrator, auto_create, integration tests #576 (closed): Identified that
install.pywas creating directories forauto_create=Falsetargets under--target=all(P1-4). The fix correctly gatedmkdironauto_create— but didn't account for the case where a project clearly uses Claude (evidenced byCLAUDE.md) without having a.claude/directory yet.Workarounds
Any of:
mkdir .claudebefore runningapm installtarget: claude(ortarget: all) toapm.ymlNeither is documented, and the behavior is surprising for users who expect
CLAUDE.mdto be sufficient signal.Possible approaches
A few options (not prescriptive — just thinking out loud):
CLAUDE.mdas equivalent to.claude/for target detection purposes..claude/doesn't exist, log a message suggesting the user create it or set an explicit target.--targets allas explicit: When the user passes--targets allon the CLI, treat it the same as an explicit target for theauto_createguard (distinct from auto-detected "all").Environment