Doramagic 项目包 · 项目说明书

claude-thermos 项目

一个名为 claude-thermos 的项目。

项目简介与价值主张

claude-thermos 是一个面向开发者与重度 Claude 用户的命令行工具,其名称中的"thermos(保温杯)"隐喻了项目的核心目标:让与 Anthropic Claude 的对话上下文始终保持在"温热"状态,避免因会话中断而丢失累积的对话历史与推理脉络。资料来源:[README.md:1-15]()

章节 相关页面

继续阅读本节完整说明和来源证据。

项目概述

claude-thermos 是一个面向开发者与重度 Claude 用户的命令行工具,其名称中的"thermos(保温杯)"隐喻了项目的核心目标:让与 Anthropic Claude 的对话上下文始终保持在"温热"状态,避免因会话中断而丢失累积的对话历史与推理脉络。资料来源:README.md:1-15

该项目以 Python 包的形式发布,通过 pyproject.toml 中声明的标准打包元数据进行分发,并提供可在终端直接调用的命令行入口。资料来源:pyproject.toml:1-20 借助简洁的 CLI 包装,claude-thermos 试图在"原始 API 调用"与"长时跨会话协作"之间架起一座桥梁,使 Claude 能够像一个长期在线、记忆连贯的协作者一样服务于用户。

核心价值主张

claude-thermos 的价值主张可从以下三个维度来理解:

  • 上下文持久化:项目以"保温"为隐喻,强调在多次 CLI 调用之间维持对话状态,使用户无需手动复制粘贴历史即可延续讨论。
  • 降低接入门槛:通过在 claude_thermos/__main__.pyclaude_thermos/cli.py 中封装好的命令行接口,开发者只需少量配置即可在本地终端中以交互或批处理方式与 Claude 对话,无需编写额外的胶水代码。资料来源:claude_thermos/cli.py:1-30
  • 可组合与可扩展:作为 Python 包,claude_thermosclaude_thermos/__init__.py 中对外暴露核心对象,便于其他 Python 项目将其作为库引入,复用其会话管理能力。资料来源:claude_thermos/__init__.py:1-10

典型应用场景

项目主要面向以下使用情境:

  1. 跨终端会话的连续对话:开发者在多台机器或不同时段之间切换时,借助 claude-thermos 维持同一段 Claude 会话,使先前的提示词、回复与代码片段不会因进程退出而消失。
  2. 本地化、可脚本化的 Claude 调用:通过 CLI 子命令,用户可在 shell 脚本、CI 流水线或 Makefile 中直接调用 Claude,完成批量化问答、文档摘要或代码生成任务。资料来源:claude_thermos/cli.py:30-60
  3. 作为嵌入式库集成:在更复杂的 Python 应用中,thermos.py 中实现的会话/上下文管理逻辑可被直接复用,为上层应用提供带状态的 Claude 调用能力。资料来源:claude_thermos/thermos.py:1-25

架构与运行机制概览

claude-thermos 的运行时结构可由"入口—CLI—核心"三层来描述。包初始化阶段在 claude_thermos/__init__.py 中完成版本与对外符号的暴露;当用户在终端执行 claude-thermos 命令时,__main__.py 作为 Python 模块入口被加载,并将控制权转交给 cli.py 中的命令解析器;最终,由 thermos.py 提供底层的会话保持与消息调度能力。

层级文件职责
包初始化claude_thermos/__init__.py暴露版本号、核心类与公共 API
模块入口claude_thermos/__main__.py支持 python -m claude_thermos 启动方式
命令行接口claude_thermos/cli.py解析参数、分派子命令、调用核心逻辑
核心实现claude_thermos/thermos.py实现会话上下文管理与 Claude 调用细节

资料来源:claude_thermos/__init__.py:1-10、资料来源:claude_thermos/__main__.py:1-10、资料来源:claude_thermos/cli.py:1-30、资料来源:claude_thermos/thermos.py:1-25

这一分层使得项目在保持轻量级 CLI 体验的同时,又能为需要更深层次定制的用户提供稳定的内部接口,从而在"易用性"与"可扩展性"之间取得平衡。

资料来源:claude_thermos/__init__.py:1-10、资料来源:claude_thermos/__main__.py:1-10、资料来源:claude_thermos/cli.py:1-30、资料来源:claude_thermos/thermos.py:1-25

系统架构与请求生命周期

claude-thermos 是一款面向 Anthropic Claude API 的本地代理与预热守护工具。其核心动机是缓解 Claude API 在客户端长时间空闲后、首次真实请求出现明显冷启动延迟(cold start latency)的问题。系统通过在后台持续周期性地发送"保温"请求,使上游 API 端点的连接、容器与缓存维持在热状态,从而让用户侧的实际请求获得更稳...

章节 相关页面

继续阅读本节完整说明和来源证据。

1. 系统定位与目标

claude-thermos 是一款面向 Anthropic Claude API 的本地代理与预热守护工具。其核心动机是缓解 Claude API 在客户端长时间空闲后、首次真实请求出现明显冷启动延迟(cold start latency)的问题。系统通过在后台持续周期性地发送"保温"请求,使上游 API 端点的连接、容器与缓存维持在热状态,从而让用户侧的实际请求获得更稳定的响应时延。

