Skip to main content

spaex — reproducible coding harnesses for any repo and development environment

Status: 4.1.0 (adds molecule install-hooks and the on-demand molecule store; see Spec 016 and Spec 017). 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.json. spaex install writes them into .claude/, .codex/, .spaex/, and any other participating roots 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.json and install them in one invocation.
  • spaex remove <molecule-ids...>: retract one or more molecules from .spaex.json and 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 migrate: read v1/v2/v3 legacy manifests (.haex-hive.json, manifest.json) and emit v4 .migrated sidecar proposals with adoption instructions.
  • spaex constitution show: print the effective constitution to stdout, assembled from adopted molecules per install.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.1.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.10+ and Git 2.30+ on $PATH. Only runtime dependency is jsonschema.

Migrating from haex-hive v3

If your project has a .haex-hive.json with haex_hive_version: "3":

pipx install spaex
cd /path/to/your/project
spaex migrate

spaex migrate walks the repo and writes .migrated siblings for every v3 (or v1/v2) manifest it finds:

  • .haex-hive.json (v1/v2/v3) → .spaex.json.migrated
  • publisher-root manifest.jsonmanifest.json.migrated
  • per-molecule manifest.jsonmanifest.json.migrated

Review the printed diffs. When satisfied, adopt each proposal:

# consumer
mv .spaex.json.migrated .spaex.json
rm .haex-hive.json

# publisher-root and each molecule
mv path/to/manifest.json.migrated path/to/manifest.json

# runtime output (safe to delete; regenerated by install)
rm -rf .haex-hive/

spaex install

After spaex install completes, .spaex/install.lock is present and byte-identical across two consecutive runs.

The v4 vocabulary at a glance

  • Compound (.spaex.json.compounds[]): a (source, revision) pair with a list of adopted molecules[]. The consumer's allowlist.
  • Molecule: a published, reverse-DNS-identified bundle that a publisher declares in its root manifest.json under molecules{}.
  • Atom: a single delivered file, grouped under a category key in a molecule's manifest.json atoms{} map.

This vocabulary (compounds -> molecules -> atoms) was introduced by Spec 013 and is unchanged in v4. The v4 delta is limited to two field-name renames: haex_hive_version -> spaex_version (value "3" -> "4") and haex_hive_min_version -> spaex_min_version.

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 state directory (publisher clones, migration proposals). 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

spaex-4.1.0.tar.gz (79.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

spaex-4.1.0-py3-none-any.whl (104.0 kB view details)

Uploaded Python 3

File details

Details for the file spaex-4.1.0.tar.gz.

File metadata

  • Download URL: spaex-4.1.0.tar.gz
  • Upload date:
  • Size: 79.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for spaex-4.1.0.tar.gz
Algorithm Hash digest
SHA256 517d89ba8fe395e6af05fb4836a4ac51f0d103601ec95854fb9eb56add7f72ef
MD5 fd894656906e7222acd3e443eb78c0b3
BLAKE2b-256 4d5003d2cf9c0c6d01c3c8bc6c2b472fc7a4c2903c86a92b85a869f302624fb5

See more details on using hashes here.

Provenance

The following attestation bundles were made for spaex-4.1.0.tar.gz:

Publisher: release.yml on haexmas/spaex

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file spaex-4.1.0-py3-none-any.whl.

File metadata

  • Download URL: spaex-4.1.0-py3-none-any.whl
  • Upload date:
  • Size: 104.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for spaex-4.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b8c833f432a434bcffb5f463635277d9afa88bf0dfde39fb77dc18710ab12779
MD5 eae171d7fb8a078d03a5b76a835ad356
BLAKE2b-256 dd8e1781897f3f77b9d879b9ea8a685938e21bd670aaba741e2677c62f8164db

See more details on using hashes here.

Provenance

The following attestation bundles were made for spaex-4.1.0-py3-none-any.whl:

Publisher: release.yml on haexmas/spaex

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

5.0.0

2 files

4.3.0

2 files

4.2.0

2 files

This release

4.1.0 This release

2 files

4.0.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page