Title:
SessionStart hook ignores inject_claude_md: false config and .cognilayer-no-inject sentinel (v4.3.0)
Body:
Summary
hooks/on_session_start.py in v4.3.0 unconditionally rewrites the === COGNILAYER === block in CLAUDE.md from the claude_md.template i18n string. Two documented opt-out mechanisms are no longer honored.
Reproduction
- CogniLayer v4.3.0 installed at
~/.cognilayer/
- Project at
~/Documents/GitHub/<name> with:
~/.cognilayer/config.yaml containing:
project_overrides:
<name>:
inject_claude_md: false
- Repo root sentinel file
.cognilayer-no-inject present
CLAUDE.md committed to git with a hand-edited === COGNILAYER (auto-generated, do not delete) === block
- Start a Claude Code session in that project.
- Observe:
git status shows CLAUDE.md modified. The COGNILAYER block has been overwritten with the current claude_md.template output.
Evidence
$ grep -rn "inject_claude_md\|no-inject\|no_inject" ~/.cognilayer/ --include="*.py"
(empty — zero matches across all Python files, including hooks/on_session_start.py)
$ diff <(awk '/# === COGNILAYER/,/=== END COGNILAYER ===/' CLAUDE.md | ...) \
<(python3 -c "from i18n import t; print(t('claude_md.template'))")
(empty — byte-identical match, confirming the COGNILAYER block came from the template)
config.yaml documents the override:
project_overrides:
portalpilot:
# Don't inject CogniLayer block into CLAUDE.md — it's committed to git
# and already well-structured. Use MCP tools instead.
inject_claude_md: false
But inject_cognilayer_block() and _inject_once() in hooks/on_session_start.py make no reference to inject_claude_md or to the project name when deciding whether to write — only when deciding what content to write.
Impact
For projects that commit CLAUDE.md to git:
- Every session start produces a permanent dirty working tree
- CI/lint hooks that block dirty trees (e.g. branch-guard) interfere
- Any hand-edits to the COGNILAYER block (e.g. project-specific guidance kept in-band) are silently reverted on every session start
- Project-specific
inject_claude_md: false and the historically working .cognilayer-no-inject sentinel both became no-ops between earlier 4.x versions and 4.3.0
Expected behavior
_inject_once() (or its caller) should short-circuit when either:
project_overrides[<project_name>].inject_claude_md is false, OR
- A sentinel file exists at
<project_path>/.cognilayer-no-inject
The MCP tools (memory_search, project_context, session_bridge) provide on-demand access to the same DNA/bridge/briefs content, so opting out of the in-CLAUDE.md mirror is reasonable.
Suggested fix
Roughly:
def _should_inject(project_path: Path, project_name: str, config: dict) -> bool:
if (project_path / ".cognilayer-no-inject").exists():
return False
overrides = config.get("project_overrides", {}).get(project_name, {})
if overrides.get("inject_claude_md") is False:
return False
return True
Called inside inject_cognilayer_block() (or earlier in on_session_start_hook()) before the file write.
Workaround for affected users
Disable the CogniLayer SessionStart hook entirely in ~/.claude/settings.json (Claude Code's user-global settings). MCP tools remain functional.
Environment
- CogniLayer: v4.3.0 (
~/.cognilayer/VERSION)
- Claude Code (recent), macOS Darwin 25.4.0
- Hook mtimes confirm a recent upgrade rewrote
on_session_start.py, i18n.py, and most of mcp-server/
GitHub issue draft — file at https://github.com/LakyFx/CogniLayer/issues/new
Title:
SessionStart hook ignores
inject_claude_md: falseconfig and.cognilayer-no-injectsentinel (v4.3.0)Body:
Summary
hooks/on_session_start.pyin v4.3.0 unconditionally rewrites the=== COGNILAYER ===block in CLAUDE.md from theclaude_md.templatei18n string. Two documented opt-out mechanisms are no longer honored.Reproduction
~/.cognilayer/~/Documents/GitHub/<name>with:~/.cognilayer/config.yamlcontaining:.cognilayer-no-injectpresentCLAUDE.mdcommitted to git with a hand-edited=== COGNILAYER (auto-generated, do not delete) ===blockgit statusshowsCLAUDE.mdmodified. The COGNILAYER block has been overwritten with the currentclaude_md.templateoutput.Evidence
config.yamldocuments the override:But
inject_cognilayer_block()and_inject_once()inhooks/on_session_start.pymake no reference toinject_claude_mdor to the project name when deciding whether to write — only when deciding what content to write.Impact
For projects that commit
CLAUDE.mdto git:inject_claude_md: falseand the historically working.cognilayer-no-injectsentinel both became no-ops between earlier 4.x versions and 4.3.0Expected behavior
_inject_once()(or its caller) should short-circuit when either:project_overrides[<project_name>].inject_claude_mdisfalse, OR<project_path>/.cognilayer-no-injectThe MCP tools (
memory_search,project_context,session_bridge) provide on-demand access to the same DNA/bridge/briefs content, so opting out of the in-CLAUDE.md mirror is reasonable.Suggested fix
Roughly:
Called inside
inject_cognilayer_block()(or earlier inon_session_start_hook()) before the file write.Workaround for affected users
Disable the CogniLayer SessionStart hook entirely in
~/.claude/settings.json(Claude Code's user-global settings). MCP tools remain functional.Environment
~/.cognilayer/VERSION)on_session_start.py,i18n.py, and most ofmcp-server/