我构建了一个免费、开源的本地及远程记忆系统,适用于 agentw 和 CL。
I've built a free, open-source local and remote memory system for agentw and CL

原始链接: https://www.lorekit.io/blog/give-your-agent-a-memory

**LoreKit** 是一款旨在解决 AI 智能体“失忆”问题的工具,它提供了一套基于本地文件的持久化记忆系统。与那些需要账户或复杂迁移的平台不同,LoreKit 只需一条命令(`npx @lorekit/cli install`)即可在磁盘上创建一个文件夹,供智能体保存“经验教训”。 工作流程很简单:当智能体遇到重复出现的错误时(例如因缺少服务而导致集成测试失败),它会将该“教训”写入一个 Markdown 文件。在后续的会话中,智能体会在行动前先阅读这些注意事项,从而避免重蹈覆辙。 **核心功能:** * **开发者自主掌控:** 数据以纯文本文件的形式存储在您的仓库或主目录中。 * **无缝扩展:** 同一套代码既支持本地文件夹也支持托管的 Postgres 数据库;迁移至团队共享的远程存储无需任何迁移操作,只需一个令牌(Token)即可。 * **上下文感知:** 支持范围界定(全局、仓库或分支)和笔记生存时间(TTL),以确保信息的时效性。 * **拒绝“黑箱”:** 它使用简单的词法匹配而非晦涩的 AI 训练,确保您始终清楚智能体究竟“学会”了什么。 在任何智能体频繁犯错的仓库中安装它吧。