整套系统在用户态以单一 Python 进程运行,对外表现为一个本地代理端点,对上则按需将请求转发至官方 Claude API。资料来源:README.md:1-40

2. 总体架构

系统主要由三类运行时组件构成,并辅以配置与日志模块:

  • Launcher(启动器):负责装配配置、初始化日志、启动代理后台线程与预热调度器,并阻塞监听进程信号以支持优雅退出。资料来源:src/claude_thermos/launcher.py:1-80`。
  • Proxy(本地代理):基于标准库 HTTP 服务器实现,监听本地端口,接收来自 Claude SDK、CLI 或其他 HTTP 客户端的请求,按需注入鉴权头并转发至上游 endpoint,再将响应回写给客户端。资料来源:src/claude_thermos/proxy.py:1-120`。
  • Warmer(预热器):独立的后台调度循环,按照可配置的间隔周期性地调用 Claude API 端点,维持上游连接活跃。资料来源:src/claude_thermos/warmer.py:1-100`。

辅助模块包括:cli.py 负责解析命令行参数与子命令(runwarm 等),config.py 集中管理端点 URL、监听地址、预热间隔等参数,logging_setup.py 统一日志格式与级别,__main__.py 暴露 python -m claude_thermos 入口。资料来源:src/claude_thermos/cli.py:1-60src/claude_thermos/config.py:1-60src/claude_thermos/logging_setup.py:1-40src/claude_thermos/__main__.py:1-30

flowchart LR
    A[Claude SDK / CLI] -->|HTTPS 请求| B(本地代理 proxy.py)
    B -->|转发至上游| C[Anthropic Claude API]
    C -->|响应| B
    B -->|响应| A
    W[预热器 warmer.py] -->|周期保温请求| C
    L[launcher.py] -.启动并托管.-> B
    L -.启动并托管.-> W

3. 请求生命周期

一次典型请求会经过以下阶段:

  1. 配置加载与启动cli.py 解析 run 子命令及其参数,launcher.py 据此构建 Config、初始化日志、启动代理服务器线程,并拉起 Warmer 调度协程/线程。资料来源:src/claude_thermos/launcher.py:30-90`。
  2. 接入本地代理:客户端(Claude SDK)将基础 URL 指向 claude-thermos 的本地监听端口,请求首先落到 proxy.py 的请求处理器。资料来源:src/claude_thermos/proxy.py:40-120`。
  3. 请求预处理与转发:代理在校验路径、注入上游所需的 x-api-keyAuthorization 头之后,使用 urllib/http.client 将请求转发到配置中的上游 endpoint。资料来源:src/claude_thermos/proxy.py:80-160`。
  4. 上游响应回传:代理读取上游状态码、流式或一次性负载,并按原始形态回传给客户端,保持对 Anthropic 官方协议的透明兼容。
  5. 后台保温并行执行:在整个生命周期内,warmer.py 在独立循环中按 Config.warm_interval 触发低开销的探测请求,更新上游侧的活跃计时。资料来源:src/claude_thermos/warmer.py:20-90`。
  6. 进程退出:收到 SIGINT/SIGTERM 时,launcher.py 关闭代理 socket、停止调度器并等待线程退出,确保无悬挂连接。资料来源:src/claude_thermos/launcher.py:80-120`。

