Build automation · Deno & TypeScript

Builds you can refactor, not just run.

Zuke /zuːk/ is a code-first, strongly-typed build system. Define targets as TypeScript class fields, wire dependencies with a fluent API, and let Zuke resolve and run them in topological order. The same file generates your CI YAML and is served to AI agents as typed tools — with zero runtime dependencies.

Install the CLI
$deno install -A -g -n zuke jsr:@zuke/cli$zuke setup$./zuke$./zuke generate-ci
import { Build, cicd, run, target } from "jsr:@zuke/core";
import { DenoTasks } from "jsr:@zuke/deno";

class MyBuild extends Build {
  // declare a pipeline → generates .github/workflows
  ci = cicd({ provider: "github" });

  clean = target().executes(() => Deno.remove("dist", { recursive: true }));
  restore = target().executes(() => DenoTasks.cache((s) => s.paths("mod.ts")));

  compile = target()
    .description("Type-check & bundle")
    .dependsOn(this.clean, this.restore)
    .executes(async () => {
      await DenoTasks.check((s) => s.paths("mod.ts"));
    });
}

await run(MyBuild);
Deno-native Zero runtime deps Published on JSR Inspired by NUKE for .NET The Z stands for Zero YAML
Who’s using Zuke

Shipping production deployments.

Using Zuke at your company? Tell us and we’ll add you here.

Why Zuke

Everything a build needs — typed end to end.

6the model

  • Typed, refactor-safe dependencies Targets reference each other with this.target — not strings. Rename one and every reference updates.
  • Just TypeScript Ordinary async functions with full types, editor support, and debugging. No YAML, no bespoke DSL.
  • Automatic topological order Declare what each target dependsOn; Zuke resolves the graph and runs everything in order, exactly once.
  • Zero runtime dependencies Ships on Deno with nothing else to install. The launcher installs Deno for you on first run.
  • Extensible by design Extend ToolSettings to build your own typed wrapper for any tool — no fork required.
  • Starts from what you have zuke import reads your package.json scripts or Makefile and writes a target per task — && chains become steps, run delegations become dependsOn.

6run & orchestrate

  • Long-lived service targets Declare a dev server or database with service(); Zuke starts it, waits until ready, and stops it in a finally.
  • Ergonomic, safe shell The $ tagged template runs processes with sane defaults and escapes interpolations to prevent injection.
  • Incremental, remote & parallel Fingerprint .inputs()/.outputs() to skip unchanged work, share a remote cache, and run targets concurrently.
  • Hermetic, pinned toolchains Fetch the CLIs a build drives, pinned by SHA-256, verified and cached — a bare CI runner is reproducible.
  • Drops into Node monorepos Resolves node_modules/.bin npx-style, provisions npm-registry tools with toolchain().npm(), and runs npm workspaces — no npx, no global installs.
  • Secrets, sourced & redacted Pull a secret from 1Password, Vault, or gcloud with .from(execSecret(…)); Zuke redacts it from every log.

5ship & automate

  • Code-first CI/CD Declare pipelines with cicd() and generate GitHub, GitLab, Azure, or Bitbucket YAML — verified up to date on every run.
  • A typed tool ecosystem Strongly-typed wrappers for 58+ tools — Deno, npm, Docker, Kubernetes, Vite and more, all on JSR.
  • Announce to chat Post build status to Slack, Teams, and Discord from a target — typed messages with levels, fields, and links.
  • Pins that can't quietly rot zuke outdated reads the lock — not the import map — so an inline jsr: specifier several minors behind is named, and --exit-code gates on it.
  • A supply chain you can verify Every package publishes to JSR over OIDC trusted publishing — no long-lived registry token exists — and JSR records a Sigstore provenance attestation naming the workflow and commit that built the version.

