Public Project Scaffold Capsule v3
September 21, 2026 ยท View on GitHub
Status: implemented bounded profile; HOSTED GREEN under the v0.4.0 release baseline. Historical local, authoring-time, ignored, device/simulator, or separately provisioned evidence below retains its narrower scope; public promotion, registry publication and broader product completion remain separately gated.
Audience: people and coding agents scaffolding SEMAPRAX projects, and compiler contributors.
semaprax project-scaffold prepares the calculator, library, or service
template as checked bytes. Public Project Scaffold Capsule
v2 emits the frozen semaprax.project.v1 manifest
layout and is pinned to those exact bytes. Capsule v3 adds one axis: the
--layout flag chooses whether the scaffold's semaprax.toml uses that
frozen layout or the extensible semaprax.manifest.v1 table layout
(Package Manifest v1), so a new project can start in
the format the ecosystem tooling reads.
Command
semaprax project-scaffold --name <name> [--template calculator|library|service] [--layout frozen|tables]
--layout frozen (the default) emits the v2 capsule, byte-for-byte identical
to what shipped, under schema semaprax.project-scaffold.v2. --layout tables
emits the v3 capsule under schema semaprax.project-scaffold.v3. For the
calculator, v3 also separates add into src/core.spx and imports it by
stable identity from src/app.spx; the library inventory is unchanged. A
--layout value other than frozen or tables exits with status 2 before any
output. The service template only derives under --layout tables: its
manifest carries a [dependencies] table, which the frozen semaprax.project.v1
layout has no room for, so --template service under the default frozen
layout is refused (SPX-J115) before anything is rendered, not silently
downgraded to a dependency-free project.
Capsule
The v3 capsule is identical to v2 except:
- the descriptor
schemaissemaprax.project-scaffold.v3; - the digest is framed under the domain
semaprax.project-scaffold.digest.v3, so a v2 and a v3 capsule of the same project never share a digest; - the
semaprax.tomlfile is the extensible table layout; - the calculator inventory adds
src/core.spx, andsrc/app.spxcontainsuse function @id("<name>.add") from <module>.core as add;.
The service template shares the calculator's table-layout inventory shape
(app.spx importing from a separate core.spx, plus tests.spx), but its
core.spx composes two bundled standard-library dependencies instead of
defining add locally: std.auth (session lifecycle, password-hash policy
bounds) and std.jobs (claim/lease/retry/idempotency state machines), pinned
in [dependencies] as std.auth = "=0.1.0" and std.jobs = "=0.1.0". Its
AGENTS.md carries an extra section naming both. See
Project Scaffold Service Template v1 for the
full template.
For the calculator template the manifest is:
schema = "semaprax.manifest.v1"
[package]
name = "<name>"
version = "0.1.0"
[modules]
entry = "<module>.app"
sources = ["src/app.spx", "src/core.spx", "src/tests.spx"]
tests = ["<module>.tests"]
[exports]
web = ["<name>.add"]
where <module> is <name> with - replaced by _. The library template is
the analogous table manifest over the library inventory. The table manifest
lowers to the same semaprax.project.v1 contract as the frozen one, so the
capsule's project_schema stays semaprax.project.v1 and the rendered project
passes the same check-and-test validation before the capsule is returned.
The frozen v1 layout carries no version; the table layout requires
[package] version, so the scaffold sets 0.1.0, matching the version the
lock and manifest examples use.
Replay
replay_project_scaffold_v1 reads the capsule's schema, maps it to the
frozen or table layout, and re-derives that exact layout, requiring byte and
digest equality. A v2 digest cannot validate v3 bytes and vice versa. The
descriptor field set and non-claims are unchanged from v2. Calculator and
library v3 capsules carry six files. The additive service template carries
eight: the same six project files plus its closed host-configuration schema and
credential-free fixture configuration. limits.files is derived from the
selected exact inventory and replayed byte-for-byte.
Evidence and nonclaims
tests/project.rs::scaffold::tables_layout_derives_a_v3_capsule_and_replays_only_as_itself
pins the v3 schema, the exact table manifest bytes for both templates, the
calculator import and added core module, the byte and digest distinction from
the frozen capsule, deterministic derivation, self-replay, and cross-digest
rejection; the unchanged
derivation_is_literal_ordered_deterministic_and_self_replaying test is the
byte guard that the frozen default did not move.
tests/project.rs::scaffold_cli pins the --layout tables CLI output and the
--layout bogus rejection.
The capsule is checked bytes only. It owns no filesystem, process, environment, current-directory, target-emission, or publication authority, and makes no release or host-support claim.