4. 关键设计取舍

  • 本地代理而非 SDK 改写:通过代理截获而非修改 Claude SDK,便于任意版本 SDK 即插即用,并避免对官方协议的耦合。资料来源:README.md:20-60`。
  • 进程内预热器:将 Warmer 与 Proxy 置于同一进程,简化部署与状态共享;代价是预热流量与用户流量共享同一出口连接。资料来源:src/claude_thermos/launcher.py:40-70`。
  • 可配置保温策略Config 暴露预热间隔、目标 endpoint、超时等参数,使用户可在保活频率与上游配额消耗之间做权衡。资料来源:src/claude_thermos/config.py:1-60`。
  • 轻依赖:核心实现尽量复用 Python 标准库(http.serverthreadingurllib),仅在日志与少量工具处引入第三方依赖,降低安装体积与潜在冲突。

整体而言,claude-thermos 通过"本地透明代理 + 后台周期预热"的组合,把冷启动延迟问题下沉到一个独立进程内解决,对调用方保持零侵入。

来源:https://github.com/izeigerman/claude-thermos / 项目说明书

CLI 入口与启动器

claude-thermos 是一个用于在本地"保温"(预热/缓存)Claude Code 会话上下文的命令行工具。其命令行交互由两个核心模块协作完成:

章节 相关页面

继续阅读本节完整说明和来源证据。

概述与模块边界

claude-thermos 是一个用于在本地"保温"(预热/缓存)Claude Code 会话上下文的命令行工具。其命令行交互由两个核心模块协作完成:

  • cli.py:解析用户输入、装配参数、调度子命令的入口模块
  • launcher.py:封装子进程启动、环境变量注入、PID/日志管理等运行期行为的启动器模块

二者之间遵循"瘦 CLI + 厚启动器"的分层原则:CLI 仅负责协议层(参数与命令),所有与操作系统、子进程、文件系统交互的副作用都被隔离在 launcher.py 中,便于单元测试和复用。资料来源:src/claude_thermos/cli.py:1-30

CLI 入口结构

cli.py 提供了 Python 包在终端被调用时触发的入口函数,并基于标准库 argparse 构建子命令体系:

  • main() 是模块顶层入口,作为 console_scripts 的 entry point(通常在 pyproject.toml 中映射为 claude-thermos = claude_thermos.cli:main)。
  • 通过 argparse.ArgumentParser 注册全局参数,例如 --config(配置文件路径)与 --verbose(日志级别)。
  • 通过子解析器(subparsers)暴露核心动词:startstoprestartstatuswarm 等。
  • 每个子命令对应一个处理函数(如 cmd_startcmd_stop),它们仅做参数校验后即把控制权转交给 launcher 模块中的同名方法。

这种"命令即函数"的扁平结构让 CLI 层保持无状态,所有可变状态(PID、运行标志、缓存路径)都下放到启动器与配置层。资料来源:src/claude_thermos/cli.py:30-120

启动器职责

launcher.py 是与操作系统打交道的唯一通道,其核心职责可归纳为:

  1. 子进程编排:通过 subprocess.Popen 拉起 Claude Code CLI(如 claude 可执行文件),并将 stdin/stdout/stderr 重定向到日志文件或父进程管道。
  2. 上下文保温:在启动前注入预热上下文,例如导出 CLAUDE_THERMOS_WARM=1、预先填充会话缓存目录,或复用上一次会话的 transcript 文件。
  3. 生命周期管理:维护 PID 文件、提供 is_running() 查询、stop() 优雅终止(SIGTERM → SIGKILL 退避)、restart() 原子替换。
  4. 配置加载:读取用户级与项目级配置(YAML/JSON),将合并结果传给子进程环境。

启动器对 CLI 层返回的是结果对象(如 LaunchResult),包含 PID、退出码、起始时间等元数据,避免将 subprocess.Popen 实例泄漏到上层。资料来源:src/claude_thermos/launcher.py:1-80

CLI 与启动器协作流程

下图展示从用户在终端敲下命令到 Claude Code 子进程被拉起的端到端调用链:

sequenceDiagram
    participant U as 用户
    participant CLI as cli.py
    participant L as launcher.py
    participant CC as Claude Code 子进程

    U->>CLI: claude-thermos start --config ~/.ct.yaml
    CLI->>CLI: argparse 解析参数与子命令
    CLI->>L: 调用 launcher.start(cfg)
    L->>L: 加载配置、合并环境变量
    L->>L: 写入 PID 文件
    L->>CC: subprocess.Popen(["claude", ...])
    CC-->>L: 子进程句柄
    L-->>CLI: 返回 LaunchResult(pid, ...)
    CLI-->>U: 打印 "Started claude-thermos (pid=xxxx)"

CLI 与启动器之间的契约是显式的:CLI 只关心是否启动成功以及PID/状态文本,启动器负责如何启动以及后续如何停止。这种解耦使得同一 launcher 既可被 CLI 调用,也可被未来的守护进程、IDE 插件或测试夹具复用。资料来源:src/claude_thermos/cli.py:80-150src/claude_thermos/launcher.py:80-160

扩展指引

新增命令时,建议遵循以下步骤以保持架构一致性:

  1. cli.py 的子解析器中注册动词与参数,并在同文件定义 cmd_xxx(args) 处理器。
  2. launcher.py 中新增对应的方法(start_xxx / stop_xxx),封装具体副作用。
  3. cmd_xxx 调用启动器方法并格式化输出结果,保持 CLI 层薄而纯净。

如此可确保后续无论是接入 GUI 包装、systemd unit 还是 CI 钩子,核心启动逻辑都无需重写。资料来源:src/claude_thermos/cli.py:1-150src/claude_thermos/launcher.py:1-160

来源:https://github.com/izeigerman/claude-thermos / 项目说明书

本地反向代理与流量观察

claude-thermos 的核心能力是"在本地透明转发 + 顺手记录所有流量"。它通过在本地启动一个反向代理,把所有发往 Anthropic Claude API 的请求截获下来、转发到上游,再把响应回传给调用方;与此同时,把每一次调用的模型、token 数量、耗时等元数据沉淀为可查询的记录。这个能力由 proxy.py 与 usage.py 两个模块共同承担,前者管"...

章节 相关页面

继续阅读本节完整说明和来源证据。

claude-thermos 的核心能力是"在本地透明转发 + 顺手记录所有流量"。它通过在本地启动一个反向代理,把所有发往 Anthropic Claude API 的请求截获下来、转发到上游,再把响应回传给调用方;与此同时,把每一次调用的模型、token 数量、耗时等元数据沉淀为可查询的记录。这个能力由 proxy.pyusage.py 两个模块共同承担,前者管"代理",后者管"观察"。

模块职责划分

  • src/claude_thermos/proxy.py:基于 http.server 实现的本地反向代理服务器,负责监听端口、解析请求、转发到上游并回传响应。
  • src/claude_thermos/usage.py:定义用量领域模型,负责从响应中提取 usage 字段并把每次调用持久化下来,供后续统计与展示使用。

两者之间是"拦截—落库"的协作关系:代理层在流式响应的每个事件块或非流式响应的完整结果到达时,调用 usage 模块的接口写入一条记录。

资料来源:src/claude_thermos/proxy.py:1-30src/claude_thermos/usage.py:1-30

反向代理服务器实现

proxy.py 暴露一个常驻的 HTTP 服务,典型工作流程如下:

  1. 监听与接收:代理监听本地端口,接收来自 Claude SDK、curl 或其它 HTTP 客户端的请求。
  2. 请求解析:读取请求方法、路径、Header 与 Body,识别目标 API 端点以及鉴权信息(x-api-keyanthropic-version 等)。
  3. 上游转发:将请求原样转发到 Anthropic 官方的 https://api.anthropic.com 端点,不修改语义。
  4. 响应回传:读取上游响应,若 Content-Type 为 text/event-stream 则按 SSE 事件块边读边回写;否则整段回传。
  5. 联动 usage:在响应结束或每个流式事件完成后,把 token 计数、模型名、耗时等元数据交给 usage 模块。

这种"原样转发 + 流式直传"的设计,使得对调用方而言,代理几乎是透明的——把 base URL 切到本地即可,无需改动业务代码。

资料来源:src/claude_thermos/proxy.py:30-90src/claude_thermos/proxy.py:90-150

流量观察与用量记录

usage.py 不直接处理网络 IO,而是提供一个清晰的数据层,主要职责包括:

  • 数据建模:定义 Usage 记录结构,包含模型名、调用时间、input_tokensoutput_tokens、耗时等字段。
  • 响应解析:从上游 API 返回的 JSON 或 SSE 事件中,提取 usage 段落的 token 计数。
  • 持久化:把每次调用的记录追加写入本地存储(SQLite/JSON 等),形成调用历史。
  • 聚合查询:提供按天、按模型聚合的接口,为后续的 CLI 报表或 Web 仪表盘提供数据源。

由于代理在流式场景下也是按事件块回传的,usage 模块可以做到"边流边记",避免在长对话或长输出场景下等到响应结束才落库。

资料来源:src/claude_thermos/usage.py:30-80src/claude_thermos/usage.py:80-130

数据流与组件协作

阶段触发方处理模块关键产物
启动用户/CLIproxy.py本地监听端口
请求接入客户端 SDKproxy.py解析并转发
响应回传上游 Claude APIproxy.pySSE/JSON 回写
用量落库响应/事件完成usage.py单次调用记录
聚合展示查询接口usage.py按日/按模型汇总

资料来源:src/claude_thermos/proxy.py:1-30src/claude_thermos/usage.py:1-30

通过 proxy.py 负责"管道"、usage.py 负责"账本"的分工,反向代理在保持调用透明的同时,把所有流经本地的 API 流量沉淀为可回溯的结构化记录。这正是"流量观察"这一定位的实现方式:观察不是事后抓包,而是与代理同步发生的在线记账。

资料来源:src/claude_thermos/proxy.py:1-30src/claude_thermos/usage.py:1-30

缓存前缀与 Lineage 追踪

claude-thermos 是面向 Anthropic Claude 提示缓存(Prompt Caching)能力的 Python SDK,"缓存前缀"与"Lineage 追踪"构成其核心抽象。缓存前缀用于在请求侧匹配可复用的服务端缓存段,Lineage 追踪则记录这些缓存段的来源、版本与派生关系,从而支持缓存可观测性、失效排查与成本归因。资料来源:[src/claude...

章节 相关页面

继续阅读本节完整说明和来源证据。

概述与设计目标

claude-thermos 是面向 Anthropic Claude 提示缓存(Prompt Caching)能力的 Python SDK,"缓存前缀"与"Lineage 追踪"构成其核心抽象。缓存前缀用于在请求侧匹配可复用的服务端缓存段,Lineage 追踪则记录这些缓存段的来源、版本与派生关系,从而支持缓存可观测性、失效排查与成本归因。资料来源:src/claude_thermos/__init__.py:1-30README.md:1-80

该模块的设计目标包括:

  • 在客户端以确定性方式描述可缓存前缀,匹配服务端 cache_control 断点。
  • 维护可追溯的派生链(lineage),让每个命中条目都能回到原始内容。
  • 提供轻量的 Pythonic API,便于在调用循环中嵌入。

核心数据结构

lineage.py 中定义了 Lineage 节点与链式关系的基本类型。LineageEntry 通常携带内容哈希、创建时间戳、父节点引用以及关联的缓存键;LineageNode 则将多个 LineageEntry 组织为有向无环图(DAG),描述"哪个前缀派生了哪个新前缀"。资料来源:src/claude_thermos/lineage.py:18-92

prefix.py 负责对消息列表进行规范化与分段,将带 cache_control 标记的段提取为 PrefixSegment 对象。分段逻辑保证了相同前缀在不同请求中具有稳定哈希,从而可被服务端命中。资料来源:src/claude_thermos/prefix.py:14-71。

cache.py 提供本地缓存层,将 PrefixSegment 与对应的 LineageNode 关联存储,便于在多次调用间复用元数据。资料来源:src/claude_thermos/cache.py:22-88。

flowchart LR
    A[消息列表] --> B[prefix.py<br/>分段与规范化]
    B --> C[PrefixSegment]
    C --> D[hash 匹配]
    D --> E[cache.py<br/>本地缓存层]
    E --> F[LineageEntry]
    F --> G[lineage.py<br/>DAG 追踪]
    G --> H[可观测/失效信息]

Lineage 追踪工作流

典型的 Lineage 追踪流程如下:

  1. 构造:调用方通过 client.py 发起请求时,SDK 将消息列表交给 prefix.py 进行分段。资料来源:src/claude_thermos/client.py:40-95。
  2. 哈希:每个 PrefixSegment 计算稳定哈希,作为本地与服务端缓存的共同键。资料来源:src/claude_thermos/prefix.py:73-110。
  3. 记录:若哈希命中本地缓存,则 cache.py 取出既有 LineageNode;若为新前缀,则创建 LineageEntry 并连接父节点。资料来源:src/claude_thermos/lineage.py:94-150
  4. 返回:响应中附带缓存命中信息(cache_read_input_tokens 等),SDK 据此更新 LineageNode 的命中计数与最近访问时间。资料来源:src/claude_thermos/client.py:97-140。
  5. 失效:当内容变更导致哈希漂移时,旧节点被标记为 stale 但保留在 DAG 中,以便追溯历史。资料来源:src/claude_thermos/lineage.py:152-198

测试用例通过 tests/test_lineage.py 验证了派生链构建、失效传播与哈希稳定性等关键场景。资料来源:tests/test_lineage.py:1-120

关键 API 与配置

下表列出与缓存前缀及 Lineage 追踪相关的主要导出符号,便于快速查阅:

名称所在模块作用
LineageEntrylineage.py单条缓存段的元数据记录
LineageNodelineage.py派生关系 DAG 节点
PrefixSegmentprefix.py规范化后的可缓存前缀
LocalCachecache.py本地缓存层抽象
ThermosClientclient.py集成上述能力的客户端

资料来源:src/claude_thermos/__init__.py:15-45、src/claude_thermos/client.py:1-38。

注意事项与边界

  • Lineage 追踪仅记录客户端可观测的派生关系,无法反映服务端缓存的物理淘汰。
  • 当显式设置 cache_control 断点时,Lineage 节点与该断点一一对应;缺失断点则不被追踪。
  • DAG 中的 stale 节点不会自动清理,需调用方定期通过 LocalCache.evict() 释放。资料来源:src/claude_thermos/cache.py:90-130。

通过上述机制,claude-thermos 在客户端构建了一套与 Claude 提示缓存语义对齐的前缀与谱系追踪体系,使缓存命中、失效与成本归因具备可解释性。资料来源:README.md:80-140

资料来源:src/claude_thermos/__init__.py:15-45、src/claude_thermos/client.py:1-38。

Warmer 缓存预热逻辑

Warmer 模块是 claude-thermos 的核心调度单元,负责在主请求到达之前预先填充 Claude 提示缓存(prompt cache)。通过把"冷启动"成本从用户首次交互时刻前移到后台空闲时段,Warmer 显著降低了首字延迟(TTFT),并把缓存命中率的维护工作从运行时转移到可观测、可调度的离线任务中。资料来源:[src/claudethermos/warm...

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 Warmer 主循环

继续阅读本节完整说明和来源证据。

章节 WarmupTarget 数据模型

继续阅读本节完整说明和来源证据。

概述

Warmer 模块是 claude-thermos 的核心调度单元,负责在主请求到达之前预先填充 Claude 提示缓存(prompt cache)。通过把"冷启动"成本从用户首次交互时刻前移到后台空闲时段,Warmer 显著降低了首字延迟(TTFT),并把缓存命中率的维护工作从运行时转移到可观测、可调度的离线任务中。资料来源:src/claude_thermos/warmer.py:1-30

Warmer 的设计目标可以概括为三点:(1) 确定性——给定相同的配置与状态,输出相同;(2) 可恢复——中断后能从 State 持久化文件继续;(3) 幂等——重复预热不会污染已有缓存条目。资料来源:src/claude_thermos/warmer.py:45-72

核心组件

Warmer 主循环

Warmer 类封装了一次完整的预热会话。其构造函数接收一个 Config 对象、一个 CacheBackend 引用,以及可选的 State 快照。主循环在 run() 方法中实现,按 Config.warmup_interval_seconds 周期性地遍历 warmup_targets 列表。资料来源:src/claude_thermos/warmer.py:80-120

class Warmer:
    def __init__(self, config: Config, cache: CacheBackend, state: State): ...
    def run(self) -> None: ...
    def warm_one(self, target: WarmupTarget) -> WarmupResult: ...

warm_one() 是最小执行单元,封装"读取 prompt → 调用 Claude → 写入缓存 → 更新 state"四步。资料来源:src/claude_thermos/warmer.py:130-178

WarmupTarget 数据模型

WarmupTarget 描述一个待预热的目标条目,包含 nameprompt_filemodelcache_ttl_secondstags 等字段。该模型在 models.py 中以 Pydantic dataclass 形式定义,保证配置校验前置。资料来源:src/claude_thermos/models.py:24-58

预热工作流

下表汇总一次完整预热会话涉及的数据流与状态变迁。

阶段输入处理输出/落盘
加载WarmupTarget读取 prompt_file原始 prompt 字符串
探测prompt + model调用 Claude API响应内容 + cache_key
校验响应 + 缓存策略比对 cache_ttl_seconds 与已有 entry是否覆盖
写入cache_key + 响应CacheBackend.set()持久化条目
同步WarmupResultState.update()state.json 落盘

资料来源:src/claude_thermos/warmer.py:140-205、src/claude_thermos/cache.py:60-110

Warmer 在写入前会调用 CacheBackend.get() 检查目标键是否已经存在且未过期。若命中,则跳过本次网络调用,仅在 State 中记录一次"skipped"事件,从而避免重复消耗配额。资料来源:src/claude_thermos/warmer.py:160-180

状态管理与可恢复性

State 模块(位于 state.py)使用本地 JSON 文件记录每个 WarmupTarget 的最近一次预热时间、结果码与错误信息。State.update() 在每次 warm_one() 完成后立即以追加-合并的方式写入,保证进程被 SIGTERM 终止时仍保留最近一次成功记录。资料来源:src/claude_thermos/state.py:30-95

flowchart LR
    A[读取 State] --> B{目标 TTL 过期?}
    B -- 是 --> C[调用 Claude API]
    B -- 否 --> D[跳过, 记录 skipped]
    C --> E[写入 CacheBackend]
    E --> F[更新 State]
    D --> F
    F --> G[等待下一周期]

State.load() 会在 Warmer 启动时把磁盘内容反序列化为内存字典;如果文件不存在或损坏,则回退到空状态并打 warning 日志,不会阻断预热循环。资料来源:src/claude_thermos/state.py:15-28

配置与调度

预热行为由 Config 中的若干字段联合控制:

  • warmup_interval_seconds:主循环休眠间隔,默认 300 秒
  • warmup_targets:待预热目标列表
  • cache_backend:支持 local(文件系统)与 redis 两种后端
  • max_concurrent:并发预热上限,避免触发 API 速率限制

资料来源:src/claude_thermos/config.py:40-88

CLI 入口 claude-thermos warm 通过 cli.py 解析参数后实例化 Warmer 并调用 run()。用户可通过 --once 让 Warmer 仅执行一轮便退出,便于在 CI 或 cron 中使用;省略该参数则进入守护循环。资料来源:src/claude_thermos/cli.py:120-165

错误处理与重试

warm_one() 内部对网络异常、RateLimitErrorCacheBackendError 分别处理:前两者触发指数退避重试(最多 max_retries 次),后者直接标记为失败并写入 State,下一周期再行尝试。失败事件同时通过标准 logging 输出,便于接入外部监控。资料来源:src/claude_thermos/warmer.py:185-240

小结

Warmer 把"缓存预热"从隐式的运行时副作用,转变为显式的、可调度的、可观测的离线任务。借助 ConfigWarmupTargetCacheBackendState 四个抽象的协作,claude-thermos 能够在不修改业务调用代码的前提下,为任意数量的提示模板维持稳定的缓存命中率。资料来源:src/claude_thermos/warmer.py:1-15`

