Claude Code that learns you — silent memory injection, self-updating notes, self-grooming, privacy-first local-only. Status: v0.2 shipped; L1 quality loop + permit learning active.
src/shed/inject.py—inject_for_prompt(): semantic search → quality re-ranking →<shed-context>block printed to stdout; called byUserPromptSubmithooksrc/shed/observe.py—observe_text(): regex correction detection → classify → redact → write proposal.md;observe_tool_use(): cross-references PostToolUse against permitssrc/shed/reflect.py—reflect_text(): Stop hook handler; runs citation detection + refreshes statusline cache + delegates toobserve_textsrc/shed/quality.py— L1 quality loop:log_injection()/log_citations()/compute_scores(); exponential decay scoring;detect_citations_in_response()src/shed/thresholds.py— L5 self-tuning:log_feedback()writes accept/reject decisions;tune()recomputes per-kind thresholds from 75th-pct of recent acceptssrc/shed/statusline.py— renders[shed:●●●○ 3↓ ✓2]; cached to~/.shed/state/statusline.txt;install_to_claude_settings()wires it insrc/shed/brief.py—walk_brief()interactive TUI (y/n/e/s/p/q),render_brief()for SessionStart hook; handles both "lesson" and "permit" proposalssrc/shed/config.py—Config(pydantic), all path functions (shed_home,proposals_dir,state_dir, etc.),current_mode(), env var overrides (SHED_HOME,SHED_MODE, etc.)src/shed/embeddings.py—Index(FAISS or fallback),get_embedder(); uses BAAI/bge-small-en-v1.5 via onnxruntime (not torch)src/shed/memory.py—Memorydataclass,discover(),save(); scansmemory_roots()src/shed/permit.py— L3 permission-pattern learning;record_approval(),apply_proposal()src/shed/redact.py— PII redaction before writing proposalssrc/shed/classify.py— maps free-text correction to an allowlisted categorysrc/shed/runtime/— S1 conductor runtime: budget governor, host keepawake, and continuation worker; launchdcom.casterly.shed-runtimeticksshed runtime-tickevery 60s; trigger-policy contract + matrix indocs/runtime.md.
- Three Claude Code hooks drive shed:
UserPromptSubmit→ inject,PostToolUse→ observe_tool_use,Stop→ reflect - Fail-open everywhere: any exception in inject returns
""(no injection, no crash) - Hard timeout: inject must finish in <200ms (the shell wrapper enforces 2s)
- Privacy:
mode = private(.shed-offfile in cwd, orSHED_MODE=private) silences all disk writes and injection - Memory roots:
~/.claude/projects/*/memory/dirs; global CLAUDE.md is also read - L1 quality loop:
injectlogs"injected"events;reflectscans response for 12-char substrings or title matches → logs"cited"events; scoring =(cited_recent + 0.5) / (injected_recent + 1.0)with exp-decay half-life 30d - Final ranking:
cosine * (1 - quality_weight) + injection_score * quality_weightwherequality_weight=0.3by default SHED_MAX_INJECTenv var (set by inject hook when session is heavy) capstop_kto save context- Proposals are markdown files in
~/.shed/proposals/;briefwalks them; accepted lessons land in firstmemory_root() - Permit proposals prefix filename with
permit-; accepting them callsshed.permit.apply_proposal() - Config at
~/.shed/config.toml(TOML/pydantic); all path dirs overridable viaSHED_*env vars for tests statusline.enabled = Falseby default (opt-in, since writing tosettings.jsonis intrusive)
cd /Users/casterly/Documents/Dev/shed
uv run pytest # full suite
uv run python -m shed brief # interactive proposal walk-through
uv run python -m shed inject # test inject (reads stdin as prompt)
uv run python -m shed status # show current mode + pending count- Working: inject, observe, reflect, quality L1, permits L3, thresholds L5, statusline, brief, and the S1 runtime. Its end-to-end wall-crossing behavior is documented in the runtime guide; lid-close survival needs the sudoers line printed by
install-runtime.sh. - Trigger policy (2026-06-04): every session has one origin —
SHED_ORIGIN=phone(watcher-spawned) vs interactive (untagged). Phone runs: no compact-guard interjections, no pending-inject read/write, no threshold learning; handoff docs still written. Interactive terminals are NEVER signaled/closed by the runtime —shed park [--goal]is the only handover verb. Goal runs (workflow goal: …email /park --goal) relaunch in cycles until literalGOAL-COMPLETElast line orexpires_at(48h default;hours:/days:body directives). Matrix:docs/runtime.md - Haiku judge (
observe.use_haiku_judge) is wired but off by default — keep cost zero - Embedder is onnxruntime/bge-small (not torch) — do not introduce torch dependency (#8 fix)
evolve(cold-memory pruning + dedup) is config-gated;evolve.enabled=Truebut only runs on-demand viashed evolve- Sync (
sync.enabled=False) is wired but not activated — git remote is pre-configured for private state repo