taskctl: A Concurrent Task Runner That Treats Your Build Pipeline Like a Graph
If you've ever waited around while make grinds through targets one at a time when half of them could've run in parallel, you know the feeling. GNU Make is everywhere, but it wasn't designed with modern CI pipelines or concurrent execution in mind. taskctl is a task runner that takes a different approach: you describe your tasks and pipelines in YAML, JSON, or TOML, and it builds a directed acyclic graph to figure out what can run at the same time.
What It Does
taskctl is a concurrent task runner and routine-tasks automation toolkit, positioned as a simple, modern alternative to GNU Make. You define tasks and pipelines in a human-readable config file (YAML, JSON, or TOML, with support for local or remote imports), and taskctl builds a graph from that pipeline to determine the execution plan. Tasks can run concurrently or cascade, depending on the dependencies you declare.
It's written in Go, and that shows up in a couple of practical ways: it ships with an embedded shell interpreter, so it doesn't depend on a system shell, and it's cross-platform as a result. Beyond pipelines, you can run individual tasks manually, trigger them with the built-in filesystem watcher for live reload, or embed the runner directly into your own Go programs.
Here's the example from the README:
tasks:
lint:
command:
- golangci-lint run
- go vet ./...
test:
allow_failure: true
command: go test ./...
build:
command: go build -o bin/app ./...
env:
GOOS: linux
GOARCH: amd64
before: rm -rf bin/*
pipelines:
release:
- task: lint
- task: test
- task: build
depends_on: [lint, test]
In that plan, lint and test run concurrently, and build waits until both finish. That's the whole idea in one snippet.
Why It's Cool
-
The DAG isn't a gimmick — it's the point. Most task runners treat parallelism as an afterthought you bolt on with flags. Here, dependencies, conditions, allowed failures, and graph visualization are core concepts. You declare what depends on what, and taskctl works out the schedule.
-
It's AI-agent friendly, which is a phrase you don't see often. The README calls out JSON discovery, NDJSON run events, a non-interactive mode, and an installable agent skill. If you're wiring task execution into an automated agent or a tool that needs to parse structured output, that's a meaningful design choice rather than an afterthought.
-
Execution contexts are a genuinely nice touch. You can wrap commands in
docker,ssh, or any binary. That means the same task definition can run locally or inside a container without rewriting it. -
No system shell dependency. The embedded shell interpreter means your pipeline behaves the same on Linux, macOS, and Windows. If you've ever debugged a Makefile that assumed bash, you'll appreciate this.
-
The output options are more thoughtful than usual. Raw, prefixed, a live dashboard, or a JSON event stream. A live dashboard for concurrent tasks is the kind of thing you don't realize you want until you've watched interleaved output from five parallel jobs.
-
Templated commands with variables, task variations, and output piped between tasks give you real composability. Plus conditions, allowed failures, and a
beforehook (as shown in the example) for setup steps. -
The extras round it out. Local and remote imports for config, an interactive task selector, shell autocomplete, and a filesystem watcher for live reload. None of these are individually surprising, but together they suggest the author actually uses this thing daily.
How to Try It
-
Head to the repository: https://github.com/taskctl/taskctl
-
Check the installation section in the README for your platform. Since it's a Go project, you can also grab it via the Go toolchain if that's your preference.
-
Create a
tasks.yaml(or JSON/TOML) in your project root. Start with something small — a lint task, a test task, and a build task, like the example above. -
Define a pipeline that ties them together with
depends_on, then run it. Watch how taskctl schedules the independent tasks concurrently. -
Once that works, try the file watcher for live reload, or pipe output between tasks to chain results.
The README's table of contents covers tasks, pipelines, variables, conditional execution, output formats, and more — worth reading through once you've got the basics running.
Final Thoughts
taskctl isn't trying to replace Make for compiling C projects with intricate file-timestamp dependencies. It's aimed at a different job: orchestrating routine developer tasks and pipelines where concurrency, readability, and cross-platform behavior matter more than incremental builds. If your Makefile has grown into a pile of .PHONY targets that mostly just shell out to other tools, and you'd like something that runs them in parallel without you hand-managing the order, this is worth a look. The AI-agent features and execution contexts suggest it's being actively shaped around real workflows, not just theory. Give it a shot on a side project first and see how the graph model feels.
Follow @githubprojects for more developer tools and open source projects.