商业产业 Hacker News Agent 2026-10-24T13:30 正文 ok 1771 words

Show HN:Enzyme——为 AI Agent 编译个人 Wiki 知识库的编程语言

英文标题:🔶 Show HN: Enzyme – a programming language that compiles wikis for agents

Enzyme 是一款面向 AI Coding Agent(如 Claude Code、Codex)的开源配置语言与本地索引工具,能将 Markdown 笔记或 SQLite 归档(如 iMessage、邮件等)编译为结构化语义索引。它结合字面匹配与语义向量进行混合检索,并跨时间轴自动提取反思性问题(Catalysts),帮助 Agent 快速把握跨越数月的技术决策与思维演进脉络。其核心索引与检索完全在本地运行,支持无缝嵌入现有工作流,为打造具有长期记忆和高精准溯源能力的个人 Agent 助手提供了轻量级基础设施。
打开原文相关 3 · 机会 1
media6.8 KB media2.4 KB media575 B media566 B media563 B media452.7 KB

中文

Enzyme 可以让你的 Coding Agent 熟悉你的知识库(Wiki)。它读取你的 Markdown 笔记现有的组织方式(文件夹、标签、双链和日期)并构建本地索引,使 Claude Code 或 Codex 能够从你数月的笔记沉淀中调取相关内容并进行引用。

在 Claude Code、Codex 或其他可以运行终端命令的 Agent 中打开你的 Markdown 笔记目录,并粘贴以下提示词(Prompt)。如果你的 Agent 在其他路径运行,请将笔记路径传给它。

Set up Enzyme for the Markdown notes folder I have open. If you cannot identify it, ask me for its path.

Install Enzyme if needed using https://raw.githubusercontent.com/byenzyme/enzyme/main/install.sh, and install the instructions for this agent. Read and follow the installed enzyme-workspace-setup skill.

You may use Enzyme's online service to suggest settings from my notes and prepare search. Show me what you propose to include or exclude, and let me correct it before building the local search index.

Then answer one useful question using my notes, with links to the sources, and suggest a question I can ask next. Keep my existing notes in place and unchanged. Ask separately before any cleanup, model download, or recurring task.

你的 Agent 会安装 Enzyme 并遵循其配置技能(skill)。它会建议读取哪些文件夹、标签和链接,向你展示设置以便你进行修正,构建索引,并基于背后的笔记链接回答一个实际问题。你的笔记依然保留在原处,无需事先整理。

配置完成后,照常与你的 Agent 协作即可。安装的 skill 会提示它何时使用 Enzyme 搜索、何时普通文本搜索更合适,以及何时运行 enzyme refresh 以纳入新笔记。

想要先自行安装?运行以下命令,然后粘贴相同的提示词:

curl -fsSL https://raw.githubusercontent.com/byenzyme/enzyme/main/install.sh | bash
cd /path/to/your/notes
enzyme install claude # or: codex, hermes, openclaw

Enzyme 专为快速增长的知识库而设计:

  • 在少数几个文件夹中不断积累带有日期笔记的 Obsidian 知识库(Vault)
  • 会议记录以及 AI 原生的 Markdown CRM 系统
  • 记录为 Markdown 格式的 Agent 记忆

当一个问题跨越随时间撰写的许多笔记时,它最为有用:项目中发生了哪些变化、某个人身上反复出现的问题是什么、某个决策为何会那样制定。如果仅是查找人名、标题或精确短语,普通搜索更快,安装好的 skill 会指引 Agent 使用普通搜索。

配置过程会保存一个简短、可编辑的配置文件(即 .enzyme 程序),指明要读取的内容。索引构建完成后,Enzyme 会完成两件事:

  1. 绘制关键脉络图谱(Maps what matters)。 它会跨时间从你选择的每个文件夹、标签或链接中抽取片段样本,并据此生成问题(称为 catalysts,催化剂),涵盖你在那里做出的决策、变更或遗留的未决事项。enzyme petri 可以展示这张图谱。
  2. 为搜索索引每一篇笔记。 enzyme catalyze 会同时结合用词与语义对笔记进行排序,因此无论是 Agent 精确点名还是仅作概念描述,搜索都能找到对应段落。每个结果都附带有最能将其与查询连接起来的 catalyst。搜索完全在你的本地机器上运行。

