Skip to content

CLI Reference ​

Commands ​

commandwhat it does
outdolist tasks (do.ts tasks + package.json scripts), grouped
outdo <task> [flags] [-- args]run a task and its dependency DAG
outdo <task1> <task2>run several tasks (shared deps run once)
outdo <ns> <task>run a namespaced task — same as outdo <ns>:<task>; outdo <ns> lists the namespace
outdo run <task...>run a task whose name is also a command (outdo run ci)
outdo -ipick a task interactively: type to filter, ↑/↓, Enter runs (then asks for required flags), Esc quits
outdo ls [--json]list tasks — machine-readable with --json
outdo explain <task> [--json]why each planned task will run or skip (cache diagnosis, inputs, steps, backend); never runs
outdo graph [--dot] [--json]dependency graph as mermaid, graphviz dot, or JSON
outdo doctor [--json]run every task's requires checks; exit 1 if any fail
outdo usage [task] [--since <span>] [--all] [--no-history] [--json]what runs most, what never runs: unused tasks, flags never passed, choices never picked, modes, hooks, duplicates; never runs anything
outdo --print-env <task> [--json]resolved env with per-key provenance + schema verdict; never runs

Background runs ​

commandwhat it does
outdo bg start <task> [flags] [-- args]start detached; returns once its service is ready (details)
outdo bg ps [--json]what is running (also plain outdo bg)
outdo bg logs <task> [-f, --follow]print (or follow) a background run's log
outdo bg stop [task...]stop one or more runs; no name stops everything

CI / CD ​

commandwhat it does
outdo ci <task...> [--all] [--base <rev>]CI run: affected only, folded logs, failure recap, GitHub annotations + step summary
outdo ci init [--force]write .github/workflows/ci.yml
outdo affected <task...> [--base <rev>] [--github-output] [--json]did these tasks' inputs change? name=true|false per task
outdo hooks [install | uninstall | list | run <hook>]git hooks declared in do.ts (list is the default)
outdo prune --docker [--out <dir>]out/json/: every package.json + the lockfile, for a Docker layer

More ​

commandwhat it does
outdo initscaffold a starter do.ts (+ gitignore .outdo/)
outdo mcpMCP server over stdio: tasks as tools
outdo skill install [--global] / outdo skill pathinstall the outdo agent skill into .claude/skills/outdo (repo, or home with --global) / print where the bundled copy lives
outdo completion <shell>completion script for bash | zsh | fish | powershell

Command words win over task names. A task named like a command still runs with outdo run <name> — the task list points this out.

Global flags ​

Global flags go before the task name; everything after the task name belongs to the task — except the runner flags --mode/-m, --yes/-y, --from, --until, which may also follow it (unless the task declares a flag or alias of that name).

flagvaluesdefaultmeaning
-m, --mode <name>a declared modefirst declaredmode: picks .env.<mode> files, sets ctx.mode / OUTDO_MODE
-y, --yesoffanswer yes to protect/confirm questions
--from <step> / --until <step>a step namerun only part of a task's steps
-w, --watchoffre-run affected tasks when watched files change
-j, --concurrency <n>integer ≥ 1CPU countmax parallel tasks
--continueoffkeep running independent tasks after a failure
--log-order <mode>stream | grouped | autoautolive prefixed lines vs per-task blocks (auto: stream in a TTY, grouped otherwise)
--output-logs <mode>full | errors-only | nonefullhow much child output to show
--dry[=json]offprint the plan (incl. cache status and step order) without running
--affected[=<rev>]rev via = formoffonly run tasks affected by git changes vs <rev> (default: the PR base / previous push in GitHub Actions, else the merge-base with origin's default branch)
--profile[=<file>]path via = formoffwrite a Chrome trace of the run (default .outdo/trace.json)
-f, --forceoffignore the fingerprint cache (still records fresh fingerprints)
-F, --filter <pattern>repeatableselect workspace packages — see Workspaces
--isolateoffforce the child-process backend even for pure chains (multiplexed output, tree-kill semantics)
--jsonoffmachine-readable output — runs emit a JSON report on stdout, logs move to stderr
--color <mode>auto | always | neverautoalso --no-color; honors NO_COLOR / FORCE_COLOR
-h, --helpglobal help; outdo <task> --help shows the task's usage, flags and steps
-V, --versionprint the version

--affected and --profile take their value with = only (--affected=main, not --affected main) so a following task name is never swallowed. --watch is exclusive with --json, --profile, and --affected (usage error, exit 2).

Environment variables outdo reads ​

variableeffect
NODE_ENVselects the env cascade layer when no modes are declared (default development)
OUTDO_READONLY=1refuse any task not marked readonly
OUTDO_NO_LOCAL=1a global outdo does not hand over to the repo's installed copy
NO_COLOR / FORCE_COLORcolor output off/on (flag --color wins)
OUTDO_WATCH_POLL=1force the polling watch backend
OUTDO_LOG=debuginternal debug logging on stderr
OUTDO_NO_USAGE=1don't record runs in .outdo/usage.jsonl (also off whenever CI is set)
AI_AGENT, CLAUDECODE, CODEX_SANDBOX, CURSOR_AGENT, GEMINI_CLImark a run as an agent's in the usage log
HISTFILEan extra shell history file for outdo usage (besides ~/.zsh_history, ~/.bash_history, fish and PowerShell history)
GITHUB_ACTIONS, GITHUB_BASE_REF, GITHUB_EVENT_NAME, GITHUB_EVENT_PATH, GITHUB_STEP_SUMMARY, GITHUB_OUTPUTread by outdo ci, --affected and outdo affected (details)

outdo sets OUTDO_MODE (the active mode) and OUTDO_NESTED=1 (so an outdo run started by a task is recorded as nested) for everything it runs. OUTDO_SSH and OUTDO_DOCKER (a JSON argv) replace the ssh / docker binaries — meant for tests.

The global binary ​

A global outdo (installed with bun add -g) looks for node_modules/@meslzy/outdo from the current directory up and, when it finds a different copy, runs that one instead — so a repo always runs the outdo in its lockfile, and you can type outdo instead of bunx outdo. OUTDO_NO_LOCAL=1 turns this off.

Shell completions ​

sh
# bash (~/.bashrc)
eval "$(outdo completion bash)"

# zsh (~/.zshrc, after oh-my-zsh / compinit)
eval "$(outdo completion zsh)"

# fish
outdo completion fish > ~/.config/fish/completions/outdo.fish

# PowerShell ($PROFILE)
outdo completion powershell | Out-String | Invoke-Expression

Completions are dynamic and also work after bunx outdo. When no global outdo is installed, the scripts call bunx outdo themselves. Tab completes:

  • task names, namespaces and commands; outdo db <Tab> → the namespace's tasks
  • per-task flags, and flag values: --source <Tab> → the flag's choices, --mode <Tab> → your modes, --filter <Tab> → workspace packages, --from <Tab> → the task's steps, --log-order <Tab> → stream grouped auto
  • positional values: outdo logs <Tab> → api web
  • bg / hooks sub-commands, background run names and hook names

The task list is cached in .outdo/complete.json, keyed by the modification times of every do.ts, package.json and lockfile it was built from — a Tab is a JSON read, not a do.ts import. Every outdo command that loads the project (a run, outdo ls) refreshes it, and so does any Tab that finds it stale.

Released under the MIT License.