5ai in the loop

  • AI in your pipeline Typed wrappers for Claude Code, Codex, and Gemini CLI run headless in CI, injection-free.
  • AI code-review gate A model reads the diff, returns a structured risk score, and breaks the build when it crosses your threshold.
  • Findings you can argue with The reviewer refutes its own weak findings, then adjudicates rebuttals from trusted reviewers on the PR — and remembers what it dismissed.
  • Self-healing builds Attach a fixer with .recoverWith(); @zuke/ai diagnoses a failure and can apply, commit, and re-run to verify.
  • Agent skills on every harness zuke-setup and zuke-write-build install from the repo's skills marketplace into Claude Code, OpenAI Codex, and the Gemini CLI alike.
Topological resolution

Declare dependencies.
Zuke figures out the order.

Each target lists what it dependsOn. Zuke builds the dependency graph, runs independent targets as far as it can, and executes everything exactly once in the correct order.

  • References are real values — this.build, never a string.
  • Per-target status, timing, and a final build summary.
  • Rename a target and every dependant updates automatically.
  • Incremental caching skips a target whose .inputs() are unchanged — reported cached, with dependents still running.
  • zuke graph --output=html renders an interactive graph you can pan, zoom, and click to trace dependencies.

↓ The graph that builds this website. See Zuke's own build graph rendered to HTML.

Code-first CI/CD

Never write CI YAML again.

For a small project the YAML hurts more than the build. Declare the pipeline in the build with one line, and Zuke writes the workflow file, keeps it in sync on every run, and fails CI the moment the committed copy drifts. The targets you push are the targets you just ran locally.

zuke.ts
import { Build, cicd, run, target } from "jsr:@zuke/core";
import { DenoTasks } from "jsr:@zuke/deno";

class MyBuild extends Build {
  // one line → .github/workflows/ci.yml, one job per target
  ci = cicd({ provider: "github", fanOut: true });

  lint = target().executes(() => DenoTasks.lint());

  test = target()
    .dependsOn(this.lint)
    .executes(() => DenoTasks.test((s) => s.allowAll()));
}

await run(MyBuild);
.github/workflows/ci.yml generated
name: CI
"on":
  push:
    branches: [main]
  pull_request:
    branches: [main]
permissions:
  contents: read
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: zuke-build/zuke@7a62523b… # v1.0.1
      - run: ./zuke lint
  test:
    runs-on: ubuntu-latest
    needs: [lint]          # ← from .dependsOn(this.lint)
    steps:
      - uses: zuke-build/zuke@7a62523b… # v1.0.1
      - run: ./zuke test
  • One declaration, four providers — the same cicd() emits GitHub Actions, GitLab CI, Azure Pipelines, or Bitbucket Pipelines. The provider is the only required field.
  • fanOut: true turns every target into its own job, wired with needs: edges that mirror dependsOn — independent targets run in parallel on the provider.
  • Verified, not just generated — every run regenerates the file; on CI it verifies instead and fails on drift, so the YAML can never disagree with the build.
  • Run it before you push./zuke ci is the pipeline. There is no second definition to keep aligned by hand.
Targets GitHub Actions GitLab CI Azure Pipelines Bitbucket
Read the CI generation guide →
shell
# write every declared pipeline file
./zuke generate-ci

# the CI gate: fail if the committed YAML drifted
./zuke generate-ci --check

# the same targets, locally, before you push
./zuke test
Readable output

A build log you can actually scan.

Every target is framed with a ruled banner and closes with a plain pass/fail line and its duration. The run ends with an aligned Build Summary — status and timing per target, a total, and a one-line verdict stamped with the time. It's all powered by @zuke/console, and the same primitives are yours to call in any target.

  • Blocks are easy to scan; a failure prints its error inline.
  • The summary table totals the wall-clock time across targets.
  • @zuke/console gives you tag-based [bold]/[green] markup plus rules, boxes, and tables — a levelled logger for your own output.
  • GitHub Actions gets matching groups, annotations, and a job-summary table.
zuke build
$ ./zuke build

══════════════════════════════
build
══════════════════════════════
  ▸ astro build — 4 pages in 2.2s
 build succeeded in 2.2s

