Files
Ekklesia/docs/architecture/decisions/0005-static-module-manifests.md
T
ekklesia 7b448d8706
CI / verify (push) Successful in 2m14s
CI / infrastructure-smoke (push) Failing after 1m36s
feat: add module runtime lifecycle
2026-07-12 22:49:51 -05:00

3.0 KiB

0005: Static module manifests and atomic discovery

  • Status: Superseded
  • Superseded by: 0006
  • Date: 2026-07-12

Context

Ekklesia modules must be installable by placing a package in modules/ without editing Core or a central registry. Core must validate identity, compatibility, dependencies, capabilities, storage requirements, and entrypoints before it runs module behavior. Importing an executable TypeScript manifest would allow top-level module code to run before validation completed.

Decision

Every module uses one inert, versioned ekklesia.module.json manifest. @ekklesia/contracts owns the authoritative Zod schema and serializable types. @ekklesia/module-sdk re-exports those public contracts and provides defineModule for typed programmatic validation without becoming a Core service locator.

Core scans immediate non-hidden directories under the configured modules directory. Discovery validates all manifests and package metadata, resolves entrypoints without loading them, checks platform and Module SDK compatibility, resolves module and capability dependencies, and produces a deterministic dependency-first order. Any error rejects the entire discovery result with sorted, structured issues; no module server code is partially loaded.

Storage requirements are declarative. A module may request one or more logical buckets in its manifest, but it cannot create provider clients or select physical bucket names. The later Core storage service will provision deployment-prefixed physical buckets and give the owning module scoped handles. Buckets remain private unless a future explicit storage contract says otherwise.

Alternatives

  • Executable module.ts manifests were rejected because discovery would cross the code-execution boundary before validation.
  • Embedding the full manifest in package.json was rejected because it couples the platform contract to package-manager metadata and makes the manifest harder to version independently.
  • A manually maintained import registry was rejected because every module installation would require a central source edit.
  • Letting modules configure SeaweedFS or S3 clients directly was rejected because Core owns credentials, provider selection, isolation, and lifecycle.

Consequences

JSON manifests do not provide TypeScript inference by themselves, so validation commands and clear path-aware errors are part of the authoring workflow. A JSON Schema can be generated from the authoritative contract later for editor completion.

Discovery currently proves entrypoint existence but does not import server behavior, execute lifecycle hooks, provision requested buckets, or register routes, jobs, schemas, and migrations. Those operations begin only after a complete valid discovery result in later runtime slices.

Migration implications

The manifest includes manifestVersion: 1. Future incompatible shapes require an explicit schema version and migration path rather than silently changing existing module interpretation.