Status: Accepted (v1 in 0.3.0) Date: 2026-06-13 Deciders: PatrickJS Index: Design decisions
Helper packages need to expose reusable task groups without owning the host app’s jobs, sync policy, cache stores, or runtime context. Passing injected helpers is the preferred form:
claimsTasks({ task, sh, agent })
That keeps the host pipeline in charge of semantics. Some tools also need a portable emitter form that can produce declaration nodes without importing the same physical copy of @async/pipeline.
Use Symbol.for("@async/pipeline.declaration") as a shared declaration marker. Factory helpers attach non-enumerable metadata with { kind, version: 1 }, and definePipeline() walks the tree, validates shapes, and normalizes to the existing runtime definitions.
Top-level sections are context-bearing containers. Plain object sections remain the default public API, while explicit section factories such as tasks({ ... }) and jobs({ ... }) are accepted for advanced composition. definePipeline() detects already-branded sections and does not double wrap them.
Task groups use . for local task paths. Source namespaces keep :, so storefront:claims.report means source storefront, local task path claims.report.
The brand is not trust. Any package can call Symbol.for(...); the host still validates every object shape and rejects unknown fields before normalization.
API-surface hashing is intentionally out of this package. A future companion package can derive feature sets and hashes from validated declaration trees, but @async/pipeline owns pipeline-specific validation and normalization.
@async/pipeline can still exchange declaration nodes in the same JavaScript realm.