{
  "markdown": "<picture>\n  <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://github.com/zuke-build/zuke/raw/master/assets/logo-white.png\" />\n  <img width=\"400px\" alt=\"Zuke\" src=\"https://github.com/zuke-build/zuke/raw/master/assets/logo.png\" />\n</picture>\n\n> A code-first, strongly-typed build automation system for Deno & TypeScript.\n\n<p align=\"center\">\n  <a href=\"https://github.com/zuke-build/zuke/actions/workflows/ci.yml\"><img alt=\"CI\" src=\"https://github.com/zuke-build/zuke/actions/workflows/ci.yml/badge.svg\" /></a>\n  <a href=\"https://github.com/zuke-build/zuke/actions/workflows/release.yml\"><img alt=\"Release\" src=\"https://github.com/zuke-build/zuke/actions/workflows/release.yml/badge.svg\" /></a>\n  <a href=\"https://codecov.io/gh/zuke-build/zuke\"><img alt=\"Coverage\" src=\"https://codecov.io/gh/zuke-build/zuke/branch/master/graph/badge.svg\" /></a>\n  <a href=\"https://scorecard.dev/viewer/?uri=github.com/zuke-build/zuke\"><img alt=\"OpenSSF Scorecard\" src=\"https://api.scorecard.dev/projects/github.com/zuke-build/zuke/badge\" /></a>\n  <a href=\"https://www.bestpractices.dev/projects/14036\"><img alt=\"OpenSSF Best Practices\" src=\"https://www.bestpractices.dev/projects/14036/badge\" /></a>\n  <a href=\"https://github.com/marketplace/actions/zuke-build\"><img alt=\"GitHub Marketplace\" src=\"https://img.shields.io/github/v/release/zuke-build/zuke?filter=%21%2A-%2A&amp;label=Marketplace&amp;logo=github&amp;color=2ea44f\" /></a>\n  <a href=\"https://jsr.io/@zuke/core\"><img alt=\"JSR\" src=\"https://jsr.io/badges/@zuke/core\" /></a>\n  <a href=\"https://jsr.io/@zuke/core\"><img alt=\"JSR score\" src=\"https://jsr.io/badges/@zuke/core/score\" /></a>\n  <a href=\"./LICENSE\"><img alt=\"License: MIT\" src=\"https://img.shields.io/badge/license-MIT-yellow.svg\" /></a>\n  <a href=\"https://deno.com/\"><img alt=\"Built for Deno\" src=\"https://img.shields.io/badge/Deno-2.x-000?logo=deno&logoColor=white\" /></a>\n</p>\n\n<p align=\"center\">\n  <img src=\"https://github.com/zuke-build/zuke/raw/master/assets/demo.svg\" alt=\"Zuke in action: scaffold a build, list targets, run the gate\" width=\"760\" />\n</p>\n\n> [!NOTE]\n> **Built with AI.** Much of Zuke — code, tests, and docs — was written with AI\n> assistance, then reviewed, type-checked, and tested in CI. Sharing how it was\n> made so you know what you're getting.\n\n> [!NOTE]\n> **Maturity.** Every one of the 54 packages is `1.x` and follows full semver —\n> `@zuke/core`, the `@zuke/cli` command, and all the tool wrappers. A minor or\n> patch release never breaks a public symbol; a breaking change bumps the major.\n> See [Versioning & compatibility](./docs/versioning.md) for the pinning\n> guidance and how to diagnose a version mismatch.\n\nZuke lets you define builds as a **TypeScript class**. Each target is a class\nfield declared with a fluent API; targets reference each other by `this.x` (not\nstrings), forming a dependency graph that Zuke resolves and runs in topological\norder. Inspired by [NUKE](https://nuke.build/) for .NET. Zuke builds itself this\nway — see [its own build graph](./docs/graph.md), regenerated straight from\n`zuke.ts` and verified in CI.\n\n- **Runtime:** Deno\n- **Packages:** `jsr:@zuke/core` plus 50+ typed tool wrappers and plugins and a\n  generic `jsr:@zuke/cmd` fallback (raw shell via `jsr:@zuke/core/shell`) — see\n  [Packages](#packages) for the full matrix with published versions\n- **Build file:** `zuke.ts` in your project root\n- **Zero runtime dependencies**\n\n```ts\nclass MyBuild extends Build {\n  compile = target()\n    .dependsOn(this.clean, this.restore)\n    .executes(async () => {\n      await DenoTasks.check((s) => s.paths(\"mod.ts\"));\n    });\n}\n```\n\n## Why Zuke\n\n- **Typed, refactor-safe dependencies.** You wire targets together with\n  `this.clean`, not `\"clean\"`. Rename a target and every reference moves with\n  it; a typo is a compile error, not a runtime surprise.\n- **Just TypeScript.** Your build logic is ordinary async functions with full\n  editor support — no YAML, no bespoke DSL.\n- **Ergonomic shell.** The `$` tagged template runs processes with sane defaults\n  (throw on failure, capture output) and is injection-safe.\n- **Small and explicit.** A tiny core: discover targets, build a graph, sort,\n  run. No magic, and no plugins to learn for a basic build — the\n  [plugin contract](./docs/extending.md) is there once you want one.\n- **Code-first CI.** Declare your pipeline in the build with\n  `cicd({ provider: \"github\" })` — the provider is the only required field — and\n  Zuke generates GitHub Actions, GitLab CI, or Azure Pipelines YAML,\n  regenerating it whenever the build runs (and verifying it on CI).\n\nSee **[How Zuke compares](./docs/comparison.md)** for a capability-by-capability\nmatrix against `deno task`, npm scripts, Make, Nx, Turborepo, and Dagger, on the\ncapabilities Zuke was built to provide.\n\n## Who's using Zuke\n\nTeams running Zuke in production:\n\n<a href=\"https://payhawk.com\">\n  <picture>\n    <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://github.com/zuke-build/zuke/raw/master/assets/users/payhawk-white.svg\" />\n    <img width=\"170px\" alt=\"Payhawk\" src=\"https://github.com/zuke-build/zuke/raw/master/assets/users/payhawk.svg\" />\n  </picture>\n</a>\n\n> Using Zuke at your company? We'd love to list you — open a pull request adding\n> your logo to `assets/users/` and an entry to this section, or say hello in an\n> [issue](https://github.com/zuke-build/zuke/issues) and we'll add it for you.\n\n## Install\n\nYou need [Deno](https://deno.com/) installed. The fastest start is the\n`@zuke/cli` tool — install it once, then scaffold a starter `zuke.ts`, the\n`./zuke` launchers, and a `deno.json` task into any directory:\n\n```sh\ndeno install -A -g -n zuke jsr:@zuke/cli   # once\nzuke setup                                 # in your project\n./zuke                                     # run the build\n```\n\nSee **[Getting started](./docs/getting-started.md)** for the full walkthrough\n(scaffolding, the `./zuke` launcher, a first build, and GitHub Actions output).\n\n## GitHub Actions\n\nThe [**Zuke Build**](https://github.com/marketplace/actions/zuke-build) action\non the Marketplace is the whole prelude a Zuke job needs — it hardens the\nrunner, checks the repository out, optionally installs Deno, and runs a target,\nin one step:\n\n```yaml\njobs:\n  ci:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: zuke-build/zuke@v1\n        with:\n          target: ci\n```\n\nIt goes **first**, before any checkout of your own: a remote action is fetched\nby the runner, not from your workspace, which is what lets it install an egress\npolicy before the code that policy governs is ever fetched.\n\n| Input                 | Default | What it does                                                                       |\n| --------------------- | ------- | ---------------------------------------------------------------------------------- |\n| `target`              | `\"\"`    | The Zuke target to run. Omit to harden and check out only.                         |\n| `egress-policy`       | `audit` | `audit` records outbound traffic; `block` enforces `allowed-endpoints`.            |\n| `allowed-endpoints`   | `\"\"`    | Space-separated `host:port` list permitted under `block`.                          |\n| `persist-credentials` | `false` | Leave the token in git config, for a job that pushes.                              |\n| `fetch-depth`         | `1`     | Commits to fetch. `0` is the full history, which a secret scan needs.              |\n| `ref`                 | `\"\"`    | Branch, tag or SHA to check out. Refused on a secret-bearing event — see below.    |\n| `deno-version`        | `\"\"`    | Install this Deno. Usually unnecessary — the `./zuke` launcher bootstraps its own. |\n\nTwo things worth knowing before you rely on it:\n\n- **`egress-policy` starts at `audit`, not `block`** — the opposite of\n  harden-runner's own default. That is deliberate, since `block` with an empty\n  allowlist fails a build on its first outbound request, but it means the\n  default **records** egress rather than enforcing it. Run once on `audit`, take\n  the endpoint list from the run's insights, then set both.\n- **`ref` is refused on an event whose content a contributor writes** —\n  `pull_request_target`, `issue_comment`, `workflow_run` and the rest. Those run\n  with your secrets and a writable token, so checking out a ref someone else\n  controls hands them both. `pull_request` and `push` are unaffected.\n\nPin the full commit SHA rather than the moving `v1` tag when you commit it, the\nway you would any other action:\n\n```yaml\n- uses: zuke-build/zuke@<40-character-sha> # v1.0.2\n```\n\n[The action section](./docs/getting-started.md#the-zuke-buildzuke-action) covers\nthe rest. Zuke's own six workflows all open with it, generated from the build —\nso the version documented here is the version this repository runs on itself.\n\n> [!NOTE]\n> All packages publish to [JSR](https://jsr.io/@zuke) from CI via release-please\n> and OIDC (see [`RELEASING.md`](./RELEASING.md)). The npm scope `@zuke` is not\n> controlled by this project — install from JSR, not npm.\n\n## Packages\n\nZuke ships as a JSR workspace: a tiny core plus a typed wrapper per tool. Every\npackage is versioned and published independently — the badges below track the\nlatest release on JSR.\n\n> **Looking for the exact API (humans and agents)?** Don't guess and don't shell\n> out — every tool is a typed wrapper. The complete, typed surface of every\n> package is in [`llms-full.txt`](./llms-full.txt) (one file), summarised in\n> [`llms.txt`](./llms.txt); for a single package run\n> `deno doc jsr:@zuke/<package>`. See also [`AGENTS.md`](./AGENTS.md).\n\n| Package                                           | Version                                                                                                                                                                 |\n| ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| [`@zuke/core`](https://jsr.io/@zuke/core)         | [![JSR](https://jsr.io/badges/@zuke/core)](https://jsr.io/@zuke/core) [![JSR score](https://jsr.io/badges/@zuke/core/score)](https://jsr.io/@zuke/core)                 |\n| [`@zuke/cli`](https://jsr.io/@zuke/cli)           | [![JSR](https://jsr.io/badges/@zuke/cli)](https://jsr.io/@zuke/cli) [![JSR score](https://jsr.io/badges/@zuke/cli/score)](https://jsr.io/@zuke/cli)                     |\n| [`@zuke/cmd`](https://jsr.io/@zuke/cmd)           | [![JSR](https://jsr.io/badges/@zuke/cmd)](https://jsr.io/@zuke/cmd) [![JSR score](https://jsr.io/badges/@zuke/cmd/score)](https://jsr.io/@zuke/cmd)                     |\n| [`@zuke/deno`](https://jsr.io/@zuke/deno)         | [![JSR](https://jsr.io/badges/@zuke/deno)](https://jsr.io/@zuke/deno) [![JSR score](https://jsr.io/badges/@zuke/deno/score)](https://jsr.io/@zuke/deno)                 |\n| [`@zuke/docs`](https://jsr.io/@zuke/docs)         | [![JSR](https://jsr.io/badges/@zuke/docs)](https://jsr.io/@zuke/docs) [![JSR score](https://jsr.io/badges/@zuke/docs/score)](https://jsr.io/@zuke/docs)                 |\n| [`@zuke/npm`](https://jsr.io/@zuke/npm)           | [![JSR](https://jsr.io/badges/@zuke/npm)](https://jsr.io/@zuke/npm) [![JSR score](https://jsr.io/badges/@zuke/npm/score)](https://jsr.io/@zuke/npm)                     |\n| [`@zuke/security`](https://jsr.io/@zuke/security) | [![JSR](https://jsr.io/badges/@zuke/security)](https://jsr.io/@zuke/security) [![JSR score](https://jsr.io/badges/@zuke/security/score)](https://jsr.io/@zuke/security) |\n| [`@zuke/ai`](https://jsr.io/@zuke/ai)             | [![JSR](https://jsr.io/badges/@zuke/ai)](https://jsr.io/@zuke/ai) [![JSR score](https://jsr.io/badges/@zuke/ai/score)](https://jsr.io/@zuke/ai)                         |\n| [`@zuke/console`](https://jsr.io/@zuke/console)   | [![JSR](https://jsr.io/badges/@zuke/console)](https://jsr.io/@zuke/console) [![JSR score](https://jsr.io/badges/@zuke/console/score)](https://jsr.io/@zuke/console)     |\n| [`@zuke/otel`](https://jsr.io/@zuke/otel)         | [![JSR](https://jsr.io/badges/@zuke/otel)](https://jsr.io/@zuke/otel) [![JSR score](https://jsr.io/badges/@zuke/otel/score)](https://jsr.io/@zuke/otel)                 |\n\n<details>\n<summary><strong>All tool wrappers</strong> (44 packages)</summary>\n\n| Package                                                       | Version                                                                                                                                                                                         |\n| ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| [`@zuke/biome`](https://jsr.io/@zuke/biome)                   | [![JSR](https://jsr.io/badges/@zuke/biome)](https://jsr.io/@zuke/biome) [![JSR score](https://jsr.io/badges/@zuke/biome/score)](https://jsr.io/@zuke/biome)                                     |\n| [`@zuke/bun`](https://jsr.io/@zuke/bun)                       | [![JSR](https://jsr.io/badges/@zuke/bun)](https://jsr.io/@zuke/bun) [![JSR score](https://jsr.io/badges/@zuke/bun/score)](https://jsr.io/@zuke/bun)                                             |\n| [`@zuke/cypress`](https://jsr.io/@zuke/cypress)               | [![JSR](https://jsr.io/badges/@zuke/cypress)](https://jsr.io/@zuke/cypress) [![JSR score](https://jsr.io/badges/@zuke/cypress/score)](https://jsr.io/@zuke/cypress)                             |\n| [`@zuke/cspell`](https://jsr.io/@zuke/cspell)                 | [![JSR](https://jsr.io/badges/@zuke/cspell)](https://jsr.io/@zuke/cspell) [![JSR score](https://jsr.io/badges/@zuke/cspell/score)](https://jsr.io/@zuke/cspell)                                 |\n| [`@zuke/docker`](https://jsr.io/@zuke/docker)                 | [![JSR](https://jsr.io/badges/@zuke/docker)](https://jsr.io/@zuke/docker) [![JSR score](https://jsr.io/badges/@zuke/docker/score)](https://jsr.io/@zuke/docker)                                 |\n| [`@zuke/docker-compose`](https://jsr.io/@zuke/docker-compose) | [![JSR](https://jsr.io/badges/@zuke/docker-compose)](https://jsr.io/@zuke/docker-compose) [![JSR score](https://jsr.io/badges/@zuke/docker-compose/score)](https://jsr.io/@zuke/docker-compose) |\n| [`@zuke/dpdm`](https://jsr.io/@zuke/dpdm)                     | [![JSR](https://jsr.io/badges/@zuke/dpdm)](https://jsr.io/@zuke/dpdm) [![JSR score](https://jsr.io/badges/@zuke/dpdm/score)](https://jsr.io/@zuke/dpdm)                                         |\n| [`@zuke/dprint`](https://jsr.io/@zuke/dprint)                 | [![JSR](https://jsr.io/badges/@zuke/dprint)](https://jsr.io/@zuke/dprint) [![JSR score](https://jsr.io/badges/@zuke/dprint/score)](https://jsr.io/@zuke/dprint)                                 |\n| [`@zuke/eslint`](https://jsr.io/@zuke/eslint)                 | [![JSR](https://jsr.io/badges/@zuke/eslint)](https://jsr.io/@zuke/eslint) [![JSR score](https://jsr.io/badges/@zuke/eslint/score)](https://jsr.io/@zuke/eslint)                                 |\n| [`@zuke/gcloud`](https://jsr.io/@zuke/gcloud)                 | [![JSR](https://jsr.io/badges/@zuke/gcloud)](https://jsr.io/@zuke/gcloud) [![JSR score](https://jsr.io/badges/@zuke/gcloud/score)](https://jsr.io/@zuke/gcloud)                                 |\n| [`@zuke/gh`](https://jsr.io/@zuke/gh)                         | [![JSR](https://jsr.io/badges/@zuke/gh)](https://jsr.io/@zuke/gh) [![JSR score](https://jsr.io/badges/@zuke/gh/score)](https://jsr.io/@zuke/gh)                                                 |\n| [`@zuke/codecov`](https://jsr.io/@zuke/codecov)               | [![JSR](https://jsr.io/badges/@zuke/codecov)](https://jsr.io/@zuke/codecov) [![JSR score](https://jsr.io/badges/@zuke/codecov/score)](https://jsr.io/@zuke/codecov)                             |\n| [`@zuke/claude`](https://jsr.io/@zuke/claude)                 | [![JSR](https://jsr.io/badges/@zuke/claude)](https://jsr.io/@zuke/claude) [![JSR score](https://jsr.io/badges/@zuke/claude/score)](https://jsr.io/@zuke/claude)                                 |\n| [`@zuke/codex`](https://jsr.io/@zuke/codex)                   | [![JSR](https://jsr.io/badges/@zuke/codex)](https://jsr.io/@zuke/codex) [![JSR score](https://jsr.io/badges/@zuke/codex/score)](https://jsr.io/@zuke/codex)                                     |\n| [`@zuke/gemini`](https://jsr.io/@zuke/gemini)                 | [![JSR](https://jsr.io/badges/@zuke/gemini)](https://jsr.io/@zuke/gemini) [![JSR score](https://jsr.io/badges/@zuke/gemini/score)](https://jsr.io/@zuke/gemini)                                 |\n| [`@zuke/git`](https://jsr.io/@zuke/git)                       | [![JSR](https://jsr.io/badges/@zuke/git)](https://jsr.io/@zuke/git) [![JSR score](https://jsr.io/badges/@zuke/git/score)](https://jsr.io/@zuke/git)                                             |\n| [`@zuke/helm`](https://jsr.io/@zuke/helm)                     | [![JSR](https://jsr.io/badges/@zuke/helm)](https://jsr.io/@zuke/helm) [![JSR score](https://jsr.io/badges/@zuke/helm/score)](https://jsr.io/@zuke/helm)                                         |\n| [`@zuke/husky`](https://jsr.io/@zuke/husky)                   | [![JSR](https://jsr.io/badges/@zuke/husky)](https://jsr.io/@zuke/husky) [![JSR score](https://jsr.io/badges/@zuke/husky/score)](https://jsr.io/@zuke/husky)                                     |\n| [`@zuke/jest`](https://jsr.io/@zuke/jest)                     | [![JSR](https://jsr.io/badges/@zuke/jest)](https://jsr.io/@zuke/jest) [![JSR score](https://jsr.io/badges/@zuke/jest/score)](https://jsr.io/@zuke/jest)                                         |\n| [`@zuke/jsr`](https://jsr.io/@zuke/jsr)                       | [![JSR](https://jsr.io/badges/@zuke/jsr)](https://jsr.io/@zuke/jsr) [![JSR score](https://jsr.io/badges/@zuke/jsr/score)](https://jsr.io/@zuke/jsr)                                             |\n| [`@zuke/knip`](https://jsr.io/@zuke/knip)                     | [![JSR](https://jsr.io/badges/@zuke/knip)](https://jsr.io/@zuke/knip) [![JSR score](https://jsr.io/badges/@zuke/knip/score)](https://jsr.io/@zuke/knip)                                         |\n| [`@zuke/kubectl`](https://jsr.io/@zuke/kubectl)               | [![JSR](https://jsr.io/badges/@zuke/kubectl)](https://jsr.io/@zuke/kubectl) [![JSR score](https://jsr.io/badges/@zuke/kubectl/score)](https://jsr.io/@zuke/kubectl)                             |\n| [`@zuke/kustomize`](https://jsr.io/@zuke/kustomize)           | [![JSR](https://jsr.io/badges/@zuke/kustomize)](https://jsr.io/@zuke/kustomize) [![JSR score](https://jsr.io/badges/@zuke/kustomize/score)](https://jsr.io/@zuke/kustomize)                     |\n| [`@zuke/lint-staged`](https://jsr.io/@zuke/lint-staged)       | [![JSR](https://jsr.io/badges/@zuke/lint-staged)](https://jsr.io/@zuke/lint-staged) [![JSR score](https://jsr.io/badges/@zuke/lint-staged/score)](https://jsr.io/@zuke/lint-staged)             |\n| [`@zuke/nest`](https://jsr.io/@zuke/nest)                     | [![JSR](https://jsr.io/badges/@zuke/nest)](https://jsr.io/@zuke/nest) [![JSR score](https://jsr.io/badges/@zuke/nest/score)](https://jsr.io/@zuke/nest)                                         |\n| [`@zuke/node`](https://jsr.io/@zuke/node)                     | [![JSR](https://jsr.io/badges/@zuke/node)](https://jsr.io/@zuke/node) [![JSR score](https://jsr.io/badges/@zuke/node/score)](https://jsr.io/@zuke/node)                                         |\n| [`@zuke/npx`](https://jsr.io/@zuke/npx)                       | [![JSR](https://jsr.io/badges/@zuke/npx)](https://jsr.io/@zuke/npx) [![JSR score](https://jsr.io/badges/@zuke/npx/score)](https://jsr.io/@zuke/npx)                                             |\n| [`@zuke/nx`](https://jsr.io/@zuke/nx)                         | [![JSR](https://jsr.io/badges/@zuke/nx)](https://jsr.io/@zuke/nx) [![JSR score](https://jsr.io/badges/@zuke/nx/score)](https://jsr.io/@zuke/nx)                                                 |\n| [`@zuke/openapi-ts`](https://jsr.io/@zuke/openapi-ts)         | [![JSR](https://jsr.io/badges/@zuke/openapi-ts)](https://jsr.io/@zuke/openapi-ts) [![JSR score](https://jsr.io/badges/@zuke/openapi-ts/score)](https://jsr.io/@zuke/openapi-ts)                 |\n| [`@zuke/orval`](https://jsr.io/@zuke/orval)                   | [![JSR](https://jsr.io/badges/@zuke/orval)](https://jsr.io/@zuke/orval) [![JSR score](https://jsr.io/badges/@zuke/orval/score)](https://jsr.io/@zuke/orval)                                     |\n| [`@zuke/oxlint`](https://jsr.io/@zuke/oxlint)                 | [![JSR](https://jsr.io/badges/@zuke/oxlint)](https://jsr.io/@zuke/oxlint) [![JSR score](https://jsr.io/badges/@zuke/oxlint/score)](https://jsr.io/@zuke/oxlint)                                 |\n| [`@zuke/playwright`](https://jsr.io/@zuke/playwright)         | [![JSR](https://jsr.io/badges/@zuke/playwright)](https://jsr.io/@zuke/playwright) [![JSR score](https://jsr.io/badges/@zuke/playwright/score)](https://jsr.io/@zuke/playwright)                 |\n| [`@zuke/pnpm`](https://jsr.io/@zuke/pnpm)                     | [![JSR](https://jsr.io/badges/@zuke/pnpm)](https://jsr.io/@zuke/pnpm) [![JSR score](https://jsr.io/badges/@zuke/pnpm/score)](https://jsr.io/@zuke/pnpm)                                         |\n| [`@zuke/redocly`](https://jsr.io/@zuke/redocly)               | [![JSR](https://jsr.io/badges/@zuke/redocly)](https://jsr.io/@zuke/redocly) [![JSR score](https://jsr.io/badges/@zuke/redocly/score)](https://jsr.io/@zuke/redocly)                             |\n| [`@zuke/release-please`](https://jsr.io/@zuke/release-please) | [![JSR](https://jsr.io/badges/@zuke/release-please)](https://jsr.io/@zuke/release-please) [![JSR score](https://jsr.io/badges/@zuke/release-please/score)](https://jsr.io/@zuke/release-please) |\n| [`@zuke/shellcheck`](https://jsr.io/@zuke/shellcheck)         | [![JSR](https://jsr.io/badges/@zuke/shellcheck)](https://jsr.io/@zuke/shellcheck) [![JSR score](https://jsr.io/badges/@zuke/shellcheck/score)](https://jsr.io/@zuke/shellcheck)                 |\n| [`@zuke/storybook`](https://jsr.io/@zuke/storybook)           | [![JSR](https://jsr.io/badges/@zuke/storybook)](https://jsr.io/@zuke/storybook) [![JSR score](https://jsr.io/badges/@zuke/storybook/score)](https://jsr.io/@zuke/storybook)                     |\n| [`@zuke/terraform`](https://jsr.io/@zuke/terraform)           | [![JSR](https://jsr.io/badges/@zuke/terraform)](https://jsr.io/@zuke/terraform) [![JSR score](https://jsr.io/badges/@zuke/terraform/score)](https://jsr.io/@zuke/terraform)                     |\n| [`@zuke/tofu`](https://jsr.io/@zuke/tofu)                     | [![JSR](https://jsr.io/badges/@zuke/tofu)](https://jsr.io/@zuke/tofu) [![JSR score](https://jsr.io/badges/@zuke/tofu/score)](https://jsr.io/@zuke/tofu)                                         |\n| [`@zuke/tsc`](https://jsr.io/@zuke/tsc)                       | [![JSR](https://jsr.io/badges/@zuke/tsc)](https://jsr.io/@zuke/tsc) [![JSR score](https://jsr.io/badges/@zuke/tsc/score)](https://jsr.io/@zuke/tsc)                                             |\n| [`@zuke/tsc-alias`](https://jsr.io/@zuke/tsc-alias)           | [![JSR](https://jsr.io/badges/@zuke/tsc-alias)](https://jsr.io/@zuke/tsc-alias) [![JSR score](https://jsr.io/badges/@zuke/tsc-alias/score)](https://jsr.io/@zuke/tsc-alias)                     |\n| [`@zuke/tsdown`](https://jsr.io/@zuke/tsdown)                 | [![JSR](https://jsr.io/badges/@zuke/tsdown)](https://jsr.io/@zuke/tsdown) [![JSR score](https://jsr.io/badges/@zuke/tsdown/score)](https://jsr.io/@zuke/tsdown)                                 |\n| [`@zuke/tsup`](https://jsr.io/@zuke/tsup)                     | [![JSR](https://jsr.io/badges/@zuke/tsup)](https://jsr.io/@zuke/tsup) [![JSR score](https://jsr.io/badges/@zuke/tsup/score)](https://jsr.io/@zuke/tsup)                                         |\n| [`@zuke/tsx`](https://jsr.io/@zuke/tsx)                       | [![JSR](https://jsr.io/badges/@zuke/tsx)](https://jsr.io/@zuke/tsx) [![JSR score](https://jsr.io/badges/@zuke/tsx/score)](https://jsr.io/@zuke/tsx)                                             |\n| [`@zuke/turbo`](https://jsr.io/@zuke/turbo)                   | [![JSR](https://jsr.io/badges/@zuke/turbo)](https://jsr.io/@zuke/turbo) [![JSR score](https://jsr.io/badges/@zuke/turbo/score)](https://jsr.io/@zuke/turbo)                                     |\n| [`@zuke/vite`](https://jsr.io/@zuke/vite)                     | [![JSR](https://jsr.io/badges/@zuke/vite)](https://jsr.io/@zuke/vite) [![JSR score](https://jsr.io/badges/@zuke/vite/score)](https://jsr.io/@zuke/vite)                                         |\n| [`@zuke/vitest`](https://jsr.io/@zuke/vitest)                 | [![JSR](https://jsr.io/badges/@zuke/vitest)](https://jsr.io/@zuke/vitest) [![JSR score](https://jsr.io/badges/@zuke/vitest/score)](https://jsr.io/@zuke/vitest)                                 |\n| [`@zuke/yarn`](https://jsr.io/@zuke/yarn)                     | [![JSR](https://jsr.io/badges/@zuke/yarn)](https://jsr.io/@zuke/yarn) [![JSR score](https://jsr.io/badges/@zuke/yarn/score)](https://jsr.io/@zuke/yarn)                                         |\n\n</details>\n\n## AI in your pipeline\n\nZuke ships typed wrappers for the major AI coding CLIs, so you can fold a model\ninto a build the same way you'd run a linter or a test — as a typed target with\nrefactor-safe dependencies.\n\n| Package                                       | CLI                                                                   | Flagship task               |\n| --------------------------------------------- | --------------------------------------------------------------------- | --------------------------- |\n| [`@zuke/claude`](https://jsr.io/@zuke/claude) | [Claude Code](https://docs.claude.com/en/docs/claude-code) (`claude`) | `run` (headless `--print`)  |\n| [`@zuke/codex`](https://jsr.io/@zuke/codex)   | [OpenAI Codex](https://developers.openai.com/codex/cli) (`codex`)     | `exec` (headless)           |\n| [`@zuke/gemini`](https://jsr.io/@zuke/gemini) | [Gemini CLI](https://github.com/google-gemini/gemini-cli) (`gemini`)  | `run` (headless `--prompt`) |\n\nEach runs the CLI **non-interactively** so it fits CI: drive a prompt, pick a\nmodel, constrain the tool set, and capture the response (request JSON for\nmachine-readable output). Arguments stay a discrete argv array end-to-end —\nnever a concatenated shell string — so command construction is injection-free,\nand API keys ride through the shared `.env(...)` chainer, backed by a\n`parameter().secret()` build input that Zuke masks in CI output.\n\n```ts\nimport { Build, parameter, target } from \"jsr:@zuke/core\";\nimport { ClaudeTasks } from \"jsr:@zuke/claude\";\n\nclass MyBuild extends Build {\n  apiKey = parameter(\"Anthropic API key\").secret();\n\n  review = target()\n    .dependsOn(this.test)\n    .executes(async () => {\n      const out = await ClaudeTasks.run((s) =>\n        s.prompt(\"Review the staged diff for bugs in one paragraph\")\n          .model(\"sonnet\")\n          .allowedTools(\"Read\", \"Grep\")\n          .outputFormat(\"json\")\n          .env({ ANTHROPIC_API_KEY: this.apiKey.value })\n      );\n      console.log(out.stdout);\n    });\n}\n```\n\nThe `mcp` (and `config`/`extensions`) tasks are flexible command builders for\neach CLI's matching subcommand group — handy for provisioning MCP servers in CI.\nSee [Tools](./docs/tools.md) for the full task matrix.\n\n### AI review and self-healing (`@zuke/ai`)\n\nBeyond driving the coding CLIs, [`@zuke/ai`](https://jsr.io/@zuke/ai) makes a\nmodel a first-class citizen of the build graph, two ways:\n\n- **AI code review** — a reviewer reads the diff, returns a _structured_\n  assessment (score, severity, findings), writes it to the job summary and the\n  pull request, and **breaks the build** when the risk crosses a threshold you\n  choose. The output is a typed verdict, not a blob of prose.\n- **Self-healing builds** — attach a fixer to any target with\n  `.recoverWith(...)`. When the target fails, `aiFixer` diagnoses it from the\n  error output and the diff and (diagnose-only default) posts a **committable,\n  Copilot-style inline suggestion** to the PR. Opt into `.autoApply()` /\n  `.commitFixes()` and it fixes the working tree, commits, and **re-runs the\n  real command to verify** — a fix only counts when the build actually goes\n  green — posting an overview of what it changed instead of a suggestion.\n- **Agent delegation** — for open-ended fixes, `agentFixer` hands the failure to\n  a coding agent you inject (Claude Code, Codex, Gemini CLI) which edits files\n  itself; one generic fixer, agent chosen at the call site.\n- **Cost controls** — a shared `budget(...)` caps spend across every reviewer\n  and fixer by an exact **token** count (no stale price tables; a USD cap is\n  opt-in with your own rates), `aiCache(...)` reuses a prior response for an\n  identical call, and `suppressions(...)` lets you dismiss a false positive by\n  its stable ID so it never fails the build again.\n\n```ts\ntest = target()\n  .executes(() => DenoTasks.test((s) => s.allowAll()))\n  // On failure: diagnose, post a committable suggestion, optionally heal.\n  .recoverWith(aiFixer((f) => f.provider(\"openai\").apiKey(this.key)));\n```\n\nApply a fixer to **every** target by overriding `recoverWith()` on the build.\nSafe by default (provider + key only): the fixer writes no files and just\ndiagnoses. Edits are gated behind a path allowlist, a file cap, and local-only\ndefaults, and nothing is committed unless you ask. See\n[AI code review](./docs/ai-review.md) and\n[Self-healing builds](./docs/self-healing.md).\n\n## Agent skills\n\nZuke ships **agent skills** so AI coding assistants set up and author builds the\nright way — using the typed `*Tasks` wrappers instead of guessing the API or\nshelling out. Two skills, authored once as portable\n[`SKILL.md`](https://agentskills.io) folders under [`skills/`](./skills):\n\n| Skill              | Use it to                                                                                    |\n| ------------------ | -------------------------------------------------------------------------------------------- |\n| `zuke-setup`       | Scaffold Zuke into a project (`zuke setup`, the `./zuke` launcher, a first build).           |\n| `zuke-write-build` | Write or edit a `zuke.ts` — add targets, wire dependencies, call tool wrappers, generate CI. |\n\n### Claude Code\n\nThe skills are packaged as a Claude Code plugin distributed from this repo's\nmarketplace. In Claude Code:\n\n```text\n/plugin marketplace add zuke-build/zuke\n/plugin install zuke@zuke\n```\n\nThat makes `zuke-setup` and `zuke-write-build` available — they trigger\nautomatically when you ask Claude to add Zuke to a project or write a build, and\ncan be invoked explicitly as `/zuke:zuke-setup` and `/zuke:zuke-write-build`.\n\n### OpenAI Codex\n\nThe same plugin installs into Codex from this repo (it carries a Codex-native\n`.agents/plugins/marketplace.json` and `.codex-plugin/plugin.json` alongside the\nClaude manifests):\n\n```text\ncodex plugin marketplace add zuke-build/zuke\ncodex plugin add zuke@zuke\n```\n\nA single skill can also be pulled straight from the repo with Codex's built-in\ninstaller skill, e.g.\n`$skill-installer install https://github.com/zuke-build/zuke/tree/master/skills/zuke-write-build`.\n\n### Gemini CLI\n\nThe repo doubles as a Gemini CLI extension (the root `gemini-extension.json`;\nGemini auto-discovers the `skills/` folder next to it):\n\n```text\ngemini extensions install https://github.com/zuke-build/zuke\n```\n\nGemini installs a GitHub extension from the repo's **latest release**, so the\nextension tracks releases rather than `master`. Each release carries a minimal\nextension archive (the manifest plus `skills/`, attached by the `release`\ntarget), so the install downloads two skills, not the whole monorepo.\n\n> The `SKILL.md` content is harness-agnostic (the open\n> [Agent Skills](https://agentskills.io) standard); each manifest above is a\n> thin adapter over the shared [`skills/`](./skills) source, so every harness\n> serves the same two skills.\n\n## Documentation\n\nFull documentation lives in [`docs/`](./docs/):\n\n- [Getting started](./docs/getting-started.md) — install, scaffold, the\n  launcher, and a first build.\n- [Core concepts](./docs/concepts.md) — the build/target/graph model and\n  execution semantics.\n- [Zuke's build graph](./docs/graph.md) — the live dependency graph of `zuke.ts`\n  itself, generated by `./zuke graphDoc` and gate-checked in CI.\n- [Parameters](./docs/parameters.md) — typed build inputs from flags and env\n  vars (`parameter()`, `this.x.value`).\n- [Authoring API](./docs/authoring.md) — `target()`, `Build`, `run()`,\n  code-first CI generation (`cicd()`), and gotchas.\n- [Run context & cancellation](./docs/run-context.md) — the `TargetContext` a\n  body receives (`runId`, `signal`, `state`) and cancelling a run.\n- [Secrets](./docs/secrets.md) — source secret values from a manager with\n  `.from(...)`, with guaranteed redaction from every output.\n- [Service targets](./docs/services.md) — `service()` for long-lived processes\n  (a dev server, a database) kept running while dependents execute.\n- [Caching](./docs/caching.md) — the incremental build cache\n  (`.inputs()`/`.outputs()`) and the AI response cache (`aiCache`).\n- [Durable run state](./docs/state.md) — persist a run's status and per-target\n  metadata to a pluggable store (`StateStore`, `ctx.state`), with an\n  [HTTP API](./docs/state-api.md) for hosting a production backend.\n- [Cross-run locks](./docs/locks.md) — `.lock()` claims an exclusive resource\n  across runs and machines, with a TTL backstop and typed `LockConflictError`s.\n- [Orchestration: waits](./docs/orchestration.md) — `.waitsFor()` suspends a run\n  until an external signal or predicate, saving its state to be resumed later.\n- [Build registry](./docs/registry.md) — `zuke register` catalogs a build for\n  dynamic, agentic discovery by an MCP server.\n- [Console output](./docs/console.md) — `@zuke/console`: the levelled logger,\n  markup, boxes/tables/rules, and the renderer behind Zuke's own build log.\n- [Shell wrapper (`$`)](./docs/shell.md) — ergonomic, injection-safe process\n  execution.\n- [Paths (`absolutePath`)](./docs/paths.md) — the fluent path type.\n- [Tools](./docs/tools.md) — the typed tool-wrapper packages and their tasks.\n- [Installing tools](./docs/installing-tools.md) — fetch pinned,\n  checksum-verified CLIs with `installRelease()` and `toolchain()`.\n- [Extending Zuke](./docs/extending.md) — the plugin contract: lifecycle\n  plugins, tool wrappers, and reusable target bundles.\n- [Observability (OpenTelemetry)](./docs/observability.md) — `@zuke/otel`\n  exports run and target spans plus counters as OTLP/HTTP JSON.\n- [MCP server](./docs/mcp.md) — `./zuke mcp` exposes the build to AI agents as\n  typed tools over the Model Context Protocol.\n- [AI code review](./docs/ai-review.md) — gate the build on a structured LLM\n  assessment of the diff (`@zuke/ai`).\n- [Self-healing builds](./docs/self-healing.md) — diagnose and fix failing\n  targets with `recoverWith` and `aiFixer`, including Copilot-style suggestions.\n- [Using Zuke in a Node/npm project](./docs/node-projects.md) — drive a Node\n  build with Deno.\n- [Scheduled runs](./docs/schedules.md) — `triggers.schedule` (`{ cron, tz }`)\n  compiled to UTC cron with a daylight-saving wall-clock guard.\n- [CLI reference](./docs/cli.md) — commands and flags.\n- [Programmatic API](./docs/programmatic-api.md) — drive Zuke from your own\n  code.\n- [Versioning & compatibility](./docs/versioning.md) — one semver tier across\n  every package, the `@zuke/core` floor, and pinning guidance.\n- [How Zuke compares](./docs/comparison.md) — a capability matrix against\n  `deno task`, npm scripts, Make, Nx, Turborepo, and Dagger, on the capabilities\n  Zuke provides.\n\n## Development\n\n```sh\ndeno task test        # run the suite\ndeno task cov         # run with coverage + enforce the 95% gate\ndeno task cov:report  # print a per-file coverage table\ndeno task check       # type-check\ndeno task fmt         # format (fmt:check to verify only)\ndeno task lint        # lint\ndeno task spell       # spell-check (cspell)\ndeno task ci          # the full gate — deno run -A --frozen zuke.ts ci\n```\n\n`deno task ci` **is** `./zuke ci`, the same gate the `ci` job in\n[`.github/workflows/ci.yml`](.github/workflows/ci.yml) runs on every push and\npull request — see [`AGENTS.md`](./AGENTS.md#commands) for the full check list.\n\n## Contributing\n\nContributions are welcome! Start with [`CONTRIBUTING.md`](./CONTRIBUTING.md) for\nthe full workflow, and please be mindful of our\n[`Code of Conduct`](./CODE_OF_CONDUCT.md).\n\n- Read [`AGENTS.md`](AGENTS.md) for the coding standards (strict typing, no\n  `any`/`as`, 95%+ coverage, hermetic tests). `CLAUDE.md` is a one-line pointer\n  to it.\n- Run `deno task ci` before opening a PR — it must be green.\n- Add tests in the same change as the code they cover.\n- Keep commits small and descriptive; update docs when behaviour changes.\n\n## Security\n\nAs a build tool that runs in other people's pipelines, Zuke treats supply-chain\nintegrity as a first-class concern: zero runtime dependencies, injection-free\n`Deno.Command` execution, OIDC trusted publishing with provenance,\nleast-privilege and SHA-pinned CI, a frozen lockfile, and continuous scanning.\nScanning runs as a typed Zuke target — `deno task zuke\nsecurity` drives zizmor,\nactionlint, and gitleaks through [`@zuke/security`](./packages/security) (which\nalso wraps osv-scanner, semgrep, and Trivy) — alongside CodeQL and OpenSSF\nScorecard for the Security tab.\n\nSee [`SECURITY.md`](./SECURITY.md) for the full posture and how to report a\nvulnerability.\n\n## License\n\nMIT — see [`LICENSE`](LICENSE).\n\n## Acknowledgements\n\nZuke stands on the shoulders of giants:\n\n- **[NUKE](https://nuke.build/)** and its creator\n  **[Matthias Koch](https://github.com/matkoch)** — the code-first,\n  strongly-typed build model that inspired Zuke. If you build for .NET, use\n  NUKE; Zuke is an homage to its ideas in the Deno/TypeScript world.\n- **[Spectre.Console](https://spectreconsole.net/)** and its creator\n  **[Patrik Svensson](https://github.com/patriksvensson)** — the .NET console\n  library whose markup, themes, and rich widgets (rules, panels, tables)\n  inspired the output model of `@zuke/console`.\n- **[Deno](https://deno.com/)** — the runtime and toolchain (test runner,\n  formatter, linter, type-checker, coverage) that makes a zero-dependency,\n  hermetic build tool possible.\n- **[JSR](https://jsr.io/)** — modern, TypeScript-native package distribution.\n- Every author of the tools Zuke wraps — Docker, Kubernetes, Terraform, Vite,\n  Playwright, and the rest of the matrix above.\n\n## Community & contact\n\nQuestions, ideas, or just want to say hi? Open an\n[issue](https://github.com/zuke-build/zuke/issues), or reach out:\n\n<p align=\"center\">\n  <a href=\"https://zuke.build\"><img alt=\"Website\" src=\"https://img.shields.io/badge/Website-zuke.build-000000?style=for-the-badge&logo=googlechrome&logoColor=white\" /></a>\n  <a href=\"mailto:contact@zuke.build\"><img alt=\"Email\" src=\"https://img.shields.io/badge/email-contact@zuke.build-8B89CC?style=for-the-badge&logo=protonmail&logoColor=white\" /></a>\n  <a href=\"https://todorov.bg\"><img alt=\"Blog\" src=\"https://img.shields.io/badge/Blog-todorov.bg-000000?style=for-the-badge&logo=rss&logoColor=white\" /></a>\n  <a href=\"https://twitter.com/totollygeek\"><img alt=\"X\" src=\"https://img.shields.io/badge/@totollygeek-000000?style=for-the-badge&logo=x&logoColor=white\" /></a>\n  <a href=\"https://www.linkedin.com/in/totollygeek\"><img alt=\"LinkedIn\" src=\"https://custom-icon-badges.demolab.com/badge/totollygeek-0A66C2?style=for-the-badge&logo=linkedin-white&logoColor=white\" /></a>\n  <a href=\"https://infosec.exchange/@totollygeek\"><img alt=\"Mastodon\" src=\"https://img.shields.io/badge/@totollygeek-6364FF?style=for-the-badge&logo=mastodon&logoColor=white\" /></a>\n  <a href=\"https://www.threads.net/@totollygeek\"><img alt=\"Threads\" src=\"https://img.shields.io/badge/@totollygeek-000000?style=for-the-badge&logo=threads&logoColor=white\" /></a>\n  <a href=\"https://bsky.app/profile/totollygeek.com\"><img alt=\"Bluesky\" src=\"https://img.shields.io/badge/totollygeek.com-0285FF?style=for-the-badge&logo=bluesky&logoColor=white\" /></a>\n  <a href=\"https://linktr.ee/totollygeek\"><img alt=\"Linktree\" src=\"https://img.shields.io/badge/totollygeek-39E09B?style=for-the-badge&logo=linktree&logoColor=white\" /></a>\n</p>\n\n## Swag\n\nZuke has a swag shop! Grab some Zuke-branded apparel and accessories and wear\nthe build:\n\n<p align=\"center\">\n  <a href=\"https://totollyshop.myspreadshop.net/\"><img alt=\"Zuke swag shop\" src=\"https://img.shields.io/badge/Swag_shop-totollyshop.myspreadshop.net-F5A623?style=for-the-badge\" /></a>\n</p>\n\n👉 **<https://totollyshop.myspreadshop.net/>**\n\n## Activity\n\n[![Repobeats analytics](https://repobeats.axiom.co/api/embed/cfe0a93aaa851e719386dc9469ec91ee1b9cf0d0.svg \"Repobeats analytics image\")](https://github.com/zuke-build/zuke/pulse)\n\n### Star history\n\n[![RepoStars](https://repostars.dev/api/embed?repo=zuke-build%2Fzuke&theme=dark)](https://repostars.dev/?repos=zuke-build%2Fzuke&theme=dark)\n\nIf Zuke is useful to you, consider **starring the repo** — it helps others find\nthe project. ⭐\n\n### Contributors\n\n<a href=\"https://github.com/zuke-build/zuke/graphs/contributors\">\n  <img alt=\"Contributors\" src=\"https://contrib.rocks/image?repo=zuke-build/zuke\" />\n</a>\n",
  "bytes": 41624,
  "sha": "e932fa2ee9f2b4085b3a598dcd354ef058007e8a1bc14fd355d5018b5ebcf4ad",
  "repo_slug": "zuke-build/zuke",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/plg_zuke_build_zuke_2a4d13f0/readme"
}