A code-first, strongly-typed build automation system for Deno & TypeScript.
Note
Built with AI. Much of Zuke β code, tests, and docs β was written with AI assistance, then reviewed, type-checked, and tested in CI. Sharing how it was made so you know what you're getting.
Note
Maturity. Every one of the 54 packages is 1.x and follows full semver β
@zuke/core, the @zuke/cli command, and all the tool wrappers. A minor or
patch release never breaks a public symbol; a breaking change bumps the major.
See Versioning & compatibility for the pinning
guidance and how to diagnose a version mismatch.
Zuke lets you define builds as a TypeScript class. Each target is a class
field declared with a fluent API; targets reference each other by this.x (not
strings), forming a dependency graph that Zuke resolves and runs in topological
order. Inspired by NUKE for .NET.
- Runtime: Deno
- Packages:
jsr:@zuke/coreplus 50+ typed tool wrappers and plugins and a genericjsr:@zuke/cmdfallback (raw shell viajsr:@zuke/core/shell) β see Packages for the full matrix with published versions - Build file:
zuke.tsin your project root - Zero runtime dependencies
class MyBuild extends Build {
compile = target()
.dependsOn(this.clean, this.restore)
.executes(async () => {
await DenoTasks.check((s) => s.paths("mod.ts"));
});
}- Typed, refactor-safe dependencies. You wire targets together with
this.clean, not"clean". Rename a target and every reference moves with it; a typo is a compile error, not a runtime surprise. - Just TypeScript. Your build logic is ordinary async functions with full editor support β no YAML, no bespoke DSL.
- Ergonomic shell. The
$tagged template runs processes with sane defaults (throw on failure, capture output) and is injection-safe. - Small and explicit. A tiny core: discover targets, build a graph, sort, run. No magic, and no plugins to learn for a basic build β the plugin contract is there once you want one.
- Code-first CI. Declare your pipeline in the build with
cicd({ provider: "github" })β the provider is the only required field β and Zuke generates GitHub Actions, GitLab CI, or Azure Pipelines YAML, regenerating it whenever the build runs (and verifying it on CI).
See How Zuke compares for a capability-by-capability
matrix against deno task, npm scripts, Make, Nx, Turborepo, and Dagger, on the
capabilities Zuke was built to provide.
You need Deno installed. The fastest start is the
@zuke/cli tool β install it once, then scaffold a starter zuke.ts, the
./zuke launchers, and a deno.json task into any directory:
deno install -A -g -n zuke jsr:@zuke/cli # once
zuke setup # in your project
./zuke # run the buildSee Getting started for the full walkthrough
(scaffolding, the ./zuke launcher, a first build, and GitHub Actions output).
The Zuke Build action on the Marketplace is the whole prelude a Zuke job needs β it hardens the runner, checks the repository out, optionally installs Deno, and runs a target, in one step:
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: zuke-build/zuke@v1
with:
target: ciIt goes first, before any checkout of your own: a remote action is fetched by the runner, not from your workspace, which is what lets it install an egress policy before the code that policy governs is ever fetched.
| Input | Default | What it does |
|---|---|---|
target |
"" |
The Zuke target to run. Omit to harden and check out only. |
egress-policy |
audit |
audit records outbound traffic; block enforces allowed-endpoints. |
allowed-endpoints |
"" |
Space-separated host:port list permitted under block. |
persist-credentials |
false |
Leave the token in git config, for a job that pushes. |
fetch-depth |
1 |
Commits to fetch. 0 is the full history, which a secret scan needs. |
ref |
"" |
Branch, tag or SHA to check out. Refused on a secret-bearing event β see below. |
deno-version |
"" |
Install this Deno. Usually unnecessary β the ./zuke launcher bootstraps its own. |
Two things worth knowing before you rely on it:
egress-policystarts ataudit, notblockβ the opposite of harden-runner's own default. That is deliberate, sinceblockwith an empty allowlist fails a build on its first outbound request, but it means the default records egress rather than enforcing it. Run once onaudit, take the endpoint list from the run's insights, then set both.refis refused on an event whose content a contributor writes βpull_request_target,issue_comment,workflow_runand the rest. Those run with your secrets and a writable token, so checking out a ref someone else controls hands them both.pull_requestandpushare unaffected.
Pin the full commit SHA rather than the moving v1 tag when you commit it, the
way you would any other action:
- uses: zuke-build/zuke@<40-character-sha> # v1.0.2The action section covers the rest. Zuke's own six workflows all open with it, generated from the build β so the version documented here is the version this repository runs on itself.
Note
All packages publish to JSR from CI via release-please
and OIDC (see RELEASING.md). The npm scope @zuke is not
controlled by this project β install from JSR, not npm.
Zuke ships as a JSR workspace: a tiny core plus a typed wrapper per tool. Every package is versioned and published independently β the badges below track the latest release on JSR.
Looking for the exact API (humans and agents)? Don't guess and don't shell out β every tool is a typed wrapper. The complete, typed surface of every package is in
llms-full.txt(one file), summarised inllms.txt; for a single package rundeno doc jsr:@zuke/<package>. See alsoAGENTS.md.
| Package | Version |
|---|---|
@zuke/core |
|
@zuke/cli |
|
@zuke/cmd |
|
@zuke/deno |
|
@zuke/docs |
|
@zuke/npm |
|
@zuke/security |
|
@zuke/ai |
|
@zuke/console |
|
@zuke/otel |
All tool wrappers (45 packages)
Zuke ships typed wrappers for the major AI coding CLIs, so you can fold a model into a build the same way you'd run a linter or a test β as a typed target with refactor-safe dependencies.
| Package | CLI | Flagship task |
|---|---|---|
@zuke/claude |
Claude Code (claude) |
run (headless --print) |
@zuke/codex |
OpenAI Codex (codex) |
exec (headless) |
@zuke/gemini |
Gemini CLI (gemini) |
run (headless --prompt) |
Each runs the CLI non-interactively so it fits CI: drive a prompt, pick a
model, constrain the tool set, and capture the response (request JSON for
machine-readable output). Arguments stay a discrete argv array end-to-end β
never a concatenated shell string β so command construction is injection-free,
and API keys ride through the shared .env(...) chainer, backed by a
parameter().secret() build input that Zuke masks in CI output.
import { Build, parameter, target } from "jsr:@zuke/core";
import { ClaudeTasks } from "jsr:@zuke/claude";
class MyBuild extends Build {
apiKey = parameter("Anthropic API key").secret();
review = target()
.dependsOn(this.test)
.executes(async () => {
const out = await ClaudeTasks.run((s) =>
s.prompt("Review the staged diff for bugs in one paragraph")
.model("sonnet")
.allowedTools("Read", "Grep")
.outputFormat("json")
.env({ ANTHROPIC_API_KEY: this.apiKey.value })
);
console.log(out.stdout);
});
}The mcp (and config/extensions) tasks are flexible command builders for
each CLI's matching subcommand group β handy for provisioning MCP servers in CI.
See Tools for the full task matrix.
Beyond driving the coding CLIs, @zuke/ai makes a
model a first-class citizen of the build graph, two ways:
- AI code review β a reviewer reads the diff, returns a structured assessment (score, severity, findings), writes it to the job summary and the pull request, and breaks the build when the risk crosses a threshold you choose. The output is a typed verdict, not a blob of prose.
- Self-healing builds β attach a fixer to any target with
.recoverWith(...). When the target fails,aiFixerdiagnoses it from the error output and the diff and (diagnose-only default) posts a committable, Copilot-style inline suggestion to the PR. Opt into.autoApply()/.commitFixes()and it fixes the working tree, commits, and re-runs the real command to verify β a fix only counts when the build actually goes green β posting an overview of what it changed instead of a suggestion. - Agent delegation β for open-ended fixes,
agentFixerhands the failure to a coding agent you inject (Claude Code, Codex, Gemini CLI) which edits files itself; one generic fixer, agent chosen at the call site. - Cost controls β a shared
budget(...)caps spend across every reviewer and fixer by an exact token count (no stale price tables; a USD cap is opt-in with your own rates),aiCache(...)reuses a prior response for an identical call, andsuppressions(...)lets you dismiss a false positive by its stable ID so it never fails the build again.
test = target()
.executes(() => DenoTasks.test((s) => s.allowAll()))
// On failure: diagnose, post a committable suggestion, optionally heal.
.recoverWith(aiFixer((f) => f.provider("openai").apiKey(this.key)));Apply a fixer to every target by overriding recoverWith() on the build.
Safe by default (provider + key only): the fixer writes no files and just
diagnoses. Edits are gated behind a path allowlist, a file cap, and local-only
defaults, and nothing is committed unless you ask. See
AI code review and
Self-healing builds.
Zuke ships agent skills so AI coding assistants set up and author builds the
right way β using the typed *Tasks wrappers instead of guessing the API or
shelling out. Two skills, authored once as portable
SKILL.md folders under skills/:
| Skill | Use it to |
|---|---|
zuke-setup |
Scaffold Zuke into a project (zuke setup, the ./zuke launcher, a first build). |
zuke-write-build |
Write or edit a zuke.ts β add targets, wire dependencies, call tool wrappers, generate CI. |
The skills are packaged as a Claude Code plugin distributed from this repo's marketplace. In Claude Code:
/plugin marketplace add zuke-build/zuke
/plugin install zuke@zuke
That makes zuke-setup and zuke-write-build available β they trigger
automatically when you ask Claude to add Zuke to a project or write a build, and
can be invoked explicitly as /zuke:zuke-setup and /zuke:zuke-write-build.
The
SKILL.mdcontent is harness-agnostic (the open Agent Skills standard); the Claude marketplace is just one adapter over the sharedskills/source. Installation for other harnesses (Codex, OpenCode, β¦) is coming later.
Full documentation lives in docs/:
- Getting started β install, scaffold, the launcher, and a first build.
- Core concepts β the build/target/graph model and execution semantics.
- Parameters β typed build inputs from flags and env
vars (
parameter(),this.x.value). - Authoring API β
target(),Build,run(), code-first CI generation (cicd()), and gotchas. - Run context & cancellation β the
TargetContexta body receives (runId,signal,state) and cancelling a run. - Secrets β source secret values from a manager with
.from(...), with guaranteed redaction from every output. - Service targets β
service()for long-lived processes (a dev server, a database) kept running while dependents execute. - Caching β the incremental build cache
(
.inputs()/.outputs()) and the AI response cache (aiCache). - Durable run state β persist a run's status and per-target
metadata to a pluggable store (
StateStore,ctx.state), with an HTTP API for hosting a production backend. - Cross-run locks β
.lock()claims an exclusive resource across runs and machines, with a TTL backstop and typedLockConflictErrors. - Orchestration: waits β
.waitsFor()suspends a run until an external signal or predicate, saving its state to be resumed later. - Build registry β
zuke registercatalogs a build for dynamic, agentic discovery by an MCP server. - Console output β
@zuke/console: the levelled logger, markup, boxes/tables/rules, and the renderer behind Zuke's own build log. - Shell wrapper (
$) β ergonomic, injection-safe process execution. - Paths (
absolutePath) β the fluent path type. - Tools β the typed tool-wrapper packages and their tasks.
- Installing tools β fetch pinned,
checksum-verified CLIs with
installRelease()andtoolchain(). - Extending Zuke β the plugin contract: lifecycle plugins, tool wrappers, and reusable target bundles.
- Observability (OpenTelemetry) β
@zuke/otelexports run and target spans plus counters as OTLP/HTTP JSON. - MCP server β
./zuke mcpexposes the build to AI agents as typed tools over the Model Context Protocol. - AI code review β gate the build on a structured LLM
assessment of the diff (
@zuke/ai). - Self-healing builds β diagnose and fix failing
targets with
recoverWithandaiFixer, including Copilot-style suggestions. - Using Zuke in a Node/npm project β drive a Node build with Deno.
- Scheduled runs β
triggers.schedule({ cron, tz }) compiled to UTC cron with a daylight-saving wall-clock guard. - CLI reference β commands and flags.
- Programmatic API β drive Zuke from your own code.
- Versioning & compatibility β core semver vs. 0.x
wrappers, the
@zuke/corefloor, and pinning guidance. - How Zuke compares β a capability matrix against
deno task, npm scripts, Make, Nx, Turborepo, and Dagger, on the capabilities Zuke provides.
deno task test # run the suite
deno task cov # run with coverage + enforce the 95% gate
deno task cov:report # print a per-file coverage table
deno task check # type-check
deno task fmt # format (fmt:check to verify only)
deno task lint # lint
deno task spell # spell-check (cspell)
deno task ci # the full gate β deno run -A zuke.ts cideno task ci is ./zuke ci, the same gate the quality job in
.github/workflows/ci.yml runs on every push and
pull request β see AGENTS.md for the full check list.
Contributions are welcome! Start with CONTRIBUTING.md for
the full workflow, and please be mindful of our
Code of Conduct.
- Read
CLAUDE.mdfor the coding standards (strict typing, noany/as, 95%+ coverage, hermetic tests). - Run
deno task cibefore opening a PR β it must be green. - Add tests in the same change as the code they cover.
- Keep commits small and descriptive; update docs when behaviour changes.
As a build tool that runs in other people's pipelines, Zuke treats supply-chain
integrity as a first-class concern: zero runtime dependencies, injection-free
Deno.Command execution, OIDC trusted publishing with provenance,
least-privilege and SHA-pinned CI, a frozen lockfile, and continuous scanning.
Scanning runs as a typed Zuke target β deno task zuke security drives zizmor,
actionlint, and gitleaks through @zuke/security (which
also wraps osv-scanner, semgrep, and Trivy) β alongside CodeQL and OpenSSF
Scorecard for the Security tab.
See SECURITY.md for the full posture and how to report a
vulnerability.
MIT β see LICENSE.
Zuke stands on the shoulders of giants:
- NUKE and its creator Matthias Koch β the code-first, strongly-typed build model that inspired Zuke. If you build for .NET, use NUKE; Zuke is an homage to its ideas in the Deno/TypeScript world.
- Spectre.Console and its creator
Patrik Svensson β the .NET console
library whose markup, themes, and rich widgets (rules, panels, tables)
inspired the output model of
@zuke/console. - Deno β the runtime and toolchain (test runner, formatter, linter, type-checker, coverage) that makes a zero-dependency, hermetic build tool possible.
- JSR β modern, TypeScript-native package distribution.
- Every author of the tools Zuke wraps β Docker, Kubernetes, Terraform, Vite, Playwright, and the rest of the matrix above.
Questions, ideas, or just want to say hi? Open an issue, or reach out:
If Zuke is useful to you, consider starring the repo β it helps others find the project. β