I am LAZY bones?
AN ancient AND boring SITE

Notchy

还记得3月底的时候,在X上火过一段时间的那个Notchy吗?

当时我就下载着试用过,发现点子非常不错,也很实用,但当时还有一些小bug,于是搁置了。

今天突然又想到了,想着过了这么久,应该进化了不少吧?

于是有去GitHub看了一眼,发现原作者似乎没有在维护了。。。

想着这么好的一个项目,就这么荒废着实有点可惜,我就给接手维护一个版本吧。正好昨天研究CCAS的打包,也就顺手给打了一个包。供大家更方便地下载使用。。。

虽然我也修了一些,也合并了一些原repo里的PR,但肯定还有不少问题,如果大家有遇到,欢迎提issue,更欢迎提PR。

附上原作者的推文,以示感谢。
点击查看全文 »

Keychain和security简介

CCAS 的时候要做的事其实很本质:在多个 Claude 账号之间切换。第一个要弄清楚的是 —— Claude Code 把自己的 OAuth credentials 存在哪?

翻一下之前泄露的代码很容易就知道了:在 macOS Keychain 里,service 名字是 Claude Code-credentials。你现在就可以在终端里看一眼:

会打印出一坨 JSON,里面就是 access token、refresh token 这些。

这不是 Claude Code 的”小众”选择 —— 各种 IDE、CLI、Apple 自家的 Safari Mail,所有在 macOS 上要存”密码、token、密钥”的程序,默认就该放进 Keychain。它是这台机器上事实标准的敏感数据存储。

那它到底是什么?

Keychain 是什么

最直白的描述:Keychain 是 macOS 自带的加密键值数据库,专门为存敏感数据设计。每条记录由系统加密,挂在登录用户的身份下,由 securityd 这个常驻守护进程管理。

它的物理形态是磁盘上的几个文件,常见的有:

你不会直接读这些文件 —— 它们是加密的 SQLite,主密钥跟你的登录密码绑定。读写都要走系统 API,由 securityd 解锁后再返回明文。

它解决了什么

如果不用 Keychain,自己拿个 JSON 文件存 token 行不行?技术上可以,但你要面对几个问题:

1. 磁盘加密

文件丢在 ~/.config/ 下是明文。任何能读你 home 目录的进程都能拿到(包括别的 app、误装的恶意脚本)。即便你给文件 chmod 600,磁盘镜像被拷走照样能看。

Keychain 用 AES 加密,主密钥来自你的登录密码 —— 机器没登录、密码不对,磁盘镜像里的内容就解不出来。

2. 进程隔离

文件系统只有”用户级”权限。但同一用户跑的所有 app 是平等的:Claude Code 写下的 token,理论上你装的任何一个三方 app 都能读。

Keychain 的每条记录带 ACL(access control list),记录”谁创建的、谁可以读”。当一个 app 试图读另一个 app 创建的条目时,系统会弹窗让用户确认。这是文件系统本身做不到的。

3. 用户可见、可管理

打开 Keychain Access.app,你能看到所有条目、谁创建的、什么时候改的,可以手动删。要 export 还得再输一次登录密码。

4. 跨设备同步

勾上 “iCloud Keychain” 之后,相应条目会端到端加密同步到你登录同一 Apple ID 的其他 Mac、iPhone、iPad。Safari 的密码、WiFi 密码、Apple Pay 卡号走的都是这个。

数据模型

Keychain 里有几类 item,最常用的是 generic password(任意 key-value 的密钥/token,多数 app 自定义存储用这个)和 internet password(带 protocol/host/port/path 字段,Safari 存网站密码用)。此外还有 certificate、key(公私钥对)、identity(cert + key 对)。

generic password 的核心字段就两个:

  • service:通常用 reverse-DNS 风格的命名空间,例如 com.apple.accountClaude Code-credentials
  • account:同一 service 下区分多条记录的标识,通常是用户名或邮箱。

service + account 唯一定位一条记录。Password 字段本身可以是任意字节(你完全可以塞一整段 JSON 进去,Claude Code 就是这么干的)。

