Memories 使用说明
本文说明如何用当前 CLI 完成已实现的主要任务。示例里的 VAULT_ID、ASSET_ID 和其他大写标识,都要换成命令实际返回的短 ID。密码从交互终端无回显读取。没有密码参数,也没有密码环境变量。应用不限制本地密码和备份密码的长度,空输入也可以;仍需要确认的步骤会要求再次输入。
所有数据命令都先要有一个正在运行、并且使用同一数据目录的守护进程。全局选项:
| 选项 | 作用 |
|---|---|
--home PATH 或 MEMORIES_HOME |
选择数据目录。默认是操作系统的应用数据目录 |
--config PATH 或 MEMORIES_CONFIG |
选择 TOML 配置。命令行优先于环境变量,然后是配置文件,最后是内置默认值 |
--lang en\|zh\|ja\|de\|fr |
只影响这一次命令的界面语言 |
命令输出是带版本的 JSON。失败时退出码非零。确认词 USE 和 APPROVE 保持英文,不随界面语言改变。
Linux 可以运行 CLI、守护进程、中继、FFI 和下面的状态页。Linux 没有原生托盘。手机端没有模型检索界面,也没有后台同步,也不能用摄像头导入 OTP 二维码。托管设备配对可以扫配对码,见设备间端到端秘密。真实云账号的端到端验证尚未完成。命令行可以导入 HOTP、otpauth://、otpauth-migration://,并用 --image 解码 OTP 二维码图片。
按任务找入口
| 要做什么 | 阅读位置 |
|---|---|
| 第一次保存笔记 | 启动与初始化,再写入、读取和搜索 |
| 选择记忆、brain、persona 或文件 | 产品概念 |
| 搜文档或获得带引用的回答 | 检索与问答 |
| 保存密码、令牌、密钥或 OTP | 凭据与受保护卡片 |
| 换设备、给别人共享或恢复备份 | 设备、同步和备份 |
| 接入 AI 客户端 | MCP 与 skill |
| 用步骤或清单跟踪工作 | 工作流卡片与清单模板 |
| 由组织统一签发授权 | 授权中心 |
| 手机首次使用、连接自建服务或 SaaS | 手机模式选择与切换 |
不清楚参数时,先看总帮助,再逐级看子命令;帮助不需要守护进程:
memories --help
memories --lang zh memory --help
memories --lang zh memory put --help
--lang zh 只切换帮助与提示语言,不改变命令名或参数写法。本文的 sh 示例使用 POSIX shell;多行命令的行尾 \ 是续行符,在 PowerShell/CMD 中请合并成一行。
启动守护进程并初始化保险库
在一个终端中启动服务。它只接受当前操作系统用户的连接:Windows 使用命名管道,Linux 和 macOS 使用 Unix 套接字。
memories daemon
另开一个终端初始化设备、创建保险库、锁定和重新解锁:
memories init --name laptop
memories vault create Personal
memories vault list
memories lock
memories unlock
memories status
memories identity
--name 可省略,默认设备名是 local-device。identity 显示本设备的公开身份。初始化、解锁和 sudo 必须在交互终端中输入密码。不要把 --home 指到一个已有的普通文件夹;程序会收紧该目录的权限。
这里的本机存储(store)是 --home 选择的数据目录,初始化建立本机身份与密码保护;保险库(vault)是其中按成员和权限划分的资料集合,一个存储可以有多个保险库。自定义目录时,服务和每条客户端命令都要带相同的 --home PATH。已有存储以后只需 unlock,不要重复 init。如果要把新设备加入已有身份,先完成设备配对,不要先创建 Personal 或「此设备」保险库。
完成上面的步骤后,用编辑器新建 UTF-8 文件 notes.md,写入一句含「项目」的测试笔记。把下面示例的 VAULT_ID 换成 vault create 或 vault list 返回的 id,即可保存并搜索第一条记忆:
memories memory put VAULT_ID --title "项目笔记" --input notes.md
memories memory search VAULT_ID "项目"
保存结果中的 id 就是后续读取所用的 ASSET_ID。普通笔记用 memory;需要标签、分类和关系时用 card;原始 PDF 等文件用 file,不会自动变成可搜索文本;秘密用 credential,不要放进普通笔记。
普通 unlock 允许权限范围内的普通资料操作,并不开放私人内容、文件或凭据。
sudo 是本机授权会话,不是操作系统管理员权限。它使用同一个本地密码,最长 15 分钟,空闲 5 分钟后失效,并且只属于该终端的父进程。锁定或重启服务会清除它。普通解锁在空闲 15 分钟后失效。
查看或创建非秘密配置:
memories config path
memories config init
memories config init --output ./development.toml
memories --config ./development.toml config show
config init 不会覆盖已有文件。config show 不打开加密库。配置项包括 storage_dir、relay_url,以及 [desktop] 和 [rag]。不要把密码、私钥、OAuth 令牌或 MCP 授权写进这个文件。改存储目录或模型配置后,要同时重启守护进程。
写入、读取和搜索记忆与卡片
写入普通记忆。正文放在 UTF-8 文件里,用 --input 传入:
memories memory put VAULT_ID --title "项目笔记" --input notes.md
memories memory search VAULT_ID "项目"
memories memory read VAULT_ID ASSET_ID
memories memory history VAULT_ID ASSET_ID
memories memory diff VAULT_ID ASSET_ID FROM_REVISION
memories memory diff VAULT_ID ASSET_ID FROM_REVISION --to TO_REVISION
memories memory grep VAULT_ID 'project|release' -i -n
memory grep 用正则表达式逐行匹配所选保险库中普通记忆的解密正文,输出 DOCUMENT_ID:LINE;加 -n / --line-number 时输出 DOCUMENT_ID:LINE_NUMBER:LINE,-i / --ignore-case 忽略大小写。私有文档、冲突版本、卡片、文件和凭据都不参与匹配,与普通搜索排除私有内容的方式一致。没有匹配时不输出任何内容。
FROM_REVISION 和 TO_REVISION 都取自 history 返回的 revision 字段,而不是 id 字段。基准版本是位置参数,不是 --from;省略 --to 时比较当前 head。
每次创建/更新都会在保险库的签名修订 DAG 中追加版本(普通记忆、知识/脑图卡片、受保护卡片元数据、文件、凭据)。memory / card / file 的 history 列出版本(revision、时间戳、作者、是否 head、摘要);read --revision 读取历史正文;diff 输出统一文本差异(含标题与卡片元数据)。文件 diff 省略二进制正文,只比较元数据与长度;凭据的秘密正文不可通过 diff/read 返回。修订随保险库长期保留,无自动修剪。
读取某一历史版本时加 --revision REVISION。替换已有记录时加 --id ASSET_ID。出现多个未合并版本时,审阅历史后再用 --id ASSET_ID --resolve 提交一个同时指向这些父版本的新版本。删除当前可见记录:
memories memory delete VAULT_ID ASSET_ID
删除不擦除签名历史。--private 把记录标为私有。私有记录需要 sudo,并排除在普通搜索和 MCP 之外。
知识卡片使用同一组资产子命令,并可以带标签、来源、别名、备注、分类和关系。card list(也可用顶层 memories list / memories ls)可省略保险库 ID,扫描所有可访问保险库(每条结果含 vault)。--type knowledge|brain|persona|workflow|account|env|token|totp|hotp|otp 按 summary.type 筛选(knowledge 为普通知识卡片;brain 为带摘要与有类型链接的结构化知识卡片;otp 表示 totp+hotp),--otp 等同 --type otp。--category 按分类筛选,--group-by-category 按分类分组:
memories card put VAULT_ID --title "一个想法" --input notes.md --tag design --source "会议" --alias "设计备忘" --notes "工作坊" --category design
memories list
memories ls --type knowledge
memories card list --type brain
memories list --type otp
memories ls --otp --category security
memories card list VAULT_ID --category design
memories card list VAULT_ID --group-by-category
memories card brain VAULT_ID --title "Alice" --abstract "连接设计与工程的产品负责人" \
--link CARD_A=reports-to --link "OTHER_VAULT/CARD_B=collaborates|共同路线图" \
--alias "Alice" --notes "组织图" --category people
memories card brain VAULT_ID --id BRAIN_ID --title "Alice" --abstract "更新后的摘要" --link CARD_B=partner
memories card link VAULT_ID CARD_A CARD_B --relation supports
memories card unlink VAULT_ID CARD_A CARD_B --relation supports
memories card graph VAULT_ID
memories card graph VAULT_ID --include-private
memories card search VAULT_ID design
memories card list VAULT_ID
memories card read VAULT_ID CARD_ID
memories card delete VAULT_ID CARD_ID
card delete 与 memory delete 一样,只把卡片从当前视图中移除,签名历史仍保留早先的版本。删除私有卡片或受保护卡片需要 sudo。
脑图(brain)卡片保存可搜索的纯文本 abstract(不升格为受保护机密),以及可跨保险库的链接 { vault?, card, role?, note? }。--link 的写法是 [VAULT/]CARD[=ROLE][|NOTE],含 | 或空格时给整个值加引号,避免被 shell 当成管道。summary.type 为 brain,并含 link_count。列表/图谱/读取在权限允许时解析链接标题与类型,缺失或无权目标标记为 broken(不级联删除)。搜索索引标题、摘要、链接角色/备注以及同库公开目标摘要,从不索引机密。同库脑图链接也会出现在 card graph 中。
移动端编辑器支持手写输入和拍照/图片文字识别,全部在设备上完成,详见 手写与文字识别。
工作流(workflow)卡片与清单模板
工作流卡片的 summary.type 为 workflow。有序步骤保存在卡片修订中,每一步的状态是 pending、active、done 或 skipped,卡片本身还有一个总体状态。--step 的写法是 TITLE 或 ID:TITLE,可在末尾加 =CARD 关联一张卡片,每一步重复一次:
memories card workflow VAULT_ID --title Release --step "Write notes" --step Ship
memories card workflow-update VAULT_ID WORKFLOW_ID --advance
memories card workflow-update VAULT_ID WORKFLOW_ID --step STEP_ID --step-status done
memories card list --type workflow
--advance 推进指定的步骤;没有指定时推进当前 active 的步骤,再没有就推进第一个 pending 步骤。
清单模板也是 workflow 类型的卡片,资料中的 template 为 true。创建模板时 --template 不带值,并需要 --assignee、--summary 和 --goal。--assignee 可以是人格卡片 ID、人格 ID 或任意名字;--assignee-name 是显示名,指向人格卡片时默认用人格的显示名。--template TEMPLATE_ID 会把模板的清单字段和工作流链接复制成一个任务:
memories card workflow VAULT_ID --template --assignee PERSONA_ID --summary "每周发布检查" --goal "按时发布"
memories card list --type workflow --template
memories card workflow VAULT_ID --template TEMPLATE_ID --workflow WORKFLOW_ID --archive MEMORY_ID
memories card workflow-update VAULT_ID TASK_ID --acceptance "已发布并通知" --status done
--workflow 关联同一保险库中的另一张工作流卡片,--archive 归档一条记忆或卡片,可重复。workflow-update 的 --clear-workflow 和 --clear-archives 分别移除这两类链接。任务本身没有步骤时,--advance、--step、--step-status 和 --status 会作用在它关联的工作流上。验收报告 --acceptance 在任务完成前可以为空。
人格(persona)卡片
人格卡片用于在 Grok Bot / Muse 等产品间同步性格与行为。保险库中的人格卡片与其关联档案为权威来源。
memories persona import VAULT_ID /path/to/xiaoya-persona
memories card list --type persona
memories card read VAULT_ID PERSONA_ID
memories card history VAULT_ID PERSONA_ID
memories card diff VAULT_ID PERSONA_ID REVISION_ID
memories persona append-event VAULT_ID PERSONA_ID --text "行为记录" --kind note
- 核心(core):怎么说话、怎么演;通过
persona put/persona_card修订。 - 档案(archives):契约、日记、装扮、视角等独立知识卡片,由人格
archives链接,勿抄回核心。 - 行为事件:
append-event追加到events档案(追加式)。
世界状态、物品、自动化和人格间聊天也通过 persona 子命令维护。省略 VAULT_ID PERSONA_ID 时使用客户端默认值中的 persona:
memories persona world-get VAULT_ID PERSONA_ID
memories persona world-set VAULT_ID PERSONA_ID --place "书房" --weather-condition "多云" --weather-temp-c 26
memories persona world-rollover VAULT_ID PERSONA_ID
memories persona thing put VAULT_ID PERSONA_ID --id notebook --name 笔记本 --count 1 --attrs '{"color":"blue"}'
memories persona thing list VAULT_ID PERSONA_ID
memories persona thing attr set VAULT_ID PERSONA_ID --id notebook --path color --value '"red"'
memories persona dice-roll VAULT_ID PERSONA_ID --sides 6
memories persona schedule-list VAULT_ID PERSONA_ID
memories persona automation list VAULT_ID PERSONA_ID
memories persona automation trigger VAULT_ID PERSONA_ID --id morning --source manual
memories persona chat send VAULT_ID PERSONA_A PERSONA_B --text "你好"
memories persona chat history VAULT_ID PERSONA_A --with PERSONA_B --limit 20
- 世界状态:
world-set更新地点、姿态、装扮、物品数量、天气、骰子、转盘、日程等;world-rollover在隔日时显式开始新的账本日,只清除meals、orders_done、简短look摘要和counters_today等当日字段,累计计数保留。 - 物品(things):
thing put/get/list/delete/image管理任意物品,thing attr get/set/delete用点号路径或 JSON Pointer 读写单个属性,attrs是自由 JSON。 - 自动化:
automation put/list/run/trigger/delete管理存放在世界状态中的 hook,时区使用人格的timezone;出站webhook_out只能发往白名单中完全一致的 URL,默认空名单会拦截所有出站 POST,用automation webhook-allow --add URL/--remove URL管理。webhook 令牌不会在响应中返回,只显示webhook_token_set。 - 聊天:同一保险库中两张人格卡片之间的消息,发送时会触发双方的
chat_message自动化 hook(负载不含消息正文);chat list查看会话,读取history不会标为已读,需要chat mark-read。
详见英文人格卡片指南。
创建普通卡片时也可以重复 --link TARGET_ID=RELATION。这类关系必须指向同一保险库中的卡片。图谱省略已删除、冲突和未授权的节点,以及连接到这些节点的边。--include-private 需要 sudo。
私人文件:
memories sudo
memories file import VAULT_ID document.pdf
memories file export VAULT_ID FILE_ID exported.pdf
memories file history VAULT_ID FILE_ID
memories file diff VAULT_ID FILE_ID FROM_REVISION
file import 可用 --title 和 --id。file export 可用 --revision。file history 列出文件的签名修订;file diff 只比较标题、元数据和长度,不输出二进制正文。
用 file exec 把托管配置交给本机程序,命令参数中的 {file} 会替换为临时文件的绝对路径:
memories sudo
memories file import VAULT_ID ./Caddyfile
# 将返回的文件 ID 填入 FILE_ID;这里使用 Caddy 2 的 Caddyfile 格式。
memories file exec VAULT_ID FILE_ID -- caddy run --config "{file}" --adapter caddyfile
权限与 file export 相同,需要解锁、保险库访问权和同一终端的 memories sudo。
在 -- 前加 --revision REVISION 可使用历史版本。即使读取的是远程或托管 daemon,
程序也在 CLI 本机、以当前用户运行。命令直接启动程序,不经过 Shell;保留工作目录、
环境变量、标准输入输出和退出码,没有五分钟执行上限,也不输出 JSON 成功响应。
临时目录和文件仅允许当前用户访问(Unix 权限为 0700/0600,Windows 使用用户 ACL)。 程序应以前台方式运行:临时文件保留到子进程结束,启动失败也会清理。Windows 的 Ctrl+C/Ctrl+Break 和 Unix 的 SIGINT/SIGTERM/SIGHUP 会触发退出清理,最多等待十秒, 再终止直接子进程。Unix 信号会转发给子进程;Windows 控制台事件由同一控制台的进程接收。
运行期间配置是明文,程序及插件能够读取和输出它,输出不会脱敏。锁库或撤销授权不会
收回已交付的副本或停止程序。强制结束 Memories、断电或关闭 Windows 控制台可能留下
临时文件;删除不等于安全擦除,也不管理脱离父进程的后台后代进程。每次运行只使用一个
名为 config 的固定快照,不自动更新、reload、展开模板或导入关联文件。相对路径按
目标程序自己的规则解释;关联配置和证书建议使用绝对路径,需要时显式指定配置格式。
列表和搜索返回的短 ID 要原样使用。长 UUID、完整修订哈希和带前缀的 ID 会被拒绝。输入有歧义时命令失败,需要重新列表或搜索。
只在本机记录 Python:
memories local-python
memories local-python --program /path/to/python
它以隔离模式运行所选解释器,记录版本和可执行文件目录,不收集环境变量。结果写入带 local_only 的「此设备」保险库。
检索和带引用的回答
先让守护进程使用包含 [rag] 的同一配置。导入一份 UTF-8 文本或 Markdown 会创建一张普通知识卡片,并返回预计分块数:
memories rag ingest VAULT_ID notes.md --title "研究笔记" --source "本地文件"
memories memory search VAULT_ID "中文 关键词"
memories rag search VAULT_ID "关键词" --mode bm25 --match-mode all
rag search 和 rag ask 的选项:
| 选项 | 取值 |
|---|---|
--mode |
bm25、vector、hybrid。搜索和问答的默认值都是 hybrid |
--match-mode |
any、all、phrase。默认 any |
--limit |
1 到 100,默认 10 |
--no-rerank |
跳过可选的结果重排 |
--cards-only |
只检索知识卡片 |
安装内置 EmbeddingGemma 权重并建立内存向量索引:
memories rag model-install
memories rag index VAULT_ID
memories rag status VAULT_ID
memories rag search VAULT_ID "这段文档在说什么" --mode vector
memories rag search VAULT_ID "找出证据" --mode hybrid --limit 8
memories rag ask VAULT_ID "根据证据概括"
model-install 不初始化加密库。权重默认装到所选数据目录下的 models/embeddinggemma。本地推理在 Memories 进程内运行,不需要 Ollama。向量和混合检索在索引未建满时也会按需补算嵌入。
rag ask 需要配置里的生成地址。只做词法检索时使用 --mode bm25;只要调用问答,生成地址仍然必需。没有证据时不会调用生成服务,结果里 insufficient_evidence 为真。回答中的 [S1] 只是这一次结果里的引用标签。打开原文时使用结果中的资产 id,不要把分块哈希当成资产 ID:
memories memory read VAULT_ID ASSET_ID
PDF、DOCX 和二进制文件不会自动抽取文本。先转换成 UTF-8 文本再导入。不要把应当保密的文本导入为普通卡片。更改模型配置后重启守护进程。
远程嵌入、生成和重排写在配置的 [rag.embedding]、[rag.generation] 和 [rag.rerank] 中。API 密钥只写环境变量名,例如 api_key_env = "GEMINI_API_KEY",密钥值放在守护进程的环境里。省略 [rag.embedding] 时嵌入保持在本地模型。Gemini Embedding 是在线 API,不是离线的 EmbeddingGemma。
捕获和使用凭据与受保护卡片
先在同一终端执行 memories sudo。
隐藏输入新增凭据,或从已有文件导入。导入不会删除源文件:
memories credential add VAULT_ID "API 令牌"
memories credential import VAULT_ID "SSH 身份" existing-private-key
捕获命令 memories catch 与 memories credential catch 相同。不加来源时提示隐藏输入:
memories catch VAULT_ID "数据库密码"
从管道读取时加 --stdin。用 --regex 提取唯一匹配;有一个捕获组时保存该组,没有捕获组时保存整个匹配。用 --json-pointer 选择一个 JSON 字符串。两者不能同时使用:
secret-tool | memories catch VAULT_ID "数据库密码" --stdin --regex "password=([^\r\n]+)"
memories catch VAULT_ID "API 令牌" --stdin --json-pointer /token < response.json
memories catch VAULT_ID "API 令牌" --exec secret-tool --json-pointer /token -- issue --format json
--exec PROGRAM 直接启动该程序并捕获标准输出,关闭其子进程标准输入并丢弃标准错误。-- 后面是程序参数,不要在参数、正则或标题里放真实秘密。--timeout 的范围是 1 到 300 秒,默认 30 秒。管道标准输入一直等到 EOF,没有超时。输入上限是 1 MiB。成功结果只含凭据 ID。用 --id CREDENTIAL_ID 替换已有凭据。
在库内生成密钥。私钥不会被打印:
memories credential generate VAULT_ID "笔记本 SSH"
memories credential generate VAULT_ID "笔记本 SSH" --algorithm rsa --bits 4096
memories credential generate VAULT_ID "数据库 CA" --kind tls-ca --algorithm rsa --subject memories-ca
memories credential generate VAULT_ID "数据库服务器" --kind tls --ca CA_ID --algorithm rsa --name db.example.test
memories credential public VAULT_ID KEY_ID
--kind 可以是 ssh、tls-ca、tls。--algorithm 可以是 ed25519、rsa、ecdsa。credential public 只返回 SSH 公钥或 TLS 证书。
把凭据交给一个绝对路径上的程序。默认从标准输入注入;--env 明确允许一个环境变量。程序的 SHA-256 必须在交互时确认,或事先用 --approve-digest 批准。子进程的两路输出都被抑制:
memories run --vault VAULT_ID --credential CREDENTIAL_ID /absolute/program/path
memories run --vault VAULT_ID --credential CREDENTIAL_ID --env API_TOKEN /absolute/program/path
运行绑定把一个凭据固定到一个程序的指纹上,让编程代理不需要你终端里的 sudo 也能用它。credential bind gh 需要 sudo 并输入 USE 确认:它在 PATH 中找到 gh,记录 SHA-256,并只把绑定存进本机的加密状态,不会同步,恢复备份时也会清除。绑定在 --hours 小时后过期(默认 8,最多 720),而且只在资料库解锁时可用。之后 run --binding gh -- 参数 会在当前目录启动程序,把凭据放进指定的环境变量,原样返回输出,但其中出现的凭据都会替换成 [REDACTED](加 --suppress-output 则丢弃输出),并用程序自己的退出码退出:
memories credential bind gh --vault VAULT_ID --credential CREDENTIAL_ID --env GH_TOKEN
memories credential bindings
memories credential unbind gh
memories run --binding gh -- pr list --state open
memories hook install --commands gh
memories hook uninstall
--deny 词 拒绝非选项参数中按顺序含有这些词的命令;--ask 词 让 hook 在执行前征求确认。对 gh 默认拒绝 auth、alias、extension(以及别名 extensions、ext),并对 pr merge、repo delete、release delete 征求确认,加 --no-default-rules 可关闭。规则只按输入的词匹配,你之前用 gh alias set 定义的别名不会被展开。在绑定过期前,以你的身份运行的任何程序都能带着凭据执行这个程序,但无法通过 memories 读到凭据本身;程序自己、它的扩展和子进程则能读到,所以只绑定可信的程序。不带 --credential 和 --env 的绑定只应用规则。
hook install --commands gh 会在展示条目并要求输入 APPROVE 后,把 PreToolUse hook 写入 Claude Code 用户设置。Claude Code 在 Bash 或 PowerShell 里要执行 gh ... 时,hook 把这个命令词改写成 memories run --binding gh --,命令行其余部分保持不变。在 $( )、反引号、sh -c、xargs 等包装里执行的 gh 会被拒绝并说明原因;heredoc 正文、以及作为参数的命令替换(例如 --body "$(cat <<'EOF' ... EOF)")不受影响。管道或重定向的输入会通过 --stdin 转发(最多 16 MiB)。程序在守护进程的环境里运行,所以 NAME=value gh ... 这种前缀会被拒绝,请改用程序自己的参数。运行时才展开的参数($var、通配符)无法按规则检查,hook 会先征求确认。只有整条命令都是绑定程序的调用时,hook 才会直接放行;如果还会运行其他程序或写文件,仍走 Claude Code 平常的确认。绑定程序留下的后台进程如果一直占着输出管道,读取这些管道的线程数量有上限,超过上限时会拒绝新的绑定运行。Claude Code 自己的 deny / ask 权限规则仍然生效,但它们可能看到的是改写后的命令,所以敏感子命令请写进绑定规则。绑定的程序在服务锁之外运行,长时间的 gh run watch 不会挡住其他客户端,但 5 分钟上限不变。
限制凭据可用的主机,并让守护进程发出只返回状态码的 HTTPS 请求:
memories credential allow-host VAULT_ID CREDENTIAL_ID api.example.com
memories credential http VAULT_ID CREDENTIAL_ID https://api.example.com/status
credential http 只使用 HTTPS 的 443 端口,不跟随重定向,也不继承代理。
受保护卡片同样从隐藏输入读取秘密,不把秘密放在参数里:
memories card account VAULT_ID --title "示例邮箱" --email user@example.test --smtp smtp.example.test
memories card env VAULT_ID ./app.env --title "应用配置"
memories card token VAULT_ID --title "API 会话" --host api.example.test
memories card token VAULT_ID --title "浏览器会话" --host app.example.test --cookie
memories card request VAULT_ID TOKEN_CARD_ID https://api.example.test/session
memories card otp VAULT_ID --title "示例 OTP" --issuer Example --account user@example.test
memories card otp VAULT_ID --title "示例 HOTP" --issuer Example --account user@example.test --hotp --counter 0
memories card otp-import VAULT_ID --title "导入的 OTP" "otpauth://totp/Example:user@example.test?secret=GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ&issuer=Example"
memories card otp-import VAULT_ID --image ./ga-export.png --title "GA import"
memories card otp-code VAULT_ID OTP_CARD_ID
账户 SMTP 默认是 SSL 端口 465,可用 --port 和 --no-ssl 调整。这只记录配置,不发送邮件。--cookie 把令牌卡片存成 Cookie 头。card request 的 --method 默认是 GET,只接受 GET 或 POST。OTP 可用 --algorithm sha1|sha256|sha512、--digits 和 --period。--hotp 改为 HOTP,--counter 是初始计数器,省略时为 0;TOTP 忽略计数器。otp-import 接受参数中的 URI;没有 URI 也没有 --image 时,从标准输入读一行。单个账户使用 otpauth://。URI 里的 totp 或 hotp 会自动识别;没写类型时,带 counter 的是 HOTP,否则是 TOTP。Google Authenticator 迁移使用 otpauth-migration://offline?data=...,可能一次创建多张卡片。--image PATH 从图片中解码第一种 otpauth:// 或 otpauth-migration:// 二维码,不能和 URI 同时使用。--title 可省略:只有一张卡片时它就是标题,有多张时它是标题前缀;省略时标题为「发行方 / 账户」。--id 只能替换一张卡片,不能用于包含多个账户的迁移导入。otp-code 返回短时验证码,不返回种子;HOTP 的结果包含下一个计数器。上面的 secret 是公开的 RFC 测试向量,不要换成真实种子。
替换已有受保护卡片时加 --id CARD_ID。凭据 ID 和卡片链接会保留;未传的 --alias / --notes / --category 保持原值,传空字符串可清除。普通 card put 不能替换受保护引用。OTP 标题可保留 issuer / account,用别名和备注单独存显示名。
在文档正文中保护一个精确出现的秘密。标签由 1 到 64 个 ASCII 字母、数字、下划线或连字符组成,并且在该文档中尚未使用:
memories memory protect-secret VAULT_ID DOCUMENT_ID API_KEY
memories card protect-secret VAULT_ID CARD_ID API_KEY
memories credential copy VAULT_ID DOCUMENT_ID --label API_KEY
memories credential copy VAULT_ID CREDENTIAL_ID
protect-secret 会提示输入秘密。复制文档引用时必须带 --label。复制结果只有 "copied": true。Windows 使用系统剪贴板,macOS 使用 pbcopy,Linux 需要 Wayland 的 wl-copy 或 X11 的 xclip。受保护的账户、令牌、环境和 OTP 卡片也可以直接复制;OTP 复制的是种子,不是一次性验证码。
手机端有「受保护卡片」「导入 .env」和「导入登录信息(CSV)」,也可以粘贴 otpauth:// URI 来导入 TOTP 或 HOTP。文档菜单中的「替换资料中的密钥」和「复制密钥」对应上述操作。OTP 的「生成 OTP」产生一次性验证码。手机端没有摄像头导入 OTP 二维码;OTP 图片和迁移 URI 使用上面的命令行。托管设备配对的扫码是另一条路径,见设备间端到端秘密。
导入和导出网站登录信息
网站登录保存在 login 受保护卡片里(公开的站点地址和用户名,密码作为独立凭据),通常成批导入导出。导入和导出都需要 memories sudo 和可写角色:
memories sudo
# 浏览器 CSV(Chrome/Edge/Brave,或 Firefox 的 about:logins);自动识别表头。
memories login import VAULT_ID --from chrome passwords.csv
memories login import VAULT_ID --from firefox firefox-logins.csv --with-notes
# 直接读取 Firefox 配置文件(现代 key4.db,会提示输入主密码,没有则留空)。
memories login import VAULT_ID --from firefox-profile "/路径/Profiles/xxxx.default"
# Windows 凭据管理器的通用凭据(仅 Windows)。
memories login import VAULT_ID --from windows --filter github
memories login import VAULT_ID --from windows --all
# 之前导出的加密文件。
memories login import VAULT_ID --from memories logins.mlx
# 导出:便携加密文件(推荐)或浏览器兼容的 CSV。
memories login export VAULT_ID --format encrypted logins.mlx
memories login export VAULT_ID --format csv logins.csv
站点主机和用户名都与已有卡片相同、且密码一致时跳过;密码不同时记为冲突并另建一张卡片,加 --update 才覆盖。CSV 里的坏行会跳过并按行号报告,单次导入上限 2000 条。浏览器的 note 列只有加 --with-notes 才导入,因为备注会进入普通全文索引。Firefox 直读支持现代密钥格式(Firefox 58 及以上);更旧的配置文件请从 about:logins 导出 CSV。读取浏览器保存的密码不会修改浏览器自身的存储。
加密导出使用独立密码,可导入任意保险库。CSV 导出是明文,用于把登录信息导回浏览器或其他密码管理器:仅限本地 CLI,会先告警,写入仅所有者可读、且必须尚不存在的文件,并对以 = + - @ 开头的单元格做防公式注入处理,用完请删除。仅本设备的保险库不能导出。
远程会话和回环代理
先用 credential allow-host 授权目标主机。SSH 还要用探针得到的主机密钥指纹,并经可信渠道核对:
memories remote probe example.test --port 22
memories remote open ssh --vault VAULT_ID --credential KEY_ID --host example.test --user alice --host-key HOST_KEY
memories remote open ssh --vault VAULT_ID --credential KEY_ID --certificate CERT_ID --host example.test --user alice --host-key HOST_KEY
memories remote sessions
memories remote run SESSION_ID -- uname -a
memories remote propose SESSION_ID -- uname -a
memories remote approve TICKET_ID
memories remote exec TICKET_ID
memories remote close SESSION_ID
remote run 一次完成提议、交互批准和执行。脚本需要拆开时,用 remote propose 排队并返回票据,remote approve 批准(需要 sudo,票据只能用一次),再由同一个已提权的调用方 remote exec 执行。
数据库默认启用 TLS 并校验主机名。--tls-ca CA_ID 增加一个库内 PEM CA。--no-tls 明确关闭 TLS。--database 是 MySQL/PostgreSQL 的库名,或 Redis 的逻辑库索引:
memories remote open mysql --vault VAULT_ID --credential CREDENTIAL_ID --host db.example.test --user app --database appdb
memories remote open postgres --vault VAULT_ID --credential CREDENTIAL_ID --tls-ca CA_ID --host db.example.test --user app --database appdb
memories remote open redis --vault VAULT_ID --credential CREDENTIAL_ID --host redis.example.test --user default
memories remote run SESSION_ID --op query -- SELECT 1
remote open 的协议是 ssh、ftp、tcp、mysql、redis、postgres。FTP 使用文件操作,SSH 和数据库会话使用 exec 或 query。每条指令先提议再批准。remote run 把提议、交互批准和执行连在一起。批准词是 APPROVE。MCP 不能打开或批准远程会话。
回环代理在 127.0.0.1 上监听。返回的 command 可在守护进程所在机器的终端里运行,其中不含存储的密码或私钥:
memories proxy start ssh --vault VAULT_ID --credential KEY_ID --host example.test --user alice --host-key HOST_KEY
memories proxy start postgres --vault VAULT_ID --credential PASSWORD_ID --host db.example.test --user app --database appdb
memories proxy start mysql --vault VAULT_ID --credential PASSWORD_ID --host db.example.test --user app --database appdb
memories proxy start redis --vault VAULT_ID --credential PASSWORD_ID --host cache.example.test --user default
memories proxy list
memories proxy stop PROXY_ID
代理协议只有 ssh、mysql、redis、postgres。可选 --listen-port,0 表示由系统选择端口。可选 --certificate、--tls-ca、--tls 和 --no-tls。任何能连上该本地端口的进程都能使用已经授权的远程账户。锁定、保险库空闲锁定、proxy stop 和守护进程退出会关闭监听和已有连接。代理最长 30 分钟,最多四个代理,每个最多 16 个连接。MCP 不能启动、列出或停止代理。
运行密码学作业
邮件和签名工具要单独安装。身份和密码分成两个凭据导入。--credential、--password_id 和 --key-password 都是凭据 ID,不是秘密本身。--password 和 --password-id 是 --password_id 的别名。
先加 --dry-run。它读取输入和工具、打印计划和 approval 摘要,不需要守护进程,也不写输出文件。确认后在同一终端执行 sudo,再运行去掉 --dry-run 的同一命令。非交互执行改为带上 --approve-digest DIGEST。输出必须是已存在目录中的新路径。
S/MIME 使用 OpenSSL。PKCS#12 身份加 --pkcs12。加密只使用收件人公钥,所以不传身份凭据:
memories crypto smime-sign --vault VAULT_ID --input message.eml --output signed.eml --credential IDENTITY_ID --password_id PASSWORD_ID --pkcs12 --tool openssl=/path/to/openssl --dry-run
memories crypto smime-encrypt --vault VAULT_ID --input signed.eml --output encrypted.eml --recipient recipient.pem --tool openssl=/path/to/openssl --dry-run
memories crypto smime-decrypt --vault VAULT_ID --input encrypted.eml --output decrypted.eml --credential IDENTITY_ID --password_id PASSWORD_ID --pkcs12 --tool openssl=/path/to/openssl --dry-run
OpenPGP 需要成对的 gpg 和 gpgconf。--identity 是完整指纹。Git for Windows 里的 MSYS 版 GnuPG 要加 --msys-gpg:
memories crypto pgp-sign --vault VAULT_ID --input message.eml --output message.sig.asc --credential KEY_ID --password_id PASSWORD_ID --identity FULL_FINGERPRINT --tool gpg=/path/to/gpg --tool gpgconf=/path/to/gpgconf --dry-run
memories crypto pgp-encrypt --vault VAULT_ID --input message.eml --output message.eml.asc --recipient recipient.asc --identity FULL_FINGERPRINT --tool gpg=/path/to/gpg --tool gpgconf=/path/to/gpgconf --dry-run
memories crypto pgp-decrypt --vault VAULT_ID --input message.eml.asc --output decrypted.eml --credential KEY_ID --password_id PASSWORD_ID --tool gpg=/path/to/gpg --tool gpgconf=/path/to/gpgconf --dry-run
Android 签名不生成安装包,也不联系应用商店。apksigner 的路径是 SDK 的 lib/apksigner.jar:
memories crypto android-apk --vault VAULT_ID --input unsigned.apk --output signed.apk --credential KEYSTORE_ID --password_id STORE_PASSWORD_ID --identity release --tool java=/jdk/bin/java --tool zipalign=/sdk/build-tools/35.0.0/zipalign --tool apksigner=/sdk/build-tools/35.0.0/lib/apksigner.jar --dry-run
memories crypto android-bundle --vault VAULT_ID --input unsigned.aab --output signed.aab --credential KEYSTORE_ID --password_id STORE_PASSWORD_ID --identity release --tool jarsigner=/jdk/bin/jarsigner --dry-run
密钥口令与库口令不同时,用 --key-password KEY_PASSWORD_ID。
iOS 签名只在 macOS 上可用。输入是已经包含匹配 embedded.mobileprovision 的 .app:
memories crypto ios-app --vault VAULT_ID --input Unsigned.app --output Signed.app --credential APPLE_P12_ID --password_id PASSWORD_ID --identity CERTIFICATE_SHA1 --entitlements App.entitlements --tool openssl=/path/to/openssl --tool security=/usr/bin/security --tool codesign=/usr/bin/codesign --dry-run
这些命令不发送邮件,也不发布应用。MCP 和手机端不能执行它们。
配对设备、同步和备份
设备配对让同一个人的新设备加入已有身份;成员邀请则给另一个人授予某个保险库的角色。两者都用请求和批准文件,但不能互换。
新设备先用自己的密码执行 init,并且在加入前不能已有保险库。然后:
memories sudo
memories device invite request.json
把请求文件交给已有设备。对照请求设备上显示的完整邀请指纹后再批准。批准命令会返回批准设备的公钥;在新设备接受之前,通过可信渠道核对这把公钥:
memories sudo
memories device approve request.json approval.json --fingerprint REQUEST_FINGERPRINT
回到新设备,在执行接受命令的同一终端重新运行 sudo,再接受批准并检查设备列表:
memories sudo
memories device accept approval.json --sender APPROVING_DEVICE_PUBLIC_KEY
memories device list
请求 10 分钟后过期,并且只能使用一次。
为另一个人批准某个保险库的成员资格:
memories member approve VAULT_ID request.json approval.json --fingerprint REQUEST_FINGERPRINT --role reader
memories member list VAULT_ID
memories member role VAULT_ID USER_PUBLIC_KEY editor
memories member remove VAULT_ID USER_PUBLIC_KEY
memories member transfer VAULT_ID USER_PUBLIC_KEY
memories device revoke VAULT_ID DEVICE_PUBLIC_KEY
邀请批准的 --role 与 member role 的角色参数应使用 admin、editor 或 reader,并受操作者权限限制:所有者管理管理员,管理员只能管理普通读者和编辑;编辑可以写,读者可以读和使用。CLI 虽接受 owner,但保险库策略要求恰有一个所有者,不能用邀请或普通角色修改新增所有者。要转交所有权,由现任所有者执行 memories member transfer VAULT_ID USER_PUBLIC_KEY,目标必须是已有成员,原所有者随后成为管理员。吊销设备要在每个相关保险库上执行。移除成员不会擦掉对方已经持有的副本。
不经过中继的文件交换:
memories sync export VAULT_ID RECIPIENT_DEVICE_PUBLIC_KEY packet.json
memories sync import packet.json
在线传输时,先在 TLS 反向代理后面运行 memories-relay,再用 sync room 生成房间号。接收方先等待,发送方再发送:
memories sync room
memories sync receive --relay wss://relay.example.com --room ROOM
memories sync send VAULT_ID RECIPIENT_DEVICE_PUBLIC_KEY --relay wss://relay.example.com --room ROOM
远程中继只接受 wss://。ws:// 只允许本机开发地址。URL 不能包含用户名或密码。配置文件中的 relay_url 可作为默认地址,命令上的 --relay 覆盖它。--slot 的默认值在发送时是 a,接收时是 b。发送成功只表示数据包交给了中继,不表示对方已经导入。中继不为离线设备排队。sync export/import 和中继 sync send/receive 都是显式整库传输,不是云对象同步,也不是远程 RPC。
查看隔离区、把旧纪元修订重新签入当前纪元,以及在双方都有效的所有者身份下保留本地策略分支:
memories sync quarantine VAULT_ID
memories sync reapply VAULT_ID REVISION
memories sync resolve-policy VAULT_ID packet.json --keep-local
云账户使用你自己注册的 OAuth 应用。登录前解锁库并在同一终端执行 sudo:
memories cloud login onedrive --client-id YOUR_MICROSOFT_CLIENT_ID
memories cloud login google-drive --client-config /path/to/google-desktop-client.json
memories cloud status
memories cloud sync onedrive
memories cloud logout onedrive
cloud login 可用 --no-browser 和 --port。0 表示自动选择本机回调端口。状态不打印令牌。登出只删除本机授权。cloud sync 会刷新令牌,并通过已连接的 OneDrive 或 Google Drive 应用文件夹上传和下载不可变密文。手机端提供云连接和前台同步控制。真实 OneDrive 与 Google Drive 账号上的端到端验证尚未完成。手机后台同步未启用。不要把数据库目录放进云盘客户端的同步文件夹。
审计和离线备份:
memories audit VAULT_ID --verify
memories sudo
memories audit VAULT_ID
memories backup offline-backup.memories
恢复必须使用新的数据目录,并在该目录启动守护进程:
memories --home NEW_DIRECTORY restore offline-backup.memories --name replacement
memories --home NEW_DIRECTORY sudo
memories --home NEW_DIRECTORY archive list
memories --home NEW_DIRECTORY archive history VAULT_ID
memories --home NEW_DIRECTORY archive read VAULT_ID REVISION
memories --home NEW_DIRECTORY archive audit VAULT_ID
恢复出的是包含当前资产和冲突头的独立保险库。原始版本、墓碑和签名审计留在只读归档中。历史凭据值不能通过普通接口或归档接口打印。设备专用库和云令牌不在备份中。
打开桌面状态界面
Windows 发布包中双击与 memories.exe 放在一起的 memories-tray.exe。macOS 打开打包的 Memories.app。终端中:
memories tray
memories webui
memories --home /path/to/development-home webui --no-open --port 0
memories webui --open
memories-tray --home /path/to/development-home --no-open
tray 打开原生托盘或菜单栏,并带状态页。webui 只打开浏览器仪表板并留在前台。--port 0 选择空闲的环回端口。--no-open 不自动打开浏览器。--open 在配置关闭自动打开时仍然打开。--config 和 --lang 同样适用于这两个命令和 memories-tray。
托盘可以显示离线、需要初始化、已锁定或已解锁,并可以启动守护进程。它不初始化、不解锁、也不提权。状态页约每两秒刷新,显示库数量、代理和远程会话数量、已配置的云提供商种类,以及上传、下载和待同步计数。它不显示正文、库名、凭据、账户、路径或令牌。退出托盘或中断前台 webui 只停止该状态页,不停止已经运行的守护进程。
Linux 使用 memories webui。Linux 没有原生托盘,Linux 发布包也不包含托盘启动器。
授予 MCP 并安装 AI skill
本节先介绍普通 MCP:按一个保险库、期限和操作范围授予 AI 客户端能力,不继承终端的 sudo。授权写到文件里,不会打印出来;文件本身是 bearer 凭证,需要保护。默认只读,--scope read_write 允许普通资料读写,--scope read_write_delete 还允许删除,--write 是 read_write 的兼容简写。时间用 --minutes,示例为 15 分钟:
memories sudo
memories mcp grant VAULT_ID PRIVATE_GRANT_FILE --minutes 15
memories mcp serve --grant-file PRIVATE_GRANT_FILE
memories mcp revoke PRIVATE_GRANT_FILE
把 AI 客户端的 stdio MCP 命令配成 memories mcp serve --grant-file ...,并使用与守护进程相同的数据目录。工具是 memory_search、memory_retrieve、memory_ask、memory_read、memory_read_revision、memory_history、memory_diff、memory_write、memory_delete、card_write、card_graph、card_link、workflow_card、workflow_read、workflow_update 和 workflow_list,另有英文人格卡片指南列出的 persona 工具。workflow_card 创建步骤工作流、清单模板或从模板复制的任务,workflow_update 修改清单字段或推进步骤,两者都需要写权限;workflow_read 和 workflow_list 只需读权限。每次调用都带已授权的保险库 ID。memory_retrieve 默认是本地 BM25;vector 和 hybrid 使用守护进程已配置的嵌入提供方。memory_ask 在配置了生成地址后回答,并拒绝不在检索证据中的引用。
普通 MCP 不包含私人记忆、文件、凭据、进程执行、远程会话、代理、密码学作业、成员管理和桌面状态。即使选择 --scope allow_all,也不会越过这条边界。授权的签发、列表、撤销和权限申请是另外的 MCP 工具,仍不继承 sudo。锁定使这些授权暂时不可用,未过期的在解锁后恢复。协议版本是 2024-11-05。带秘密引用的卡片不能用当前的 card_write 更新,因为该工具不保留引用映射;请用 CLI 或手机端编辑。
需要无人值守读取时,另行阅读无人值守 CLI/MCP。该路径必须显式选择密钥托管后端,输入 ENABLE 并完成密码授权,再创建保险库范围内的客户端文件;使用 mcp serve-unattended --client-file PATH,不是普通 mcp serve。它仅限本机、只读,但包含私人资料、原始文件、历史和明确请求的凭据明文,不继承 sudo。AI 客户端及其日志可能保留秘密,Base64 不是加密。手动锁定会持续阻止该访问,直到密码授权的 unattended resume;远程传输、手机和 Center 管理的存储不能使用它。
memories unattended enable --backend windows-dpapi
memories unattended mint --vault VAULT_ID --client-file /private/dir/client.json
memories unattended list VAULT_ID --client-file /private/dir/client.json
memories unattended history VAULT_ID ASSET_ID --client-file /private/dir/client.json
memories unattended read VAULT_ID ASSET_ID --client-file /private/dir/client.json
memories unattended credential-bytes VAULT_ID CREDENTIAL_ID --client-file /private/dir/client.json
memories mcp serve-unattended --client-file /private/dir/client.json
memories unattended status
memories unattended resume
memories unattended revoke GRANT_ID
memories unattended disable
后端可选 windows-dpapi、macos-keychain、linux-secret-service,或需显式选择、保护较弱的 owner-file。客户端文件所在目录必须已存在且只有所有者可访问,mint 不会覆盖已有文件。read 和 credential-bytes 按 base64url 字节分段返回:从 --offset 0 开始,每次用上一次响应的 next 作为新的 --offset,并用 --revision 固定第一次返回的修订,直到 next 为 null,再按顺序拼接解码后的字节。list / history 每页最多 100 条。status、resume、revoke 和 disable 需要已解锁并已 sudo 的终端。
安装随程序提供的 skill。安装本身不打开库,也不配置 MCP:
memories inject all --dry-run
memories inject all
memories inject codex
memories inject opencode claude
memories inject all --project /path/to/project
all 包含 Codex、OpenCode 和 Claude Code。claude-code 是 claude 的别名。--project 安装到一个已存在的项目目录。升级 CLI 后,用 --force 替换以前装过的不同内容:
memories inject all --force
--force 只替换 SKILL.md。相同内容会保持不动。指向技能文件或目录的链接会被拒绝。
为项目生成说明如何操作 Memories 的 AGENTS.md,或 Cursor/Codex 风格的 skill 目录,可选嵌入一张人格卡片的核心概要。agents 是 skill 的别名:
memories skill generate --out AGENTS.md
memories skill generate --out AGENTS.md --persona VAULT/PERSONA
memories agents generate --out ./skills/memories-persona --layout skill --persona VAULT/PERSONA
--layout agents(默认)写一个 Markdown 文件;--layout skill 在输出目录下写 SKILL.md(输出路径已以 .md 结尾时直接写该文件)。省略 --persona 时使用客户端默认值里的 persona。带人格生成时通过守护进程读取该卡片,需要先解锁;不带人格时离线生成,不需要守护进程。--force 替换内容不同的已有文件,--dry-run 只预览不写入。
客户端默认值
非秘密的命令行默认值保存在数据目录(--home / MEMORIES_HOME)下的 defaults.json,不进入保险库密文:
memories default set persona VAULT/PERSONA
memories default set vault VAULT_ID
memories default set type persona
memories default get
memories default get type
memories default delete type
| 键 | 含义 |
|---|---|
persona |
persona 命令省略保险库和资产时使用的 VAULT/ASSET |
vault |
list / card list 以及单参数 persona 命令的默认保险库 |
type |
列表命令默认的 --type 筛选 |
category |
列表命令默认的 --category 筛选 |
daemon |
默认的 --daemon URL |
daemon_relay |
默认的 --daemon-relay URL |
daemon_room |
默认的 --daemon-room |
显式参数总是优先。接受保险库和资产的 persona 子命令(world-get、thing、append-event 等)会把省略的位置参数当作默认值;persona import 仍要在 skill 路径前写明保险库 ID。
授权中心(Center)
Center 是外部的授权控制面,向各端分发登记票据和能力票据。只要配置文件里列出任何一个 [[centers]],该端就由 Center 管理:本地 init / restore 自举和本地 MCP 授权都会被禁止,改用 Center 签发的票据。保险库解锁仍在本地用设备密码完成,Center 拿不到保险库密钥或秘密明文;监听令牌、Center 签名密钥和管理令牌都不写进 TOML。
# 管理员:生成写入配置的公钥并签发票据(或使用 memories-center HTTP 服务)
export MEMORIES_CENTER_SECRET="…" # 32 字节,URL 安全 base64 或 64 位十六进制
memories center public-key
memories center issue-bootstrap --center corp --device-name laptop
memories center issue-grant --center corp --vault VAULT_ID --scope read --minutes 15
# 终端(守护进程已按含 centers 的配置运行)
memories center list
memories center enroll --ticket "$BOOTSTRAP_TICKET"
memories sudo
memories center import-grant --ticket "$GRANT_TICKET"
授权范围(read、write、read_write、read_write_delete、allow_all 及其别名)、配置格式和威胁模型详见英文 Authorization Center。
托管保险库(SaaS)
memories-center --data DIR(或环境变量 MEMORIES_CENTER_DATA)让 Center 运行完整的托管保险库:服务端用运营者持有的密码加密保存 Store,复用守护进程的同一套服务接口。配置中唯一的 mode = "saas" 条目会让本机守护进程进入 SaaS 模式,内容操作由该 Center 控制(令牌来自 MEMORIES_CENTER_TOKEN)。管理员可通过 /v1/admin/lock、/v1/admin/unlock 远程加锁/解锁,通过 /v1/admin/members 管理成员。托管数据对运营者可见,不是端到端加密。请求元数据存于 DIR/requests.json,哈希链审计存于 DIR/audit.jsonl。
授权链
保险库角色为 Owner、Admin、Editor、Reader。只有 Admin 及以上可以签发或委托授权;签发只需已解锁的保险库,不需要终端提权,但批准角色请求需要提权。授权范围不超过签发者角色(及上级授权),被授权者角色不能高于签发者,center-admin 不能作为被授权者。委托深度最多 2 层。省略范围时默认为 read,而不是 allow_all。本机守护进程和托管 Center 同时最多 10000 张有效授权。
权限请求可广播给所有有资格的审批者,或用 --approver 指定审批者;可以批准或拒绝,但不能决定自己的请求。批准不返回令牌,请求者需领取一次:memories request claim VAULT ID、memories center request claim ID、MCP request_claim,或 POST /v1/requests/{id}/claim。每个请求者在每个保险库最多 20 个待处理请求,每个保险库最多 200 个(Center 返回 HTTP 429);待处理及已批准未领取的请求 7 天后过期,已结束的请求保留 30 天。
memories access list VAULT # 按级别列出成员、设备、待处理与已批准未领取的请求
memories grant list VAULT
memories request create VAULT --scope read --approver MEMBER_ID
memories request approve VAULT ID
memories request claim VAULT ID
移除成员会级联吊销其签发的授权(按成员代数失效);授权只持久化哈希;审计日志为哈希链。详见英文 Authorization。
选择语言
手机端在锁屏和库界面都有语言菜单,默认跟随系统,手动选择会在重启后保留。
命令行的优先级是 --lang、MEMORIES_LANG、已保存的语言,然后是第一个非空的 LC_ALL、LC_MESSAGES 或 LANG。Windows 在这些变量都没有时还会看操作系统语言。无法识别的区域设置回退到英语。zh-CN 和 fr_FR.UTF-8 可以识别。
memories --lang zh --help
memories language zh
memories language
memories language system
language 后面可省略,用来显示已保存和当前生效的语言。system 清除选择并重新跟随系统。保存的语言按 --home 区分,不需要守护进程。命令名、选项名、JSON 字段、错误码以及 USE 和 APPROVE 不翻译。用户内容也不翻译。
远程守护进程(HTTP/WebSocket / 中继 RPC)
可选的令牌认证 HTTP/WebSocket 监听与 WSS 中继 RPC 使用同一套 WebSocket 二进制 JSON 帧(AuthFrame 后接 Wire),与本地 IPC 的 service::Request 协议一致。
RPC 在远端主机的存储上执行命令,不在调用方建立保险库副本。要交换副本用 sync;要通过 OneDrive/Google Drive 的持久云对象队列同步用 cloud sync PROVIDER。中继承载 RPC 或整库传输时都不是离线资产仓库。
监听令牌只能通过标志或环境变量提供,不能写入 TOML。默认明文 HTTP/WS 不需要证书;需要时用 --tls-cert / --tls-key 启用 HTTPS/WSS。桌面守护进程在远程解锁/提权后提供与本地 IPC 相同的全功能操作面(ws:remote / relay:remote 提权命名空间);移动端 Share 仍遵循 FFI 拒绝列表。详情见 remote-daemon.md。
中继也可以转发人格自动化 webhook:POST /v1/persona/{room}/{vault}/{persona}/automation/trigger,请求体和 webhook 令牌与守护进程相同,中继只把它转给已连接的主机,不对外发起 POST。
全局 TLS 选项:--ca-file PATH(MEMORIES_CA_FILE)为出站 TLS 客户端添加 PEM CA;--insecure 跳过证书和主机名校验但仍使用 TLS,仅限开发/自签名环境,优先使用 --ca-file。
memories daemon --listen http://127.0.0.1:7900 --listen-token "$TOKEN"
export MEMORIES_DAEMON=http://127.0.0.1:7900
export MEMORIES_DAEMON_TOKEN="$TOKEN"
memories status
手机模式选择与切换
首次启动时选择模式;从没有模式设置的旧版升级后,也会显示选择页。App 会记住选择,下次直接进入对应模式。
| 模式 | 数据位置 | 开始使用 |
|---|---|---|
| 单机模式 | 手机本地加密资料库,可离线使用 | 创建资料库,或解锁已有资料库 |
| Center 模式 | 客户自建服务器上的托管库 | 填写完整的 HTTPS 服务地址和成员令牌,点击“连接” |
| SaaS 模式 | https://memories.ivjn.us 的托管库 |
地址固定,填写该服务的成员令牌并连接 |
这里的 Center 模式是自建托管服务,服务器需启用 memories-center --data DIR。它与只签发设备及权限票据的授权 Center 不同。手机端不需要编辑 config.toml、设置 mode = "saas" 或先解锁本地库;这些 TOML 配置用于桌面守护进程。
Center 地址只填服务器源地址,例如 https://center.example.com,不要加 /v1/rpc、查询参数或用户名密码。非回环地址必须使用 HTTPS;手机上的 localhost 指手机本身。成员令牌由服务运营者提供,能执行的操作取决于其保险库、角色、范围和有效期。运营者的管理令牌不能直接代替成员令牌读写内容。
使用中切换
主界面顶部的双向箭头是“切换模式”,登录前后均可使用。弹窗标记当前模式,选择另一个模式即切换;取消则保留当前会话。编辑页需先保存或退出,未保存内容会提示确认。
| 操作 | 结果 |
|---|---|
| 切换模式 | 锁定本地库、停止共享、关闭当前托管连接并清除页面内容,记住新模式 |
| 切回单机 | 原资料库保留,需要重新解锁 |
| 再次进入 Center 或 SaaS | 如有已保存的连接信息,尝试恢复对应连接 |
| 断开连接 | 移除当前模式保存的令牌,保留地址,不影响另一模式的连接信息 |
| 应用进入后台 | 锁定本地访问,关闭托管会话及敏感页面,丢弃未保存草稿 |
| 从后台返回 | 托管页需点击“重新连接已保存的会话”,或重新输入令牌连接 |
切换不会上传、搬迁、合并或删除库中的数据。断开连接不会在服务端吊销令牌。Center 和 SaaS 的地址与令牌分别保存在系统安全存储中;旧版连接只迁移到对应模式,正式 SaaS 地址进入 SaaS,其余地址进入 Center。
各模式的功能范围
单机模式保留本地资料的浏览、搜索、编辑、备份恢复、共享和云连接入口。Center / SaaS 提供托管知识列表、搜索、详情、编辑、创建和删除,以及授权请求审批和已配对设备管理。连接后可查看当前库和授权范围,进入“托管知识”管理内容。新建卡片暂不提供标签、来源和关系;编辑已有普通卡片支持这些字段并保留其他元数据。普通记忆使用正文编辑器;结构化配置、受保护卡片、类型模板及端到端卡片在此仅供查看,修改需使用专用编辑器。
授权页分为“待处理”和“历史记录”。批准或拒绝前可查看申请人、保险库、范围、时长和完整原因,并需确认;批准后仍由申请者单独领取授权。历史记录包含本次连接内的处理记录及服务端返回的已批准请求,不是完整审计日志。连接失败时检查网络、证书、地址、成员令牌,以及自建 Center 是否已启用托管存储。
手机托管模式(Hosted Center)
搜索由服务端执行,不包含私密内容、凭据和文件;清空关键词后返回知识列表,有读取权限时可查看列表中的私密卡片。只读账号不显示修改入口,只写账号可直接创建,删除需要删除权限并再次确认。保存失败保留草稿,服务器确认删除后才退出详情。当前保存未提供基于预期版本的原子并发检查,多人同时编辑同一卡片可能覆盖彼此最新字段。
升级 App 时需同步升级自建 Center,以提供 /v1/session 接口。会话过期或被撤销时,请断开连接后使用有效令牌重新连接;权限不足请联系服务管理员;服务不可用或库锁定时稍后重试。
Center 和 SaaS 共用 FFI memories_call 的 hosted_* 接口:连接、请求列表与审批、访问列表、断开,以及受限的 hosted_rpc。连接通过 hosted_status 校验,对应 GET /v1/session,返回当前库、范围、角色、到期时间和读写删能力,不返回令牌。hosted_rpc 支持列表、读取、搜索、删除、卡片类型、知识卡片创建、字段和凭据操作;put 支持 memory、card 和 credential。完整白名单和设备接口见 手机托管接口。FFI 支持的操作不一定都有对应的 Flutter 页面。
托管模式下服务端可读:Store 在磁盘上加密保存,但运营者持有解锁密码,可以读取托管内容;App 会显示“服务端可读”标记。活跃令牌由 Rust 客户端保存在内存中,Flutter 用系统安全存储保存各模式的连接信息。设备间密封秘密具有独立的端到端保护边界,见下一节。
设备间端到端(E2E)秘密同步
托管 Center 上的普通内容服务端可读。对于不能让服务器看到的秘密,请配对设备并发送密封信封(X25519 加密,发送方 Ed25519 签名);Center 只保存公钥和密文。
配对流程:
1. 电脑:memories device hosted init --backend … 在系统密钥托管中生成设备身份。
2. 电脑(成员令牌):memories device hosted pair --vault V,Center 创建带设备指纹的权限请求,返回一次性配对码和二维码内容(含 Center id)。配对码 5 分钟过期。终端(stderr)打印的二维码同时包含一次性配对码,手机扫码即可;stdout JSON 不变。已激活的设备重复配对返回 409,吊销后可用同一密钥重新配对。
3. 手机(管理员):输入/扫描配对码获取设备公钥(只能获取一次,失败过多会限流)。
4. 手机通过 /v1/requests/{id}/approve 批准,并附上用手机 Ed25519 密钥签名的设备证明(attestation)。
5. 电脑:memories device hosted claim --request-id ID 一次性领取设备授权,令牌保存在系统密钥托管中,Center 只存哈希。
6. 比对 SAS:手机在批准前显示(分组,如 123 456);批准后电脑运行 memories device hosted sas --pairing-id P 应显示相同数字,不同则吊销设备并重新配对。
手机扫码会拒绝非 Memories 配对码、Center id 与当前连接不一致、或设备指纹不一致的二维码。权限:Android CAMERA(相机为可选特性),iOS NSCameraUsageDescription。拒绝相机权限时,手机提示到系统设置开启,并可手动输入配对码。CLI 与手机会把 Center 状态码转为可操作提示(404 过期/已用/其他 Center,409 已处理或已配对,403 无权限或设备已吊销,422 e2e 内容被拒,429 请求过多)。
SAS 定义:SHA-256("memories/device-sas/v1\0" ‖ 手机公钥 ‖ "\0" ‖ 电脑公钥 ‖ "\0" ‖ pairing_id) 前 8 字节按大端转为整数,对 10^6 取模,补零为 6 位。不一致说明公钥被替换,应立即吊销。
规则:设备授权绑定设备与成员代数,委托深度 ≤ 2;设备不能签发授权或审批请求;成员变更会使设备失效并删除其信封;e2e: true 的卡片在托管 Center 上拒绝明文秘密;访问列表包含设备;MCP 提供 device_list 和需要明确意图(intent: "reveal_plaintext" + 理由)的 sealed_reveal。
威胁模型:Center 无法读取密封秘密,但能看到元数据,也可能扣留信封。吊销无法收回已经送达设备的明文——吊销后请在源头轮换该秘密。
E2E 加固(P2)
- e2e 标记不可悄悄撤销:卡片一旦为
e2e: true,去掉该标记的写入会被拒绝(422);只有 Owner 授权(非设备授权)可用不含任何秘密的写入清除它。 - OTP 参数:密封的 OTP 可以是 Base32 种子(SHA1/6 位/30 秒)或完整
otpauth://totp/...URI;sealed-get --otp遵循其中的 algorithm(SHA1/SHA256/SHA512)、digits(6/8)、period(30/60)。device hosted pair会在终端(stderr)打印配对二维码。 - 吊销后重新加密:吊销设备会删除其信封,并把相关卡片标记为
needs_rotation(在 sealed 列表、/v1/sealed/rotation、访问列表和手机重新加密页面可见)。已送达的明文无法召回:请先在源头轮换秘密,再在手机上“为所有设备重新加密”,它只发给当前已批准的设备并清除标记。 - 手机身份恢复:Center 从不保存手机身份。首次创建时显示一次性恢复码(32 字节种子 + 2 字节校验的 Base32,每 4 位一组),请抄写;“用恢复码还原”可恢复同一身份。
- 身份轮换:“迁移到新手机密钥”会生成新身份,并提交由旧密钥和新密钥共同签名的轮换记录(仅管理员成员可提交,旧密钥必须已被某设备信任)。CLI 首次使用时固定批准手机的公钥(
hosted-device-trust.json),只接受从该根经已验证轮换链可达的签名者。 - 硬件存储:手机种子用
flutter_secure_storage最强内置选项保存:iOS/macOS 钥匙串passcode(仅本机、不同步、需设备密码);Android Keystore 包装并要求生物识别或设备凭据,resetOnError: false。限制:签名/加密时种子仍需进入应用内存(Secure Enclave/StrongBox 不支持 X25519/Ed25519),只保护静态存储。 - 透明日志:Center 维护仅追加、哈希链接的设备日志(配对、批准、身份轮换、吊销),
GET /v1/devices/log。memories device hosted log --verify校验链、所有签名,以及日志是否延续上次验证的链头(hosted-device-log.json)。
手机生物识别与设备锁
在单机模式下解锁资料库后,可在更多菜单中开启“使用生物识别/设备锁解锁”。开启时需先通过一次系统验证;该安全开关也用于托管审批等敏感操作。
- Android:使用系统 BiometricPrompt(指纹/面容),并可回退到设备 PIN、图案或密码。快速解锁所需的资料库密码保存在 Android Keystore 绑定的密钥下,该密钥要求用户验证(
setUserAuthenticationRequired),且在新增或删除指纹/面容后自动失效(setInvalidatedByBiometricEnrollment(true))。 - iOS:使用 Face ID/Touch ID(可回退到设备密码),钥匙串条目仅在设备设置了密码时可用。
- 受保护的操作:解锁资料库、显示或复制凭据明文、使用受保护卡片/生成 OTP、批准配对设备、批准托管请求、封装(seal)与重新封装(re-seal)。
- 生物识别信息变更:密钥失效时应用会明确提示,资料库与数据不会被删除;用设备凭据验证后输入一次资料库密码,即可重新创建密钥。
- 无生物识别或关闭开关:设备没有可用的生物识别/设备锁,或开关关闭时,沿用原有的密码流程。关闭开关会删除保存的快速解锁信息。
新建内容(手机端)
新建记忆、凭据和托管中心条目共用同一个编辑器:可从文件导入(默认以文件名为标题,可修改);.env 等配置内容自动切换为等宽多行编辑(也可手动切换);名称可先留空,保存时依次从文件名或第一行非空文本推断,仍为空时才提示输入。
知识卡片采用全屏表单,底部固定保存按钮;“编辑正文”打开共享正文编辑器,可导入文件、手写或扫描。记忆和知识卡片在保存成功后才关闭,保存失败保留草稿供重试,并阻止重复提交。导入覆盖已有正文、离开未保存内容时均需确认。草稿只在内存中保存,后台锁定后不会恢复。单机卡片和托管普通卡片编辑保留标签、来源、关系及自定义字段;托管创建只提供当前创建接口接受的元数据。
多字段凭据
一个凭据可以同时保存多个相互独立、均可为空的字段:用户名/账号、密码、OTP(otpauth:// URI 或 base32 种子及参数)、API Key、URL、备注,以及自定义字段(可标记为机密)。密码、OTP、API Key 和标记为机密的自定义字段只存放在加密正文中;用户名、URL、备注和非机密自定义字段可以直接查看。
memories credential set VAULT [ASSET] --username 我 --url https://example.com --password --otp --field 团队=core --secret-field PIN
memories credential show VAULT ASSET
memories credential get VAULT ASSET --field username
memories credential get VAULT ASSET --field password --reveal
memories credential copy VAULT ASSET --field api_key
memories credential otp VAULT ASSET
memories credential migrate VAULT ASSET
机密值只通过隐藏输入录入,不作为命令行参数。旧的单字段凭据仍可直接读取:otpauth:// 或标题以 OTP: 开头的映射为 OTP,带 HTTP 认证或允许主机的映射为 API Key,其余映射为密码。第一次通过 credential set 修改(或执行 credential migrate)时会改写为结构化格式,旧版本保留在历史中,不会丢失数据。原有只使用单个机密的功能(HTTP 注入、运行绑定、不带 --field 的复制)使用“主机密”:密码优先,其次 API Key、OTP、第一个机密自定义字段。
多字段凭据:MCP、托管中心与端到端同步
- MCP
credential_fields(读权限)只返回非机密字段和机密字段名;credential_reveal(allow_all 授权)需intent: "reveal_plaintext"与理由,逐字段返回并审计。 - 托管中心:端到端(e2e)凭据在中心只保存描述信息,机密字段只存在于设备密封信封中。
- 已配对设备:
memories device sealed-get --vault V --card C --field password --reveal、--otp生成验证码。 - 手机:新建凭据为分区表单(登录信息、一次性验证码、API、更多、自定义字段),全部可空;复制机密字段和查看实时验证码(带倒计时)需系统解锁验证。