This release is a pre-release and may not be stable for production use.
alphex
Biological sequence alphabet orderings, and letter-preserving conversions between them.
uv add alphex
Why
Three different amino-acid orderings are in common use, under at least five different names:
| ordering | letters | used by |
|---|---|---|
| ProteinMPNN | ACDEFGHIKLMNPQRSTVWY |
ProteinMPNN, and most "canonical" alphabets |
| AlphaFold | ARNDCQEGHILKMFPSTWYV |
AlphaFold restypes, LG/JTT substitution models, IQ-TREE |
| ESM | LAGVSERTIDPKQNFYMHWC |
ESM3 / ESM-C, at offset 4 |
ProteinMPNN and AlphaFold order have exactly three fixed points — A, S and T. Build a
lookup table from one and label it with the other, and 17 of 20 residues are silently permuted.
The result is shape-valid, dtype-valid, and wrong; nothing raises. That bug has shipped.
An ecosystem census that motivated this package found those three orderings declared at 30
sites across four repositories, in six different sentinel conventions (no sentinel; X at 20;
gap at 20; gap at 0 with residues shifted to 1; gap at 20 with X at 21; X at 20 with gap at
21). Every site was an independent opportunity to get it wrong.
alphex holds one declaration of each, and one way to convert between them.
What it does
from alphex import Policy, SpecialKind, known, perm
# A table from ProteinMPNN order (gap at 20) into ESM's vocabulary.
table = perm(known.MPNN_GAP_21, known.ESM_C, policy=Policy.RAISE)
table.shape # (21,) -- the whole source domain, never just the 20 residues
int(table[0]) # 5 -- 'A'
int(table[20]) # 30 -- the gap, which ESM declares
Four entry points, because four genuinely different things get converted and using the wrong one scrambles letter identity silently:
relation(src, dst) |
classify first: IDENTITY, EXTENSION, PERMUTATION, INCOMPATIBLE, plus lossy and which letters moved |
perm(src, dst, *, policy) |
build the lookup table |
convert(codes, src, dst, *, policy) |
relabel sequence codes |
reindex(data, src, dst, *, policy, axes) |
move a posterior or substitution-matrix axis |
The design commitments
Letters, not indices. The invariant is that the amino acid at each position is unchanged and only its integer moves. Index equality cannot catch this bug class — the broken table and the correct one both round-trip perfectly within themselves.
Every index means something. A declaration must account for every index in [0, size) as a
residue, a named special, or explicitly unclaimed. A table shorter than its domain is how a
JAX gather clamped a gap index onto valine.
No silent defaults. policy is keyword-only and has no default, anywhere. It is keyed per
SpecialKind, so ESM's eight specials cannot collapse onto one destination index without you
writing that down.
No in-band sentinels. Policy.MASK returns a MaskedPerm, a distinct type — because every
in-band marker is a valid index somewhere. -1 selects the last element of the destination
axis; size is clamped rather than rejected by JAX.
Declarations carry provenance. citation is required and must be non-empty. An ordering
without a source is how one gets relabelled.
Names are not identity. Two Alphabets compare equal when their index spaces match,
whatever they are called. That is what makes an alias collision detectable instead of invisible.
CLI and MCP
Optional surfaces, for asking the two questions whose absence let a mislabelled table ship — "which ordering is this?" and "what does the table look like?" — without writing a script.
uv add "alphex[cli]" # or [mcp], or [agent] for both
alphex list # every shipped declaration
alphex show MPNN_GAP_21 # symbols, specials, citation, warnings
alphex relation MPNN_20 AF_20 # classify before converting
alphex perm MPNN_GAP_21 ESM_C # the table, plus a letter-preservation check
alphex lint # declarations with conflated sentinels
Every command takes --json-out. The MCP server (alphex-mcp) exposes the same five as tools —
list_alphabets, show_alphabet, relation, perm, lint — registered through
cisternal, which also ships the using-alphex skill and
project rules to Claude Code, Cursor, Copilot and Antigravity via .praxia/manifest.toml.
Both surfaces answer from one module (alphex._surface) so they cannot drift, and both take a
single uniform policy: the per-SpecialKind mapping form exists precisely so ESM's eight
specials cannot be collapsed onto one index by accident, and squeezing that through a CLI flag
would make doing so easy. Anything needing per-kind policy calls perm directly.
(The mcp extra pulls cisternal, which requires Python ≥3.13. alphex itself supports ≥3.11 and
will keep doing so, so the dependency is marker-gated: below 3.13 the library and CLI work
normally and alphex-mcp exits with a message saying why.)
Dependencies
numpy, and nothing else. That ceiling is the reason this is its own distribution rather than a
module inside a larger library: extras can only add to a base install, never subtract, so the
only way to make "just the alphabets" cheap for a consumer is for it to ship separately.
JAX consumers pass the result through jnp.asarray — the table is a small constant.
Status
Alpha. The value type, the shipped declarations and the conversion kernel are implemented and
tested. Not yet implemented: aliases for degenerate and non-standard residues (B, Z, J,
U, O), the substitution/rate-matrix asset layer, and the plugin registry for third-party
alphabets. The entry-point group names (alphabet_contract.v1.*) are reserved and deliberately
independent of this distribution's name.
Provenance
The orderings are facts about published tools, cited per declaration in known.py: ProteinMPNN
(Dauparas et al. 2022, MIT), AlphaFold residue_constants (Apache-2.0), ESM3/ESM-C
SEQUENCE_VOCAB (MIT). No code from those projects is included or derived from.
MIT licensed.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file alphex-0.1.0a1.tar.gz.
File metadata
- Download URL: alphex-0.1.0a1.tar.gz
- Upload date:
- Size: 22.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8ae8706c26eac2ccf78d1dd1e73a41bd3046e87552cc37306f80e43b75954652
|
|
| MD5 |
5dd132e0860c2ac3a0d7ba5f47620d60
|
|
| BLAKE2b-256 |
0d2f9b031d6422f3495d765490de930f873e8a17e6f1fa3d3b51085cf90f3e77
|
Provenance
The following attestation bundles were made for alphex-0.1.0a1.tar.gz:
Publisher:
release.yml on maraxen/alphex
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
alphex-0.1.0a1.tar.gz -
Subject digest:
8ae8706c26eac2ccf78d1dd1e73a41bd3046e87552cc37306f80e43b75954652 - Sigstore transparency entry: 2478971821
- Sigstore integration time:
-
Permalink:
maraxen/alphex@4f0b60069fa79bc196613a0af6c4d710ee00420e -
Branch / Tag:
refs/tags/v0.1.0a1 - Owner: https://github.com/maraxen
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4f0b60069fa79bc196613a0af6c4d710ee00420e -
Trigger Event:
push
-
Statement type:
File details
Details for the file alphex-0.1.0a1-py3-none-any.whl.
File metadata
- Download URL: alphex-0.1.0a1-py3-none-any.whl
- Upload date:
- Size: 26.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ce16ce1b214e84d0abc5cf7b68fb8d8d3cc56b056756ee22b36be8e0c94f9338
|
|
| MD5 |
27425fa3c7ed274bc9c243db133021a0
|
|
| BLAKE2b-256 |
5959fe50bd7c21ae9aa57a7b010916510aef70b95e99e2d65d8d11da74c0996c
|
Provenance
The following attestation bundles were made for alphex-0.1.0a1-py3-none-any.whl:
Publisher:
release.yml on maraxen/alphex
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
alphex-0.1.0a1-py3-none-any.whl -
Subject digest:
ce16ce1b214e84d0abc5cf7b68fb8d8d3cc56b056756ee22b36be8e0c94f9338 - Sigstore transparency entry: 2478971976
- Sigstore integration time:
-
Permalink:
maraxen/alphex@4f0b60069fa79bc196613a0af6c4d710ee00420e -
Branch / Tag:
refs/tags/v0.1.0a1 - Owner: https://github.com/maraxen
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4f0b60069fa79bc196613a0af6c4d710ee00420e -
Trigger Event:
push
-
Statement type: