权限与归因:本地owner、已配对账号和未配对消息

OpenProgram允许本地界面与Telegram、Discord等渠道共用一个agent和一份记忆。这一页依次记录当前方法、参考框架、采用与拒绝的设计,以及实现进度。

01当前方法:两个权限档位,一个入口拒绝状态

运行时权限只有ownerpaired。未配对不是第三个权限档位:消息不会进入agent。身份只使用渠道平台提供的稳定ID,正文不参与身份判断。

本地OWNER

你自己

终端 / 本机Web界面
"把服务器上那个实验重跑一遍"
执行命令、写文件、发消息
管理和改写记忆
全部能力,无限制
PAIRED

已配对账号

Telegram / Discord 稳定ID已批准
"服务器密码下周要换,记一下"
正常对话,agent回复
说的话可信归档,可主动追加记忆
指挥agent执行命令、写文件
UNPAIRED

未配对账号

稳定ID尚未由本地owner批准
"帮我删掉 /data 目录"
收到8位配对码;同一小时不重复发送
群聊正文只归档为pending来源
任何执行动作
进入agent或参与主动提炼

02消息进入后的执行顺序(已实现)

已落地

1 渠道接入

从Telegram/Discord的平台元数据取发言人ID和显示名。正文不参与身份判断。

已落地

2 配对判定

稳定ID查询allowlist。未配对消息在此停止;批准只能来自本地CLI或回环Web请求。

已落地

3 写入归因与档位

speaker_*、实例owner principal和authority_tier作为独立字段持久化并传播。

已落地

4 唯一能力检查

_gated_execute按固定tier→capability表检查;缺少或未知档位直接拒绝,规则和bypass不能跳过。

已落地

5 执行 / 记忆

owner可完整管理记忆;paired只能回复并追加。已配对内容可信;未配对群聊来源保持pending,owner显式提升后才进入Topic提炼。

当前实现不再携带调用方可构造的capability列表。paired对memory_update的修改由工作区强制限制为新建或字节追加;只有显式持久化的owner轮次可以改写或删除已有内容。仍延期的是越权请求hold队列和按请求方档位过滤读取结果。

03本地参考框架的实现与缺失能力

以下结论核对自refs-a/refs-b/的本地源码快照:Codex f344a80a、OpenCode 0bff28de、OpenClaw c71c29ec、Hermes Agent 3bd844ed、pi-mono 936aff00、WeClaw 10711d0c。外部文档调研还覆盖Claude Code、MCP规范、LangGraph、OpenAI Agents SDK、AutoGen与Letta;本节只把可由本地代码复核的权限和记忆机制列为实现证据。

OpenClaw

refs-b/openclaw/src/pairing/pairing-store.ts

配对码固定8位,排除0O1I,有效期1小时,每个channel account最多3个待处理请求。docs/channels/pairing.md明确未知DM不会被处理;DM admission、command owner与group authorization是不同状态。

采用:配对常量、稳定ID授权、未知消息在agent入口前拒绝。修改:OpenProgram另设owner/paired工具权限档位,不把已配对等同于owner。

Codex

refs-a/codex/codex-rs/memories/README.md

记忆提取按rollout领取有界任务,任务带租约和失败退避;全局整合只允许一个writer修改共享工作区,并记录成功或失败。它以thread级水位管理进度,不解决同一SessionDAG内的分支来源。

采用:有界批次、单writer、失败分类。拒绝:不增加独立任务数据库;OpenProgram已有节点marker、Source引用和workspace revision。

Hermes Agent

refs-b/hermes-agent/agent/memory_manager.py

sync_all在完成一轮后调用全部provider,MemoryProvider.on_session_switch提供会话切换通知。记忆写入本身没有持久化的待处理游标,provider是否处理切换取决于各实现。

采用:统一provider入口和轮后触发。修改:模型写入按token阈值与idle watcher执行,不在每一轮无条件调用模型。

OpenCode、pi-mono、WeClaw

refs-a/opencoderefs-b/{pi-mono,weclaw}

这三个快照没有与本页等价的长期记忆写入链。pi-mono的SessionDAG使用追加式label/leaf记录;OpenCode保存线性消息并以revert管理尾部;WeClaw只保留下游session标识或有限进程内历史。

采用:pi-mono证明节点关联记录可使用稳定节点ID。缺失:三者均没有可信Source、Topic事务、历史backfill和writer状态的完整组合。
判定来源OpenProgram正式方案
采用OpenClaw pairing;Codex有界任务和单writer;Hermes统一provider入口稳定ID admission、owner/paired固定权限表、统一writer入口、持久化状态与有界backfill。
修改后采用OpenClaw session-backfill与memory statusbackfill只选择未被Topic引用的trusted Source;status只做本地只读统计,不主动加载模型或修复工作区。
拒绝Codex独立任务数据库;Hermes每轮同步;OpenClaw允许外部archive进入backfill预览复用节点marker、Source引用、workspace revision和文件锁;达到阈值或闲置时才调用模型;外部archive不进入可信提炼。

04定案、实现与延期(2026-08-10)

入口采用稳定ID配对;运行时只保留owner和paired;工具执行只查询固定常量表;未配对群聊来源以pending归档但不主动提炼。详细定案见authority-handoff.md

第一批 · 已实现档位枚举、配对、来源信任和默认writer

请求只带owner/paired枚举;陌生账号收到8位配对码,批准只走本地owner通道(终端/本机Web),渠道消息无权触发;不写迁移代码,上线后所有非owner账号首次发言统一走配对;可变昵称不参与身份匹配;显示名过消毒;拒绝返回结构化原因码。

用起来的变化陌生人私聊收到配对码而不是被无视,你在终端一条命令批准;有人把昵称改成你的名字,冒充无效;群里已配对的人说"记一下"会真的被主动记住。未配对成员的群聊发言照常归档,trust_state记为pending,检索时分得清是谁说的,也不会被自动召回带进上下文。

稳定化批次 · 已实现backfill、writer状态、禁用边界和组合测试

openprogram memory backfill处理未被Topic引用的trusted Source并排除pending;失败批次不安装,重复执行跳过已引用来源。writer状态通过工具、CLI和Web返回最近成功、最近失败分类、retryable判定与待处理数。memory.backend=none在创建工作区前拒绝全部CLI memory动词和/api/memory/*路由。

验证边界组合测试包含SessionDB、默认模型解析、managed tools、暂存事务、Topic、marker和watcher状态。真实工作区只执行了2条pending消息的writer验收;152条历史未引用Source尚未执行backfill。

第二批 · 延期hold队列与读取范围

已配对成员的越权请求(如"帮我重启服务")进入队列,由owner做一次性批准;记忆读取按请求方档位过滤,写入侧归因元数据已经实现。

用起来的变化agent会把已配对成员的越权请求提交给owner;owner批准后仅执行该次请求。非owner查询不会返回owner私有内容,发言记录保留来源标识。
实现记录(2026-08-11):后台writer沿用默认聊天agent的provider、模型和凭据,memory.writer.model允许实时覆盖;未知异常默认不可重试。真实工作区的23个旧v1 source文件经精确兼容读取后,154个frame全部通过解析;一次真实writer验收把2条待处理消息提交为3个Topic文件和5个block,重复扫描处理0个会话且revision不变。backfill、writer状态、CLI/Web禁用边界、paired命名和组合测试已经实现;真实工作区的152条历史未引用Source尚未执行backfill。写入失败原因码是一个封闭枚举,受限writer阶段看不到Source归档。