@rm0nroe/coach-claw 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +311 -0
- package/coach/README.md +99 -0
- package/coach/bin/aggregate_facets.py +274 -0
- package/coach/bin/analyze.py +678 -0
- package/coach/bin/bank.py +247 -0
- package/coach/bin/banner_themes.py +645 -0
- package/coach/bin/coach_paths.py +33 -0
- package/coach/bin/coexistence_check.py +129 -0
- package/coach/bin/configure.py +245 -0
- package/coach/bin/cron_check.py +81 -0
- package/coach/bin/default_statusline.py +135 -0
- package/coach/bin/doctor.py +663 -0
- package/coach/bin/insights-llm.sh +264 -0
- package/coach/bin/insights.sh +163 -0
- package/coach/bin/insights_window.py +111 -0
- package/coach/bin/marker_io.py +154 -0
- package/coach/bin/merge.py +671 -0
- package/coach/bin/redact.py +86 -0
- package/coach/bin/render_env.py +148 -0
- package/coach/bin/reward_hints.py +87 -0
- package/coach/bin/run-insights.sh +20 -0
- package/coach/bin/run_with_lock.py +85 -0
- package/coach/bin/scoring.py +260 -0
- package/coach/bin/skill_inventory.py +215 -0
- package/coach/bin/stats.py +459 -0
- package/coach/bin/status.py +293 -0
- package/coach/bin/statusline_self_patch.py +205 -0
- package/coach/bin/statusline_variants.py +146 -0
- package/coach/bin/statusline_wrap.py +244 -0
- package/coach/bin/statusline_wrap_action.py +460 -0
- package/coach/bin/switch_to_plugin.py +256 -0
- package/coach/bin/themes.py +256 -0
- package/coach/bin/user_config.py +176 -0
- package/coach/bin/xp_accounting.py +98 -0
- package/coach/changelog.md +4 -0
- package/coach/default-statusline-command.sh +19 -0
- package/coach/default-statusline-wrap-command.sh +15 -0
- package/coach/profile.yaml +37 -0
- package/coach/tests/conftest.py +13 -0
- package/coach/tests/test_aggregate_facets.py +379 -0
- package/coach/tests/test_analyze_aggregate.py +153 -0
- package/coach/tests/test_analyze_redaction.py +105 -0
- package/coach/tests/test_analyze_strengths.py +165 -0
- package/coach/tests/test_bank_atomic_write.py +61 -0
- package/coach/tests/test_bank_concurrency.py +126 -0
- package/coach/tests/test_banner_themes.py +981 -0
- package/coach/tests/test_celebrate_dedup.py +409 -0
- package/coach/tests/test_coach_paths.py +50 -0
- package/coach/tests/test_coexistence_check.py +128 -0
- package/coach/tests/test_configure.py +258 -0
- package/coach/tests/test_cron_check.py +118 -0
- package/coach/tests/test_cron_nudge_hook.py +134 -0
- package/coach/tests/test_detection_parity.py +105 -0
- package/coach/tests/test_doctor.py +595 -0
- package/coach/tests/test_hook_bespoke_dispatch.py +288 -0
- package/coach/tests/test_hook_module_resolution.py +116 -0
- package/coach/tests/test_hook_relevance.py +996 -0
- package/coach/tests/test_hook_render_env.py +364 -0
- package/coach/tests/test_hook_session_id_guard.py +160 -0
- package/coach/tests/test_insights_llm.py +759 -0
- package/coach/tests/test_insights_llm_venv_path.py +109 -0
- package/coach/tests/test_insights_window.py +237 -0
- package/coach/tests/test_install.py +1150 -0
- package/coach/tests/test_install_pyyaml_fallback.py +142 -0
- package/coach/tests/test_marker_consumption.py +167 -0
- package/coach/tests/test_marker_writer_locking.py +305 -0
- package/coach/tests/test_merge.py +413 -0
- package/coach/tests/test_no_broken_mktemp.py +90 -0
- package/coach/tests/test_render_env.py +137 -0
- package/coach/tests/test_render_env_glyphs.py +119 -0
- package/coach/tests/test_reward_hints.py +59 -0
- package/coach/tests/test_scoring.py +147 -0
- package/coach/tests/test_session_start_weekly_trigger.py +92 -0
- package/coach/tests/test_skill_inventory.py +368 -0
- package/coach/tests/test_stats_hybrid.py +142 -0
- package/coach/tests/test_status_accounting.py +41 -0
- package/coach/tests/test_statusline_failsafe.py +70 -0
- package/coach/tests/test_statusline_self_patch.py +261 -0
- package/coach/tests/test_statusline_variants.py +110 -0
- package/coach/tests/test_statusline_wrap.py +196 -0
- package/coach/tests/test_statusline_wrap_action.py +408 -0
- package/coach/tests/test_switch_to_plugin.py +360 -0
- package/coach/tests/test_themes.py +104 -0
- package/coach/tests/test_user_config.py +160 -0
- package/coach/tests/test_wrap_announce_hook.py +130 -0
- package/coach/tests/test_xp_accounting.py +55 -0
- package/hooks/coach-session-start.py +536 -0
- package/hooks/coach-user-prompt.py +2288 -0
- package/install-launchd.sh +102 -0
- package/install.sh +597 -0
- package/launchd/com.local.claude-coach.plist.template +34 -0
- package/launchd/run-insights.sh +20 -0
- package/npm/coach-claw.js +259 -0
- package/package.json +52 -0
- package/requirements.txt +11 -0
- package/settings-snippet.json +31 -0
- package/skills/coach/SKILL.md +107 -0
- package/skills/coach-insights/SKILL.md +78 -0
- package/skills/config/SKILL.md +149 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ryan Monroe
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
# Coach Claw
|
|
2
|
+
|
|
3
|
+
> [**rm0nroe.github.io/coach-claw →**](https://rm0nroe.github.io/coach-claw/) · live demo with the scroll-pinned tip walkthrough
|
|
4
|
+
|
|
5
|
+
A self-evolving coaching layer for [Claude Code](https://claude.com/claude-code). It learns
|
|
6
|
+
from your actual session transcripts and nudges your habits — both the ones to break and
|
|
7
|
+
the ones to keep going — with XP-rewarded ambient tips inside Claude Code.
|
|
8
|
+
|
|
9
|
+
A daily background pass (the deterministic Coach insights cron) detects concrete behavior
|
|
10
|
+
patterns from your transcripts. The `SessionStart` hook injects the watch-list into Claude's
|
|
11
|
+
context. The `UserPromptSubmit` hook runs a deterministic scheduler — picks a tip, pre-computes
|
|
12
|
+
its reward attribution, asks Claude to render it. Follow the tip → next turn shows `✅ Tip cleared`.
|
|
13
|
+
Five clean Coach insights runs in a row → the weakness graduates and retires. Lifetime XP
|
|
14
|
+
crosses a threshold → 🎉 Level up.
|
|
15
|
+
|
|
16
|
+
**Cron path: local-only, zero network.** Transcripts and the profile live under `~/.claude/`.
|
|
17
|
+
The scheduled cron pass is pure Python — no LLM call, no token cost. **Weekly path + on-demand
|
|
18
|
+
`/coach-insights`** triggers Claude Code's built-in `/insights` once per 7 days (via `claude -p`)
|
|
19
|
+
to refresh structured `facets/*.json` sidecar data. Coach itself does not independently upload
|
|
20
|
+
transcripts; the nested `/insights` refresh is an Anthropic-side Claude Code operation that
|
|
21
|
+
runs inside the user's existing authenticated session and writes only to local sidecar files.
|
|
22
|
+
Coach reads those local sidecars. The LLM call's content output is discarded — only the sidecar
|
|
23
|
+
refresh matters. Detections come from deterministic Python aggregation of stable enum keys.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Install
|
|
28
|
+
|
|
29
|
+
Coach Claw ships two parallel distributions. Pick whichever you prefer
|
|
30
|
+
— they share the same `~/.claude/coach/` state, so you can use either
|
|
31
|
+
or both:
|
|
32
|
+
|
|
33
|
+
| Path | Best for | Command |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| **npm CLI** (canonical) | Provider-agnostic + OS-side cron + statusLine | `npx @rm0nroe/coach-claw@latest install` |
|
|
36
|
+
| **Claude Code plugin** | Marketplace install, no terminal needed | `/plugin marketplace add rm0nroe/coach-claw-plugin-marketplace` then `/plugin install coach-claw@coach-claw-plugins` |
|
|
37
|
+
|
|
38
|
+
The npm CLI is the canonical path — it manages launchd/cron registration,
|
|
39
|
+
patches the main statusline, and works regardless of which AI coding
|
|
40
|
+
assistant you're using day-to-day. The plugin is a Claude-Code-native
|
|
41
|
+
alternative that self-installs hooks and statusline; it nudges you to
|
|
42
|
+
the npm CLI for OS-level scheduling that the plugin model can't
|
|
43
|
+
register on its own. When both are installed, the plugin defers to the
|
|
44
|
+
CLI by default (run `/coach-claw:switch` to flip control).
|
|
45
|
+
|
|
46
|
+
### Prerequisites (both paths)
|
|
47
|
+
|
|
48
|
+
- macOS 11+ or Linux
|
|
49
|
+
- `bash`, `git`, Python 3.8+ (system or Homebrew)
|
|
50
|
+
- [Claude Code](https://claude.com/claude-code) installed and run at least once
|
|
51
|
+
- PyYAML — the npm installer auto-installs it; the plugin path
|
|
52
|
+
provisions a per-plugin venv on first SessionStart. See
|
|
53
|
+
[Troubleshooting](#troubleshooting) if either path's PyYAML setup fails.
|
|
54
|
+
|
|
55
|
+
### Install via npm CLI
|
|
56
|
+
|
|
57
|
+
1. **Check your machine**
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npx @rm0nroe/coach-claw@latest doctor
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
2. **Run the installer**
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npx @rm0nroe/coach-claw@latest install --seed
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`--seed` is optional but recommended — it pre-populates your profile
|
|
70
|
+
from the last 7 days of transcripts so your first session isn't empty.
|
|
71
|
+
See [Install options](#install-options) for the full flag list.
|
|
72
|
+
|
|
73
|
+
3. **Register the daily insights cron**
|
|
74
|
+
|
|
75
|
+
- **macOS**:
|
|
76
|
+
```bash
|
|
77
|
+
npx @rm0nroe/coach-claw@latest launchd
|
|
78
|
+
```
|
|
79
|
+
- **Linux** — `crontab -e`, then add (runs daily at 04:00 local):
|
|
80
|
+
```
|
|
81
|
+
0 4 * * * $HOME/.claude/coach/bin/insights.sh 1d >> /tmp/claude-coach.log 2>&1
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
4. **Verify**
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npx @rm0nroe/coach-claw@latest doctor
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Open a fresh Claude Code session and run:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
/coach status
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
You should see your level, ELO, and (if `--seed` was passed) a
|
|
97
|
+
tracked weakness or two.
|
|
98
|
+
|
|
99
|
+
5. **(Optional) Customize the look**
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
npx @rm0nroe/coach-claw@latest config wizard
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Interactive picker for statusline variant + theme. Or
|
|
106
|
+
non-interactive:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
npx @rm0nroe/coach-claw@latest config set --theme ocean --statusline pips
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Same backing file as the `/config` slash command inside Claude
|
|
113
|
+
Code — `~/.claude/coach/.user_config.json`. Run either surface
|
|
114
|
+
any time, they don't conflict.
|
|
115
|
+
|
|
116
|
+
### Install options
|
|
117
|
+
|
|
118
|
+
| Flag | Effect |
|
|
119
|
+
|---|---|
|
|
120
|
+
| `--seed` (alias `--bootstrap`) | After install, run a 7-day insights pass against your existing transcripts so the profile isn't empty on day one. |
|
|
121
|
+
| `--no-seed` | Skip seeding explicitly (forward-compatible with a future TTY-gated seed prompt). Mutually exclusive with `--seed`. |
|
|
122
|
+
| `--fresh` | Skip recovery from a prior `/coach uninstall`. Forces a true fresh install (drops any `coach.bak.<ts>/` siblings). |
|
|
123
|
+
| `--no-prune-backups` | Keep ALL `coach.bak.<ts>/`, `settings.json.bak.<ts>`, and `hooks/*.bak.<ts>`. Default trims to the 3 most recent of each kind. |
|
|
124
|
+
| `-h`, `--help` | Print full usage and exit. |
|
|
125
|
+
|
|
126
|
+
### Install via Claude Code plugin
|
|
127
|
+
|
|
128
|
+
If you'd rather install from inside Claude Code, add the marketplace
|
|
129
|
+
once and then install the plugin:
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
/plugin marketplace add rm0nroe/coach-claw-plugin-marketplace
|
|
133
|
+
/plugin install coach-claw@coach-claw-plugins
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
After install, restart Claude Code (or open a new session) so the
|
|
137
|
+
plugin's SessionStart hook can:
|
|
138
|
+
|
|
139
|
+
- bootstrap a per-plugin Python venv at `${CLAUDE_PLUGIN_DATA}/venv/`
|
|
140
|
+
(PyYAML lands there automatically)
|
|
141
|
+
- self-install the main statusline into `~/.claude/settings.json`
|
|
142
|
+
|
|
143
|
+
The plugin namespaces all skills under `/coach-claw:`:
|
|
144
|
+
|
|
145
|
+
| npm CLI command | Plugin equivalent |
|
|
146
|
+
|---|---|
|
|
147
|
+
| `/coach status` | `/coach-claw:coach status` |
|
|
148
|
+
| `/coach-insights` | `/coach-claw:coach-insights` |
|
|
149
|
+
| `/config` | `/coach-claw:config` |
|
|
150
|
+
| _(none — npm-only)_ | `/coach-claw:switch` (flip control to plugin if both installed) |
|
|
151
|
+
| _(none — npm-only)_ | `/coach-claw:doctor` (diagnose plugin state; `--remove-statusline`, `--wrap-statusline`, `--unwrap-statusline` actions) |
|
|
152
|
+
|
|
153
|
+
When Claude Code starts a session and finds a custom statusline, the
|
|
154
|
+
plugin auto-wraps it: your existing command keeps rendering, and the
|
|
155
|
+
Coach segment appends to it. Original is preserved in
|
|
156
|
+
`~/.claude/coach/.statusline-wrap.json`. Run
|
|
157
|
+
`/coach-claw:doctor --unwrap-statusline` to revert (sticky — the
|
|
158
|
+
plugin won't auto-rewrap). The CLI installer (`npx coach-claw install`)
|
|
159
|
+
does the same wrap on a fresh box.
|
|
160
|
+
|
|
161
|
+
The plugin **does not** register the daily insights cron. The first
|
|
162
|
+
time you start a session under a plugin-only install, you'll see a
|
|
163
|
+
one-time banner suggesting `npx @rm0nroe/coach-claw@latest launchd`.
|
|
164
|
+
The cron stays an npm-CLI feature because the plugin model has no
|
|
165
|
+
equivalent for OS-level scheduling.
|
|
166
|
+
|
|
167
|
+
### Troubleshooting
|
|
168
|
+
|
|
169
|
+
**`ERROR: could not install PyYAML automatically` on macOS**
|
|
170
|
+
|
|
171
|
+
Homebrew Python 3.12+ blocks `pip install --user` per PEP 668. The
|
|
172
|
+
installer auto-retries with `pip … --break-system-packages` (safe for
|
|
173
|
+
a per-user library install — the marker exists to protect *system*
|
|
174
|
+
site-packages, which `--user` doesn't touch). If both attempts fail,
|
|
175
|
+
install PyYAML manually with one of:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
python3 -m pip install --user --break-system-packages pyyaml
|
|
179
|
+
# or, if you'd rather isolate it:
|
|
180
|
+
python3 -m venv ~/.coach-venv && ~/.coach-venv/bin/pip install pyyaml
|
|
181
|
+
# then re-run install.sh with that venv's python3 on PATH:
|
|
182
|
+
PATH=~/.coach-venv/bin:$PATH ./install.sh
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Then re-run `./install.sh` (the first form) or use the `PATH=…` prefix
|
|
186
|
+
shown above (the venv form).
|
|
187
|
+
|
|
188
|
+
**`python3 not found in PATH`**
|
|
189
|
+
|
|
190
|
+
Install Python 3.8+ via your OS package manager (`brew install python`
|
|
191
|
+
on macOS) and re-run.
|
|
192
|
+
|
|
193
|
+
**More**: see
|
|
194
|
+
[`artifacts/infrastructure.md`](./artifacts/infrastructure.md).
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Use
|
|
199
|
+
|
|
200
|
+
Inside Claude Code (slash commands):
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
/coach status level, XP, weakness streaks, last Coach insights run
|
|
204
|
+
/coach off | on toggle without uninstalling
|
|
205
|
+
/coach uninstall mv (not rm) to ~/.claude/coach.bak.<ts>
|
|
206
|
+
/coach-insights manual LLM-driven pass — refreshes /insights facets
|
|
207
|
+
sidecars, aggregates stable enum keys, merges
|
|
208
|
+
into profile by default. Pass --dry-run to print
|
|
209
|
+
the detections JSON without merging. (Also fires
|
|
210
|
+
automatically once / 7d on session start.)
|
|
211
|
+
/config statusline variant + theme + ELO range
|
|
212
|
+
(4 variants × 12 themes — see /config preview)
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
From the terminal (same backing file as `/config`):
|
|
216
|
+
|
|
217
|
+
```
|
|
218
|
+
npx @rm0nroe/coach-claw@latest config preview # see all combos
|
|
219
|
+
npx @rm0nroe/coach-claw@latest config wizard # interactive picker
|
|
220
|
+
npx @rm0nroe/coach-claw@latest config set --theme ocean # scriptable
|
|
221
|
+
npx @rm0nroe/coach-claw@latest config set --statusline pips
|
|
222
|
+
npx @rm0nroe/coach-claw@latest config set --elo 1200 2800
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Per-session kill: `COACH_DISABLE=1 claude`.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Cost
|
|
230
|
+
|
|
231
|
+
| | Input tokens / session | Notes |
|
|
232
|
+
|---|---:|---|
|
|
233
|
+
| `SessionStart` block | ~2,400 | once per session, prompt-cacheable |
|
|
234
|
+
| Tip when fired | ~530 | 1–3 / session, probability + cooldown gated |
|
|
235
|
+
| Scheduled cron insights pass | **0** | pure Python, runs daily at 04:00 |
|
|
236
|
+
| Weekly LLM-driven trigger | one Claude session / 7 days | spawns `claude -p "/insights"` for the side effect of refreshing sidecars; output discarded |
|
|
237
|
+
| On-demand `/coach-insights` | one Claude session per `--force` invocation | same wrapper as the weekly trigger |
|
|
238
|
+
| Statusline + `/coach status` | **0** | pure Python |
|
|
239
|
+
|
|
240
|
+
≈ $0.03–$0.10/day on Sonnet, $0.15–$0.50/day on Opus at 5 sessions/day.
|
|
241
|
+
Weekly LLM trigger adds ~$0.01–$0.03/week (~$0.50/year) — we don't pay
|
|
242
|
+
for output tokens we don't read.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Privacy
|
|
247
|
+
|
|
248
|
+
**Cron path (the deterministic daily insights pass):** `coach/bin/redact.py` runs before any
|
|
249
|
+
transcript byte reaches `analyze.py`. Strips API keys (Anthropic, OpenAI, AWS, GitHub, Slack,
|
|
250
|
+
Stripe, HuggingFace, npm, Google), Bearer tokens, PEM blocks, JWTs, and long hex secrets.
|
|
251
|
+
Over-redacts by design — false positives are cheap, leaked credentials are not. `profile.yaml`
|
|
252
|
+
ends up with only pattern slugs, counts, and timestamps. Nothing leaves your machine.
|
|
253
|
+
|
|
254
|
+
**Weekly path + on-demand `/coach-insights`:** triggers Claude Code's built-in `/insights`
|
|
255
|
+
once per 7 days (via a `claude -p` subprocess). That's an Anthropic-side LLM step you're already
|
|
256
|
+
inside of by virtue of running Claude Code — Coach just runs it for the side effect of refreshing
|
|
257
|
+
`~/.claude/usage-data/facets/*.json`. We discard the CLI's content output and read only the
|
|
258
|
+
locally-written sidecar JSON Anthropic produces. Detections derive from stable enum keys
|
|
259
|
+
(`friction_counts.*`, `primary_success`) — deterministic Python aggregation, no slug translation,
|
|
260
|
+
no fuzzy matching. `profile.yaml` still ends up with only short summaries (≤120 chars, file
|
|
261
|
+
paths and extensions redacted); raw transcript content never lands in Coach state.
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## Tunable
|
|
266
|
+
|
|
267
|
+
For display (statusline variant, level-name theme, ELO range): use
|
|
268
|
+
`/config`. Settings persist to `~/.claude/coach/.user_config.json`.
|
|
269
|
+
Tip behavior + math are still constants at the top of two files:
|
|
270
|
+
|
|
271
|
+
- `~/.claude/hooks/coach-user-prompt.py` — `TIP_FIRE_PROBABILITY`, cooldowns, label rotation
|
|
272
|
+
- `~/.claude/coach/bin/merge.py` — confidence math, debounce, decay, graduation thresholds
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## Failsafe
|
|
277
|
+
|
|
278
|
+
Both hooks wrap `main()` in `try/except` and always `exit 0`. A coach bug cannot break a
|
|
279
|
+
Claude Code session.
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## Tests
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
cd ~/.claude/coach && python3 -m pytest tests/
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## Docs
|
|
292
|
+
|
|
293
|
+
- [`artifacts/architecture.md`](./artifacts/architecture.md) — full loop, components,
|
|
294
|
+
data model, scheduler internals, design rationale
|
|
295
|
+
- [`artifacts/infrastructure.md`](./artifacts/infrastructure.md) — install, runbook,
|
|
296
|
+
Linux cron, launchd, troubleshooting, config reference
|
|
297
|
+
- [`BACKLOG.md`](./BACKLOG.md) — open work
|
|
298
|
+
- [`CONTRIBUTING.md`](./CONTRIBUTING.md) — test-first workflow, code style, PR expectations
|
|
299
|
+
- [`CLAUDE.md`](./CLAUDE.md) — guidance for Claude Code sessions on this codebase
|
|
300
|
+
- [`AGENTS.md`](./AGENTS.md) — project structure + build commands
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## License
|
|
305
|
+
|
|
306
|
+
MIT — see [`LICENSE`](./LICENSE).
|
|
307
|
+
|
|
308
|
+
## Acknowledgments
|
|
309
|
+
|
|
310
|
+
The lobster mark in `artifacts/social-preview.png` is adapted from
|
|
311
|
+
[Twemoji](https://github.com/jdecked/twemoji) (codepoint U+1F99E), CC-BY 4.0.
|
package/coach/README.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Coach Claw — data directory
|
|
2
|
+
|
|
3
|
+
This directory is the live state of your coach: your tracked patterns,
|
|
4
|
+
lifetime XP, banked sessions, and one-line-per-run changelog. Everything
|
|
5
|
+
here is git-tracked (so profile mutations are rollback-able commits)
|
|
6
|
+
and stays local to your machine — Coach never independently uploads
|
|
7
|
+
`profile.yaml`, the changelog, the session ledger, or any redacted
|
|
8
|
+
example. (The weekly LLM path invokes `claude -p "/insights"` for the
|
|
9
|
+
side effect of refreshing local sidecars in `~/.claude/usage-data/`;
|
|
10
|
+
that goes through Claude Code, not Coach. See
|
|
11
|
+
`artifacts/infrastructure.md` § Security.)
|
|
12
|
+
|
|
13
|
+
## Files
|
|
14
|
+
|
|
15
|
+
| File | Purpose |
|
|
16
|
+
|---|---|
|
|
17
|
+
| `profile.yaml` | Active + probationary + candidate entries, graduated patterns, neutral archives, skill hints, split XP accounting (`session_banked_xp`, `milestone_xp`, `graduation_xp`, `manual_adjustments`). Source of truth. |
|
|
18
|
+
| `changelog.md` | One line per `/coach-insights` run — what got added, promoted, retired. |
|
|
19
|
+
| `banked_sessions.json` | Per-session XP ledger, keyed by session UUID. Populated by `bank.py` at SessionStart. |
|
|
20
|
+
| `log.ndjson` | Bounded redacted `tip_fired` / `tip_completed` events. No transcript text, tool commands, examples, or generated tip prose. |
|
|
21
|
+
| `.disabled` | Flag file — if present, both hooks exit silently. Removed by `/coach on`. |
|
|
22
|
+
| `.lock` | `flock` file used by `merge.py` + `bank.py` for profile writes. |
|
|
23
|
+
| `.pending_*` | Markers the hook consumes on next turn (graduation, streak tick, regression, level-up). |
|
|
24
|
+
| `.tip_state.json` | Scheduler state — last-fire timestamps, pending completions, global cooldown. |
|
|
25
|
+
| `.level_state.json` | High-water-mark level index; never moves downward (prevents false re-celebration). |
|
|
26
|
+
|
|
27
|
+
## Control
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
/coach on # remove .disabled
|
|
31
|
+
/coach off # write .disabled (hooks silent until re-enabled)
|
|
32
|
+
/coach status # level, XP breakdown, per-pattern streaks, last /coach-insights run
|
|
33
|
+
/coach uninstall # move this data dir to ~/.claude/coach.bak.<ts>/
|
|
34
|
+
COACH_DISABLE=1 claude # one-shot bypass without writing state
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Backup hygiene
|
|
38
|
+
|
|
39
|
+
Re-running `npx @rm0nroe/coach-claw@latest install` or `./install.sh` snapshots
|
|
40
|
+
the existing coach dir to
|
|
41
|
+
`~/.claude/coach.bak.<ts>/` and leaves byte-different `settings.json` /
|
|
42
|
+
`hooks/*.py` snapshots beside their live counterparts. Byte-identical
|
|
43
|
+
re-installs do not leave behind redundant `.bak.<ts>` siblings, and the
|
|
44
|
+
installer prunes by default — keeping the 3 most recent of each kind
|
|
45
|
+
(`coach.bak.*`, `settings.json.bak.*`, `hooks/<hook>.bak.*`) so backups
|
|
46
|
+
don't accumulate over months of upgrades.
|
|
47
|
+
|
|
48
|
+
To opt out (e.g. holding a specific `.bak` for forensic recovery):
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
./install.sh --no-prune-backups
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Manual equivalent of the prune for a one-shot cleanup outside the
|
|
55
|
+
installer:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
ls -dt ~/.claude/coach.bak.* | tail -n +4 | xargs rm -rf
|
|
59
|
+
ls -t ~/.claude/settings.json.bak.* | tail -n +4 | xargs rm -f
|
|
60
|
+
ls -t ~/.claude/hooks/*.bak.* | tail -n +4 | xargs rm -f
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Reinstall & Uninstall Safety
|
|
64
|
+
|
|
65
|
+
Re-running `npx @rm0nroe/coach-claw@latest install` or `./install.sh` from the
|
|
66
|
+
bundle preserves coach state, including XP, tracked patterns, the session
|
|
67
|
+
ledger, cooldowns, pending markers, and the disabled flag. `/coach uninstall`
|
|
68
|
+
is reversible: it renames this directory to
|
|
69
|
+
`~/.claude/coach.bak.<timestamp>/` instead of deleting it, then removes the
|
|
70
|
+
coach hook entries from `settings.json`.
|
|
71
|
+
|
|
72
|
+
For a clean setup test, uninstall, run `npx @rm0nroe/coach-claw@latest install --seed`
|
|
73
|
+
or `./install.sh --seed`, verify the new install, then copy the saved progress
|
|
74
|
+
files from the `coach.bak.<timestamp>/` directory back into
|
|
75
|
+
`~/.claude/coach/`. For an exact restore, also copy hidden runtime state files
|
|
76
|
+
if present: `.level_state.json`, `.tip_state.json`, `.last_session_start`, and
|
|
77
|
+
`log.ndjson`.
|
|
78
|
+
|
|
79
|
+
## Rollback
|
|
80
|
+
|
|
81
|
+
Every `/coach-insights` run is a commit in `~/.claude/coach/`:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
git -C ~/.claude/coach log --oneline | head
|
|
85
|
+
git -C ~/.claude/coach diff HEAD~1 -- profile.yaml # see what changed
|
|
86
|
+
git -C ~/.claude/coach checkout HEAD~1 -- profile.yaml # roll back one run
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Hand-edits are welcome — the merge logic preserves explicit fields. If
|
|
90
|
+
a tracked weakness is wrong, edit the nudge or delete the entry directly.
|
|
91
|
+
|
|
92
|
+
## Tests
|
|
93
|
+
|
|
94
|
+
The parent install also copied `tests/` here. After you have `pytest`
|
|
95
|
+
installed (`python3 -m pip install --user pytest`):
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
cd ~/.claude/coach && python3 -m pytest tests/
|
|
99
|
+
```
|