关于 plexus
plexus 是面向 AI Agent 的可自托管知识图谱,将信息保存为带类型的实体和有时效的关系。人类可通过仪表板查看,Agent 则通过 MCP 创建、更新和关联内容,适用于跨会话或团队共享记忆。
主要功能
- 01带类型的实体与关系
- 02基于 MCP 写入图谱
- 03全文搜索与关系遍历
- 04时效关系与历史查询
- 05用户、令牌和权限范围管理
- 06图谱检查与技能加载
适用场景
- 01保存跨会话的 Agent 记忆
- 02在不同 Agent 间交接工作
- 03追溯决策及其来源
- 04将研究资料整理为关联知识
MCP 相关
plexus 通过 MCP 暴露 15 个工具,供 Agent 搜索、读取、创建、更新实体并管理关系;访问范围由令牌权限控制。
配置
远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。
https://{plexus_host}/mcpclaude mcp add --transport http pcas-io-plexus https://{plexus_host}/mcp{"mcpServers":{"pcas-io-plexus":{"type":"http","url":"https://{plexus_host}/mcp"}}}在 Cursor 中打开{"servers":{"pcas-io-plexus":{"type":"http","url":"https://{plexus_host}/mcp"}}}在 VS Code 中打开{"mcpServers":{"pcas-io-plexus":{"type":"http","url":"https://{plexus_host}/mcp"}}}{"mcpServers":{"pcas-io-plexus":{"serverUrl":"https://{plexus_host}/mcp"}}}命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。
工具
详细介绍
plexus (_graph)
面向 AI Agent 的类型化本地知识图谱。人类只读,Agent 只写,通过 Model Context Protocol 进行交互。
属于 pcas.io 产品系列。