Build Summary
────────────────────────────
Target   Status     Duration
────────────────────────────
clean    Succeeded      0.1s
install  Succeeded     12.4s
check    Succeeded      3.1s
build    Succeeded      2.2s
────────────────────────────
Total                  17.8s

✔ Build succeeded — 4/4 targets in 17.8s · 2026-06-23 07:19

Compose the same output in your own targets

Import @zuke/console and reach for rules, colored markup, boxes, and tables directly — the exact primitives the runner uses for its banners and summary. Read the Console output guide →

zuke.ts
import { ConsoleTasks as Log } from "jsr:@zuke/console";

Log.rule("Release");
Log.info("pushing [bold]core@1.2.0[/]");        // markup: [tag]…[/]
Log.success("[green]✔[/] published 4 packages");
Log.warn("coverage [yellow]94.2%[/] — below gate");

Log.box(["core  1.2.0  ✔", "cli   1.2.0  ✔"], {
  title: "Artifacts",
  border: ["green"],
});

Log.table(
  [{ header: "Package" }, { header: "Size", align: "right" }],
  [["@zuke/core", "18 kB"], ["@zuke/cli", "12 kB"]],
);
output
────────────── Release ──────────────
 pushing core@1.2.0
 published 4 packages
 coverage 94.2% — below gate

Artifacts  core  1.2.0  
  cli   1.2.0  

Package      Size
─────────────────
@zuke/core   18 kB
@zuke/cli    12 kB
shell.ts
// The $ tagged template runs processes safely — no shell injection.
const sha = await $`git rev-parse HEAD`.text();   // trimmed stdout
await $`deno test -A`;                              // throws on non-zero
const code = await $`flaky-cmd`.noThrow().code();   // never throws
The $ shell

Run processes without the footguns.

The $ tagged template from @zuke/core/shell turns every interpolation into a discrete argv entry — no shell is involved at all, so there is nothing for an untrusted value to break out of. Chain .text(), .code(), or .noThrow() for exactly the behaviour you want.

Read the shell guide →
Caching & distributed builds New

Build it once. Reuse it everywhere.

Zuke fingerprints a target's .inputs() and skips it when nothing changed. A remote cache takes that across machines — a fresh checkout or a CI job restores a target's built outputs from a shared store instead of rebuilding them — and --affected narrows a run to just what a change can reach.

  • Incremental, locally.inputs()/.outputs() are fingerprinted; an unchanged target is skipped and shown cached.
  • Remote cache — on a local miss, restore a target's outputs from a shared store instead of rebuilding; upload after a green run so the next machine reuses them.
  • Two backends — a mounted directory or any HTTP object store (S3/GCS/R2), via a typed remoteCache() override or ZUKE_REMOTE_CACHE_* in CI.
  • --affected runs only the targets a git diff can reach, and fanOut emits one parallel CI job per target — the monorepo combo.
Cache backends Filesystem HTTP S3 / GCS / R2
Read the caching guide →
zuke.ts
import { Build, HttpCacheStore, cicd, target } from "jsr:@zuke/core";
import { DenoTasks } from "jsr:@zuke/deno";

class CI extends Build {
  // Restore built outputs on a local miss; upload
  // after a green run so the next job reuses them.
  override remoteCache() {
    return new HttpCacheStore({
      url: this.cacheUrl.value,
      token: this.token.value,
    });
  }

  build = target()
    .inputs("src", "deno.json")   // fingerprint → cache key
    .outputs("dist")              // archived to the store
    .executes(() => DenoTasks.run((s) => s.script("build.ts")));

  // One CI job per target, wired by dependsOn —
  // independent jobs run in parallel.
  ci = cicd({ provider: "github", fanOut: true });
}
remote cache
build · machine A bundled dist/ — uploaded after a green run
Remote store · cache.example.com build @ a3f9c21
build · CI job (fresh checkout) restored dist/cached in 0.0s, no rebuild
AI code review New

A reviewer that argues its case.

