# https://github.com/ahwurm/localharness 项目说明书

生成时间：2026-07-20 12:23:39 UTC

## 目录

- [项目概览与快速上手](#page-1)
- [代理运行时、工具与权限](#page-2)
- [SQLite 记忆系统与写入门控](#page-3)
- [推理服务器生命周期、基准与已知故障模式](#page-4)

<a id='page-1'></a>

## 项目概览与快速上手

### 相关页面

相关主题：[代理运行时、工具与权限](#page-2)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/ahwurm/localharness/blob/main/README.md)
- [pyproject.toml](https://github.com/ahwurm/localharness/blob/main/pyproject.toml)
- [src/localharness/__init__.py](https://github.com/ahwurm/localharness/blob/main/src/localharness/__init__.py)
- [src/localharness/cli/app.py](https://github.com/ahwurm/localharness/blob/main/src/localharness/cli/app.py)
- [docs/reference-architectures/README.md](https://github.com/ahwurm/localharness/blob/main/docs/reference-architectures/README.md)
</details>

# 项目概览与快速上手

## 项目定位与目标

`localharness` 是一个本地化的智能体（agent）运行环境，面向"在本地起一个模型 + 在 REPL 中长期使用 + 跨会话沉淀记忆"的场景。它在用户进程内把模型 server、工具调用、记忆与检查点串成一个闭环，避免反复启动 vLLM/Transformers 后端或将状态外置到外部服务。

项目的核心定位包含三件事：

- **本地模型托管**：通过 `server.local_models` 注册命名 checkpoint，配合 `vllm serve` 启动参数，运行时可在 REPL 中整体替换模型（v0.9.23 引入的全量模型切换能力）。
- **REPL 作为一等公民**：CLI 入口就是一个交互式会话，既能跑普通问答，也能在 turn 结束时自动做记忆管线处理。
- **持久化记忆层**：通过语义原子（sem/）与查询时注入（ambient injection）构建长期可用的事实库。

资料来源：[README.md:1-40](), [src/localharness/__init__.py:1-20]()

## 整体架构

整体可拆为四层，分别承担"模型进程、对话循环、记忆与工具、可观测"职责：

| 层 | 主要职责 | 入口/模块 |
| --- | --- | --- |
| 模型服务层 | 启动并管理 `vllm serve` 子进程（docker 或本机） | `server.local_models` |
| 对话循环层 | REPL、turn 结束簿记、摘要、CONFIRMED 哨兵处理 | `src/localharness/agent/loop.py` |
| 记忆与工具层 | 写入门控、语义原子去重、检索注入 | `src/localharness/memory/` |
| 路由与分类层 | `type-anytime` 输入分类、tier-2 推理 | 路由器模块 |

```mermaid
flowchart LR
    U[用户] --> R[REPL / CLI]
    R --> A[Agent Loop]
    A --> S[vLLM Server]
    A --> M[Memory Pipeline]
    M --> I[Ambient Injection]
    I --> A
    A --> R
```

资料来源：[docs/reference-architectures/README.md:1-30](), [src/localharness/cli/app.py:1-40]()

## 安装与首次启动

推荐使用 `uv` 做 editable 安装，便于直接修改源码并立即生效：

```bash
uv sync
uv run localharness
```

安装元数据来自 `pyproject.toml` 中声明的版本号；命令行 banner 读取的是 distribution metadata，而不是 `localharness.__version__`。在 editable 模式下，源码更新后必须重新执行 `uv sync`，否则 banner 会停留在旧版本。

资料来源：[pyproject.toml:1-30](), [src/localharness/__init__.py:1-15]()

## REPL 内常用操作

启动后会进入交互式会话，常用指令包括：

- `/model`：列出已注册命名、本机存活、HF 缓存中的模型，选定后会重启 server 加载新 checkpoint（每次切换只对该 checkpoint 生效，避免 MoE/量化参数泄漏到兄弟模型）。
- 直接问答：模型若无需工具会被要求输出 `CONFIRMED`，确认上一次回复作为最终答案；该路径若摘要回退会回到 `session.messages` 的最后一条助手内容（issue #91）。
- `Ctrl+C` 退出：建议在回复渲染完成、turn 结束簿记（如 `TurnCompleted`、micro-pass、记忆管线）运行后再退出；立刻退出可能跳过当轮处理（issue #93）。

资料来源：[src/localharness/cli/app.py:1-60](), [src/localharness/agent/loop.py:246-256]()

## 已知影响快速上手的若干问题

社区中已记录一些会影响首次体验或日常使用的边界情况，建议在快速上手时留意：

- **Docker 模式下僵尸进程**：若 `launch: docker` 启动 vLLM 失败，`docker run --rm` 客户端会变成未收割的 zombie，REPL 进程下的 `wait()` 缺失（issue #99）。
- **版本号陈旧**：banner 不会随源码自动刷新，需要 `uv sync`（issue #97）。
- **首轮空记忆**：没有任何已存在事实的 turn，因 injected-id 列表为空而不会写入 injection trace，覆盖率统计会出现盲区（issue #96）。
- **撤回/合并缺位**：矛盾的语义原子各自拥有唯一 key，可能并存为 active（issue #95）；`proposed` 标签在真实 store 中长期未被命名/晋升（issue #90）。

资料来源：[src/localharness/memory/discovery.py:286-290](), [src/localharness/agent/loop.py:246-256]()

## 小结

`localharness` 把"本地模型 + REPL + 持久化记忆"压缩成一个可独立运行的进程；上手路径很短（`uv sync` + `uv run localharness`），但要在生产式使用中获得稳定行为，需要同时关注 server 进程管理、turn 退出时机，以及记忆层的去重与覆盖统计。这些点恰好也是当前社区 issue 的集中处。

---

<a id='page-2'></a>

## 代理运行时、工具与权限

### 相关页面

相关主题：[SQLite 记忆系统与写入门控](#page-3), [推理服务器生命周期、基准与已知故障模式](#page-4)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/localharness/agent/loop.py](https://github.com/ahwurm/localharness/blob/main/src/localharness/agent/loop.py)
- [src/localharness/agent/permissions.py](https://github.com/ahwurm/localharness/blob/main/src/localharness/agent/permissions.py)
- [src/localharness/agent/subagent.py](https://github.com/ahwurm/localharness/blob/main/src/localharness/agent/subagent.py)
- [src/localharness/orchestrator/router.py](https://github.com/ahwurm/localharness/blob/main/src/localharness/orchestrator/router.py)
- [src/localharness/tools/builtin/__init__.py](https://github.com/ahwurm/localharness/blob/main/src/localharness/tools/builtin/__init__.py)
- [src/localharness/tools/mcp.py](https://github.com/ahwurm/localharness/blob/main/src/localharness/tools/mcp.py)
</details>

# 代理运行时、工具与权限

## 概述

localharness 的代理运行时围绕一个 **单回合（turn）** 调度循环展开，由 `agent/loop.py` 统一驱动消息累积、工具调用解析、回退渲染与回合终了记账。工具面分两条平行通路：内置工具经 `tools/builtin/__init__.py` 注册，MCP 工具经 `tools/mcp.py` 通过 Model Context Protocol 接入。权限策略集中于 `agent/permissions.py`，负责对每一次工具执行进行前置检查。`orchestrator/router.py` 提供 type-anytime 路由与分级（tier-2）分类，`agent/subagent.py` 实现子代理的派生与隔离。

## 代理循环与回合终了

主循环位于 `agent/loop.py`，负责在每一回合累积消息、解析工具调用、调用权限闸口并产生最终答复。`_format_completion_summary` 在模型回退为 `CONFIRMED` 哨兵时，从 `session.messages` 中提取上一条助手内容作为兜底展示——但因读取的是全量多回合消息列表，存在误把**前几回合**的旧答复当作本回合答复的隐患。资料来源：[src/localharness/agent/loop.py:246-256]()

回合记账路径依赖一个明确的"回合结束"事件 `TurnCompleted` 触发后置的内存与追踪写入；若用户在该事件触发前通过 Ctrl+C 立即退出 REPL（例如答复刚刚渲染），可让回合在未最终化前结束，导致内存管线处理、注入追踪写入与 TurnCompleted 事件整体丢失。资料来源：[src/localharness/agent/loop.py:240-280]()

主循环还内置一层 "act-guard"：当模型本回合零工具调用时，提示"如确实无需工具，请回复 CONFIRMED"。该路径在裸 `CONFIRMED` 上与回退摘要共用同一管线，可能使元指令回声替换本应可见的真实答复。资料来源：[src/localharness/agent/loop.py:200-260]()

## 工具系统：内置与 MCP

`tools/builtin/__init__.py` 维护一个内置工具注册表，提供 REPL 直接调用的基础能力集合。注册采用"名称→实现"映射，新增工具只需追加条目并保证签名与权限策略对接。资料来源：[src/localharness/tools/builtin/__init__.py:1-80]()

`tools/mcp.py` 提供对外部 MCP 服务的桥接，把 MCP 暴露的工具声明合并进代理的工具列表，并以统一接口转发调用与回流结果。该模块通常负责处理连接生命周期、能力发现（capabilities discovery）以及错误重试等横切关注点。资料来源：[src/localharness/tools/mcp.py:1-120]()

下表汇总了工具调用在不同路径下的关键差异：

| 路径 | 注册位置 | 权限闸口 | 典型用途 |
| --- | --- | --- | --- |
| 内置工具 | `tools/builtin/__init__.py` | `agent/permissions.py` | 文件、Shell、检索等本地能力 |
| MCP 工具 | `tools/mcp.py` | 同上，附带 server 来源标识 | 调用外部 MCP server 暴露的能力 |

## 权限控制

`agent/permissions.py` 在每次工具调用执行前进行决策：基于工具名、参数范围、会话上下文判断放行、拦截或要求确认。该模块通常以"工具白名单/黑名单"+"危险操作需确认"的分层策略实现，保证 agent 在获得工具能力的同时不脱离用户授权范围。资料来源：[src/localharness/agent/permissions.py:1-120]()

写入路径上的"新颖性"判定（"First successful use of tool X"）在写闸门（write-gate）里被复用，但当前比对的是**会话作用域**状态而非持久化存储，导致同一工具在不同日期的"首次成功使用"会重复触发；最终由唯一活跃键约束以 upsert 方式静默合并并刷新更新时间戳。资料来源：[src/localharness/agent/permissions.py:120-200]()

## 编排、路由与子代理

`orchestrator/router.py` 实现 type-anytime 路由，把入站消息按紧急度与语义分为多档（tier），其中 tier-2 通过独立的分类调用进行更精细的意图判定。该分类调用复用了代理自身的 LLM 客户端，受单飞（single-flight）推理信号量约束——而该信号量在流式生成期间持续持有，因此 tier-2 分类会被同一流阻塞，造成回合内饥饿与故障静默。资料来源：[src/localharness/orchestrator/router.py:1-200]()

`agent/subagent.py` 负责子代理的派生、上下文裁剪与结果回收，使主代理能够把长链任务拆解为可并行或隔离执行的子任务。子代理通常继承受限的工具集与权限策略，避免子任务越权访问主代理范围之外的资源。资料来源：[src/localharness/agent/subagent.py:1-160]()

## 已知问题与注意事项

- **僵尸 docker-run 客户端**：managed vLLM server 启动失败时，`docker run --rm` 进程退出但未被 `wait()`，留下僵尸进程，绕过 fail-fast 路径。资料来源：[src/localharness/agent/loop.py:280-340]()
- **Act-guard 哨兵回声**：无工具回合的 CONFIRMED 处理与回退摘要共用代码，可能把元指令回声作为可见答复呈现。资料来源：[src/localharness/agent/loop.py:200-260]()
- **回合终了记账竞态**：REPL 立即退出可能跳过 TurnCompleted 与回合终结微处理。资料来源：[src/localharness/agent/loop.py:240-300]()
- **tier-2 分类饥饿**：单飞推理信号量在流式期间持续持有，导致 mid-turn 分类延迟与失败路径静默。资料来源：[src/localharness/orchestrator/router.py:1-200]()
- **写入新颖性跨日重放**：会话作用域的新颖性判定会在多日重复触发"首次使用"。资料来源：[src/localharness/agent/permissions.py:120-200]()

---

<a id='page-3'></a>

## SQLite 记忆系统与写入门控

### 相关页面

相关主题：[代理运行时、工具与权限](#page-2), [推理服务器生命周期、基准与已知故障模式](#page-4)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/localharness/memory/sqlite.py](https://github.com/ahwurm/localharness/blob/main/src/localharness/memory/sqlite.py)
- [src/localharness/memory/predictive_write_gate.py](https://github.com/ahwurm/localharness/blob/main/src/localharness/memory/predictive_write_gate.py)
- [src/localharness/memory/discovery.py](https://github.com/ahwurm/localharness/blob/main/src/localharness/memory/discovery.py)
- [src/localharness/memory/consolidation.py](https://github.com/ahwurm/localharness/blob/main/src/localharness/memory/consolidation.py)
- [src/localharness/memory/mining.py](https://github.com/ahwurm/localharness/blob/main/src/localharness/memory/mining.py)
- [src/localharness/memory/hierarchy.py](https://github.com/ahwurm/localharness/blob/main/src/localharness/memory/hierarchy.py)
</details>

# SQLite 记忆系统与写入门控

Localharness 的记忆子系统负责在长会话与跨会话周期中持久化经验型知识,并通过预测式写入门控决定哪些观察值得入库。其核心由 SQLite 存储层、原子键管理、事实挖掘、候选发现与合并等模块协同工作,共同支撑环境注入、回合回顾与发现式标签生成。

## 系统定位与模块划分

记忆系统位于 `src/localharness/memory/` 包下,主要职责包括:

- 提供一个可事务化的本地持久层,跨回合保存 `sem/`(语义原子)、`ep/`(情景痕迹)、`fact/`(高阶事实)等记录。资料来源：[src/localharness/memory/sqlite.py:1-120]()
- 在写入前由预测式写入门控做新颖度、置信度与上下文的过滤,避免噪声淹没存储。资料来源：[src/localharness/memory/predictive_write_gate.py:1-80]()
- 通过发现模块从已有原子聚类中抽取"候选标签",并由合并模块定期压缩重复/陈旧项。资料来源：[src/localharness/memory/discovery.py:1-60](),[src/localharness/memory/consolidation.py:1-60]()
- 由挖掘模块把对话与工具结果中的高置信事实降维成语义原子。资料来源：[src/localharness/memory/mining.py:1-60]()
- 在分级层管理 L0(原始痕迹)、L1(原子)、L2(标签/概念)之间的提升路径。资料来源：[src/localharness/memory/hierarchy.py:1-60]()

## SQLite 持久化层

`sqlite.py` 把记忆表示为带唯一性约束的行,通过原子键 `key`(形如 `<scope>:<bucket>:<hash>`)实现 upsert 语义。典型写入序列包括:

1. 读取或新建一条原子行,主键由 `(bucket, key)` 构成。
2. 在同事务内更新 `last_seen_ts`、`support_count`、`status` 等元数据。
3. 通过 `evidence_links` 表登记该原子在哪些回合/工具调用中出现过。

唯一性约束带来一个可观察的副作用:两条相互矛盾的事实只要哈希键不同,会同时保持 `active` 状态。社区在 #95 中记录到此问题——例如"vLLM 监听 8000 端口"与"vLLM 监听 8081 端口"在 `sem/` 桶里拥有不同的 `key`,因此谁也不会被对方"挤掉",从而并存于活动集合。资料来源：[src/localharness/memory/sqlite.py:120-260](),[#95](https://github.com/ahwurm/localharness/issues/95)

## 预测式写入门控

`predictive_write_gate.py` 位于"挖掘→持久化"之间,典型职责为:

- 基于当前会话上下文判断是否首次出现某工具/某事实,若是则标记为 `novel` 以提高写入优先级。
- 检查置信度阈值,并返回 `allow` / `suppress` / `demote` 三种决定之一。
- 抑制重复噪声,避免同一事实在多回合反复写盘造成 `support_count` 虚增。

社区已知问题 #89 揭示了会话范围检查的局限:写入门控以**会话级**状态做新颖度比较,而非查询持久化存储,导致同一工具的"首次成功使用"会在不同日期反复触发;唯一性约束虽然阻止了重复行的真正插入,但会无声地 `upsert` 并刷新元数据。资料来源：[src/localharness/memory/predictive_write_gate.py:80-180](),[#89](https://github.com/ahwurm/localharness/issues/89)

## 发现、合并与生命周期

发现模块负责把语义原子聚类为标签候选;每个候选自诞生起处于 `proposed` 状态,等待被模型命名并在足够证据下被提升为 `promoted`。

| 阶段 | 触发条件 | 状态变化 |
|------|----------|----------|
| 提议 | 新原子簇与现有候选匹配 | `proposed` → 记录 `last_accrual_ts` |
| 命名 | 模型给出可读标签 | `proposed` → `named` |
| 提升 | 累计支持度/座位达到阈值 | `named` → `promoted` |

社区问题 #90 报告"proposed 候选停留 6 天以上仍未被命名/提升",问题 #94 指出发现流水线对未变化的原子簇无条件刷新 `last_accrual_ts`,导致陈旧性剪枝永远无法生效——候选因此进入永久 limbo。资料来源：[src/localharness/memory/discovery.py:200-320](),[#90](https://github.com/ahwurm/localharness/issues/90),[#94](https://github.com/ahwurm/localharness/issues/94)

合并模块 `consolidation.py` 周期性地压缩近似原子、清理过期情景,并通过 `mining.py` 抽取出新的高层事实,以维持存储紧凑与查询高效;分级层 `hierarchy.py` 决定哪些 L1 原子应晋升为 L2 标签或概念节点。资料来源：[src/localharness/memory/consolidation.py:60-180](),[src/localharness/memory/mining.py:80-200](),[src/localharness/memory/hierarchy.py:60-180]()

## 与回合生命周期的耦合

写入门控的运行点位于回合结束或工具结果归并阶段。若 REPL 在答案渲染后被立即中断(`Ctrl+C` 即退),回合结束的微型 pass 与记忆流水线都不会运行。社区 #93 描述了此风险:在该回合中可能产生"未持久化的工具结果"或"未触发的写入门控评估"。资料来源：[#93](https://github.com/ahwurm/localharness/issues/93)

此外,环境注入追踪(ambient injection trace)仅在注入 ID 列表非空时记录一行,导致首回合或新存储的"未注入"事件被静默丢失(#96)。这会影响按回合统计的覆盖率指标,提示在评估记忆效果时需额外注意。资料来源：[#96](https://github.com/ahwurm/localharness/issues/96)

---

<a id='page-4'></a>

## 推理服务器生命周期、基准与已知故障模式

### 相关页面

相关主题：[代理运行时、工具与权限](#page-2), [SQLite 记忆系统与写入门控](#page-3)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/localharness/provider/server.py](https://github.com/ahwurm/localharness/blob/main/src/localharness/provider/server.py)
- [src/localharness/provider/detector.py](https://github.com/ahwurm/localharness/blob/main/src/localharness/provider/detector.py)
- [src/localharness/cli/model_cmd.py](https://github.com/ahwurm/localharness/blob/main/src/localharness/cli/model_cmd.py)
- [src/localharness/cli/model_ops.py](https://github.com/ahwurm/localharness/blob/main/src/localharness/cli/model_ops.py)
- [src/localharness/cli/repl.py](https://github.com/ahwurm/localharness/blob/main/src/localharness/cli/repl.py)
- [src/localharness/bench/orchestrator.py](https://github.com/ahwurm/localharness/blob/main/src/localharness/bench/orchestrator.py)
</details>

# 推理服务器生命周期、基准与已知故障模式

本页面向希望理解、调试或扩展 localharness 受管推理后端的工程师与运维人员，覆盖受管 vLLM 服务的启动、运行、停止与在 REPL 内热切换路径，并整理基准编排入口与社区已知的若干故障模式。受众应已熟悉 vLLM `serve` CLI、Docker 启动语义以及 Python REPL 的基本行为。

## 受管服务器生命周期

### 启动模式

`localharness` 的受管服务器由 `src/localharness/provider/server.py` 持有抽象，支持 `launch: docker` 与本地子进程两种形态。`docker` 模式会以 `docker run --rm` 启动 vLLM 镜像，并把宿主机端口、模型缓存目录与 `VLLM_*` 环境变量透传给容器；本地模式则直接以 `vllm serve` 作为子进程接管 资料来源：[src/localharness/provider/server.py:1-120]()。

自 v0.9.23 起，`server.local_models` 字段允许在配置中按"名称 → 检查点 + 私有参数"的方式注册多个本地模型，每个注册项可以携带仅对该检查点生效的 `vllm serve` 参数（如 MoE 专属后端标志或与检查点严格耦合的量化标志）资料来源：[src/localharness/cli/model_cmd.py:1-200]()。这样既避免了无关标志在不同检查点之间泄漏，也使 `/model` 列表能够并列展示注册名、当前活动模型与 HF 缓存内可发现的模型。

### 进程模型与 PID 查询

`server_pid()` 接口返回受管后端的当前 PID，供 REPL 健康检查与 `/model swap` 等命令在切换前判定目标进程是否仍然存活。该返回值在 `docker` 模式下是宿主机上 `docker run --rm` 客户端进程的 PID，而不是容器内 vLLM 自身的 PID——这一点对理解下文的故障模式至关重要 资料来源：[src/localharness/provider/server.py:120-180]()。

### REPL 内热切换

`/model` 命令由 `src/localharness/cli/model_cmd.py` 实现：先列出三类候选（注册名、当前活动、HF 缓存内候选），再由用户挑选并触发 `src/localharness/cli/model_ops.py` 中的停止→启动序列。停止逻辑对 `docker` 模式使用 `docker stop`/`docker rm`，对本地模式向子进程发送 `SIGTERM` 并 `wait()`；启动逻辑则使用新检查点对应的私有参数重建调用 资料来源：[src/localharness/cli/model_ops.py:1-160]()。

```mermaid
flowchart LR
    A[/model 命令] --> B[model_cmd 列出候选]
    B --> C{用户选择}
    C --> D[model_ops 停止旧后端]
    D --> E[清理 docker 客户端 / 子进程]
    E --> F[用新参数重建启动]
    F --> G[轮询健康端点]
    G --> H[切换完成]
```

## 后端检测与基准编排

### 后端探测

`src/localharness/provider/detector.py` 负责在 REPL 启动或 `/model` 触发时探测本机可用推理后端：解析 `vllm --version`、检查 Docker 守护进程可达性、枚举 HF 缓存目录下的检查点，并将结果缓存到会话级 `ProviderInventory`。该缓存会在显式 `/model refresh` 或配置文件变更时失效 资料来源：[src/localharness/provider/detector.py:1-140]()。

### 基准编排入口

`src/localharness/bench/orchestrator.py` 暴露基准运行编排能力：接受任务集、并发度与采样参数，按需调用受管服务器端点、收集延迟/吞吐指标，并将结果写入可追溯的输出目录。orchestrator 复用 `provider/server.py` 的客户端，不直接 spawn 进程，因此与受管后端的生命周期保持一致 资料来源：[src/localharness/bench/orchestrator.py:1-180]()。

## 已知故障模式

### 僵尸 `docker run --rm` 客户端（Issue #99）

当 `launch: docker` 的 vLLM 服务在启动阶段崩溃——例如 `--quantization` 与检查点不匹配——容器侧的 vLLM 退出，但宿主机侧的 `docker run --rm` 客户端进程没有被任何代码 `wait()`，从而成为挂在 REPL 进程下的**僵尸**。`server_pid()` 仍然返回该僵尸 PID，使"死进程立即失败"的快速失败语义被绕过 资料来源：[src/localharness/provider/server.py:180-240]()。建议在停止路径上显式对客户端 PID 调用 `os.waitpid()`，或改用 `docker run --init`/`tini` 让 init 进程接管回收。

### 版本横幅读取陈旧元数据（Issue #97）

CLI 与启动横幅读取的是已安装发行版的分发元数据，而非 `localharness.__version__`。在 editable 安装下，`git pull` 之后源码已更新但 dist-info 未变，导致横幅始终显示旧版本号 资料来源：[src/localharness/cli/repl.py:1-120]()。运行 `uv sync` 或 `pip install -e . --no-deps --force-reinstall` 可临时缓解；长期方案是横幅直接读取运行时模块属性。

### 健康检查与切换的耦合

`/model swap` 的"停止 → 启动"序列依赖健康端点轮询来判断旧后端已就绪退出。若旧后端处于上述僵尸态，轮询将一直成功（端口仍被旧容器占用），新启动会因为端口冲突而失败，并被报告为"启动失败"而非"旧后端未释放" 资料来源：[src/localharness/cli/model_ops.py:160-260]()。运维侧应以 `server_pid()` 的存活状态作为前置条件，而非仅看端口探测。

### 与单飞行推理门控的相互影响（Issue #92）

tier-2 输入分类复用了智能体自身的 LLM 客户端，而该客户端被一个跨整个流式响应持续持有的 single-flight 信号量串行化。当受管服务器刚刚完成启动、首个请求尚在排队时，分类调用会被同步阻塞，导致 tier-2 路径呈现"无声卡死" 资料来源：[src/localharness/agent/loop.py:240-320]()。在基准场景下这会扭曲首 token 延迟（TTFT）测量结果，应在编排时记录并剔除这一窗口。

## 排查建议速查

| 现象 | 优先检查文件 | 关键信号 |
|---|---|---|
| `/model swap` 后端口冲突 | `cli/model_ops.py` | 旧 PID 是否仍存活、`docker ps` 是否残留容器 |
| 横幅版本号与 `git log` 不一致 | `cli/repl.py` | editable 元数据 vs `__version__` |
| 基准 TTFT 异常偏高 | `bench/orchestrator.py` | 启动后第一个请求是否落入 single-flight 窗口 |
| 受管进程"已退出但端口仍占用" | `provider/server.py` | `server_pid()` 返回的僵尸是否未被 `waitpid` |

掌握上述生命周期边界与故障模式后，开发者可以更可靠地扩展 `server.local_models` 语义、为新后端（如 `llama.cpp` server）撰写平行启动路径，并在基准实验中规避首请求偏差。

---

<!-- evidence_pipeline_checked: true -->
<!-- evidence_injected: true -->

---

## Doramagic 踩坑日志

项目：ahwurm/localharness

摘要：发现 39 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：安装坑 - 失败模式：installation: Version banner reads stale install metadata on editable installs — shows old version after ev...。

## 1. 安装坑 · 失败模式：installation: Version banner reads stale install metadata on editable installs — shows old version after ev...

- 严重度：medium
- 证据强度：source_linked
- 发现：Developers should check this installation risk before relying on the project: Version banner reads stale install metadata on editable installs — shows old version after every source update
- 对用户的影响：Developers may fail before the first successful local run: Version banner reads stale install metadata on editable installs — shows old version after every source update
- 证据：failure_mode_cluster:github_issue | https://github.com/ahwurm/localharness/issues/97 | Version banner reads stale install metadata on editable installs — shows old version after every source update

## 2. 安装坑 · 来源证据：Discovery candidate tags never progress past 'proposed' — naming/promotion unobserved for 6+ days

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：Discovery candidate tags never progress past 'proposed' — naming/promotion unobserved for 6+ days
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/ahwurm/localharness/issues/90 | 来源类型 github_issue 暴露的待验证使用条件。

## 3. 安装坑 · 来源证据：Discovery candidates can enter permanent limbo: evidence re-accrual on unchanged clusters defeats staleness pruning

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：Discovery candidates can enter permanent limbo: evidence re-accrual on unchanged clusters defeats staleness pruning
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/ahwurm/localharness/issues/94 | 来源类型 github_issue 暴露的待验证使用条件。

## 4. 安装坑 · 来源证据：Exiting the REPL immediately after an answer skips that turn's end-of-turn bookkeeping

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：Exiting the REPL immediately after an answer skips that turn's end-of-turn bookkeeping
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/ahwurm/localharness/issues/93 | 来源类型 github_issue 暴露的待验证使用条件。

## 5. 安装坑 · 来源证据：Version banner reads stale install metadata on editable installs — shows old version after every source update

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：Version banner reads stale install metadata on editable installs — shows old version after every source update
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/ahwurm/localharness/issues/97 | 来源类型 github_issue 暴露的待验证使用条件。

## 6. 安装坑 · 来源证据：Zombie docker-run client defeats the managed server's dead-process fail-fast

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：Zombie docker-run client defeats the managed server's dead-process fail-fast
- 对用户的影响：可能阻塞安装或首次运行。
- 证据：community_evidence:github | https://github.com/ahwurm/localharness/issues/99 | 来源讨论提到 docker 相关条件，需在安装/试用前复核。

## 7. 配置坑 · 可能修改宿主 AI 配置

- 严重度：medium
- 证据强度：source_linked
- 发现：项目面向 Claude/Cursor/Codex/Gemini/OpenCode 等宿主，或安装命令涉及用户配置目录。
- 对用户的影响：安装可能改变本机 AI 工具行为，用户需要知道写入位置和回滚方法。
- 证据：capability.host_targets | https://github.com/ahwurm/localharness | host_targets=claude, chatgpt, claude_code

## 8. 配置坑 · 失败模式：configuration: Zombie docker-run client defeats the managed server's dead-process fail-fast

- 严重度：medium
- 证据强度：source_linked
- 发现：Developers should check this configuration risk before relying on the project: Zombie docker-run client defeats the managed server's dead-process fail-fast
- 对用户的影响：Developers may misconfigure credentials, environment, or host setup: Zombie docker-run client defeats the managed server's dead-process fail-fast
- 证据：failure_mode_cluster:github_issue | https://github.com/ahwurm/localharness/issues/99 | Zombie docker-run client defeats the managed server's dead-process fail-fast

## 9. 能力坑 · 能力判断依赖假设

- 严重度：medium
- 证据强度：source_linked
- 发现：README/documentation is current enough for a first validation pass.
- 对用户的影响：假设不成立时，用户拿不到承诺的能力。
- 证据：capability.assumptions | https://github.com/ahwurm/localharness | README/documentation is current enough for a first validation pass.

## 10. 运行坑 · 失败模式：runtime: Mid-turn tier-2 input classification is starved by the single-flight inference gate, and its...

- 严重度：medium
- 证据强度：source_linked
- 发现：Developers should check this runtime risk before relying on the project: Mid-turn tier-2 input classification is starved by the single-flight inference gate, and its failure path is silent
- 对用户的影响：Developers may hit a documented source-backed failure mode: Mid-turn tier-2 input classification is starved by the single-flight inference gate, and its failure path is silent
- 证据：failure_mode_cluster:github_issue | https://github.com/ahwurm/localharness/issues/92 | Mid-turn tier-2 input classification is starved by the single-flight inference gate, and its failure path is silent

## 11. 运行坑 · 来源证据：Agent loop accepts a tool-less reply that announces further work as the turn's final answer

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个运行相关的待验证问题：Agent loop accepts a tool-less reply that announces further work as the turn's final answer
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/ahwurm/localharness/issues/84 | 来源类型 github_issue 暴露的待验证使用条件。

## 12. 运行坑 · 来源证据：Contradictory sem/ atoms coexist as active — mined facts never supersede on contradiction

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个运行相关的待验证问题：Contradictory sem/ atoms coexist as active — mined facts never supersede on contradiction
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/ahwurm/localharness/issues/95 | 来源类型 github_issue 暴露的待验证使用条件。

## 13. 运行坑 · 来源证据：Messages typed into the input box leave no permanent record in the terminal transcript

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个运行相关的待验证问题：Messages typed into the input box leave no permanent record in the terminal transcript
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/ahwurm/localharness/issues/85 | 来源类型 github_issue 暴露的待验证使用条件。

## 14. 运行坑 · 来源证据：Mid-turn tier-2 input classification is starved by the single-flight inference gate, and its failure path is silent

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个运行相关的待验证问题：Mid-turn tier-2 input classification is starved by the single-flight inference gate, and its failure path is silent
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/ahwurm/localharness/issues/92 | 来源类型 github_issue 暴露的待验证使用条件。

## 15. 运行坑 · 来源证据：Mint-time classification can assign BOTH L1 buckets to one atom

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个运行相关的待验证问题：Mint-time classification can assign BOTH L1 buckets to one atom
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/ahwurm/localharness/issues/88 | 来源类型 github_issue 暴露的待验证使用条件。

## 16. 运行坑 · 来源证据：Turn summary fallback can resurface a PRIOR turn's reply when the model answers with only the confirmation sentinel

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个运行相关的待验证问题：Turn summary fallback can resurface a PRIOR turn's reply when the model answers with only the confirmation sentinel
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/ahwurm/localharness/issues/91 | 来源类型 github_issue 暴露的待验证使用条件。

## 17. 运行坑 · 来源证据：Turns with an empty memory shelf are never recorded in injection traces

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个运行相关的待验证问题：Turns with an empty memory shelf are never recorded in injection traces
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/ahwurm/localharness/issues/96 | 来源类型 github_issue 暴露的待验证使用条件。

## 18. 运行坑 · 来源证据：Working indicator renders in the input box's bottom border, crowding queue count and decision flash

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个运行相关的待验证问题：Working indicator renders in the input box's bottom border, crowding queue count and decision flash
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/ahwurm/localharness/issues/86 | 来源类型 github_issue 暴露的待验证使用条件。

## 19. 运行坑 · 来源证据：Write-gate novelty capture re-claims 'first successful use' of the same tool across days

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个运行相关的待验证问题：Write-gate novelty capture re-claims 'first successful use' of the same tool across days
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/ahwurm/localharness/issues/89 | 来源类型 github_issue 暴露的待验证使用条件。

## 20. 运行坑 · 来源证据：remember()-saved memories are never tagged at write time; backfill runs so late in consolidation that user activity sta…

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个运行相关的待验证问题：remember()-saved memories are never tagged at write time; backfill runs so late in consolidation that user activity starves it
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/ahwurm/localharness/issues/87 | 来源类型 github_issue 暴露的待验证使用条件。

## 21. 维护坑 · 来源证据：Act-guard sentinel echo replaces the user-visible answer with the CONFIRMED meta-line

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个维护/版本相关的待验证问题：Act-guard sentinel echo replaces the user-visible answer with the CONFIRMED meta-line
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/ahwurm/localharness/issues/98 | 来源类型 github_issue 暴露的待验证使用条件。

## 22. 维护坑 · 维护活跃度未知

- 严重度：medium
- 证据强度：source_linked
- 发现：未记录 last_activity_observed。
- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。
- 证据：evidence.maintainer_signals | https://github.com/ahwurm/localharness | last_activity_observed missing

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 证据：downstream_validation.risk_items | https://github.com/ahwurm/localharness | no_demo; severity=medium

## 24. 安全/权限坑 · 存在评分风险

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：风险会影响是否适合普通用户安装。
- 证据：risks.scoring_risks | https://github.com/ahwurm/localharness | no_demo; severity=medium

## 25. 能力坑 · 失败模式：capability: Agent loop accepts a tool-less reply that announces further work as the turn's final answer

- 严重度：low
- 证据强度：source_linked
- 发现：Developers should check this capability risk before relying on the project: Agent loop accepts a tool-less reply that announces further work as the turn's final answer
- 对用户的影响：Developers may hit a documented source-backed failure mode: Agent loop accepts a tool-less reply that announces further work as the turn's final answer
- 证据：failure_mode_cluster:github_issue | https://github.com/ahwurm/localharness/issues/84 | Agent loop accepts a tool-less reply that announces further work as the turn's final answer

## 26. 能力坑 · 失败模式：capability: Contradictory sem/ atoms coexist as active — mined facts never supersede on contradiction

- 严重度：low
- 证据强度：source_linked
- 发现：Developers should check this capability risk before relying on the project: Contradictory sem/ atoms coexist as active — mined facts never supersede on contradiction
- 对用户的影响：Developers may hit a documented source-backed failure mode: Contradictory sem/ atoms coexist as active — mined facts never supersede on contradiction
- 证据：failure_mode_cluster:github_issue | https://github.com/ahwurm/localharness/issues/95 | Contradictory sem/ atoms coexist as active — mined facts never supersede on contradiction

## 27. 能力坑 · 失败模式：capability: Discovery candidate tags never progress past 'proposed' — naming/promotion unobserved for 6+...

- 严重度：low
- 证据强度：source_linked
- 发现：Developers should check this capability risk before relying on the project: Discovery candidate tags never progress past 'proposed' — naming/promotion unobserved for 6+ days
- 对用户的影响：Developers may hit a documented source-backed failure mode: Discovery candidate tags never progress past 'proposed' — naming/promotion unobserved for 6+ days
- 证据：failure_mode_cluster:github_issue | https://github.com/ahwurm/localharness/issues/90 | Discovery candidate tags never progress past 'proposed' — naming/promotion unobserved for 6+ days

## 28. 能力坑 · 失败模式：capability: Messages typed into the input box leave no permanent record in the terminal transcript

- 严重度：low
- 证据强度：source_linked
- 发现：Developers should check this capability risk before relying on the project: Messages typed into the input box leave no permanent record in the terminal transcript
- 对用户的影响：Developers may hit a documented source-backed failure mode: Messages typed into the input box leave no permanent record in the terminal transcript
- 证据：failure_mode_cluster:github_issue | https://github.com/ahwurm/localharness/issues/85 | Messages typed into the input box leave no permanent record in the terminal transcript

## 29. 能力坑 · 失败模式：capability: Mint-time classification can assign BOTH L1 buckets to one atom

- 严重度：low
- 证据强度：source_linked
- 发现：Developers should check this capability risk before relying on the project: Mint-time classification can assign BOTH L1 buckets to one atom
- 对用户的影响：Developers may hit a documented source-backed failure mode: Mint-time classification can assign BOTH L1 buckets to one atom
- 证据：failure_mode_cluster:github_issue | https://github.com/ahwurm/localharness/issues/88 | Mint-time classification can assign BOTH L1 buckets to one atom

## 30. 能力坑 · 失败模式：capability: Turn summary fallback can resurface a PRIOR turn's reply when the model answers with only the...

- 严重度：low
- 证据强度：source_linked
- 发现：Developers should check this capability risk before relying on the project: Turn summary fallback can resurface a PRIOR turn's reply when the model answers with only the confirmation sentinel
- 对用户的影响：Developers may hit a documented source-backed failure mode: Turn summary fallback can resurface a PRIOR turn's reply when the model answers with only the confirmation sentinel
- 证据：failure_mode_cluster:github_issue | https://github.com/ahwurm/localharness/issues/91 | Turn summary fallback can resurface a PRIOR turn's reply when the model answers with only the confirmation sentinel

## 31. 能力坑 · 失败模式：capability: Working indicator renders in the input box's bottom border, crowding queue count and decision...

- 严重度：low
- 证据强度：source_linked
- 发现：Developers should check this capability risk before relying on the project: Working indicator renders in the input box's bottom border, crowding queue count and decision flash
- 对用户的影响：Developers may hit a documented source-backed failure mode: Working indicator renders in the input box's bottom border, crowding queue count and decision flash
- 证据：failure_mode_cluster:github_issue | https://github.com/ahwurm/localharness/issues/86 | Working indicator renders in the input box's bottom border, crowding queue count and decision flash

## 32. 能力坑 · 失败模式：capability: Write-gate novelty capture re-claims 'first successful use' of the same tool across days

- 严重度：low
- 证据强度：source_linked
- 发现：Developers should check this capability risk before relying on the project: Write-gate novelty capture re-claims 'first successful use' of the same tool across days
- 对用户的影响：Developers may hit a documented source-backed failure mode: Write-gate novelty capture re-claims 'first successful use' of the same tool across days
- 证据：failure_mode_cluster:github_issue | https://github.com/ahwurm/localharness/issues/89 | Write-gate novelty capture re-claims 'first successful use' of the same tool across days

## 33. 能力坑 · 失败模式：capability: remember()-saved memories are never tagged at write time; backfill runs so late in consolidat...

- 严重度：low
- 证据强度：source_linked
- 发现：Developers should check this capability risk before relying on the project: remember()-saved memories are never tagged at write time; backfill runs so late in consolidation that user activity starves it
- 对用户的影响：Developers may hit a documented source-backed failure mode: remember()-saved memories are never tagged at write time; backfill runs so late in consolidation that user activity starves it
- 证据：failure_mode_cluster:github_issue | https://github.com/ahwurm/localharness/issues/87 | remember()-saved memories are never tagged at write time; backfill runs so late in consolidation that user activity starves it

## 34. 能力坑 · 失败模式：conceptual: Act-guard sentinel echo replaces the user-visible answer with the CONFIRMED meta-line

- 严重度：low
- 证据强度：source_linked
- 发现：Developers should check this conceptual risk before relying on the project: Act-guard sentinel echo replaces the user-visible answer with the CONFIRMED meta-line
- 对用户的影响：Developers may hit a documented source-backed failure mode: Act-guard sentinel echo replaces the user-visible answer with the CONFIRMED meta-line
- 证据：failure_mode_cluster:github_issue | https://github.com/ahwurm/localharness/issues/98 | Act-guard sentinel echo replaces the user-visible answer with the CONFIRMED meta-line

## 35. 运行坑 · 失败模式：performance: Discovery candidates can enter permanent limbo: evidence re-accrual on unchanged clusters def...

- 严重度：low
- 证据强度：source_linked
- 发现：Developers should check this performance risk before relying on the project: Discovery candidates can enter permanent limbo: evidence re-accrual on unchanged clusters defeats staleness pruning
- 对用户的影响：Developers may hit a documented source-backed failure mode: Discovery candidates can enter permanent limbo: evidence re-accrual on unchanged clusters defeats staleness pruning
- 证据：failure_mode_cluster:github_issue | https://github.com/ahwurm/localharness/issues/94 | Discovery candidates can enter permanent limbo: evidence re-accrual on unchanged clusters defeats staleness pruning

## 36. 运行坑 · 失败模式：performance: Exiting the REPL immediately after an answer skips that turn's end-of-turn bookkeeping

- 严重度：low
- 证据强度：source_linked
- 发现：Developers should check this performance risk before relying on the project: Exiting the REPL immediately after an answer skips that turn's end-of-turn bookkeeping
- 对用户的影响：Developers may hit a documented source-backed failure mode: Exiting the REPL immediately after an answer skips that turn's end-of-turn bookkeeping
- 证据：failure_mode_cluster:github_issue | https://github.com/ahwurm/localharness/issues/93 | Exiting the REPL immediately after an answer skips that turn's end-of-turn bookkeeping

## 37. 运行坑 · 失败模式：performance: Turns with an empty memory shelf are never recorded in injection traces

- 严重度：low
- 证据强度：source_linked
- 发现：Developers should check this performance risk before relying on the project: Turns with an empty memory shelf are never recorded in injection traces
- 对用户的影响：Developers may hit a documented source-backed failure mode: Turns with an empty memory shelf are never recorded in injection traces
- 证据：failure_mode_cluster:github_issue | https://github.com/ahwurm/localharness/issues/96 | Turns with an empty memory shelf are never recorded in injection traces

## 38. 维护坑 · issue/PR 响应质量未知

- 严重度：low
- 证据强度：source_linked
- 发现：issue_or_pr_quality=unknown。
- 对用户的影响：用户无法判断遇到问题后是否有人维护。
- 证据：evidence.maintainer_signals | https://github.com/ahwurm/localharness | issue_or_pr_quality=unknown

## 39. 维护坑 · 发布节奏不明确

- 严重度：low
- 证据强度：source_linked
- 发现：release_recency=unknown。
- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。
- 证据：evidence.maintainer_signals | https://github.com/ahwurm/localharness | release_recency=unknown

<!-- canonical_name: ahwurm/localharness; human_manual_source: deepwiki_human_wiki -->
