docs: README 对齐 1.4.0 现状,并移除看板娘

四处过时事实:
  1. 「v1.3.x 线(v1.3.1–v1.3.12,最新已发布)」→ 补上 v1.3.13,并按 main 的实际内容
     新增 v1.4.x 段落(同轮工具并行、seq 序列编排、结果只统计不裁剪、结构化错误契约、
     设备命令白名单、GUI 增量渲染)。这些是 MAIN 上已合入但 README 从未提及的特性。
  2. 「内置 18 个插件」×2 → 实际 20 个(漏了 seq / kbtree 等)。
  3. 6 处 gitcode 链接 → GitHub(仓库已迁至 github.com/JianFeeeee/HomeAgent,
     SDK 为 github.com/JianFeeeee/homeagentsdk)。gitcode 仍作国内镜像保留。
  4. 移除「看板娘 / Web Mascot」整段(中英文各一处)—— 按用户要求。

三张架构图按代码重画(此前图上缺了 1.4.0 的核心机制):
  - 图一「消息处理时序」:tool 分支改为**批**语义 —— batchRunnable 三条判据
    (批内 >1、全部 ParallelSafe、无同通道重复发送)、可并发/整批降级两条路、
    以及「按声明序收尾 + 同通道保序」。
  - 图二「Stage 管道」:④⑤ 拆成并发/串行两条边,并注明并行只影响执行时序,
    post_action 与 after_toolcall 的可见顺序不变。
  - 图三「三层记忆」:补上**场面识别(声明 + 涌现)**子系统 —— 指纹权重、
    归属/唤起阈值、origin=declared|emergent、用进废退衰减。

另加一段说明:agent 自己的回复也写回记忆(context.Append(Source:"agent")),
因此它能读到自己先前的结论并主动纠正 —— 这是记忆召回的自然结果,
内核里**没有**任何名为「反思」的机制(避免把涌现行为误读成已实现的特性)。
This commit is contained in:
JianFeeeee
2026-09-29 17:09:02 +08:00
parent 2c34a7938c
commit f0d943e4bb
2 changed files with 142 additions and 55 deletions

View File