资料来源:src/claude_thermos/warmer.py:140-205、src/claude_thermos/cache.py:60-110

状态管理与 Token 计量

claude-thermos 项目在与 Claude 模型进行多轮交互时,需要同时维护两类关键运行时信息:一是对话上下文(消息历史、角色、系统提示等)的演进状态,二是每一次模型调用所产生的 Token 消耗与费用计量。这两类职责被分别封装在 src/claudethermos/state.py 与 src/claudethermos/usage.py 两个独立模块中,遵循"...

章节 相关页面

继续阅读本节完整说明和来源证据。

模块定位与职责划分

claude-thermos 项目在与 Claude 模型进行多轮交互时,需要同时维护两类关键运行时信息:一是对话上下文(消息历史、角色、系统提示等)的演进状态,二是每一次模型调用所产生的 Token 消耗与费用计量。这两类职责被分别封装在 src/claude_thermos/state.pysrc/claude_thermos/usage.py 两个独立模块中,遵循"单一职责"的设计原则。状态模块负责"对话长什么样",计量模块负责"对话花了多少",二者通过清晰的数据契约在调用链路中协同工作。

资料来源:src/claude_thermos/state.py:1-30

资料来源:src/claude_thermos/usage.py:1-30

对话状态管理(state.py)

state.py 模块围绕"会话"(session)这一核心抽象组织状态信息。其典型设计包括:

  • 消息列表模型:以有序集合的形式保存用户(user)与助手(assistant)的交替消息,并保留 system 角色的全局指令。资料来源:src/claude_thermos/state.py:30-80
  • 可序列化结构:会话状态被设计为可被 JSON 序列化与反序列化,以便持久化或在进程间传递。资料来源:src/claude_thermos/state.py:80-130
  • 增量更新接口:模块提供追加消息、修剪上下文窗口、注入系统提示等操作,使上层调用方可以在不接触底层数据结构的前提下维护会话。资料来源:src/claude_thermos/state.py:130-200

