Date: 2026-06-16
Status: Accepted
Context
Generated apps expose request-level net/http entry points, but the generated
binary has been web-only. Apps that need background work or an additional
in-process server have had to replace the generated main or use hidden
goroutines in generated app code.
The lifecycle extension must preserve the compiler/runtime boundary from ADR 0006 and the generated Go boundary from ADR 0005. It must also avoid turning a specific protocol adapter, such as MCP, into framework core.
Decision
GOWDK will provide a generic generated-binary lifecycle:
gowdk.Config.Lifecycle.Servicesdeclares import/function service provider refs.- Generated app packages expose
App()for process startup while keepingHandler()andServeMux()request-only. runtime/app.Runowns signal handling, service supervision, cancellation, and graceful HTTP shutdown.- Lifecycle services use
runtime/app.Service,ServiceContext, andServiceHooks. - Contract-aware generated apps expose a shared
ContractRegistry()and pass it throughServiceContext.Valuesunder a string key.runtime/appdoes not importruntime/contracts.
MCP is not a built-in GOWDK addon or runtime package. An MCP bridge can be written as app code or an external package that returns lifecycle services.
Consequences
Positive
- Generated binaries can run workers, metrics endpoints, protocol bridges, and other app-owned servers without replacing generated main.
- Startup errors and shutdown behavior become visible and testable.
- The framework owns only lifecycle supervision, not app protocol semantics.
Negative
- Invalid provider symbols fail during generated app Go compilation, not during config AST parsing.
- Services that ignore context can still delay process exit until timeout.
Neutral
Handler()andServeMux()remain the integration surface for external routers and custom mains.- Target-specific lifecycle configuration remains future work.
Alternatives Considered
- Function-valued config. Rejected because generated binaries cannot carry build-time function values across the compiler/runtime boundary.
- Built-in MCP addon. Rejected because MCP is a protocol adapter and should not become framework implementation.
init()goroutines. Rejected because they hide errors and have no shutdown contract.
Follow-Up
- Add examples for generic app-owned services.
- Re-scope issue #480 as external/app-owned MCP adapter documentation if kept open.