ADR-0004 · Barrel-only public API — no exported pull()
Status: Accepted
The public SDK surface is the generated registry.ts barrel, which re-exports each prompt as a named import. The pull(pin: string) function exists only as an internal utility consumed by generated code. It is not exported from the promptregistry package entry point.
Why
Three forces converged in the round-table grill:
- Refactor safety.
pull('customer-summary@v3')is string-keyed and greppable only by regex. Renaming a prompt requires a global string search, not a TypeScript rename-symbol. - The type-safety pitch. The whole product is "a PM removes a variable and
tsccatches it." If the canonical API is a string-keyed runtime call, the consumer experience is indistinguishable from an untyped registry. Named imports make the type contract visible at the import statement. - The launch story. The README hero is a screenshot of a rewritten
tscerror. That error must point at a call site the user recognises (customerSummary.with({...})), not at an internal.d.tsgenerated from a string key.
pull() still exists because the barrel needs something to call at runtime to resolve a Pin against the Manifest and construct a promptkit Compiled template. But that runtime call is hidden inside generated code.
Considered options
- Export
pull()as a public function alongside the barrel. Rejected — teams will use it, and the string-keyed path undermines the refactor-safety story. - Export
pull()but document it as "advanced use only." Rejected — "advanced" surfaces in Stack Overflow answers and hackathon code; the default path must be the only path. - No
pull()at all — inline the resolution into each generated file. Rejected — duplicates the Manifest-loading and template-construction logic across N files; a single internal utility keeps the codegen output small and the runtime surface minimal.
Consequences
- The
promptregistrypackage exports only types and the CLI binary. The SDK surface is entirely generated. - Every example in the README uses named imports from the barrel.
- The internal
pull()signature is not under semver lock from consumers, only from the codegen step. - If a future version introduces dynamic prompt resolution (e.g.
pull()from a database), that becomes a new exported function with a different name, not a promotion of the internal utility.