| 术语 | 定义 |
|------|------|
| Area | JD 顶级分类(00-99) |
| Category | Area 内分类(000-999) |
| ID | Category 内序号(0001-9999) |
| 短 ID | Git 风格的简化 ID(如
| Namespace | 资源逻辑分组,对应目录 |
| Frontmatter | Markdown 文件头部 YAML 元数据 |
| GTD | Getting Things Done 方法论 |
| CORE | Capture, Organize, Review, Execute |
| Sidecar Index | SQLite 索引文件(`.synapse/index.db`) |
| Fuzzy Finder | 模糊搜索功能,支持标题匹配 |
| Command Palette | 命令面板,类似 VS Code
| Refile | 将资源从 Inbox 移动到目标位置(Emacs Org-mode 术语) |
| Link Refactoring | Refile 时自动更新所有引用该资源的链接 |
| Transaction Rollback | 事务回滚,利用 Git 暂存区实现原子性操作 |
| Hybrid Search | 混合搜索,结合全文(Ripgrep)和元数据(SQLite) |
| Application-Layer Tokenization | 应用层分词,写入/搜索前用 jieba 预处理 |
| Stopword Filtering | 停用词过滤,去除标点和无意义字符 |
| Session Persistence | 会话持久化,记录用户上下文状态 |
| Suspension Context | 暂停上下文,Git 操作期间暂停 watchdog 避免自激 |
| watchdog | Python 文件系统监听库 |
| Textual Workers | Textual 框架的异步任务机制(@work 装饰器) |
---
## 附录 B:参考资源
- [Johnny.Decimal](https://johnnydecimal.com/)
- [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)
- [k9s](https://k9scli.io/)
- [GTD](https://gettingthingsdone.com/)
- [GraphRAG](https://github.com/microsoft/graphrag)
- [LiteLLM](https://github.com/BerriAI/litellm)
- [Textual](https://textual.textualize.io/) - Python TUI 框架
- [Ripgrep](https://github.com/BurntSushi/ripgrep) - 高性能搜索工具
- [watchdog](https://github.com/gorakhargosh/watchdog) - Python 文件系统监听
- [jieba](https://github.com/fxsjy/jieba) - 中文分词(FTS5 增强)
|------|------|
| Area | JD 顶级分类(00-99) |
| Category | Area 内分类(000-999) |
| ID | Category 内序号(0001-9999) |
| 短 ID | Git 风格的简化 ID(如
10.1.15 → `10.001.0015`) || Namespace | 资源逻辑分组,对应目录 |
| Frontmatter | Markdown 文件头部 YAML 元数据 |
| GTD | Getting Things Done 方法论 |
| CORE | Capture, Organize, Review, Execute |
| Sidecar Index | SQLite 索引文件(`.synapse/index.db`) |
| Fuzzy Finder | 模糊搜索功能,支持标题匹配 |
| Command Palette | 命令面板,类似 VS Code
Ctrl+P || Refile | 将资源从 Inbox 移动到目标位置(Emacs Org-mode 术语) |
| Link Refactoring | Refile 时自动更新所有引用该资源的链接 |
| Transaction Rollback | 事务回滚,利用 Git 暂存区实现原子性操作 |
| Hybrid Search | 混合搜索,结合全文(Ripgrep)和元数据(SQLite) |
| Application-Layer Tokenization | 应用层分词,写入/搜索前用 jieba 预处理 |
| Stopword Filtering | 停用词过滤,去除标点和无意义字符 |
| Session Persistence | 会话持久化,记录用户上下文状态 |
| Suspension Context | 暂停上下文,Git 操作期间暂停 watchdog 避免自激 |
| watchdog | Python 文件系统监听库 |
| Textual Workers | Textual 框架的异步任务机制(@work 装饰器) |
---
## 附录 B:参考资源
- [Johnny.Decimal](https://johnnydecimal.com/)
- [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)
- [k9s](https://k9scli.io/)
- [GTD](https://gettingthingsdone.com/)
- [GraphRAG](https://github.com/microsoft/graphrag)
- [LiteLLM](https://github.com/BerriAI/litellm)
- [Textual](https://textual.textualize.io/) - Python TUI 框架
- [Ripgrep](https://github.com/BurntSushi/ripgrep) - 高性能搜索工具
- [watchdog](https://github.com/gorakhargosh/watchdog) - Python 文件系统监听
- [jieba](https://github.com/fxsjy/jieba) - 中文分词(FTS5 增强)
| 操作 | 数据源 |
|------|--------|
|
|
|
### 13.5 混合搜索(Hybrid Search)
**场景**:用户想搜 "Project X"(全文)且 "Status=Todo"(元数据)。
**实现逻辑**:
**命令示例**:
**时间筛选参数说明**:
| 参数 | 对应字段 | 说明 |
|------|----------|------|
|
|
|
|
|
|
**示例**:
### 13.6 批量操作与异步机制
针对 10,000+ 文件规模的操作优化:
**SQLite 事务批量写入**:
**Textual 异步 Workers**:
**进度反馈**:
- 操作耗时 > 500ms 时,TUI 底部状态栏显示 Spinner
- 批量操作(如 Refile 多个文件)显示进度条
---
## 14. 成功标准
1. 快速捕获到 Inbox 并高效处理
2. Johnny.Decimal 编号清晰组织(支持短 ID 和模糊匹配)
3. Git 完整审计追踪(Conventional Commits)
4. k9s 风格 TUI(列表/日历/时间线/图谱视图 + 命令面板)
5. CORE 工作流:捕获 → 组织 → 回顾 → 执行
6. 本地 Hook 优先 + GitHub Actions 远程通知
7. 仅 Markdown,仓库精简(`syn media` 处理附件)
8. Namespace 支持项目级配置
9. 10,000 资源列表 < 500ms(SQLite 索引 + 批量事务)
10. 多端同步无痛(自动 rebase + 智能字段合并)
11. Refile 时链接自动更新,永不断裂
12. 中文全文搜索精准(jieba 应用层分词)
13. 会话状态持久化,随时恢复上下文
---
## 15. 边缘情况处理
| 场景 | 处理方案 |
|------|----------|
| title 修改 | 文件名同步更新(包含 title),但链接仅使用 ID,不受影响 |
| Refile 链接断裂 | 自动全局搜索替换旧 ID → 新 ID(见 5.5) |
| 脏工作区 Refile | 拒绝操作,TUI 提供快捷 Commit/Stash 选项(见 5.5) |
| Refile 中途失败 | 前置检查确保工作区干净后,失败可安全回滚(见 5.5) |
| 短 ID 歧义 | CLI 报错列出候选项,TUI 弹窗二选一(见 3.2) |
| 并发编辑 | watchdog 实时监听 + Hash 检测(见 7.6) |
| watchdog 自激 | Git 操作期间暂停监听(SuspensionContext),避免误报(见 7.6) |
| 多端同步 | 启动 `pull --rebase`,退出 `push`,智能字段合并(见 7.4-7.5) |
| 索引损坏 |
| 大文件 |
| 耗时操作 | Textual @work 异步执行,底部显示进度(见 13.6) |
| 中文搜索噪音 | 停用词过滤 + 标点清理,减小索引体积(见 13.2) |
---
## 16. 范围外(初始版本)
**优先级低,预留设计的功能**:
- **§8 媒体管理**:初始版本仅支持外部链接,`syn media` 命令预留
- **§10 知识图谱**:初始版本不实现,预留
- **§11 邮件集成**:初始版本仅支持手动创建,API 集成预留
**明确排除的功能**:
- 完整 LLM GraphRAG(仅预留接口)
- 实时协作(多人同时编辑)
- Web/移动端
- 邮件 API 自动集成
- 自定义 FTS5 分词器(使用应用层分词替代)
---
## 附录 A:术语表
|------|--------|
|
syn list, syn search (Frontmatter) | SQLite ||
syn search --content (全文) | Ripgrep → 再查 SQLite 补充元数据 ||
syn show, syn edit | 实际 Markdown 文件 |### 13.5 混合搜索(Hybrid Search)
**场景**:用户想搜 "Project X"(全文)且 "Status=Todo"(元数据)。
**实现逻辑**:
1. Ripgrep 搜索全文 → 返回匹配文件路径列表
2. 用路径列表查询 SQLite → 过滤 Status=Todo
3. 返回最终结果(带完整元数据)
**命令示例**:
# 混合搜索:全文包含 "kubernetes" 且状态为 todo
syn search "kubernetes" --status todo
# 混合搜索:全文包含 "设计" 且标签包含 urgent
syn search "设计" --tag urgent
# 纯元数据搜索(due-before 基于 due 字段)
syn search --type task --priority high --due-before 2024-01-15
**时间筛选参数说明**:
| 参数 | 对应字段 | 说明 |
|------|----------|------|
|
--due-before | due | 截止日期早于指定日期的任务 ||
--due-after | due | 截止日期晚于指定日期的任务 ||
--created-before | created | 创建时间早于指定日期 ||
--created-after | created | 创建时间晚于指定日期 ||
--modified-before | modified | 修改时间早于指定日期 ||
--modified-after | modified | 修改时间晚于指定日期 |**示例**:
# 查找本周内到期的任务
syn search --type task --due-after monday --due-before sunday
# 查找过去 7 天修改过的笔记
syn search --type note --modified-after "7 days ago"
### 13.6 批量操作与异步机制
针对 10,000+ 文件规模的操作优化:
**SQLite 事务批量写入**:
# ❌ 错误:单条插入 1000 次 ≈ 5秒
for item in items:
cursor.execute("INSERT INTO resources ...", item)
conn.commit()
# ✅ 正确:事务批量插入 1000 次 ≈ 0.05秒
cursor.execute("BEGIN TRANSACTION")
for item in items:
cursor.execute("INSERT INTO resources ...", item)
cursor.execute("COMMIT")
**Textual 异步 Workers**:
from textual import work
class SynapseApp(App):
@work(exclusive=True)
async def action_batch_update_tags(self, ids: list, add_tag: str):
"""耗时操作放入后台线程,不阻塞 UI"""
self.notify("正在批量更新标签...")
# 执行文件 IO 和 DB 更新
await processor.batch_add_tag(ids, add_tag)
self.notify(f"✓ 已更新 {len(ids)} 个资源")
self.refresh_list()
**进度反馈**:
- 操作耗时 > 500ms 时,TUI 底部状态栏显示 Spinner
- 批量操作(如 Refile 多个文件)显示进度条
---
## 14. 成功标准
1. 快速捕获到 Inbox 并高效处理
2. Johnny.Decimal 编号清晰组织(支持短 ID 和模糊匹配)
3. Git 完整审计追踪(Conventional Commits)
4. k9s 风格 TUI(列表/日历/时间线/图谱视图 + 命令面板)
5. CORE 工作流:捕获 → 组织 → 回顾 → 执行
6. 本地 Hook 优先 + GitHub Actions 远程通知
7. 仅 Markdown,仓库精简(`syn media` 处理附件)
8. Namespace 支持项目级配置
9. 10,000 资源列表 < 500ms(SQLite 索引 + 批量事务)
10. 多端同步无痛(自动 rebase + 智能字段合并)
11. Refile 时链接自动更新,永不断裂
12. 中文全文搜索精准(jieba 应用层分词)
13. 会话状态持久化,随时恢复上下文
---
## 15. 边缘情况处理
| 场景 | 处理方案 |
|------|----------|
| title 修改 | 文件名同步更新(包含 title),但链接仅使用 ID,不受影响 |
| Refile 链接断裂 | 自动全局搜索替换旧 ID → 新 ID(见 5.5) |
| 脏工作区 Refile | 拒绝操作,TUI 提供快捷 Commit/Stash 选项(见 5.5) |
| Refile 中途失败 | 前置检查确保工作区干净后,失败可安全回滚(见 5.5) |
| 短 ID 歧义 | CLI 报错列出候选项,TUI 弹窗二选一(见 3.2) |
| 并发编辑 | watchdog 实时监听 + Hash 检测(见 7.6) |
| watchdog 自激 | Git 操作期间暂停监听(SuspensionContext),避免误报(见 7.6) |
| 多端同步 | 启动 `pull --rebase`,退出 `push`,智能字段合并(见 7.4-7.5) |
| 索引损坏 |
syn index rebuild 重建 || 大文件 |
.gitignore 排除,`syn media` 上传到外部存储 || 耗时操作 | Textual @work 异步执行,底部显示进度(见 13.6) |
| 中文搜索噪音 | 停用词过滤 + 标点清理,减小索引体积(见 13.2) |
---
## 16. 范围外(初始版本)
**优先级低,预留设计的功能**:
- **§8 媒体管理**:初始版本仅支持外部链接,`syn media` 命令预留
- **§10 知识图谱**:初始版本不实现,预留
syn graph 接口- **§11 邮件集成**:初始版本仅支持手动创建,API 集成预留
**明确排除的功能**:
- 完整 LLM GraphRAG(仅预留接口)
- 实时协作(多人同时编辑)
- Web/移动端
- 邮件 API 自动集成
- 自定义 FTS5 分词器(使用应用层分词替代)
---
## 附录 A:术语表
| 协议 | 认证方式 | 说明 |
|------|----------|------|
| Gmail API | OAuth2 | 需要 Google Cloud 项目 |
| IMAP | SSL/TLS | 传统邮箱协议 |
| Microsoft Graph | OAuth2 | Outlook/Office365 |
**凭证配置(预留)**:
---
## 12. 配置
### 12.1 配置文件示例
---
## 13. 性能与索引机制
### 13.1 性能目标
| 操作 | 目标 | 实现方式 |
|------|------|----------|
| 列表 10,000 资源 | < 500ms | SQLite 索引 |
| 全文搜索 | < 1s | Ripgrep |
| 创建/更新 | < 300ms | 增量索引更新 |
### 13.2 SQLite Sidecar Index
**问题**:10,000 个 Markdown 文件逐个解析 Frontmatter,IO 开销巨大。
**方案**:`.synapse/index.db` 缓存所有元数据。
**中文搜索:应用层分词方案**(推荐)
SQLite 原生不支持加载 Python jieba 作为分词器。最佳实践是**应用层分词**:
**停用词过滤的好处**:
- 减小
- 提高搜索精度(避免"的"、"了"等高频词干扰)
- 加快搜索速度
**工作流程**:
- **写入**:"完成了需求设计!" → 清理标点 → jieba → 过滤停用词 → "完成 需求 设计" → 存入 FTS
- **搜索**:用户搜 "需求" → 同样处理 → "需求" → MATCH 成功
### 13.3 索引更新策略
| 触发时机 | 动作 |
|----------|------|
|
| CRUD 操作 | 实时更新索引 |
| Git hook |
| 手动 |
### 13.4 查询路由
|------|----------|------|
| Gmail API | OAuth2 | 需要 Google Cloud 项目 |
| IMAP | SSL/TLS | 传统邮箱协议 |
| Microsoft Graph | OAuth2 | Outlook/Office365 |
**凭证配置(预留)**:
# config.yaml
email:
provider: gmail # gmail | imap | microsoft
gmail:
client_id_env: GMAIL_CLIENT_ID
client_secret_env: GMAIL_CLIENT_SECRET
imap:
server: imap.example.com
port: 993
username_env: IMAP_USERNAME
password_env: IMAP_PASSWORD
---
## 12. 配置
### 12.1 配置文件示例
# ~/.config/synapse/config.yaml
workspace: ~/synapse-data
default_namespace: personal
namespaces:
- personal # 1
- work-project # 2
- study # 3
editor:
windows: { default: notepad, options: [notepad, typora, code] }
linux: { default: vim, options: [vim, typora] }
macos: { default: vim, options: [vim, typora] }
git:
auto_commit: true
commit_style: conventional # conventional | simple | llm
llm:
enabled: false
provider: litellm
model: gpt-4o-mini
api_base: https://api.openai.com/v1
api_key_env: OPENAI_API_KEY
remotes:
- name: origin
url: [email protected]:user/synapse-data.git
auto_push: true
johnny_decimal:
areas:
00: "Inbox"
10: "个人管理"
20: "工作项目"
30: "学习成长"
review:
daily_time: "08:00"
weekly_day: friday
weekly_time: "18:00"
---
## 13. 性能与索引机制
### 13.1 性能目标
| 操作 | 目标 | 实现方式 |
|------|------|----------|
| 列表 10,000 资源 | < 500ms | SQLite 索引 |
| 全文搜索 | < 1s | Ripgrep |
| 创建/更新 | < 300ms | 增量索引更新 |
### 13.2 SQLite Sidecar Index
**问题**:10,000 个 Markdown 文件逐个解析 Frontmatter,IO 开销巨大。
**方案**:`.synapse/index.db` 缓存所有元数据。
-- 主索引表
CREATE TABLE resources (
id TEXT PRIMARY KEY, -- "10.001.0015"
namespace TEXT,
area TEXT, -- "10"
category TEXT, -- "001"
type TEXT,
title TEXT,
status TEXT,
priority TEXT,
due DATE,
created DATETIME,
modified DATETIME,
tags TEXT, -- JSON array
content_hash TEXT, -- 用于变更检测
file_path TEXT
);
-- 全文搜索 (FTS5) - 存储预分词后的内容
CREATE VIRTUAL TABLE resources_fts USING fts5(
id, title_tokens, tags_tokens, content_tokens,
tokenize = 'simple' -- 使用默认分词器,输入已分词字符串
);
**中文搜索:应用层分词方案**(推荐)
SQLite 原生不支持加载 Python jieba 作为分词器。最佳实践是**应用层分词**:
import jieba
import re
# 停用词表(标点、空格、无意义字符)
STOPWORDS = set(['的', '了', '是', '在', '我', '有', '和', '就',
'不', '人', '都', '一', '一个', '上', '也', '很',
'到', '说', '要', '去', '你', '会', '着', '没有'])
class SearchEngine:
def _tokenize(self, text: str) -> str:
"""分词 + 停用词过滤 + 标点清理"""
# 1. 移除标点符号和特殊字符
text = re.sub(r'[^\w\s\u4e00-\u9fff]', ' ', text)
# 2. jieba 分词
tokens = jieba.cut_for_search(text)
# 3. 停用词过滤 + 去除空白
filtered = [t.strip() for t in tokens
if t.strip() and t not in STOPWORDS]
return " ".join(filtered)
def update_index(self, id: str, title: str, content: str):
"""写入索引前,用 jieba 预处理 + 停用词过滤"""
title_tokens = self._tokenize(title)
content_tokens = self._tokenize(content)
cursor.execute("""
INSERT INTO resources_fts (id, title_tokens, content_tokens)
VALUES (?, ?, ?)
""", (id, title_tokens, content_tokens))
def search(self, query: str):
"""搜索时,同样分词处理"""
query_tokens = " AND ".join(self._tokenize(query).split())
cursor.execute("""
SELECT id FROM resources_fts
WHERE content_tokens MATCH ?
""", (query_tokens,))
**停用词过滤的好处**:
- 减小
index.db 体积(去除 30%+ 无意义词)- 提高搜索精度(避免"的"、"了"等高频词干扰)
- 加快搜索速度
**工作流程**:
- **写入**:"完成了需求设计!" → 清理标点 → jieba → 过滤停用词 → "完成 需求 设计" → 存入 FTS
- **搜索**:用户搜 "需求" → 同样处理 → "需求" → MATCH 成功
### 13.3 索引更新策略
| 触发时机 | 动作 |
|----------|------|
|
syn 启动 | 检测 Git 变更,增量更新索引 || CRUD 操作 | 实时更新索引 |
| Git hook |
post-merge, post-checkout 触发重建 || 手动 |
syn index rebuild 强制重建 |### 13.4 查询路由
# config.yaml
media:
provider: s3 # s3 | github | local
# 凭证配置
credentials:
# 方式 1:环境变量(推荐)
aws_access_key_env: AWS_ACCESS_KEY_ID
aws_secret_key_env: AWS_SECRET_ACCESS_KEY
# 方式 2:配置文件(不推荐,敏感信息)
# aws_access_key: "AKIA..."
# aws_secret_key: "..."
s3:
bucket: your-bucket
region: us-east-1
prefix: synapse/ # 存储前缀
# 最终路径:s3://your-bucket/synapse/{resource_id}/{filename}
github:
repo: user/media
branch: main
token_env: GITHUB_TOKEN # GitHub Personal Access Token
local:
path: ~/synapse-media # 本地存储路径(.gitignore 隔离)
base_url: file://~/synapse-media
### 8.5 TUI 集成(预留)
在编辑模式下:
-
Ctrl+V`:检测剪贴板图片 → 自动调用 `syn media paste → 插入链接---
## 9. 自动化工作流
### 9.1 本地自动化(优先)
对于生成类任务,优先使用**本地 Hook**,无需等待网络:
# 本地执行,立即生成并打开
syn review daily # → 生成今日回顾,直接打开编辑
syn review weekly # → 生成周报,直接打开编辑
syn review monthly # → 生成月报,直接打开编辑
syn standup # → 生成站会报告
# LLM 辅助生成(可选)
syn review daily --llm # → 使用 LLM 生成摘要
syn review weekly --llm # → 使用 LLM 生成周报
syn review monthly --llm # → 使用 LLM 生成月报
#### 9.1.1 Review 资源类型与存储
Review 生成的资源是 note 类型,存储在配置的 review Area/Category 下:
personal/
└── 90/ # Area 90: 回顾与复盘
├── 001/ # Category 001: 每日回顾
│ ├── 90.001.0001-note-2024-01-15-daily-review.md
│ └── 90.001.0002-note-2024-01-16-daily-review.md
├── 002/ # Category 002: 每周回顾
│ └── 90.002.0001-note-2024-W03-weekly-review.md
├── 003/ # Category 003: 每月回顾
│ └── 90.003.0001-note-2024-01-monthly-review.md
└── 004/ # Category 004: 站会报告
└── 90.004.0001-note-2024-01-15-standup.md
**Frontmatter 示例**:
---
jd_number: "90.001.0015"
type: note
namespace: personal
title: "2024-01-15 每日回顾"
tags: [review, daily]
created: 2024-01-15T18:00:00Z
modified: 2024-01-15T18:30:00Z
review_type: daily # daily | weekly | monthly | standup
review_period: "2024-01-15"
llm_generated: false # 是否使用 LLM 生成
---
**本地 Hook 配置**:
# config.yaml
hooks:
review_daily:
command: "python ~/.synapse/hooks/daily_review.py"
auto_open: true # 生成后自动打开编辑器
review_weekly:
command: "python ~/.synapse/hooks/weekly_review.py"
auto_open: true
review_monthly:
command: "python ~/.synapse/hooks/monthly_review.py"
auto_open: true
standup:
command: "python ~/.synapse/hooks/standup.py"
auto_open: true
review:
area: "90" # Review 存储的 Area
daily_category: "001" # syn review daily
weekly_category: "002" # syn review weekly
monthly_category: "003" # syn review monthly
standup_category: "004" # syn standup
llm:
enabled: true
prompt_template: "~/.synapse/prompts/review.md"
### 9.2 GitHub Actions 模板(远程)
用于**跨设备通知**和**长期归档**:
| 模板 | 触发 | 功能 |
|------|------|------|
| daily-standup | 工作日 9:00 | 昨日完成、今日计划、阻塞问题 |
| weekly-review | 周五 18:00 | 周报生成 |
| due-reminder | 每天 8:00 | 到期/逾期提醒 |
| inbox-reminder | 工作日 17:00 | Inbox 清理提醒 |
| monthly-retro | 每月 1 日 | 月度复盘归档 |
| graph-sync | push 触发 | 图谱同步 |
**设计理念**:
- **本地 Hook**:生成类(review, standup)→ 即时响应,无网络依赖
- **GitHub Actions**:通知类、归档类 → 跨设备、定时触发
---
## 10. 知识图谱(优先级低,预留设计)
> ⚠️ 本章节为预留设计,待后续迭代完善。初始版本不实现图谱功能。
### 10.1 预留接口
syn graph # 启动图谱视图(TUI)
syn graph export # 导出图谱数据
syn graph sync # 同步到 Nebula Graph(如配置)
### 10.2 数据模型(预留)
**节点类型**:Resource, Namespace, Tag, Person, TimePoint, Chunk
**边类型**:RELATED_TO, BELONGS_TO, CREATED_BY, ASSIGNED_TO, TAGGED_WITH, BLOCKED_BY 等
### 10.3 GraphRAG 集成(预留)
- 使用 Nebula Graph 存储知识图谱
- 支持 LLM 驱动的图谱查询和推理
- 自动发现资源间的隐含关系
---
## 11. 邮件集成(优先级低,预留设计)
> ⚠️ 本章节为预留设计,待后续迭代完善。初始版本仅支持手动创建邮件资源。
### 11.1 手动创建(初始版本支持)
syn new email --subject "项目进度汇报"
- 支持剪贴板粘贴邮件内容
- 自动解析标题和正文
- 发件人/收件人需手动填写
### 11.2 API 集成(预留)
**字段级合并策略配置**:
**冲突安全网**:
- 当 Merge Driver 无法自动解决(如正文同一行被修改):
- 生成
- TUI 启动时检测到冲突文件 → 进入"冲突解决向导"模式
- 用户可选择:保留本地 / 保留远程 / 手动合并
### 7.6 并发编辑检测
**场景**:TUI 打开时,用户用 VS Code 编辑同一文件。
**方案 1:Hash 检测**(基础)
1.
2. 外部编辑器关闭后:检查 hash
3. 如果 hash 变化且非当前进程修改:
- 提示冲突
- 显示 diff
- 用户选择:覆盖 / 合并 / 放弃
**方案 2:watchdog 实时监听**(增强)
使用
**线程安全注意**:
-
- Textual UI 更新必须在主线程
- 必须使用
**自激抑制(Suspension Context)**:
⚠️ **问题**:当 Synapse 执行
**行为**:
- TUI 打开时,自动启动 watchdog **仅监听当前 Namespace 目录**(性能优化)
- 切换 Namespace 时,watchdog 同步切换监听目标
- 检测到当前查看/编辑的文件被外部修改 → 实时弹出警告
- 用户可选择:重新加载 / 忽略 / 查看 diff
- **Git 操作期间自动暂停监听**,避免误报
---
## 8. 媒体管理(优先级低,预留设计)
> ⚠️ 本章节为预留设计,待后续迭代完善。初始版本仅支持外部链接引用媒体。
### 8.1 设计原则
- **仓库纯净**:禁止二进制文件直接入库
- **体验友好**:提供便捷的截图/贴图工作流
### 8.2
### 8.3 媒体存储目录结构
**建议使用资源 ID 作为目录名**,便于关联和管理:
### 8.4 媒体存储配置
# config.yaml
git:
merge_strategy:
# 默认策略:取 modified 最新的一方 (Last Write Wins)
default: "take_latest_modified"
# 特殊字段策略
fields:
# 标签:取并集。A端加了[urgent], B端加了[work] -> [urgent, work]
tags: "union"
# 关联:取并集
related: "union"
# 状态:取最新修改方(或自定义优先级:done > in-progress > todo)
status: "take_latest_modified"
# 正文内容:标准 Git 文本合并
content: "git_standard"
**冲突安全网**:
- 当 Merge Driver 无法自动解决(如正文同一行被修改):
- 生成
.conflict 备份文件- TUI 启动时检测到冲突文件 → 进入"冲突解决向导"模式
- 用户可选择:保留本地 / 保留远程 / 手动合并
### 7.6 并发编辑检测
**场景**:TUI 打开时,用户用 VS Code 编辑同一文件。
**方案 1:Hash 检测**(基础)
1.
syn edit 前:记录文件 hash2. 外部编辑器关闭后:检查 hash
3. 如果 hash 变化且非当前进程修改:
- 提示冲突
- 显示 diff
- 用户选择:覆盖 / 合并 / 放弃
**方案 2:watchdog 实时监听**(增强)
使用
watchdog 库监听文件系统事件,TUI 运行时实时感知外部修改:
# 伪代码示意 - 注意线程安全!
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
class SynapseFileWatcher(FileSystemEventHandler):
def __init__(self, app):
self.app = app # Textual App 实例
def on_modified(self, event):
if event.src_path == self.app.current_open_file:
# ⚠️ 关键:watchdog 在独立线程,必须用 call_from_thread
self.app.call_from_thread(
self.app.show_file_modified_warning,
event.src_path
)
**线程安全注意**:
-
watchdog 运行在独立线程- Textual UI 更新必须在主线程
- 必须使用
app.call_from_thread() 跨线程调用,否则 TUI 会崩溃**自激抑制(Suspension Context)**:
⚠️ **问题**:当 Synapse 执行
git pull 或 git checkout 时,文件系统变化会触发 watchdog,错误地向用户报告"外部修改警告"。
class FileWatcher:
def __init__(self):
self._suspended = False
def pause(self):
"""暂停监听(Git 操作前调用)"""
self._suspended = True
def resume(self):
"""恢复监听(Git 操作后调用)"""
self._suspended = False
def on_modified(self, event):
if self._suspended:
return # 忽略自身触发的变更
# ... 正常处理外部修改
class SynapseApp:
def perform_git_operation(self):
self.file_watcher.pause() # 暂停监听
try:
git.pull()
self.index.refresh() # 主动刷新索引
finally:
self.file_watcher.resume() # 恢复监听
**行为**:
- TUI 打开时,自动启动 watchdog **仅监听当前 Namespace 目录**(性能优化)
- 切换 Namespace 时,watchdog 同步切换监听目标
- 检测到当前查看/编辑的文件被外部修改 → 实时弹出警告
- 用户可选择:重新加载 / 忽略 / 查看 diff
- **Git 操作期间自动暂停监听**,避免误报
class SynapseFileWatcher:
def __init__(self, app):
self.app = app
self.observer = Observer()
self._current_path = None
self._started = False
def start(self):
"""启动观察者线程(TUI 启动时调用)"""
if not self._started:
self.observer.start()
self._started = True
def stop(self):
"""停止观察者线程(TUI 退出时调用)"""
if self._started:
self.observer.stop()
self.observer.join() # 等待线程结束
self._started = False
def watch_namespace(self, namespace_path: str):
"""切换监听目标到指定 Namespace"""
# 1. 取消之前的监听
if self._current_path:
self.observer.unschedule_all()
# 2. 调度新的监听目标
self._current_path = namespace_path
self.observer.schedule(
self,
namespace_path,
recursive=True # 监听 Namespace 下所有子目录
)
# 3. 确保观察者已启动
self.start()
---
## 8. 媒体管理(优先级低,预留设计)
> ⚠️ 本章节为预留设计,待后续迭代完善。初始版本仅支持外部链接引用媒体。
### 8.1 设计原则
- **仓库纯净**:禁止二进制文件直接入库
- **体验友好**:提供便捷的截图/贴图工作流
### 8.2
syn media 命令
# 从剪贴板上传图片
syn media paste
# → 自动上传到配置的存储 → 返回 Markdown 链接
# 上传指定文件
syn media upload /path/to/image.png
# 输出示例

### 8.3 媒体存储目录结构
**建议使用资源 ID 作为目录名**,便于关联和管理:
媒体存储根目录/
├── 10.001.0015/ # 资源 ID 为目录名
│ ├── screenshot-001.png
│ └── diagram.svg
├── 10.002.0003/
│ └── meeting-photo.jpg
└── _orphan/ # 未关联资源的媒体(待清理)
└── temp-upload.png
### 8.4 媒体存储配置
**TUI 交互**:
**行为**:
- Refile 前**必须检查**工作区状态
- 脏工作区时拒绝操作,提示用户先提交/暂存
- TUI 提供快捷操作:一键 Commit WIP 或 Stash
- 绝不丢失用户的其他修改
**更新的引用类型**:
| 引用形式 | 示例 | 搜索方式 | 更新方式 |
|----------|------|----------|----------|
| Wiki-style 链接 |
| Frontmatter related |
设计原则:精确引用更新,避免误改
⚠️ **不进行盲目的全文替换**:只更新明确的引用语法,不替换正文中的裸 ID 字符串。
为什么不替换裸 ID?
- 裸 ID 可能出现在非引用上下文:`"历史记录显示 10.001.0001 已于 2023 年完成"`
- 格式说明文本:`"ID 格式为 10.001.0001,其中 10 表示 Area..."`
- 盲目替换会导致语义错误和数据损坏
- 用户若需更新裸 ID,可通过
为什么 related 字段仍需 SQLite?
**SQLite 方案确保**:
- 查询精确定位到
- 解析 JSON 数组后,只替换匹配的元素
- 重新序列化,保证 YAML 格式正确
**Refile 预览模式**:
为避免意外修改,支持
> **注意**:预览中的 "Skipped" 部分提示用户哪些裸 ID 不会被自动更新,用户可根据需要手动处理。
---
## 6. 工作流与回顾
### 6.1 回顾类型
| 类型 | 触发 | 内容 |
|------|------|------|
| 每日 |
| 每周 |
| Inbox |
### 6.2 智能提醒
- 任务接近截止日期时高亮显示
- 资源长期未访问时在回顾中提示
- 阻塞任务链识别和提示
---
## 7. 存储与版本控制
### 7.1 Markdown 格式
**文件命名**:`{Area}.{Category}-{resource-type}-{title}.md`
**Frontmatter 示例**:
### 7.2 文件约束
- 仅允许
- 禁止 图片、视频、音频等二进制文件
- 必须 使用外部链接引用媒体资源
-
### 7.3 Git 集成
- 自动提交:所有 CRUD 操作
- commit 格式:Conventional Commits
- 支持多远程仓库
- 支持 SSH/HTTPS 认证
### 7.4 Git 同步策略
| 时机 | 动作 |
|------|------|
|
| CRUD 操作 |
|
### 7.5 智能冲突合并
**问题**:多端同步时,`modified` 时间戳经常冲突。
**方案**:自定义 Git merge driver + 细粒度字段策略
┌─────────────────────────────────────────────────────────┐
│ ⚠️ Refile 需要干净的工作区 │
├─────────────────────────────────────────────────────────┤
│ 检测到以下未提交的修改: │
│ M 10/001/10.001.0005-note-学习笔记.md │
│ M 20/001/20.001.0003-task-开发任务.md │
│ │
│ 请先提交或暂存这些修改: │
│ [C] 快速提交 (commit -m 'WIP') │
│ [S] 暂存 (git stash) │
│ [Q] 取消 Refile │
└─────────────────────────────────────────────────────────┘
**行为**:
- Refile 前**必须检查**工作区状态
- 脏工作区时拒绝操作,提示用户先提交/暂存
- TUI 提供快捷操作:一键 Commit WIP 或 Stash
- 绝不丢失用户的其他修改
**更新的引用类型**:
| 引用形式 | 示例 | 搜索方式 | 更新方式 |
|----------|------|----------|----------|
| Wiki-style 链接 |
[[10.001.0001]] | Ripgrep | 字符串替换 || Frontmatter related |
related: ["10.001.0001"] | SQLite 索引 | 解析 YAML,更新数组 |设计原则:精确引用更新,避免误改
⚠️ **不进行盲目的全文替换**:只更新明确的引用语法,不替换正文中的裸 ID 字符串。
---
related: ["10.001.0001"] # ← YAML 数组,精确更新 ✓
---
# 设计说明
参考 [[10.001.0001]] 的架构思路... # ← Wiki-style 链接,更新 ✓
任务 10.001.0001 定义了核心接口... # ← 裸 ID,不更新 ✗(可能是历史描述)
为什么不替换裸 ID?
- 裸 ID 可能出现在非引用上下文:`"历史记录显示 10.001.0001 已于 2023 年完成"`
- 格式说明文本:`"ID 格式为 10.001.0001,其中 10 表示 Area..."`
- 盲目替换会导致语义错误和数据损坏
- 用户若需更新裸 ID,可通过
--dry-run 预览后手动处理为什么 related 字段仍需 SQLite?
related 是 YAML 数组格式,直接全文替换可能破坏 YAML 结构:
# 原始
related: ["10.001.0001", "10.002.0003"]
# Ripgrep 替换后可能出现的问题(如果替换逻辑不够精确)
related: ["20.001.0005", "10.002.0003"] # ✓ 正确
related: ["20.001.0005", "20.001.0005"] # ✗ 如果 10.002.0003 也被误改
**SQLite 方案确保**:
- 查询精确定位到
related 字段- 解析 JSON 数组后,只替换匹配的元素
- 重新序列化,保证 YAML 格式正确
**Refile 预览模式**:
为避免意外修改,支持
--dry-run 预览变更:
syn inbox move 00.000.0001 --to work-project --dry-run
# 输出预览:
Will refile: 00.000.0001 → 20.001.0003
Source file:
R inbox/00.000.0001-unprocessed-xxx.md → work-project/20/001/20.001.0003-task-xxx.md
- Frontmatter: jd_number: "00.000.0001" → "20.001.0003"
References to update (2 files):
M personal/10/001/10.001.0005-note-设计笔记.md
- Line 5: related: ["00.000.0001"] → ["20.001.0003"]
- Line 12: [[00.000.0001]] → [[20.001.0003]]
M personal/10/002/10.002.0001-task-开发任务.md
- Line 15: [[00.000.0001]] → [[20.001.0003]]
Skipped (bare IDs not updated):
- personal/10/003/10.003.0001-note-历史记录.md
- Line 8: "任务 00.000.0001 已于 2023 年完成"(裸 ID,需手动处理)
Proceed? [y/N]
> **注意**:预览中的 "Skipped" 部分提示用户哪些裸 ID 不会被自动更新,用户可根据需要手动处理。
---
## 6. 工作流与回顾
### 6.1 回顾类型
| 类型 | 触发 | 内容 |
|------|------|------|
| 每日 |
syn review daily | 今日到期、今日会议、昨日未完成 || 每周 |
syn review weekly | 本周完成、下周计划、项目进度 || Inbox |
syn inbox process | 处理未分类项目 |### 6.2 智能提醒
- 任务接近截止日期时高亮显示
- 资源长期未访问时在回顾中提示
- 阻塞任务链识别和提示
---
## 7. 存储与版本控制
### 7.1 Markdown 格式
**文件命名**:`{Area}.{Category}-{resource-type}-{title}.md`
**Frontmatter 示例**:
---
jd_number: "10.001.0015"
type: task
namespace: work-project
title: "完成项目设计"
status: in-progress
priority: high
due: 2024-01-15
created: 2024-01-01T10:00:00Z
modified: 2024-01-05T14:30:00Z
tags: [design, urgent]
related: ["10.001.0012", "10.002.0003"]
---
### 7.2 文件约束
- 仅允许
.md 文件- 禁止 图片、视频、音频等二进制文件
- 必须 使用外部链接引用媒体资源
-
.gitignore 配置忽略常见二进制格式### 7.3 Git 集成
- 自动提交:所有 CRUD 操作
- commit 格式:Conventional Commits
- 支持多远程仓库
- 支持 SSH/HTTPS 认证
### 7.4 Git 同步策略
| 时机 | 动作 |
|------|------|
|
syn 启动 | git pull --rebase || CRUD 操作 |
git add + git commit ||
syn 退出 / syn sync | git push |### 7.5 智能冲突合并
**问题**:多端同步时,`modified` 时间戳经常冲突。
**方案**:自定义 Git merge driver + 细粒度字段策略
# .gitattributes
*.md merge=synapse-frontmatter
# .git/config 或全局配置
[merge "synapse-frontmatter"]
name = Synapse Frontmatter Merge
driver = syn merge-driver %O %A %B %Pdef refile_with_link_update(old_id, new_id, old_path, new_path, workspace):
# 0. 前置检查:工作区必须干净
if not is_working_tree_clean():
raise RefileError(
"Refile requires a clean working tree.\n"
"Please commit or stash your changes first:\n"
" syn commit -m 'WIP' 或 git stash"
)
try:
# 1. 移动源文件(暂存)
git_mv(old_path, new_path)
# 1b. 更新源文件的 Frontmatter(jd_number 字段)
source_content = read_file(new_path) # 文件已移动,从新路径读取
source_fm, source_body = parse_frontmatter(source_content)
source_fm['jd_number'] = new_id # 更新 ID
source_fm['modified'] = datetime.now().isoformat() # 更新修改时间
write_file(new_path, serialize_frontmatter(source_fm) + source_body)
git_add(new_path) # ⚠️ 必须暂存源文件的内容修改(git_mv 只暂存重命名)
# 2. 查找并更新所有引用(其他文件)
# ⚠️ 顺序重要:先 YAML 精确处理,再全文替换,避免竞态
modified_files = set()
files_with_related = set() # 记录有 related 字段的文件
# 2a. 先处理 Frontmatter 中的 related 字段(YAML 精确解析)
# 必须先于全文替换,否则 old_id 已被替换,条件判断会失败
related_refs = db_query(
"SELECT file_path FROM resources WHERE related LIKE ?",
(f'%"{old_id}"%',) # 在 JSON 数组字符串中搜索
)
for (file_path,) in related_refs:
content = read_file(file_path)
frontmatter, body = parse_frontmatter(content)
# 安全检查:确保 related 是非空列表
related = frontmatter.get('related')
if isinstance(related, list) and old_id in related:
# 精确更新 YAML 数组
frontmatter['related'] = [
new_id if rid == old_id else rid
for rid in related
]
# 只替换 wiki-style 链接(避免误改非引用上下文)
body = body.replace(f"[[{old_id}]]", f"[[{new_id}]]")
content = serialize_frontmatter(frontmatter) + body
write_file(file_path, content)
modified_files.add(file_path)
files_with_related.add(file_path)
# 2b. 搜索 wiki-style 链接:[[old_id]]
# ⚠️ 只更新明确的引用语法,不盲目替换正文中的 ID 字符串
wiki_refs = rg_search(f"\\[\\[{old_id}\\]\\]", workspace)
for file_path in wiki_refs:
if file_path in files_with_related:
continue # 已被 2a 处理,跳过
content = read_file(file_path)
content = content.replace(f"[[{old_id}]]", f"[[{new_id}]]")
write_file(file_path, content)
modified_files.add(file_path)
# 3. 暂存所有修改
for f in modified_files:
git_add(f)
# 4. 提交事务(+1 是源文件本身)
git_commit(f"refactor: refile {old_id} → {new_id}, update {len(modified_files) + 1} files")
except Exception as e:
# 4. 安全回滚(因为工作区干净,此时可以安全 reset)
git_reset_hard()
logger.error(f"Refile failed, rolled back: {e}")
raise RefileError("操作失败,已回滚所有修改")
def is_working_tree_clean() -> bool:
"""检查工作区是否干净"""
result = subprocess.run(
["git", "status", "--porcelain"],
capture_output=True, text=True
)
return len(result.stdout.strip()) == 0
策略 B:智能回滚(复杂场景)
如果必须允许脏工作区 Refile,回滚时需精确还原:
def smart_rollback(modified_files: list, old_path: str, new_path: str):
"""精确回滚,不影响其他未提交修改"""
# 1. Unstage 暂存的文件
for f in modified_files:
subprocess.run(["git", "reset", "HEAD", f])
# 2. 还原被修改的文件内容
for f in modified_files:
subprocess.run(["git", "checkout", "--", f])
# 3. 移回源文件
if os.path.exists(new_path):
subprocess.run(["git", "mv", new_path, old_path])┌─────────────────────────────────────────────┐
│ Refile: 00.000.0001 - 快速记录 │
├─────────────────────────────────────────────┤
│ [1] personal │
│ [2] work-project │
│ [3] study │
│ [q] Cancel │
└─────────────────────────────────────────────┘
↓ 按 2
┌─────────────────────────────────────────────┐
│ Refile to: work-project │
├─────────────────────────────────────────────┤
│ [20] 项目管理 │
│ [21] 开发 │
│ [22] 设计 │
│ [+] 新建 Area │
│ [q] Back │
└─────────────────────────────────────────────┘
↓ 按 20
┌─────────────────────────────────────────────┐
│ Refile to: work-project/20 │
├─────────────────────────────────────────────┤
│ [001] 任务 │
│ [002] 会议 │
│ [+] 新建 Category │
│ [q] Back │
└─────────────────────────────────────────────┘
↓ 按 001
✓ Moved to: work-project/20/001/20.001.0003-task-快速记录.md
**关键设计**:
- 用户只需选"要去哪个区",**不需要手动输入 ID**
- 系统自动分配下一个可用 ID
- 支持快捷键直接跳转(数字键选择)
- 支持
/ 搜索过滤 Namespace/Area/Category### 5.5 引用自动更新(Link Refactoring)
**问题**:Refile 导致 ID 变化时,其他文件中的引用会断裂。
场景:
1. Inbox 中有 00.000.0001(想法A)
2. 笔记 10.002.0005 中写道:"参考 [[00.000.0001]]"
3. Refile 后,A 变为 20.001.0003
4. 结果:[[00.000.0001]] 成为 Dead Link
解决方案:自动重构所有引用
当执行
syn inbox move 且 ID 发生变化时,更新**两种引用形式**:
1. 搜索旧 ID 的引用(使用不同策略):
- Wiki-style 链接:Ripgrep 搜索 [[00.000.0001]]
- Frontmatter related:SQLite 索引查询(精确匹配,避免误改)
2. 自动替换为新 ID
3. 将所有修改一并加入 Git Commit
**实现逻辑(带安全回滚)**:
⚠️ **原子性保证**:Refile 涉及跨多文件修改,必须保证原子性。
⚠️ **安全警告**:绝对不能使用 `git reset --hard`!它会清空**所有**未提交的修改,包括与 Refile 无关的用户编辑。
策略 A:前置检查(推荐)
在开始 Refile 前,检查工作区是否干净:
## 5. Inbox 处理与最佳实践
### 5.1 Inbox 概念
- Inbox 是特殊 namespace(`_inbox`),Area 固定为
- 快速捕获的内容默认进入 Inbox,状态为
- Inbox 中的资源无需完整,支持最小化输入
### 5.2 处理操作
| 操作 | 说明 | 命令 |
|------|------|------|
| 归类 (Refile) | 移动到目标 namespace,分配 Area.Category |
| 转换 | 转换资源类型(如 note → task) |
| 归档 | 原地标记 status=`archived`,不移动文件 |
| 删除 | 永久删除(Git 可恢复) |
**归档说明**:
- 归档操作**不移动文件**,仅修改 Frontmatter 中的
- 归档后的资源在列表中默认隐藏,可通过
- 如需移动到特定归档目录,应使用
- **`unprocessed` 类型特殊处理**:由于
### 5.3 Inbox 处理最佳实践(GTD 风格)
处理流程决策树:
最佳实践规则:
1. **2 分钟规则**:如果一件事 2 分钟内能完成,立即做,不要放入任务列表
2. **每日清空**:每天至少处理一次 Inbox,目标是 Inbox Zero
3. **快速决策**:每个项目只处理一次,立即决定其去向
4. **最小化输入**:捕获时只记录关键信息,处理时再补充细节
处理快捷流程:
TUI Inbox 处理快捷键:
| 快捷键 | 操作 | 说明 |
|--------|------|------|
|
|
|
|
|
|
### 5.4 Refile 交互优化(类似 Emacs Org-mode)
### 5.1 Inbox 概念
- Inbox 是特殊 namespace(`_inbox`),Area 固定为
00- 快速捕获的内容默认进入 Inbox,状态为
unprocessed- Inbox 中的资源无需完整,支持最小化输入
### 5.2 处理操作
| 操作 | 说明 | 命令 |
|------|------|------|
| 归类 (Refile) | 移动到目标 namespace,分配 Area.Category |
syn inbox move <id> --to <ns> --type <type> || 转换 | 转换资源类型(如 note → task) |
syn inbox convert <id> --type task || 归档 | 原地标记 status=`archived`,不移动文件 |
syn inbox archive <id> || 删除 | 永久删除(Git 可恢复) |
syn inbox delete <id> |**归档说明**:
- 归档操作**不移动文件**,仅修改 Frontmatter 中的
status 字段为 archived- 归档后的资源在列表中默认隐藏,可通过
--include-archived 显示- 如需移动到特定归档目录,应使用
syn inbox move --to archive-namespace- **`unprocessed` 类型特殊处理**:由于
unprocessed 状态不可变,归档时自动转换为 note 类型并标记 status=archived
syn inbox archive 00.000.0001
# unprocessed → note (status=archived)
# 文件重命名:00.000.0001-unprocessed-xxx.md → 00.000.0001-note-xxx.md
### 5.3 Inbox 处理最佳实践(GTD 风格)
处理流程决策树:
┌─────────────┐
│ Inbox 项目 │
└──────┬──────┘
│
┌──────▼──────┐
│ 这是什么? │
│ 需要行动吗? │
└──────┬──────┘
│
┌────────────┼────────────┐
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│ 不需要 │ │ 需要行动 │ │ 参考资料 │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
┌────▼────┐ │ ┌────▼────┐
│ 删除 │ │ │ 归类为 │
│ 或归档 │ │ │ note │
└─────────┘ │ └─────────┘
│
┌────────────┼────────────┐
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│ < 2分钟 │ │ 委派他人 │ │ 需要规划 │
│ 立即做! │ │ │ │ │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│ 完成后 │ │ 创建任务 │ │ 创建任务 │
│ 归档/删除│ │ 分配给 │ │ 设置 │
└─────────┘ │ 他人 │ │ 截止日期 │
└─────────┘ └─────────┘
最佳实践规则:
1. **2 分钟规则**:如果一件事 2 分钟内能完成,立即做,不要放入任务列表
2. **每日清空**:每天至少处理一次 Inbox,目标是 Inbox Zero
3. **快速决策**:每个项目只处理一次,立即决定其去向
4. **最小化输入**:捕获时只记录关键信息,处理时再补充细节
处理快捷流程:
# 批量处理 Inbox
syn inbox process
# 交互式处理(逐项显示,提供操作选项)
# [m]ove | [c]onvert | [a]rchive | [d]elete | [s]kip
# 快速转换为任务
syn inbox convert <id> --type task --due tomorrow --priority high
# 快速归类
syn inbox move <id> --to work-project --type meeting
TUI Inbox 处理快捷键:
| 快捷键 | 操作 | 说明 |
|--------|------|------|
|
Enter | 查看详情 | 与全局快捷键一致 ||
e | 编辑后处理 | 打开编辑器,关闭后弹出处理选项 ||
m | 移动(Refile) | 层级菜单选择目标位置 ||
t | 快速转换为 task | 一键转换,保留原位置 ||
a | 归档 | 标记 status=archived ||
d | 删除 | 永久删除(Git 可恢复) |### 5.4 Refile 交互优化(类似 Emacs Org-mode)
m (move) 是最高频操作,TUI 实现层级菜单式 Refile:┌─────────────────────────────────────────────┐
│ @work-project/20 │ ← 范围搜索
├─────────────────────────────────────────────┤
│ 显示 work-project namespace Area 20 资源 │
└─────────────────────────────────────────────┘
Calendar - Week (2024-W03) [personal]
┌────────┬────────┬────────┬────────┬────────┬────────┬────────┐
│ Mon 15 │ Tue 16 │ Wed 17 │ Thu 18 │ Fri 19 │ Sat 20 │ Sun 21 │
├────────┼────────┼────────┼────────┼────────┼────────┼────────┤
│ ▓▓▓▓ │ ██ │ ▓▓▓▓▓▓ │ ████ │ ██ │ │ │
│ ████ │ │ ▓▓▓▓ │ ▓▓ │ │ │ │
├────────┴────────┴────────┴────────┴────────┴────────┴────────┤
│ ▶ [Wed 14:00] 项目评审会议 (meeting) - 14:00~16:00 │
│ Attendees: @alice, @bob │
└──────────────────────────────────────────────────────────────┘
[↑↓] Select [←→] Navigate [Enter] Details [w/m] Week/Month [q] Back
图例:▓▓ = meeting (紫色) ██ = task (蓝色) ░░ = note (灰色)
Timeline - Last 7 Days [personal]
─────┬──────┬──────┬──────┬──────┬──────┬──────┬─────────
│ ▓▓ │ ████ │ ██ │ ████ │ ▓▓ │██████│ ██
│ ████ │ ▓▓ │ ████ │ ██ │ ████ │ ▓▓▓▓ │ ████
─────┴──────┴──────┴──────┴──────┴──────┴──────┴─────────
Mon Tue Wed Thu Fri Sat Sun
▶ [Sun 14:32] feat(task): add new task for review
→ 10.001.0015-task-完成项目设计.md
──────────────────────────────────────────────────────────
[↑↓] Select [←→] Navigate [Enter] Resource [d/w/m/y] Scale [q] Back
图例:▓▓ = meeting ██ = task ░░ = note (颜色同日历视图)
**行为**:
- 启动
-
- 每个 Namespace 独立记录筛选状态和最近文件
---
│ @work-project/20 │ ← 范围搜索
├─────────────────────────────────────────────┤
│ 显示 work-project namespace Area 20 资源 │
└─────────────────────────────────────────────┘
### 4.5 上下文感知交互
| 视图 | `Enter` | `Space` | `e` |
|------|---------|---------|-----|
| Task 列表 | 查看详情 | 切换 status: `todo` → `in-progress` → `done` | 编辑 |
| Meeting 列表 | 查看详情 | 切换 status: `scheduled` ↔ `completed` | 编辑 |
| Email 列表 | 查看详情 | 切换 status: `unread` → `read` → `replied` | 编辑 |
| Note 列表 | 查看详情 | (无活跃状态循环,使用 `a` 键归档) | 编辑 |
| Calendar (日) | 资源详情 | 同上(根据资源类型) | 新建事项 |
| Inbox | 查看详情 | (unprocessed 状态不可切换) | 编辑后处理 |
**Space 状态循环**(仅限活跃状态):
- Task: `todo` → `in-progress` → `done` → `todo`
- Meeting: `scheduled` ↔ `completed`(二元切换)
- Email: `unread` → `read` → `replied` → `unread`
- Note: **无 Space 循环**(仅有 `active`/`archived` 两态,使用 `a` 键切换)
**终态处理**(`archived` / `cancelled`):
- `archived` 和 `cancelled` 是**终态**,不参与 Space 循环
- 当资源处于终态时,Space 键**无响应**(或显示提示"资源已归档/取消")
- 进入/退出终态:使用 `a` 键(归档/取消归档)或编辑 Frontmatter
| 状态 | 类型 | 进入方式 | 退出方式 |
|------|------|----------|----------|
| `archived` | task, email | `a` 键归档 | `a` 键取消归档(恢复到 `todo`/`unread`) |
| `archived` | note | `a` 键归档 | `a` 键取消归档(恢复到 `active`) |
| `cancelled` | meeting | 编辑 status 字段 | 编辑 status 字段 |
**`a` 键行为**:
- 活跃状态 → `archived`(归档)
- `archived` → 恢复到默认活跃状态(task→`todo`, email→`unread`, note→`active`)
### 4.6 编辑器配置
| 平台 | 默认 | 可选 |
|------|------|------|
| Windows | notepad | typora, vscode |
| Linux | vim | typora |
| macOS | vim | typora |
### 4.7 日历视图
**时间来源**:
- task: `due` / `start_date`
- meeting: `datetime` / `duration`
**条带说明**:每个条带代表一个资源,高度表示时间跨度,颜色表示类型/优先级。
**交互**:
- `↑↓` 在同一天的条带间切换选中
- `←→` 在日期间导航
- 选中条带时,底部显示资源摘要
- `Enter` 查看资源详情
Calendar - Week (2024-W03) [personal]
┌────────┬────────┬────────┬────────┬────────┬────────┬────────┐
│ Mon 15 │ Tue 16 │ Wed 17 │ Thu 18 │ Fri 19 │ Sat 20 │ Sun 21 │
├────────┼────────┼────────┼────────┼────────┼────────┼────────┤
│ ▓▓▓▓ │ ██ │ ▓▓▓▓▓▓ │ ████ │ ██ │ │ │
│ ████ │ │ ▓▓▓▓ │ ▓▓ │ │ │ │
├────────┴────────┴────────┴────────┴────────┴────────┴────────┤
│ ▶ [Wed 14:00] 项目评审会议 (meeting) - 14:00~16:00 │
│ Attendees: @alice, @bob │
└──────────────────────────────────────────────────────────────┘
[↑↓] Select [←→] Navigate [Enter] Details [w/m] Week/Month [q] Back
图例:▓▓ = meeting (紫色) ██ = task (蓝色) ░░ = note (灰色)
**跨天显示**:start_date 到 due 的任务、跨天会议,在每天都显示连续条带。
### 4.8 时间线视图
**时间来源**:Git commit 时间戳(资源的 `modified` 时间)
**条带说明**:每列代表一天,条带高度表示当天活动密度,每个条带对应一次 commit。
**交互**:
- `←→` 在时间轴上导航
- `↑↓` 在同一天的 commit 间切换
- 选中 commit 时,底部显示 commit 信息和涉及的资源
- `Enter` 跳转到该资源
Timeline - Last 7 Days [personal]
─────┬──────┬──────┬──────┬──────┬──────┬──────┬─────────
│ ▓▓ │ ████ │ ██ │ ████ │ ▓▓ │██████│ ██
│ ████ │ ▓▓ │ ████ │ ██ │ ████ │ ▓▓▓▓ │ ████
─────┴──────┴──────┴──────┴──────┴──────┴──────┴─────────
Mon Tue Wed Thu Fri Sat Sun
▶ [Sun 14:32] feat(task): add new task for review
→ 10.001.0015-task-完成项目设计.md
──────────────────────────────────────────────────────────
[↑↓] Select [←→] Navigate [Enter] Resource [d/w/m/y] Scale [q] Back
图例:▓▓ = meeting ██ = task ░░ = note (颜色同日历视图)
### 4.9 会话持久化(Session Persistence)
系统在 `.synapse/session.json`(不入 Git)中记录当前上下文状态:
```json
{
"last_active_namespace": "work-project",
"namespaces": {
"personal": {
"last_view": "calendar",
"selected_date": "2024-01-20",
"recent_files": ["10.001.0001", "10.002.0005"]
},
"work-project": {
"last_view": "list",
"filter_state": {"status": "todo", "tag": "urgent"},
"recent_files": ["20.001.0003"]
}
},
"global_history": [
"syn show 10.001.0001",
"syn search kubernetes"
]
}
**行为**:
- 启动
syn 时,自动恢复到上次退出的 Namespace 和 View-
Ctrl+Tab 可在最近打开的两个文件/视图间快速切换- 每个 Namespace 独立记录筛选状态和最近文件
---
workspace/
├── .synapse/ # 系统目录
│ ├── config.yaml # 全局配置
│ ├── index.db # SQLite 索引
│ └── hooks/ # Git hooks
├── personal/ # namespace
│ ├── .synapse.yaml # namespace 配置
│ ├── 10/ # Area 10: 个人管理
│ │ ├── 001/ # Category 001: 任务
│ │ │ ├── 10.001.0001-task-完成报告.md
│ │ │ └── 10.001.0002-task-学习计划.md
│ │ └── 002/ # Category 002: 笔记
│ │ └── 10.002.0001-note-学习笔记.md
│ └── 11/ # Area 11: 会议
│ └── 001/
│ └── 11.001.0001-meeting-周会.md
├── work-project/
│ ├── .synapse.yaml
│ └── 20/
│ └── 001/
│ ├── 20.001.0001-meeting-需求评审.md
│ └── 20.001.0002-task-开发任务.md
└── _inbox/ # 特殊 namespace
└── 00/
└── 000/ # Inbox 固定使用 00.000
├── 00.000.0001-unprocessed-快速记录.md
└── 00.000.0002-unprocessed-临时想法.md
**设计说明**:
- **双层分桶**:Area → Category,避免单目录大量文件
- 每个 Category 目录最多 9999 个文件,人眼可管理
- 查询走 SQLite 索引,目录层级不影响性能
- Area/Category 子目录由系统自动创建
---
## 4. 用户界面
### 4.1 统一命令设计
CLI 和 TUI 使用统一的命令/操作命名:
| 操作 | CLI 命令 | TUI 快捷键 | 说明 |
|------|----------|------------|------|
| 新建 |
syn new [type] | n | 创建新资源 || 列表 |
syn list [type] | l | 列表视图 || 查看 |
syn show <id> | Enter | 查看详情 || 编辑 |
syn edit <id> | e | 编辑资源 || 删除 |
syn delete <id> | d | 删除资源 || 搜索 |
syn search <query> | / | 搜索过滤 || 日历 |
syn calendar | c | 日历视图 || 时间线 |
syn timeline | t | 时间线视图 || 图谱 |
syn graph | g | 图谱视图 |### 4.2 CLI 命令示例
# TUI 启动
syn
# 资源操作
syn new task --title "完成设计" --priority high --due 2024-01-15
syn new note --title "会议记录"
syn list task --status todo
syn show 10.001.0015 # 完整 ID
syn show 10.1.15 # 短 ID(自动补零)
syn show 15 # 最短 ID(当前 Namespace 内唯一)
syn edit 10.001.0015
syn delete 10.001.0015
syn search "kubernetes" --type note --tag devops
# Inbox 操作
syn inbox list
syn inbox process
syn inbox move <id> --to <namespace> --type <type>
# 回顾操作
syn review daily
syn review weekly
# Namespace 操作
syn ns list
syn ns new my-project
syn ns switch work-project
### 4.3 TUI 快捷键
| 快捷键 | 功能 |
|--------|------|
|
n | 新建资源 ||
e | 编辑(外部编辑器) ||
d | 删除 ||
a | 归档/取消归档(切换 archived 状态) ||
/ | 搜索/Fuzzy Finder ||
Enter | 查看详情 ||
Space | 切换活跃状态(见 §4.5 状态循环) ||
r | 刷新 ||
q | 退出/返回 ||
? | 帮助 ||
Ctrl+P | 命令面板 ||
l | 列表视图 ||
c | 日历视图 ||
t | 时间线视图 ||
g | 图谱视图 ||
0 | 切换到 Inbox ||
1-9 | 切换 Namespace |### 4.4 命令面板 (Command Palette)
参考 VS Code / Obsidian 的交互逻辑,区分不同模式:
| 快捷键 | 模式 | 功能 |
|--------|------|------|
|
Ctrl+P | 文件跳转 | Fuzzy Search Title/ID ||
Ctrl+Shift+P 或 > | 命令执行 | 执行命令 ||
# | Tag 搜索 | 按标签过滤 ||
@ | 范围搜索 | 按 Namespace/Area 过滤 |**交互示例**:
`┌─────────────────────────────────────────────┐
│ 设计文档 │ ← 默认:文件跳转
├─────────────────────────────────────────────┤
│ 10.001.0015 - 完成项目设计 │
│ 10.002.0003 - 设计规范笔记 │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ > review │ ← 命令模式
├─────────────────────────────────────────────┤
│ syn review daily │
│ syn review weekly │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ #urgent │ ← Tag 搜索
├─────────────────────────────────────────────┤
│ 10.001.0015 - 紧急任务 [urgent, work] │
└─────────────────────────────────────────────┘
def allocate_next_id(namespace: str, area: str, category: str) -> str:
"""
原子分配下一个可用 ID
使用 IMMEDIATE 事务模式 + UNIQUE 约束确保并发安全
"""
max_retries = 3
for attempt in range(max_retries):
try:
# ⚠️ 关键:使用 IMMEDIATE 模式,事务开始时立即获取写锁
# 这会阻塞其他写事务,避免空 Category 的竞态条件
cursor.execute("BEGIN IMMEDIATE")
# 1. 查询当前 Category 下最大 ID
# 同时查询 id_reservations 表(可能有预占但未使用的 ID)
cursor.execute("""
SELECT MAX(id_num) FROM (
SELECT CAST(SUBSTR(jd_number, -4) AS INTEGER) as id_num
FROM resources
WHERE namespace = ? AND jd_number LIKE ?
UNION ALL
SELECT CAST(SUBSTR(jd_number, -4) AS INTEGER) as id_num
FROM id_reservations
WHERE namespace = ? AND jd_number LIKE ?
)
""", (namespace, f"{area}.{category}.%",
namespace, f"{area}.{category}.%"))
row = cursor.fetchone()
max_id = (row[0] if row else None) or 0
next_id = max_id + 1
if next_id > 9999:
cursor.execute("ROLLBACK")
raise OverflowError(f"Category {area}.{category} ID exhausted (max 9999)")
# 2. 预占 ID(UNIQUE 约束是最后一道防线)
new_jd = f"{area}.{category}.{next_id:04d}"
cursor.execute("""
INSERT INTO id_reservations (jd_number, namespace, reserved_at)
VALUES (?, ?, datetime('now'))
""", (new_jd, namespace))
cursor.execute("COMMIT")
return new_jd
except sqlite3.IntegrityError:
# UNIQUE 约束冲突,说明有并发分配,重试
cursor.execute("ROLLBACK")
if attempt == max_retries - 1:
raise AllocationError(f"Failed to allocate ID after {max_retries} retries")
continue # 重试
def release_reservation(jd_number: str):
"""创建失败时释放预占的 ID"""
cursor.execute("DELETE FROM id_reservations WHERE jd_number = ?", (jd_number,))
**id_reservations 表结构**:
CREATE TABLE id_reservations (
jd_number TEXT PRIMARY KEY, -- ⚠️ UNIQUE 约束,防止重复分配
namespace TEXT NOT NULL,
reserved_at TEXT NOT NULL,
INDEX idx_namespace_jd (namespace, jd_number)
);
-- 定期清理过期预占(超过 1 小时未使用)
DELETE FROM id_reservations
WHERE reserved_at < datetime('now', '-1 hour');
**并发控制机制**:
| 层级 | 机制 | 作用 |
|------|------|------|
| 1 |
BEGIN IMMEDIATE | 事务级写锁,阻塞其他写事务 || 2 | 查询含
id_reservations | 感知其他进程的预占 || 3 |
jd_number PRIMARY KEY | UNIQUE 约束,最后防线 || 4 | 重试机制 | 冲突时自动重试 |
**批量导入优化**:
```bash
# 批量模式:一次性预占 N 个 ID,减少锁竞争
syn import --batch /path/to/files/ --count 100
# 内部实现:单次事务分配 100 个连续 ID
**ID 耗尽处理**:
- 每个 Category 最多 9999 个资源
- 接近上限(>9000)时 CLI/TUI 显示警告
- 建议用户创建新 Category 或清理归档资源
### 3.2 短 ID 支持
为降低 CLI 输入摩擦,支持 Git 风格的短 ID:
| 输入方式 | 示例 | 匹配规则 |
|----------|------|----------|
| 完整 ID |
10.001.0015 | 精确匹配 || 短 ID |
10.1.15 | 自动补零 → 10.001.0015 || 最短 ID |
15 | 当前 Namespace 内唯一匹配 || 标题模糊 |
设计文档 | Fuzzy Finder 模糊搜索 |
syn show 15 # 当前 Namespace 内唯一,直接匹配
syn show 10.1.15 # 自动补零
syn show 设计 # Fuzzy Finder
**歧义处理**:当短 ID 匹配到多个结果时:
- **CLI**:报错并列出候选项,用户需输入更精确的 ID
- **TUI**:弹窗让用户选择
$ syn show 15
Error: Ambiguous ID '15'. Did you mean:
[1] 10.001.0015 - 完成项目设计 (task)
[2] 20.001.0015 - 会议纪要 (meeting)
Use full ID or choose: syn show 10.001.0015
**Shell 自动补全**:CLI 必须实现 Tab completion(支持 Bash/Zsh/Fish)。
### 3.3 目录结构(双层分桶)
# Synapse (syn) - 需求规格说明书
> Synapse - 神经突触,象征知识连接与传递。缩写
---
## 1. 引言
### 1.1 系统愿景
Synapse 是一个基于 Python 3 构建的命令行/TUI 工作流管理工具,提供统一的知识与任务管理平台。
核心理念: "快速捕获、清晰组织、经常回顾、有效执行" (CORE)
### 1.2 核心原则
| 原则 | 描述 |
|------|------|
| 快速捕获 | 最小化录入摩擦,新内容默认进入 Inbox |
| 清晰组织 | Johnny.Decimal 变体 + k8s 风格资源管理 |
| 经常回顾 | GTD、周期性和智能回顾模式 |
| 有效执行 | 任务跟踪、状态管理、自动化工作流 |
### 1.3 目标用户
- **个人用户**:知识管理、任务追踪
- **团队用户**:协作、项目管理
- 支持个人使用,可扩展到团队协作
### 1.4 技术栈
| 组件 | 选型 | 说明 |
|------|------|------|
| TUI | Textual | CSS 布局,鼠标支持,适合 k9s 风格 |
| 存储 | Markdown | 仅
| 索引 | SQLite + FTS5 | Sidecar Index,加速查询 |
| 搜索 | Ripgrep | 全文搜索,高性能 |
| 文件监听 | watchdog | 实时检测外部修改 |
| 版本控制 | Git | 本地 + 远程 |
| 图谱 | Nebula Graph | GraphRAG 就绪(优先级低) |
| 自动化 | 本地 Hook + GitHub Actions | 本地优先,远程通知 |
---
## 2. 资源管理
### 2.1 资源标识
**文件路径**(双层分桶:Area → Category):
**示例**:
| 组件 | 说明 |
|------|------|
| namespace | 用户自定义(个人/项目名称),对应目录 |
| Area | JD 顶级分类(00-99),对应子目录 |
| Category | Area 内分类(000-999),对应子目录 |
| ID | Category 内序号(0001-9999) |
| resource-type | 资源类型(task, note, meeting 等) |
| title | 资源标题(可包含中文) |
### 2.2 资源操作规范
当 任何资源被操作时(CRUD):
- 自动触发 Git 提交
- 更新
- commit message 遵循 [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)
- 可选使用 LiteLLM 自动生成 commit message
**commit 类型**:`feat` |
### 2.3 Namespace 管理
Namespace 作为项目/领域的管理容器:
- 对应目录:`{workspace}/{namespace}/`
- 可包含配置文件
- 支持自定义资源类型和 SOP
### 2.4 预设资源类型
#### 2.4.1 类型与字段定义
| 类型 | 必填字段 | 可选字段 |
|------|----------|----------|
| task | title | status, priority, due, start_date, assignee, blocked_by |
| note | title | status, tags, links |
| meeting | title, datetime | status, duration, location, attendees, action_items |
| email | subject | status, from_addr, to_addr, cc, body |
| contact | name | organization, email, phone, custom_fields |
| unprocessed | (无) | status*, title, content |
> \*
**contact 支持自定义字段**:IP、MAC、微信号等任意键值对。
#### 2.4.2 状态定义
| 类型 | 状态字段 | 可选值 | 默认值 |
|------|----------|--------|--------|
| task | status |
| meeting | status |
| email | status |
| note | status |
| contact | (无状态) | - | - |
| unprocessed | (固定) |
> **说明**:`unprocessed` 类型状态不可变,归档时自动转换为
#### 2.4.3 优先级定义(仅 task)
| 优先级 | 含义 | TUI 颜色 |
|--------|------|----------|
|
|
|
#### 2.4.4 类型颜色标识
| 类型 | TUI 颜色 | 说明 |
|------|----------|------|
| task | 蓝色 | 待办任务 |
| note | 灰色 | 笔记 |
| meeting | 紫色 | 会议 |
| email | 青色 | 邮件 |
| contact | 橙色 | 联系人 |
| unprocessed | 白色/默认 | 未处理 |
---
## 3. Johnny.Decimal 组织结构
### 3.1 编号规则
采用标准 JD 三级结构,便于分桶管理:
**示例**:`10.001.0015` = Area 10 > Category 001 > 第 15 项
#### 3.1.1 ID 分配器与并发控制
**问题**:快速连续创建文件(如脚本批量导入)时,获取"下一个可用 ID"存在竞态条件。
解决方案:SQLite IMMEDIATE 事务 + UNIQUE 约束
⚠️ 为什么 `FOR UPDATE` 在空 Category 不起作用?
-
- 空 Category 的
- 多个进程可能同时得到
正确方案:BEGIN IMMEDIATE + UNIQUE 约束双重保障
> Synapse - 神经突触,象征知识连接与传递。缩写
syn 简短易记,与知识管理高度契合。---
## 1. 引言
### 1.1 系统愿景
Synapse 是一个基于 Python 3 构建的命令行/TUI 工作流管理工具,提供统一的知识与任务管理平台。
核心理念: "快速捕获、清晰组织、经常回顾、有效执行" (CORE)
### 1.2 核心原则
| 原则 | 描述 |
|------|------|
| 快速捕获 | 最小化录入摩擦,新内容默认进入 Inbox |
| 清晰组织 | Johnny.Decimal 变体 + k8s 风格资源管理 |
| 经常回顾 | GTD、周期性和智能回顾模式 |
| 有效执行 | 任务跟踪、状态管理、自动化工作流 |
### 1.3 目标用户
- **个人用户**:知识管理、任务追踪
- **团队用户**:协作、项目管理
- 支持个人使用,可扩展到团队协作
### 1.4 技术栈
| 组件 | 选型 | 说明 |
|------|------|------|
| TUI | Textual | CSS 布局,鼠标支持,适合 k9s 风格 |
| 存储 | Markdown | 仅
.md 文件,禁止二进制 || 索引 | SQLite + FTS5 | Sidecar Index,加速查询 |
| 搜索 | Ripgrep | 全文搜索,高性能 |
| 文件监听 | watchdog | 实时检测外部修改 |
| 版本控制 | Git | 本地 + 远程 |
| 图谱 | Nebula Graph | GraphRAG 就绪(优先级低) |
| 自动化 | 本地 Hook + GitHub Actions | 本地优先,远程通知 |
---
## 2. 资源管理
### 2.1 资源标识
**文件路径**(双层分桶:Area → Category):
{namespace}/{Area}/{Category}/{Area.Category.ID}-{resource-type}-{title}.md
**示例**:
personal/10/001/10.001.0001-task-完成报告.md
personal/10/002/10.002.0001-note-学习笔记.md
work-project/20/001/20.001.0001-meeting-需求评审.md
_inbox/00/000/00.000.0001-unprocessed-快速记录.md
| 组件 | 说明 |
|------|------|
| namespace | 用户自定义(个人/项目名称),对应目录 |
| Area | JD 顶级分类(00-99),对应子目录 |
| Category | Area 内分类(000-999),对应子目录 |
| ID | Category 内序号(0001-9999) |
| resource-type | 资源类型(task, note, meeting 等) |
| title | 资源标题(可包含中文) |
### 2.2 资源操作规范
当 任何资源被操作时(CRUD):
- 自动触发 Git 提交
- 更新
modified 时间戳- commit message 遵循 [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)
- 可选使用 LiteLLM 自动生成 commit message
**commit 类型**:`feat` |
fix | docs | refactor | chore | archive### 2.3 Namespace 管理
Namespace 作为项目/领域的管理容器:
- 对应目录:`{workspace}/{namespace}/`
- 可包含配置文件
.synapse.yaml- 支持自定义资源类型和 SOP
### 2.4 预设资源类型
#### 2.4.1 类型与字段定义
| 类型 | 必填字段 | 可选字段 |
|------|----------|----------|
| task | title | status, priority, due, start_date, assignee, blocked_by |
| note | title | status, tags, links |
| meeting | title, datetime | status, duration, location, attendees, action_items |
| email | subject | status, from_addr, to_addr, cc, body |
| contact | name | organization, email, phone, custom_fields |
| unprocessed | (无) | status*, title, content |
> \*
unprocessed 的 status 字段为系统固定值,不可由用户修改(见 §2.4.2)。**contact 支持自定义字段**:IP、MAC、微信号等任意键值对。
#### 2.4.2 状态定义
| 类型 | 状态字段 | 可选值 | 默认值 |
|------|----------|--------|--------|
| task | status |
todo, in-progress, done, archived | todo || meeting | status |
scheduled, completed, cancelled | scheduled || email | status |
unread, read, replied, archived | unread || note | status |
active, archived | active || contact | (无状态) | - | - |
| unprocessed | (固定) |
unprocessed | unprocessed |> **说明**:`unprocessed` 类型状态不可变,归档时自动转换为
note 类型(见 §5.2)。#### 2.4.3 优先级定义(仅 task)
| 优先级 | 含义 | TUI 颜色 |
|--------|------|----------|
|
high | 紧急重要 | 🔴 红色 ||
medium | 一般 | 🟡 黄色 ||
low | 可延后 | 🟢 绿色 |#### 2.4.4 类型颜色标识
| 类型 | TUI 颜色 | 说明 |
|------|----------|------|
| task | 蓝色 | 待办任务 |
| note | 灰色 | 笔记 |
| meeting | 紫色 | 会议 |
| email | 青色 | 邮件 |
| contact | 橙色 | 联系人 |
| unprocessed | 白色/默认 | 未处理 |
---
## 3. Johnny.Decimal 组织结构
### 3.1 编号规则
采用标准 JD 三级结构,便于分桶管理:
Area.Category.ID
│ │ │
│ │ └─ 4位数字 (0001-9999)
│ └─ 3位数字 (000-999)
└─ 2位数字 (00-99)
**示例**:`10.001.0015` = Area 10 > Category 001 > 第 15 项
#### 3.1.1 ID 分配器与并发控制
**问题**:快速连续创建文件(如脚本批量导入)时,获取"下一个可用 ID"存在竞态条件。
# 并发场景示例
$ for i in {1..100}; do syn new task --title "Task $i" & done
# 如果无锁机制,多个进程可能拿到相同的 ID
解决方案:SQLite IMMEDIATE 事务 + UNIQUE 约束
⚠️ 为什么 `FOR UPDATE` 在空 Category 不起作用?
-
FOR UPDATE 只能锁定 SELECT 返回的行- 空 Category 的
MAX() 查询返回零行,无行可锁- 多个进程可能同时得到
max_id = 0`,都尝试分配 `0001正确方案:BEGIN IMMEDIATE + UNIQUE 约束双重保障
Amp 生成的 Mermaid 图可以点击跳转到对应的代码块,这个分析源码还挺有用的 https://ampcode.com/news/clickable-diagrams
Text-to-SQL新范式:智能体自主探索搞定超大 AutoLink... http://xhslink.com/o/2coEcSKRwMe
复制后打开【小红书】查看笔记!
复制后打开【小红书】查看笔记!
一个外卖女骑手的真实记录,口碑爆了 https://b23.tv/PEwGtMl
将alb的timeout设置为60秒,以在Spring WebClient的idletime中从alb取消连接,从而引发socket closed issue
将WebClient上的maxIdleTime设置为59秒,以便在60秒之前关闭idle time
将WebClient上的maxIdleTime设置为59秒,以便在60秒之前关闭idle time