# Zuke Setup

> Set up Zuke — a code-first, strongly-typed build automation system for Deno/TypeScript — in a project. Use when the user wants to add Zuke to a repo, scaffold a zuke.ts build file, install the Zuke CLI, or bootstrap the ./zuke launcher. After scaffolding, switch to the zuke-write-build skill to author targets.

- Skill: `zuke-build/zuke-setup` (Agent Skill)
- Install (CLI): `npx skillmds@latest add zuke-build/zuke-setup`
- Raw SKILL.md: https://api.skillmd.com/api/skills/zuke-build/zuke-setup/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: zuke-build (https://skillmd.com/u/zuke-build)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/zuke-build/zuke-setup

---


# Set up Zuke in a project

Zuke defines builds as a TypeScript class run on **Deno**. Each target is a
class field; targets reference each other by `this.<field>` (never strings).
Packages are imported from **JSR** (`jsr:@zuke/...`), not npm.

## The fast path: `zuke setup`

The `@zuke/cli` tool scaffolds everything. Install it once, then run `setup` in
the target project:

```sh
deno install -A -g -n zuke jsr:@zuke/cli   # once, globally
zuke setup                                  # in the project root
./zuke                                       # run the build
```

No global install? The same wizard runs directly:

```sh
deno run -A jsr:@zuke/cli setup
```

`setup` flags: `--dir <path>`, `--name <ClassName>`, `--force` (overwrite
existing files), `--yes` (non-interactive), `--bootstrap-deno` /
`--no-bootstrap-deno` (which launchers to write — see below; the wizard asks
when interactive, and `--yes` takes the default, bootstrap), `--mcp` (also write `.mcp.json`
registering the build's MCP server, so this agent — and any other stdio MCP
client — can list and run the targets through typed calls; `--allow-run`
registers it with execution enabled and implies `--mcp`), `--launcher-name
<name>` (write the launcher under a different name when a `zuke/` directory
already occupies it — a directory collision now fails with an actionable error
instead of silently skipping the launcher). With `--mcp`, an MCP client lists
and runs the targets through typed calls; without it, the build is still
discoverable through `./zuke --list --json`.

Running as an agent, always pass `--yes`: it skips every interactive question,
including the closing "star the Zuke repository?" prompt — that question is for
a human at a terminal, and an agent must never answer it (or star anything) on
the user's behalf.

To read a `@zuke/*` package's API without a Node repo's `@types/node` noise, run
`zuke doc <package>` (e.g. `zuke doc core`) — it runs `deno doc` in an isolated
directory.

### Migrating an existing project: `zuke import`

If the project already has `package.json` scripts or a `Makefile`, prefer
`zuke import` over `setup` — it reads them and generates a `zuke.ts` with a
target per task, a working starting point instead of a blank build:

```sh
zuke import                  # auto-detects package.json, then a Makefile
zuke import --from makefile   # or pin the source (package.json | makefile)
```

