spaex — reproducible coding harnesses for any repo and development environment
Status: 4.3.0 (adds explicit multi-agent Spec Kit installation support on top of the behavior harness and declarative Spec Kit integration installer; see Spec 023 and Spec 024). Portmanteau of spec and haex. See docs/adr/0011-rename-to-spaex.md for the rename decision and specs/014-rename-to-spaex/ for the full spec.
What it is
spaex composes a coding harness for a single repo out of reusable pieces (skills, MCPs, constitutions, slash commands, dev-environment files, collectively "molecules"). You declare which molecules you want in .spaex/manifest.json. All spaex-owned project state lives under .spaex/; spaex install writes participating runtime files deterministically, pinned by SHA. Two consecutive spaex install runs on unchanged inputs produce byte-identical output.
What you can do today
spaex add <source-url> <molecule-ids...>: adopt one or more molecules from a publisher repo into.spaex/manifest.jsonand install them in one invocation.spaex remove <molecule-ids...>: retract one or more molecules from.spaex/manifest.jsonand re-run install (files that only the retracted molecule contributed are deleted).spaex install: publish adopted molecules atomically into their participating roots. Writes.spaex/install.lock.spaex constitution show: print the effective spaex constitution to stdout, assembled from adopted molecules perinstall.lock.
Molecule install-hooks
A molecule may declare an optional install_hook in its manifest.json. spaex install invokes it as a normal subprocess (arbitrary code, consumer-user permissions, full environment inheritance) after any required atom materialization and before publishing the install.lock generation; hook-only molecules run without atom materialization. Per-molecule on_failure: "abort" | "warn" selects between transaction rollback and continue-with-hook_status-recorded. Consumers can opt out for a single invocation via spaex install --no-install-hooks (or spaex add --no-install-hooks). See docs/install-hooks.md for the full contract: declaration schema, execution semantics, the four failure kinds, idempotency, non-reversibility, and the trust model.
Atom-category conventions
The v4 molecule-manifest schema treats atoms{} as an open Dict[str, List[str]] map. Publishers pick category names by convention. Common categories today: constitution, slash_commands, agents, mcps.
Environment-config files (flake.nix, Dockerfile, devcontainer.json, .envrc, shell.nix, etc.) can be declared under any category name a publisher chooses. Spec 014 makes no naming commitment here; multi-environment vocabulary (dev/staging/prod), consumer-side selection, and orchestration verbs are the scope of Spec 015 (planned; see docs/plans/2026-09-07-slot-015-multi-environment-placeholder.md).
Install
Once published to PyPI (upcoming with the v4.3.0 tag):
pipx install spaex
From a local checkout (development):
git clone https://github.com/haexmas/spaex.git
cd spaex
pip install -e '.[dev]'
Requires Python 3.14.x and Git 2.30+ on $PATH. spaex includes uv for
isolated, pinned CLI provisioning; jsonschema and pyyaml are the other
runtime dependencies.
After spaex install completes, .spaex/install.lock is present and byte-identical across two consecutive runs.
The spaex vocabulary at a glance
- Compound (
.spaex/manifest.json.compounds[]): a(source, revision)pair with a list of adoptedmolecules[]. The consumer's allowlist. - Molecule: a published, reverse-DNS-identified bundle that a publisher declares in its root
manifest.jsonundermolecules{}. - Atom: a single delivered file, grouped under a category key in a molecule's
manifest.jsonatoms{}map.
This vocabulary (compounds -> molecules -> atoms) is the clean-cut spaex format. There is no migration command or legacy manifest fallback.
Multi-device delegation
Not part of spaex. That is a separate project: holzi (Nostr + iroh + MCP agent plane, single-user first). spaex is deliberately scoped to one repo, one device.
Environment variable
spaex honors $SPAEX_STATE for the per-invocation publisher-clone state directory. Unset falls back to ~/.local/share/spaex/.
Documentation
- Every spec under specs/ is authoritative for the mechanism it introduces.
- Design plans under docs/plans/ capture pre-spec requirements.
- Architecture Decision Records under docs/adr/ record decisions that reshape the system.
- The constitution at .specify/memory/constitution.md is the non-negotiable invariant set every spec, plan, and implementation MUST respect.
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 spaex-4.3.0.tar.gz.
File metadata
- Download URL: spaex-4.3.0.tar.gz
- Upload date:
- Size: 117.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
71ab0c05e0a424a9fd4ad647bfb88eab4eb03e8b63e65525cacc2b608a5f4909
|
|
| MD5 |
8d340346555be4772733c810b41fcfba
|
|
| BLAKE2b-256 |
8f00c24f2914c535c12ea965502500414246ee947c70ba26ae1b506a2fc8e21d
|
Provenance
The following attestation bundles were made for spaex-4.3.0.tar.gz:
Publisher:
release.yml on haexmas/spaex
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
spaex-4.3.0.tar.gz -
Subject digest:
71ab0c05e0a424a9fd4ad647bfb88eab4eb03e8b63e65525cacc2b608a5f4909 - Sigstore transparency entry: 2830553248
- Sigstore integration time:
-
Permalink:
haexmas/spaex@dcd66a4afc7ca0a7bdc86c4a5f9a62f3258a7c9c -
Branch / Tag:
refs/tags/v4.3.0 - Owner: https://github.com/haexmas
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@dcd66a4afc7ca0a7bdc86c4a5f9a62f3258a7c9c -
Trigger Event:
push
-
Statement type:
File details
Details for the file spaex-4.3.0-py3-none-any.whl.
File metadata
- Download URL: spaex-4.3.0-py3-none-any.whl
- Upload date:
- Size: 148.2 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 |
1519bb7b43c28c8dbcd1eb160eaa30fc4b02628a223238bf2df7cc8d6871b5c7
|
|
| MD5 |
28ef360f14bd35dd9570cb1b8d7a6628
|
|
| BLAKE2b-256 |
1ebc83b551b7eb97eb981903b5c6ea793f83dcdfed6552a453a6dfc7e219ae19
|
Provenance
The following attestation bundles were made for spaex-4.3.0-py3-none-any.whl:
Publisher:
release.yml on haexmas/spaex
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
spaex-4.3.0-py3-none-any.whl -
Subject digest:
1519bb7b43c28c8dbcd1eb160eaa30fc4b02628a223238bf2df7cc8d6871b5c7 - Sigstore transparency entry: 2830553269
- Sigstore integration time:
-
Permalink:
haexmas/spaex@dcd66a4afc7ca0a7bdc86c4a5f9a62f3258a7c9c -
Branch / Tag:
refs/tags/v4.3.0 - Owner: https://github.com/haexmas
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@dcd66a4afc7ca0a7bdc86c4a5f9a62f3258a7c9c -
Trigger Event:
push
-
Statement type: