handoffpack — MCP structured-card translator
Deterministic codec + guards + MCP server for HP1 structured handoff cards. Turns agent handoffs, session logs, and recurring-instruction files into compact structured cards. All deterministic work runs locally; the server never calls an LLM API and holds no API keys.
Install
Python 3.11+ required.
# From PyPI (once published):
pip install handoffpack
# Pre-publish / local: from the package directory
pip install .
# or editable, with test deps:
pip install -e .[dev]
Core codec/guards tests run with stdlib + pytest only; the mcp package
is needed only to run server.py.
Register the MCP server (Claude Code)
python -m handoffpack.server # stdio transport, run directly
claude mcp add handoffpack -- python -m handoffpack.server
Other clients (Cursor, etc.): use the same command in their MCP server
registration UI. A handoffpack console script is also installed as an
alias for python -m handoffpack.server.
License key (paid add-ons only)
The 4 MCP tools (encode / decode / compact_to_l2l / verify) are
FREE and unlimited. Only paid add-ons (e.g. the full hp-instructions
conversion run) require a key. The verifier is fully offline (embedded
Ed25519 public key, no phone-home). Key discovery precedence:
export HP_LICENSE=HP1.xxxxx... # macOS/Linux
set HP_LICENSE=HP1.xxxxx... # Windows
# or place the key on the first line of ~/.handoffpack/license
# or pass --license <KEY> to hp-instructions
hp-instructions --check (drift scan) is free; a full conversion run
requires a plus-tier key.
Layout
mcp-translator/
├── pyproject.toml
├── src/handoffpack/
│ ├── legend.json # public card schema (typed slots + kv pairs)
│ ├── codec.py # assemble/parse/validate + chars/4 token estimator
│ ├── guards.py # breakeven passthrough, BAN-field rule, nuance heuristic
│ ├── license.py # offline Ed25519 license verifier (paid add-ons)
│ ├── adapter_instructions.py # hp-instructions CLI (CLAUDE.md -> HP1 cards)
│ └── server.py # MCP server: encode / decode / compact_to_l2l / verify
└── tests/
Run tests
pytest # 114 tests
Build & publish (maintainer)
python -m build # produces dist/*.whl + dist/*.tar.gz
python -m twine upload dist/*
If build is unavailable offline, an equivalent wheel can be produced
with python -m pip wheel . -w dist --no-deps --no-build-isolation.
Architecture notes (caller-does-semantics)
- Deterministic work (card assembly, parsing, schema validation, guards, token estimation) is local and pure. The server never calls an LLM API and holds no API keys (zero-server-cost invariant).
- Semantic work (slot extraction, compaction keep/drop judgment) belongs
to the CALLING model:
encode(slots={...})— the caller extracts TASK/ROLE/IN/DO/OUT/LIM/BAN from its own context and passes them directly (mode: "slots",confidence: "caller"). Passtexttoo for token metrics.compact_to_l2l— two-call protocol. Call 1 (session_textonly) returns a per-segmentscaffold+fill_slots_and_recall+ a crude deterministic fallback. Call 2 addssegment_slots={"<seg>": {slots} | "TASK string"}.decode/verify— deterministic.
- Freeform
encode(text=...)without caller slots returns a deterministic skeleton card plusfill_slots_and_recallguidance for a second call. - MCP sampling (
session.create_message) survives only as an OPTIONAL, capability-detected upgrade path (deprecated upstream: MCP 2026-07-28 spec RC, SEP-2577; replaced by Multi Round-Trip Requests, SEP-2322; Claude Code never implemented it, anthropics/claude-code#1785). It is OFF unless the operator setsHP_ENABLE_SAMPLING=1AND the client advertises the capability; results are always deterministically re-validated. Nothing depends on sampling. - Token estimates use ceil(chars/4). Crude by design; never used for claims or billing.
Guard behavior
- Inputs under ~70 estimated tokens are returned unchanged with a reason (encoding overhead exceeds savings below breakeven).
- BAN slots accept plain forbidden actions only. Conditional negation ("X unless Y", "only outside Z") is rejected; express the condition as a positive LIM constraint instead.
- Prose with high conditional-clause density gets an advise-skip verdict instead of a lossy card.
Metadata
Release files for handoffpack 0.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| handoffpack-0.3.1.tar.gz | 42.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| handoffpack-0.3.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 76.0 kB
Release files / handoffpack-0.3.1.tar.gz
| Download URL | handoffpack-0.3.1.tar.gz |
|---|---|
| Size | 42.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7f1833efd47cb4fa91e6362f0c74c3885978c25705f90ffbddcbe79495c73d84
|
|
BLAKE2b-256 checksum How to use checksums |
7ba70d052304e120cd30be3bd7e49efe38ff0b6140cb82a472efda28b9f5a251
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.3
|
Release files / handoffpack-0.3.1-py3-none-any.whl
| Download URL | handoffpack-0.3.1-py3-none-any.whl |
|---|---|
| Size | 33.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
deb20d8ba8c99b8f9e3e8a0c8371e93575a5bd2cfaf695de10cb170d90c087ac
|
|
BLAKE2b-256 checksum How to use checksums |
6a6e1a4826840fbcc87e5309965ef66735fb480a08af79f5923a9cbe8ce51d0c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.3
|