devcoach 0.3.9__tar.gz → 0.3.11__tar.gz
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.
- {devcoach-0.3.9 → devcoach-0.3.11}/.gitignore +2 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/CLAUDE.md +1 -1
- {devcoach-0.3.9 → devcoach-0.3.11}/PKG-INFO +21 -7
- {devcoach-0.3.9 → devcoach-0.3.11}/README.md +20 -6
- devcoach-0.3.11/docs/how-it-works.md +86 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/docs/index.md +17 -21
- {devcoach-0.3.9 → devcoach-0.3.11}/pyproject.toml +1 -1
- {devcoach-0.3.9 → devcoach-0.3.11}/sonar-project.properties +1 -1
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/SKILL.md +144 -48
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/cli/commands.py +5 -1
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/core/coach.py +5 -1
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/core/db.py +30 -62
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/core/models.py +11 -9
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/mcp/server.py +96 -27
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/web/app.py +7 -1
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/web/templates/settings.html +1 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/tests/conftest.py +5 -3
- {devcoach-0.3.9 → devcoach-0.3.11}/tests/test_cli_commands.py +26 -1
- {devcoach-0.3.9 → devcoach-0.3.11}/tests/test_db_extra.py +10 -9
- {devcoach-0.3.9 → devcoach-0.3.11}/tests/test_mcp_server.py +285 -3
- {devcoach-0.3.9 → devcoach-0.3.11}/tests/test_web_extra.py +14 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/uv.lock +4 -4
- devcoach-0.3.9/SKILL.md +0 -185
- devcoach-0.3.9/docs/how-it-works.md +0 -112
- {devcoach-0.3.9 → devcoach-0.3.11}/.github/dependabot.yml +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/.github/scripts/export_backup.py +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/.github/scripts/fixtures/devcoach-backup.zip +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/.github/scripts/take_screenshots.py +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/.github/workflows/ci.yml +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/.github/workflows/ruff-autofix.yml +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/.github/workflows/update-screenshots.yml +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/LICENSE +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/NOTICE +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/docs/PLAN.md +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/docs/cli.md +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/docs/configuration.md +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/docs/favicon.svg +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/docs/getting-started.md +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/docs/mcp-server.md +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/docs/screenshots/knowledge-map-dark.png +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/docs/screenshots/knowledge-map-light.png +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/docs/screenshots/lesson-ci-cd-pipeline-stages-dark.png +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/docs/screenshots/lesson-ci-cd-pipeline-stages-light.png +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/docs/screenshots/lesson-docker-layer-cache-dark.png +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/docs/screenshots/lesson-docker-layer-cache-light.png +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/docs/screenshots/lesson-git-interactive-rebase-dark.png +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/docs/screenshots/lesson-git-interactive-rebase-light.png +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/docs/screenshots/lesson-postgresql-explain-analyze-dark.png +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/docs/screenshots/lesson-postgresql-explain-analyze-light.png +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/docs/screenshots/lesson-redis-cache-stampede-dark.png +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/docs/screenshots/lesson-redis-cache-stampede-light.png +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/docs/screenshots/lessons-dark.png +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/docs/screenshots/lessons-light.png +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/docs/screenshots/settings-dark.png +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/docs/screenshots/settings-light.png +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/docs/web-ui.md +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/mkdocs.yml +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/__init__.py +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/cli/__init__.py +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/core/__init__.py +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/core/detect.py +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/core/git.py +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/core/prompts.py +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/mcp/__init__.py +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/web/__init__.py +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/web/static/favicon.svg +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/web/static/relative-time.js +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/web/static/style.css +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/web/static/vendor/alpinejs.min.js +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/web/static/vendor/flatpickr-dark.min.css +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/web/static/vendor/flatpickr.min.css +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/web/static/vendor/flatpickr.min.js +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/web/static/vendor/highlight.min.js +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/web/static/vendor/hljs-dark.min.css +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/web/static/vendor/hljs-light.min.css +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/web/static/vendor/htmx.min.js +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/web/static/vendor/icons/bitbucket.svg +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/web/static/vendor/icons/github.svg +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/web/static/vendor/icons/gitlab.svg +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/web/static/vendor/icons/vscode.svg +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/web/static/vendor/marked.min.js +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/web/static/vendor/tailwind.js +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/web/templates/base.html +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/web/templates/lesson_detail.html +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/web/templates/lessons.html +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/src/devcoach/web/templates/profile.html +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/tests/__init__.py +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/tests/test_cli.py +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/tests/test_coach.py +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/tests/test_detect.py +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/tests/test_git.py +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/tests/test_prompts.py +0 -0
- {devcoach-0.3.9 → devcoach-0.3.11}/tests/test_web.py +0 -0
|
@@ -182,7 +182,7 @@ The `log_lesson` tool accepts this schema:
|
|
|
182
182
|
{
|
|
183
183
|
"id": "uuid-or-random-string",
|
|
184
184
|
"timestamp": "2025-01-15T20:30:00Z",
|
|
185
|
-
"topic_id": "
|
|
185
|
+
"topic_id": "python",
|
|
186
186
|
"category": "python",
|
|
187
187
|
"title": "Generator expressions vs list comprehensions",
|
|
188
188
|
"level": "mid",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devcoach
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.11
|
|
4
4
|
Summary: A local MCP server that acts as a progressive technical coach for Claude Code and Claude Desktop
|
|
5
5
|
Project-URL: Homepage, https://github.com/UltimaPhoenix/dev-coach
|
|
6
6
|
Project-URL: Repository, https://github.com/UltimaPhoenix/dev-coach
|
|
@@ -245,12 +245,26 @@ Description-Content-Type: text/markdown
|
|
|
245
245
|
|
|
246
246
|
## How it works
|
|
247
247
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
248
|
+
```mermaid
|
|
249
|
+
flowchart TD
|
|
250
|
+
A([Task completed]) --> B[Check rate limit]
|
|
251
|
+
B -->|denied| Z([Silent])
|
|
252
|
+
B -->|allowed| D
|
|
253
|
+
|
|
254
|
+
subgraph loop["coaching loop"]
|
|
255
|
+
D[Select topic & depth]
|
|
256
|
+
E[Compose & deliver]
|
|
257
|
+
G[log_lesson]
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
D -->|nothing| Z
|
|
261
|
+
D -->|found| E
|
|
262
|
+
E --> G
|
|
263
|
+
G --> F([Done])
|
|
264
|
+
G -.->|prompts| U(["You: ✅ ❌ ⏭"])
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
→ [Full decision flow: session startup · lesson selection · depth calibration](https://ultimaphoenix.github.io/dev-coach/how-it-works/)
|
|
254
268
|
|
|
255
269
|
Everything runs **locally**. No data leaves your machine. One SQLite file at `~/.devcoach/coaching.db`.
|
|
256
270
|
|
|
@@ -14,12 +14,26 @@
|
|
|
14
14
|
|
|
15
15
|
## How it works
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
```mermaid
|
|
18
|
+
flowchart TD
|
|
19
|
+
A([Task completed]) --> B[Check rate limit]
|
|
20
|
+
B -->|denied| Z([Silent])
|
|
21
|
+
B -->|allowed| D
|
|
22
|
+
|
|
23
|
+
subgraph loop["coaching loop"]
|
|
24
|
+
D[Select topic & depth]
|
|
25
|
+
E[Compose & deliver]
|
|
26
|
+
G[log_lesson]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
D -->|nothing| Z
|
|
30
|
+
D -->|found| E
|
|
31
|
+
E --> G
|
|
32
|
+
G --> F([Done])
|
|
33
|
+
G -.->|prompts| U(["You: ✅ ❌ ⏭"])
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
→ [Full decision flow: session startup · lesson selection · depth calibration](https://ultimaphoenix.github.io/dev-coach/how-it-works/)
|
|
23
37
|
|
|
24
38
|
Everything runs **locally**. No data leaves your machine. One SQLite file at `~/.devcoach/coaching.db`.
|
|
25
39
|
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# How it works
|
|
2
|
+
|
|
3
|
+
devcoach is a silent technical coach that hooks into every Claude response.
|
|
4
|
+
The diagrams below show the three main flows: session startup, the coaching loop,
|
|
5
|
+
and how a lesson topic is selected.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Session startup
|
|
10
|
+
|
|
11
|
+
At the start of each Claude session devcoach checks whether the user is set up,
|
|
12
|
+
loads prior coaching context, and primes lesson selection before any task is done.
|
|
13
|
+
|
|
14
|
+
```mermaid
|
|
15
|
+
flowchart LR
|
|
16
|
+
A([Start]) --> B{First run?}
|
|
17
|
+
B -- yes --> C[Detect stack]
|
|
18
|
+
C --> D[Confirm topics\n& groups]
|
|
19
|
+
D --> E[Save profile]
|
|
20
|
+
B -- no --> F[Load profile\n& notebook]
|
|
21
|
+
E & F --> G([Ready])
|
|
22
|
+
|
|
23
|
+
subgraph onboarding["onboarding"]
|
|
24
|
+
C
|
|
25
|
+
D
|
|
26
|
+
E
|
|
27
|
+
end
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Coaching loop
|
|
33
|
+
|
|
34
|
+
After every technical task Claude evaluates whether to deliver a lesson.
|
|
35
|
+
The loop is silent when nothing is worth teaching or when the rate limit is reached.
|
|
36
|
+
|
|
37
|
+
```mermaid
|
|
38
|
+
flowchart TD
|
|
39
|
+
A([Task completed]) --> B[Check rate limit]
|
|
40
|
+
B -->|denied| Z([Silent])
|
|
41
|
+
B -->|allowed| D
|
|
42
|
+
|
|
43
|
+
subgraph loop["coaching loop"]
|
|
44
|
+
D[Select topic & depth]
|
|
45
|
+
E[Compose & deliver]
|
|
46
|
+
G[log_lesson]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
D -->|nothing| Z
|
|
50
|
+
D -->|found| E
|
|
51
|
+
E --> G
|
|
52
|
+
G --> F([Done])
|
|
53
|
+
G -.->|prompts| U(["You: ✅ ❌ ⏭"])
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Lesson selection
|
|
59
|
+
|
|
60
|
+
When a teachable concept is found, devcoach walks this priority list from top to bottom
|
|
61
|
+
and picks the first match. Depth is then calibrated to the per-topic confidence score.
|
|
62
|
+
|
|
63
|
+
| Priority | Trigger | Condition |
|
|
64
|
+
|:---:|---|---|
|
|
65
|
+
| ① | Notebook follow-up | The coaching notebook flagged an angle relevant to the current task |
|
|
66
|
+
| ② | Profile pitfall | A pitfall committed or avoided on a profile topic |
|
|
67
|
+
| ③ | Profile pattern | An interesting pattern on a profile topic worth formalising |
|
|
68
|
+
| ④ | Off-profile pitfall | A pitfall on a topic prominent in the task but absent from the profile |
|
|
69
|
+
| ⑤ | Knowledge gap | A profile topic with confidence < 5 |
|
|
70
|
+
| ⑥ | Deep-dive | A profile topic at confidence 4–6, not yet mastered |
|
|
71
|
+
|
|
72
|
+
First match wins. No match → silent.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Depth calibration
|
|
77
|
+
|
|
78
|
+
The lesson level is determined by the confidence score for the **specific topic being taught**,
|
|
79
|
+
adjusted by observations in the coaching notebook.
|
|
80
|
+
|
|
81
|
+
| Confidence | Level | Lesson angle |
|
|
82
|
+
|---|---|---|
|
|
83
|
+
| 0 – 3 | Junior | Introduce correct practice, explain from scratch, use analogies |
|
|
84
|
+
| 4 – 6 | Mid | Explain the why, mention trade-offs and alternatives |
|
|
85
|
+
| 7 – 9 | Senior | Edge cases, historical context, architectural implications |
|
|
86
|
+
| 10 | Cutting-edge | Latest developments — ignores level floor and taught-topics filter |
|
|
@@ -9,29 +9,25 @@ Everything runs **locally**. No data leaves your machine. One SQLite file at `~/
|
|
|
9
9
|
## How it works
|
|
10
10
|
|
|
11
11
|
```mermaid
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
User->>+Claude: ✅ know · ❌ don't know · ⏭ skip
|
|
29
|
-
Claude->>devcoach: submit_feedback → confidence ±1
|
|
30
|
-
Claude->>Claude: update coaching notebook if warranted
|
|
31
|
-
Claude-->>-User: acknowledged
|
|
12
|
+
flowchart TD
|
|
13
|
+
A([Task completed]) --> B[Check rate limit]
|
|
14
|
+
B -->|denied| Z([Silent])
|
|
15
|
+
B -->|allowed| D
|
|
16
|
+
|
|
17
|
+
subgraph loop["coaching loop"]
|
|
18
|
+
D[Select topic & depth]
|
|
19
|
+
E[Compose & deliver]
|
|
20
|
+
G[log_lesson]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
D -->|nothing| Z
|
|
24
|
+
D -->|found| E
|
|
25
|
+
E --> G
|
|
26
|
+
G --> F([Done])
|
|
27
|
+
G -.->|prompts| U(["You: ✅ ❌ ⏭"])
|
|
32
28
|
```
|
|
33
29
|
|
|
34
|
-
|
|
30
|
+
→ [Full decision flow: session startup · lesson selection · depth calibration](how-it-works.md)
|
|
35
31
|
|
|
36
32
|
---
|
|
37
33
|
|
|
@@ -9,7 +9,10 @@ description: >
|
|
|
9
9
|
lesson at the bottom of the response. DO NOT wait for the user to ask explicitly:
|
|
10
10
|
activate autonomously. Also use this skill when the user asks "what did I learn
|
|
11
11
|
today/this week", "show me my profile", "how good am I at X", "coaching log",
|
|
12
|
-
"devcoach"
|
|
12
|
+
"devcoach", "setup devcoach", "redo onboarding", "configure my profile",
|
|
13
|
+
"reset my topics", or any similar request to (re-)initialise the knowledge profile.
|
|
14
|
+
No session startup required: onboarding status is checked before every lesson
|
|
15
|
+
and is always accurate regardless of context compaction or plan mode.
|
|
13
16
|
---
|
|
14
17
|
|
|
15
18
|
# devcoach — Progressive Coaching
|
|
@@ -19,28 +22,44 @@ by teaching one thing at a time, at the right moment, based on what they actuall
|
|
|
19
22
|
|
|
20
23
|
---
|
|
21
24
|
|
|
22
|
-
##
|
|
25
|
+
## Onboarding flow
|
|
23
26
|
|
|
24
|
-
|
|
27
|
+
The onboarding flow runs inline, immediately before delivering a lesson, whenever
|
|
28
|
+
it is needed. There is no separate session startup phase — this makes the skill
|
|
29
|
+
robust to context compaction and plan-mode transitions.
|
|
25
30
|
|
|
26
|
-
|
|
31
|
+
Check `knowledge_ready` and `notebook_ready` from `devcoach://onboarding` independently
|
|
32
|
+
— each step can run alone:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
knowledge_ready = false → run Steps 1–3 (topic collection + complete_onboarding)
|
|
36
|
+
notebook_ready = false → run Step 4 (notebook initialisation)
|
|
37
|
+
both ready → proceed normally
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
This means a user who restores from backup has their knowledge automatically, so
|
|
41
|
+
only Step 4 runs. On-demand re-setup ("redo onboarding", "reset my topics") always
|
|
42
|
+
re-runs Steps 1–3 regardless of `knowledge_ready`.
|
|
27
43
|
|
|
28
44
|
### Step 1 — Offer to restore from backup
|
|
29
45
|
Ask once: *"Do you have an existing devcoach backup to restore? If yes, provide the
|
|
30
46
|
file path — otherwise I'll help you build your profile from scratch."*
|
|
31
47
|
|
|
32
|
-
If a path is provided: call `restore` (CLI) with the file.
|
|
33
|
-
|
|
34
|
-
|
|
48
|
+
If a path is provided: call `restore` (CLI) with the file. The restore process
|
|
49
|
+
brings back knowledge entries automatically — no further DB steps needed. Re-read
|
|
50
|
+
`devcoach://onboarding` after restore; if `knowledge_ready` is now true, skip to
|
|
51
|
+
Step 4. If `notebook_ready` is also true, proceed normally.
|
|
35
52
|
|
|
36
53
|
### Step 2 — Choose setup mode
|
|
37
54
|
Ask: *"Would you like me to detect your tech stack automatically from this project,
|
|
38
55
|
or set it up manually through a conversation?"*
|
|
39
56
|
|
|
40
57
|
**Automatic mode:**
|
|
41
|
-
- Read `
|
|
42
|
-
|
|
43
|
-
|
|
58
|
+
- Read `devcoach://onboarding` and present a merged topic list: `detected_stack`
|
|
59
|
+
(auto-detected from project files) enriched with relevant entries from
|
|
60
|
+
`default_topics` (the project's default knowledge map).
|
|
61
|
+
- Show each topic with its suggested confidence. Ask the user to confirm, adjust,
|
|
62
|
+
or remove each: *"Looks right? Or enter 1–10 to change it."*
|
|
44
63
|
- After the list, ask: *"Anything else I missed? List any tools, languages,
|
|
45
64
|
frameworks, or practices you work with regularly."* — add each with a confidence.
|
|
46
65
|
|
|
@@ -48,9 +67,9 @@ or set it up manually through a conversation?"*
|
|
|
48
67
|
- Have a free-form conversation: *"Tell me about the technologies you work with
|
|
49
68
|
day-to-day. For each one I'll ask how confident you are:
|
|
50
69
|
1–3 = still learning · 4–6 = comfortable · 7–9 = strong · 10 = expert."*
|
|
51
|
-
-
|
|
52
|
-
|
|
53
|
-
architecture patterns, etc. Keep probing until the user says they're done.
|
|
70
|
+
- Use `default_topics` as a domain checklist: probe areas the user hasn't mentioned
|
|
71
|
+
(languages, frameworks, databases, infrastructure, version control, CI/CD, testing,
|
|
72
|
+
architecture patterns, etc.). Keep probing until the user says they're done.
|
|
54
73
|
|
|
55
74
|
### Step 3 — Propose groups and save
|
|
56
75
|
Once the full topic list is agreed:
|
|
@@ -66,18 +85,44 @@ Once the full topic list is agreed:
|
|
|
66
85
|
"groups": { "Languages": ["lang_a"], "DevOps": ["tool_b"], "Version Control": ["practice_c"] }
|
|
67
86
|
}
|
|
68
87
|
```
|
|
69
|
-
- Confirm setup is complete and continue
|
|
88
|
+
- Confirm setup is complete and continue to Step 4.
|
|
70
89
|
|
|
71
90
|
**Rule:** Never ask about groups during topic collection. Propose them only in
|
|
72
91
|
Step 3 after all topics are known.
|
|
73
92
|
|
|
93
|
+
### Step 4 — Initialise the coaching notebook
|
|
94
|
+
|
|
95
|
+
Write `~/.devcoach/learning-state.md` with observations from this conversation.
|
|
96
|
+
If the file already exists (returning user or post-restore), integrate new
|
|
97
|
+
observations without overwriting prior entries.
|
|
98
|
+
|
|
99
|
+
```markdown
|
|
100
|
+
# devcoach — Coaching Notebook
|
|
101
|
+
_Last updated: [ISO timestamp]_
|
|
102
|
+
|
|
103
|
+
## Observations
|
|
104
|
+
[User background, confidence style, or gaps noted during onboarding.
|
|
105
|
+
Leave empty if nothing notable was observed.]
|
|
106
|
+
|
|
107
|
+
## Recurring patterns
|
|
108
|
+
[Leave empty — nothing observed yet.]
|
|
109
|
+
|
|
110
|
+
## Recommended focus
|
|
111
|
+
[Topics the user flagged as priorities or areas of uncertainty.]
|
|
112
|
+
|
|
113
|
+
## Open hypotheses
|
|
114
|
+
[Leave empty — nothing to track yet.]
|
|
115
|
+
```
|
|
116
|
+
|
|
74
117
|
---
|
|
75
118
|
|
|
76
119
|
## Session context
|
|
77
120
|
|
|
78
|
-
|
|
121
|
+
Before the first lesson in this context window, read `~/.devcoach/learning-state.md`
|
|
122
|
+
if it exists and has not already been loaded. Use its content for all subsequent
|
|
123
|
+
lessons in this window — do not re-read it on every lesson.
|
|
79
124
|
|
|
80
|
-
If it exists and is non-empty, load it as your coaching context
|
|
125
|
+
If it exists and is non-empty, load it as your coaching context:
|
|
81
126
|
- Resume patterns and hypotheses you noted in previous sessions
|
|
82
127
|
- Prioritise angles you flagged as still pending
|
|
83
128
|
- Avoid re-covering ground you noted as absorbed
|
|
@@ -93,6 +138,8 @@ Do not mention this file to the user. It is an internal coaching tool.
|
|
|
93
138
|
|
|
94
139
|
Always read these MCP resources before deciding to teach:
|
|
95
140
|
|
|
141
|
+
- `devcoach://onboarding` — check `knowledge_ready` and `notebook_ready`; if either
|
|
142
|
+
is false, run the onboarding flow (see above) before delivering the lesson
|
|
96
143
|
- `devcoach://rate-limit` — check `allowed`; if false, skip entirely
|
|
97
144
|
- `devcoach://taught-topics` — never repeat a topic already in this list
|
|
98
145
|
- `devcoach://profile` — use confidence scores to pick depth, and treat each topic
|
|
@@ -103,6 +150,10 @@ Always read these MCP resources before deciding to teach:
|
|
|
103
150
|
- **Open hypotheses** relevant to the current task → watch for confirming/refuting evidence
|
|
104
151
|
- **Recurring patterns** → use them to calibrate depth and angle, not just the confidence score
|
|
105
152
|
|
|
153
|
+
If `devcoach://profile` returns an **empty knowledge map**, do not deliver a lesson.
|
|
154
|
+
Run the onboarding flow first (Steps 1–3 of Session startup), then resume lesson
|
|
155
|
+
delivery once `complete_onboarding` has been called.
|
|
156
|
+
|
|
106
157
|
---
|
|
107
158
|
|
|
108
159
|
## Lesson levels
|
|
@@ -146,6 +197,14 @@ Evaluate whether to append a lesson **after every technical response** that invo
|
|
|
146
197
|
- DB queries, optimisations, migrations
|
|
147
198
|
- Security, performance, scalability
|
|
148
199
|
- CLI, scripting, automation
|
|
200
|
+
- Completing a git commit — the commit is a natural unit-of-work checkpoint;
|
|
201
|
+
treat it as a **high-priority** lesson trigger
|
|
202
|
+
|
|
203
|
+
**Commit checkpoint:** When a successful `git commit` is the trigger, the staged
|
|
204
|
+
diff and commit message visible in the preceding Bash output are the primary
|
|
205
|
+
teaching context — they capture exactly what was written and why. Use the changed
|
|
206
|
+
code (not the commit mechanics themselves) as the basis for lesson selection,
|
|
207
|
+
exactly as you would for any other code task.
|
|
149
208
|
|
|
150
209
|
**Do not activate** for: pure factual questions, web searches, translations, creative
|
|
151
210
|
writing, non-technical conversation.
|
|
@@ -288,7 +347,7 @@ Call `log_lesson` right after delivering the lesson, without waiting for feedbac
|
|
|
288
347
|
{
|
|
289
348
|
"id": "unique-slug-or-uuid",
|
|
290
349
|
"timestamp": "2026-04-27T14:30:00Z",
|
|
291
|
-
"topic_id": "
|
|
350
|
+
"topic_id": "topic",
|
|
292
351
|
"categories": ["the_topic_category", "architecture"],
|
|
293
352
|
"title": "Lesson title",
|
|
294
353
|
"level": "junior|mid|senior",
|
|
@@ -298,45 +357,44 @@ Call `log_lesson` right after delivering the lesson, without waiting for feedbac
|
|
|
298
357
|
}
|
|
299
358
|
```
|
|
300
359
|
|
|
360
|
+
**`topic_id` naming:** use the single most characterizing word for the domain
|
|
361
|
+
(e.g. `sqlite`, `python`, `docker`). For compound concepts with no single-word
|
|
362
|
+
equivalent, keep the essential part — `ci_cd_pipeline_design` → `ci_cd`. Never
|
|
363
|
+
more than 3 words.
|
|
364
|
+
|
|
301
365
|
Git metadata (`project`, `repository`, `branch`, `commit_hash`, `folder`,
|
|
302
366
|
`repository_platform`) is **auto-detected server-side**. Do not run git commands
|
|
303
367
|
manually. Omitting these fields is correct and will not reduce lesson quality.
|
|
304
368
|
|
|
305
369
|
`log_lesson` returns the saved `Lesson` object with all resolved fields.
|
|
306
370
|
|
|
307
|
-
### Step 1b —
|
|
371
|
+
### Step 1b — Feedback is collected by log_lesson
|
|
308
372
|
|
|
309
|
-
|
|
310
|
-
|
|
373
|
+
`log_lesson` asks "Did that land?" via an interactive MCP elicitation prompt.
|
|
374
|
+
The user selects know / don't know / skip directly in the client UI — no text
|
|
375
|
+
parsing required.
|
|
311
376
|
|
|
312
|
-
|
|
313
|
-
question : "Did that land?"
|
|
314
|
-
options : ["✅ know — got it", "❌ don't know — need to revisit", "⏭️ skip"]
|
|
315
|
-
```
|
|
377
|
+
Read the `feedback` field of the returned `Lesson` object:
|
|
316
378
|
|
|
317
|
-
|
|
318
|
-
|
|
379
|
+
- `"know"` or `"dont_know"` → feedback was given and confidence was already
|
|
380
|
+
adjusted server-side. Go to Step 3 (starring). **Do not call `submit_feedback`.**
|
|
381
|
+
- `null` / absent → elicitation was declined or not supported by this client.
|
|
382
|
+
Fall back: append the text prompt below, capture the reply in the next message
|
|
383
|
+
turn, then call `submit_feedback` manually (Step 2).
|
|
319
384
|
|
|
320
|
-
**
|
|
321
|
-
After the lesson body, end the response with this exact block — the interface will
|
|
322
|
-
render the options as clickable buttons:
|
|
385
|
+
**Fallback prompt (only when feedback is null):**
|
|
323
386
|
|
|
324
387
|
Did that land?
|
|
325
388
|
- ✅ know — got it
|
|
326
389
|
- ❌ don't know — need to revisit
|
|
327
390
|
- ⏭️ skip
|
|
328
391
|
|
|
329
|
-
Keep labels short (≤ 5 words). Do not wrap in a blockquote or code fence — plain
|
|
330
|
-
list format is what the client renders as buttons.
|
|
331
|
-
When the user clicks or types a reply that matches feedback (know / don't know / skip,
|
|
332
|
-
✅, ❌, 1 / 2 / 3), treat it as feedback before handling any new request in that message.
|
|
333
|
-
|
|
334
392
|
---
|
|
335
393
|
|
|
336
|
-
### Step 2 — Record feedback and conditionally adjust confidence
|
|
394
|
+
### Step 2 — Record feedback and conditionally adjust confidence (fallback only)
|
|
337
395
|
|
|
338
|
-
When feedback
|
|
339
|
-
`submit_feedback` according to this table:
|
|
396
|
+
When `log_lesson` returned `feedback: null` (elicitation declined or not supported),
|
|
397
|
+
collect feedback via the fallback prompt and call `submit_feedback` according to this table:
|
|
340
398
|
|
|
341
399
|
| User response | Condition | Action |
|
|
342
400
|
|---|---|---|
|
|
@@ -466,10 +524,46 @@ When the user asks about their learning journey, use the MCP tools and resources
|
|
|
466
524
|
|
|
467
525
|
## 7. Dynamic calibration
|
|
468
526
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
527
|
+
Triggered after every `log_lesson` where `total_lessons % 10 == 0`.
|
|
528
|
+
|
|
529
|
+
**Step 1 — Fetch the window**
|
|
530
|
+
|
|
531
|
+
Call `get_lessons()` (default `limit=10`, newest first) to get the last 10 lessons.
|
|
532
|
+
Read `devcoach://profile` for the current knowledge map.
|
|
533
|
+
|
|
534
|
+
**Step 2 — Per-topic signal analysis**
|
|
535
|
+
|
|
536
|
+
Group the 10 lessons by `topic_id`. For each topic that appeared:
|
|
537
|
+
|
|
538
|
+
| Signal | Condition | Action |
|
|
539
|
+
|---|---|---|
|
|
540
|
+
| Consistent mastery | All feedback `know`, no `dont_know` | `update_knowledge(topic, +1)` if confidence < 9 |
|
|
541
|
+
| Persistent gap | 2+ lessons on same topic, any `dont_know` | `update_knowledge(topic, -1)` if confidence > 1 |
|
|
542
|
+
| Recurring topic | 3+ lessons on same topic, mixed or no feedback | no confidence change — note in notebook |
|
|
543
|
+
| New topic | `topic_id` absent from `devcoach://profile` | `add_topic` — see Step 3 |
|
|
544
|
+
|
|
545
|
+
Apply at most **one** `update_knowledge` call per topic per calibration run.
|
|
546
|
+
Never call `update_knowledge` on a topic with confidence 10 (already mastered).
|
|
547
|
+
|
|
548
|
+
**Step 3 — New topic discovery**
|
|
549
|
+
|
|
550
|
+
For each lesson whose `topic_id` is not in `devcoach://profile`:
|
|
551
|
+
- 2+ lessons share this `topic_id` in the window → call `add_topic(topic_id, confidence=5)`;
|
|
552
|
+
assign it to the same group as the closest related existing topic, or `"Other"` if unclear.
|
|
553
|
+
- Only 1 lesson on this `topic_id` → note under **Open hypotheses** in the notebook; do not add yet.
|
|
554
|
+
|
|
555
|
+
**Step 4 — Update the coaching notebook**
|
|
556
|
+
|
|
557
|
+
Read `~/.devcoach/learning-state.md`. Merge findings into the relevant sections:
|
|
558
|
+
|
|
559
|
+
- **Recurring patterns** — append any `topic_id` that appeared 3+ times, with its count
|
|
560
|
+
and whether feedback was positive, negative, or absent.
|
|
561
|
+
- **Recommended focus** — replace or append topics that had 2+ `dont_know` in the window.
|
|
562
|
+
- **Open hypotheses** — add single-occurrence new topics not yet in the profile;
|
|
563
|
+
remove hypotheses confirmed (topic added) or disproved (not seen in 20+ subsequent lessons).
|
|
564
|
+
|
|
565
|
+
Always update `_Last updated` to the current ISO timestamp.
|
|
566
|
+
Never delete prior entries — integrate new observations alongside existing ones.
|
|
473
567
|
|
|
474
568
|
---
|
|
475
569
|
|
|
@@ -477,14 +571,16 @@ Every 10 lessons delivered, re-evaluate the profile:
|
|
|
477
571
|
|
|
478
572
|
- **Never break the flow** of the main response — the lesson is always at the bottom
|
|
479
573
|
- **Never mention** that you skipped a lesson due to rate limit
|
|
480
|
-
- **Always read
|
|
481
|
-
-
|
|
482
|
-
-
|
|
574
|
+
- **Always read before deciding to teach:** `devcoach://onboarding`,
|
|
575
|
+
`devcoach://rate-limit`, `devcoach://taught-topics`, `devcoach://profile`
|
|
576
|
+
- Onboarding is checked before every lesson — no separate session startup.
|
|
577
|
+
Works correctly after context compaction and after plan-mode transitions.
|
|
483
578
|
- The lesson should feel **natural and contextual**, not a mechanical add-on
|
|
484
579
|
- If there is nothing interesting to teach → stay silent. Better nothing than forced.
|
|
485
|
-
-
|
|
486
|
-
|
|
487
|
-
- Never call `update_knowledge` directly after `log_lesson` —
|
|
488
|
-
- `submit_feedback` handles the confidence delta; skip it entirely on no response
|
|
580
|
+
- Feedback is handled inside `log_lesson` via MCP elicitation — only call
|
|
581
|
+
`submit_feedback` manually if `log_lesson` returned `feedback: null`
|
|
582
|
+
- Never call `update_knowledge` directly after `log_lesson` — feedback handles the delta
|
|
489
583
|
- Propose starring when `don't know` on mid/senior, or when the topic recurs 2+ times
|
|
490
584
|
- Never star a lesson silently — always ask first
|
|
585
|
+
- After each `log_lesson`, check `total_lessons` from `devcoach://rate-limit`;
|
|
586
|
+
when `total_lessons % 10 == 0`, run the dynamic calibration from section 7
|
|
@@ -369,10 +369,11 @@ def cmd_backup(args: argparse.Namespace) -> None:
|
|
|
369
369
|
|
|
370
370
|
out_path = Path(args.output)
|
|
371
371
|
out_path.write_bytes(data)
|
|
372
|
+
notebook_note = " + notebook" if db.LEARNING_STATE_PATH.exists() else ""
|
|
372
373
|
console.print(
|
|
373
374
|
f"[green]Backup saved:[/green] {out_path} "
|
|
374
375
|
f"([cyan]{lessons_count}[/cyan] lessons, "
|
|
375
|
-
f"[cyan]{knowledge_count}[/cyan] topics)"
|
|
376
|
+
f"[cyan]{knowledge_count}[/cyan] topics{notebook_note})"
|
|
376
377
|
)
|
|
377
378
|
|
|
378
379
|
|
|
@@ -398,6 +399,8 @@ def cmd_restore(args: argparse.Namespace) -> None:
|
|
|
398
399
|
if result["invalid"]:
|
|
399
400
|
parts.append(f"[red]{result['invalid']}[/red] rejected (invalid)")
|
|
400
401
|
console.print(f"[green]✓[/green] Lessons: {', '.join(parts)}")
|
|
402
|
+
if result["learning_state"]:
|
|
403
|
+
console.print("[green]✓[/green] Notebook restored")
|
|
401
404
|
|
|
402
405
|
|
|
403
406
|
def _claude_desktop_config() -> Path:
|
|
@@ -543,6 +546,7 @@ def cmd_setup(_args: argparse.Namespace) -> None:
|
|
|
543
546
|
db.set_setting(conn, "onboarding_completed", "1")
|
|
544
547
|
console.print(
|
|
545
548
|
f"[green]✓[/green] Restored: {result['topics']} topics, {result['lessons']} lessons"
|
|
549
|
+
+ (", notebook" if result["learning_state"] else "")
|
|
546
550
|
)
|
|
547
551
|
console.print("[green]Setup complete![/green]")
|
|
548
552
|
return
|
|
@@ -50,10 +50,14 @@ def check_rate_limit(conn: sqlite3.Connection) -> RateLimitResult:
|
|
|
50
50
|
remaining = settings.min_gap_minutes - elapsed_minutes
|
|
51
51
|
gap_h, gap_m = divmod(settings.min_gap_minutes, 60)
|
|
52
52
|
rem_h, rem_m = divmod(int(remaining), 60)
|
|
53
|
+
if elapsed_minutes < 0:
|
|
54
|
+
ago_text = f"in {-elapsed_minutes:.0f}m (future timestamp)"
|
|
55
|
+
else:
|
|
56
|
+
ago_text = f"{elapsed_minutes:.0f}m ago"
|
|
53
57
|
return RateLimitResult(
|
|
54
58
|
allowed=False,
|
|
55
59
|
reason=(
|
|
56
|
-
f"Too soon: last lesson {
|
|
60
|
+
f"Too soon: last lesson {ago_text}, "
|
|
57
61
|
f"minimum interval is {gap_h}h {gap_m}m "
|
|
58
62
|
f"({rem_h}h {rem_m}m remaining)"
|
|
59
63
|
),
|