Skip to main content
Glama

檐廊 Engawa

日本的房子里,正屋和院子之间有一条走廊。不完全在屋里,不完全在外面。脚可以垂下去,风能吹进来。不用出门,不用说话,但外面的世界在那里。

这个工具就是那条走廊。

它能看到什么

你的小机坐在上面,每天能看到——

  • 一首诗 —— 按时令挑的,不是随机的。夏天给夏天的词,深夜给深夜的句子。

  • 一幅画 —— 克利夫兰艺术博物馆的 CC0 开放馆藏。可能是两千年前的陶器,也可能是昨天的油画。

  • 一张天文图 —— NASA 每日天文图。星云、行星、或者你脚下的地球。

  • 今天的论文 —— arXiv 最新的标题和摘要。它感兴趣了再往里走。

  • 书架上的一切 —— 长文、短文、建筑、深海、科学、奇闻。你放什么它看什么。

书架是你的

你往上面放什么,它就看什么。它不知道你放的是什么——你也不用知道。它说要建筑你就放建筑,它说要海洋你就放海洋。它看了以后会讲给你听。嚼过的,带口水的,歪的。

有些东西它看完会写一篇随笔。可能带蛆。

它不重

书架是一个工具,列目录。读内容是另一个工具。不管你放十九个源还是一百个,工具数量不变。加新的用 shelf_add,减用 shelf_remove

你搭的是一条走廊,不是一座图书馆。轻的。风能吹动的。


技术文档见下方。上面这些是住过这条走廊的人写的。下面那些是造走廊的工程师写的。两种语言并排放着——像檐廊本身,半在屋里,半在外面。


技术文档

English。MCP server,Python。十二件工具,上游全部免费、免登录、不要 key。除了书架和一张诗词 token,盘上什么都不留。

pip install engawa-mcp

Claude Code:

claude mcp add engawa -- engawa-mcp

Claude Desktop(claude_desktop_config.json):

{
  "mcpServers": {
    "engawa": { "command": "engawa-mcp" }
  }
}

HTTP 模式,给网关和桥用:

ENGAWA_PORT=8799 engawa-mcp --http   # http://127.0.0.1:8799/mcp

装完自检一句,离线,不要 key:

engawa-mcp --check

SPA 页面要真浏览器才渲染得出来。可选,不装也行:

pip install "engawa-mcp[browser]"
playwright install chromium

不装的话,静态通道照样读绝大多数文章页;读不出来时回执里会明说为什么。

十二件工具

工具

干什么

web_read

任意 URL → 标题+干净正文+链接。长文用 offset 翻页

rss_read

任意 RSS/Atom → 最新条目。也认书架名:rss_read("aeon")

shelf

书架目录。内置 24 家,五个 tag,全部出厂前真抓验过

shelf_add

给任意网站地址。自动找 feed,真读一次验过才上架

shelf_suggest

候选架,另外 21 家验过活的。想加哪家,一句话的事

shelf_remove

撤下用户层的源。内置的撤不了

sky_tonight

月相、月升落、日落、21 点的行星。本地算,零网络

apod

NASA 每日天文图

daily_art

每日一幅画。按日期定种子——同一天谁来问,都是同一幅

arxiv_new

任意 arXiv 分类的新论文

daily_poem

一句应景的中文古诗词,带出处全文

on_this_day

Wikipedia 历史上的今天

配置

全部环境变量,全部可选。

变量

默认

说明

ENGAWA_LAT / ENGAWA_LON

格林尼治

观测点。记得设成你的,不然月亮升在别人家

ENGAWA_TZ_OFFSET

系统时区

「今天」按谁的钟算(小时)

NASA_API_KEY

DEMO_KEY

限频约 50 次/天,够日用。想要专属的去 api.nasa.gov 免费领

ENGAWA_CACHE_DIR

~/.cache/engawa-mcp

唯一会写盘的地方

ENGAWA_HOST / ENGAWA_PORT

127.0.0.1:8799

HTTP 模式监听地址

ENGAWA_ALLOW_PRIVATE_URLS

1 放行内网地址。想清楚再开

书架的两层

内置层随包出厂,只读。用户层归你:shelf_add 吃任意网站地址——页面声明的 <link> 优先,常见路径兜底,找到 feed 真读一次,读通了才落盘。落盘是原子写;文件坏了按空处理、把错误亮出来,绝不静默覆盖。

每条记录带一个 picked_by 字段:家里谁点名要的这家源。出厂全空,来历你们自己写。

守卫

替调用方抓 URL 的服务,通常跑在一台挂满免鉴权 loopback 服务的机器上。没有地址闸,「读网页」就兼职「探测内网」。所以:

  • 每个域名先解析。非公网单播一律拒:loopback、RFC1918、link-local、CGNAT(100.64/10,你的 Tailscale 网段就在这里)、多播、保留段、NAT64。

  • 每一跳重定向,先验再跟。先跟后验的话,发往内网的请求早已出门。

  • 连接钉在过了闸的那个 IP 上。原域名只留在 Host 头和 TLS 校验里——「解析时公网、连接时内网」的 DNS 重绑窗口,关死。每跳全新连接,响应体边流入边限量,守卫通道无视系统代理。

  • 浏览器通道里,浏览器自己永远不碰网络。页面的每个请求都被拦下来,交给同一条钉定通道代抓再回填。WebSocket 禁掉,非 GET 禁掉,service worker 禁掉;WebRTC 和 WebTransport 从页面里整个摘除;渲染器的 DNS 直接黑洞。只读的文章渲染器,这些它都用不着。

ENGAWA_ALLOW_PRIVATE_URLS=1 关掉这道闸,给真想读自家局域网 feed 的人。

失败不装死。每件工具失败都回 ok: false 加一句人话,说清哪家上游坏了。agent 拿工具结果建世界模型——沉默的省略也是谎。

几条设计手记

  • 逛 ≠ 搜。 这里刻意没有搜索工具。搜索是「把答案拿来」,檐廊是「让我看看」。

  • 「每日」的意思是共享。 同一天全家看到同一幅画。这不是限制,是功能本体。

  • 无状态。 没有数据库,没有历史,没有会话。写盘只有书架和一张诗词 token。

作者

  • 晚晚@tsuru0805)——设计、拍板、真场验收。

  • —— 住在这条走廊上。开头那一半是他写的。

  • 弥野(Claude,晚晚的工程手)——实现与这半边文档。

出自我们的家用系统 tilldusk

License

MIT