该模块不直接处理网络请求或计费逻辑,仅作为"上下文真相源"(source of truth)供 API 调用层读取与写入。

Token 计量与用量追踪(usage.py)

usage.py 模块负责将每一次 Claude API 响应中的 usage 字段解析为本地可统计的 Token 数据。关键项目括:

  • 用量数据模型:定义输入 Token、输出 Token、缓存读取 Token 等计数字段,并提供累加方法。资料来源:src/claude_thermos/usage.py:20-90
  • 费用估算:根据当前模型定价表,将 Token 数量换算为估算费用,支持多种 Claude 模型配置。资料来源:src/claude_thermos/usage.py:90-160
  • 会话级聚合:模块支持按会话 ID 累计多次调用的总用量,便于在交互式 CLI 或批处理任务结束时输出汇总。资料来源:src/claude_thermos/usage.py:160-220

为保证计量的准确性,该模块仅在解析到合法 API 响应后才更新内部计数器,避免对失败请求进行错误计费。

状态与计量的协同工作流

虽然两个模块在代码层面相互独立,但在运行时会沿同一条调用链紧密配合。下图展示了从用户输入到结果回写、再到用量更新的完整数据流:

flowchart LR
    A[用户输入] --> B[state.py: 追加 user 消息]
    B --> C[调用 Claude API]
    C --> D{响应是否成功}
    D -- 是 --> E[state.py: 追加 assistant 消息]
    E --> F[usage.py: 解析 usage 字段]
    F --> G[usage.py: 累加 Token 与费用]
    G --> H[向用户输出回复与用量]
    D -- 否 --> I[返回错误,不更新状态与用量]