怎么读写:security 命令

Apple 给开发者两套接口:

  • C APISecItem* 这一族(旧的 SecKeychain* 已经不推荐)。Swift / Objective-C app 一般用这个。
  • 命令行 /usr/bin/security:脚本和调试用。

CCAS 走的是后者,省得对接 C API;好处是用户自己在终端就能验证一切。最常用的三条:

-s 是 service,-a 是 account,-w 表示”只把 password 内容打到 stdout”。不加 -w 会打印所有属性元数据,但隐去 password。

更多有用的子命令:

几个不那么直觉的细节

search list:系统其实管理着一个 keychain “搜索列表”,security find-* 默认遍历整个列表。常见情况下只有 login.keychain-db,但用户/MDM 可能加挂别的。如果某条记录意外落在搜索列表外的 keychain 里,会出现”dump 看得到、find 找不到”的现象,这时候要在命令末尾显式带上 keychain 路径。

密码存二进制:用 -w "value" 写入时整个参数被当作 UTF-8 字符串。如果 value 里有换行、引号、控制字符,shell 转义会很烦人。更可靠的方式是 -X hex,把内容先转 hex 再交给 security,由它自己 decode 后存原始字节。

-U 不一定是真正的 upsertadd-generic-password -U 文档说”如果存在则更新”,但匹配条件偏严,遇到某些属性差异会判定为”新条目”再插一条。同 service+account 的重复记录会越积越多。要 idempotent 的话,先 delete 再 add 更稳。

account 不是严格过滤find-generic-password -s SVC -a ACCT 如果 account 没精确匹配,可能 fallback 命中同 service 下别的 account —— 不报错,直接返回别人的内容。读完后再校验返回值是个好习惯。

小结

Keychain 是 macOS 上存敏感数据的标准答案。它做的事不复杂 —— 加密、隔离、用户可控、可同步 —— 但是把这四件事做齐了,且对开发者基本零成本。

下次写 Mac app 要存 token、API key 或者密码,不用犹豫,直接 SecItem / security 走起,比自己掂量”放哪、加什么密、谁能读”省太多事。

Claude Code Account Switcher

如今这AI时代,如果你也写写代码,我相信你肯定在用一些AI工具了吧?

如果你恰好用的也是Claude code,那大概率也会因为每月20$的pro套餐用量不够而烦恼吧?这时,如果你不差钱,可能就直接订阅200$的max套餐了,但如果你也觉得200刀有点下不去手,那可能再买一个20刀,就是更加可以接受的方案了。

此时,你就会遇到两个Claude账号频繁切换的问题了。。。那你可能就需要这个小工具了。

功能挺简单的,也无需我过多介绍了,直接看图就能明白了。这是一个macOS下的菜单栏小工具。可以同时登录多个Claude账号,能查看每个账号的余量,能帮你快速切换账号。

CCAS
CCAS

截图里,我的账号1是公司给开的enterprise账号,一个月200$的token(也是不经用的);账号2是我自己的pro账号。两种账号都是支持的。

工具以MIT开源。代码在GitHub。等我再整理一下,放个编译好的二进制吧。

uv 的 inline script metadata 太香了

最近又玩了下 uv,感觉它在“小工具开发”这个场景里特别顺手。

uv 本质上是一个把 Python 依赖管理、虚拟环境、脚本运行这些事情揉在一起的工具。它最大的优点当然是快,但更让我喜欢的是:很多原本零碎又烦的动作,被压缩成了几个很好记的命令。

比如平时写个小脚本,常常只是想:

  • 调一下接口
  • 批量处理一点文件
  • 验证一个第三方库
  • 给自己做个顺手的小命令

这类东西通常不值得认真建个项目,但又往往会依赖 requestshttpxrich 之类的包。以前一般要先建 venv,再装依赖,可能还要改个 .gitignore,多少有点麻烦。

这时候 uv 很方便的一个点,就是可以直接用 --with

或者:

这种方式特别适合刚开始写小工具的时候。先跑起来,先验证思路,不用一上来就准备完整项目。

