Project Scaffold Service Template v1
September 21, 2026 · View on GitHub
Status: implemented bounded profile; local evidence only (tests/project.rs,
tests/project/new_cli.rs, and the full toolchain's cli_new_project_v1).
No hosted or release-archive run has exercised it yet; the calculator and
library templates' HOSTED GREEN evidence in
Public Project Scaffold Capsule v3 does not extend
to this template.
Audience: new SEMAPRAX users and coding agents who want a scaffolded starting point that already composes a bundled standard-library dependency, and compiler contributors maintaining the scaffold's frozen inventory/digest contract.
Purpose
--template service adds a third built-in Public Project Scaffold Capsule
v3 template beside calculator and library: a
small multi-user task-tracking service that composes two bundled
standard-library decision layers instead of defining every function locally.
It exists so a newcomer who wants to see a [dependencies]-carrying project
work end to end does not have to hand-write one; semaprax new --template service <destination> and semaprax project-scaffold --name <name> --template service --layout tables both derive it from the same compiled-in bytes as the
other two templates, with no filesystem, network, or process authority.
Command
semaprax new <destination> [--name project-name] [--template calculator|library|service]
semaprax project-scaffold --name <name> [--template calculator|library|service] [--layout frozen|tables]
The service template only derives under the table manifest layout. Its
semaprax.toml declares a [dependencies] table, and the frozen
semaprax.project.v1 layout that --layout frozen (the default for
project-scaffold) emits has no such table to put it in, so
derive_project_scaffold_v1_with_layout(name, "service", ScaffoldLayout::Frozen)
returns SPX-J115 before rendering anything, rather than silently dropping
the dependencies. semaprax new is unaffected: both CLI binaries always
derive through ScaffoldLayout::Tables regardless of template, so new --template service always succeeds for a valid destination and name.
Inventory and contents
The service template's nine-file inventory contains README.md, AGENTS.md,
semaprax.toml, src/app.spx, src/core.spx, src/tests.spx,
service-config.schema.json, service.config.json, and
service-host-adapter-request.json. The six ordinary project files retain the
calculator table layout's shape; the three additional files make the service's
host configuration boundary explicit:
semaprax.tomluses theuseful-data.v1profile and declares the bundledstd.auth,std.db,std.http,std.jobs,std.log,std.log.redact,std.metrics,std.export.policy,std.tracing, andstd.webhookdecision packages under[dependencies], and exports<name>.identifier_is_validand<name>.method_is_rejectedunder[exports].web(Public Useful Data Export v1admits no authored aggregate in a project that also declares a web export, so the domain record and its job are modeled as plain scalar facts, not arecord).src/core.spxcomposes auth/session, database/migration/transaction, request-line, durable-job/idempotency, bounded redacted-log, metric/export, trace-context, and webhook-admission predicates by stable@id. Its webhook step combines the existing exact-descriptor idempotency outcome with a bounded signature envelope, symmetric replay window, attempt count, and caller-classified secret guard; it is a decision before any signing, queueing, retry scheduling, or transport.src/app.spxcalls the core module'srun_scenario, which walks register/login/create-or-update/enqueue/complete/query/logout end to end and confirms both an unauthorized-access and an invalid-request rejection.src/tests.spxasserts the same scenario plus focused success, refusal, idempotency, redaction, tracing, metric, export, and webhook cases.AGENTS.mdis the same base guide every template ships, with the table layout's "Project v1 function boundaries" section (declared aggregates cannot cross a scalar-signature function boundary) plus one more section naming all ten bundled dependencies and their non-claims.service-config.schema.jsonis a closed Draft 2020-12 schema for fixture, SQLite/PostgreSQL, native HTTP/TLS, OTLP, and host-owned secret-reference selections. Nested database, HTTP, telemetry, and secret objects all refuse unknown fields and retain finite string bounds.service.config.jsonselects only credential-free fixture adapters, null endpoints, and null secret references. It carries no DSN, password, token, signing material, environment-variable name, or authority to resolve one.src/project/scaffold/service_config.rsindependently decodes this v1 wire under a 16 KiB pre-parse bound, exact closed objects, canonical sorted JSON, bounded reference/origin grammar, and paired mode rules: fixture mode admits only null/fixture selections, while host mode requires SQLite/PostgreSQL, native modern-TLS HTTP, OTLP, HTTPS origins, and nonempty host-owned secret references. JSON Schema guidance is therefore not the compiler's sole check.service-host-adapter-request.jsonis the compiler-rendered canonical handoff for the fixture configuration. It is bounded to 16 KiB and declares no capabilities. From a valid host configuration the same decoder renders a separate request naming exactly four capabilities — database connect, native TLS serve, host-secret resolve, and telemetry emit — plus only bounded origins and secret references. A separate closed request-v1 decoder replays those bytes for host consumption and retains the telemetry origin as an intent only. It cannot construct an outbound policy or capability: the host must separately grant one whose exact allowed-origin set contains that target before it can bind an adapter. This is an intent declaration, not a capability grant or a physical adapter implementation.
This mirrors examples/task-service-project/, generalized with the
{{name}}/{{module}} substitution every template uses; the reference
example is not itself part of the scaffold's compiled-in bytes.
Capsule
The service template lowers to the same semaprax.project.v1 contract and
Public Project Scaffold Capsule v3 descriptor shape
as the other two: schema semaprax.project-scaffold.v3, digest domain
semaprax.project-scaffold.digest.v3, limits.files nine, and the rendered
project passes the same in-memory check-and-test validation
(validate_owned_project_test) before the capsule is returned to the caller,
using the bundled dependency registry
(src/project/standard_dependencies.rs) to resolve all ten decision
packages purely in memory -- no filesystem or network access, exactly like an
ordinary project naming those packages in [dependencies].
Compatibility
Both CLI binaries accept --template service identically: semaprax new's
standalone create-new route
(standalone project creation v1) and the full
toolchain's held-parent staged publication route share one authority path for
the calculator and service templates (both name their sources app.spx,
core.spx, tests.spx), and a separate one for the library template's
different file names.
Evidence
tests/project/scaffold.rs::service_template_composes_bundled_dependencies_and_only_derives_under_tables_layout
pins the frozen-layout refusal, the exact inventory, the manifest's
[dependencies] table and web exports, the AGENTS.md additions, deterministic
derivation, self-replay, and cross-template replay rejection.
tests/project/scaffold_cli.rs and tests/project/new_cli.rs pin the CLI
output and the full end-to-end check/test/run/fmt --check loop for a
created project. The full toolchain's
crates/semaprax-toolchain/tests/cli_new_project_v1.rs::service_template_has_exact_bytes_and_passes_the_developer_loop
pins the same loop through the held-parent authority and is the regression
test for a prior defect where that authority's new_project::run collapsed
every non-library template to the calculator after parse had already
accepted --template service.
tests/project/scaffold.rs::service_scaffold_configuration_is_closed_and_credential_free
pins the nested closed-schema rules, exact database adapter vocabulary, fixture
selection, empty fixture capability request, and absence of endpoints and
secret values. Descriptor replay binds all three configuration/adapter files
byte-for-byte with the other generated assets.
The decoder's own hostile corpus rejects unknown members, mode/adapter drift,
credential-shaped DSNs, insecure origins, noncanonical encoding, and max-plus-
one input before the fixture can enter scaffold derivation.
The independent host-request decoder separately rejects unknown, duplicate,
reordered-capability, noncanonical, and max-plus-one request bytes. Its
private-root loopback integration starts from a checked host configuration,
then proves that only a separately host-granted outbound policy matching the
decoded OTLP origin can bind the fixed telemetry route. Neither the scaffold
fixture (which has no requirements) nor request replay grants network I/O.
Nonclaims
Unchanged from Public Project Scaffold Capsule v3: the capsule is checked bytes only, owning no filesystem, process, environment, current-directory, target-emission, or publication authority, and it makes no release or host-support claim. The bundled dependencies are pure decision layers with no hashing, signing, socket, database, job-queue, retry-scheduling, telemetry-emission, or webhook-delivery host capability of their own; a real deployment performs all of those outside this scaffold.