TL;DR
二十年来,知识管理一直是一场围绕文档展开的运动——文件夹、笔记、Wiki、编辑器之争。plexus 颠覆了这一模式。
在 plexus 中,每条信息都是一个类型化实体——concept、decision、fact、project、task、document、skill,……——实体之间通过严格且有时间效力的边连接。没有自由格式文本,没有被遗忘的标签,也没有“我以后再整理”。写入和链接只能通过 MCP,由你的 Agent 完成。仪表板展示图谱;没有编辑按钮。
这样你就能获得三项优势:
- 你的 Agent 不必询问你——它可以直接构建,并严格遵守类型和关系规范。
- 图谱永不过时,因为 lint、取代和来源记录都属于工作流的一部分。
- 你可以分享单个想法,而不是整个图谱——通过通行密钥保护的一次性链接,首次点击后即失效。
可在你自己的硬件上通过 Docker Compose 运行。采用 Apache-2.0 许可证。
可以把它看作面向大模型的 Wiki
传统 Wiki 是为人类读者构建的:自由格式的文字、手工整理的链接,以及一棵只要停止维护就会腐朽的页面树。在 Wiki 前面放一个大模型,它做的第一件事就是让你总结内容。
plexus 颠倒了受众。大模型既是读者,也是写作者。每个页面都是一条类型化记录,而不是一段文字;每条链接都是一种具名关系,而不是超链接;每次编辑都是一次原子化的 MCP 调用,而不是 Markdown 差异。界面向你展示 Agent 所见的同一张图谱——但由你的 Agent 负责整理。
这与 Andrej Karpathy 在其 "The LLM wiki" gist(2026 年 4 月,5000+ 星标)中勾勒的模式相同:大模型不必每次查询都针对原始文档进行无状态 RAG,而是一次性将知识编译成结构化、交叉引用的 Wiki,并持续更新。plexus 将这一模式落实到基础设施中:
| Karpathy 的 LLM wiki | plexus |
|---|---|
| 原始来源(不变) | Agent 使用 web_fetch、文件 I/O 等读取的外部文档 |
| Wiki(类型化 Markdown,经过整理) | Agent 通过 MCP 写入图谱的类型化实体和具名边 |
架构(CLAUDE.md / AGENTS.md 中的约定) | list_kinds + list_relations 注册表,在 MCP 边界强制执行 |
| ingest → compile → reflect → query → lint | search_entities → save_entity / update_entity → link_entities → get_related → lint_graph |
Karpathy 将这个 gist 称为“想法文件”——一种与供应商无关的提示词模式。plexus 为它提供了生产级后端:类型化存储、乐观锁、时间边、多用户身份验证和审计日志。
由此你可以获得:
- 跨会话的单一事实来源。 你的 Agent 会在每次对话开始时加载上下文。你不必反复解释自己。
- 跨 Agent 的单一事实来源。 Claude web、Claude Code、Claude Desktop、Le Chat、Gemini——无论谁连接进来,使用的都是同一张图谱。
- 跨用户的单一事实来源。 开箱即用的多用户支持、每人独立的作用域令牌、共享的
project容器和审计日志。
目录
了解它
- 使用场景 — plexus 专为七种具体场景打造
运行它
- 快速入门 — 两分钟内通过 Docker Compose 启动
- 创建管理员用户(首次运行) — 引导式操作流程,包括在哪里查找管理员令牌
将 Agent 接入它
- 连接 Agent — Claude 网页版 / Code / Desktop 配置片段
- Agent 系统提示词模板 — 可直接复制粘贴的内容,让大模型正确使用 plexus
- 示例:摄取来源 — 以 Karpathy 风格的大模型维基为例,完整演示如何将内容摄取到 plexus
参考
运维
使用场景
持久化 Agent 记忆。 每次对话都会从 context_load 开始,因此助手会记住你已经做过哪些 ADR、哪些项目正在进行,以及你昨天完成了哪些任务。无需通过提示词工程来让它说“如你所忆……”
跨 Agent 交接。 Claude Code 完成功能后,会写入一条交接事实。第二天早上,Claude 网页版会接续同一上下文,知道哪些提交已发布、还有哪些事项未完成。无需重新介绍情况。
小团队的团队记忆。 启动一个实例,为每个人发放范围受限的个人令牌,并共享一个 project 容器。所有人都可以使用只读仪表板,Agent 为所有人写入内容。不用 Notion、维基,也不必翻查 Slack 考古。
决策考古。 每个 ADR 都是一个一等 decision 实体,并带有 supersedes / derived_from 边。一年后,你可以追溯 F-1 引擎为何保留、Apollo 13 事后分析引发了什么,以及哪些设计取代了哪些设计。通过 get_related(as_of: "2026-01-01") 进行时光回溯查询。
事件 → 修复闭环。 生产事件会成为一条带有 severity: high 的 fact。缓解措施 ADR 通过 triggered_by 关联到该事实。操作手册会 documents 该 ADR。六个月后新员工入职时,他们只需沿图谱遍历一次,无需翻看十二条 Slack 讨论串。
文献 / 研究摘要。 Agent 摄取论文,为来源创建一条 note,提取 concept 和 fact 实体,并附加 mentions 边。你可以按主题查询图谱;每条主张都有来源,可追溯到一条 derived_from 笔记。
Agent 真正会使用的私人“第二大脑”。 使用 inbox_item 捕捉内容,在每周回顾时将其提升为 task / concept / fact,再通过 supersedes 归档。笔记会自动结构化,无需你填写表单。
快速入门
# 1. Clone
git clone https://github.com/pcas-io/plexus.git
cd plexus
# 2. Configure — generates .env from the template with fresh 32-byte
# secrets for all four required fields:
# PLEXUS_ADMIN_TOKEN ← you'll use this once, to bootstrap
# PLEXUS_OAUTH_SECRET ← OAuth state signing
# PLEXUS_COOKIE_SECRET ← dashboard session cookie signing
# PLEXUS_SURREAL_PASS ← SurrealDB root password
scripts/bootstrap_env.sh
# 3. Start
docker compose up -d
# 4. Open the dashboard
open http://localhost:8787
首次登录时需要用到的管理员令牌位于 .env 中:
grep '^PLEXUS_ADMIN_TOKEN=' .env
复制该十六进制值——下一节将介绍一次性引导流程。
完整配置参考见 .env.example。下文还提供 Coolify、纯 Docker 和 Kubernetes 的部署说明。
创建管理员用户(首次运行)
plexus 在空数据库上启动时没有用户。你将使用 PLEXUS_ADMIN_TOKEN 一次来创建首个管理员账户,之后该令牌便不再使用。
1. 查找管理员令牌
你在快速入门中运行的 scripts/bootstrap_env.sh 脚本已将令牌写入 .env。读取该令牌:
grep '^PLEXUS_ADMIN_TOKEN=' .env
# PLEXUS_ADMIN_TOKEN=<64-char-hex>
复制 = 后面的十六进制值。你只需将它粘贴到仪表板中一次;完成引导后,plexus 会拒绝在 MCP 和常规登录中使用管理员令牌。
2. 走一遍流程
| # | 操作 | plexus 的响应 |
|---|---|---|
| 1 | 打开 http://localhost:8787 | 显示登录表单 |
| 2 | 粘贴管理员令牌,点击 Continue | 识别到“管理员令牌 + 不存在管理员用户”→ 重定向到 /bootstrap |
| 3 | 输入管理员名称(字母、数字、_、-、.),点击 Create admin | 创建管理员用户,并仅显示一次新的个人令牌 pt_…。请复制该令牌。 |
| 4 | 点击 Continue to login | 返回 /auth/login,并设置待处理身份验证 Cookie |
| 5 | 粘贴 pt_ 令牌 | 显示通行密钥注册界面 |
| 6 | 点击 Register passkey now,使用 Touch ID / Face ID / Windows Hello / YubiKey 确认 | 保存通行密钥,然后轮换 pt_ 令牌,并仅显示一次新令牌。请覆盖密码管理器中的原有记录。 |
| 7 | 点击 Sign in with new token,粘贴新令牌并轻触通行密钥 | 进入 /home |
从此以后,管理员令牌仅用于管理平面端点(备份、重置)。它在 MCP 中以及普通仪表板登录时都会被拒绝。
为什么要轮换?
初始令牌(管理员令牌和第一个 pt_)是一次性邀请码。如果它们被截获——例如通过邮件、聊天或屏幕共享——轮换令牌会在你登录的那一刻让截获的令牌失效。对于你通过 /users 创建的其他用户,同样的管理员→用户交接流程和首次注册时的令牌轮换也能提供相同保护。
接下来可以做什么
仪表板中的 /help 页面介绍了其他所有内容:MCP 集成、令牌范围、通行密钥管理、共享链接和图谱视图。