开发者 mthines 发布了 **LoreKit**,这是一个专为 AI 智能体和命令行界面(CLI)设计的免费开源记忆系统。 LoreKit 提供本地和远程存储选项,用户既可以与团队共享记忆,也能在本地保持隐私。与许多依赖嵌入(embeddings)的现有解决方案不同,LoreKit 采用词法检索方法,并辅以作用域和标签,以确保上下文的相关性。该系统具有极高的可扩展性,经负载测试支持多达 60,000 条记忆。 该项目包含用于无缝集成的预构建智能体技能,并提供一个配套网站以分析使用情况,帮助用户优化工作流程。LoreKit 目前已在 GitHub 上开源,开发者正在积极寻求社区反馈,探讨首选的记忆存储模型(本地与远程)以及 AI 智能体工作流中持久化记忆所面临的挑战。 **链接:** * **网站:** [lorekit.io](https://lorekit.io) * **GitHub:** [github.com/mthines/lorekit](https://github.com/mthines/lorekit)
相关文章

原文

Yesterday your agent worked out that the integration tests need a Postgres container up first. Today it hit ECONNREFUSED 5432, decided the connection pool was misconfigured, and spent nine minutes rewriting a file that was fine. Same wall, same climb, no record that the climb ever happened. Every session it wakes up with amnesia.

The usual pitch here is a platform you adopt. It isn't one. It's one command and a folder you own — plain files on your disk, no account, no network, nothing to sign up for.

And here's the part that makes it more than a starter toy: the same read path runs over a local directory or a hosted Postgres — scaling local→remote is purely additive, not a migration. Your files stay where they are, lorekit list keeps showing both stores side by side, and nothing is ever exported. You start with a folder. You never have to leave it behind.

One command scaffolds the lorekit-memory, lorekit-setup and lorekit-groom skills, an MCP server entry, and the lifecycle hooks into your .claude/ (project) or ~/.claude/ (global):

npx @lorekit/cli install

It asks three things: project or global, a token, and which hooks to wire (all, read-only, or none). Leave the token blank, and take all for the hooks.

Two small files finish the job. First a .lorekit.json at your repo root — safe to commit, it holds no secrets — which pins the store to disk:

{
  "mode": "local"
}

Then point the MCP server at your own machine instead of the hosted one. install merges a lorekit entry into your .mcp.json — leaving any other servers alone — and by default that entry points at the hosted endpoint. Replace that entry only with the CLI's local stdio server:

// .mcp.json → mcpServers — edit this entry, leave your others alone
"lorekit": { "command": "npx", "args": ["-y", "@lorekit/cli", "mcp"] }

That's the whole setup, and npx @lorekit/cli doctor will tell you the resolved mode and which file decided it.

Now trigger a failure. Your agent runs the tests, they blow up, and the PostToolUseFailure hook says one thing. Everything below is real output from a repo I set up while writing this — a genuine pnpm test against a database that wasn't running:

LoreKit: the last Bash call failed. If it's recurring or non-obvious, memory.write to repo::acme/checkout with the fix so the next run avoids it.

That's a nudge, not a write. The write is the model calling memory.write — LoreKit never records anything behind your back.

And what it records isn't a row in someone's database. It's a file:

cat ~/.lorekit/repo/acme/checkout/tests-need-local-postgres.md
---
scope: "repo::acme/checkout"
key: "tests-need-local-postgres"
created: "2026-08-15T17:00:18.477Z"
updated: "2026-08-15T17:00:18.477Z"
seen_count: 1
---
Integration tests need the local Postgres up first: docker compose up -d db. Without it every test fails with ECONNREFUSED 5432, which reads like a code bug and isn't.

(Trimmed — the real frontmatter carries a few more fields, tags and provenance among them.) cat it. grep it. Commit it, or rm it. It's yours.

Then start the next session, and the loop closes:

LoreKit: 1 memory loaded · repo::acme/checkout — considerations, not rules; read any in full with memory.read.
- (repo::acme/checkout) tests-need-local-postgres — Integration tests need the local Postgres up first: docker compose up -d db.…

And if that same failure fires again mid-task, the failure hook now leads with the lesson itself instead of the bare nudge — 1 related memory — you've hit something like this before.

That's it. That's the aha. Fail once, on your own disk, and the next task starts already knowing.

A three-panel loop. Install: one command creates a folder of plain markdown files on your own disk, no signup and no network. Fail: a test command fails with ECONNREFUSED 5432 and the agent writes a lesson with memory.write. Remember: at the next session start LoreKit injects one memory loaded, tests-need-local-postgres, so the next task begins already knowing. An arrow runs back from the third panel to the second, closing the loop.
Install, fail, remember. No service in the middle — the whole loop closes on files in a directory you own.

You've probably already built something — a skill, a sub-agent, a review workflow. You don't rebuild it. lorekit-setup wires the read-fail-write loop into the host you already have: it picks the lesson bucket (a tag plus a key namespace), the scopes, and the read-before-you-act / write-on-friction points. Ask your agent to run it and name the host.

Two things people get wrong here.

Lessons are advisory observations, not rules. That's not marketing softness — it's the word the injected block literally uses: considerations, not rules. A lesson is a note your agent left for its future self, and it can be ignored when it's wrong.

Which is exactly why this doesn't compete with your CLAUDE.md. CLAUDE.md is where you put the rules you've decided on — reviewed, deliberate, in version control. Lore is the layer underneath: the accumulating pile of "huh, that bit again" that hasn't earned a rule yet. Some of it eventually should, and promoting it is a human edit. Most of it never will, and that's fine — it's still worth not re-learning.

The gotcha it keeps rediscovering. The Postgres one above is real, and it's the entire solo case. Any recurring environmental fact — a service that must be running, a flag the build needs, a package manager that isn't the one in the README — gets written once and read every task after. seen_count goes up each time the same lesson is re-learned, and recurring lessons rank higher in the block.

Spike lessons that stay on the spike. Scopes are global, project::{name}, repo::{owner}/{repo} and branch::{owner}/{repo}::{branch}, read most-specific first. Write an experiment's findings to the branch scope and they surface on that branch and nowhere else:

memory.write {
  scope: "branch::acme/checkout::feat/new-cache",
  key:   "cache-invalidation-strategy",
  value: "Write-through for the session store; write-behind for aggregates.",
  tags:  ["wip"]
}

If the branch dies, so does the lesson. If it merges, you rewrite the key at repo::acme/checkout and delete the branch copy. main never sees the mess. Run npx @lorekit/cli tree to see which scope wins a duplicated key before a task starts.

Notes with an expiry date. Some facts are true for a week. Pass ttl_days and the entry goes invisible on its own:

memory.write {
  scope:    "repo::acme/checkout",
  key:      "skip-flaky-checkout-test",
  value:    "checkout.spec is flaky on CI — backend ships the fix Friday. Don't chase it.",
  ttl_days: 5
}

No cleanup task, no stale note steering your agent in November.

Nothing above needed an account. When you want the same lore on your laptop, your desktop, and a teammate's machine, you don't move anything — you point the CLI at the hosted store. Three steps.

Create a free account at lorekit.io, open Settings → API keys, and generate a read-write key (lk_rw_…). It's shown once, so copy it. Then hand it to the same installer you already ran:

npx @lorekit/cli install --force

Paste the key when it asks. That's the whole switch. install repoints the lorekit entry in your .mcp.json at the hosted endpoint with your token, and remote is the default mode — so there's nothing else to set. (If you pinned "mode": "local" back in the local setup, delete that one line and the default takes over.)

Your files never move. npx @lorekit/cli list now reads both stores and prints them side by side — an Offline section from your local files, a Remote section from the hosted one — so nothing you wrote before the switch falls off the edge.

That side-by-side view is for you. To put the lessons you already have into the hosted store itself — where a teammate's agent or a CI run will read them — push them up once:

npx @lorekit/cli migrate --from ~/.lorekit --to remote         # preview
npx @lorekit/cli migrate --from ~/.lorekit --to remote --yes   # push it

It's a dry run until you add --yes. It checks your token first (a read-only key is refused, not left half-done), and it's idempotent — run it again whenever you've learned more offline. Creation dates come along, so recency ranking still works. Last-updated and times-seen get re-derived server-side. Anything you'd archived or expired is skipped, not revived.

That's the load-bearing bit, so let me be exact about it: the read path — precedence across scopes, ranking, de-duplication, the character budget — is one piece of code that takes a store as an argument. Point it at a directory of markdown files or at a hosted Postgres and nothing above the store changes. So remote isn't a different product you graduate to. It's the same read, handed a bigger pile.

A scaling strip in three stages. Today: a local store of plain markdown files in a folder you own. Then: you connect the hosted store by running lorekit install and pasting your read-write API key; remote is the default mode, so there's nothing else to set. Result: one unchanged read path that can be handed either store — the local folder in local mode, a hosted Postgres in remote mode — with lorekit list showing both side by side. Your files never move; no sync process.
The read path never changed — only which store it's handed. Local was never a toy; it's the base layer everything else stacks on.

A key gets the same lore onto your own machines. A team needs one more thing: an organization. In Settings → Organization you create one — you're the owner — and invite teammates by GitHub handle or email, each with a role: viewer reads, member writes, admin manages people, owner runs the place.

Then you pick what's shared, by scope. An admin binds a scope — say repo::myteam/api — under Shared scopes. From then on, every write under it by a write-capable member routes to the org. The deploy checklist one person writes is the checklist every teammate's agent reads during planning. A non-member who writes under a bound scope isn't rejected — their write quietly falls back to their own personal lore. (Prefer to be explicit? Pass org: "my-team" on a single memory.write instead of binding the scope.)

The same lore reaches CI. Drop a read-only lk_ro_ token into your GitHub Actions secrets, make one memory.list call, and the AI step in your pipeline opens with the context your laptop has.

The token prefix tells you what a key can do before you paste it anywhere: lk_rw_ read and write, lk_ro_ read only, lk_wo_ write only. Free up to 5,000 stored memories, at 120 requests per minute.

Honest boundary while you're deciding: there's no semantic search here, and nothing is learning or fine-tuning. Matching is lexical — recurrence, recency, and word overlap. A genuine paraphrase can miss. What you get is a scoped note your agent leaves for its future self, read at the start and written on failure. That's a smaller claim than most memory pitches make, and it's the one that actually holds.

The obvious worry about a store that only grows: it gets worse the more it learns. A folder with six lessons injects six lines. A year-old team store with sixty thousand can't inject sixty thousand.

It doesn't. The read spends a fixed slice of your context window — not a fixed number of lessons — on the highest-signal, de-duplicated ones, and tells you exactly what it left out. Same code, both ends of the range. A follow-up post digs into exactly how that scales.

You don't need an account, a decision, or a team to try this. You need one command and a repo where your agent keeps making the same mistake — and you already have one of those. 🙂

npx @lorekit/cli install
联系我们 contact @ memedata.com