1. t3code 不是又一个笔记软件:我到底想用它解决什么
t3code 是我用 Node.js 写的一个命令行代码片段管理工具,名字是自己拼的,三个 T 分别代表 Terminal、Tag、Template。说白了,我写它只是因为烦透了在 VS Code 的 User Snippets、Notion 页面、项目的.code-snippets文件和一堆聊天记录里反复翻同一段代码的日子。
如果你也有类似经历,应该能马上 get 到痛点:某段认证逻辑你三个月前写过一次,现在要用,第一反应是去旧项目里grep;某个 Docker Compose 编排你说“先存到笔记里”,结果存进去之后再也没打开过;团队群里出现过一次很好用的 Git 钩子,但因为没人把它整理成正式资产,后来每个新人都要重写一遍。t3code 就是把我这些“散落的可执行知识”统一收进一个本地目录,用命令行随时检索、复制、插入,并且通过 Git 做版本管理和多设备同步。
名字里的三个 T 实际上也是这个工具的三个核心设计维度:Tag 负责给片段做结构化标签,Template 负责在插入时自动替换变量,Trace 负责记录片段的使用情况。它不是一个知识管理软件,也不是 IDE 插件,它更像是“代码片段层面的本地资产管理系统”。适合的人群很明确:经常在多个项目之间切换、依赖终端工作、需要把个人代码片段变成可复用资产的前端、后端或者 DevOps 工程师。
1.1 我的片段散落在四个地方,最后谁也找不着
在写 t3code 之前,我的可复用代码基本分布在四类地方:编辑器自带的 snippet 配置、公司的 Wiki / 个人笔记、GitHub Gist、旧项目本身。这四类地方各有各的毛病。
编辑器自带 snippet 的问题在于它和编辑器强绑定,而且作用域通常很有限。同一个片段在 VS Code 里能感知到当前文件的语言,但如果我在终端里想复制一段fetch封装给同事,得先把配置文件路径翻出来。项目里的旧代码看起来最可靠,但为了找一段工具函数要打开整个项目,通常还要处理依赖关系,只是复制一小段的话成本太高。笔记软件又有另一个问题:内容塞进去容易,检索出来难。你记得自己写过“分页组件”,但想不起来当时放在了哪一页,更别说 HTML 里那些代码块复制出来还带着样式。Gist 虽然能存公开片段,但默认的搜索体验很原始,也没有标签和分类的概念。
t3code 的核心思路其实特别朴素:每个片段就是一个带 YAML Front Matter 的 Markdown 文件,文件名是稳定 ID,正文是代码本身,元数据全部写在开头的---块里。这样我可以用任何文本工具打开、编辑、浏览,也可以直接从一个地方全部同步走。
1.2 三个 T:Tag、Template、Trace 分别承担什么
Tag 是检索的基础。每个片段除了标题之外,必须有一组标签和一个或多个别名。比如我经常用的 axios 请求封装,标签是http、axios、typescript,别名是req、request、http。这样搜索的时候,我不但可以按完整标题搜,还能用缩略词快速命中。别小看这个设计,它解决的是“我记得大概是什么,但记不住准确名字”的典型场景。
Template 是插入时的变量替换层。很多片段不是纯静态代码,比如 React 函数组件、定时任务脚本、数据库连接配置,里面总有几个会因为项目不同而变化的地方:组件名、超时时间、API 地址、用户名。t3code 用{{变量名}}这种占位符标记动态部分,插入时自动弹交互式提示,把变量问你一遍,然后生成完整代码。这一步直接省掉了“粘贴之后逐行改名字”的无聊劳动。
Trace 是我后来加进去的。以前我总觉得自己有些片段“看起来很厉害”,但只有真正统计使用次数才知道哪些是高价值资产。t3code 会在每次insert或copy时更新本地统计文件,记录使用次数和最后使用时间。配合 Git 历史,还能看到这个片段什么时候创建、什么时候改过、改了几次。它不会把任何数据上传到远端,默认所有统计都留在自己的机器上。
1.3 t3code 的定位:给“个人知识库里的可执行部分”一个家
如果你搜索 t3code 这个名字,可能首先会看到 T3 Stack 相关的项目,那个是 Next.js、tRPC、Tailwind、TypeScript 的组合,和我说的工具不是一回事。我这里的 t3code 只是一个很轻的本地 CLI,没有服务端,没有数据库,也没有复杂的插件体系。
但它解决了一个真实问题:个人知识库里最值钱的部分,往往不是网盘里那些资料,而是你反复写过的、已经验证过能跑的代码。这些代码值得拥有比“旧项目里的某一个文件”更稳定的存放位置。t3code 做的就是这件事:让代码片段成为一种可以被搜索、被版本控制、被团队共享的普通文件资产。
2. 存储、检索、插入:t3code 的三个底层设计决策
写工具最怕一上来就堆功能。我给自己定的原则是:能用纯文本解决就不上数据库,能用成熟外部工具解决就不自己实现,能少暴露配置就少暴露配置。所以 t3code 的架构非常朴素,但每一层都经过了比较实际的取舍。
2.1 为什么每个片段就是一个 Markdown 文件而不是 SQLite
有人可能会问,片段管理系统难道不应该用 SQLite 或者 JSON 文件存索引吗?我在最开始确实试过 SQLite,但很快就放弃了。最大的原因是:数据库文件不方便人工查看和合并,也不方便用git diff看变更记录。对于一个以“片段”为单位的工具,文件系统本身就是足够好的索引。
每个片段保存成~/.t3code/snippets/<id>.md,格式大概是这样:
--- id: axios-request-wrapper title: axios 请求封装(超时 + 拦截器) tags: [http, axios, typescript, 请求] alias: [req, request] lang: typescript created: 2024-03-12T10:20:00Z updated: 2024-11-03T09:15:00Z --- import axios from 'axios' const http = axios.create({ baseURL: '{{BASE_URL}}', timeout: {{TIMEOUT}}, }) http.interceptors.request.use((config) => { const token = localStorage.getItem('token') if (token) { config.headers.Authorization = `Bearer ${token}` } return config }) export default http选择 Markdown 文件的原因有三个:第一,可 grep,任何时候我都能直接grep -rn "interceptors" ~/.t3code/snippets,完全不依赖 t3code 本身的搜索逻辑;第二,可 diff,修改一个片段之后,Git 里能看到精确到行级的变更,而不是一个整块的二进制差异;第三,可迁移,未来就算 t3code 不维护了,这些文件仍然是普通的文本文件,没有绑定任何私有格式。
这套设计也有代价:如果你有几千个片段,文件数量会比较多,但现代操作系统处理几万个文件根本不是问题。对我来说,片段是“少而精”的资产,数量到几百已经很可观了。
2.2 为什么不自己写搜索,而是把选择权交给 fzf
搜索模块我一开始准备自己实现模糊匹配,写了几天之后意识到这是在重复造轮子。t3code 的本地搜索能力无论如何都不可能超过 fzf,所以我干脆做了一个决定:CLI 里直接调用 fzf,如果不希望依赖外部工具,就退回到简单的关键词过滤模式。
实际使用时的体验大概是这样的:
t3 search --fzft3 search会先读取所有片段文件,把id、title、tags、alias、lang拼成几列文本,然后喂给 fzf 做模糊搜索。fzf 本身就是为终端里的交互式选择而生的,支持键盘上下选择、多列预览、颜色高亮,我只需要把结果解析回来就行。
t3 list | fzf --preview 'bat --color=always -l {}'这样做的好处是,我不需要维护一套复杂的检索算法,也不需要担心中文分词、拼音首字母这些细节。用户如果不想用 fzf,可以直接t3 search req,命令行参数里带关键词也能完成搜索。外部工具的边界拿捏得很清楚:没有 fzf 的时候功能不瘫痪,有 fzf 的时候体验直接上一个档次。
2.3 模板变量和剪贴板:插入这件事的完整链路
如果你只是把代码片段搜出来复制到剪贴板,那很多工具都能做到。t3code 真正让我觉得好用的是模板变量和剪贴板的无缝衔接。
插入一个动态片段的流程是这样的:
t3 insert reqt3code 会先根据别名req找到对应片段文件,然后扫描正文里的{{BASE_URL}}、{{TIMEOUT}}这类变量,再逐个询问:
? 请输入 BASE_URL: https://api.example.com ? 请输入 TIMEOUT: 8000 ✔ 生成结果已复制到剪贴板生成结果之后,它会调用当前系统的剪贴板命令。macOS 上是pbcopy,Linux 上有xsel或wl-copy,Windows 上是clip。安装时 t3code 会探测一次系统类型,把对应的命令缓存到配置里。如果探测不到,也不会直接报错,而是把最终结果打印到终端,让你手动复制。
这一步看似简单,但对工作流的影响很大。以前用 VS Code snippet 的时候,虽然编辑器能自动展开变量,但只能在编辑器内部用。t3code 把能力扩展到了整个终端:我可以从终端里复制一段 curl、一段 nginx 配置、一段 SQL,往任何地方粘贴。
2.4 配置文件的默认路径与跨平台处理
t3code 的配置文件放在~/.config/t3code/config.yml,内容很克制:
snippet_dir: ~/.t3code/snippets editor: nvim clipboard: auto sync: enable: true remote: git@github.com:yourname/t3code-snippets.git branch: mainsnippet_dir是片段仓库的位置,默认在用户目录下。editor用来指定执行t3 edit时打开哪个编辑器。clipboard可以设成auto,也可以手动指定具体命令。sync这部分主要是针对走 Git 同步的场景。
跨平台处理里最麻烦的其实是路径分隔符和剪贴板命令。我一开始只考虑了自己的 macOS 环境,后来同事在 Windows 上装了之后发现路径拼接有问题,才加了一个统一的路径抽象层。现在不管是~/.t3code/snippets还是C:\Users\xxx\.t3code\snippets,内部统一用path.join处理,不再手写斜杠字符串拼接。
3. 从安装到日常使用:一套可以直接抄的工作流
工具只有真正进入日常开发流程才有价值。下面这套工作流是我自己用了半年之后沉淀下来的,从初始化到日常新增、检索、同步,每一步都能直接照做。
3.1 安装和初始化
t3code 目前以源码方式分发,没有发布到 npm 的正式包名。安装步骤很简单:
git clone git@github.com:yourname/t3code.git cd t3code npm install npm run build npm link t3 --versionNode.js 版本建议 18 以上,因为代码里用了比较新的原生 API。装完之后第一步是初始化:
t3 init这个命令会在~/.t3code下创建snippets目录、一份README.md、一套默认.gitignore,以及上面的config.yml。如果~/.t3code还不是一个 Git 仓库,它会自动帮你执行git init,然后生成最初的 commit。
3.2 录入第一个片段:交互式 t3 add
添加片段我用的是交互式表单,刻意避免让你一行命令写太多参数。运行t3 add之后,它会问你几个问题:
? 片段标题: axios 请求封装 ? 标签(逗号分隔): http, axios, typescript ? 别名(逗号分隔): req, request ? 语言: typescript ? 输入片段内容,以 line 包含 #END 结束:它会根据alias的第一个值生成文件名,比如req.md。如果没填别名,就从英文标题生成 kebab-case 文件名;如果是纯中文标题又没给别名,那就要你补一个英文别名,避免文件名变成一串 URL 编码。这个设计是在实际踩坑之后加进去的,后面专门讲。
保存好之后可以马上试一下搜索:
t3 search req提示:
t3 add只是一个交互式外壳,你可以直接用文本编辑器往snippets/目录里加.md文件,效果完全一样。这个习惯对团队协作很重要,因为片段本质上就是普通文本文件。
3.3 检索和插入:我推荐的两条高频路径
日常使用我基本只需要两条路径。第一条是“只复制不改变量”:用t3 copy,例如t3 copy req,它会把片段正文里的变量替换成默认值(如果没设默认值,就原样保留),然后复制到剪贴板。适合拷贝纯静态代码。
第二条是“需要填变量”:用t3 insert,就是前面提到的交互式变量替换流程。适合拷贝组件模板、配置样板、带有项目相关参数的脚本。
如果你不习惯记命令,也可以只记一个:
t3 s reqs是search的别名,输出会包含片段 ID、标题、标签和语言。配合 fzf 使用的时候,按回车之后还可以选择把结果直接复制还是用编辑器打开,一步到位。
3.4 团队共享:为什么 Git 同步比云同步靠谱
我见过很多团队用在线文档的“代码块”维护共享代码片段,结果代码一多,文档就乱成一锅粥。t3code 的选择是直接拥抱 Git,因为团队本来就在用 Git 管代码,为什么破例用另一个系统去管代码片段?
在团队内共享的时候,你只需要把~/.t3code里的snippets目录提交到一个单独的 Git 仓库,然后让其他成员把仓库地址写到各自的config.yml里。t3code 的t3 sync命令本质上就是对 Git 的封装:
t3 sync --pull t3 sync --push使用 Git 有三个额外的好处:第一,天然有审计记录,谁在什么时候加了什么、改了什么都清清楚楚;第二,可以走代码评审流程,PR 和 MR 的老规矩照样用;第三,可以 fork,别人在你片段的基础上做修改,形成自己的分支,不会污染主仓库。这一点是任何在线文档平台都很难做到的。
3.5 常用命令速查表
| 命令 | 作用 |
|---|---|
t3 init | 初始化本地片段仓库和配置 |
t3 add | 交互式新增片段 |
t3 list | 列出所有片段 |
t3 search <query> | 按标题、标签、别名搜索 |
t3 search --fzf | 用 fzf 做交互式模糊搜索 |
t3 copy <pattern> | 找到片段并复制到剪贴板 |
t3 insert <pattern> | 找到片段,填变量,然后复制 |
t3 edit <pattern> | 用配置指定的编辑器打开片段 |
t3 stats | 查看片段使用统计 |
t3 sync --push/--pull | 同步远程 Git 仓库 |
这套命令表基本覆盖了我所有关于“片段”的操作。不需要一个常驻的后台进程,也不需要打开某个 GUI 窗口,所有事情都在终端里完成。
4. 用了半年以后真正踩到的坑
任何工具光看设计都觉得挺好,真正用起来才会暴露问题。t3code 也是,下面这几个坑我基本都真实踩过,写出来帮你避开。
4.1 中文文件名的坑
最早我允许直接用中文标题作为文件名,比如axios请求封装.md。在 macOS 上看起来没问题,但放到 Linux 服务器或者 Windows 上,编码和文件名长度的问题就开始冒头。更麻烦的是,如果同一个片段在多台设备之间合并,中文文件名在某些旧系统的 Git 配置里会显示成转义序列,看得人一头雾水。
后来我改成:文件名只允许英文小写、数字、连字符,优先取第一个alias;如果别名没填,就取英文标题的 kebab-case;如果都没有,会生成一个短随机 ID。中文信息全部留在 Front Matter 的title字段里。这个改动之后,多设备同步和跨平台使用都没再出过文件系统层面的问题。
4.2 模板语法和代码本身撞车的处理
模板变量的设计早期有个大坑:我用的是{{变量名}},但很多前端模板本身也用这个语法。比如 Vue 文件里到处都是{{ message }},如果我把这样的代码存成片段,t3 insert就会误把它当成变量,弹出提示问我message是什么,直接乱套。
解决方案是在片段文件里用\{{表示字面量。比如 Vue 模板里的插值,需要写成这样:
<div>\{{ message }}</div>t3code 在解析变量之前会先扫描转义占位符,把它们替换成特殊标记,等所有真实变量都替换完之后,再把标记还原成{{ message }}。第一次意识到这个问题的场景我记得特别清楚:我把一个 Vue 组件的完整模板存进片段,第二天用的时候,t3code 一口气问了十几个变量,我差点以为是程序坏了。这个问题解决之后,模板语法的适用面就宽了很多,不管是 Vue、Handlebars 还是 Go Template,都能正常存档和插入。
4.3 多设备冲突与 Git 操作的细节
用 Git 同步片段,最常见的坑是两台设备同时改了同一个片段。t3code 的sync命令默认会先git add -A && git commit -m "sync",然后git pull --rebase,最后git push。大部分情况下 rebase 能顺利解决,但如果你在两台设备上分别添加了同一个alias的不同片段,文件名相同,就一定会产生冲突。
我的处理经验是:首先不要用编辑器去解决这种冲突,直接在终端里看冲突标记,确认哪一版是你想要的;如果两个都想要,就把其中一个改名为新的id和alias,让它们变成两个独立片段。另外,我把stats/usage.json放进了.gitignore,因为使用次数统计是一种本地状态,没必要在每台设备之间来回合并,冲突只会添乱。
4.4 一个我差点忽略的权限问题
还有一次遇到的很隐蔽的问题是:~/.t3code目录的权限设置得太开放,导致别的用户或者某些自动化脚本也能读到片段内容。因为片段里偶尔会包含数据库连接串、内部 API 地址这类敏感信息,即使仓库是私有 Git,本机权限也应该收紧。
所以我添加了安装时的一个检查项:如果~/.t3code的目录权限不是700,就给出警告,提醒你执行:
chmod -R 700 ~/.t3code这个细节很容易被忽略,但非常重要。代码片段管理工具的核心资产就是文本文件本身,文件系统的权限策略,某种程度上就相当于你的“数据安全防线”。
5. 和常见工具对比之后,我的推荐边界在哪里
每次跟别人聊 t3code,都会被问到它和 VS Code Snippets、massCode、AI 补全这些方案比有什么优势。坦白说,它们不是完全替代关系,但在某些维度上 t3code 确实更顺手。
5.1 t3code vs VS Code 自带 Snippets
VS Code 的 User Snippets 很成熟,但它的本质是编辑器配置文件,而不是资产管理系统。它只活在编辑器内部,不能在终端里复制,也不能脱离当前工作区使用。t3code 的片段就是普通文件,可以用任意编辑器打开,可以在 shell 管道里被处理,也可以在 CI 脚本里调用。
不过如果你是纯 VS Code 用户,并且大部分代码都在编辑器里完成,那 VS Code Snippets 的体验依然很顺滑,毕竟它原生、零依赖。我自己的用法是两者共存:编辑器里高频的那几个片段还是会在 VS Code 里定义,但是跨项目、跨终端、需要长期维护的代码资产,一律放进 t3code。
5.2 t3code vs 图形化片段库
massCode、SnippetsLab 这类工具界面更好看,预览更直观,适合“看”代码。但它们的共同问题是:数据格式封闭、命令行支持弱、自动化困难。我手动整理过几百个片段之后,非常在意数据的可迁移性和可脚本化能力,这一点纯文本 + Git 的路径明显更稳。
当然,如果你想给片段添加截图、写详细的长文笔记、甚至做标签云可视化,图形化工具体验更好。t3code 故意没有做这些,因为它的定位就是“终端里的确定性工作流”,不是“知识花园”。
5.3 t3code vs AI 补全
AI 补全对生成一次性代码很有用,但它维护不了“确定性资产”。我今天想让团队所有人都使用同一版认证封装,AI 每次生成的结果都可能不一样,或者说会有“合理漂移”。t3code 里的片段是固定的,经过 review、测试、实际项目验证过的版本。它不是帮你写代码,而是帮你在写代码时快速取出已经写好的最优版本。
所以我的建议是:让 AI 做它擅长的方案探索和初稿生成,用 t3code 沉淀那些你愿意反复使用的、已经验证过的代码。两者并不冲突,甚至可以说 AI 让片段产生的速度更快了,t3code 让这些片段真正留得下来。
5.4 我不建议用 t3code 的几种情况
也有一些人我明确不建议用 t3code。第一种是只做前端页面、所有代码都在编辑器和框架脚手架里完成,很少跨项目复用代码,那没必要多学一个 CLI。第二种是你需要的是“富文档 + 截图 + 可视化标签管理”的完整知识库,t3code 给不了。第三种是对数据安全有严格合规要求、不允许在本地和远程仓库之间同步代码片段的团队,那应该使用公司统一的内部代码片段服务。
一句话总结我的推荐边界:如果你经常在终端工作、对代码资产的版本管理和可迁移性有执念、并且愿意用文本文件来管理“可执行知识”,t3code 会很合拍。
6. 下一步:我要把它从“我的玩具”变成“能分享的玩具”
t3code 目前已经在我自己每天的工作里跑了大半年,稳定性和易用性基本达到我自己的标准。但作为个人项目,下一步我规划了两件很具体的事。
第一件事是把模板变量升级成更正式的 schema。现在的{{变量名}}很轻,但缺少默认值、枚举值、必填提示这些能力。我打算在 Front Matter 里增加一个params字段,让一个片段可以声明变量的类型、默认值和说明。比如:
params: BASE_URL: type: string default: https://api.example.com required: true help: 接口服务地址 TIMEOUT: type: number default: 8000这样交互式提示就能更友好,也可以支持从命令行直接传参,比如t3 insert req --BASE_URL=https://dev.api.local。
第二件事是做一个只读的静态分享页。想法很简单,t3 share <pattern>会把选中的片段渲染成一个独立的 HTML 文件,带上语法高亮和说明信息,方便发到团队文档或者内部 Wiki 里。它不会引入在线服务,也不会把你的片段上传到任何服务器,只是在本地生成一个文件。
最后分享一个我一直在用的整理习惯:每周五跑一次t3 stats,看看哪些片段使用次数最高,哪些从创建之后就再也没被碰过。连续三个月都是零次使用的片段,我会考虑删除或者归档。这个习惯让 t3code 不只是“随手存代码”的地方,而是真正会帮我审视自己技术资产价值的入口。工具永远会迭代,但这种“定期清点”的习惯,才是让代码片段仓库保持干净的核心。