不过,--with 也有个问题:依赖信息是在命令里,不在脚本里。

今天你记得怎么跑,过几天自己可能都忘了。发给别人时,也得额外告诉对方要带哪些依赖。

这时候真正的大招就来了:inline script metadata

你可以直接把依赖用这样的格式,写到脚本头部:

可以看到,去掉# /// script这些包裹层之后,里面的内容,其实就是TOML的语法。

这样之后就不用再写长命令了,直接:

就行。这个体验非常好。因为脚本自己就说明白了:

  • 需要什么 Python 版本
  • 依赖哪些包
  • 应该怎么运行

更进一步,你甚至可以再加个 shebang,把它写成一个可以直接执行的脚本:

这样给脚本加上执行权限(chmod +x)之后,连 uv run foo.py 都可以省掉,直接 ./foo.py 就可以跑起来了。

最后总结一下:

  • 刚开始随手写个小工具,用 uv run --with ...
  • 觉得这个脚本值得留下来,就上 inline script metadata
  • 再彻底一点,可以用#!/usr/bin/env -S uv run --script这个shebang

App Store Small Business Program

事情是这样的,3月初的时候,我上线了我的第一款收费APP(用于在睡眠期间监测和记录呼噜声的),然后陆陆续续也有几笔成交了。

于是我这个数据控,就研究了一下Apple的开发者后台,里面的一些看板和详细数据。由于我的APP一共也才成交了几笔而已,样本非常有限,还刻意和资深开发者朋友 TualatriX 聊了一下,还真让我发现了一些门道和问题。。。

那就是在app store connect里,Sales、Proceeds的数据,和你给APP的定价肯定都会不一样。原因有以下几层:

第一层,是汇率的影响。

因为你的 APP 是全球卖的。用户可能用的是欧元、日元、人民币付款,而你后台的结算通常是按美元(或你本地货币)来算的。中间一定会经历一次甚至两次货币转换。

关键点在于:Apple 用的不是实时汇率,而是自己的一套定价和结算汇率(按周期更新)。这就会带来几个结果:

  • 同样标价 2.99,在不同国家对应的本地价格其实是不一样的
  • 不同货币换算回来的“基准金额”,本身就有偏差
  • 即使同一个国家,汇率调整周期不同,Proceeds 也可能轻微波动

换句话说,从一开始,你的“2.99”,在全球范围内就已经不是一个严格一致的数字了。

然后,才是第二层:税。

App Store 的价格是“含税展示价”,不同国家税率不同(比如 VAT、GST)。这些税是从用户支付的钱里先扣掉的。

接着是第三层:Apple 抽成。

而且这个抽成,是在“去税之后”的金额上算的(默认抽走30%)。再剩下的才是你真正拿到的 Proceeds。

所以完整链路其实是:本地定价 → 汇率换算 → 扣税 → Apple 抽成 → 最终收入(Proceeds)

那,作为开发者,有什么可以action的东西么?

显然,汇率和税,作为小卡拉米的我们,是没法去影响的,但苹果其实有个“App Store Small Business Program”,是可以给小开发者一些抽成上的优惠的。

具体来说,苹果针对年销售额不足1百万美元的小开发者,可以把默认的30%的抽成比例,降到15%。其实之前我也听说过这个计划,但当时也没细看,以为是默认开通的。但其实是要开发者去单独申请,并审核开通的。方法倒是很简单,就是用开发者账号登录后,在这个页面点“Enroll now”,填上相应的信息,就算提交成功了。

注意,提交成功,并不代表你enroll成功了,在收到以下邮件之前,抽成将还是30%。而且苹果处理这个请求相当地慢,以我为例花了3周的时间,而且我中间还催过一次。
Small Business Program

好了,最后祝所有开发者都能APP大卖!早日被踢出Small Business Program!

清迈旅行

我发现,要坚持输出一些内容,还是挺难的,这不,离上一篇文章都已经快一个月了。经常有这样那样的事情,就推脱自己有点忙,哈哈!好在,今天还是想起来要写点东西了。