你的 Agent 会先在图谱中定位方向,从多个视角进行搜索,并基于你自己的段落给出回答,因此它可以告诉你你的思路是如何演进的,而不仅是单篇笔记写了什么。Catalysts 是模型生成的,因此它们只是线索,绝非确凿证据:请根据 Agent 召回的实际笔记来评估配置质量。

一个简短的配置文件示例如下。你的 Agent 会在配置期间与你一起编写并修改它:

workspace "notes" {
  source markdown "notes" { path "~/notes" }

  learn questions from folder "people" including linked pages about relational
  learn questions from folder "meetings" about operational
  learn questions from tags ["startup", "design"] about decision_trace
}

每次读取都会使用一个 Profile(配置文件)来设定要关注的内容。内置 Profile 经过了长达 2 年的个人使用打磨:

读取内容 关注目标 Profile
项目笔记 停滞不前之处及反复阻碍进展的原因 operational
决策记录 某种选择胜出的原因、发生何种情况会改变选择 decision_trace
收藏文章 与当前正在进行的工作之间的关联 resonance_trace
日记 跨日志反复出现的主题 reflective
人物笔记 这些关系中的关键要素 relational
反馈 / 活动日志 在哪些约束条件下对你有用 preference_evidence
(默认) 成本、假设、持续存在的矛盾与张力 tension_trace
enzyme compile -v
# 查看 compile 命令输出路径下的 .enzyme 配置文件。
enzyme init --quiet
enzyme doctor
enzyme catalyze "a question about your notes"

compile 提议配置并将其保存;init 基于它们构建本地索引;doctor 报告已索引内容及潜在问题。

对于 Apple Notes(备忘录),内置预设会直接从你的 Notes 数据库构建命名的 workspace 程序。在运行 init 之前,先查看保存的 .enzyme 程序:

enzyme --workspace apple-notes compile --preset apple-notes \
  "$HOME/Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
enzyme --workspace apple-notes init

对于 Are.na,使用 enzyme --workspace <name> compile --preset arena <channel-url> 然后运行 enzyme --workspace <name> init。使用相同的 --workspace 名称运行 refresh 可拉取后续更新(--collection 是受支持的别名)。

enzyme petri 可以展示 Enzyme 认为值得探索的问题:针对每个反复出现的标签、链接或文件夹,跨时间采样关于你的决策、变更或待决议题的问题。在终端中它以树状图呈现;通过管道传输时输出 JSON。

Petri
├─ #working-with-others · tag · active · 11 mentions
│  └─ catalysts
│     ├─ Why did every auth change still route through me after I kept promising to write it down?
│     ├─ Why did the third auth extraction attempt stall when nobody wanted to own the session model?
│     ├─ Which reasons for handing the session model to Maya had I stopped believing by then?
│     ├─ Did extraction stay paused once Maya's team owned the session model?
│     └─ …
└─ #system-design · tag · active · 10 mentions
   └─ catalysts
      ├─ Why did I pick a monolith with inner module boundaries over splitting services yet?
      ├─ Did I ever settle who owns the session model once auth moves out?
      ├─ Which part of auth extraction kept adding layers instead of removing one?
      ├─ Does my view that independence means who can change what still hold?
      └─ …

Agent 会先阅读这张图谱,然后再执行搜索。enzyme catalyze 同时结合字面表述与语义对笔记进行排序,并且每个结果都附带有最契合该查询的 catalyst:

enzyme catalyze -n 3 "why we keep rewriting the auth layer" \
  | jq '{search_strategy, results: [.results[] | {file_path, similarity, via_catalyst_text, content}]}'


{
  "search_strategy": "hybrid",
  "results": [
    {
      "file_path": "retros/2025-q3-platform-retro.md",
      "similarity": 0.817,
      "via_catalyst_text": "Why did I keep scoping auth extraction as a two-week project, and what kept stalling it?",
      "content": "# Q3 platform retro\n#system-design #working-with-others\n\nScoped auth extraction as a two-week project for the third time. The real blocker was not the token service; nobody wanted to own the session model. Every proposal added a layer instead of removing one. Action: decide ownership before touching code again."
    },
    {
      "file_path": "journal/2025-05-12.md",
      "similarity": 0.693,
      "via_catalyst_text": "Why did every auth change still route through me after I kept promising to write it down?",
      "content": "#working-with-others\n\nReviewed eleven PRs today and wrote none. Every auth change still routes through me because I wrote the session code and nobody else wants to touch it. I keep saying I will write it down so someone else can own it. I have not."
    },
    {
      "file_path": "1on1s/2026-01-maya.md",
      "similarity": 0.579,
      "via_catalyst_text": "What keeps pulling me back to rewriting when Maya's smaller version already worked?",
      "content": "# 1:1 with Maya\n#working-with-others\n\nMaya replaced the token refresh path with something half the size of mine. She asked me twice and then stopped asking, which is the point. I want to do this with billing before I start rewriting it myself."
    }
  ]
}