@ -26,6 +26,18 @@ homed(内核零 IO) ← PluginSDK → 插件(所有 IO 能力)
- **Document 层**:临时记忆,冷数据自动下沉,也支持用户主动提交 - **Document 层**:临时记忆,冷数据自动下沉,也支持用户主动提交
- **Graph 层**:SQLite 图数据库,持久化实体关系和语义记忆,支持蒸馏管道从原始对话中提取三元组 - **Graph 层**:SQLite 图数据库,持久化实体关系和语义记忆,支持蒸馏管道从原始对话中提取三元组
**场面识别:声明 + 涌现** — 记忆不按「会话」切,而按**可观察的场所指纹**切:
通道(`chan:*`)与对话对象最强(权重 1.0),工具 0.8、话题 0.4、时段最弱 0.2。
两条路同时走——**声明**(注入点/工具声明「这是哪个场面」)与**涌现**
(指纹同类重复 ≥2 次就自己长出场景,`origin=emergent`,无需标注、无需模型配合)。
相似度 ≥0.5 判归属、≥0.35 判唤起(**唤起比归属宽松**:想不起来是损失,多想起一条只是多几行上下文)。
场景每次重现强度 +1,久不重现按半衰期衰减。
> 这条机制有一个值得注意的副作用:**agent 自己的回复也写回记忆**
> (`task.go` 的 `context.Append(Source: "agent")`),所以它在同一场面上会**读到自己先前的结论**。
> 当输入已过期时,它会据此认出「这事上一轮已经办过」并**主动纠正自己先前的错误判断**——
> 表现为自我复盘。这是记忆召回的自然结果,内核里**没有**任何名为「反思」的机制。
**输入调度:两类别 + 四级中断** — 输入不直接进 LLM,先进调度器。 **输入调度:两类别 + 四级中断** — 输入不直接进 LLM,先进调度器。
排队(待办工作)与中断(按"有多不能等"分 L1~L4)两类;高级可抢占低级并保存现场 排队(待办工作)与中断(按"有多不能等"分 L1~L4)两类;高级可抢占低级并保存现场
(中断栈),同级不抢占。L4 只归内核与内核级插件(如 WebUI 终止按钮)。 (中断栈),同级不抢占。L4 只归内核与内核级插件(如 WebUI 终止按钮)。
@ -76,14 +88,22 @@ sequenceDiagram
LLM->>LLM: 安全点:中断求值/让位 LLM->>LLM: 安全点:中断求值/让位
LLM->>LLM: LLM Chat LLM->>LLM: LLM Chat
LLM->>ST: StagePostAction 插件可修改/短路 LLM->>ST: StagePostAction 插件可修改/短路
alt 无tool call alt 无 tool call
LLM-->>EV: 返回response LLM-->>EV: 返回response
else else 一批 N 个 tool_call
loop 每个tool Note over EV: batchRunnable 判据:批内 >1 且全部 ParallelSafe<br/>且无同通道重复发送(output_send__「通道」)
ST->>ST: StageBeforeToolcall 插件可拒绝 alt 可并发(三条全满足)
LLM->>LLM: executeToolCall par fan-out 并发执行
ST->>ST: StageAfterToolcall ST->>ST: StageBeforeToolcall ×N 插件可拒绝
LLM->>LLM: executeToolCall ×N
end
else 整批降级串行(任一个未声明 ParallelSafe)
loop 每个 tool 依次
ST->>ST: StageBeforeToolcall 插件可拒绝
LLM->>LLM: executeToolCall
end
end end
Note over EV: 顺序收尾:按**声明序** StageAfterToolcall → 落 tool 消息<br/>同通道输出严格保序
end end
end end
end end
@ -104,18 +124,26 @@ sequenceDiagram
flowchart LR flowchart LR
S1[① on_input] --> S2[② pre_action] S1[① on_input] --> S2[② pre_action]
S2 --> S3[③ post_action] S2 --> S3[③ post_action]
S3 --> Q{有tool?} S3 --> Q{有 tool_call?}
Q -->|是| S4[④ before_toolcall] Q -->|是,一批 N 个| PB{batchRunnable?<br/>全声明 ParallelSafe<br/>且无同通道重复发送}
S4 --> T[executeToolCall] PB -->|可并发| S45P[④⑤ 并发 ×N<br/>before_toolcall×N → 执行×N<br/>→ 按声明序 after_toolcall]
T --> S5[⑤ after_toolcall] PB -->|整批降级| S45S[④⑤ 依次 ×N<br/>before_toolcall → 执行<br/>→ after_toolcall]
S5 --> S3 S45P --> S3
S45S --> S3
Q -->|否| S6[⑥ before_output] Q -->|否| S6[⑥ before_output]
S6 --> S7[⑦ after_output] S6 --> S7[⑦ after_output]
style S1 fill:#e1f5fe style S1 fill:#e1f5fe
style S3 fill:#fff3e0 style S3 fill:#fff3e0
style S6 fill:#e8f5e9 style S6 fill:#e8f5e9
style S45P fill:#fce4ec
style S45S fill:#f5f5f5
``` ```
> ①–⑦ 七个 Stage 均由 `internal/sdk/plugin.go` 公开(`StageOnInput` … `StageAfterOutput`),
> 插件可注册挂钩。⚠️ 并行只影响 **④⑤ 的执行时序**:`post_action` 仍在本批工具
> 全部收尾后由下一轮触发,`after_toolcall` 也仍按**声明序**回调——
> 并发的是 IO 等待,不是插件契约的可见顺序。
### 三、三层记忆 ### 三、三层记忆
```mermaid ```mermaid
@ -138,6 +166,17 @@ flowchart TB
IDX[Indexer 向量+jieba→BFS depth=2] -->|【记忆索引】| SP IDX[Indexer 向量+jieba→BFS depth=2] -->|【记忆索引】| SP
MEM[memory_recall/commit/merge/purge/edit] MEM[memory_recall/commit/merge/purge/edit]
SOC[person_query/set_trait] SOC[person_query/set_trait]
subgraph SC[场面识别:声明 + 涌现]
FE[① 指纹 chan/peer/tool/topic/part<br/>权重 1.0/1.0/0.8/0.4/0.2]
EN{② EnterSceneWithHint<br/>相似度 ≥0.5 归属<br/>≥0.35 唤起}
FE --> EN
EN -->|插件已声明| DEC[origin=declared]
EN -->|重现 ≥2 次| EM[origin=emergent<br/>自动长出场景]
EM -->|每次重现 strength+1| STR[③ 用进废退<br/>久不重现按半衰期衰减]
DEC --> STR
end
STR -->|Primary| CARRY[本轮命中的场景<br/>挂载的记忆自动唤起]
CARRY -->|【场景记忆】| SP
end end
subgraph H[④ 心跳蒸馏] subgraph H[④ 心跳蒸馏]
REORG -->|Step3 冷文档| CD REORG -->|Step3 冷文档| CD
@ -151,13 +190,6 @@ flowchart TB
详细说明见 [`assets/docs/zh/ARCHITECTURE.md`](assets/docs/zh/ARCHITECTURE.md)。 详细说明见 [`assets/docs/zh/ARCHITECTURE.md`](assets/docs/zh/ARCHITECTURE.md)。
## 看板娘
<div align="center">
<img src="assets/branding/mascot-xiaozhai.webp" alt="HomeAgent 看板娘 小宅" width="200">
<p><strong>小宅</strong> — HomeAgent 看板娘</p>
</div>
## 快速体验 ## 快速体验
```bash ```bash
@ -203,17 +235,33 @@ internal/
├── memory/ 三层记忆:Graph(SQLite) / Document(JSON+TF-IDF) / Text(JSONL) + StaticEmbedder(预训练词嵌入/TF-IDF回退) + CleanTemplateText(去模版) ├── memory/ 三层记忆:Graph(SQLite) / Document(JSON+TF-IDF) / Text(JSONL) + StaticEmbedder(预训练词嵌入/TF-IDF回退) + CleanTemplateText(去模版)
├── knowledge/ 知识库(文件系统 + TF-IDF) ├── knowledge/ 知识库(文件系统 + TF-IDF)
├── plugin/ 插件注册表 + 子进程加载器(stdio RPC + 共享内存段 + 事件环) ├── plugin/ 插件注册表 + 子进程加载器(stdio RPC + 共享内存段 + 事件环)
├── plugins/ 内置 18 个插件(webui/cli/timer/cmd/mcp/files/cfgmgr/agentcli/healthcheck/pluginmgr/clawhubadapter/multimodal/remotedevice/ai_image/localuse/skillmgr/data 等) ├── plugins/ 内置 20 个插件(webui/cli/timer/cmd/mcp/files/cfgmgr/agentcli/healthcheck/pluginmgr/clawhubadapter/multimodal/remotedevice/ai_image/localuse/skillmgr/data/seq/kbtree 等)
├── sdk/ PluginSDK(Tool/Stage/Event 三通道) ├── sdk/ PluginSDK(Tool/Stage/Event 三通道)
├── config/ SQLite 配置中心 ├── config/ SQLite 配置中心
├── events/ 事件总线 ├── events/ 事件总线
└── internal/lua/adapters/ 10 个 LLM 协议适配器脚本 └── internal/lua/adapters/ 10 个 LLM 协议适配器脚本
外部插件开发见 [homeagent-sdk](https://gitcode.com/JianFeeeee/homeagent-sdk) 仓库,使用 `hmapdev` 工具链开发,参考 `example/` 目录下的 Go 和 Lua 示例 外部插件开发见 [homeagent-sdk](https://github.com/JianFeeeee/homeagentsdk) 仓库,使用 `hmapdev` 工具链开发,参考 `example/` 目录下的 Go 和 Lua 示例
``` ```
## 项目状态 ## 项目状态
**v1.3.x 线**(v1.3.1–v1.3.12,最新已发布)—— **驻留式子 agent** + **输入调度器重做**。 **v1.4.x 线**(进行中,`main`)—— **声明式并发安全** + **序列编排(seq)** + **工具结果诚实化**。
- **同轮工具并行执行**:同一轮里的多个 `tool_call` 默认并发执行,**但以「安全」为前置**——
工具必须在自己的 `ToolDef` 里显式声明 `ParallelSafe`(内置工具用 `toolDefOptions`),
未声明的一律串行;`Serial` 优先级更高。**批内只要有一个不安全,整批降级为串行**。
并发声明写在**工具自身**,内核不做硬编码工具名安全表。同通道输出**严格保序**,
结果与文本分离(`toolOutcome.Text` / `Raw`)。
- **`seq` 序列编排插件**:AST 解析 + 持久化、具名 group、变量槽、**组内并行 + 组间串行**、
条件调用(`seq_when_call`)、跨序列调用图与环检测、错误契约。
- **工具结果只统计不裁剪**:结果超出预算时**报告**统计量,不静默截断。
- **结构化工具错误契约**:参数按 schema **预校验**(分派前拦下)、
「工具不存在」与「执行失败」区分、`Success` 不再恒真。
- **设备命令白名单可配置**(waiter `device_cmd_allowlist`)、
**站点漂移巡检**、**GUI 增量渲染**(保留全部历史,按 `data-msgkey` 复用节点,
50/200/400 条实测 8.2/23.5/38.2ms)。
**v1.3.x 线**(v1.3.1–v1.3.13)—— **驻留式子 agent** + **输入调度器重做**。
- **驻留式子 agent**:内核可派驻轻量内核的子 agent(自己的调度器、自己的 temp 图记忆、 - **驻留式子 agent**:内核可派驻轻量内核的子 agent(自己的调度器、自己的 temp 图记忆、
共享通道登记表)。父经 `resident_agents`(list/create/send/inspect/compress/reclaim/destroy) 共享通道登记表)。父经 `resident_agents`(list/create/send/inspect/compress/reclaim/destroy)
@ -278,7 +326,7 @@ internal/
**v0.9.0** — C ABI v2:外部插件 Stage 回调支持写回(`invoke_stage` 增加 result 输出,插件可在 OnInput/AfterToolcall/PostAction 修改 RawMessage/LLMText/ToolResults 等并同步回内核),ABI 版本随内核 minor 对齐(v0.9.x → ABIVersion=2,`version_min=1` 向后兼容旧插件)。同步修复工具循环 zen 兼容补位误伤首轮 system 上下文的问题。配套 SDK 提供增强版 sanitizer 示例(坏 UTF-8/U+FFFD/ANSI 转义全链路清洗)。**该 ABI 已随 v1.0.0 退场。** **v0.9.0** — C ABI v2:外部插件 Stage 回调支持写回(`invoke_stage` 增加 result 输出,插件可在 OnInput/AfterToolcall/PostAction 修改 RawMessage/LLMText/ToolResults 等并同步回内核),ABI 版本随内核 minor 对齐(v0.9.x → ABIVersion=2,`version_min=1` 向后兼容旧插件)。同步修复工具循环 zen 兼容补位误伤首轮 system 上下文的问题。配套 SDK 提供增强版 sanitizer 示例(坏 UTF-8/U+FFFD/ANSI 转义全链路清洗)。**该 ABI 已随 v1.0.0 退场。**
**v0.8.0** — 核心可用,插件系统增强。内置 20+ 插件,外部插件开发见 [homeagent-sdk](https://gitcode.com/JianFeeeee/homeagent-sdk) 仓库。新增输入通道 `NoMemory`/`Cleaner`、`ChannelDef`、插件禁用/启用系统(CLI + WebUI),`plugindev` 工具链完成 C ABI `ChannelDef` 传递。 **v0.8.0** — 核心可用,插件系统增强。内置 20+ 插件,外部插件开发见 [homeagent-sdk](https://github.com/JianFeeeee/homeagentsdk) 仓库。新增输入通道 `NoMemory`/`Cleaner`、`ChannelDef`、插件禁用/启用系统(CLI + WebUI),`plugindev` 工具链完成 C ABI `ChannelDef` 传递。
## 文档 ## 文档
@ -290,7 +338,7 @@ internal/
## 下载 ## 下载
[Releases](https://gitcode.com/JianFeeeee/HomeAgent/releases) 提供三种变体: [Releases](https://github.com/JianFeeeee/HomeAgent/releases) 提供三种变体:
| 变体 | 内容 | 适用 | | 变体 | 内容 | 适用 |
| --- | --- | --- | | --- | --- | --- |
@ -328,12 +376,12 @@ make install # 安装到系统
**通过网络提供服务时也要向使用者提供源码**(§13 Remote Network Interaction)。 **通过网络提供服务时也要向使用者提供源码**(§13 Remote Network Interaction)。
即:任何人把改过的 HomeAgent 对外提供网络服务,都必须让该服务的使用者拿到改动后的源码。 即:任何人把改过的 HomeAgent 对外提供网络服务,都必须让该服务的使用者拿到改动后的源码。
插件与本项目通过公开 [homeagent-sdk](https://gitcode.com/JianFeeeee/homeagent-sdk) 静态链接 插件与本项目通过公开 [homeagent-sdk](https://github.com/JianFeeeee/homeagentsdk) 静态链接
(SDK 源码会进入插件二进制),但那个仓**以 MIT 发布**——MIT 是宽松许可,拿到授权的代码不继承 (SDK 源码会进入插件二进制),但那个仓**以 MIT 发布**——MIT 是宽松许可,拿到授权的代码不继承
本项目的 AGPL。因此**外部插件不是本项目的衍生作品**,作者可自行选择许可(含闭源、商业、私有), 本项目的 AGPL。因此**外部插件不是本项目的衍生作品**,作者可自行选择许可(含闭源、商业、私有),
既不必同许可、也不受 §13 网络条款约束。第三方插件生态的安全与活跃正建立在这条之上。 既不必同许可、也不受 §13 网络条款约束。第三方插件生态的安全与活跃正建立在这条之上。
边界很清楚:**AGPL 覆盖内核与随包内置插件**(`homed`、`internal/`、`internal/plugins/` 下 18 个内置插件); 边界很清楚:**AGPL 覆盖内核与随包内置插件**(`homed`、`internal/`、`internal/plugins/` 下 20 个内置插件);
**MIT 覆盖公开 SDK**(`sdk/`,`go.mod` 零外部依赖、只依赖 Go 标准库,不引用内核任何代码)。 **MIT 覆盖公开 SDK**(`sdk/`,`go.mod` 零外部依赖、只依赖 Go 标准库,不引用内核任何代码)。
子进程隔离在这里不重要了——决定许可的是被链接的 SDK 代码本身,而它是 MIT。 子进程隔离在这里不重要了——决定许可的是被链接的 SDK 代码本身,而它是 MIT。

View File

@ -87,12 +87,20 @@ sequenceDiagram
LLM->>ST: StagePostAction Plugin can modify/short-circuit LLM->>ST: StagePostAction Plugin can modify/short-circuit
alt No tool call alt No tool call
LLM-->>EV: Returns response LLM-->>EV: Returns response
else else a batch of N tool_calls
loop Each tool Note over EV: batchRunnable criteria: batch >1 AND all declare ParallelSafe<br/>and no same-channel duplicate send (output_send__«channel»)
ST->>ST: StageBeforeToolcall Plugin can reject alt parallel (all three satisfied)
LLM->>LLM: executeToolCall par fan-out concurrent execution
ST->>ST: StageAfterToolcall ST->>ST: StageBeforeToolcall ×N Plugin can reject
LLM->>LLM: executeToolCall ×N
end
else whole batch degrades to serial (any undeclared)
loop Each tool in turn
ST->>ST: StageBeforeToolcall Plugin can reject
LLM->>LLM: executeToolCall
end
end end
Note over EV: ordered tail: StageAfterToolcall in **declaration order** → append tool msgs<br/>same-channel output strictly ordered
end end
end end
end end
@ -113,18 +121,27 @@ sequenceDiagram
flowchart LR flowchart LR
S1[① on_input] --> S2[② pre_action] S1[① on_input] --> S2[② pre_action]
S2 --> S3[③ post_action] S2 --> S3[③ post_action]
S3 --> Q{Has tool?} S3 --> Q{Any tool_call?}
Q -->|Yes| S4[④ before_toolcall] Q -->|Yes, batch of N| PB{batchRunnable?<br/>all declare ParallelSafe<br/>and no same-channel duplicate send}
S4 --> T[executeToolCall] PB -->|parallel| S45P[④⑤ concurrent ×N<br/>before_toolcall×N → execute×N<br/>→ after_toolcall in declaration order]
T --> S5[⑤ after_toolcall] PB -->|degrade to serial| S45S[④⑤ sequential ×N<br/>before_toolcall → execute<br/>→ after_toolcall]
S5 --> S3 S45P --> S3
S45S --> S3
Q -->|No| S6[⑥ before_output] Q -->|No| S6[⑥ before_output]
S6 --> S7[⑦ after_output] S6 --> S7[⑦ after_output]
style S1 fill:#e1f5fe style S1 fill:#e1f5fe
style S3 fill:#fff3e0 style S3 fill:#fff3e0
style S6 fill:#e8f5e9 style S6 fill:#e8f5e9
style S45P fill:#fce4ec
style S45S fill:#f5f5f5
``` ```
> All seven stages ①–⑦ are published by `internal/sdk/plugin.go` (`StageOnInput` …
> `StageAfterOutput`); plugins may register hooks. ⚠️ Parallelism affects only the
> **execution timing of ④⑤**: `post_action` still fires on the next round once the whole
> batch is collected, and `after_toolcall` still runs in **declaration order** —
> what runs concurrently is IO waiting, not the plugin-visible contract order.
### 3. Three-Layer Memory ### 3. Three-Layer Memory
```mermaid ```mermaid
@ -137,16 +154,27 @@ flowchart TB
end end
subgraph D[② Document File Memory] subgraph D[② Document File Memory]
DS[DocStore JSON+TF-IDF] DS[DocStore JSON+TF-IDF]
Q1[Query summary auto-inject] -->|[Related Memory Docs]| SP Q1[Query summary auto-inject] -->|Related Memory Docs| SP
Q2[doc_query LLM active recall] -->|Consume+delete source| DS Q2[doc_query LLM active recall] -->|Consume+delete source| DS
Q2 -->|Original timestamp write to context| RC Q2 -->|Original timestamp write to context| RC
CD[FindColdDocs 72h] -->|docToTriples| G CD[FindColdDocs 72h] -->|docToTriples| G
end end
subgraph G[③ Graph Database] subgraph G[③ Graph Database]
DB[(SQLite)] DB[(SQLite)]
IDX[Indexer vector+jieba→BFS depth=2] -->|[Memory Index]| SP IDX[Indexer vector+jieba→BFS depth=2] -->|Memory Index| SP
MEM[memory_recall/commit/merge/purge/edit] MEM[memory_recall/commit/merge/purge/edit]
SOC[person_query/set_trait] SOC[person_query/set_trait]
subgraph SC[Scene recognition: declared + emergent]
FE[① fingerprint chan/peer/tool/topic/part<br/>weights 1.0/1.0/0.8/0.4/0.2]
EN{② EnterSceneWithHint<br/>similarity ≥0.5 join<br/>≥0.35 recall}
FE --> EN
EN -->|plugin declared| DEC[origin=declared]
EN -->|seen ≥2 times| EM[origin=emergent<br/>the scene grows itself]
EM -->|each recurrence strength+1| STR[③ use-it-or-lose-it<br/>decay by half-life when unused]
DEC --> STR
end
STR -->|Primary| CARRY[scene hit this round<br/>its memories auto-recalled]
CARRY -->|Scene Memory| SP
end end
subgraph H[④ Heartbeat Distillation] subgraph H[④ Heartbeat Distillation]
REORG -->|Step3 Cold docs| CD REORG -->|Step3 Cold docs| CD
@ -160,13 +188,6 @@ flowchart TB
See [`assets/docs/en/ARCHITECTURE.md`](assets/docs/en/ARCHITECTURE.md) for details. See [`assets/docs/en/ARCHITECTURE.md`](assets/docs/en/ARCHITECTURE.md) for details.
## Web Mascot
<div align="center">
<img src="assets/branding/mascot-xiaozhai.webp" alt="HomeAgent Web Mascot Xiaozhai" width="200">
<p><strong>Xiaozhai</strong> — HomeAgent Web Mascot</p>
</div>
## Quick Start ## Quick Start
```bash ```bash
@ -195,17 +216,35 @@ internal/
├── memory/ Three-layer memory: Graph(SQLite) / Document(JSON+TF-IDF) / Text(JSONL) + StaticEmbedder(pretrained word embedding/TF-IDF fallback) + CleanTemplateText(de-template) ├── memory/ Three-layer memory: Graph(SQLite) / Document(JSON+TF-IDF) / Text(JSONL) + StaticEmbedder(pretrained word embedding/TF-IDF fallback) + CleanTemplateText(de-template)
├── knowledge/ Knowledge base (filesystem + TF-IDF) ├── knowledge/ Knowledge base (filesystem + TF-IDF)
├── plugin/ Plugin registry + subprocess loader (stdio RPC + shared memory segment + event ring) ├── plugin/ Plugin registry + subprocess loader (stdio RPC + shared memory segment + event ring)
├── plugins/ 18 built-in plugins (webui/cli/timer/cmd/mcp/files/cfgmgr/agentcli/healthcheck/pluginmgr/clawhubadapter/multimodal/remotedevice/ai_image/localuse/skillmgr/data, ...) ├── plugins/ 20 built-in plugins (webui/cli/timer/cmd/mcp/files/cfgmgr/agentcli/healthcheck/pluginmgr/clawhubadapter/multimodal/remotedevice/ai_image/localuse/skillmgr/data/seq/kbtree, ...)
├── sdk/ PluginSDK (Tool/Stage/Event three channels) ├── sdk/ PluginSDK (Tool/Stage/Event three channels)
├── config/ SQLite config center ├── config/ SQLite config center
├── events/ Event bus ├── events/ Event bus
└── internal/lua/adapters/ 10 LLM protocol adapter scripts └── internal/lua/adapters/ 10 LLM protocol adapter scripts
External plugin development: see [homeagent-sdk](https://gitcode.com/JianFeeeee/homeagent-sdk) repo, use `hmapdev` toolchain, refer to Go and Lua examples in `example/` External plugin development: see [homeagent-sdk](https://github.com/JianFeeeee/homeagentsdk) repo, use `hmapdev` toolchain, refer to Go and Lua examples in `example/`
``` ```
## Project Status ## Project Status
**v1.3.x line** (v1.3.1–v1.3.12, latest released) — **resident sub-agents** + **input scheduler rework**. **v1.4.x line** (in progress, `main`) — **declarative concurrency safety** + **sequence orchestration (seq)** + **honest tool results**.
- **Same-round parallel tool execution**: multiple `tool_call`s in one round run concurrently,
**but safety gates it** — a tool must explicitly declare `ParallelSafe` in its own `ToolDef`
(built-ins use `toolDefOptions`); anything undeclared runs serially, and `Serial` wins.
**A single unsafe tool degrades the whole batch to serial.** Declarations live **in the tool
itself**; the kernel keeps no hardcoded name table. Same-channel output stays **strictly ordered**,
and results are separated from text (`toolOutcome.Text` / `Raw`).
- **`seq` orchestration plugin**: AST parsing + persistence, named groups, variable slots,
**parallel within a group / serial between groups**, conditional calls (`seq_when_call`),
cross-sequence call graph with cycle detection, error contract.
- **Tool results are reported, never silently truncated** — over budget emits statistics.
- **Structured tool error contract**: arguments pre-validated against the schema (rejected before
dispatch), "tool not found" distinguished from "execution failed", `Success` no longer always true.
- **Configurable device command allowlist** (waiter `device_cmd_allowlist`),
**site drift watcher**, **incremental GUI rendering** (keeps all history, reuses nodes by
`data-msgkey`; 50/200/400 messages measured at 8.2/23.5/38.2ms).
**v1.3.x line** (v1.3.1–v1.3.13) — **resident sub-agents** + **input scheduler rework**.
- **Resident sub-agents**: the kernel can station lightweight-kernel child agents (their own - **Resident sub-agents**: the kernel can station lightweight-kernel child agents (their own
scheduler, their own temp graph memory, sharing the channel registry). The parent dispatches scheduler, their own temp graph memory, sharing the channel registry). The parent dispatches
@ -215,11 +254,11 @@ External plugin development: see [homeagent-sdk](https://gitcode.com/JianFeeeee/
(consistent across all three filter points) lets parent/child deliver to each other; (consistent across all three filter points) lets parent/child deliver to each other;
device capabilities became output channels too (one `device/<id>` per device). device capabilities became output channels too (one `device/<id>` per device).
- **Input scheduler**: two task classes (queued/interrupt) + four interrupt levels (L1–L4) - **Input scheduler**: two task classes (queued/interrupt) + four interrupt levels (L1–L4)
+ preempt/suspend/resume/interrupt-stack; same level never preempts same level, with a - preempt/suspend/resume/interrupt-stack; same level never preempts same level, with a
starvation guard and preemption cooldown. L4 belongs only to the kernel and kernel-level starvation guard and preemption cooldown. L4 belongs only to the kernel and kernel-level
plugins (e.g. the WebUI stop button). plugins (e.g. the WebUI stop button).
- **Lightweight kernel profile**: a child's memory surface narrows to "conventional context - **Lightweight kernel profile**: a child's memory surface narrows to "conventional context
+ graph memory" (narrow interface; the main graph opens as a query_only handle, writes go - graph memory" (narrow interface; the main graph opens as a query_only handle, writes go
to its own temp instance). to its own temp instance).
- **Backlog timely feedback** (later in the line): when the main agent is busy for a long time, - **Backlog timely feedback** (later in the line): when the main agent is busy for a long time,
the kernel hands queued input to a temporary **triage assistant** — simple items are handled the kernel hands queued input to a temporary **triage assistant** — simple items are handled
@ -307,7 +346,7 @@ semantic memory; the blob is only a cache that capacity GC may evict.
**v0.9.0** — C ABI v2: external plugin Stage callbacks can now write back (`invoke_stage` gained a result out-param; plugins may mutate RawMessage/LLMText/ToolResults etc. in OnInput/AfterToolcall/PostAction and have them synced to the core). ABI version now tracks core minor releases (v0.9.x → ABIVersion=2, `version_min=1` keeps old plugins loadable). Also fixes the tool-loop zen-compat placeholder that wrongly fired on first-turn system context tail. The SDK ships an enhanced sanitizer example (bad-UTF-8 / U+FFFD / ANSI-escape scrub across the whole pipeline). **This ABI retired with v1.0.0.** **v0.9.0** — C ABI v2: external plugin Stage callbacks can now write back (`invoke_stage` gained a result out-param; plugins may mutate RawMessage/LLMText/ToolResults etc. in OnInput/AfterToolcall/PostAction and have them synced to the core). ABI version now tracks core minor releases (v0.9.x → ABIVersion=2, `version_min=1` keeps old plugins loadable). Also fixes the tool-loop zen-compat placeholder that wrongly fired on first-turn system context tail. The SDK ships an enhanced sanitizer example (bad-UTF-8 / U+FFFD / ANSI-escape scrub across the whole pipeline). **This ABI retired with v1.0.0.**
**v0.8.0** — Core is functional, plugin system enhanced. 20+ built-in plugins. External plugin development via [homeagent-sdk](https://gitcode.com/JianFeeeee/homeagent-sdk) repo. Added input channel `NoMemory`/`Cleaner`, `ChannelDef`, plugin disable/enable system (CLI + WebUI), `plugindev` toolchain C ABI `ChannelDef` support. **v0.8.0** — Core is functional, plugin system enhanced. 20+ built-in plugins. External plugin development via [homeagent-sdk](https://github.com/JianFeeeee/homeagentsdk) repo. Added input channel `NoMemory`/`Cleaner`, `ChannelDef`, plugin disable/enable system (CLI + WebUI), `plugindev` toolchain C ABI `ChannelDef` support.
## Documentation ## Documentation
@ -319,10 +358,10 @@ semantic memory; the blob is only a cache that capacity GC may evict.
## Downloads ## Downloads
[Releases](https://gitcode.com/JianFeeeee/HomeAgent/releases) ship three variants: [Releases](https://github.com/JianFeeeee/HomeAgent/releases) ship three variants:
| Variant | Contents | For | | Variant | Contents | For |
|---|---|---| | --- | --- | --- |
| **full** | homed + waiter + desktop GUI + systemd unit | Single-machine, everything | | **full** | homed + waiter + desktop GUI + systemd unit | Single-machine, everything |
| **server** | homed + waiter + systemd unit | Servers (no desktop environment) | | **server** | homed + waiter + systemd unit | Servers (no desktop environment) |
| **client** | waiter + desktop GUI | Connecting to a remote HomeAgent | | **client** | waiter + desktop GUI | Connecting to a remote HomeAgent |
@ -360,7 +399,7 @@ with it over a network** (§13, Remote Network Interaction). Anyone running a mo
as a network service therefore has to make the modified source available to that service's users. as a network service therefore has to make the modified source available to that service's users.
Plugins are **statically linked** against this project through the public Plugins are **statically linked** against this project through the public
[homeagent-sdk](https://gitcode.com/JianFeeeee/homeagent-sdk) (the SDK source ends up inside the [homeagent-sdk](https://github.com/JianFeeeee/homeagentsdk) (the SDK source ends up inside the
plugin binary), but that repository is released under **MIT** — a permissive license, so code plugin binary), but that repository is released under **MIT** — a permissive license, so code
received under it does **not** inherit this project's AGPL. External plugins are therefore **not received under it does **not** inherit this project's AGPL. External plugins are therefore **not
derivative works of this project**: authors pick their own license (closed-source, commercial or derivative works of this project**: authors pick their own license (closed-source, commercial or
@ -368,7 +407,7 @@ private included), with no same-license obligation and no §13 network clause. T
vitality of the third-party plugin ecosystem rest on this. vitality of the third-party plugin ecosystem rest on this.
The boundary is clean: **AGPL covers the kernel and the bundled plugins** (`homed`, `internal/`, The boundary is clean: **AGPL covers the kernel and the bundled plugins** (`homed`, `internal/`,
the 18 built-in plugins under `internal/plugins/`); **MIT covers the public SDK** (`sdk/`, whose the 20 built-in plugins under `internal/plugins/`); **MIT covers the public SDK** (`sdk/`, whose
`go.mod` has zero external dependencies and imports only the Go standard library — it never `go.mod` has zero external dependencies and imports only the Go standard library — it never
references any kernel code). Process isolation is beside the point here — what decides the references any kernel code). Process isolation is beside the point here — what decides the
license is the linked SDK code itself, and that code is MIT. license is the linked SDK code itself, and that code is MIT.
@ -376,7 +415,7 @@ license is the linked SDK code itself, and that code is MIT.
### Third-party components shipped with the packages ### Third-party components shipped with the packages
| Component | License | Location | | Component | License | Location |
|---|---|---| | --- | --- | --- |
| Chinese-CLIP ViT-B/16 (ONNX artifacts) | Apache-2.0 | `/usr/lib/homeagent/models/chinese-clip-vit-b16-onnx/` | | Chinese-CLIP ViT-B/16 (ONNX artifacts) | Apache-2.0 | `/usr/lib/homeagent/models/chinese-clip-vit-b16-onnx/` |
| ONNX Runtime (`libonnxruntime.so`) | MIT | `/usr/lib/homeagent/onnxruntime/` | | ONNX Runtime (`libonnxruntime.so`) | MIT | `/usr/lib/homeagent/onnxruntime/` |
| jieba dictionary (embedded in the binary) | MIT | `internal/memory/jiebadict/` | | jieba dictionary (embedded in the binary) | MIT | `internal/memory/jiebadict/` |