# Vendoring chattolib This plugin ships a **vendored copy of chattolib and all its dependencies** in `vendor/`. Nothing has to be installed separately — the plugin brings its own dependency tree. ## Why Vendoring? - **No dependencies to install**: `hermes plugin install` works immediately - **No lazy-import complexity**: no `ensure()` or `lazy_import` mechanisms - **Isolated**: the vendored copy cannot conflict with a system-installed one - **Offline-friendly**: works in air-gapped environments ## Layout Three of the vendored packages contain compiled extension modules and are therefore platform-specific: `pyqwest` (~15 MB, the HTTP core used by `connectrpc`), `protobuf` and `protobuf-py-ext`. Everything else is pure Python. The tree is split accordingly, so the shared part is stored once: ``` vendor/ ├── __init__.py ├── common/ # pure-Python packages (~8 MB), all platforms │ ├── chattolib/ │ ├── connectrpc/ │ ├── httpx/ httpcore/ h11/ anyio/ idna/ certifi/ │ └── opentelemetry/ protobuf/ typing_extensions.py └── platform/ # compiled extensions, ~16 MB per platform ├── linux-x86_64/ # pyqwest/, protobuf_ext/, google/ ├── linux-aarch64/ └── macos-arm64/ ``` `vendor_path.py` derives the platform tag from `platform.system()` / `platform.machine()` at import time and prepends `vendor/platform/` and `vendor/common` to `sys.path` — platform directory first, so the right binaries win. Both `adapter.py` and `platform_config.py` call `setup_vendor_path()` before importing anything from `chattolib`. If the current platform was not vendored, the import fails with an explicit message naming the available platforms — rather than a cryptic `dlopen` error about an invalid Mach-O/ELF file. ## Updating or rebuilding ```bash # Default platform set: linux-x86_64, linux-aarch64, macos-arm64 ./vendor_chattolib.sh # A single platform PLATFORMS="linux-x86_64" ./vendor_chattolib.sh # Add another one (see the table below for valid tags) PLATFORMS="linux-x86_64 linux-aarch64 macos-arm64 windows-amd64" ./vendor_chattolib.sh # Pin a specific chattolib version CHATTOLIB_SPEC="chattolib==0.4.20" ./vendor_chattolib.sh ``` The script wipes `vendor/`, installs the dependency tree once per platform via `uv pip install --python-platform …`, splits the result with `vendor_split.py`, and verifies that `import chattolib` works on the machine you ran it on. Afterwards: `git add vendor/`. ### Supported platform tags | Tag | uv `--python-platform` | vendored by default | | -------------------- | ------------------------------ | ------------------- | | `linux-x86_64` | `x86_64-unknown-linux-gnu` | ✅ | | `linux-aarch64` | `aarch64-unknown-linux-gnu` | ✅ | | `macos-arm64` | `aarch64-apple-darwin` | ✅ | | `linux-x86_64-musl` | `x86_64-unknown-linux-musl` | — | | `linux-aarch64-musl` | `aarch64-unknown-linux-musl` | — | | `macos-x86_64` | `x86_64-apple-darwin` | — | | `windows-amd64` | `x86_64-pc-windows-msvc` | — | All seven are available as binary wheels upstream; only the default three are committed, to keep the repository at a reasonable size (~59 MB for `vendor/`). ### Python versions The script resolves wheels for **Python 3.11** (`PYTHON_VERSION`), which is the project minimum. At that version the three binary packages still provide `cp310-abi3` wheels, and the stable ABI is forward compatible — so one build covers 3.11 through 3.14. Resolving for 3.12+ would instead pull version-specific wheels (`cp312-…`) that only work on that exact version. **If you raise `PYTHON_VERSION`, check that the resulting `.so` files are still named `*.abi3.so`.** If they are not, the vendored tree silently becomes Python-version-specific. ## Development without vendoring ```bash pip install chattolib ``` A system-installed chattolib is only used if `vendor/` is absent — the vendored copy is deliberately prepended to `sys.path` and therefore wins. ## License The vendored chattolib is licensed under **MPL-2.0 + Apache-2.0** (see `vendor/common/chattolib-*.dist-info/`). Upstream source: https://github.com/chattocorp/chatto