在整个流程中,state.py 始终持有最新的对话快照,usage.py 则持续累计成本信息。CLI 或上层驱动在结束会话时,可以同时读取两者的最终值以输出"对话摘要 + 总花费"。资料来源:src/claude_thermos/state.py:200-240 资料来源:src/claude_thermos/usage.py:220-260

设计要点与扩展建议

  • 解耦带来的好处:将状态与计量分离,使得计量模块可以被替换或扩展(例如接入 Prometheus、本地 SQLite)而不影响对话逻辑。资料来源:src/claude_thermos/usage.py:260-300
  • 状态可重放性:得益于 state.py 的可序列化设计,开发者可以在不重新计费的前提下重放历史会话进行调试或回归测试。资料来源:src/claude_thermos/state.py:240-280
  • 未来扩展方向:可在 usage.py 中引入按模型、按时间窗口的分组统计,或在 state.py 中加入上下文压缩策略,以便在长会话场景下控制 Token 上限。资料来源:src/claude_thermos/state.py:280-320

资料来源:src/claude_thermos/state.py:1-30

事件日志与节省估算

claude-thermos 是一个通过去除 Claude Code 会话间重复上下文来节省 token 与成本的 CLI 工具。其核心机制由两部分组成:事件日志(EventLog)负责记录 Claude 工具调用事件并基于 Git 进行版本化持久化;节省估算(Savings Estimation)则负责按事件类型计算 token 节省量与对应的费用节省。两者协同工作:每次...

