Skip to content
Apothem
架构

自包含运行时

Apothem 的引擎如何从任意检出运行——vendored 依赖、PYTHONPATH=src 调用模型,以及插件树引导。

自包含运行时

Apothem 的引擎是一个自包含运行时:它无需注册表,可直接从任意检出或已放置的源码树运行,因为它的第三方依赖随它一起携带。两部分使之成立——一棵 vendored 依赖树,以及一个无需已安装控制台脚本的 python -m 调用模型。

Vendored 依赖树

校验与序列化栈以纯 Python 源码形式 vendored 到 src/apothem/_vendor/ 下,每个包都与其上游许可证文件放在一起:

  • yaml(纯 Python 解析器/发射器;不携带可选的 libyaml C 扩展)
  • jsonschema,及其依赖链 attrs(及其 attr 别名)、referencing 和 jsonschema_specifications
  • rpds——一个纯 Python 垫片,以内置类型为后端,重新实现了 jsonschema 和 referencing 所使用的 HashTrieMap、HashTrieSet 和 List 表面,因此整个栈在零编译扩展的情况下运行
  • typing_extensions

Vendored 副本优先于任何系统安装的版本:插件引导、npm 垫片、安装器以及 python -m apothem 入口点本身,都会把 vendor 目录放在 sys.path 上 site-packages 之前。选择策略——哪些包 vendored、哪些不 vendored,以及 vendored 包如何刷新——记录在依赖 vendoring 策略中。

有两个依赖留在树外:click 和 rich,即 CLI 导入的面向终端的库。它们必须能在运行引擎的解释器下导入;安装器会检查两者,指出缺失的那个,并提议为你安装——经你确认后安装,或通过 --yes / APOTHEM_AUTO_INSTALL_DEPS=1 自动安装。在其他每个渠道上,入口点都会在导入 CLI 之前用标准库检查两者,缺失其中一个会使其停止,并给出一条错误,指明适用于当前运行解释器的确切 pip 命令(在 --json 下是一个代码为 runtime.dependency_missing 的 JSON 信封)。

python -m 调用模型

Apothem 有意不在 pyproject.toml 中声明任何控制台脚本——控制台脚本只有在包管理器将其放到 PATH 上时才存在,而自包含运行时从不假定存在包管理器。引擎改为提供两个调用表面:

表面调用方式上下文
引擎 CLIpython -m apothem <command>一棵将 src/ 置于 PYTHONPATH 上的源码树(检出、npx 缓存、插件树)
钩子运行时<resolved CPython> "<harness-root>/.apothem/support/hooks/dispatch.py" <event>Claude Code 的物化形态:位于工具根目录共享 .apothem/support/ 树下的副本,按绝对路径调用
  • python -m apothem 运行 src/apothem/__main__.py,后者将 src/apothem/_vendor 放到 sys.path 上,检查 click 和 rich 是否可导入,然后调用 apothem.cli:main——即 Click 命令组。
  • 物化后的 settings.json / hooks.json 中的钩子条目按绝对脚本路径调用分派器(对于 Claude Code,还会调用位于 <harness-root>/.apothem/support/conformity/gate.py 的合规闸门)。两者都是独立的标准库脚本,会自行引导各自的 sys.path,而闸门的 schema 夹具就放在它旁边的 <harness-root>/.apothem/support/schemas/ 中,因此钩子在宿主上没有可导入的 apothem 包的情况下也能运行。模板携带一个 ${HARNESS_ROOT} 令牌,apothem install 会将其渲染为正斜杠形式的真实工具根路径。
  • 在源码检出中,模块形式 python -m apothem.hooks.dispatch 和 python -m apothem.conformity.gate 运行相同的代码,供开发使用。

将检出的 src/ 目录前置到 PYTHONPATH,即可使包目录可导入:

PYTHONPATH="$HOME/.apothem/src" python -m apothem <command>

当 apothem 启动器不在 PATH 上时,install.sh 会在安装完成时打印这一形式:vendored 目录排在 src/ 之前,并以其所解析到的 CPython 代替 python。install.ps1 以 PowerShell 形式打印同样的两项设置:一条 $env:PYTHONPATH 赋值,它用 ; 连接 vendored 目录与 src/ 目录,随后是 & '<CPython>' -m apothem <command>。

插件树引导

Claude Code 插件将引擎打包在 <plugin_root>/lib/apothem 下,而不依赖 PYTHONPATH。引导模块 apothem.lib.plugin_bootstrap 暴露 bootstrap_syspath,它以幂等方式将 <plugin_root>/lib 和 vendor 目录前置到 sys.path,使 import apothem 和每个 vendored 依赖都从插件树解析。格式错误的树(缺少 lib/)会抛出 PluginBootstrapError,而不是无声地导入一份陈旧的系统副本。

安装器在磁盘上放置了什么

脚本安装器在 ~/.apothem(可用 APOTHEM_HOME 覆盖)放置一份源码树的 git 克隆,并从中运行引擎——除了可选的 click / rich 前置条件安装提议之外,不会向 site-packages 安装任何 Python 包。该克隆是完整的仓库,包括运行时从不导入的测试套件和文档站点,这出于两个有意的原因:引擎物化其集合——规则、技能、命令和模板——直接从该树物化到每个工具中,因此该树是实时的权威来源,而不仅仅是一个运行时;并且 .git 目录保留在原处,使 apothem update 在现有克隆中检出发布标签,而不是重新下载。

这种从源码运行的布局与 nvm、pyenv 和 oh-my-zsh 等工具所用的模式相同——几兆字节的源码加历史记录,可用卸载器一步移除(没有需要回退的系统状态)。更精简的占用——省略 tests/ 和 site/ 的浅检出或稀疏检出——是可行的,但会舍弃原地进行、经签名验证、基于 git 的更新路径;当前布局优先考虑简单、可验证的更新,而非最小磁盘占用。

运行时如何找到 Python

一键安装器和 npx 垫片探测的名称不同,但适用相同的规则。安装器探测 python3、python 以及带版本号的名称(python3.14 到 python3.10)。npx 垫片在设置了 APOTHEM_PYTHON 时先探测它,然后依次探测 python3、python 和 py -3;它没有带版本号的名称。两者都拒绝 Microsoft Store 启动器垫片,并接受第一个报告版本为 3.10 或更高的候选项。从源码树运行时,安装器复用捆绑的 hooks/lib/find-python 定位器,它应用相同的版本下限。

推荐的下一步

在检出的 src/ 目录位于 PYTHONPATH 上的情况下,运行 python -m apothem --help,以确认自包含 CLI 路径能在你的宿主上解析。

On this page