Skip to main content

spaex — reproducible coding harnesses for any repo and development environment

Status: 5.0.0 (external skills remain standard skill content but are delegated to upstream installers through molecule hooks; see Spec 018). 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 (MCPs, constitutions, slash commands, dev-environment files, and external skill references, 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.json and install them in one invocation.
  • spaex remove <molecule-ids...>: retract one or more molecules from .spaex/manifest.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 constitution show: print the effective spaex 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: behavior, slash_commands, agents, mcps. The legacy constitution category remains readable for older molecules but is not the canonical way to contribute policy.

Environment-config files (flake.nix, Dockerfile, devcontainer.json, .envrc, shell.nix, etc.) can be declared under any category name a publisher chooses. The retired skill and skills categories are the one exception: a skill may still live in the publisher repository, but is declared as an external_skills reference and installed by the molecule's install_hook. Spec 014 makes no other 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 v5.0.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.

External skills

Molecules may keep standard SKILL.md directories in the publisher repository, including haexmas/atoms. They are not copied by spaex's atom materializer. The current 5.0.0 implementation uses opaque external_skills references and molecule hooks. The Spec 018 design update proposes structured source metadata and explicit spaex skills install / spaex skills configure commands with consumer-selected installer, agent, and scope. Those commands and the skill_installation policy are not implemented yet; the update is documentation-only.

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 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) 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

spaex-5.0.0.tar.gz (119.7 kB view details)

Uploaded Source

Built Distribution

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

spaex-5.0.0-py3-none-any.whl (150.3 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for spaex-5.0.0.tar.gz
Algorithm Hash digest
SHA256 42ed1384920277d5923f8a98da656ea012b275612f9ce60c9cdb6f4f5acdb934
MD5 a2d9f5cc5a4848ffecf6b99b5adb3969
BLAKE2b-256 09f339a2ed8351e227586a1c6bde16d2f5b15ae054cfc028b45d4aa2b2ec4581

See more details on using hashes here.

Provenance

The following attestation bundles were made for spaex-5.0.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-5.0.0-py3-none-any.whl.

File metadata

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

File hashes

Hashes for spaex-5.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fa20a0a8cf064fb55425da49fb1b9c5cb466cbd21df3124af9f7c29132a9955b
MD5 cebe6688636c1ca391507c3578c59a9f
BLAKE2b-256 38f58349804c873092ce790e236562bf76f9d0a1eed46ff7a115a81428cbc5de

See more details on using hashes here.

Provenance

The following attestation bundles were made for spaex-5.0.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

This release

5.0.0 This release

2 files

4.3.0

2 files

4.2.0

2 files

4.1.0

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