Narrative pass over the manifest spec, plus one correction to the guide I
committed in ba052736.
- **`app.id` allowed `_`.** `is_valid_app_id` accepts lowercase ASCII letters,
digits and single hyphens only — no underscores, no leading/trailing hyphen,
no `--`. The spec's "alphanumeric + `-`/`_`" would have a developer write an id
that fails to parse.
- **"Must match the directory name"** is a convention, not a rule. The loader
(`prod_orchestrator.rs:1455-1474`) walks `*/manifest.yml` and keys off
`app.id`, never comparing it to the folder, so a mismatch silently registers
the app under a different id. Said so rather than implying enforcement.
- **The Quadlet claim was the same one architecture.md was corrected for**
(f55ed6bf): install does NOT compile to a `user.slice` Quadlet unit today.
`config.use_quadlet_backends` defaults false, so apps take the legacy
`podman create + start` path; Quadlet is opt-in per node and companion UIs are
the exception that already use it.
- **"no per-app installer code"** — true of installers, but
`run_pre_start_hooks` is a hardcoded `match app_id` covering seven first-party
apps (bitcoin-ui, filebrowser, lnd, archy-nbxplorer, btcpay-server,
fedimint-clientd, grafana). Documented as the caveat it is; anyone reading the
source will find it in a minute and the doc should not look like it's hiding it.
- `derived_env` now names the full closed allow-list including `{{BITCOIN_HOST}}`
and what it resolves to.
Correction to ba052736: I wrote there that an unknown `derived_env` placeholder
passes through verbatim. It doesn't — `validate_derived_template` rejects both
unknown names and unbalanced `{{`. Fixed that row in the guide.
Verified accurate and left alone: the capability allow-list, network_policy
values, `/dev/*` device rule, volume option allow-list, bind-source confinement,
the four generated_secret kinds, `hooks.pre_start` being schema-only, and the
30s reconciler interval (`BootReconciler::DEFAULT_INTERVAL`).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- app-manifest-spec.md: full rewrite from the real schema in
core/container/src/manifest.rs — it was 5 months stale and missing the
entire modern feature set (build, network/network_aliases, derived_env,
secret_env, generated_secrets/certs, data_uid, files, interfaces, hooks,
extensions flatten) and documented wrong network_policy values.
- app-developer-guide.md: add generated_secrets/generated_certs/
network_aliases/hooks to the field table.
- APP-PACKAGING-MIGRATION-PLAN.md: phase status stamped (1-3 done, 5 mostly,
4+6 open); deleted meshtastic app removed from regression-proof lists.
- registry-manifest-design.md: status design → implemented (phases 1-3),
stale manifest_dir:Option line fixed.
- marketplace-protocol.md: reframed proposal → as-built (marketplace.rs +
RPCs + UI shipped; create-invoice noted; schema disambiguated).
- manifest-hooks-design.md: phase 3 (indeedhub) done, phase 4 resolved via
orchestrator+generated_secrets instead of hooks.
- README/architecture: restore the NIP-07 signer-bridge claim — it is real
(neode-ui/public/nostr-provider.js), the earlier audit only grepped Rust.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>