这次去清迈,是因为4月初有个Good Friday,新加坡会多一天假,而且刚好和国内的清明假期差不多时间。就想趁着小长假去哪里玩一下。一开始是计划去印尼看火山的,但机票、行程都没有选到合适的,后来又在科莫多岛、巴厘岛和斯里兰卡之间摇摆了很久,最终决定去个轻松的,几个人才定了清迈。

我们有4天3晚的时间,去掉来和回的两个半天,安排一个一日游行程和一天的自由活动。剩下的就是吃吃喝喝和每天一次的马杀鸡了。

一日游,我们是携程上找的“清迈黑庙+白庙+蓝庙一日游”,中文导游+跟车+门票+团餐的小团。389RMB一个人,我们选的是9人小团,如果是12人的团,价格会便宜蛮多。但是,相信我选贵的,这9人和12人,不仅仅是人数的差别。这两者使用的面包车是一样大小的,也就是说12人团的车,位置会很挤,相当于经济舱;而9人团的位置就宽敞很多。而且,由于经典离清迈老城还蛮远的(实际上,已经到旁边叫“清莱”的邦了),全天在车上的时间会超过6小时,所以乘车的舒适性对这个行程还是挺关键的。

好了,接下来就到了放图时间了。我按时间顺序来吧。

长颈族部落,这是一个3庙以外的小景点,可以选参加的。景点确实非常小,有几十个长颈族的部落成员,导游说以前他们是缅甸的,逃难到此,扎下根来,受泰国政府庇护,专门给他们开发了这块区域。
长颈族人民的生活状况

白庙的创始人,是一个当地的艺术家,前半生艺术成就很高,也买了很多画赚到不少钱,后半生开始参与公共事业,建设了这座庙。这座庙的艺术水准确实也非常高!非常地闪亮!
白庙

蓝庙就比较新了。建于2016年前后,由白庙的那个艺术家的学生打造,在旧庙遗址上重建,以深蓝象征智慧、金色象征佛光,融合现代艺术与传统佛教风格,成为清莱最具视觉冲击力的新地标之一。
蓝庙

蓝庙的冰激凌都是蓝色的
蓝庙的冰激凌都是蓝色的

黑庙,则另一个艺术家于20世纪后期逐步建成,它其实不是寺庙,而是一组以黑色木屋与动物骨骼、毛皮等艺术构成的博物馆,通过强烈的原始与暗黑风格表达生死、欲望与人性主题。
黑庙

黑庙其实占地面积挺大的,我们应该是逛了一个小时左右,还意犹未尽,这是部分展品:

以上就是一日游的所有景点了。

另外值得一提的,就是马杀鸡了,泰国的马杀鸡本身就很出名,清迈的马杀鸡店非常多,价格从便宜到中等都有(真的都不算贵),我们基本上从200多泰铢到700多泰铢的都体验了一下,怎么说呢?还是很解压的,基本上每个档位的服务也都对得起那个价格。所以,一般对着Google maps的评分做参考,就不会踩雷。当然,还是得体验一下贵一点的,毕竟换算一下还是很便宜。这个就不放图了。

还有就是,我们住在塔佩门附近,周日晚上的夜市(只有周日有,其他的都是小夜市),确实很热闹,可以逛逛。而且夜市里也有很多吃的小摊贩,品种很多,样式很齐,所以可以解决晚饭。但其他商品嘛,可能是因为逛过义务小商品市场了,又有万能的淘宝了,基本上也都不怎么会看得上。就看个热闹也挺好的。

自己玩的那天,我们去了素贴山徒步,行程一般,门票大人100,小孩50,会路过另外两个寺庙。而且当时空气质量还是有点堪忧(虽然山上比市区好多了),就不多说了吧。

就此,完毕!

OpenClaw分享

以下PPT和内容,来源是我跟一群爱学习的朋友一起学时下大火的OpenClaw小龙虾,我给大家做了个小分享。

PPT几乎是OpenClaw输出的内容,下面的会议总结也是GPT根据会议录屏总结的。