@zuke/ai attaches an AI reviewer to a target as a validation. It reads the diff, asks the model for a structured risk assessment, and breaks the build when the score crosses your threshold — a real verdict your pipeline can branch on, not a blob of prose. And because a gate is only worth having if its findings are, the reviewer refutes what it can't defend and talks the rest through with your team.

  • .verify() attacks its own findings — a second pass refutes any whose failure path it can't concretely trace.
  • .discussion() reads the PR thread — quote a finding's ID to contest it and the reviewer upholds it or dismisses it on the merits, then remembers the dismissal.
  • .fileContext() and .conventionsFile() judge whole files against your rules — not lone hunks against generic taste.
  • Security, secrets, correctness, licensing, or code quality — built-in rubrics, tunable with .criteria().
  • .comment() posts the verdict to the PR/MR — GitHub, GitLab, Azure & Bitbucket — and aiReviewWorkflow() generates the CI workflow for every host.
Works with Claude OpenAI Gemini
Comments & workflows for GitHub GitLab Azure Bitbucket
Read the AI review guide →
🛡 securityReviewer ✘ Build blocked
8/10
HIGH risk score · threshold 7
  • HIGH Hard-coded API token in src/config.ts:42 a1b2c3d4
  • MED Open redirect in routes/login.ts e5f6a7b8dismissed
  • LOW Stack trace leaked in error response c9d0e1f2refuted

verification refuted 1 candidate — no traceable failure path

maintainer e5f6a7b8 — that target is allow-listed in config.ts.

🤖 Zuke AI review Dismissed e5f6a7b8 — the allow-list covers every branch into the redirect. Won't be re-raised.

via @zuke/ai · claude-opus-4-8 · verify + discussion · tokens: 1234 in · 567 out · 1801 total

Self-healing builds New

When a build breaks, Zuke fixes it.

Attach a fixer to any target with .recoverWith(aiFixer(…)). When the target fails, @zuke/ai diagnoses it from the exact command, its stderr, and the diff, then proposes a fix — or applies one. The real build command is the verifier: a fix only counts when the command actually goes green.

  • Diagnose-only by default — posts a committable, Copilot-style suggestion to the PR, anchored to the exact file:line.
  • .autoApply() heals it — writes the fix, commits, and re-runs the real command; a bad edit fails the build instead of landing.
  • Safe by default — no files written until you opt in; edits gated behind a path allowlist, a file cap, and local-only defaults.
  • agentFixer hands open-ended failures to a coding agent you inject — Claude Code, Codex, or Gemini CLI — that edits files itself.
Heals with Claude OpenAI Gemini
Read the self-healing guide →
recoverWith · aiFixer
  1. test failed TypeError: name is undefined — src/format.ts:18
  2. aiFixer diagnosing command + stderr + diff → model
  3. fix: guard the null user in formatName() applied · committed a3f9c21
  4. re-running deno test to verify the real command is the gate
  5. healed — 12/12 passing in 1.9s a fix only counts when the build goes green
🤖 Zuke AI fix src/format.ts · line 18
- return user.name.toUpperCase();
+ return (user?.name ?? "anon").toUpperCase();
Suggested change Commit suggestion
zuke.ts
import { Build, parameter, run, target } from "jsr:@zuke/core";
import { DenoTasks } from "jsr:@zuke/deno";
import { aiFixer } from "jsr:@zuke/ai";

class CI extends Build {
  key = parameter("OpenAI API key").secret().required();

  test = target()
    .executes(() => DenoTasks.test((s) => s.allowAll()))
    // On failure: diagnose from the error + diff, post a committable
    // suggestion — or apply, commit, and re-run to verify it goes green.
    .recoverWith(
      aiFixer((f) =>
        f.provider("openai").apiKey(this.key)
          .autoApply()                 // write the fix to the working tree
          .allowPaths("src/**")        // blast-radius allowlist
          .maxEdits(5)                 // …and a file cap
          .commitFixes()               // stage, commit & push to the PR branch
      ),
    )
    .recoverAttempts(2);               // up to two fix-then-rerun cycles
}

