Compose apps you can control and trust
Beta: This project is currently in beta. The API may change before the stable release.
- Simplicity — lightweight IoC, no containers/providers/decorators. Framework-agnostic.
- Clarity — no magic, no globals; context flows through typed wiring.
- Reusability — same code, different context per compose.
- Testability — missing context, duplicates, unused wires fail in CI.
- Observability — your app as plain JSON; hooks for start, complete, fail.
A minimal example built on the three key pieces: Task, Tag, and Wire (how they connect). Two features share data without knowing about each other.
import { createTask, createWire, compose, tag } from "@grlt-hub/app-compose"
// where the name to greet will live
const whoToGreet = tag<string>("whoToGreet")
const greeting = createTask({
name: "greeting",
run: {
// greeting reads from it
context: whoToGreet.value,
fn: (name) => console.log(`Hello, ${name}!`),
},
})
const user = createTask({
name: "user",
run: { fn: () => ({ name: "World" }) },
})
compose()
.step(user)
// filled by the user task
.step(createWire({ from: user.result.name, to: whoToGreet }))
.step(greeting)
.run()Quick start — a step-by-step guide to the core concepts. Or browse the full docs and guides.