@xiaotianxt/skills 0.1.0
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/EXCLUDED.md +42 -0
- package/LICENSE +21 -0
- package/README.md +165 -0
- package/SECURITY.md +23 -0
- package/SOURCES.md +45 -0
- package/bin/skills.mjs +241 -0
- package/package.json +38 -0
- package/skills/1password/SKILL.md +94 -0
- package/skills/1password/agents/openai.yaml +4 -0
- package/skills/1password/references/item-management.md +80 -0
- package/skills/1password/references/op-cli.md +107 -0
- package/skills/apple-calendar-event/SKILL.md +81 -0
- package/skills/apple-calendar-event/agents/openai.yaml +4 -0
- package/skills/apple-calendar-event/scripts/calendar_audit.py +201 -0
- package/skills/apple-calendar-event/scripts/calendar_event.py +164 -0
- package/skills/bro-browser/SKILL.md +118 -0
- package/skills/bro-browser/agents/openai.yaml +4 -0
- package/skills/bro-browser/references/tool-map.md +102 -0
- package/skills/bro-browser/references/workflows.md +146 -0
- package/skills/bro-browser/scripts/bro-call.mjs +189 -0
- package/skills/calendar/SKILL.md +182 -0
- package/skills/calendar/agents/openai.yaml +4 -0
- package/skills/calendar/references/operations.md +255 -0
- package/skills/calendar/scripts/calendar_list_review.py +157 -0
- package/skills/calendar/scripts/event_dedupe_preview.py +155 -0
- package/skills/canvas/SKILL.md +70 -0
- package/skills/canvas/agents/openai.yaml +4 -0
- package/skills/canvas/references/canvas-api.md +76 -0
- package/skills/course-exam-review-planner/SKILL.md +127 -0
- package/skills/cx/SKILL.md +25 -0
- package/skills/gh-fix-ci/LICENSE.txt +201 -0
- package/skills/gh-fix-ci/SKILL.md +81 -0
- package/skills/gh-fix-ci/agents/openai.yaml +6 -0
- package/skills/gh-fix-ci/assets/github-small.svg +3 -0
- package/skills/gh-fix-ci/assets/github.png +0 -0
- package/skills/gh-fix-ci/scripts/inspect_pr_checks.py +509 -0
- package/skills/gh-review-workflow/SKILL.md +61 -0
- package/skills/gh-review-workflow/agents/openai.yaml +4 -0
- package/skills/gh-review-workflow/references/workflow.md +48 -0
- package/skills/gh-review-workflow/scripts/fetch_review_state.py +222 -0
- package/skills/gh-review-workflow/scripts/resolve_review_threads.py +83 -0
- package/skills/github/SKILL.md +74 -0
- package/skills/github/agents/openai.yaml +6 -0
- package/skills/github/assets/github-small.svg +3 -0
- package/skills/github/assets/github.png +0 -0
- package/skills/gws-calendar/SKILL.md +126 -0
- package/skills/gws-calendar-agenda/SKILL.md +52 -0
- package/skills/gws-calendar-insert/SKILL.md +66 -0
- package/skills/gws-docs/SKILL.md +48 -0
- package/skills/gws-docs-write/SKILL.md +49 -0
- package/skills/gws-drive/SKILL.md +137 -0
- package/skills/gws-drive-upload/SKILL.md +52 -0
- package/skills/gws-gmail/SKILL.md +62 -0
- package/skills/gws-gmail-forward/SKILL.md +55 -0
- package/skills/gws-gmail-reply/SKILL.md +58 -0
- package/skills/gws-gmail-reply-all/SKILL.md +62 -0
- package/skills/gws-gmail-send/SKILL.md +57 -0
- package/skills/gws-gmail-triage/SKILL.md +50 -0
- package/skills/gws-gmail-watch/SKILL.md +58 -0
- package/skills/gws-shared/SKILL.md +27 -0
- package/skills/helium-browser-mcp/SKILL.md +137 -0
- package/skills/helium-browser-mcp/agents/openai.yaml +4 -0
- package/skills/helium-browser-mcp/scripts/obmcp.mjs +92 -0
- package/skills/helium-browser-mcp/scripts/openbrowsermcp-stdio-proxy.mjs +170 -0
- package/skills/learn/SKILL.md +122 -0
- package/skills/learn/agents/openai.yaml +7 -0
- package/skills/learn/assets/AGENTS.template.md +33 -0
- package/skills/learn/assets/errorlog.template.typ +61 -0
- package/skills/learn/assets/reading-sequence.template.md +23 -0
- package/skills/learn/assets/source-index.template.md +17 -0
- package/skills/learn/assets/tasklog.template.typ +57 -0
- package/skills/learn/assets/workbook.template.typ +60 -0
- package/skills/learn/references/learning-science.md +103 -0
- package/skills/learn/scripts/init_learning_workspace.py +70 -0
- package/skills/macos-messages/SKILL.md +258 -0
- package/skills/memory/SKILL.md +33 -0
- package/skills/memory/codex.md +186 -0
- package/skills/memory/opencode.md +164 -0
- package/skills/mimestreamctl/SKILL.md +170 -0
- package/skills/mimestreamctl/agents/openai.yaml +4 -0
- package/skills/mimestreamctl/scripts/mimestreamctl +33 -0
- package/skills/mon/SKILL.md +51 -0
- package/skills/mon/scripts/mon_spend_review.py +458 -0
- package/skills/ocr/SKILL.md +136 -0
- package/skills/ocr/agents/openai.yaml +4 -0
- package/skills/ocr/references/local-ocr-best-practices.md +297 -0
- package/skills/ocr/references/mineru-api.md +159 -0
- package/skills/ocr/scripts/ocr-router +22 -0
- package/skills/ocr/scripts/ocr_router.py +741 -0
- package/skills/panopto-mp4-bulk-download/SKILL.md +57 -0
- package/skills/panopto-mp4-bulk-download/agents/openai.yaml +4 -0
- package/skills/panopto-mp4-bulk-download/references/url-patterns.md +26 -0
- package/skills/panopto-mp4-bulk-download/scripts/panopto_bulk_mp4.sh +213 -0
- package/skills/rust-systems-style/SKILL.md +109 -0
- package/skills/rust-systems-style/agents/openai.yaml +4 -0
- package/skills/rust-systems-style/references/rust-review-checklist.md +77 -0
- package/skills/rust-systems-style/references/style-sources.md +68 -0
- package/skills/ship-ai-native-cli/SKILL.md +76 -0
- package/skills/ship-ai-native-cli/agents/openai.yaml +4 -0
- package/skills/ship-ai-native-cli/references/case-notes.md +83 -0
- package/skills/ship-ai-native-cli/references/product-method.md +82 -0
- package/skills/ship-ai-native-cli/references/release-checklist.md +147 -0
- package/skills/ship-ai-native-cli/references/rust-cli-shape.md +111 -0
- package/skills/telegram-mtproto-session/SKILL.md +125 -0
- package/skills/telegram-mtproto-session/agents/openai.yaml +4 -0
- package/skills/telegram-mtproto-session/scripts/telegram_session.py +687 -0
- package/skills/tg/SKILL.md +173 -0
- package/skills/things3-manager/SKILL.md +116 -0
- package/skills/things3-manager/scripts/things +42 -0
- package/skills/things3-manager/scripts/things_cli.py +514 -0
- package/skills/web-artifacts-builder/LICENSE.txt +202 -0
- package/skills/web-artifacts-builder/SKILL.md +74 -0
- package/skills/web-artifacts-builder/scripts/bundle-artifact.sh +54 -0
- package/skills/web-artifacts-builder/scripts/init-artifact.sh +379 -0
- package/skills/web-artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
- package/skills/yeet/LICENSE.txt +201 -0
- package/skills/yeet/SKILL.md +71 -0
- package/skills/yeet/agents/openai.yaml +6 -0
- package/skills/yeet/assets/yeet-small.svg +3 -0
- package/skills/yeet/assets/yeet.png +0 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#set page(paper: "a4", margin: 1.8cm)
|
|
2
|
+
#set text(font: ("PingFang SC", "Arial Unicode MS"), size: 10.5pt, lang: "zh")
|
|
3
|
+
#set par(justify: true, leading: 0.62em)
|
|
4
|
+
|
|
5
|
+
= {TOPIC} 错题与误区日志
|
|
6
|
+
|
|
7
|
+
用途:记录学习过程中暴露出的错误、模糊理解、概念混淆、迁移失败和关键盲点。这个文件决定后续复习顺序。
|
|
8
|
+
|
|
9
|
+
记录规则:
|
|
10
|
+
|
|
11
|
+
- 只记录会影响后续理解或应用的错误,不记录每个小瑕疵。
|
|
12
|
+
- 保留学习者原始回答的意思,避免事后美化。
|
|
13
|
+
- 每条错误必须包含正确理解和下一次复习动作。
|
|
14
|
+
- 连续两次跨会话答对,才可以从 `review` 改为 `closed`。
|
|
15
|
+
|
|
16
|
+
== 错误分类
|
|
17
|
+
|
|
18
|
+
#table(
|
|
19
|
+
columns: (3.0cm, 1fr),
|
|
20
|
+
inset: 5pt,
|
|
21
|
+
align: left,
|
|
22
|
+
[类型], [说明],
|
|
23
|
+
[concept], [概念混淆。],
|
|
24
|
+
[source], [没有说清楚依据来自哪份资料,或脱离资料泛泛而谈。],
|
|
25
|
+
[application], [不能迁移到新场景。],
|
|
26
|
+
[boundary], [忽略边界条件或失败模式。],
|
|
27
|
+
[terminology], [术语不熟。],
|
|
28
|
+
[method], [解题方法、分析步骤或学习策略错误。],
|
|
29
|
+
[process], [学习流程问题,例如跳过提问或复盘。],
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
== 活跃错误表
|
|
33
|
+
|
|
34
|
+
#table(
|
|
35
|
+
columns: (1.1cm, 1.6cm, 1.7cm, 2.3cm, 1fr, 1fr, 2.0cm, 1.5cm),
|
|
36
|
+
inset: 3.6pt,
|
|
37
|
+
align: left,
|
|
38
|
+
[ID], [日期], [课程], [类型], [错误表现], [修正解释], [复习日期], [状态],
|
|
39
|
+
[E000], [{DATE}], [Plan], [process], [尚未开始正式问答。], [从 L001 开始,用验证问题暴露真实薄弱点。], [{DATE}], [open],
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
== 新错误记录模板
|
|
43
|
+
|
|
44
|
+
#table(
|
|
45
|
+
columns: (3.0cm, 1fr),
|
|
46
|
+
inset: 5pt,
|
|
47
|
+
align: left,
|
|
48
|
+
[字段], [内容],
|
|
49
|
+
[ID], [E001],
|
|
50
|
+
[日期], [YYYY-MM-DD],
|
|
51
|
+
[课程], [L???],
|
|
52
|
+
[类型], [concept / source / application / boundary / terminology / method / process],
|
|
53
|
+
[原问题], [助教提出的验证问题。],
|
|
54
|
+
[学习者回答], [保留学习者原意,避免事后美化。],
|
|
55
|
+
[错误表现], [具体指出错在哪里。],
|
|
56
|
+
[正确理解], [用简单语言修正。],
|
|
57
|
+
[为什么重要], [如果这个错误保留下来,会影响哪类理解、题目、项目或判断。],
|
|
58
|
+
[复习动作], [下一次如何验证是否真正掌握。],
|
|
59
|
+
[复习日期], [YYYY-MM-DD],
|
|
60
|
+
[状态], [open / review / closed],
|
|
61
|
+
)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# {TOPIC} Reading Sequence
|
|
2
|
+
|
|
3
|
+
Goal: {GOAL}
|
|
4
|
+
|
|
5
|
+
## First Pass
|
|
6
|
+
|
|
7
|
+
### L001: Establish the Goal and Map the Sources
|
|
8
|
+
|
|
9
|
+
Read:
|
|
10
|
+
|
|
11
|
+
- `materials/source-index.md`
|
|
12
|
+
|
|
13
|
+
Questions:
|
|
14
|
+
|
|
15
|
+
- What should the learner be able to do after this topic?
|
|
16
|
+
- Which sources are authoritative?
|
|
17
|
+
- What is the first small unit worth teaching?
|
|
18
|
+
|
|
19
|
+
Output:
|
|
20
|
+
|
|
21
|
+
- Update `tasklog.typ`.
|
|
22
|
+
- Ask verification questions before marking L001 done.
|
|
23
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# {TOPIC} Source Index
|
|
2
|
+
|
|
3
|
+
Goal: {GOAL}
|
|
4
|
+
|
|
5
|
+
## Source Table
|
|
6
|
+
|
|
7
|
+
| Priority | Source | Local Path / URL | Type | Use |
|
|
8
|
+
|---|---|---|---|---|
|
|
9
|
+
| must | TBD | TBD | book/course/doc/paper/video | Core source |
|
|
10
|
+
|
|
11
|
+
## Collection Rules
|
|
12
|
+
|
|
13
|
+
- Prefer primary sources.
|
|
14
|
+
- Convert enough material into AI-readable text to teach accurately.
|
|
15
|
+
- Keep raw files and links; write original notes instead of copying long copyrighted text.
|
|
16
|
+
- Add sources as questions demand them; do not block learning on exhaustive collection.
|
|
17
|
+
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#set page(paper: "a4", margin: 1.8cm)
|
|
2
|
+
#set text(font: ("PingFang SC", "Arial Unicode MS"), size: 10.5pt, lang: "zh")
|
|
3
|
+
#set par(justify: true, leading: 0.62em)
|
|
4
|
+
|
|
5
|
+
= {TOPIC} 学习任务日志
|
|
6
|
+
|
|
7
|
+
目标:{GOAL}
|
|
8
|
+
|
|
9
|
+
使用规则:
|
|
10
|
+
|
|
11
|
+
- 每次讲解后,助教必须提出验证问题。
|
|
12
|
+
- 学习者回答后,助教必须评分并更新本日志。
|
|
13
|
+
- 答错、含糊、只会背但不能应用的内容,必须同步写入 `errorlog.typ`。
|
|
14
|
+
- 状态使用 `todo`、`doing`、`review`、`done`。
|
|
15
|
+
- `done` 的条件是:能用自己的话解释,能应用到新场景,能指出常见误判。
|
|
16
|
+
|
|
17
|
+
== 评分规则
|
|
18
|
+
|
|
19
|
+
#table(
|
|
20
|
+
columns: (1.2cm, 3.2cm, 1fr),
|
|
21
|
+
inset: 5pt,
|
|
22
|
+
align: left,
|
|
23
|
+
[分数], [判定], [标准],
|
|
24
|
+
[0], [未掌握], [无法解释核心概念,或给出误导性答案。],
|
|
25
|
+
[1], [初步听懂], [能复述定义,但不能独立举例或应用。],
|
|
26
|
+
[2], [基本掌握], [能解释含义,并能应用到一个合理场景。],
|
|
27
|
+
[3], [可实战沟通], [能说明边界、误区、失败模式和下一步行动。],
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
== 学习计划
|
|
31
|
+
|
|
32
|
+
#table(
|
|
33
|
+
columns: (1.4cm, 4.2cm, 1.5cm, 1.4cm, 1fr),
|
|
34
|
+
inset: 4pt,
|
|
35
|
+
align: left,
|
|
36
|
+
[课], [主题], [优先级], [状态], [目标],
|
|
37
|
+
[L001], [建立问题和目标], [must], [doing], [明确学习目标、资料范围、输出标准和第一轮问题。],
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
== 讲解会话日志
|
|
41
|
+
|
|
42
|
+
#table(
|
|
43
|
+
columns: (2.2cm, 1.8cm, 1.8cm, 1.8cm, 1.7cm, 1fr),
|
|
44
|
+
inset: 4pt,
|
|
45
|
+
align: left,
|
|
46
|
+
[日期], [课程], [状态], [平均分], [错题数], [下一步],
|
|
47
|
+
[{DATE}], [Plan], [doing], [-], [0], [开始收集资料并建立第一轮学习顺序。],
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
== 验证问题模板
|
|
51
|
+
|
|
52
|
+
1. 概念解释:请用自己的话解释本节最重要的概念。
|
|
53
|
+
2. 来源依据:资料中哪一处支持这个说法?
|
|
54
|
+
3. 应用场景:把概念应用到一个新例子。
|
|
55
|
+
4. 误判识别:最容易犯的错误解释是什么?
|
|
56
|
+
5. 下一步:如果证据不足,下一步应该读什么、问什么或做什么?
|
|
57
|
+
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#set page(paper: "a4", margin: 1.8cm)
|
|
2
|
+
#set text(font: ("PingFang SC", "Arial Unicode MS"), size: 10.5pt, lang: "zh")
|
|
3
|
+
#set par(justify: true, leading: 0.62em)
|
|
4
|
+
|
|
5
|
+
= {TOPIC} 学习工作本
|
|
6
|
+
|
|
7
|
+
目标:{GOAL}
|
|
8
|
+
|
|
9
|
+
这个文件用于记录每节课的讲解结构、关键例子、验证问题和修正后的理解。错题本只记录错误;工作本记录学习过程。
|
|
10
|
+
|
|
11
|
+
== 使用方法
|
|
12
|
+
|
|
13
|
+
每个小节按这个结构记录:
|
|
14
|
+
|
|
15
|
+
#enum[
|
|
16
|
+
Source:本节基于哪些资料。
|
|
17
|
+
][
|
|
18
|
+
Map:本节知识地图。
|
|
19
|
+
][
|
|
20
|
+
Explanation:完整讲解。
|
|
21
|
+
][
|
|
22
|
+
Example:例题、业务场景、代码场景或案例。
|
|
23
|
+
][
|
|
24
|
+
Questions:验证问题。
|
|
25
|
+
][
|
|
26
|
+
Correction:回答后的修正说明。
|
|
27
|
+
][
|
|
28
|
+
Drill:下一次复习或迁移练习。
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
== L001:起步
|
|
32
|
+
|
|
33
|
+
=== Source
|
|
34
|
+
|
|
35
|
+
待补。
|
|
36
|
+
|
|
37
|
+
=== Map
|
|
38
|
+
|
|
39
|
+
待补。
|
|
40
|
+
|
|
41
|
+
=== Explanation
|
|
42
|
+
|
|
43
|
+
待补。
|
|
44
|
+
|
|
45
|
+
=== Example
|
|
46
|
+
|
|
47
|
+
待补。
|
|
48
|
+
|
|
49
|
+
=== Questions
|
|
50
|
+
|
|
51
|
+
待补。
|
|
52
|
+
|
|
53
|
+
=== Correction
|
|
54
|
+
|
|
55
|
+
待补。
|
|
56
|
+
|
|
57
|
+
=== Drill
|
|
58
|
+
|
|
59
|
+
待补。
|
|
60
|
+
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Learning Science Reference
|
|
2
|
+
|
|
3
|
+
Use these principles to design or adjust learning workflows.
|
|
4
|
+
|
|
5
|
+
## Evidence-Backed Defaults
|
|
6
|
+
|
|
7
|
+
### Retrieval Practice
|
|
8
|
+
|
|
9
|
+
Testing is not only assessment; it is a learning event. Prefer short-answer questions, explanation prompts, trace interpretation, and transfer questions over recognition-only checks.
|
|
10
|
+
|
|
11
|
+
Implementation:
|
|
12
|
+
|
|
13
|
+
- Teach a small unit.
|
|
14
|
+
- Ask the learner to explain or apply it without looking.
|
|
15
|
+
- Give corrective feedback.
|
|
16
|
+
- Log the exact misconception if the answer is weak.
|
|
17
|
+
|
|
18
|
+
Source anchors:
|
|
19
|
+
|
|
20
|
+
- Dunlosky et al. (2013): practice testing is high utility.
|
|
21
|
+
- Roediger & Karpicke (2006): retrieval after studying prose improved later retention.
|
|
22
|
+
|
|
23
|
+
### Distributed Practice and Successive Relearning
|
|
24
|
+
|
|
25
|
+
Spacing matters. Review should happen after a gap, and practice should continue until the learner can retrieve to criterion.
|
|
26
|
+
|
|
27
|
+
Implementation:
|
|
28
|
+
|
|
29
|
+
- Keep error items `open`, `review`, or `closed`.
|
|
30
|
+
- Review open items after time has passed or when the user asks.
|
|
31
|
+
- Close only after repeated correct retrieval in separate sessions.
|
|
32
|
+
- Do not force a rigid schedule that annoys the user.
|
|
33
|
+
|
|
34
|
+
Source anchors:
|
|
35
|
+
|
|
36
|
+
- Cepeda et al. (2006): spacing effects are broadly supported, with optimal gaps depending on retention interval.
|
|
37
|
+
- Rawson & Dunlosky (2022): successive relearning combines spaced sessions and retrieval to criterion, but cost-benefit matters.
|
|
38
|
+
|
|
39
|
+
### Formative Feedback
|
|
40
|
+
|
|
41
|
+
Feedback should answer: where is the learner going, how are they doing, and what should happen next. Feedback should explain the correction, not only mark right/wrong.
|
|
42
|
+
|
|
43
|
+
Implementation:
|
|
44
|
+
|
|
45
|
+
- Score answers with a transparent rubric.
|
|
46
|
+
- Write the corrected model.
|
|
47
|
+
- Add a next review action.
|
|
48
|
+
- Avoid generic praise or vague criticism.
|
|
49
|
+
|
|
50
|
+
Source anchors:
|
|
51
|
+
|
|
52
|
+
- Shute (2007): formative feedback varies by type and timing; effective feedback includes explanation, hints, or worked examples depending on task and learner.
|
|
53
|
+
|
|
54
|
+
### Cognitive Load
|
|
55
|
+
|
|
56
|
+
Learning complex technical material fails when working memory is overloaded by disorganized sources, unnecessary notation, scattered files, or too many simultaneous objectives.
|
|
57
|
+
|
|
58
|
+
Implementation:
|
|
59
|
+
|
|
60
|
+
- Convert sources into readable text.
|
|
61
|
+
- Create a reading sequence.
|
|
62
|
+
- Teach in small units.
|
|
63
|
+
- Use worked examples before independent problems for novices.
|
|
64
|
+
- Fade support as competence rises.
|
|
65
|
+
|
|
66
|
+
Source anchors:
|
|
67
|
+
|
|
68
|
+
- Sweller, van Merrienboer, & Paas (1998): instructional design should account for working-memory limits, intrinsic load, extraneous load, and schema construction.
|
|
69
|
+
- Kalyuga (2007): learner prior knowledge changes which instructional support helps; too much guidance can hurt advanced learners.
|
|
70
|
+
|
|
71
|
+
### Active Learning and ICAP
|
|
72
|
+
|
|
73
|
+
Do not confuse "interactive chat" with active learning. The learner must generate, explain, compare, debug, or transfer.
|
|
74
|
+
|
|
75
|
+
Implementation:
|
|
76
|
+
|
|
77
|
+
- Require the learner to explain in their own words.
|
|
78
|
+
- Ask transfer questions: "what tool next?", "what field/module does this become?", "what failure mode follows?"
|
|
79
|
+
- Prefer constructive and interactive activities over passive reading.
|
|
80
|
+
|
|
81
|
+
Source anchors:
|
|
82
|
+
|
|
83
|
+
- Freeman et al. (2014): active learning improved STEM outcomes in a large meta-analysis.
|
|
84
|
+
- Chi & Wylie (2014): ICAP orders engagement from passive to active to constructive to interactive.
|
|
85
|
+
|
|
86
|
+
## Critique of the Folder + Sources + Logs Pipeline
|
|
87
|
+
|
|
88
|
+
The pipeline is strong because it creates source grounding, retrieval, feedback, and cumulative error memory. It should be adjusted in four ways:
|
|
89
|
+
|
|
90
|
+
1. Do not over-collect. Start with a minimum viable corpus, then collect more when a question demands it.
|
|
91
|
+
2. Do not over-convert. Convert enough for AI use; keep raw originals and indexes rather than rewriting entire books.
|
|
92
|
+
3. Do not over-log. Log misconceptions that would cause future failure, not every stylistic weakness.
|
|
93
|
+
4. Do not over-schedule review. Use spaced review as a tool, but let the user trigger heavy review unless a deadline requires a plan.
|
|
94
|
+
|
|
95
|
+
## Practical Design Rule
|
|
96
|
+
|
|
97
|
+
A good learning workspace has exactly four persistent memories:
|
|
98
|
+
|
|
99
|
+
1. Source memory: what materials exist and where.
|
|
100
|
+
2. Goal memory: what the learner is trying to become able to do.
|
|
101
|
+
3. Progress memory: what has been covered and scored.
|
|
102
|
+
4. Error memory: what the learner got wrong and how to revisit it.
|
|
103
|
+
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Initialize a source-grounded learning workspace."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
from datetime import date
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def slugify(value: str) -> str:
|
|
12
|
+
out = []
|
|
13
|
+
last_dash = False
|
|
14
|
+
for ch in value.lower():
|
|
15
|
+
if ch.isalnum():
|
|
16
|
+
out.append(ch)
|
|
17
|
+
last_dash = False
|
|
18
|
+
elif not last_dash:
|
|
19
|
+
out.append("-")
|
|
20
|
+
last_dash = True
|
|
21
|
+
return "".join(out).strip("-") or "learning-topic"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def render(template: str, topic: str, goal: str) -> str:
|
|
25
|
+
return (
|
|
26
|
+
template.replace("{TOPIC}", topic)
|
|
27
|
+
.replace("{GOAL}", goal)
|
|
28
|
+
.replace("{DATE}", date.today().isoformat())
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def main() -> int:
|
|
33
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
34
|
+
parser.add_argument("topic", help="Human-readable topic name")
|
|
35
|
+
parser.add_argument("--path", default=".", help="Parent directory for workspace")
|
|
36
|
+
parser.add_argument("--name", help="Workspace folder name; defaults to topic slug")
|
|
37
|
+
parser.add_argument("--goal", default="Build practical, source-grounded mastery.")
|
|
38
|
+
parser.add_argument("--force", action="store_true", help="Overwrite existing template files")
|
|
39
|
+
args = parser.parse_args()
|
|
40
|
+
|
|
41
|
+
skill_dir = Path(__file__).resolve().parents[1]
|
|
42
|
+
assets = skill_dir / "assets"
|
|
43
|
+
root = Path(args.path).expanduser().resolve() / (args.name or slugify(args.topic))
|
|
44
|
+
root.mkdir(parents=True, exist_ok=True)
|
|
45
|
+
|
|
46
|
+
for subdir in ["materials", "notes", "cases", "outputs"]:
|
|
47
|
+
(root / subdir).mkdir(exist_ok=True)
|
|
48
|
+
|
|
49
|
+
files = {
|
|
50
|
+
"AGENTS.md": assets / "AGENTS.template.md",
|
|
51
|
+
"tasklog.typ": assets / "tasklog.template.typ",
|
|
52
|
+
"errorlog.typ": assets / "errorlog.template.typ",
|
|
53
|
+
"workbook.typ": assets / "workbook.template.typ",
|
|
54
|
+
"materials/source-index.md": assets / "source-index.template.md",
|
|
55
|
+
"notes/reading-sequence.md": assets / "reading-sequence.template.md",
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
for rel, template_path in files.items():
|
|
59
|
+
target = root / rel
|
|
60
|
+
if target.exists() and not args.force:
|
|
61
|
+
continue
|
|
62
|
+
text = render(template_path.read_text(), args.topic, args.goal)
|
|
63
|
+
target.write_text(text)
|
|
64
|
+
|
|
65
|
+
print(root)
|
|
66
|
+
return 0
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
if __name__ == "__main__":
|
|
70
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: macos-messages
|
|
3
|
+
description: Read and search local macOS Messages.app iMessage/SMS history directly through the chat.db SQLite database. Use when the user wants to read, search, or analyze local iPhone messages, SMS, iMessage conversations, or message attachments on this Mac.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# macOS Messages
|
|
7
|
+
|
|
8
|
+
Direct read-only SQLite access to `~/Library/Messages/chat.db` for local iMessage and SMS history. No CLI wrapper — use `sqlite3` with the queries below.
|
|
9
|
+
|
|
10
|
+
## Privacy
|
|
11
|
+
|
|
12
|
+
Chat data is private. Keep all work local. Print only the message content the user asked for. Never export `chat.db` to external services. Treat message bodies, sender identities, and attachment paths as sensitive.
|
|
13
|
+
|
|
14
|
+
## Setup
|
|
15
|
+
|
|
16
|
+
The terminal needs **Full Disk Access** in System Settings → Privacy & Security → Full Disk Access. Without it, `~/Library/Messages/chat.db` is permission-denied.
|
|
17
|
+
|
|
18
|
+
Verify:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
sqlite3 ~/Library/Messages/chat.db "SELECT COUNT(*) FROM message"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Schema
|
|
25
|
+
|
|
26
|
+
Four core tables, three join tables:
|
|
27
|
+
|
|
28
|
+
| Table | Role |
|
|
29
|
+
| --- | --- |
|
|
30
|
+
| `chat` | Conversation. `chat_identifier` is phone/email/group-id. `display_name` is the group name. |
|
|
31
|
+
| `message` | Individual message. `text` or `attributedBody` holds the body, `date` is timestamp, `is_from_me`=1 means sent. |
|
|
32
|
+
| `handle` | Contact. `id` is phone or email, `service` is iMessage/SMS/RCS. |
|
|
33
|
+
| `attachment` | Media file. `filename` is the on-disk path, `mime_type` is MIME type. |
|
|
34
|
+
|
|
35
|
+
Join tables: `chat_message_join`, `chat_handle_join`, `message_attachment_join`.
|
|
36
|
+
|
|
37
|
+
## Text vs attributedBody
|
|
38
|
+
|
|
39
|
+
**This is the most common pitfall.** `message.text` is frequently NULL because Messages.app stores the body in `attributedBody` (NSKeyedArchiver binary blob) instead. This happens for most SMS, RCS, and rich iMessages. Plain-text iMessages are the main case where `text` is populated.
|
|
40
|
+
|
|
41
|
+
To extract readable text from `attributedBody`:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
sqlite3 ~/Library/Messages/chat.db \
|
|
45
|
+
"SELECT HEX(attributedBody) FROM message WHERE ROWID=<MSG_ID>" \
|
|
46
|
+
| xxd -r -p | strings | grep -vE '^(NS|__)' | grep -v streamtyped | head -20
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
To run this in a single pipeline for a full chat read, see **Reading with extraction** below.
|
|
50
|
+
|
|
51
|
+
## Date Conversion
|
|
52
|
+
|
|
53
|
+
All timestamps use Mac absolute time (since 2001-01-01). Convert:
|
|
54
|
+
|
|
55
|
+
```sql
|
|
56
|
+
-- message.date: nanoseconds since 2001-01-01
|
|
57
|
+
datetime(date/1000000000 + 978307200, 'unixepoch', 'localtime')
|
|
58
|
+
|
|
59
|
+
-- attachment.created_date: seconds since 2001-01-01
|
|
60
|
+
datetime(created_date + 978307200, 'unixepoch', 'localtime')
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`978307200` = delta in seconds between Unix epoch (1970-01-01) and Mac epoch (2001-01-01).
|
|
64
|
+
|
|
65
|
+
## Common Queries
|
|
66
|
+
|
|
67
|
+
### List recent chats
|
|
68
|
+
|
|
69
|
+
```sql
|
|
70
|
+
SELECT c.ROWID, c.chat_identifier, c.display_name, c.service_name,
|
|
71
|
+
datetime(MAX(m.date)/1000000000 + 978307200, 'unixepoch', 'localtime') AS last_msg
|
|
72
|
+
FROM chat c
|
|
73
|
+
JOIN chat_message_join cmj ON c.ROWID = cmj.chat_id
|
|
74
|
+
JOIN message m ON cmj.message_id = m.ROWID
|
|
75
|
+
GROUP BY c.ROWID
|
|
76
|
+
ORDER BY MAX(m.date) DESC
|
|
77
|
+
LIMIT 20
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Find a chat
|
|
81
|
+
|
|
82
|
+
```sql
|
|
83
|
+
SELECT ROWID, chat_identifier, display_name, service_name
|
|
84
|
+
FROM chat
|
|
85
|
+
WHERE chat_identifier LIKE '%KEYWORD%'
|
|
86
|
+
OR display_name LIKE '%KEYWORD%'
|
|
87
|
+
LIMIT 10
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Read messages from a chat (with extraction)
|
|
91
|
+
|
|
92
|
+
Replace `<CHAT_ID>` with the chat ROWID. This extracts text from both `text` and `attributedBody`:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
sqlite3 ~/Library/Messages/chat.db -separator $'\t' \
|
|
96
|
+
"SELECT m.ROWID, datetime(m.date/1000000000 + 978307200, 'unixepoch', 'localtime') AS time,
|
|
97
|
+
CASE WHEN m.is_from_me THEN 'Me' ELSE COALESCE(h.id, m.service) END AS sender,
|
|
98
|
+
COALESCE(m.text, HEX(m.attributedBody)) AS body
|
|
99
|
+
FROM message m
|
|
100
|
+
JOIN chat_message_join cmj ON m.ROWID = cmj.message_id
|
|
101
|
+
LEFT JOIN handle h ON m.handle_id = h.ROWID
|
|
102
|
+
WHERE cmj.chat_id = <CHAT_ID>
|
|
103
|
+
ORDER BY m.date DESC
|
|
104
|
+
LIMIT 50" \
|
|
105
|
+
| while IFS=$'\t' read rowid time sender body; do
|
|
106
|
+
text="$body"
|
|
107
|
+
if [[ "$body" =~ ^[0-9A-Fa-f]+$ ]] && [ ${#body} -gt 40 ]; then
|
|
108
|
+
text=$(echo "$body" | xxd -r -p | strings | grep -vE '^(NS|__)' | grep -v streamtyped | tr '\n' ' ' 2>/dev/null | head -c 500)
|
|
109
|
+
fi
|
|
110
|
+
echo "$time | $sender | ${text:0:300}"
|
|
111
|
+
done
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
For ascending order (oldest first): change `DESC` to `ASC`.
|
|
115
|
+
|
|
116
|
+
For a quick peek (no extraction, just see which messages have body):
|
|
117
|
+
|
|
118
|
+
```sql
|
|
119
|
+
SELECT datetime(m.date/1000000000 + 978307200, 'unixepoch', 'localtime') AS time,
|
|
120
|
+
CASE WHEN m.is_from_me THEN 'Me' ELSE COALESCE(h.id, m.service) END AS sender,
|
|
121
|
+
CASE WHEN m.text IS NOT NULL THEN SUBSTR(m.text, 1, 80)
|
|
122
|
+
WHEN m.attributedBody IS NOT NULL THEN '[attributedBody: ' || LENGTH(m.attributedBody) || ' bytes]'
|
|
123
|
+
ELSE '[empty]' END AS preview
|
|
124
|
+
FROM message m
|
|
125
|
+
JOIN chat_message_join cmj ON m.ROWID = cmj.message_id
|
|
126
|
+
LEFT JOIN handle h ON m.handle_id = h.ROWID
|
|
127
|
+
WHERE cmj.chat_id = <CHAT_ID>
|
|
128
|
+
ORDER BY m.date DESC
|
|
129
|
+
LIMIT 50
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Read messages in a date range
|
|
133
|
+
|
|
134
|
+
```sql
|
|
135
|
+
WHERE cmj.chat_id = <CHAT_ID>
|
|
136
|
+
AND m.date >= strftime('%s', '2026-04-01', 'localtime') * 1000000000 - 978307200000000000
|
|
137
|
+
AND m.date < strftime('%s', '2026-05-01', 'localtime') * 1000000000 - 978307200000000000
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Search all messages
|
|
141
|
+
|
|
142
|
+
Searches both `text` and `attributedBody`. Pipe through grep to handle binary extraction:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
sqlite3 ~/Library/Messages/chat.db -separator $'\t' \
|
|
146
|
+
"SELECT m.ROWID, datetime(m.date/1000000000 + 978307200, 'unixepoch', 'localtime') AS time,
|
|
147
|
+
CASE WHEN m.is_from_me THEN 'Me' ELSE COALESCE(h.id, m.service) END AS sender,
|
|
148
|
+
COALESCE(m.text, HEX(m.attributedBody)) AS body,
|
|
149
|
+
c.chat_identifier
|
|
150
|
+
FROM message m
|
|
151
|
+
JOIN chat_message_join cmj ON m.ROWID = cmj.message_id
|
|
152
|
+
JOIN chat c ON cmj.chat_id = c.ROWID
|
|
153
|
+
LEFT JOIN handle h ON m.handle_id = h.ROWID
|
|
154
|
+
WHERE m.text LIKE '%KEYWORD%' ESCAPE '\'
|
|
155
|
+
OR HEX(m.attributedBody) LIKE '%' || REPLACE(HEX('KEYWORD'), '00', '') || '%'
|
|
156
|
+
ORDER BY m.date DESC
|
|
157
|
+
LIMIT 30" \
|
|
158
|
+
| while IFS=$'\t' read rowid time sender body chat; do
|
|
159
|
+
text="$body"
|
|
160
|
+
if [[ "$body" =~ ^[0-9A-Fa-f]+$ ]] && [ ${#body} -gt 40 ]; then
|
|
161
|
+
text=$(echo "$body" | xxd -r -p | strings | grep -vE '^(NS|__)' | grep -v streamtyped | tr '\n' ' ' 2>/dev/null | head -c 500)
|
|
162
|
+
fi
|
|
163
|
+
echo "$time | $sender | ${text:0:300} | [$chat]"
|
|
164
|
+
done
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
The `REPLACE(HEX('KEYWORD'), '00', '')` accounts for UTF-16 encoding in the blob — hex matching handles ASCII text without needing full blob decode.
|
|
168
|
+
|
|
169
|
+
For a faster SQL-only search (returns matched rows, requires separate extraction):
|
|
170
|
+
|
|
171
|
+
```sql
|
|
172
|
+
SELECT m.ROWID, datetime(m.date/1000000000 + 978307200, 'unixepoch', 'localtime') AS time,
|
|
173
|
+
CASE WHEN m.is_from_me THEN 'Me' ELSE COALESCE(h.id, m.service) END AS sender,
|
|
174
|
+
SUBSTR(COALESCE(m.text, ''), 1, 80) AS snippet,
|
|
175
|
+
c.chat_identifier
|
|
176
|
+
FROM message m
|
|
177
|
+
JOIN chat_message_join cmj ON m.ROWID = cmj.message_id
|
|
178
|
+
JOIN chat c ON cmj.chat_id = c.ROWID
|
|
179
|
+
LEFT JOIN handle h ON m.handle_id = h.ROWID
|
|
180
|
+
WHERE m.text LIKE '%KEYWORD%' ESCAPE '\'
|
|
181
|
+
OR HEX(m.attributedBody) LIKE '%' || REPLACE(HEX('KEYWORD'), '00', '') || '%'
|
|
182
|
+
ORDER BY m.date DESC
|
|
183
|
+
LIMIT 30
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Search by contact
|
|
187
|
+
|
|
188
|
+
Find the handle first:
|
|
189
|
+
|
|
190
|
+
```sql
|
|
191
|
+
SELECT ROWID, id, service FROM handle WHERE id LIKE '%PHONE_OR_EMAIL%' LIMIT 10
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Then get their messages with extraction (replace `<HANDLE_ID>`):
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
sqlite3 ~/Library/Messages/chat.db -separator $'\t' \
|
|
198
|
+
"SELECT m.ROWID, datetime(m.date/1000000000 + 978307200, 'unixepoch', 'localtime') AS time,
|
|
199
|
+
COALESCE(m.text, HEX(m.attributedBody)) AS body, m.is_from_me
|
|
200
|
+
FROM message m
|
|
201
|
+
WHERE m.handle_id = <HANDLE_ID>
|
|
202
|
+
ORDER BY m.date DESC
|
|
203
|
+
LIMIT 50" \
|
|
204
|
+
| while IFS=$'\t' read rowid time body is_from_me; do
|
|
205
|
+
text="$body"
|
|
206
|
+
if [[ "$body" =~ ^[0-9A-Fa-f]+$ ]] && [ ${#body} -gt 40 ]; then
|
|
207
|
+
text=$(echo "$body" | xxd -r -p | strings | grep -vE '^(NS|__)' | grep -v streamtyped | tr '\n' ' ' 2>/dev/null | head -c 500)
|
|
208
|
+
fi
|
|
209
|
+
echo "$time | $([ "$is_from_me" = 1 ] && echo 'Me' || echo '→') | ${text:0:300}"
|
|
210
|
+
done
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Message counts per chat
|
|
214
|
+
|
|
215
|
+
```sql
|
|
216
|
+
SELECT c.chat_identifier, c.display_name, COUNT(m.ROWID) AS msg_count
|
|
217
|
+
FROM chat c
|
|
218
|
+
JOIN chat_message_join cmj ON c.ROWID = cmj.chat_id
|
|
219
|
+
JOIN message m ON cmj.message_id = m.ROWID
|
|
220
|
+
GROUP BY c.ROWID
|
|
221
|
+
ORDER BY msg_count DESC
|
|
222
|
+
LIMIT 20
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Get attachments for a message
|
|
226
|
+
|
|
227
|
+
```sql
|
|
228
|
+
SELECT a.filename, a.mime_type, a.total_bytes
|
|
229
|
+
FROM attachment a
|
|
230
|
+
JOIN message_attachment_join maj ON a.ROWID = maj.attachment_id
|
|
231
|
+
WHERE maj.message_id = <MESSAGE_ID>
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Attachments by date
|
|
235
|
+
|
|
236
|
+
```sql
|
|
237
|
+
SELECT datetime(a.created_date + 978307200, 'unixepoch', 'localtime') AS time,
|
|
238
|
+
a.filename, a.mime_type, a.total_bytes
|
|
239
|
+
FROM attachment a
|
|
240
|
+
ORDER BY a.created_date DESC
|
|
241
|
+
LIMIT 30
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## Safety
|
|
245
|
+
|
|
246
|
+
- **Read-only only.** Never run INSERT, UPDATE, DELETE, or DROP against `chat.db`.
|
|
247
|
+
- Always add `LIMIT`. This database can have tens of thousands of rows.
|
|
248
|
+
- When `text` is NULL, extract from `attributedBody` using the pipeline above — never assume a NULL `text` means an empty message.
|
|
249
|
+
|
|
250
|
+
## Troubleshooting
|
|
251
|
+
|
|
252
|
+
| Symptom | Fix |
|
|
253
|
+
| --- | --- |
|
|
254
|
+
| `unable to open database file` | Grant Full Disk Access to Terminal in System Settings |
|
|
255
|
+
| `database is locked` | Normal when Messages.app is running; sqlite3 handles concurrent reads fine |
|
|
256
|
+
| No results for a known contact | Try both phone number and email in `handle.id`. iMessage uses email, SMS uses phone. |
|
|
257
|
+
| `text` IS NULL | Body is in `attributedBody`. Extract with: `HEX(attributedBody) \| xxd -r -p \| strings \| grep -vE '^(NS\|__)' \| grep -v streamtyped` |
|
|
258
|
+
| Search misses expected messages | Query only searched `text`. Add `OR HEX(m.attributedBody) LIKE '%' \|\| REPLACE(HEX('KEYWORD'), '00', '') \|\| '%'` to cover attributedBody. |
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: memory
|
|
3
|
+
description: Query and read past coding-agent session/conversation history, across both opencode and codex. Use when the user wants to recall something discussed in a previous session, search past conversations by keyword, review context from old sessions, or continue prior work. Triggers include "查一下之前的聊天记录", "还记得上次那个...", "look up a past session", "what did we talk about...", or any request to recall historical context.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Memory
|
|
7
|
+
|
|
8
|
+
This skill provides read-only access to past conversation history, supporting multiple coding agents.
|
|
9
|
+
|
|
10
|
+
## Agent detection
|
|
11
|
+
|
|
12
|
+
Determine which agent you are running under, then load the corresponding reference file:
|
|
13
|
+
|
|
14
|
+
| Agent | How to detect | Reference file |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| **OpenCode** | System prompt mentions "opencode" OR you have the `opencode` CLI; DB exists at `~/.local/share/opencode/opencode.db` | [opencode.md](opencode.md) |
|
|
17
|
+
| **Codex (OpenAI)** | System prompt mentions "Codex" or "GPT-5"; sessions in `~/.codex/sessions/` | [codex.md](codex.md) |
|
|
18
|
+
|
|
19
|
+
**Detection priority:**
|
|
20
|
+
1. Check your system prompt / identity (e.g. "You are Codex" vs "You are opencode").
|
|
21
|
+
2. If ambiguous, check which session store exists on disk.
|
|
22
|
+
|
|
23
|
+
Once detected, read the corresponding file:
|
|
24
|
+
|
|
25
|
+
- For **OpenCode**: open `opencode.md` in the same directory as this file.
|
|
26
|
+
- For **Codex**: open `codex.md` in the same directory as this file.
|
|
27
|
+
|
|
28
|
+
## Common safety rules (both agents)
|
|
29
|
+
|
|
30
|
+
- **Read-only**: Never modify session data (INSERT, UPDATE, DELETE, file write, etc.).
|
|
31
|
+
- **Limit output**: Always use `LIMIT` or piping (`head`) to avoid flooding context.
|
|
32
|
+
- **Privacy**: Avoid printing API keys, tokens, account emails, or raw error bodies.
|
|
33
|
+
- **WAL/Concurrency**: Both systems support concurrent reads; no need to stop the agent.
|