await run(CI);

One primitive powers it: a Remediation runs only after a target body fails. Attach a fixer per target, or override recoverWith() on the build to heal every target at once.

MCP server New

Hand your build to an agent.

zuke mcp runs a Model Context Protocol server over your build, so an AI client discovers typed tools — list the targets, inspect the graph, run one with the right parameters — and operates the pipeline through real calls instead of guessing shell commands. Read-only by default; --allow-run opts into execution.

  • Read tools, always onlist_targets, describe_build, and graph expose the whole build surface: the live counterpart of llms.txt.
  • run:<target> with --allow-run — one run tool per target, its input schema derived from your declared parameters (required, enum, number) plus a dryRun flag.
  • Safe by default — execution is off until you opt in; run tools carry MCP's destructiveHint so clients prompt, and .secret() values stay redacted in what the agent sees.
  • Registered by the scaffolderzuke setup --mcp writes the .mcp.json Claude Code, Codex and other stdio clients read, so a new project is agent-ready before its first commit.
  • Knows who is callingmcpAuth() turns a bearer token or a proxy header into a typed identity, and the ordered roles read < run < operator decide each call. A target's requiresRole() is enforced across the whole plan it would run, never just the entry point.
  • Dependency-free — newline-delimited JSON-RPC 2.0, implemented by hand with no MCP SDK. Stdio by default; --http <host:port> serves the same server over streamable HTTP, advertising where to authenticate via OAuth protected-resource metadata.
Works with Claude Desktop Claude Code IDEs Any agent
Read the MCP guide →
shell
# scaffold a build that is agent-ready from day one:
# writes .mcp.json registering the build's server
zuke setup --mcp

# read-only: an agent inspects the build, never runs it
zuke mcp

# also expose run:<target> tools that execute targets
zuke mcp --allow-run

# or register by hand with any MCP client (Claude Code shown)
claude mcp add zuke -- deno run -A zuke.ts mcp
zuke · mcp — tools
  • list_targets targets, descriptions & deps read
  • describe_build the full build surface read
  • graph target → deps read
  • run:test executes the target · --allow-run ⚡ run
tools/call { "name": "run:test", "arguments": { "environment": "dev" } }
install the skills
# Claude Code
/plugin marketplace add zuke-build/zuke
/plugin install zuke@zuke

# OpenAI Codex
codex plugin marketplace add zuke-build/zuke
codex plugin add zuke@zuke

# Gemini CLI
gemini extensions install https://github.com/zuke-build/zuke
Agent skills New

Skills your agent installs from a marketplace.

Two agent skills — zuke-setup scaffolds Zuke into a project, zuke-write-build writes or edits a zuke.ts — teach an assistant to author builds with the typed API instead of guessing. Authored once as portable SKILL.md folders, they're distributed from the repo's own skills marketplace, which installs into Claude Code, OpenAI Codex, and the Gemini CLI alike.

Installs into Claude Code OpenAI Codex Gemini CLI
Read the agent-skills guide →
Built for continuous delivery

A cross-run layer for real deployments.

Durable state, external-event waits, cross-run locks, batch fan-out, cancellation, and governed agent access — the orchestration Zuke layers on top of the typed DAG. All backed by a pluggable state store, with zero overhead until you reach for it.

Durable & resumable

Pipelines that outlive the process.

A target can suspend on an external event — deploy, then wait days for manual approval. The run parks in the state store and the process exits 0; a later zuke resume continues it in a fresh process, exactly once. State persists across the gap, so promoteToProd reads what deployToSit left behind.

  • .waitsFor(externalSignal(…)) suspends; zuke resume <id> --signal continues it.
  • A racing resumer gets a clean AlreadyResumedError — safe to drive from a retrying cron.
  • zuke runs list / show <id> reconstruct a run's full status from the store alone.