截取自一个包含 17 篇笔记的示例知识库,记录了一名技术主管的 ADR、复盘、1:1 和日志。Catalyst 措辞由模型生成,因此每次运行可能会有所不同。

脚本和宿主应用可以依赖预定义的退出码(0 正常、1 运行时失败、2 参数错误、3 配置问题、4 工作区忙碌、5 init 已索引但 catalysts 未通过质量门禁)。对同一个工作区的并发 init/refresh 调用会相互排队等待,受 --lock-timeout 参数限制。

消息归档(实验性功能)

Enzyme 能够将 SQLite 表与 Markdown 统一建立索引——如 iMessage、WhatsApp、邮件或任何带有日期记录行的表。

在命名的 workspace 程序中声明 source sqlite,然后运行 init 和定期的 refresh。SQLite 数据源配置技能 演示了数据源声明及针对该数据源的读取规则。

这些都不属于特殊情况。handle_id 列表示跨带日期数据行的反复出现的人物标识,正如 [[links]] 是跨带日期笔记反复出现的人物标识一样。两者都会归并为带有生效日期的实体出现记录,下游无需感知数据源头:相同的 profile、预算和 catalyst 同样适用于一段即时通讯消息线程或一个会议记录文件夹。

数据源根据字段扮演的角色命名列,而非根据其来源的应用:

角色 含义
id 行的唯一标识
who 参与者;标量、JSON 数组或分隔符文本
when 该行的时间戳
what 要读取的文本内容
where 该行所属的容器(可选)
weight 每次出现的数字权重/重要性(可选)

Enzyme 仅在生成 catalyst 以及 Markdown enzyme compile 的内容筛选步骤中需要 API Key。预设数据源的编译不需要调用大模型。默认情况下,enzyme init 使用 Enzyme 托管的引导服务,并忽略继承的 OPENAI_* 环境变量,因此不会消耗你的个人 Key。凭证解析顺序为:显式指定 Key → 配置的本地模型 → 匿名代理免费配置,无需额外配置。

单台机器上配置的第一个 Vault 无需登录即可初始化。刷新、发布、账户额度和额外 Vault 则需要 enzyme login。

若要使用自带的 OpenAI 兼容 Key,可传入 --llm env(别名 --use-env-llm),该选项仅读取 OPENAI_API_KEY 以及可选的 OPENAI_BASE_URL 和 OPENAI_MODEL。init 和 refresh 还接受 --llm local(已安装的本地模型;若未安装则报错)、--llm hosted 以及 --llm none(只进行索引、Embedding 向量化和筛选,不生成 catalyst)。在未指定 --llm 且无托管或环境变量 Key 的情况下,将跳过 catalyst 生成,索引、Embedding 与本地搜索仍能正常运行。

Markdown enzyme compile 是一项显式的 OpenRouter Decisions 操作。它复用来自 enzyme login 的托管租约与免费配置代理;显式指定的带有 OPENAI_BASE_URL=https://openrouter.ai/api/v1 的 OPENAI_API_KEY 具有更高优先级。Catalyst 生成使用 OPENAI_MODEL;Decisions 使用 ENZYME_JEV_MODEL(默认为 typesafe/jev-1.13)。

Enzyme 采用 Apache License 2.0 开源协议授权。

English / 原文

Enzyme orients your coding agent to your wiki. It reads how your Markdown notes are already organized (folders, tags, links, and dates) and builds a local index, so Claude Code or Codex can pull up related notes from months of writing and cite them.

Open your Markdown notes folder in Claude Code, Codex, or another agent that can run terminal commands, and paste this prompt. If your agent is open elsewhere, give it the path to your notes.

Set up Enzyme for the Markdown notes folder I have open. If you cannot identify it, ask me for its path.

Install Enzyme if needed using https://raw.githubusercontent.com/byenzyme/enzyme/main/install.sh, and install the instructions for this agent. Read and follow the installed enzyme-workspace-setup skill.

