Typed do.ts, not YAML
Tasks are TypeScript. Autocomplete, go-to-definition, refactoring — and a dep typo is a compile error with a "did you mean" fix.
Tasks live in a typed do.ts — no YAML, no Makefile, no DSL. Compile-time dependency checking, schema-validated env, parallel DAG scheduling, caching, and watch mode. Zero runtime dependencies.
bun add -d @meslzy/outdo
bunx outdo init # scaffolds a starter do.tsimport { defineTasks, task } from "@meslzy/outdo";
import { z } from "zod";
export default defineTasks({
build: {
desc: "Build the project",
inputs: ["src/**/*.ts"], // fingerprint cache
outputs: ["dist/**"],
run: async ({ $ }) => {
await $`bun build src/index.ts --outdir dist`;
},
},
test: {
deps: ["biuld"], // ← compile error: Did you mean "build"?
run: async ({ $ }) => {
await $`bun test`;
},
},
deploy: task({
env: z.object({ DEPLOY_URL: z.url() }), // validated before anything runs
args: { dry: { type: "boolean", short: "d" } },
run: async ({ $, env, args }) => {
if (!args.dry) {
await $`./push.sh ${env.DEPLOY_URL}`;
}
},
}),
});outdo # grouped task list
outdo build # run a task + its deps
outdo deploy -d # typed flags
outdo --watch build # re-run on change
outdo explain build # why will it run? what's cached?
outdo --affected test # only what changed vs the base branch
outdo --json build # full run report for CI / agents