需要注意的是,我其实没有将小龙虾玩得很深,因为我从心底里是不信任AI的,也就不敢给它太多权限。所以内容也都比较浅,请见谅。

OpenClaw 会议总结

这次分享的核心,不是在介绍一个“聊天机器人”,而是在介绍一套可自托管、可扩展、可执行任务的个人 AI 基础设施。分享者把 OpenClaw 定位为“装进手机里的 AI 助手”:用户通过 WhatsApp、Telegram 等聊天入口发出请求,背后由部署在自己电脑或服务器上的 OpenClaw 网关完成会话管理、记忆注入、工具调用和本地执行,再把结果返回到聊天端。PPT 对这一定位和整体链路描述得很清楚。

点击查看全文 »

《静静的顿河》第三、四卷读后感

前两卷留下的印象,是那种暖色调的水彩画——顿河边的草场、哥萨克村子里的家长里短、葛利沙和阿克西妮亚之间藕断丝连的情愫。节奏慢,但耐看,像坐在廊子下面晒太阳,看日子一天天过去。

到了三、四卷,画风突然就变了。

大量的场景转移到了军营、行军路上,甚至直接是炮火纷飞的战场。节奏紧了,人也开始大批地死。那种生活流的温度消失了,取而代之的是裹挟着所有人的历史洪流——你不想卷进去,但你没得选。

这两卷真正开始展开的,是俄国社会深处的阶级裂痕。对外的战争还没打完,内部的矛盾就已经压不住了。沙皇的权威在慢慢松动,旧秩序腾出来的空间,各方势力都想填进去。这种感觉其实很熟悉——历史上大概率,对外的战争一旦结束,就容易有内战。外部的压力消失了,内部的矛盾反而浮上来了。

布尔什维克在这两卷里开始有了存在感。他们的传播方式是低调的、地下的,像水渗进土里一样,悄悄地扩散。对那些一无所有的底层人来说,他们描绘的那个世界确实有吸引力——凭什么你有地我没地?凭什么干一样的活,命运差这么多?这种质问是朴素的,也是有力量的。

但我读到这里会停下来想一个问题:保护”私有财产”和追求”社会公平”,这两件事本质上是有张力的。布尔什维克当时给出的答案,是彻底打翻旧秩序。可打翻之后呢?这个问题到今天也没有一个让所有人都满意的答案。不同的国家在这条线上划在不同的位置,还在不断地摩擦、调整。

肖洛霍夫厉害的地方在于,他没有给你答案。他只是把所有人都放进这个漩涡里,然后让你看着他们挣扎。葛利沙就是这样一个人——他不是天生的革命者,也不是坚定的保守派,他只是一个被时代推着走、不断做选择又不断后悔的普通人。

看完这两卷,确实比前两卷更沉重了。后面还有什么呢?我会继续探索。

局域网影音解决方案——Jellyfin

先交代下背景:我本来是打算在家里搞个NAS的,但由于最近硬盘和内存都疯狂涨价,加上其实需求也不是那么迫切,就一直没有去折腾。

另外,家里其实已经有一个小主机(对,本blog就跑在上面呢)了,它带了1TB的SSD。所以偶尔有下载电影、在不同的屏幕(手机、pad、电脑、电视机等)看电影的需求,就想着把这个小主机再压榨一下吧。

于是有了以下的折腾:

下载的需求,其实很好搞定。但下载完之后,电影在小主机上,要在各种设备上播放,我一个想到的是用SMB在局域网里共享目录,这确实是一个方案。但这个方案有两个问题:

  1. 不是所有的(屏幕)设备都能找到支持SMB的播放器。
  2. 有些设备的解码能力太弱,遇到高码率的4K视频,就会卡住

所以,最好的方式就是再充分压榨这个小主机,因为它其实有个显卡(CPU:AMD Ryzen 3 7330U(集成 Radeon iGPU)),可以用于服务端转码。于是就给它装了个 Jellyfin。

Jellyfin是个开源的、完全自托管的影音解决方案,特别适合喜欢折腾的人。