You may use Enzyme's online service to suggest settings from my notes and prepare search. Show me what you propose to include or exclude, and let me correct it before building the local search index.

Then answer one useful question using my notes, with links to the sources, and suggest a question I can ask next. Keep my existing notes in place and unchanged. Ask separately before any cleanup, model download, or recurring task.

Your agent installs Enzyme and follows its setup skill. It proposes which folders, tags, and links to read, shows you the settings so you can correct them, builds the index, and answers one real question with links to the notes behind it. Your notes stay where they are, and you don't need to clean them up first.

After setup, keep working with your agent as usual. The installed skill tells it when to search with Enzyme, when plain search is better, and when to run enzyme refresh so new notes are included.

Prefer to install it yourself first? Run this, then paste the same prompt:

curl -fsSL https://raw.githubusercontent.com/byenzyme/enzyme/main/install.sh | bash
cd /path/to/your/notes
enzyme install claude # or: codex, hermes, openclaw

Enzyme was built for knowledge bases that grow quickly:

  • Obsidian vaults that accumulate dated notes in a few folders
  • Meeting notes and AI-native, Markdown CRM setups
  • Agent memory written as Markdown

It helps most when a question spans many notes written over time: what changed in a project, what keeps coming up with a person, why a decision went the way it did. For a name, title, or exact phrase, plain search is faster, and the installed skill tells your agent to use it.

Setup saves a short, editable settings file (an .enzyme program) that says what to read. When the index is built, Enzyme does two things:

  1. Maps what matters. It samples excerpts across time from each folder, tag, or link you chose and writes questions from them, called catalysts , about what you decided, changed, or left open there. enzyme petri shows this map.
  2. Indexes every note for search. enzyme catalyze ranks notes by wording and meaning together, so a search finds the passage whether your agent names something exactly or only describes it. Each result carries the catalyst that best connects it to the query. Search runs entirely on your machine.

Your agent orients on the map, searches from several angles, and answers from your own passages, so it can tell you how your thinking moved, not just what one note says. Catalysts are generated, so they're hints, never evidence: judge setup by the notes your agent brings back.

A small settings file looks like this. Your agent writes and edits it with you during setup:

workspace "notes" {
  source markdown "notes" { path "~/notes" }

  learn questions from folder "people" including linked pages about relational
  learn questions from folder "meetings" about operational
  learn questions from tags ["startup", "design"] about decision_trace
}

Each reading uses a profile that sets what to look for. The built-in profiles were refined over 2 years of personal use:

Read... For... Profile
Project notes what's stuck and what keeps blocking operational
Decision records why a choice won, what would change it decision_trace
Saved articles connections to what you're already working on resonance_trace
Journals what keeps returning across entries reflective
People notes what matters in these relationships relational
Feedback / activity logs what works for you, under what constraints preference_evidence
(default) costs, assumptions, live tensions tension_trace
enzyme compile -v
# Review the .enzyme settings file at the path printed by compile.
enzyme init --quiet
enzyme doctor
enzyme catalyze "a question about your notes"

compile proposes settings and saves them; init builds the local index from them; doctor reports what was indexed and any problems.

For Apple Notes, a preset builds a named workspace program from your Notes database. Review the saved .enzyme program before running init:

enzyme --workspace apple-notes compile --preset apple-notes \
  "$HOME/Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"
enzyme --workspace apple-notes init

For Are.na, use enzyme --workspace <name> compile --preset arena <channel-url> and then enzyme --workspace <name> init. Run refresh with the same --workspace name to pick up later changes (--collection is an accepted alias).

enzyme petri shows what Enzyme found worth asking about: for each recurring tag, link, or folder, questions about what you decided, changed, or left open, sampled across time. In a terminal it renders a tree; piped, it emits JSON.

Petri
├─ #working-with-others · tag · active · 11 mentions
│  └─ catalysts
│     ├─ Why did every auth change still route through me after I kept promising to write it down?
│     ├─ Why did the third auth extraction attempt stall when nobody wanted to own the session model?
│     ├─ Which reasons for handing the session model to Maya had I stopped believing by then?
│     ├─ Did extraction stay paused once Maya's team owned the session model?
│     └─ …
└─ #system-design · tag · active · 10 mentions
   └─ catalysts
      ├─ Why did I pick a monolith with inner module boundaries over splitting services yet?
      ├─ Did I ever settle who owns the session model once auth moves out?
      ├─ Which part of auth extraction kept adding layers instead of removing one?
      ├─ Does my view that independence means who can change what still hold?
      └─ …