连接 Agent
plexus 通过 POST /mcp 使用 Model Context Protocol。任何支持 MCP 的客户端都可以连接。
Claude.ai(网页)
设置 → 集成 → 添加自定义集成 → https://<your-plexus-host>/mcp。plexus 会自动处理 OAuth——你只需查看一次同意界面。
Claude Code(命令行)
claude mcp add plexus --transport http \
--header "Authorization: Bearer pt_YOUR_TOKEN" \
https://<your-plexus-host>/mcp
Claude Desktop
在 ~/Library/Application Support/Claude/claude_desktop_config.json 中:
{
"mcpServers": {
"plexus": {
"type": "http",
"url": "https://<your-plexus-host>/mcp",
"headers": { "Authorization": "Bearer pt_YOUR_TOKEN" }
}
}
}
MCP 工具
plexus 提供 15 个工具。
| 工具 | 用途 | 范围 |
|---|---|---|
save_entity | 创建新实体 | 写入 |
get_entity | 按 ID 获取单个实体 | 读取 |
list_entities | 按条件筛选并列出实体(类型、上下文、状态) | 读取 |
search_entities | 按 BM25 排序的全文搜索,可选择高亮 | 读取 |
update_entity | 使用乐观锁(expected_version)更新实体 | 写入 |
archive_entity | 软删除(状态 → 已归档) | 写入 |
link_entities | 在两个实体之间创建时间边 | 写入 |
unlink_entity | 使边失效(valid_to = now) | 写入 |
get_related | 按方向和时间点筛选遍历边 | 读取 |
list_kinds | 查询类型注册表 | 读取 |
list_relations | 查询关系注册表 | 读取 |
context_load | 会话预热——最近的 20 个实体 + 注册表 | 读取 |
lint_graph | 检查孤立实体和重复标题 | 读取 |
list_skills | 所有技能的精简索引 | 读取 |
load_skill | 按名称、触发短语或 BM25 回退方式加载一项技能 | 读取 |
每个工具都会在处理程序边界强制执行范围检查:requireWrite()、checkContext()、checkKind() 和 rejectSecret()。通过 MCP 无法访问 kind=secret,且所有读取响应都会过滤掉此类内容。