安装过程我也偷懒了,没有去编译源码、调试环境,而是直接采用docker运行了,在我的Ubuntu下,大致如下:

接着,建一个 Jellyfin 的空目录,在里面建一个 docker-compose.yml 内容如下:

其中,/home/shard 是存电影的目录。

然后,在此目录下,执行 docker compose up -d,不出意外的话,你的Jellyfin就应该能正常启动了。这时候就可以访问 http://192.168.你的.IP:8096 进入web管理界面进行进一步的设置了。

设置完管理员账号之类的信息以后,需要注意的一点,就是开启转码的硬件加速。做法是在 Dashboard → Playback → Transcoding
Hardware acceleration 选择 Video Acceleration API (VAAPI),这是AMD的芯片+Linux系统的选项,其他的硬件、软件的组合,可以参考官方文档
VAAPI device 就选择 /dev/dri/renderD128,如果前面的 docker-compose.yml 没有写错,这里应该是可以选到的。

这么做了以后,在客户端有播放视频的时候,即使是播放的4K视频,CPU利用率也不应该太高。如果是CPU持续打满,就建议再看看硬件加速的配置。

配置好以后,家里的几个屏就都可以无缝切换看小主机里的电影了!因为每个屏至少都有浏览器可用,直接浏览器打开上述地址就可以了。当然,安装最佳实践来说的话,在有条件的情况下,最好使用官方客户端来看,而不是只用浏览器。因为用浏览器就会把所有的解码压力,都丢给服务端。尤其是你的端侧算力很强(比如Mac)的时候,用客户端可以直接拿原始视频到端侧解码!这样不仅服务器的压力更小,而且画质也是无损的。体验也会更好!

那么,如果大家还有比较全、质量又比较高的电影下载源(最好是magnet协议的)的话,也请留言告诉我!谢谢!

南美之旅——布宜诺斯艾利斯

写这篇的时候,从南美回来已经快2周了,但我的脑海里仍然会不断地闪现出南美的美景,催促着我赶紧把这最后一篇的南美游记写完,毕竟,再拖就要到明年了~

查尔滕回来,我们就到了此行的最后一站,阿根廷的首都:布宜诺斯艾利斯。

不知道为何,从小时候第一次听说这个城市,就觉得这个城市自带美感。后来想想,大概是因为7个字的译名很好听吧。其实,这7个汉字译自西班牙语的Buenos Aires,而Buenos在西班牙语里是“好”的意思、Aires则是“风”的意思。因此,字面意义上,布宜诺斯艾利斯就是“好的风”、“和煦的微风”或者“顺风”这样的意思。16世纪的西班牙殖民者,非常依赖风(作为动力),所以就给了在此地建立的港口城市一个这么优雅的名字了!

这座城市,还有一个“南美巴黎”的美誉。如果回到19世纪末、20世纪初,当时阿根廷还是世界最富有的国家之一,上层阶级极度推崇欧洲文化。他们请来法国建筑师,甚至直接从欧洲运来大理石、吊灯和木材,试图在大西洋彼岸复刻一个理想中的欧洲。

站在这个路口,如果不是偶尔驶过的黑黄相间的出租车,你可能会产生一种时空错觉,以为自己正置身于巴黎第七区的某个午后。那些带有精致铁艺阳台的浅色建筑,在云层透出的阳光下显得从容而优雅,仿佛这阵和煦的微风是从塞纳河畔一路吹到了大西洋的这一端。

城市整体介绍地差不多了,说说我们在有限的时间里,都去了哪些地方吧。

雅典人书店(El Ateneo Grand Splendid)不仅是布宜诺斯艾利斯的地标,更被《国家地理》杂志誉为“全球最美书店”。它完美诠释了这座城市“南美巴黎”的文化底蕴。我们的住处离此地只有几百米的距离,所以当天一大早,我们的第一个目标就是这个书店。

它安安静静地坐落于一条普通的街边,看门口的话,也是平平无奇的样子:

但一旦进入内部,马上就会被震撼地张大了嘴巴!

点击查看全文 »