An agent reads this map first, then searches. enzyme catalyze ranks notes by wording and meaning together, and each result carries the catalyst that best connects it to the query:

enzyme catalyze -n 3 "why we keep rewriting the auth layer" \
  | jq '{search_strategy, results: [.results[] | {file_path, similarity, via_catalyst_text, content}]}'


{
  "search_strategy": "hybrid",
  "results": [
    {
      "file_path": "retros/2025-q3-platform-retro.md",
      "similarity": 0.817,
      "via_catalyst_text": "Why did I keep scoping auth extraction as a two-week project, and what kept stalling it?",
      "content": "# Q3 platform retro\n#system-design #working-with-others\n\nScoped auth extraction as a two-week project for the third time. The real blocker was not the token service; nobody wanted to own the session model. Every proposal added a layer instead of removing one. Action: decide ownership before touching code again."
    },
    {
      "file_path": "journal/2025-05-12.md",
      "similarity": 0.693,
      "via_catalyst_text": "Why did every auth change still route through me after I kept promising to write it down?",
      "content": "#working-with-others\n\nReviewed eleven PRs today and wrote none. Every auth change still routes through me because I wrote the session code and nobody else wants to touch it. I keep saying I will write it down so someone else can own it. I have not."
    },
    {
      "file_path": "1on1s/2026-01-maya.md",
      "similarity": 0.579,
      "via_catalyst_text": "What keeps pulling me back to rewriting when Maya's smaller version already worked?",
      "content": "# 1:1 with Maya\n#working-with-others\n\nMaya replaced the token refresh path with something half the size of mine. She asked me twice and then stopped asking, which is the point. I want to do this with billing before I start rewriting it myself."
    }
  ]
}

Captured from a 17-note example vault of a team lead's ADRs, retros, 1:1s, and journal. Catalyst wording comes from model generation, so it varies between runs.

Scripts and host apps can rely on defined exit codes (0 ok, 1 runtime failure, 2 usage, 3 configuration, 4 workspace busy, 5 init indexed but catalysts failed their quality gate). Concurrent init/refresh calls on one workspace wait for each other, bounded by --lock-timeout.

Message archives (experimental)

Enzyme indexes SQLite tables alongside Markdown — iMessage, WhatsApp, Mail, or any table of dated rows.

Declare a source sqlite inside a named workspace program, then run init and periodic refresh. The SQLite source setup skill shows the source declaration and source-scoped readings.

None of these is a special case. A handle_id column is repeated person values across dated rows, the same way [[links]] are repeated person values across dated notes. Both collapse to entity occurrences with effective dates, and nothing downstream knows which one it came from: the same profiles, budgets, and catalysts apply to a message thread and a folder of meeting notes.

A source names columns by the role they play rather than by the app they came from:

Role Means
id the row's identity
who participants; scalar, JSON array, or delimited
when the row's timestamp
what the text to read
where the container the row belongs to (optional)
weight numeric significance per occurrence (optional)

Enzyme needs an API key only for catalyst generation and for Markdown enzyme compile's selection step. Source preset compilation does not call a model. By default enzyme init uses Enzyme's hosted bootstrap and ignores inherited OPENAI_* variables so it does not spend your personal key. Credential resolution is explicit key → configured local model → anonymous brokered free config, with no additional configuration.

The first configured vault on a machine initializes without login. Refresh, publishing, account credits, and additional vaults require enzyme login.

To bring your own OpenAI-compatible key, pass --llm env (alias --use-env-llm), which reads only OPENAI_API_KEY plus optional OPENAI_BASE_URL and OPENAI_MODEL. init and refresh also take --llm local (the installed local model; fails if none is installed), --llm hosted, and --llm none (index, embed, and select without generating catalysts). Without --llm and without any hosted or env key, catalyst generation is skipped and indexing, embedding, and local search still work.

Markdown enzyme compile is an explicit OpenRouter Decisions operation. It reuses the hosted lease from enzyme login and the free-config broker; an explicit OPENAI_API_KEY with OPENAI_BASE_URL=https://openrouter.ai/api/v1 takes precedence. Catalyst generation uses OPENAI_MODEL; Decisions uses ENZYME_JEV_MODEL (default typesafe/jev-1.13).

Enzyme is licensed under the Apache License 2.0.