Read the orchestration guide →
zuke.ts
awaitTesting = target()
  .dependsOn(this.deployToSit)
  .waitsFor((s) =>
    s.on(externalSignal("testing-approved"))
      .timeout("72h")
      .onTimeout(() => this.rollback));

promoteToProd = target()
  .dependsOn(this.awaitTesting)
  .executes((ctx) => {
    // resumes in a fresh process, days later —
    // the approval payload survived the wait
    promote(ctx.signals.get("testing-approved")?.data);
  });
deploy → wait → promote
$ ./zuke promoteToProd --repo api
 deployToSit   succeeded
 awaitTesting  waiting — signal: testing-approved
  run 6f1c9a suspended · exit 0

$ zuke resume 6f1c9a --signal testing-approved
 promoteToProd succeeded — shipped to prod
zuke.ts
promoteToProd = target()
  // one deploy of a repo at a time — across runs, across machines
  .lock((s) =>
    s.lockKey("deploy", this.repo.value).withTtl("4h")
      .onConflict((h) => `held by ${h.actor}, run ${h.runId}`))
  .executes((ctx) => applyToProd(this.repo.value, ctx))
  .onCancel(() => this.rollback);   // undone in reverse order on cancel
conflict & rollback
$ ./zuke promoteToProd --repo api
 promoteToProd lock conflict
  held by alice, run 6f1c9a since 09:14
  wait, or: zuke cancel 6f1c9a

$ zuke cancel 6f1c9a
 rollback compensated — sit-7 torn down
 run cancelled · lock released
Safe by construction

Serialize deploys. Undo cleanly.

A .lock() claims a resource across runs, processes, and machines — one deploy of a repo at a time. The loser fails fast with the holder's identity and guidance, not a corrupt double-deploy. And .onCancel() registers the inverse of a target, so zuke cancel (or Ctrl-C, or a timed-out wait) unwinds succeeded work in reverse order — reading the exact state each step recorded.

  • TTL + auto-renew: a live holder keeps its lock; a kill -9 frees it after the TTL.
  • Locks release in a finally — success, failure, and cancellation all let go.
  • Compensations run maximally: one that throws is recorded, the rest still run.
Read the locks guide →
Fan-out

One list. N deploys. Honest per-item status.

.forEach() runs the same ordered pipeline over a runtime list — items concurrent, stages sequential per item, with a bounded concurrency. One repo failing doesn't stop the others; the batch fails at the end if any item did. Every item is first-class: deployBatch[api].deploy gets its own summary row and run-record entry, so zuke runs show and MCP report a verdict per repo.

  • Per-item isolation with continueOnItemFailure — no more all-or-nothing batches.
  • The list is an .array() parameter, validated element-by-element before anything runs.
  • The end of JSON-array-in-a-text-field: typed, checked, reportable inputs.
Read the fan-out guide →
zuke.ts
deployBatch = target().forEach(
  () => this.repos.value,          // a validated runtime list
  (repo) => ({                     // an ordered pipeline per repo
    checks: target().executes(() => check(repo)),
    deploy: target().executes((c) => applyToSit(repo, c)),
  }),
  { concurrency: 3, continueOnItemFailure: true },
);
zuke deployBatch
$ ./zuke deployBatch --repos api,web,worker
 deployBatch[api]     succeeded
 deployBatch[web]     failed — checks
 deployBatch[worker]  succeeded
────────────────────────────
 deployBatch — 1/3 items failed
shell
# governed, auditable agent access over authenticated HTTP
zuke mcp --http 0.0.0.0:7777 \
  --allow-run --protect promoteToProd --confirm-destructive

# one server over the whole catalog —
# pipelines registered later appear with no restart
zuke mcp --registry --allow-run
zuke runs show mcp-audit
tool                actor    outcome
───────────────────────────────────
run:deployBatch     alice    ok
signal_run          bob      ok
run:promoteToProd   carol    denied
  reason: operator token required
Governed agent operations

Hand CD to an agent — with a paper trail.

