@swifty.js/swifty 0.0.1-canary

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.
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __swiftyCreateRequire } from "node:module";
3
+ const require = __swiftyCreateRequire(import.meta.url);
4
+ import{g as w}from"./chunk-H7VXSMJR.js";import{$ as K,L as x,N as P,O,P as v,Q as f,R as S,X as j,Y as I,Z as U,_ as $,aa as g,ba as W,da as B,e as L,ea as M,p as N}from"./chunk-XWWKIJ5J.js";import"./chunk-NCPOPA4A.js";import"./chunk-X3UA5OZL.js";var d=L({module:"llm"});var F=3e3,G=x.object({max_input_tokens:x.preprocess(n=>{if(n==null||n===""||n===!1)return g;let t=Number(n);return Number.isFinite(t)&&t>0?t:g},x.number().positive())});async function et(n){if(n.protocol!=="anthropic")return 0;let t=M(n),o=`${n.base_url.replace(/\/+$/,"")}/v1/models/${encodeURIComponent(n.model)}`,r=new AbortController,i=setTimeout(()=>{r.abort()},F);try{let l=await fetch(o,{method:"GET",headers:{"anthropic-version":"2023-06-01",...t?{"x-api-key":t}:{}},signal:r.signal});if(!l.ok)return g;let y=await l.json(),{success:h,data:k}=await N(G,y);return h?k.max_input_tokens:g}catch(l){return d.error({err:l},"llm operation failed"),g}finally{clearTimeout(i)}}function H(){return!0}function Y(n){let t=[];for(let e of n)if(e.role==="assistant"){let o=[];if(e.thinkingBlocks)for(let r of e.thinkingBlocks)o.push({type:"thinking",thinking:r.thinking,signature:r.signature});if(e.content&&o.push({type:"text",text:e.content}),e.toolUses)for(let r of e.toolUses)o.push({type:"tool_use",id:r.toolUseId,name:r.toolName,input:r.arguments});o.length===0&&o.push({type:"text",text:""}),t.push({role:"assistant",content:o})}else if(e.toolResults&&e.toolResults.length>0){let o=[];for(let r of e.toolResults)o.push({type:"tool_result",tool_use_id:r.toolUseId,is_error:r.isError,content:r.content});t.push({role:"user",content:o})}else{if(t.length===0){t.push({role:"user",content:[{type:"text",text:e.content}]});continue}let o=!1,r=t[t.length-1],i=r.content;r.role==="user"&&(typeof i=="string"||Array.isArray(i)&&i.length>0&&i[0].type==="text")&&(o=!0),o?(typeof i=="string"&&(i=r.content=i.trim().length>0?[{type:"text",text:i}]:[]),i.push({type:"text",text:e.content})):t.push({role:"user",content:[{type:"text",text:e.content}]})}return t}var D=class{client;model;thinking;systemPrompt;maxOutputTokens;contextWindow;constructor(t,e){let o=M(t);if(!o)throw new I("Anthropic API key not found, set ANTHROPIC_API_KEY in .swifty/config.y(a)ml, or via ANTHROPIC_API_KEY env variable.");this.client=new w({apiKey:o,baseURL:t.base_url}),this.model=t.model,this.thinking=t.thinking??!0,this.systemPrompt=e,this.maxOutputTokens=B(t),this.contextWindow=W(t)}setMaxOutputTokens(t){this.maxOutputTokens=t}async*stream(t,e,o){let r=Y(t.getMessages()),i=e.map(c=>{let p=c.input_schema;return{name:c.name,description:c.description,input_schema:{type:"object",properties:p.properties,required:p.required??[]}}});i.length>0&&(i[i.length-1].cache_control={type:"ephemeral"}),q(r);let l={model:this.model,max_tokens:this.maxOutputTokens,stream:!0,system:[{type:"text",text:this.systemPrompt,cache_control:{type:"ephemeral"}}],messages:r,...i.length>0?{tools:i}:{}};this.thinking?H()&&(l.thinking={type:"enabled",budget_tokens:this.maxOutputTokens-1}):l.thinking={type:"enabled",budget_tokens:this.maxOutputTokens-1};let y=0,h=0,k=0,R=0,C="end_turn",b="",T="",A=!1,E=0;try{let c=this.client.messages.stream(l,{...o?{signal:o}:{}}),p="",_="",u="";for await(let a of c)switch(a.type){case"content_block_start":{let s=a.content_block;s.type==="thinking"?(A=!0,b="",T=""):s.type==="tool_use"&&(_=s.id,p=s.name,u="",yield{type:"tool_call_start",toolName:p,toolId:_});break}case"content_block_delta":{let s=a.delta;s.type==="thinking_delta"?(b+=s.thinking,yield{type:"thinking_delta",text:s.thinking}):s.type==="signature_delta"?(d.debug({signature:s.signature},"thinking signature received"),T=s.signature):s.type==="text_delta"?yield{type:"text_delta",text:s.text}:s.type==="input_json_delta"&&(u+=s.partial_json,yield{type:"tool_call_delta",text:s.partial_json});break}case"content_block_stop":{if(A&&(yield{type:"thinking_complete",thinking:b,signature:T},A=!1),p){let s={};if(u)try{let m=JSON.parse(u);s=O(m)?v(m):{[P]:u}}catch(m){d.error({err:m},"llm operation failed"),s={[P]:u}}yield{type:"tool_call_complete",toolId:_,toolName:p,arguments:s},p="",_="",u=""}break}case"message_delta":{a.delta.stop_reason&&(C=a.delta.stop_reason),a.usage.output_tokens&&(h=a.usage.output_tokens);break}case"message_start":{E=performance.now(),y=a.message.usage.input_tokens,h=a.message.usage.output_tokens,k=a.message.usage.cache_read_input_tokens??0,R=a.message.usage.cache_creation_input_tokens??0;break}case"message_stop":{let m=performance.now()-E;d.debug({elapsedMs:m},"message stream complete");break}}yield{type:"stream_end",stopReason:C,usage:{inputTokens:y,outputTokens:h,cacheReadInputTokens:k,cacheCreationInputTokens:R}}}catch(c){throw d.error({err:c},"llm operation failed"),J(c)}}};function q(n){for(let t=n.length-1;t>=0;t--){if(n[t].role!=="user")continue;let e=n[t].content;if(typeof e=="string"&&e.length===0||Array.isArray(e)&&e.length===0)return;typeof e=="string"&&(e=n[t].content=[{type:"text",text:e}]);let o=e[e.length-1];Reflect.set(o,"cache_control",{type:"ephemeral"})}}function J(n){if(n instanceof w.APIError){if(n.status===413||/prompts?\s+too\s+long/i.test(n.message))return new K(`Prompt too long: ${n.message}`);if(n.status===401)return new I(`Invalid API key: ${n.message}`);if(n.status===429){let t=v(n.headers)["retry-after"],e="Rate Limited";if(t){let o=Number.parseInt(f(t));Number.isNaN(o)&&(e+=", please wait."),e+=`, retry after ${f(o)}s.`}else e+=", please wait.";return new U(e,t?f(t):void 0)}return new j(`Anthropic API error (${f(n.status)}): ${n.message}`)}return new $(`Network error: ${S(n)}`)}export{D as AnthropicClient,Y as buildAnthropicMessages,et as fetchModelContextWindow};
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: commit
3
+ description: Analyze git diff and produce a conventional commit
4
+ mode: inline
5
+ allowed_tools:
6
+ - Bash
7
+ - ReadFile
8
+ - Grep
9
+ ---
10
+
11
+ # Task
12
+
13
+ You are creating a git commit for the user.
14
+
15
+ ## Steps
16
+
17
+ 1. Run `git status` to see what has changed.
18
+ 2. Run `git diff` and `git diff --staged` to inspect the actual changes. Read both staged and unstaged.
19
+ 3. Decide the commit type from the diff content:
20
+ - `feat`: new user-facing capability
21
+ - `fix`: bug fix
22
+ - `docs`: documentation only
23
+ - `refactor`: code restructuring without behavior change
24
+ - `test`: tests only
25
+ - `chore`: build / tooling / non-source changes
26
+ 4. Compose a message in conventional-commit format: `type(scope): description`.
27
+ - Description in English, no trailing period, ≤ 72 chars.
28
+ - Scope optional; use the package or module touched (e.g. `feat(skills): ...`).
29
+ 5. Stage files one by one with `git add <path>` — never `git add -A` or `git add .`.
30
+ - Skip `.env`, credentials, secrets, large binaries, build artifacts.
31
+ - If more than 10 files changed, ask the user whether to split into multiple commits before staging.
32
+ 6. Create the commit with `git commit -m "<message>"`.
33
+ 7. Report the commit hash and the message.
34
+
35
+ ## Notes
36
+
37
+ - If the user provided extra context in `$ARGUMENTS`, fold it into the message body (after the title line, blank line, then prose).
38
+ - Do not push.
39
+ - If the working tree is clean, report that and stop.
40
+
41
+ $ARGUMENTS
@@ -0,0 +1,105 @@
1
+ ---
2
+ name: fullstack-interview
3
+ description: Run a focused fullstack interview (TS+React frontend, Go backend) based on the candidate's real repository docs
4
+ mode: inline
5
+ allowed_tools:
6
+ - Bash
7
+ - Glob
8
+ - ReadFile
9
+ - Grep
10
+ ---
11
+
12
+ # Task
13
+
14
+ You are conducting a fullstack engineering interview. The candidate's stack is TypeScript + React on the frontend and Golang on the backend. Instead of a resume, you will clone the candidate's repository, read its docs, and ask questions grounded in the actual project.
15
+
16
+ Run in four rounds, one at a time, waiting for the candidate's answer before moving on.
17
+
18
+ ## Setup — clone and read the candidate's repo
19
+
20
+ 1. Create a temp directory and clone the repo:
21
+
22
+ ```bash
23
+ tmp=$(mktemp -d)
24
+ git clone https://github.com/hangtiancheng/h.git "$tmp/h"
25
+ ```
26
+
27
+ 2. Use Glob to understand the docs directory structure:
28
+
29
+ ```
30
+ Glob: **/*
31
+ Path: $tmp/h/docs
32
+ ```
33
+
34
+ 3. Move the docs directory out of the repo into a clean location so it's easy to reference:
35
+
36
+ ```bash
37
+ mv "$tmp/h/docs" "$tmp/docs"
38
+ ```
39
+
40
+ 4. Use ReadFile to read every document under `$tmp/docs/`. Use Grep if you need to search across docs for specific keywords (e.g., "architecture", "API", "component", "handler").
41
+
42
+ 5. Build a mental model of the project from the docs:
43
+ - What is this project? What problem does it solve?
44
+ - Frontend: What React patterns / TS types / state management are mentioned?
45
+ - Backend: What Go packages / patterns / concurrency model are mentioned?
46
+ - How do the frontend and backend communicate?
47
+
48
+ Use this understanding to tailor every question — never ask about something the docs don't cover.
49
+
50
+ ## Round 1 — frontend fundamentals (3 questions)
51
+
52
+ Pick 3 concepts from the candidate's frontend stack as described in the docs (TypeScript, React, state management, etc.). For each:
53
+
54
+ - One concept question grounded in the project's actual code (e.g., "I see you use `useCallback` in the component at `src/foo.tsx` — when would you NOT use it?")
55
+ - Probe one follow-up if the answer is shallow
56
+
57
+ ## Round 2 — backend fundamentals (3 questions)
58
+
59
+ Pick 3 concepts from the candidate's Go/backend stack as described in the docs. For each:
60
+
61
+ - One concept question grounded in the project's actual code (e.g., "I see you use a worker pool in `internal/pool.go` — why channels instead of a mutex+slice?")
62
+ - Probe one follow-up if the answer is shallow
63
+
64
+ ## Round 3 — project deep-dive (1 topic)
65
+
66
+ Pick the most interesting architectural decision visible in the docs:
67
+
68
+ - Ask the candidate to walk through the fullstack architecture: React frontend ↔ API layer ↔ Go backend ↔ data store
69
+ - Drill into one specific decision on each side:
70
+ - Frontend: component composition, state management choice, rendering strategy (SSR/CSR/streaming)
71
+ - Backend: API style (REST/gRPC/GraphQL), concurrency model, error handling, data layer
72
+ - Find the part where the candidate had to compromise — pressure-test that trade-off
73
+
74
+ ## Round 4 — system design (1 prompt)
75
+
76
+ Pick a design prompt sized to their YoE, scoped to extending the project they already have:
77
+
78
+ - 1-3 YoE: Add a real-time feature (e.g., live updates, collaborative editing) to the existing fullstack app
79
+ - 3-7 YoE: Scale an existing component (e.g., add a notification system, file upload pipeline) using the project's current architecture
80
+ - 7+ YoE: Redesign a subsystem for multi-tenant / high-scale (e.g., split the monolith into Go microservices + React SPA)
81
+
82
+ Give them 10 minutes of "interview thinking time" via the prompt; they describe the fullstack architecture out loud. Push back on missing concerns:
83
+
84
+ - Frontend: bundle size, re-render performance, accessibility, state synchronization
85
+ - Backend: latency, failure mode, concurrency, graceful degradation
86
+ - Integration: API contract design, error propagation, type safety across the boundary
87
+
88
+ ## Output
89
+
90
+ After all four rounds, produce a short report:
91
+
92
+ - Frontend strengths (2-3 bullets)
93
+ - Backend strengths (2-3 bullets)
94
+ - Gaps (2-4 bullets)
95
+ - Hire signal: strong / lean-hire / lean-no-hire / no-hire — with one-line rationale
96
+
97
+ ## Notes
98
+
99
+ - Do not give answers away during the interview.
100
+ - One question per turn. Wait for response.
101
+ - If the candidate goes off-script ("can we skip this?"), pick a different angle in the same round, don't abandon the round.
102
+ - If the candidate is stronger on one side (frontend or backend), spend more time on the weaker side to calibrate accurately.
103
+ - Clean up the temp directory when the interview is over: `rm -rf "$tmp"`.
104
+
105
+ $ARGUMENTS
@@ -0,0 +1,399 @@
1
+ ---
2
+ name: teach-me
3
+ description: "Personalized 1-on-1 AI tutor. Diagnoses level, builds learning path, teaches via guided questions, tracks misconceptions. Use when user wants to learn/study/understand a topic, says 'teach me', 'help me understand', or invokes /teach-me."
4
+ mode: inline
5
+ allowed_tools:
6
+ - AskUserQuestion
7
+ - ReadFile
8
+ - WriteFile
9
+ - Glob
10
+ ---
11
+
12
+ # Teach Me
13
+
14
+ Personalized mastery tutor. Diagnose, question, advance on understanding.
15
+
16
+ ## Usage
17
+
18
+ ```bash
19
+ /teach-me JavaScript event loop
20
+ /teach-me TypeScript --level beginner
21
+ /teach-me React hooks --resume
22
+ ```
23
+
24
+ ## Arguments
25
+
26
+ | Argument | Description |
27
+ | ----------------- | ---------------------------------------------------------------------------- |
28
+ | `<topic>` | Subject to learn (required, or prompted) |
29
+ | `--level <level>` | Starting level: beginner, intermediate, advanced (default: diagnose) |
30
+ | `--resume` | Resume previous session from `.swifty/skills/teach-me/records/{topic-slug}/` |
31
+
32
+ ## Core Rules
33
+
34
+ 1. **Minimize lecturing, but don't be dogmatic.** Prefer questions that lead to discovery. For complete beginners with zero context, a brief 1-2 sentence framing is acceptable before asking.
35
+ 2. **Diagnose first.** Always probe current understanding before teaching.
36
+ 3. **Mastery gate.** Advance to next concept only when the learner can explain it clearly and apply it.
37
+ 4. **1-2 questions per round.** No more.
38
+ 5. **Patience + rigor.** Encouraging tone, but never hand-wave past gaps.
39
+ 6. **Language follows user.** Match the user's language. Technical terms can stay in English.
40
+ 7. **Always use AskUserQuestion.** Every question to the learner MUST use AskUserQuestion with predefined options. Never ask open-ended plain-text questions — users need options to anchor their thinking. Even conceptual/deep questions should offer 3-4 options plus let the user pick "Other" for free-form input. Options serve as scaffolding, not just convenience.
41
+
42
+ ## Output Directory
43
+
44
+ All teach-me data is stored under `.swifty/skills/teach-me/records/`:
45
+
46
+ ```
47
+ .swifty/skills/teach-me/records/
48
+ ├── learner-profile.md # Cross-topic notes (created on first session)
49
+ └── {topic-slug}/
50
+ ├── session.md # Learning state: concepts, status, notes
51
+ └── {topic-slug}-notes.md # Learner-facing summary notes (generated at session end)
52
+ ```
53
+
54
+ **Slug**: Topic in kebab-case, 2-5 words. Example: "Python decorators" → `python-decorators`
55
+
56
+ ## Workflow
57
+
58
+ ```
59
+ Input → [Load Profile] → [Diagnose] → [Build Concept List] → [Tutor Loop] → [Session End]
60
+ ```
61
+
62
+ ### Step 0: Parse Input
63
+
64
+ 1. Extract topic. If none, use AskUserQuestion to ask what they want to learn (provide common categories as options).
65
+ 2. Detect language from user input.
66
+ 3. Load learner profile if `.swifty/skills/teach-me/records/learner-profile.md` exists.
67
+ 4. Check for existing session:
68
+ - If `--resume`: read `session.md`, restore state, continue.
69
+ - If exists without `--resume`: use AskUserQuestion to ask whether to resume or start fresh.
70
+ 5. Create output directory: `.swifty/skills/teach-me/records/{topic-slug}/`
71
+
72
+ ### Step 1: Diagnose Level
73
+
74
+ Ask 2-3 questions to calibrate understanding, all via AskUserQuestion with predefined options.
75
+
76
+ If learner profile exists, use it to skip known strengths and probe known weak areas.
77
+
78
+ If `--level` provided, use as hint but still ask 1-2 probing questions.
79
+
80
+ **Example for "Python decorators"**:
81
+
82
+ Round 1 (AskUserQuestion):
83
+
84
+ ```
85
+ header: "Level check"
86
+ question: "Which of these Python concepts are you comfortable with?"
87
+ multiSelect: true
88
+ options:
89
+ - label: "Functions as values"
90
+ - label: "Closures"
91
+ - label: "The @ syntax"
92
+ - label: "Writing custom decorators"
93
+ ```
94
+
95
+ Round 2 (AskUserQuestion — conceptual question with options as scaffolding):
96
+
97
+ ```
98
+ header: "Understanding"
99
+ question: "When Python sees @my_decorator above a function, what do you think happens?"
100
+ multiSelect: false
101
+ options:
102
+ - label: "It replaces the function with a new one"
103
+ description: "The decorator wraps or replaces the original function"
104
+ - label: "It's just syntax sugar for calling the decorator"
105
+ description: "@decorator is equivalent to func = decorator(func)"
106
+ - label: "It modifies the function in-place"
107
+ description: "The original function object is changed directly"
108
+ - label: "I'm not sure"
109
+ description: "No worries, we'll figure it out together"
110
+ ```
111
+
112
+ ### Step 2: Build Concept List
113
+
114
+ Decompose topic into 5-15 atomic concepts, ordered by dependency. Save to `session.md`:
115
+
116
+ ```markdown
117
+ # Session: {topic}
118
+
119
+ - Level: {diagnosed}
120
+ - Started: {timestamp}
121
+
122
+ ## Concepts
123
+
124
+ 1. ✓ Functions as first-class objects (mastered)
125
+ 2. ○ Higher-order functions (in progress)
126
+ 3. ⬜ Closures
127
+ 4. ⬜ Decorator basics
128
+ ...
129
+
130
+ ## Misconceptions
131
+
132
+ - [concept]: "{what learner said}" → likely root cause: {analysis}
133
+
134
+ ## Log
135
+
136
+ - [timestamp] Diagnosed: intermediate
137
+ - [timestamp] Concept 1: pre-existing knowledge, skipped
138
+ - [timestamp] Concept 2: started
139
+ ```
140
+
141
+ Use simple status: ✓ mastered | ○ in progress | ⬜ not started | ✗ needs review
142
+
143
+ Present the concept list to the learner as a brief text outline so they see the path ahead.
144
+
145
+ ### Step 3: Tutor Loop
146
+
147
+ For each concept:
148
+
149
+ #### 3a. Introduce (Brief)
150
+
151
+ Set context with 1-2 sentences max, then ask an opening question via AskUserQuestion. Options serve as thinking scaffolds:
152
+
153
+ Example for "closures":
154
+
155
+ ```
156
+ header: "Closures"
157
+ question: "A closure is a function that remembers variables from where it was created. Why might that be useful?"
158
+ multiSelect: false
159
+ options:
160
+ - label: "To create private state"
161
+ description: "Keep variables hidden from outside code"
162
+ - label: "To pass data between functions"
163
+ description: "Share information without global variables"
164
+ - label: "To cache expensive computations"
165
+ description: "Remember results for reuse"
166
+ - label: "I'm not sure yet"
167
+ description: "We'll explore this together"
168
+ ```
169
+
170
+ #### 3b. Question Cycle
171
+
172
+ ALL questions use AskUserQuestion. Design options that probe understanding — include a mix of correct, partially correct, and common-wrong-answer distractors. The user can always use "Other" for free-form input when they have a specific idea.
173
+
174
+ **Option design tips**:
175
+
176
+ - Include 1-2 correct answers (split nuance into separate options)
177
+ - Include 1 distractor based on a common misconception
178
+ - Include "I'm not sure" or "Let me think about it" as a safe option
179
+ - Use descriptions to add hints or context to each option
180
+
181
+ **Interleaving** (every 3-4 questions): Mix a previously mastered concept into the current question's options naturally. Don't announce it as review.
182
+
183
+ Example (learning closures, already mastered higher-order functions):
184
+
185
+ ```
186
+ header: "Prediction"
187
+ question: "Here's a function that takes a callback and returns a new function. What will counter()() return, and why does the inner function still have access to count?"
188
+ multiSelect: false
189
+ options:
190
+ - label: "0, because count starts at 0"
191
+ description: "The inner function reads the initial value"
192
+ - label: "1, because count was incremented before returning"
193
+ description: "Closure captures the live variable, not a copy"
194
+ - label: "Error, because count is out of scope"
195
+ description: "The outer function already returned, so count is gone"
196
+ - label: "Undefined behavior"
197
+ description: "Depends on how the function was defined"
198
+ ```
199
+
200
+ #### 3c. Respond to Answers
201
+
202
+ | Answer Quality | Response |
203
+ | --------------------------- | ------------------------------------------------------------------------------------------- |
204
+ | Correct + good explanation | Brief acknowledgment, harder follow-up via AskUserQuestion |
205
+ | Correct but shallow | "Good. Can you explain _why_?" — as AskUserQuestion with why-options |
206
+ | Partially correct | "On the right track with [part]." — follow up with a more targeted AskUserQuestion |
207
+ | Incorrect | "Interesting. Let's step back." — simpler AskUserQuestion to re-anchor |
208
+ | "I don't know" / "Not sure" | "That's fine." — give a concrete example, then ask via AskUserQuestion with simpler options |
209
+
210
+ **Hint escalation**: rephrase → simpler question → concrete example → point to principle → walk through minimal example together.
211
+
212
+ #### 3d. Misconception Tracking
213
+
214
+ On incorrect or partially correct answers, diagnose the underlying wrong mental model:
215
+
216
+ 1. Present a counter-example via AskUserQuestion — ask the learner to predict what happens, where the wrong mental model leads to a clearly wrong answer:
217
+
218
+ ```
219
+ header: "Check this"
220
+ question: "Given [counter-example], what do you think the output will be?"
221
+ multiSelect: false
222
+ options:
223
+ - label: "[wrong prediction from their mental model]"
224
+ description: "Based on what we discussed earlier"
225
+ - label: "[correct prediction]"
226
+ description: "A different perspective"
227
+ - label: "[another wrong prediction]"
228
+ description: "Yet another possibility"
229
+ - label: "I need to think more"
230
+ description: "Take your time"
231
+ ```
232
+
233
+ 2. Record in session.md under `## Misconceptions`
234
+ 3. When the learner sees the contradiction (their model predicts the wrong thing), guide them to articulate why.
235
+ 4. A misconception is resolved when the learner articulates why their old thinking was wrong AND handles a new scenario correctly.
236
+
237
+ Never say "that's a misconception." Let them discover it.
238
+
239
+ #### 3e. Mastery Check
240
+
241
+ After 3-5 question rounds, assess qualitatively. The learner demonstrates mastery when they can:
242
+
243
+ - Explain the concept in their own words
244
+ - Apply it to a new scenario
245
+ - Distinguish it from similar concepts
246
+ - Find errors in incorrect usage
247
+
248
+ If not ready: identify the specific gap and cycle back with targeted questions.
249
+
250
+ #### 3f. Practice Phase
251
+
252
+ Before marking mastered, give a small hands-on task via AskUserQuestion. Present the task as a code/output prediction or scenario choice:
253
+
254
+ - **Programming**: Show a small code snippet and ask what it outputs or which fix is correct:
255
+
256
+ ```
257
+ header: "Practice"
258
+ question: "Here's a buggy decorator. What's wrong with it?"
259
+ multiSelect: false
260
+ options:
261
+ - label: "Missing return wrapper"
262
+ description: "The decorator doesn't return the inner function"
263
+ - label: "Wrong function signature"
264
+ description: "The wrapper doesn't accept *args, **kwargs"
265
+ - label: "Missing @functools.wraps"
266
+ description: "Metadata from the original function is lost"
267
+ - label: "I'd like to try writing one from scratch"
268
+ description: "Use 'Other' to write your own code"
269
+ ```
270
+
271
+ - **Non-programming**: Ask to identify which scenario best applies the concept:
272
+
273
+ ```
274
+ header: "Apply it"
275
+ question: "Which real-world scenario best demonstrates [concept]?"
276
+ multiSelect: false
277
+ options:
278
+ - label: "[scenario A]"
279
+ - label: "[scenario B]"
280
+ - label: "[scenario C]"
281
+ - label: "I have my own example"
282
+ description: "Use 'Other' to share your own"
283
+ ```
284
+
285
+ Keep it 2-5 minutes. Pass = mastered. Fail = diagnose gap, cycle back.
286
+
287
+ #### 3g. Sync Progress (Every Round)
288
+
289
+ Update `session.md` after each round:
290
+
291
+ - Change concept status if applicable
292
+ - Add new misconceptions or resolve existing ones
293
+ - Append to log
294
+
295
+ ### Step 4: Session End
296
+
297
+ When all concepts mastered or user ends session:
298
+
299
+ 1. Update `session.md` with final state.
300
+ 2. **Generate learner-facing notes** — write `{topic-slug}-notes.md` in the topic directory. This is a standalone reference document the learner can review later. See "Notes Generation" below for format.
301
+ 3. Update `.swifty/skills/teach-me/records/learner-profile.md` (keep under 30 lines):
302
+
303
+ ```markdown
304
+ # Learner Profile
305
+
306
+ Updated: {timestamp}
307
+
308
+ ## Style
309
+
310
+ - Learns best with: {concrete examples / abstract principles / visual ...}
311
+ - Pace: {fast / moderate / needs-time}
312
+
313
+ ## Patterns
314
+
315
+ - Tends to confuse X with Y
316
+ - Recurring difficulty with: {area}
317
+
318
+ ## Topics
319
+
320
+ - Python decorators (8/10 concepts, 2025-01-15)
321
+ ```
322
+
323
+ 4. Give a brief text summary of what was covered, key insights, and areas for further study.
324
+
325
+ ## Notes Generation
326
+
327
+ At session end, generate a learner-facing notes file at `{topic-slug}/{topic-slug}-notes.md`. This file is **written for the learner to review later**, not for the tutor. It should be self-contained and organized as a quick-reference.
328
+
329
+ ### Notes Structure
330
+
331
+ ```markdown
332
+ # {Topic} Notes
333
+
334
+ ## 1. {Section Name}
335
+
336
+ {Key concept, mechanism, or principle}
337
+
338
+ - **One-line summary**: {what it does / why it matters}
339
+ - **Detail**: {brief explanation, 2-4 sentences max}
340
+ - **Example** (if applicable): {code snippet, command, or concrete scenario}
341
+
342
+ ---
343
+
344
+ ## 2. {Section Name}
345
+
346
+ ...
347
+
348
+ ---
349
+
350
+ ## n. 实战参数 / Cheat Sheet (if applicable)
351
+
352
+ {Practical commands, config, or quick-reference table}
353
+
354
+ | Parameter / Concept | What it does | Tuning tip |
355
+ | ------------------- | ------------ | ---------- |
356
+ | ... | ... | ... |
357
+ ```
358
+
359
+ ### Notes Writing Rules
360
+
361
+ 1. **Start with "what & why"** before "how". Each section should answer: what is this, why does it exist, what problem does it solve.
362
+ 2. **Use analogies sparingly but effectively**. Only include an analogy if it clarifies a non-obvious mechanism (e.g., "PagedAttention is like OS virtual memory paging").
363
+ 3. **Include trade-offs**. Every optimization or design choice has a cost. Always state it (e.g., "TP improves throughput but increases communication latency").
364
+ 4. **Code / command examples should be minimal**. Under 10 lines, self-contained, with comments explaining the key flags.
365
+ 5. **Organize by concept dependency**, not by chronological teaching order. Foundation concepts first, advanced ones last.
366
+ 6. **No quiz questions, no misconceptions, no tutor-side notes**. This is a clean reference document.
367
+ 7. **Language matches the session**. If the session was in Chinese, notes are in Chinese (technical terms can stay in English).
368
+ 8. **Keep it under 150 lines**. If it gets too long, the learner won't review it. Be ruthless about cutting fluff.
369
+
370
+ ## Resuming Sessions
371
+
372
+ On `--resume`:
373
+
374
+ 1. Read `session.md` and `learner-profile.md`
375
+ 2. Quick check on 1-2 previously mastered concepts via AskUserQuestion:
376
+
377
+ ```
378
+ header: "Quick review"
379
+ question: "Last time you mastered [concept X]. Can you recall which of these is true about it?"
380
+ multiSelect: false
381
+ options:
382
+ - label: "[correct statement]"
383
+ - label: "[plausible distractor]"
384
+ - label: "[plausible distractor]"
385
+ - label: "I forgot this one"
386
+ description: "No worries, we'll revisit it"
387
+ ```
388
+
389
+ 3. If forgotten, mark as ✗ needs review and revisit before continuing
390
+ 4. Recap: "Last time you mastered [X]. You were working on [Y]."
391
+ 5. Continue from first in-progress or not-started concept
392
+
393
+ ## Notes
394
+
395
+ - Keep it conversational, not mechanical
396
+ - Vary question types: predict, compare, debug, extend, teach-back, connect
397
+ - Slow down when struggling, speed up when flying
398
+ - Interleaving should feel natural, not like a pop quiz
399
+ - Wrong answers are more informative than right ones — never rush past them