The Standard Library Was Already Enough: Rebuilding Taskfile in Pure Go
Description and use
A zero‑dependency task runner raptor built entirely with Go’s standard library, replacing go-task/task to achieve deterministic builds, reduced binary size, and simplified maintenance.
Problem
Replacing the popular Go task runner go-task/task with a zero‑dependency implementation to reduce audit surface and improve reproducibility.
Outcome
A fully functional, zero‑dependency task runner that matches go-task/task features, with reduced binary size, improved security, and deterministic incremental builds.
Workflow
- 1. Hand‑write an indentation‑sensitive YAML subset parser with line:column error reporting.
- 2. Implement a DAG scheduler using depth‑first search for topological sort and cycle detection.
- 3. Add bounded parallel execution via channel‑based semaphores scaling to
runtime.NumCPU(). - 4. Enable incremental builds by tracking source and generate files with timestamps and
crypto/sha256content hashing. - 5. Support dynamic variables and templating, evaluating
{ sh: cmd }once per run and providing template functions like{{.KEY | upper}}andfor:loops. - 6. Provide deterministic output modes: interleaved live streaming, prefixed lines, and topological group output.
- 7. Handle concurrency log tearing by spooling concurrent task streams to temporary files and re‑emitting them in DAG order when
--ordered-outputis enabled. - 8. Replace each third‑party dependency with a standard library alternative (e.g.,
flag.FlagSetfor Cobra,filepath.Matchfor globbing,os.CreateTempfor temp files).
Evidence
I replaced a Go tool that itself replaces make — and did it with an empty go.mod (zero third‑party imports).
Within an hour, "writing a small YAML parser" turned into "writing a strict parser for a subset of YAML that fails loudly on invalid syntax."
- Record date: 2026-09-08T06:38:14.766Z