The MCP server grows a streamable-HTTP transport and three authorization tiers: an allow-list of runnable targets, an operator token for protected ones, and a confirm step for destructive calls. Authenticate the callers and it goes further — per-caller roles decide each call, and an agent can intervene on a live run: signal it, cancel it, or settle one target it must not execute. Every mutating call is attributed in an audit log. A build registry makes it fleet-wide — one server over a catalog of pipelines that picks up newly-registered builds with no restart.

  • --allow-run=deploy,checks*, --protect promoteToProd, --confirm-destructive.
  • Loopback by default; a non-loopback bind requires a bearer token.
  • Roles read < run < operator, or your own IdP group names — and a run stays steerable by its initiator.
  • force_target (zuke force) settles a step that cannot succeed, or one a person did by hand — refused on anything the build declared unforceable().
  • zuke register + zuke mcp --registry — new pipelines become callable tools live.
Security posture

Every feature ships attacked.

Zuke runs inside your pipeline with your credentials in scope, and publishes 58 packages to a public registry. That makes security a gate on the way in rather than a page in the docs: no feature is finalized until a review pass has actively tried to break it, and periodic independent assessments re-check the whole surface for what a feature-level pass cannot see.

Adversarial review · every feature

A green gate is the floor, not the bar.

Once the implementation and its tests pass, a separate pass tries to break the change — bypasses, leaks, race conditions, unhandled throws, untested security branches. Independent reviewers attack each dimension, and every candidate finding is reproduced against the real code path, defaulting to refuted when the reproduction fails. What survives is a list of defects, not of suspicions. Anything confirmed is fixed before the pull request opens, each with a regression test that keeps it fixed.

  • Standing on every PR, between the dedicated reviews: an AI security assessment on the thread, CodeQL over both the sources and the workflow YAML, and the scanner gate — zizmor, actionlint, gitleaks.
  • A moved trust boundary — a new transport, credential, or privilege — triggers a fresh dedicated review in the same change that moves it.
  • Least privilege by default — fork pull requests run without secrets, every action is pinned to a commit SHA, and egress is blocked to an allowlist on any job holding a write-scoped token.
The @zuke ecosystem · 58 packages

Typed wrappers for the tools you already use.

Every wrapper is a fluent, strongly-typed API over a real CLI — published to JSR, tree-shakeable, and refactor-safe. And if one's missing, you can write your own.

Runtimes & package managers

7

Install, run, and publish across every major JS toolchain.

Bundlers & monorepo

6

Bundle apps and orchestrate monorepos from a typed pipeline.

TypeScript runners & compilers

3

Execute, type-check, and compile TypeScript with or without a build step.

Frameworks & code generation

5

Scaffold app frameworks and generate typed clients from a schema.

AI coding, review & self-healing

5

Fold the major AI coding CLIs into a build, gate it on a model-assessed review, or let a fixer heal failures.

Lint, format & quality

9

Keep the tree clean with linters, formatters, and dead-code checks.

Test, coverage & browsers

5

Run unit and end-to-end suites, then upload coverage to your dashboard.

Containers & orchestration

5

Build images and ship to clusters from a typed pipeline.

Cloud & infrastructure

3

Provision and deploy with infra-as-code, typed end to end.

Version control, registry & CI

5

Script Git, GitHub, and publishing straight from your build.

Supply-chain security

1

Scan workflows, secrets, and dependencies as part of the gate.

Engine & plugins

5

The first-party packages that aren't CLI wrappers — the build engine, the global CLI, the process layer, the console, and the OpenTelemetry plugin.

Zuke swag New

Wear the build.

The Zuke swag shop is open — Zuke-branded apparel and accessories for everyone who would rather write a typed build than one more YAML file.

Visit the shop →

Ship your first typed build in minutes.

Install the CLI, scaffold a zuke.ts, and run your first target. Already have package.json scripts or a Makefile? Swap zuke setup for zuke import and start from a target per task instead of a blank page.

$deno install -A -g -n zuke jsr:@zuke/cli$zuke setup$./zuke --list