OpenHarness源码研究-5-基础设施-配置/认证/权限/扩展
type
Post
status
Published
date
Jun 30, 2026
slug
250630-openhasness-5
summary
把配置、认证、权限、扩展体系、记忆和Swarm这些"基础设施"一次讲清楚。它们不直接产生对话,但没有它们,Agent Loop 一步都走不了。
tags
开发
category
技术分享
icon
password
前言配置-四层覆盖与ProviderProfile认证-三种流统一为一个ResolvedAuth权限-5层决策链扩展体系-四种途径给AI加能力Hook-生命周期拦截MCP-外部工具和资源Plugin-项目级扩展包Skill-slash 命令路由记忆系统-文件级的持久记忆Swarm-多Agent协作总结写到最后
前言
把配置、认证、权限、扩展体系、记忆和Swarm这些"基础设施"一次讲清楚。它们不直接产生对话,但没有它们,Agent Loop 一步都走不了。
配置-四层覆盖与ProviderProfile
Settings 是整个系统的"唯一真相来源"。它通过 Pydantic BaseModel 定义,加载时走四层优先级:
以 model 参数为例:
oh --model deepseek-chat 覆盖 OPENHARNESS_MODEL 环境变量,覆盖 ~/.openharness/settings.json 里的 model 字段,覆盖代码中的默认值 "claude-sonnet-4-6"。具体实现:
这里有一个容易踩坑的设计:扁平字段 vs ProviderProfile 的双轨制。
Settings 上同时有 model、api_format、base_url 这些扁平字段,也有 profiles: dict[str, ProviderProfile] 这个结构化字段。两者描述的是同一件事(当前用什么模型),但来源不同——扁平字段来自 CLI 覆盖,Profile 来自持久化配置。materialize_active_profile() 的作用是把当前 active profile 的数据"投影"回扁平字段。sync_active_profile_from_flat_fields() 则反过来——把 CLI 覆盖的扁平字段"写回" profile。这对方法的注释写得清楚:设计这种双轨制的原因是兼容——旧版只有扁平字段,新版引入了 Profile 概念。如果从零开始设计,可能根本不需要这层同步。
模型别名系统:用户输
sonnet 不是合法的 API 模型名,需要在内部转成 claude-sonnet-4-6:还有特殊的
opusplan 别名——在 plan 模式下用 Opus,其他时候用 Sonnet。把模型选择和权限模式绑定,是个实用的设计。认证-三种流统一为一个ResolvedAuth
认证体系的场景很杂:Claude API Key、OpenAI API Key、GitHub OAuth 设备码、Codex JWT Token、Claude 订阅 OAuth Token。每种来源不同、存储位置不同、刷新策略不同。AuthManager 把它们统一为一个返回类型:
resolve_auth() 的查找顺序体现了优先级:这套优先级保证了:命令行临时覆盖 > 环境变量 > 持久化配置 > keyring。同时"外部订阅"这一类认证在最前面,因为它最特殊——token 有过期时间,需要刷新逻辑。
认证的存储有两套机制:keyring(系统密钥链,macOS 是 Keychain,Linux 是 Secret Service)和明文文件(
~/.openharness/ 下的 JSON 文件)。keyring 用于 API Key 这种敏感数据,明文文件用于 OAuth token 缓存和外部订阅绑定。权限-5层决策链
permissions/checker.py 的 PermissionChecker.evaluate() 是一个顺序执行的决策链,前一步拦截了就不往后走:关键实现细节:
is_read_only 不仅仅是个标志位,它决定了整个后半段逻辑。读操作在 DEFAULT/PLAN 模式下都是直接放行的,只有当工具声明自己是"非只读"时,权限检查才真正介入。敏感路径列表值得单独拿出来看:
这些路径在任何权限模式下都不可访问。即使你开了
--dangerously-skip-permissions,这个检查也不会跳过——它是在 PermissionChecker.evaluate() 最开头就执行的,不经过任何模式判断。扩展体系-四种途径给AI加能力
Hook-生命周期拦截
Hook 只有 4 个事件,但覆盖了关键的拦截点:
每种 Hook 有三种实现方式:
- Command Hook:执行一个 shell 命令,把 payload 通过环境变量或
$ARGUMENTS模板注入
- HTTP Hook:POST 到指定 URL,payload 作为 JSON body
- Prompt Hook / Agent Hook:调 LLM 判断,返回
{"ok": true}或{"ok": false, "reason": "..."}
PRE_TOOL_USE 可以阻止工具执行,POST_TOOL_USE 可以做事后审计。SESSION_START/END 用于初始化和清理。Hook 的 matcher 机制用
fnmatch 做通配符匹配,可以指定"只对 bash 工具生效"或"只对包含特定关键字的 prompt 生效"。MCP-外部工具和资源
MCP(Model Context Protocol)是一种标准化的工具扩展协议。任何实现了 MCP 协议的服务端,都可以作为工具源接入:
MCP 工具会和内置工具一起注册到 ToolRegistry 中。对 Agent Loop 来说,MCP 工具和内置工具没有区别——都是
BaseTool 的子类实例。Plugin-项目级扩展包
Plugin 是比 Skill 更重的扩展机制。每个 Plugin 有自己的 manifest,可以注册命令、Hook、Skill。Plugin 的发现基于目录扫描,加载时做 manifest 校验。
Skill-slash 命令路由
Skill 是用户最常见的扩展入口。通过
/skill-name 的方式调用。Skill 的注册是声明式的——在特定目录下放一个 markdown 文件,定义 name 和 description,运行时自动发现。handle_line() 处理用户输入时,先查 slash 命令注册表,匹配到就路由给对应 handler,没匹配到就当作普通对话发给引擎。记忆系统-文件级的持久记忆
记忆系统用 Markdown 文件做持久化,每个记忆是一个独立的
.md 文件,放在项目下的 .claude/memory/ 目录中:每个记忆文件有 frontmatter 元数据(name、description、type),正文是记忆内容。
[[wikilink]] 语法用于关联相关记忆。召回路径:
build_runtime_system_prompt() 在构建 System Prompt 时,先加载 MEMORY.md 索引(作为概览注入),再用 find_relevant_memories() 做关键词检索,把和当前用户 prompt 最相关的几个记忆全文注入:Swarm-多Agent协作
Swarm 系统允许一个"leader" Agent 启动多个"worker" Agent 并行工作。核心组件:
- TeammateSpawnConfig:定义 worker 的 peer 配置(name、prompt、model、permissions、worktree 隔离路径)
- TeammateMailbox:Agent 间通信的消息队列。每个 Agent 有一个 inbox 目录,消息是独立的 JSON 文件。写入先写
.tmp再os.rename保证原子性,读取按时间戳排序
- Worktree:可选的 git worktree 隔离,每个 worker 在独立的文件系统沙箱中操作
- Backend:
subprocess(子进程)、in_process(协程)、tmux/iterm2(终端面板)三种执行模式
Mailbox 支持的消息类型:user_message(文本消息)、permission_request/response(权限协商)、shutdown(关闭指令)、idle_notification(空闲通知)。
AgentTool(第 4 篇提过)就是通过
TeammateExecutor.spawn() 启动新 Agent,Swarm 相当于 AgentTool 的"多对多"版本——不只是嵌套调用,而是持续性的团队协作。总结
- Settings 四层覆盖(cli → env → file → default),扁平字段和 ProviderProfile 双轨同步是历史包袱,不是理想设计
- AuthManager 把 API Key / OAuth / JWT 三种认证流统一为
ResolvedAuth,查找顺序体现了优先级的精心安排
- PermissionChecker 是 5 层顺序决策链,敏感路径保护是最外层、不可绕过
- Hook 提供 4 个生命周期拦截点,MCP 提供标准化外部工具协议,Plugin 和 Skill 负责扩展发现和路由
- 记忆系统用 Markdown 文件做持久化,召回时标题命中权重是正文的 2 倍
- Swarm 把单 Agent 的工具调用升级为多 Agent 的持续性协作,Mailbox 用文件系统实现消息队列
写到最后
Prev
OpenHarness源码研究-6-架构全景与设计模式总结
Next
OpenHarness源码研究-4-AgentLoop对话引擎与工具系统
Loading...

