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.2.0
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.2.0.tar.gz | 40.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| handoffpack-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 70.4 kB
Release files / handoffpack-0.2.0.tar.gz
| Download URL | handoffpack-0.2.0.tar.gz |
|---|---|
| Size | 40.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6101f76fe52d6d6710a2f8c9b052253ec28fd813937952c0b8e8774785471cb3
|
|
BLAKE2b-256 checksum How to use checksums |
98521b2416779578b1a1d6b3f8f692b6408a0ac55a806a1ff5829cfa9133965c
|
| 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.2.0-py3-none-any.whl
| Download URL | handoffpack-0.2.0-py3-none-any.whl |
|---|---|
| Size | 30.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
341aa74fcf09f797320353c0308e67b508e1e17d3f3f2178f8f82d937456fd4b
|
|
BLAKE2b-256 checksum How to use checksums |
0af069c313a77d7b90724acf98b39dd033a45574532b395f573f5243650629cc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.3
|