Typed do.ts, not YAML
A task can be one command string — or a typed object. Autocomplete everywhere, and a dep or step typo is a compile error with a "did you mean" fix. Your package.json scripts are tasks too.
Tasks live in a typed do.ts — no YAML, no Makefile, no DSL. One-line tasks, compile-time checked deps and steps, schema-validated env and flags, parallel DAG scheduling, caching, CI and git hooks. Zero runtime dependencies.
bun add -d @meslzy/outdo
bunx outdo init # scaffolds a starter do.tsimport { defineTasks } from "@meslzy/outdo";
import { z } from "zod";
export default defineTasks({
fix: "bunx biome check --write", // a task can be one command
build: {
desc: "Build the project",
inputs: ["src/**/*.ts"], // fingerprint cache
outputs: ["dist/**"],
run: "bun build src/index.ts --outdir dist",
},
test: {
deps: ["biuld"], // ← compile error: Did you mean "build"?
run: "bun test",
},
gate: { steps: ["fix", "build", "test"] }, // one after another
deploy: {
env: z.object({ DEPLOY_URL: z.url() }), // validated before anything runs
args: { dry: { type: "boolean", short: "d" } },
protect: true, // asks first; --yes answers
run: async ({ $, env, args }) => {
if (!args.dry) {
await $`./push.sh ${env.DEPLOY_URL}`;
}
},
},
});outdo # grouped task list (package.json scripts included)
outdo build # run a task + its deps
outdo gate --from build # part of a task's steps
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
bunx outdo ci gate # in GitHub Actions: changed tasks, folded logs, annotations