Each script/target becomes a `target()`; a command maps to `CmdTasks.exec(...)`
— a **placeholder**, not the destination: before accepting it, check the package
catalogue (`llms.txt`'s `## Packages` list, or the table in
[`zuke-write-build`'s cheatsheet](../zuke-write-build/references/cheatsheet.md))
for a `@zuke/<tool>` wrapper matching that command and replace the placeholder
with it — leaving `CmdTasks.exec` in place for a tool that has a typed wrapper
is a bug, not a shortcut. An `&&` chain becomes sequential steps, a
`run`/prerequisite delegation becomes `.dependsOn(...)`, and anything too
shell-specific to translate (pipes, redirects, env assignments) is preserved
behind a `// TODO` so the file still compiles. It scaffolds the launchers and
`deno.json` exactly like `setup`, and takes the same `--dir`, `--name`,
`--force`, `--yes`, `--bootstrap-deno` / `--no-bootstrap-deno`, `--mcp` and
`--allow-run` flags. Afterwards, use the **zuke-write-build** skill to
finish replacing any remaining generated `CmdTasks.exec` calls with typed
`*Tasks` wrappers.

### What `zuke setup` writes

- **`zuke.ts`** — a starter build class with a sample target and a `default`.
- **`./zuke`** + **`./zuke.ps1`** — launchers that locate the project and run
  `zuke.ts`. By default (`--bootstrap-deno`) they use the Deno on `PATH` and,
  when there is none, download the pinned release Zuke itself runs on, verify
  it against a per-platform SHA-256, and install it under `~/.deno` — never an
  install script, never an unverified binary — so a clone needs nothing
  installed first. With `--no-bootstrap-deno` they require Deno on `PATH` and
  exit with the install docs URL when it is missing, for a project that must
  never download a tool from its build entry point. Both pass `--frozen` once
  a `deno.lock` exists, so the first run writes the lockfile and every run
  after verifies it.
- **`deno.json`** — merged to add a `zuke` task, plus `fmt`/`lint`/`test` if
  absent. The merge is all-or-nothing: if a `zuke` task is already declared the
  file is left alone entirely, and an unparseable one is skipped with a notice.
- **`zuke.json`** — `{ "name": "..." }`, which marks the repo root.
- **`.gitignore`** — created or appended so `.zuke/` is ignored (the cache and
  durable run state live there); untouched if it already covers it.
- **`.mcp.json`** (with `--mcp`) — `mcpServers.zuke` launching
  `deno run -A zuke.ts mcp` (plus `--allow-run` when asked). Merged around any
  other servers already in the file; an existing `zuke` entry is kept unless
  `--force` is set.

## Running the build

```sh
./zuke                 # run the default target  (Windows: .\zuke.ps1)
./zuke <target>        # run a specific target
./zuke --list          # list every target
./zuke --list --json   # the whole build surface (commands, flags, targets) as JSON
./zuke <target> --dry-run   # print the plan without executing
```

The CLI is self-describing: `./zuke --help` prints the usage grammar plus the
build's live targets and parameters, so an agent discovers the real command
surface instead of guessing. For an AI client to operate the build through typed
calls, `zuke mcp` runs a Model Context Protocol server over it (register with
`claude mcp add zuke -- deno run -A zuke.ts mcp`; add `--allow-run` to let the
agent execute targets, not just inspect them).

If Deno is already installed you can also use `deno task zuke <target>` or
`deno run -A zuke.ts <target>`. The `-A` flag grants permissions, since targets
typically run processes and touch files. These are not quite equivalent to the
launcher: the scaffolded `zuke` task deliberately omits `--frozen`, so it may
heal a stale lockfile where `./zuke` would fail on it.

## Manual setup (no CLI)

Create `zuke.ts` in the project root, extend `Build`, declare targets with
`target()`, and call `await run(MyBuild)` at the bottom:

<!-- check -->

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

class CI extends Build {
  lint = target().executes(() => DenoTasks.lint());
  test = target().dependsOn(this.lint)
    .executes(() => DenoTasks.test((s) => s.allowAll()));
  default = target().dependsOn(this.test).executes(() => {});
}

await run(CI);
```

Run with `deno run -A zuke.ts test`. (For the `./zuke` launcher experience,
prefer `zuke setup`, which drops the launcher scripts in for you.)

## Finding the exact API — never guess

Every external tool has a typed `*Tasks` wrapper; **do not fall back to
`Deno.Command` or hand-rolled shell.** First confirm a wrapper exists at all —
`llms.txt`'s `## Packages` catalogue or the table in
[`zuke-write-build`'s cheatsheet](../zuke-write-build/references/cheatsheet.md)
is the only way to answer that; a per-package `deno doc` needs a name to target,
so it cannot reveal that one exists. Once you know the package name, get its
exact signatures:

- A single package on the command line: `deno doc jsr:@zuke/<package>`. Prefer
  this in a consumer repo — it resolves the version the project actually has
  installed, so it cannot describe an API that version lacks.
- The whole typed surface of every package is in **`llms-full.txt`** (indexed by
  `llms.txt`) — at the repo root in the Zuke repo itself, or from a consumer
  repo <https://raw.githubusercontent.com/zuke-build/zuke/master/llms-full.txt>
  (index: <https://raw.githubusercontent.com/zuke-build/zuke/master/llms.txt>).
  Both track `master`, so they may document symbols that are merged but not yet
  released; use them to find what exists, then confirm the signature with
  `deno doc`.

Once the project is scaffolded, use the **zuke-write-build** skill to add and
edit targets.

