Personalization currently captures full `export NAME=value` payloads and
re-injects them through local rules into future system prompts. Narrow the
environment-variable extraction to the variable name so the feature can still
remember environment hints without persisting secret material.
Constraint: Keep personalization's environment-hint workflow intact
Rejected: Remove env_var extraction entirely | larger behavior change than needed for a first fix
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Do not persist raw env var values without a separate sensitivity model and tests
Tested: PYTHONPATH=src pytest -q tests/test_personalization/test_extractor.py tests/test_prompts/test_claudemd.py
Tested: PYTHONPATH=src ruff check src tests
Not-tested: Full pytest suite in this environment (collection fails because optional pyperclip dependency is missing)
Related: #149
Add a personalization layer that learns the user's local environment from
conversation history and injects discovered rules into the system prompt.
Problem: Every OH user has unique infrastructure (server IPs, data paths,
conda envs, API endpoints, cron schedules) that must be manually configured
in CLAUDE.md or system_prompt. This is tedious and easy to forget.
Solution: Automatically extract environment-specific facts from each session
and persist them as local rules that are injected into future sessions.
How it works:
1. SESSION END: extractor scans conversation for patterns (SSH hosts,
data paths, conda envs, API endpoints, env vars, Ray config, etc.)
2. PERSISTENCE: facts are merged into ~/.openharness/local_rules/facts.json
with deduplication and confidence scoring
3. SESSION START: local rules are loaded as markdown and injected into
the system prompt alongside CLAUDE.md and memory
Files:
- personalization/extractor.py: regex-based fact extraction (10 pattern types)
- personalization/rules.py: facts persistence and rules markdown generation
- personalization/session_hook.py: session-end integration
- prompts/context.py: inject local rules into system prompt
- ui/runtime.py: call extraction at session close (best-effort, non-blocking)
- 12 tests covering extraction, merging, and markdown generation
The extraction is pattern-based (no LLM calls needed), zero-cost, and
runs in <10ms at session end. Facts accumulate over sessions, building
a progressively richer environment profile.