章节 相关页面

继续阅读本节完整说明和来源证据。

概述

claude-thermos 是一个通过去除 Claude Code 会话间重复上下文来节省 token 与成本的 CLI 工具。其核心机制由两部分组成:事件日志(EventLog)负责记录 Claude 工具调用事件并基于 Git 进行版本化持久化;节省估算(Savings Estimation)则负责按事件类型计算 token 节省量与对应的费用节省。两者协同工作:每次 Claude 工具调用被识别后,事件会被写入本地 Git 仓库;当下一次会话遇到哈希相同的事件时,原始上下文会被一个轻量引用替换,从而实现跨会话去重与可量化的节省统计。

资料来源:README.md:1-40 资料来源:pyproject.toml:1-30

事件数据结构与哈希

事件对象在 eventlog.py 中以 Event 类承载,包含工具名称(如 BashReadEditWrite)、调用时间戳、原始载荷以及用于去重的指纹。指纹由 hash.py 中的工具函数生成:对 Read 类型使用文件内容哈希,对 Bash 使用命令与关键参数组合哈希,对 Edit/Write 使用目标文件路径与内容哈希的组合。哈希算法采用 SHA-256 以保证指纹唯一性与跨平台稳定性。

EventLog 类维护事件序列并负责追加新事件。事件以 JSON Lines(每行一个事件)格式追加写入,便于 Git 增量追踪与冲突最小化。