Agent 系统提示词模板
将此代码块粘贴到任何支持 MCP 的 Agent 中(Claude 网页版自定义集成、Claude Code CLI、Claude Desktop、Le Chat、自定义 SDK 测试框架)。它特意写得很精炼——每一行都有其用处。与模型无关;适用于任何支持 MCP 工具调用的大模型。
# Plexus is your long-term memory
You have access to **plexus**, a persistent on-prem knowledge graph,
over MCP. Treat it as authoritative memory across sessions. Never
re-derive what the graph already knows; never let the graph drift.
## Every session
1. **Start:** call `context_load` once. Read the 20 most recent
entities and the kinds/relations registries. No other lookups
until you know what's already there.
2. **Before writing:** call `search_entities` (BM25, 2–4 keywords) to
avoid duplicates. If you find a close match, `update_entity` with
`expected_version`; do not create a new one.
3. **Writing new knowledge:** `save_entity` with the right `kind`.
Pick deliberately — kind drives how other agents will query it.
- `concept` — pattern, idea, domain term
- `decision` — an ADR (see "ADR discipline" below)
- `fact` — atomic statement, incident, milestone
- `project` — container that other entities are `part_of`
- `task` — actionable item (`attributes.is_milestone: true` for
milestones)
- `document` — runbook, post-mortem, design doc
- `note` — provenance anchor for an external source (URL, paper)
- `config` / `secret` — URLs, env vars, credentials. Secrets are
MCP-unreadable by design; do not attempt to read them.
- `inbox_item` — GTD quick capture to triage later
4. **Linking:** pick a named relation, not `relates_to`:
`part_of`, `depends_on`, `blocks`, `supersedes`, `documents`,
`derived_from`, `triggered_by`, `implements`, `produces`,
`consumes`, `mentions`, `owned_by`, `has_version`, `variant_of`.
5. **Traversal:** prefer one `get_related` over multiple
`get_entity` calls. Use `as_of` for point-in-time queries.
6. **Graph hygiene:** at the end of a substantial session, call
`lint_graph` and fix orphans and duplicate titles.
## ADR discipline
Every `kind=decision` MUST carry at least one edge —
`derived_from`, `triggered_by`, `supersedes`, or `part_of`. A
free-floating decision is a bug; the next agent won't find it.
## Session handoff
At the end of every non-trivial session, save a handoff-fact:
- `kind: "fact"`
- `attributes.session_type: "handoff"`
- `attributes.session_date: "<ISO date>"`
- `attributes.session_id: "<short slug>"`
- `attributes.agent_id: "<model id>"`
- `attributes.git_branch: "<branch>"` if applicable
- `part_of: "<project-entity-id>"` (required for handoffs, not
optional — server enforces this)
Title format: `"<Project> Handoff <Date> — <Core topic>"`.
## Optimistic locking
Every `update_entity` requires `expected_version`. On
`version_conflict`, re-fetch with `get_entity` and retry; never
blindly overwrite.
## Versioning, not deletion
Never delete by hand. Supersede: create the new entity, link
`supersedes <old>` (1:1), then `archive_entity` the old one.
## Memory routing — when plexus, when local scratchpad
**Goes in plexus (the default):**
- Anything team-, project-, architecture- or decision-relevant.
- Incidents, milestones, post-mortems, ADRs.
- Anything an agent in another session will want to know.
**Keep in a local scratchpad instead:**
- Per-session ephemera (current file paths, interim REPL output).
- Host-local gotchas with no team value (a specific IDE's template
literal trap, one machine's firewall oddity).
**When in doubt, plexus wins.** You can always archive a noisy
entity; you cannot recover one you never wrote.
## Trigger phrases
If the user says any of these, load the matching skill via
`load_skill` before acting:
| Phrase | Skill |
|---|---|
| "ADR" / "decision" | entscheidung / adr |
| "post-mortem" | post-mortem |
| "pre-mortem" | pre-mortem |
| "5 whys" / "root cause" | 5-whys |
| "runbook" | runbook |
| "STRIDE" / "threat model" | stride |
| "weekly review" | weekly-review |
| "meeting notes" | meeting-protokoll |
Skills are `kind=skill` entities in the graph with a trigger-phrase
attribute. `list_skills` gives you the index; `load_skill` returns
the full markdown body.
根据 Agent 角色收紧权限。 签发范围受限的独立个人令牌,而不是一个无所不能的令牌:
- Writer Agent(Claude Code CLI):
permission=write,所有上下文、所有类型。 - Reader 小组件(仪表板、监控任务):
permission=read,仅限单个contexts: [dev],不含机密信息。 - 特定领域 Agent(例如研究摘要 Agent):
permission=write,仅限kinds: [note, concept, fact]。
仪表板的 /tokens 页面只需两次点击即可生成上述任意令牌。
示例:摄取来源
以下是 Agent 实际使用 plexus 时,Karpathy 风格的摄取循环。用户提交一篇文章;Agent 仅使用 plexus 工具,按 LLM-wiki 模式完成五个阶段,并在不到一分钟内丰富知识图谱。
用户:“把这篇内容加进来:https://example.com/engineering/feature-flags-at-scale”
1 — 分类与定位。 Agent 获取来源,将其分类为 article,并检查已有内容,以免重复:
search_entities({ query: "feature flags progressive rollout", limit: 10 })
// → 2 concepts, 1 ADR, 1 fact in the dev context
2 — 提取。 对于文章,Agent 会提取关键论点、新事实、决策,以及任何与现有实体相矛盾的内容。
3 — 写入带类型的实体。 每种意图对应一种类型;更新现有实体,而不是创建重复项。
// New concept — the specific rollout pattern the article introduces
save_entity({
kind: "concept", context: "dev",
title: "Shadow-flag pre-rollout (Acme pattern)",
body: "# Shadow flag pre-rollout\n..."
})
// → entities:ab12...
// New atomic fact with provenance-grade attributes
save_entity({
kind: "fact", context: "dev",
title: "Acme reduced rollout-related incidents by 62% after adopting shadow flags",
attributes: { severity: "info", category: "benchmark", source_year: 2026 }
})
// → entities:cd34...
// Existing concept gets enriched, not duplicated
update_entity({
id: "entities:prev-concept-id",
expected_version: 3,
body: body + "\n\n## Update 2026-04-17\n..."
})
4 — 标注来源。 每次摄取都会恰好创建一个作为来源锚点的 note,且每个提取出的实体都会通过 derived_from 链接回该笔记:
save_entity({
kind: "note", context: "dev",
title: "Source: Acme — Feature flags at scale",
body: "## Metadata\nURL, date, author.\n\n## Summary\n2–3 sentences.\n\n## Derived entities\n- Shadow-flag pre-rollout (Acme pattern)\n- Acme reduced rollout-related incidents by 62% ..."
})
// → entities:ef56...
link_entities({ from_id: "entities:ab12...", to_id: "entities:ef56...", relation: "derived_from" })
link_entities({ from_id: "entities:cd34...", to_id: "entities:ef56...", relation: "derived_from" })
link_entities({ from_id: "entities:prev-concept-id", to_id: "entities:ef56...", relation: "mentions" })
5 — 双重输出。 回复用户并更新知识图谱——两者在同一轮中完成,而不是留待以后处理。
Agent 的回复:
已摄取 Acme 的功能标志文章。新增 2 个实体,丰富了 1 个现有概念,并创建了 3 条指向新来源笔记(
entities:ef56…)的derived_from/mentions边。影子标志的预发布阶段与现有的发布 ADR 并不矛盾——两者相辅相成。
六个月后,有人问你的 Agent:“我们当初为什么选择影子标志?”你的 Agent 会执行 search_entities({ query: "shadow flag rollout" }),再对命中的实体调用 get_related,以获取来源笔记和引用该笔记的 ADR,并依据汇总后的知识图谱作答,而不是重新阅读原始 HTML。无需重新总结,也不用说“如你可能还记得”。答案早已在知识库中。
知识图谱的内容
类型
| 类型 | 含义 |
|---|---|
concept | 抽象知识、模式 |
decision | 架构决策记录 |
fact | 原子陈述、事件、里程碑 |
project | 容器 |
task | 工作项(里程碑使用属性 is_milestone) |
document | 设计文档、运行手册、事后分析、协议 |
note | 来源、来源锚点 |
template | 可复用模式 |
config | URL、环境变量 |
secret | 凭据——MCP 无法访问,仅限仪表板使用并需通过升级验证的通行密钥 |
inbox_item | GTD 快速记录 |
user | 用户引用 |
tag | 分类标签 |
skill | 带有触发短语的 Markdown 技能,通过 load_skill 加载 |
关系
contains / part_of · relates_to · depends_on / blocks · supersedes / superseded_by · documents / documented_by · implements · produces / produced_by · consumes · mentions · derived_from · triggered_by · has_version · variant_of · executed_by · owned_by
每条边都带有 valid_from、valid_to、confidence 和 source(manual / llm-inferred / computed / imported)。unlink_entity 会将 valid_to 设为 now;该边仍会作为历史记录保留。get_related(as_of: …) 可以提供过去任意时间点的知识图谱状态。

身份验证
面向人类:通行密钥
控制面板仅支持通行密钥。首次登录时使用令牌 + 通行密钥,令牌会自动轮换——初始令牌是一次性邀请码,注册通行密钥后即失效。每位用户最多可添加 3 个通行密钥(笔记本电脑、手机、硬件密钥);最后一个通行密钥无法删除。
面向 Agent:个人令牌和 OAuth
个人令牌(pt_…)是通过控制面板签发的第一方自助令牌,并具有明确的作用域:permission × contexts × kinds × expires_in_days。可将它们用于 claude code、CLI 自动化,或任何你愿意授予长期凭证的 MCP 客户端。
OAuth 2.1 令牌(ot_…)适用于第三方 MCP 客户端。plexus 提供完整的授权服务器:
- 通过 RFC 8414(授权服务器元数据)和 RFC 9728(受保护资源元数据)进行发现。
- 动态客户端注册(RFC 7591)。
- 必须使用 PKCE 和
S256;架构和代码都会拒绝plain。 - 授权端点和令牌端点均支持资源指示符(RFC 8707)。
- 以恒定时间进行重定向 URI 精确匹配比较。
- 刷新时轮换令牌——签发新刷新令牌的同时立即撤销旧刷新令牌,以便检测凭证泄露。
管理员令牌在 /mcp 上会被拒绝,并返回硬性 403。不存在“直接使用管理员令牌”的变通方式。
分享
你可以将单个实体分享为只读的一次性链接,无需交出整个图谱。
- 在控制面板中打开该实体。点击 分享。
- 通过与用途绑定的通行密钥进行提权验证(
stepup:share:<userId>)——分享质询无法被重放为重置质询。 - plexus 会签发一个 32 字节的
st_令牌。系统只存储 SHA-256 哈希值。URL 仅显示一次。 - 接收者打开
GET /share/:token——无需登录,受到速率限制,且为只读。 - 第二次调用会返回
410 Gone。你可以随时撤销。
一个分享 URL,三种格式:
| URL | Content-Type | 用途 |
|---|---|---|
/share/:token | text/html | 浏览器 |
/share/:token?raw | text/markdown | 管道传输给大模型或 glow |
/share/:token?raw=json | application/json | 适用于 jq 的自动化 |
kind=secret 的实体无法分享——检查会在创建令牌之前进行。
搜索
search_entities 基于 SurrealDB BM25 索引运行,并使用自定义分析器(plexus_text):
blank+class分词器,lowercase+ascii过滤器(Unicode 到 ASCII 折叠——ü可匹配u,ß可匹配ss)。- 两个索引:
entities_title_search和entities_body_search。 - 排名:
search::score(0) * 2 + search::score(1)——标题权重为两倍。 - 可选的高亮功能会用
<mark>标签包裹匹配项。 - 可选的
body_preview_chars(0–2000)用于限制响应大小——宽泛查询时建议使用。

架构
┌──────────────────────────────────────────────┐
│ agents (Claude web / CLI / Desktop / ...) │
└───────────────┬──────────────────────────────┘
│ MCP over HTTPS + Bearer token
▼
┌──────────────────────────────────────────────┐
│ plexus worker (Hono + TypeScript, Node 22) │
│ ├─ POST /mcp — MCP tool dispatcher │
│ ├─ /oauth/* — OAuth 2.1 AS + PRM │
│ ├─ /auth/* — WebAuthn passkey flow │
│ ├─ /share/:token — one-shot read links │
│ ├─ /dashboard — read-only human UI │
│ └─ /admin/backup — portable JSON export │
└───────────────┬──────────────────────────────┘
│ SurrealQL
▼
┌──────────────────────────────────────────────┐
│ SurrealDB v2 (RocksDB, persistent volume) │
│ entities · edges · registries · activity │
└──────────────────────────────────────────────┘
源码目录结构
src/
├── index.ts # HTTP bootstrap, CSP, security headers
├── auth/ # passkeys, sessions, CORS allow-list
├── db/ # SurrealDB client, repositories, util
├── mcp/ # MCP tool handlers, skill tools, dispatcher
├── routes/ # dashboard, oauth, shares, admin, well-known
├── ui/ # layout, styles, pages, markdown renderer
├── backup.ts # portable JSON export
└── version.ts # build-embedded version string
migrations/ # SurrealDB schema in migration order
scripts/ # one-off admin / ops helpers
文件大小软上限:约 700 行。超过上限的文件会按职责拆分。
配置
所有配置均通过环境变量完成。完整列表及默认值请参阅 .env.example。
| 变量 | 必需 | 描述 |
|---|---|---|
PLEXUS_ADMIN_TOKEN | ✓ | 引导管理员令牌。在生产环境中请使用密钥管理器。 |
PLEXUS_OAUTH_SECRET | ✓ | 用于签署授权码和 OAuth 状态。 |
PLEXUS_COOKIE_SECRET | ✓ | 用于签署仪表板会话 Cookie。 |
PLEXUS_SURREAL_URL | ✓ | SurrealDB 端点——在 compose 网络内默认为 http://surrealdb:8000。 |
PLEXUS_SURREAL_USER | ✓ | SurrealDB 根用户。 |
PLEXUS_SURREAL_PASS | ✓ | SurrealDB 根密码。 |
PLEXUS_SURREAL_NS | 命名空间(默认为 plexus)。 | |
PLEXUS_SURREAL_DB | 数据库(默认为 main)。 | |
PLEXUS_RP_ID | WebAuthn 依赖方 ID——必须与主机名匹配。默认为 localhost。 | |
PLEXUS_RP_NAME | 通行密钥提示中显示的名称。 | |
PLEXUS_BASE_URL | OAuth 元数据使用的规范基础 URL。 | |
PLEXUS_PORT | HTTP 监听端口(默认为 8787)。 | |
PLEXUS_LOG_LEVEL | debug / info / warn / error。 |
生成高熵密钥:
openssl rand -hex 32
自托管
Docker Compose(推荐)
随附的 docker-compose.yml 会同时启动 plexus 工作进程和 SurrealDB。工作进程仅发布在 127.0.0.1:8787 上,也就是仅限 localhost 访问,因此即使公共 DNS 记录有误,也不会意外暴露仪表板。若要从本机以外的设备访问,请在前面配置反向代理。
docker compose up -d
docker compose logs -f plexus
对于 Coolify 主机,在其上叠加 Coolify 覆盖配置,以附加外部 coolify Traefik 网络并固定路由标签:
docker compose -f docker-compose.yml -f docker-compose.coolify.yml up -d
位于反向代理之后
plexus 在生产环境中要求使用 TLS。仪表板会设置 Secure Cookie,在 localhost 之外通过纯 HTTP 访问时会出现异常。请使用 Caddy、Traefik 或 nginx 等代理;最精简的 Caddy 配置见 Caddyfile。
CSP 标头会为 D3 固定 cdn.jsdelivr.net(并使用 SRI 哈希)。如果通过其他 CDN 提供仪表板,请相应更新 src/index.ts 中的 CSP。
备份
curl -H "Authorization: Bearer $PLEXUS_ADMIN_TOKEN" \
https://<your-plexus-host>/admin/backup \
> plexus-backup-$(date +%Y-%m-%d).json
导出内容包含实体、边、类型、关系和用户(不含令牌哈希)。它不包含会话、通行密钥、OAuth 令牌、个人令牌或共享令牌——凭据和会话状态绝不会备份。传入 ?include_audit=1 可将最近 1000 条活动日志记录包含在单独的文件中(默认不包含,因为这些记录含有个人数据)。
开发
npm ci
docker compose up -d surrealdb
cp .env.example .env # fill in required fields
npm run dev # live reload on :8787
质量检查:
npm run typecheck
npm run build
npx vitest run
npm audit --omit=dev --audit-level=moderate
有关提交规范、PR 要求以及我们在审查期间坚持的设计原则,请参阅 CONTRIBUTING.md。
安全
- Markdown 通过允许列表 URL 解析器进行渲染;链接带有
rel="noopener nofollow ugc"。 - 属性载荷上限为 64 KB,并会在 Zod 边界处被拒绝;原型键(
__proto__、constructor、prototype)会被递归剥除。 - 令牌生成采用 base62 拒绝采样,以避免模运算偏差。
- 敏感操作的 WebAuthn 挑战会通过用途绑定进行增强验证。
- 无论(用户、通行密钥、速率限制)中的哪一项验证失败,登录错误路径都会统一返回
LOGIN_FAIL——不会泄露用户是否存在。 kind=secret无法通过 MCP 访问、不可共享,并且仅限管理员在仪表板中通过增强验证的通行密钥操作。
请私下报告漏洞——参阅 SECURITY.md。请勿公开提交安全问题。
许可证
Apache License 2.0。请参阅 LICENSE。
plexus 和 pcas.io 是 pcas.io 项目的商标。Apache 许可证适用于代码;不授予商标权。
致谢
plexus 基于 SurrealDB、Hono、the Model Context Protocol SDK、SimpleWebAuthn、Zod 和 D3 构建。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。