headroom/tests/test_learn
Manmit Singh c600e314b3
fix(learn): honor CLAUDE_CONFIG_DIR when locating Claude logs and memory (#1642)
## Description

`headroom learn` ignored `CLAUDE_CONFIG_DIR`.
`ClaudeCodePlugin.__init__` resolved the Claude config directory as
`~/.claude`, and the memory writer wrote the global `CLAUDE.md` to
`~/.claude/CLAUDE.md`. A user who relocates their Claude config with
that env var had `learn` scan the wrong directory and detect no
projects.

Other parts of the codebase already honor the override
(`subscription/client.py`, `subscription/session_tracking.py`,
`mcp_registry/claude.py`); the `learn` path was the outlier.

Closes #1630

## Type of Change

- [x] Bug fix (non-breaking change that fixes an issue)

## Changes Made

- Add `claude_config_dir()` to `headroom/learn/_shared.py` — returns
`$CLAUDE_CONFIG_DIR` when set, else `~/.claude` (via `Path.home()`,
matching the existing override elsewhere).
- `ClaudeCodePlugin.__init__` now defaults `claude_dir` to
`claude_config_dir()` instead of a hardcoded `~/.claude` (an explicit
`claude_dir=` argument still wins).
- `ClaudeCodeWriter._resolve_context_path` writes the home-directory
global memory to `claude_config_dir() / "CLAUDE.md"` instead of
`~/.claude/CLAUDE.md`.

## Testing

- [x] Unit tests pass (`pytest`)
- [x] Linting passes (`ruff check .`)
- [x] Type checking passes (`mypy headroom`)
- [x] New tests added for new functionality
- [x] Manual testing performed

### Test Output

```text
$ pytest tests/test_learn/test_claude_config_dir.py tests/test_learn/test_writer.py -q
35 passed, 1 warning in 0.18s

$ ruff check headroom/learn/ tests/test_learn/test_claude_config_dir.py
All checks passed!

$ mypy headroom/learn/_shared.py headroom/learn/plugins/claude.py headroom/learn/writer.py
Success: no issues found in 3 source files
```

## Real Behavior Proof

- Environment: macOS (arm64), Python 3.14 venv, editable install of this
branch.
- Exact command / steps: ran `python -c "from
headroom.learn.plugins.claude import ClaudeCodePlugin;
print(ClaudeCodePlugin().projects_dir)"` with and without
`CLAUDE_CONFIG_DIR=/tmp/altclaude` set, then `pytest tests/test_learn/
tests/test_cli_learn.py`.
- Observed result: default prints `/Users/<me>/.claude/projects`; with
`CLAUDE_CONFIG_DIR=/tmp/altclaude` it prints `/tmp/altclaude/projects`
(before this change the second still printed `~/.claude/projects`). Test
suite: 226 passed, 3 skipped. New regression tests cover the plugin scan
dir, explicit-arg precedence, and the writer's home-memory path.
- Not tested: end-to-end `headroom learn` against a real relocated log
tree with live Claude Code transcripts — verified at the plugin/writer
resolution layer plus the existing scanner suite.

## Review Readiness

- [x] I have performed a self-review
- [x] This PR is ready for human review

## Additional Notes

The identical hardcode also exists at `headroom/cli/mcp.py:21`
(`CLAUDE_CONFIG_DIR = Path.home() / ".claude"`), but that is a separate
command outside this issue's scope, so I left it for a follow-up to keep
this PR to one issue.

---------

Co-authored-by: JerrettDavis <mxjerrett@gmail.com>
2026-07-01 23:22:16 -05:00
..
__init__.py Add headroom learn: offline failure learning for coding agents 2026-02-27 21:19:03 -08:00
test_analyzer.py fix(learn): claude-cli streams output with idle timeout (#373) 2026-06-11 11:55:19 -05:00
test_claude_config_dir.py fix(learn): honor CLAUDE_CONFIG_DIR when locating Claude logs and memory (#1642) 2026-07-01 23:22:16 -05:00
test_gemini_scanner.py Plugin architecture for headroom learn + live traffic flush 2026-04-09 20:30:20 -07:00
test_integration.py feat(learn): write per-project learnings to CLAUDE.local.md by default (#1115) 2026-06-22 15:05:06 -05:00
test_loop_weighting.py feat(learn): weight loops in Headroom Learn + RTK-loop eval (#1160) 2026-06-22 18:49:08 -05:00
test_opencode_scanner.py feat: add first-class OpenCode support (wrap, learn, mcp install) (#559) 2026-06-25 13:38:58 -05:00
test_plugin_encoding.py Fix headroom learn crashing/no-op on Windows from missing UTF-8 encoding (#1239) 2026-06-21 10:37:37 -07:00
test_registry.py feat: add first-class OpenCode support (wrap, learn, mcp install) (#559) 2026-06-25 13:38:58 -05:00
test_rtk_loop_eval.py feat(learn): weight loops in Headroom Learn + RTK-loop eval (#1160) 2026-06-22 18:49:08 -05:00
test_scanner.py feat: headroom wrap opencode / unwrap opencode CLI (#1105) 2026-06-22 11:07:12 -05:00
test_subagent_scanning.py fix(learn): scan subagent and workflow transcripts (#1045) 2026-06-16 12:20:37 -07:00
test_writer.py feat(learn): write per-project learnings to CLAUDE.local.md by default (#1115) 2026-06-22 15:05:06 -05:00