Metadata-Version: 2.4
Name: spaex
Version: 4.0.0
Summary: spaex 4.0: reproducible coding harnesses for any repo. Compose skills, MCPs, constitutions, slash commands, and dev-environment files into a single project; add/remove/install/migrate/constitution show CLI.
Author: spaex contributors
License: Apache-2.0
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: jsonschema>=4.18
Provides-Extra: dev
Requires-Dist: pytest>=7.4; extra == "dev"
Requires-Dist: pytest-subprocess>=1.5; extra == "dev"
Requires-Dist: ruff>=0.5; extra == "dev"
Requires-Dist: mypy>=1.8; extra == "dev"

# spaex — reproducible coding harnesses for any repo and development environment

**Status**: `4.0.0.dev0` (v4 vocabulary landed as part of Spec 014, first PyPI release upcoming). Portmanteau of `spec` and `haex`. See [docs/adr/0011-rename-to-spaex.md](docs/adr/0011-rename-to-spaex.md) for the rename decision and [specs/014-rename-to-spaex/](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`.

## 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](docs/plans/2026-09-07-slot-015-multi-environment-placeholder.md)).

## Install

**Once published to PyPI (upcoming with the `v4.0.0` tag):**

```bash
pipx install spaex
```

**From a local checkout (development):**

```bash
git clone https://github.com/haexmas/haex-hive.git
cd haex-hive
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"`:

```bash
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.json` → `manifest.json.migrated`
- per-molecule `manifest.json` → `manifest.json.migrated`

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

```bash
# 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](https://github.com/haexmas/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/](specs/) is authoritative for the mechanism it introduces.
- Design plans under [docs/plans/](docs/plans/) capture pre-spec requirements.
- Architecture Decision Records under [docs/adr/](docs/adr/) record decisions that reshape the system.
- The constitution at [.specify/memory/constitution.md](.specify/memory/constitution.md) is the non-negotiable invariant set every spec, plan, and implementation MUST respect.