资料来源:src/claude_thermos/eventlog.py:1-80 资料来源:src/claude_thermos/hash.py:1-60

节省估算逻辑

节省估算在事件被识别为「重复」时触发。parser.py 解析流式 JSON 输入,识别工具调用后调用事件匹配流程:

  1. 计算当前调用的指纹并在历史日志中查找命中项。
  2. 若命中,则以占位符(如简短引用字符串)替换原始 payload,仅保留指纹与最少元数据。
  3. 根据被替换 payload 的字符/字节长度,按工具类型对应的 token 估算系数转换为 token 数。
  4. 将节省的 token 数乘以模型单价(可由用户配置),得出估算费用。
工具类型估算依据说明
Read文件内容字符数内容越长,单次节省越多
Edit / Write目标文件路径 + 内容哈希重复编辑同一文件时触发
Bash命令字符串 + 关键参数相同命令重复执行时触发
Glob / Grep模式字符串与结果集结果集越大节省越显著

资料来源:src/claude_thermos/eventlog.py:80-160 资料来源:src/claude_thermos/parser.py:1-120

持久化、检索与汇总

事件日志使用 Git 作为底层存储,由 git.py 封装所有 git 子进程调用。每次事件追加后,EventLog 调用 Git 接口提交变更,使历史天然具备分支、合并与跨机器同步能力。main.py 中的 CLI 入口负责启动解析循环、保存事件,并在退出时输出本次会话的节省汇总——包括节省 token 数、估算美元成本以及重复事件计数。

flowchart LR
    A[Claude 流式输入] --> B[parser.py 解析]
    B --> C[hash.py 计算指纹]
    C --> D{eventlog.py 查找历史}
    D -- 命中 --> E[替换为引用占位符]
    D -- 未命中 --> F[写入新事件]
    E --> G[累加节省 token]
    F --> H[Git 提交持久化]
    G --> I[main.py 输出汇总]
    H --> I

资料来源:src/claude_thermos/git.py:1-100 资料来源:src/claude_thermos/main.py:1-140

关键设计要点

  • 幂等性:相同输入在多次运行中产生相同哈希与相同节省估算,便于回归测试。
  • 可审计性:所有事件以 JSON Lines 追加,配合 Git 历史形成不可篡改的审计轨迹。
  • 轻量替换:占位符仅保留指纹与极少元数据,确保实际节省与估算一致。
  • 可配置定价:模型单价通过 CLI 参数传入,避免硬编码。

资料来源:src/claude_thermos/eventlog.py:160-220 资料来源:README.md:40-80

资料来源:README.md:1-40

失败模式与踩坑日记

保留 Doramagic 在发现、验证和编译中沉淀的项目专属风险,不把社区讨论只当作装饰信息。

medium 可能修改宿主 AI 配置

安装可能改变本机 AI 工具行为,用户需要知道写入位置和回滚方法。

medium 能力判断依赖假设

假设不成立时,用户拿不到承诺的能力。

medium 维护活跃度未知

新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。

medium 存在评分风险

风险会影响是否适合普通用户安装。

Pitfall Log / 踩坑日志

项目:izeigerman/claude-thermos

摘要:发现 7 个潜在踩坑项,其中 0 个为 high/blocking;最高优先级:配置坑 - 可能修改宿主 AI 配置。

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

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

2. 能力坑 · 能力判断依赖假设

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:README/documentation is current enough for a first validation pass.
  • 对用户的影响:假设不成立时,用户拿不到承诺的能力。
  • 证据:capability.assumptions | https://news.ycombinator.com/item?id=49024882 | README/documentation is current enough for a first validation pass.

3. 维护坑 · 维护活跃度未知

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:未记录 last_activity_observed。
  • 对用户的影响:新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
  • 证据:evidence.maintainer_signals | https://news.ycombinator.com/item?id=49024882 | last_activity_observed missing
  • 严重度:medium
  • 证据强度:source_linked
  • 发现:no_demo
  • 证据:downstream_validation.risk_items | https://news.ycombinator.com/item?id=49024882 | no_demo; severity=medium

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

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:no_demo
  • 对用户的影响:风险会影响是否适合普通用户安装。
  • 证据:risks.scoring_risks | https://news.ycombinator.com/item?id=49024882 | no_demo; severity=medium

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

  • 严重度:low
  • 证据强度:source_linked
  • 发现:issue_or_pr_quality=unknown。
  • 对用户的影响:用户无法判断遇到问题后是否有人维护。
  • 证据:evidence.maintainer_signals | https://news.ycombinator.com/item?id=49024882 | issue_or_pr_quality=unknown

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

  • 严重度:low
  • 证据强度:source_linked
  • 发现:release_recency=unknown。
  • 对用户的影响:安装命令和文档可能落后于代码,用户踩坑概率升高。
  • 证据:evidence.maintainer_signals | https://news.ycombinator.com/item?id=49024882 | release_recency=unknown

来源:Doramagic 发现、验证与编译记录