# Docs for AI agents (/agents) These docs are built for AI agents as well as people. Every page is available as clean Markdown, and the whole site is indexed in machine-readable form. Each section below stands on its own. ## Fetch any page as Markdown [#fetch-any-page-as-markdown] Append `.md` to any docs URL to get its Markdown source — no HTML, no navigation chrome: ```bash curl https://docs.harmont.dev/pipeline-sdk/patterns.md curl https://docs.harmont.dev/cli/run.md ``` ## Or use content negotiation [#or-use-content-negotiation] Send an `Accept: text/markdown` header and the same URL returns Markdown. Most coding agents (e.g. Claude Code, Cursor) send this automatically: ```bash curl https://docs.harmont.dev/cli/run -H 'Accept: text/markdown' ``` The response carries `Vary: Accept`, so a browser at the same URL still gets HTML. ## Site indexes [#site-indexes] * [/llms.txt](https://docs.harmont.dev/llms.txt) — a Markdown index of every page, with links and one-line descriptions. * [/llms-full.txt](https://docs.harmont.dev/llms-full.txt) — every page's Markdown concatenated into one document, for loading the whole corpus at once. ## Point an agent at Harmont [#point-an-agent-at-harmont] The fastest way to get a correct pipeline from an agent: tell it to read [/pipeline-sdk/patterns.md](https://docs.harmont.dev/pipeline-sdk/patterns.md) first. That page is the canonical do/don't guidance — chiefly, **use the high-level toolchain APIs (`hm.rust.toolchain()`, `hm.cmake()`, …) rather than hand-rolling commands through the general-purpose `hm.sh(...)` escape hatch.** For a working starting point, copy an [example](/examples) and adapt it. # Architecture (/architecture) You don't need anything here to use Harmont — it's for the curious and for debugging. The higher-level guides stay focused on writing and running pipelines; this is the one place that explains what happens beneath them. ## From code to a build [#from-code-to-a-build] Running a pipeline goes through a few stages: 1. **You write a pipeline** in the [Pipeline SDK](/pipeline-sdk) — a Python or TypeScript program under `.hm/`. 2. **`hm` compiles it** to a small, versioned JSON document — the intermediate representation (IR). The IR describes your steps as a graph: each step's command, image, cache policy, and which steps it depends on. 3. **Harmont creates a build** from that IR — one build with a job per step. 4. **The executor runs each job** in an isolated sandbox, streaming logs back as it goes. Dependent steps run in order and share a filesystem snapshot; independent steps run in parallel. Two ways to start a build — hm run from your local working tree, or Harmont Cloud — both compile to the same IR. Harmont creates the build and the executor runs each job in an isolated sandbox, streaming logs back. ## Why an IR [#why-an-ir] The IR is the stable contract between the SDK and the rest of Harmont. Both the Python and TypeScript SDKs are front-ends that compile to the same IR, which is why any example can ship the same pipeline in either language — and why your choice of SDK is a matter of taste. You can print the IR a pipeline compiles to, without running it: ```bash hm render ci ``` # Getting started (/getting-started) Harmont runs CI against your local working tree with `hm run`, so you can put a change through CI before you commit it. This guide takes you from an empty repo to a passing build. ## Install hm [#install-hm] ```bash curl -fsSL https://get.harmont.dev/install.sh | sh ``` The script downloads the static binary for your platform, verifies its SHA-256 against `https://get.harmont.dev/sha256sums.txt`, and installs to `~/.local/bin/hm`. Confirm it works: ```bash hm --version ``` You also need Docker running locally; `hm run` executes each step in a container. ## Scaffold a pipeline with `hm init` [#scaffold-a-pipeline-with-hm-init] Run `hm init` in your project. It asks which kind of project you have and writes a ready-to-run starter pipeline to `.hm/`: ```bash hm init ``` ``` ? Select a project template › CMake Elixir Next.js JavaScript / TypeScript ❯ Rust Zig Python ``` Pick one (or skip the prompt with `hm init --template rust`) and `hm init` writes `.hm/pipeline.py` (or `.hm/pipeline.ts` for the Next.js, JavaScript/TypeScript, and Zig templates). For example, the Rust template: ```python title=".hm/pipeline.py" import harmont as hm from harmont._rust import RustToolchain @hm.target() def project() -> RustToolchain: return hm.rust.toolchain(path=".") @hm.pipeline( "ci", env={"CI": "true"}, default_image="ubuntu:24.04", triggers=[hm.push(branch="main")], ) def ci(project: hm.Target[RustToolchain]) -> tuple[hm.Step, ...]: return (project.build(), project.test(), project.clippy(), project.fmt()) ``` ## Run it [#run-it] ```bash hm run ci ``` `hm run` packs your working tree, boots a local sandbox, and streams the build: ``` Packing working tree (6 files, 12 KB)... done. Build #1 created. Streaming logs. rust-install ✓ 2.1s build ✓ 3.4s test ✓ 0.9s Build passed in 6.4s. ``` ## Grow the pipeline [#grow-the-pipeline] Two rules cover most pipelines: * A step built **off** another runs **after** it and inherits its filesystem. That's a sequence. * Steps returned **together** with no dependency between them run in **parallel**. install runs first; build, test, clippy, and fmt fork from its snapshot and run at the same time. To go deeper, read the [Pipeline SDK](/pipeline-sdk) guide. For complete, runnable projects in other languages, see [Examples](/examples). ## Get help [#get-help] Stuck on a step, or want to see how others structure their pipelines? Join the [Harmont Discord](https://discord.gg/hm-dev) — it's the fastest way to get an answer from the team and the community. # Harmont (/) ## Where to start [#where-to-start] One curl. Two minutes. A uv project running in local CI in under five minutes. Starter pipelines you can copy — React, Rust, Python, Zig, TypeScript. REST endpoints. Bearer-token auth. Limited access. Ask questions, share pipelines, talk to the people building Harmont. ## Community [#community] Harmont is built in the open with the people who use it. The fastest way to get unstuck — or to shape where the product goes next — is the [Harmont Discord](https://discord.gg/hm-dev). Bring your pipeline, your bug, or your idea. # API (/api) The Harmont API is **not yet open to the public**. Endpoints require an account, and accounts are currently granted from the waitlist. **[Request access at harmont.dev](https://harmont.dev/)** — we're onboarding in batches. The reference below is published so you can build against the contract ahead of time. The Harmont API is the REST surface to Harmont's service. ## Quick orientation [#quick-orientation] | | | | ------------- | ------------------------------------------------------------------------------------------------------------- | | **Base URL** | `https://api.harmont.dev/api/v0` | | **Auth** | `Authorization: Bearer ` | | **Errors** | Single envelope, stable `code`, doc URL on each (see [Errors](/api/errors)) | | **Endpoints** | [Reference](/api/reference) — every endpoint, grouped by tag | | **Spec** | [openapi.json](/openapi.json) — full OpenAPI 3 document, suitable for Postman / openapi-generator / Stoplight | ## A minimal request [#a-minimal-request] ```bash curl -fsS https://api.harmont.dev/api/v0/ping \ -H "Authorization: Bearer $HM_TOKEN" ``` ```json { "response": "pong" } ``` You can create new API access tokens by navigating to the settings page in [Harmont](https://app.harmont.dev). The full API reference is available [here](/api/reference). # Configuration (/cli/config) `hm` builds its configuration by layering four sources, lowest precedence first: 1. Built-in defaults. 2. User config — `~/.config/hm/config.toml`. 3. Project config — `/.hm/config.toml`. 4. Environment variables, prefixed `HM_` with `__` between nested keys. Each layer overrides the one before it: a project file beats your user file, and an environment variable beats both. Every field is optional — omit a layer and the defaults stand. `hm` writes the user file with its directory restricted to `0700`. ## Fields [#fields] | Key | Type | Default | Meaning | | ------------------------ | --------------------- | ------------------------- | ---------------------------------------------- | | `cloud.api_url` | string | `https://api.harmont.dev` | Harmont API base URL. | | `cloud.org` | string | *(none)* | Active organization slug. | | `preferences.format` | `"human"` \| `"json"` | `"human"` | Default output format. | | `preferences.auto_watch` | bool | `false` | Watch a build automatically after creating it. | ## Example [#example] ```toml title="~/.config/hm/config.toml" [cloud] api_url = "https://api.harmont.dev" org = "acme" [preferences] format = "human" auto_watch = true ``` ## Environment overrides [#environment-overrides] Any field can be set with an `HM_`-prefixed variable, using `__` to separate nested keys: ```bash export HM_CLOUD__API_URL="https://api.harmont.dev" export HM_CLOUD__ORG="acme" export HM_PREFERENCES__FORMAT="json" ``` # hm CLI (/cli) `hm` is the Harmont command line. It scaffolds pipelines, runs them against your local working tree, and inspects what it would run. | Command | Purpose | | -------------------------------- | ---------------------------------------------------------- | | [`hm init`](/cli/init) | Scaffold a starter pipeline into `.hm/`. | | [`hm run`](/cli/run) | Run a pipeline against your local working tree, in Docker. | | [`hm pipelines`](/cli/pipelines) | Print the discovered pipelines as JSON. | | `hm render ` | Print the JSON a pipeline compiles to, without running it. | | `hm cache {save,restore,clean}` | Manage the local Docker image/workspace cache. | | `hm plugin list` | List the registered runner plugins. | | `hm version` | Print the CLI version. | Configuration lives in [`~/.config/hm/config.toml`](/cli/config). ## Global options [#global-options] | Flag | Meaning | | ----------------- | -------------------------------------------------- | | `--api-url ` | Override the API base URL (env `HARMONT_API_URL`). | | `-v, --verbose` | Enable debug logging. | | `--no-color` | Disable colored output. | # hm init (/cli/init) ## Synopsis [#synopsis] ```bash hm init [--template ] [--dir ] [--force] ``` `hm init` writes a ready-to-run starter pipeline to `.hm/`. Run it with no flags for an interactive picker, or pass `--template` to skip the prompt. ## Templates [#templates] | Template | Flag value | File written | | ----------------------- | ---------- | ----------------- | | CMake | `cmake` | `.hm/pipeline.py` | | Elixir | `elixir` | `.hm/pipeline.py` | | Next.js | `nextjs` | `.hm/pipeline.ts` | | JavaScript / TypeScript | `js` | `.hm/pipeline.ts` | | Rust | `rust` | `.hm/pipeline.py` | | Zig | `zig` | `.hm/pipeline.ts` | | Python | `python` | `.hm/pipeline.py` | ## Options [#options] | Flag | Default | Meaning | | ----------------------- | ---------- | --------------------------------------- | | `-t, --template ` | *(prompt)* | Pick a template non-interactively. | | `-d, --dir ` | `.` | Target directory. | | `--force` | off | Overwrite an existing `.hm/` directory. | ## Example [#example] ```bash hm init --template cmake ``` ``` created .hm/pipeline.py (Python pipeline, template: Cmake) next step: run `hm run` to execute your pipeline locally ``` Then run it: ```bash hm run ci ``` # hm pipelines (/cli/pipelines) ## Synopsis [#synopsis] ```bash hm pipelines [--dir ] ``` `hm pipelines` discovers every pipeline declared under `.hm/` and prints a machine-readable envelope (`schema_version: "1"`) describing each one — slug, name, triggers, and whether manual runs are allowed. A repo with no `.hm/` prints an empty registry rather than erroring. | Flag | Default | Meaning | | ------------------ | ------- | ------------------------------ | | `-d, --dir ` | `.` | Source root containing `.hm/`. | To see the full compiled plan for a single pipeline, use `hm render `. # hm run (/cli/run) ## Synopsis [#synopsis] ```bash hm run [PIPELINE] [OPTIONS] ``` `hm run` packs your current working tree, boots a local Docker sandbox, and runs the pipeline against it as it stands, including changes you haven't committed. If your repo declares exactly one pipeline, the `PIPELINE` slug is optional. ## Options [#options] | Flag | Default | Meaning | | ------------------------- | ------------ | ------------------------------------------ | | `-b, --branch ` | *(detected)* | Branch to record on the build. | | `-m, --message ` | *(none)* | Build message. | | `-e, --env ` | *(none)* | Set an environment variable (repeatable). | | `-d, --dir ` | `.` | Source root to pack. | | `--parallelism ` | *(cores)* | Max concurrent chains. | | `--format ` | `human` | Output format: `human` or `json`. | | `--logs` | off | Stream full logs instead of progress bars. | | `--no-watch` | off | Don't watch the build after creating it. | ## Example [#example] ```bash hm run ci --env CI=true --logs ``` # CMake (C / C++) (/examples/cmake) Harmont has first-class CMake support. One `hm.cmake(...)` call picks the compiler, passes cache `defines`, and gives you `test()`, `lint()`, and `fmt()` actions backed by CTest and clang-format. This example uses an explicit compiler and a Release build with C++20. ## Project layout [#project-layout] ## Pipeline [#pipeline] **Python** **TypeScript** ## Run it [#run-it] ```bash hm run ci ``` For a minimal single-binary setup, see the `c/` and `cpp/` examples in the [harmont-cli repo](https://github.com/harmont-dev/harmont-cli/tree/main/examples). # Elixir (/examples/elixir) A mix project: compile, test, format, Credo, Dialyzer, plus deps\_audit/hex\_audit. ## Project layout [#project-layout] ## Pipeline [#pipeline] **Python** **TypeScript** ## Run it [#run-it] ```bash hm run ci ``` # Go (/examples/go) A Go module: build, test, vet, and fmt. ## Project layout [#project-layout] ## Pipeline [#pipeline] **Python** **TypeScript** ## Run it [#run-it] ```bash hm run ci ``` # Examples (/examples) Each example is a real project with a pipeline you can copy and run with `hm run ci`. Pick the one closest to your stack. Every pipeline is shown in both Python and TypeScript — use the switch on any sample to choose. ## Compiled languages [#compiled-languages] ## Web & scripting [#web--scripting] ## Backend frameworks [#backend-frameworks] # Next.js (/examples/nextjs) A Next.js app via the js toolchain: build, test, and lint. ## Project layout [#project-layout] ## Pipeline [#pipeline] **Python** **TypeScript** ## Run it [#run-it] ```bash hm run ci ``` ## Before your first run: pin your package manager [#before-your-first-run-pin-your-package-manager] `create-next-app` installs your dependencies with a specific pnpm version and writes a supply-chain policy (`minimumReleaseAge`, the 24-hour package-age gate) next to the lockfile. The trouble starts when the build runs a *different*, **newer** pnpm than the one that scaffolded the project: pnpm 11.1+ re-validates the committed lockfile against that policy before installing, and a brand-new app pins the freshest Next.js, React, and type packages — all published in the last day — so the install fails before fetching anything: ``` ✗ Lockfile failed supply-chain policy check [ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION] 5 lockfile entries failed verification: caniuse-lite@1.0.30001799 was published ... within the minimumReleaseAge cutoff ``` The fix is to build with the **same pnpm that scaffolded the project**, so CI resolves exactly what you ran locally. `create-next-app` prints that version on its last line: ``` Done in 5.4s using pnpm v10.33.0 ``` Add a matching `packageManager` field to `package.json`: ```json title="package.json" { "packageManager": "pnpm@10.33.0" } ``` The `js` toolchain reads this field and pins the build's pnpm to it (via `corepack`), so CI installs with the same package manager as your machine. The build becomes reproducible **and** your lockfile's supply-chain policy stays intact — no need to weaken it. Use the exact version from your own `create-next-app` output — it may differ from `10.33.0`. Pinning `packageManager` is good hygiene for any JS project on Harmont: it's what makes your local install and your CI install byte-for-byte the same. ## Stuck? [#stuck] Pipelines for real apps hit real edges. If something doesn't build the way you expect, ask in the [Harmont Discord](https://discord.gg/hm-dev) — we answer fast. # Python (uv) (/examples/python-uv) A uv-managed project: test (pytest), lint (ruff), fmt, and typecheck (mypy). ## Project layout [#project-layout] ## Pipeline [#pipeline] **Python** **TypeScript** ## Run it [#run-it] ```bash hm run ci ``` # Rust (/examples/rust) A Cargo project: build, test, clippy, and fmt fork from one toolchain install. ## Project layout [#project-layout] ## Pipeline [#pipeline] **Python** **TypeScript** ## Run it [#run-it] ```bash hm run ci ``` # Zig (/examples/zig) A Zig project: build, test, and fmt. ## Project layout [#project-layout] ## Pipeline [#pipeline] **Python** **TypeScript** ## Run it [#run-it] ```bash hm run ci ``` # Caching (/pipeline-sdk/caching) Pass a cache policy to any step so its result is reused on the next run. A policy decides when a cached step is still valid: for a fixed window (`ttl`), until a tracked file changes (`on_change`), or until its command changes (`forever`). Compose policies to require all of them. **Python** ```python import harmont as hm from datetime import timedelta deps = hm.sh( "make deps", cache=hm.compose( hm.on_change("requirements.txt"), hm.ttl(timedelta(hours=6)), ), ) ``` **TypeScript** ```typescript import { sh, compose, onChange, ttl } from "@harmont/hm"; const deps = sh("make deps", { cache: compose(onChange("requirements.txt"), ttl(6 * 60 * 60)), }); ``` See the [cache reference](/pipeline-sdk/reference/cache) for every policy. # Chains & steps (/pipeline-sdk/chains) A pipeline is a directed graph of **steps**. You build it by chaining method calls off a root and returning the leaf (or leaves). A step built off another runs after it and inherits its filesystem; steps returned together with no dependency between them run in parallel. ## Starting a chain [#starting-a-chain] `hm.sh(...)` starts a chain and sets its first command — shorthand for `hm.scratch().sh(...)`. **Python** ```python import harmont as hm build = hm.sh("make build").sh("make test") ``` **TypeScript** ```typescript import { sh } from "@harmont/hm"; const build = sh("make build").sh("make test"); ``` ## Forking and joining [#forking-and-joining] Call `.fork()` to branch, and `hm.wait()` for a join barrier. **Python** ```python import harmont as hm root = hm.sh("make deps") lint = root.fork("lint").sh("make lint") test = root.fork("test").sh("make test") ``` **TypeScript** ```typescript import { sh } from "@harmont/hm"; const root = sh("make deps"); const lint = root.fork({ label: "lint" }).sh("make lint"); const test = root.fork({ label: "test" }).sh("make test"); ``` The full `Step` field and method list is in the [chains reference](/pipeline-sdk/reference/chains). # Pipeline SDK (/pipeline-sdk) A Harmont pipeline is a small program. You import the SDK, build a graph of shell steps, and register it so the CLI can find it. You write pipelines as Python or TypeScript programs rather than YAML, and `hm` runs them. The same pipeline can be written in Python or TypeScript. Pick a language with the switch on any code sample; your choice follows you across the docs. **Python** ```python title=".hm/pipeline.py" import harmont as hm @hm.pipeline("ci", triggers=[hm.push(branch="main")]) def ci() -> tuple[hm.Step, ...]: project = hm.rust.toolchain(path=".") return (project.build(), project.test()) ``` **TypeScript** ```typescript title=".hm/pipeline.ts" import { pipeline, push, type PipelineDefinition } from "@harmont/hm"; import { rust } from "@harmont/hm/toolchains"; const project = rust.toolchain({ path: "." }); const pipelines: PipelineDefinition[] = [ { slug: "ci", triggers: [push({ branch: "main" })], pipeline: pipeline([project.build(), project.test()]), }, ]; export default pipelines; ``` ## Install [#install] Install the SDK for your language so your editor gives you types and autocomplete as you write pipelines. **Python** ```bash pip install harmont # or: uv add harmont ``` **TypeScript** ```bash npm install @harmont/hm # or: pnpm add @harmont/hm # or: bun add @harmont/hm ``` ## Where to go next [#where-to-go-next] # Patterns & anti-patterns (/pipeline-sdk/patterns) This page is the canonical guidance for writing Harmont pipelines well. Each rule stands on its own — read any section in isolation. The single most important rule: **prefer a toolchain over raw shell.** ## Prefer toolchains over raw shell [#prefer-toolchains-over-raw-shell] Harmont ships toolchains for Rust, Python, Go, JavaScript/TypeScript, CMake (C/C++), Elixir, and Zig. A toolchain installs the runtime, warms the dependency cache, and exposes opinionated `build`/`test`/`lint`/`fmt` actions. Use it. It gives you correct install, caching, and parallelism for free. `hm.sh(...)` is the general-purpose escape hatch — a raw shell step. It is the right tool only when **no toolchain covers your case**. Reaching for it first means you re-implement install and caching by hand, usually worse. ✅ **Do — use the toolchain for your language:** **Python** ```python title=".hm/pipeline.py" import harmont as hm @hm.pipeline("ci") def ci() -> tuple[hm.Step, ...]: project = hm.rust.toolchain(path=".") return (project.build(), project.test(), project.clippy(), project.fmt()) ``` **TypeScript** ```typescript title=".hm/pipeline.ts" import { pipeline, type PipelineDefinition } from "@harmont/hm"; import { rust } from "@harmont/hm/toolchains"; const project = rust.toolchain({ path: "." }); const pipelines: PipelineDefinition[] = [ { slug: "ci", pipeline: pipeline([project.build(), project.test(), project.clippy(), project.fmt()]) }, ]; export default pipelines; ``` ❌ **Don't — hand-roll the same thing with raw shell:** **Python** ```python title=".hm/pipeline.py" import harmont as hm # Anti-pattern: no managed toolchain install, no dependency caching, and you # now own the correctness of every command. @hm.pipeline("ci") def ci() -> tuple[hm.Step, ...]: return ( hm.sh("curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y") .sh("cargo build") .sh("cargo test"), ) ``` **TypeScript** ```typescript title=".hm/pipeline.ts" import { pipeline, sh, type PipelineDefinition } from "@harmont/hm"; // Anti-pattern: no managed toolchain install, no dependency caching. const pipelines: PipelineDefinition[] = [ { slug: "ci", pipeline: pipeline([ sh("curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y") .sh("cargo build") .sh("cargo test"), ]), }, ]; export default pipelines; ``` When you genuinely have no toolchain (a bespoke build tool, a one-off script), `hm.sh(...)` is correct and supported — see [Chains & steps](/pipeline-sdk/chains). ## Fork shared work; don't repeat install [#fork-shared-work-dont-repeat-install] Toolchain actions already fork off one shared install step, so adding a check costs only the check. When you do build chains by hand, fork off a common root instead of re-running setup in every branch. ✅ **Do — one root, parallel forks:** **Python** ```python import harmont as hm root = hm.sh("make deps") lint = root.fork("lint").sh("make lint") test = root.fork("test").sh("make test") ``` **TypeScript** ```typescript import { sh } from "@harmont/hm"; const root = sh("make deps"); const lint = root.fork({ label: "lint" }).sh("make lint"); const test = root.fork({ label: "test" }).sh("make test"); ``` ❌ **Don't — re-install dependencies in every chain:** **Python** ```python import harmont as hm lint = hm.sh("make deps").sh("make lint") # installs deps test = hm.sh("make deps").sh("make test") # installs deps again ``` **TypeScript** ```typescript import { sh } from "@harmont/hm"; const lint = sh("make deps").sh("make lint"); // installs deps const test = sh("make deps").sh("make test"); // installs deps again ``` ## Declare triggers in code; don't gate inside steps [#declare-triggers-in-code-dont-gate-inside-steps] Run-on-push / run-on-PR belongs in the pipeline's `triggers`, not in shell conditionals. The trigger is visible to Harmont; a branch check buried in a step is not. ✅ **Do:** **Python** ```python import harmont as hm @hm.pipeline("ci", triggers=[hm.push(branch="main")]) def ci() -> tuple[hm.Step, ...]: project = hm.rust.toolchain(path=".") return (project.build(), project.test()) ``` **TypeScript** ```typescript import { pipeline, push, type PipelineDefinition } from "@harmont/hm"; import { rust } from "@harmont/hm/toolchains"; const project = rust.toolchain({ path: "." }); const pipelines: PipelineDefinition[] = [ { slug: "ci", triggers: [push({ branch: "main" })], pipeline: pipeline([project.build(), project.test()]), }, ]; export default pipelines; ``` ❌ **Don't — branch-gate inside a shell step:** **Python** ```python import harmont as hm @hm.pipeline("ci") def ci() -> tuple[hm.Step, ...]: return (hm.sh('[ "$BRANCH" = "main" ] && cargo test || true'),) ``` **TypeScript** ```typescript import { pipeline, sh, type PipelineDefinition } from "@harmont/hm"; const pipelines: PipelineDefinition[] = [ { slug: "ci", pipeline: pipeline([sh('[ "$BRANCH" = "main" ] && cargo test || true')]) }, ]; export default pipelines; ``` See [Triggers](/pipeline-sdk/triggers) for the full trigger surface. ## Write pipelines with the SDK; don't hand-author IR JSON [#write-pipelines-with-the-sdk-dont-hand-author-ir-json] Pipelines are programs. Author them with the `harmont` / `@harmont/hm` SDK and let `hm` lower them. Never hand-write the underlying v0 IR JSON — it is a compiler target, not an authoring format, and it is unstable across versions. # Toolchains (/pipeline-sdk/toolchains) A toolchain wraps three things: installing the runtime, warming the dependency cache, and the common build/test/lint commands. You call one factory, then attach the actions you want. Each action forks off the shared install step, so adding a check costs you the action — never the install. ## Rust [#rust] `hm.rust.toolchain()` installs the toolchain; the action methods build, test, lint, and format. **Python** ```python import harmont as hm @hm.pipeline("ci") def ci() -> tuple[hm.Step, ...]: project = hm.rust.toolchain(path=".") return (project.build(), project.test(), project.clippy(), project.fmt()) ``` **TypeScript** ```typescript import { pipeline, type PipelineDefinition } from "@harmont/hm"; import { rust } from "@harmont/hm/toolchains"; const project = rust.toolchain({ path: "." }); const pipelines: PipelineDefinition[] = [ { slug: "ci", pipeline: pipeline([project.build(), project.test(), project.clippy(), project.fmt()]) }, ]; export default pipelines; ``` ## CMake (C / C++) [#cmake-c--c] `hm.cmake()` configures and builds with CMake. Pass `compiler`, `defines`, a `generator`, or a `preset`; the action methods run CTest, clang-format, and clang-tidy. **Python** ```python import harmont as hm @hm.pipeline("ci") def ci() -> tuple[hm.Step, ...]: project = hm.cmake( path=".", compiler="clang-18", defines={"CMAKE_BUILD_TYPE": "Release", "CMAKE_CXX_STANDARD": "20"}, ) return (project.test(), project.lint(), project.fmt()) ``` **TypeScript** ```typescript import { pipeline, type PipelineDefinition } from "@harmont/hm"; import { cmake } from "@harmont/hm/toolchains"; const project = cmake({ path: ".", compiler: "clang-18", defines: { CMAKE_BUILD_TYPE: "Release", CMAKE_CXX_STANDARD: "20" }, }); const pipelines: PipelineDefinition[] = [ { slug: "ci", pipeline: pipeline([project.test(), project.lint(), project.fmt()]) }, ]; export default pipelines; ``` ## Every toolchain [#every-toolchain] Harmont ships toolchains for **Rust**, **Python**, **Go**, **JavaScript/TypeScript** (`js`/`ts`, with npm, pnpm, yarn, and Bun), **CMake** (C/C++), **Elixir**, and **Zig**. Each one's full method list lives in the [toolchains reference](/pipeline-sdk/reference/toolchains). # Triggers (/pipeline-sdk/triggers) Pass `triggers=[...]` when you register a pipeline to control when Harmont runs it on a connected repository. ## Push [#push] ## Pull request [#pull-request] **Python** ```python import harmont as hm @hm.pipeline( "ci", triggers=[hm.push(branch="main"), hm.pull_request(branches=["main"])], ) def ci() -> hm.Step: return hm.sh("make test") ``` **TypeScript** ```typescript import { pipeline, push, pullRequest, sh, type PipelineDefinition } from "@harmont/hm"; const pipelines: PipelineDefinition[] = [ { slug: "ci", triggers: [push({ branch: "main" }), pullRequest({ branches: ["main"] })], pipeline: pipeline([sh("make test")]), }, ]; export default pipelines; ``` Full options are in the [triggers reference](/pipeline-sdk/reference/triggers). # Authentication (/sdk/authentication) Every Harmont API request is authenticated with a bearer token. The SDK lets you build a configured client once and pass it to each call. ## Create a client [#create-a-client] ```ts import { createClient, createConfig } from "@harmont/cloud"; const client = createClient( createConfig({ baseUrl: "https://api.harmont.dev", // the default; override for dev/self-host }), ); ``` `createConfig` seeds the client's configuration; `createClient` returns a client instance you pass to each SDK call. The default `baseUrl` is already `https://api.harmont.dev`, so you can omit it in production. ## Attach your token [#attach-your-token] Add an interceptor so every request carries your `Authorization` header: ```ts client.interceptors.request.use((req) => { req.headers.set("Authorization", `Bearer ${process.env.HARMONT_TOKEN}`); return req; }); ``` Create API tokens from the settings page in [Harmont](https://app.harmont.dev). Treat them like passwords — they grant full access to your organizations. ## The default client [#the-default-client] The SDK also exports a ready-made `client` (with the production `baseUrl`). Configure it once and the SDK functions use it when you don't pass one explicitly: ```ts import { client } from "@harmont/cloud"; client.setConfig({ headers: { Authorization: `Bearer ${process.env.HARMONT_TOKEN}` }, }); ``` Passing an explicit `client` per call (the pattern above) is clearer for apps that talk to more than one environment or token; the shared default is convenient for scripts. See [Making calls](/sdk/usage) next. # End-to-end example (/sdk/example) A complete script that authenticates, creates a build, polls it to completion, and streams its logs. It uses only the public SDK functions. ```ts title="run.ts" import { createClient, createConfig, listOrganizations, createBuild, getBuild, getBuildLogToken, listJobs, } from "@harmont/cloud"; const token = process.env.HARMONT_TOKEN!; const baseUrl = process.env.HARMONT_API_URL ?? "https://api.harmont.dev"; const client = createClient(createConfig({ baseUrl })); client.interceptors.request.use((req) => { req.headers.set("Authorization", `Bearer ${token}`); return req; }); // 1. Pick an organization. const { data: orgs, error: orgErr } = await listOrganizations({ client }); if (orgErr) throw new Error(orgErr.error.code); const org = orgs!.data[0].slug; // 2. Create a build on a pipeline. const { data: build, error: buildErr } = await createBuild({ client, path: { org, pipeline: "ci" }, body: { branch: "main", commit: "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2", source_url: "https://example.com/source.tar.gz", }, }); if (buildErr) throw new Error(buildErr.error.code); const number = build!.number; // 3. Poll until the build reaches a terminal state. const terminal = new Set(["passed", "failed", "canceled"]); let state = build!.state; while (!terminal.has(state)) { await new Promise((r) => setTimeout(r, 2000)); const { data } = await getBuild({ client, path: { org, pipeline: "ci", number } }); state = data!.state; console.log(`build #${number}: ${state}`); } // 4. Stream the first job's logs. const { data: tok } = await getBuildLogToken({ client, path: { org, pipeline: "ci", number } }); const { data: jobs } = await listJobs({ client, path: { org, pipeline: "ci", number } }); const jobId = jobs!.data[0].id; const res = await fetch(`${baseUrl}/v0/jobs/${jobId}/logs?token=${tok!.token}`); const reader = res.body!.getReader(); const decoder = new TextDecoder(); for (;;) { const { value, done } = await reader.read(); if (done) break; process.stdout.write(decoder.decode(value)); } ``` Run it with a token in your environment: ```bash HARMONT_TOKEN=hmt_… npx tsx run.ts ``` Each function used here is documented in the [SDK reference](/sdk/reference), and the response shapes (`build.state`, `jobs.data[].id`) are defined in the [API reference](/api/reference). # Cloud SDK (/sdk) The Harmont API is **not yet open to the public**. Endpoints require an account, granted from the waitlist. **[Request access at harmont.dev](https://harmont.dev/)**. The SDK and reference below are published so you can build against the contract ahead of time. `@harmont/cloud` is the official TypeScript SDK for the Harmont API. It is generated from the same [OpenAPI spec](/openapi.json) that backs the [REST reference](/api/reference), so its functions and types mirror the API exactly — one function per endpoint, fully typed request and response shapes. ## Install [#install] ```bash npm install @harmont/cloud ``` The SDK is built on a small fetch-based client and ships as both ESM and CommonJS with TypeScript declarations. It targets Node 18+ and any modern browser or bundler. ## What's inside [#whats-inside] Construct a client and attach your bearer token. Call typed functions, read responses, handle errors. Follow a job's logs over SSE. Create a build, poll it, and stream its logs. Every public function, generated from the spec. ## Relationship to the REST API [#relationship-to-the-rest-api] The SDK is a thin, typed wrapper — there is no behaviour it adds beyond the HTTP contract. Anything documented in the [API reference](/api/reference) (auth, error envelope, rate limits) applies unchanged. When in doubt about a field, the [API reference](/api/reference) is the schema-level source of truth; the [SDK reference](/sdk/reference) shows the TypeScript surface. # Streaming logs (/sdk/logs) Job logs stream over Server-Sent Events (SSE), not a request/response endpoint, so they are intentionally **not** an SDK function. Streaming is two steps: mint a short-lived log token with the SDK, then open the SSE URL directly. ## 1. Mint a log token [#1-mint-a-log-token] ```ts import { getBuildLogToken } from "@harmont/cloud"; const { data: tok, error } = await getBuildLogToken({ client, path: { org: "acme", pipeline: "ci", number: 42 }, }); if (error) throw new Error(error.error.code); ``` The token is short-lived and scoped to that build's logs. ## 2. Open the SSE stream [#2-open-the-sse-stream] Open the log endpoint with the token as a query parameter and iterate the response body. Note the log stream lives at `/v0/jobs/{jobId}/logs` — outside the `/api/v0` base the other endpoints use: ```ts const res = await fetch( `https://api.harmont.dev/v0/jobs/${jobId}/logs?token=${tok.token}`, ); const reader = res.body!.getReader(); const decoder = new TextDecoder(); for (;;) { const { value, done } = await reader.read(); if (done) break; process.stdout.write(decoder.decode(value)); } ``` List a build's jobs with `listJobs` to get each `jobId`. See the [end-to-end example](/sdk/example) for the full create → poll → stream flow. The log token is passed as a query parameter because `EventSource` and many SSE clients can't set custom headers. It is redacted from server-side request logs. # Making calls (/sdk/usage) Each SDK function maps to one API endpoint. You pass a single options object — `{ client, path, query, body }` as the endpoint requires — and get back a typed result. ## A typed call [#a-typed-call] ```ts import { createClient, createConfig, listOrganizations } from "@harmont/cloud"; const client = createClient(createConfig()); client.interceptors.request.use((req) => { req.headers.set("Authorization", `Bearer ${process.env.HARMONT_TOKEN}`); return req; }); const { data, error } = await listOrganizations({ client }); if (error) throw new Error(`request failed: ${error.error.code}`); console.log(data); // typed response ``` The result is `{ data, error }`: on success `data` holds the typed response and `error` is `undefined`; on a non-2xx response `error` holds the API's [error envelope](/api/errors) (with its stable `code`) and `data` is `undefined`. ## Path, query, and body [#path-query-and-body] Endpoints that take parameters declare them on the options object. For example, creating a build: ```ts import { createBuild } from "@harmont/cloud"; const { data: build, error } = await createBuild({ client, path: { org: "acme", pipeline: "ci" }, body: { // CreateBuildRequest — see the reference link below for the full schema source_url: "https://example.com/source.tar.gz", }, }); ``` TypeScript enforces the shape of `path` and `body` from the generated types, so a missing `org` or a misspelled field is a compile error, not a 422 at runtime. ## Errors [#errors] The SDK never throws on a non-2xx response — it returns the error in the result. Check `error` and branch on its stable `code`: ```ts const { data, error } = await getBuild({ client, path: { org: "acme", pipeline: "ci", number: 42 }, }); if (error) { if (error.error.code === "build_not_found") return null; throw new Error(`unexpected: ${error.error.code}`); } return data; ``` Every `code` is documented in the [error reference](/api/errors). The full per-function surface — every parameter and response type — is in the [SDK reference](/sdk/reference). # account_has_billing_history (/api/errors/account_has_billing_history) ## When this happens [#when-this-happens] You asked to delete your account, but it carries billing history — redeemed coupons, coupons you created, or completed Stripe checkouts. Deleting the account would orphan those financial records, so the API refuses. ## How to fix it [#how-to-fix-it] Contact support to close an account with billing history. Support can reconcile or archive the records and then complete the deletion. # api_token_not_found (/api/errors/api_token_not_found) ## When this happens [#when-this-happens] You tried to revoke an API key by its id, but no key with that id exists on your account. This usually means the key was already revoked — often from another tab or device — and the page you are looking at is stale. ## How to fix it [#how-to-fix-it] Reload your API key list so it reflects the current state, then retry against a key that still exists. If the entry keeps reappearing after a reload, sign out and back in to refresh your session. # billing_insufficient_balance (/api/errors/billing_insufficient_balance) ## When this happens [#when-this-happens] Running the build would cost more than your current account balance. The response message names the specific shortfall. ## How to fix it [#how-to-fix-it] Top up your balance or redeem a coupon from the billing page, then retry the build. # billing_provider_error (/api/errors/billing_provider_error) ## When this happens [#when-this-happens] Harmont reached the payment provider, but it returned an error or was unreachable. This is an upstream problem, not an issue with your request. ## How to fix it [#how-to-fix-it] Wait a moment and try again. If the charge or top-up keeps failing, check the billing page for provider status and contact support with the `request_id`. # billing_unconfigured (/api/errors/billing_unconfigured) ## When this happens [#when-this-happens] A billing action was attempted but this deployment has no payment provider configured. Common on self-hosted or local environments. ## How to fix it [#how-to-fix-it] If you operate this deployment, set the billing provider credentials (for example `STRIPE_SECRET_KEY`) and restart the API. Otherwise contact support. # email_unconfigured (/api/errors/email_unconfigured) ## When this happens [#when-this-happens] An action required sending email (sign-up, recovery), but this Harmont deployment has no email provider configured. You will see this on self-hosted or local environments before mail credentials are set. ## How to fix it [#how-to-fix-it] If you run this deployment, configure the email provider credentials and restart the API. On harmont.dev, contact support with the `request_id`. # Errors (/api/errors) Every non-2xx response from the Harmont API uses the same JSON envelope. Scripts match on `code`, humans read `message`, and `doc_url` points at the page for that exact error. ```json { "error": { "type": "invalid_request", "code": "passkey_unknown_credential", "message": "This passkey is not registered. Try a different passkey or use recovery.", "doc_url": "https://docs.harmont.dev/api/errors/passkey_unknown_credential", "request_id": "req_01H..." } } ``` | Field | Notes | | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `type` | Closed-set classifier for generic handling (retry, auth prompts). One of `invalid_request`, `not_found`, `unauthorized`, `forbidden`, `conflict`, `billing`, `server_error`, `rate_limited`. | | `code` | Stable snake\_case identifier — the scripting contract. Never renamed in place; new codes are added and old ones aliased. | | `message` | Human-readable, in the user's voice. No stack traces, no type names. | | `doc_url` | Link to the page for this `code` (the pages listed in the sidebar). | | `request_id` | Echoed from the `X-Request-Id` response header. Paste it into support requests. | HTTP status follows REST convention: `400` invalid request, `401` unauthenticated, `403` unauthorized, `404` not found, `409` conflict, `402` billing, `429` rate-limited, `5xx` server. ## Error doctrine [#error-doctrine] Every Harmont error points precisely, states what was observed, and states the fix. We do not write "did you mean?" — we have the context, so we use it. * *"Field `name` is required."* — not *"Bad request."* * *"Build #14 has already finished and cannot be canceled."* — not *"Conflict."* ## Handling errors in clients [#handling-errors-in-clients] Switch on `code` for behavior; show `message` to the user; link `doc_url`: ```ts async function call(url: string) { const r = await fetch(url, { headers: { Authorization: `Bearer ${HM_TOKEN}` } }); if (r.ok) return r.json(); const { error } = await r.json(); switch (error.code) { case 'passkey_unknown_credential': throw new AuthError(error.message, error.doc_url); default: throw new ApiError(error.type, error.message, error.doc_url); } } ``` Browse the individual error codes in the sidebar for the cause and fix of each. # passkey_assertion_failed (/api/errors/passkey_assertion_failed) ## When this happens [#when-this-happens] Your authenticator produced a signature that did not verify against the stored public key. This can follow a corrupted credential, a mismatched origin (for example, signing in from a different domain than the one you registered), or a browser extension interfering with WebAuthn. ## How to fix it [#how-to-fix-it] Try the sign-in again. If it keeps failing, register a new passkey from a trusted device on the official domain, or sign in with Google/GitHub and add a fresh passkey from settings. The response message includes a specific reason after the colon. # passkey_challenge_invalid (/api/errors/passkey_challenge_invalid) ## When this happens [#when-this-happens] Each passkey sign-in or registration starts a server-issued challenge that is valid for a short window. The challenge expired, or the page was left open too long before you completed the prompt. ## How to fix it [#how-to-fix-it] Reload the page to start a fresh ceremony, then complete the passkey prompt without delay. # passkey_email_send_failed (/api/errors/passkey_email_send_failed) ## When this happens [#when-this-happens] Harmont tried to send a verification or recovery email and the upstream mail provider rejected or failed the send. This is a transient server-side problem, not something wrong with your input. ## How to fix it [#how-to-fix-it] Wait a few minutes and request the email again. If it keeps failing, contact support with the `request_id` from the response. # passkey_last_credential (/api/errors/passkey_last_credential) ## When this happens [#when-this-happens] You attempted to delete the only passkey on an account that has no linked Google or GitHub identity. Removing it would lock you out. ## How to fix it [#how-to-fix-it] Add another passkey, or link Google or GitHub from settings, before removing this one. # passkey_not_found (/api/errors/passkey_not_found) ## When this happens [#when-this-happens] You tried to rename or delete a passkey by its id, but no passkey with that id exists on your account. This usually means the passkey was already removed — often from another tab or device — and the page you are looking at is stale. ## How to fix it [#how-to-fix-it] Reload your passkey list so it reflects the current state, then retry against a passkey that still exists. If the entry keeps reappearing after a reload, sign out and back in to refresh your session. # passkey_registration_failed (/api/errors/passkey_registration_failed) ## When this happens [#when-this-happens] The attestation your authenticator returned during sign-up could not be verified. This can follow a mismatched relying-party domain (registering from a different origin than the one the server expects), an authenticator that returns an attestation format the server does not accept, a credential the device declined to create with the required user verification, or a browser extension interfering with WebAuthn. ## How to fix it [#how-to-fix-it] Start the sign-up again from the official domain and complete the device prompt (PIN or biometric) when asked. If it keeps failing, try a different authenticator or device, or sign in with Google/GitHub and add a passkey from settings afterward. The response message includes a specific reason after the colon, and the server records the underlying cause for support to inspect. # passkey_signup_email_taken (/api/errors/passkey_signup_email_taken) ## When this happens [#when-this-happens] You tried to sign up with an email that already has a Harmont account, possibly created through Google or GitHub. ## How to fix it [#how-to-fix-it] Sign in with the existing method instead of signing up. If you don't remember which method you used, start account recovery for that email. # passkey_token_invalid (/api/errors/passkey_token_invalid) ## When this happens [#when-this-happens] Sign-up and recovery links are single-use and short-lived. You see this after the link in your email has expired, was already redeemed, or was truncated by your mail client. ## How to fix it [#how-to-fix-it] Request a fresh link from the sign-up or recovery screen and open it promptly. If links keep failing, copy the full URL directly from the email rather than clicking, in case your client wrapped it. # passkey_unknown_credential (/api/errors/passkey_unknown_credential) ## When this happens [#when-this-happens] The credential your authenticator offered is not on file. This usually means the passkey was created for a different account, was removed from your account, or you are signing in to the wrong environment. ## How to fix it [#how-to-fix-it] Try a different passkey, or use account recovery to register a new one. If you still have access through Google or GitHub, sign in that way and add a fresh passkey from settings. # passkey_user_verification_required (/api/errors/passkey_user_verification_required) ## When this happens [#when-this-happens] Harmont requires user verification (a PIN, fingerprint, or face check) on every passkey sign-in. Your authenticator completed the ceremony without performing that step. ## How to fix it [#how-to-fix-it] Use a passkey backed by a PIN or biometric, or enable a device unlock method on your security key, then sign in again. # pipeline_manual_disabled (/api/errors/pipeline_manual_disabled) ## When this happens [#when-this-happens] You tried to start a build by hand on a pipeline whose configuration disables manual triggers. The pipeline still builds from webhooks and schedules. ## How to fix it [#how-to-fix-it] Trigger the build through its configured source (a push or a schedule), or enable manual builds in the pipeline settings if you own it. # signup_cap_reached (/api/errors/signup_cap_reached) ## When this happens [#when-this-happens] Harmont is in early access and caps how many accounts can exist at once. When that cap is reached, new sign-ups are paused and any attempt to register returns this error until capacity frees up. ## How to fix it [#how-to-fix-it] Try again later — the cap lifts as we expand capacity. For updates, join our Discord at [https://discord.gg/hm-dev](https://discord.gg/hm-dev). If you have a business use-case and need access sooner, email [marko@harmont.dev](mailto:marko@harmont.dev). # signup_failed (/api/errors/signup_failed) ## When this happens [#when-this-happens] Something went wrong on our side while creating your account, so the sign-up did not complete. This is a transient server error, not a problem with your input. ## How to fix it [#how-to-fix-it] Try again in a few moments. If it keeps failing, reach out at [marko@harmont.dev](mailto:marko@harmont.dev) so we can look into it. # user_name_invalid (/api/errors/user_name_invalid) ## When this happens [#when-this-happens] You tried to set a display name that is empty or longer than 255 characters. ## How to fix it [#how-to-fix-it] Send a display name with 1 to 255 characters and try again. # Auth (/api/reference/auth) The Auth endpoints mint and exchange Harmont session tokens. They are the only endpoints in this API where the request is *unauthenticated* on purpose; everything else takes a `Bearer` header from one of these. {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Billing (/api/reference/billing) Billing endpoints expose an organization's ledger: its current balance, its transaction history, and a usage breakdown of VM-lease time by pipeline and user. They also start a Stripe Checkout session for topping up and redeem coupon codes. Balances are denominated in cents. Top-ups are credited asynchronously when Stripe confirms the checkout via webhook, so a successful `checkout` call returns a redirect URL, not an immediate balance change. {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Builds (/api/reference/builds) A build is one run of a pipeline. Each build has a `number` unique within its pipeline (the URL key) and a stable `id` UUID. Its aggregate state — `scheduled`, `running`, `passed`, `failed`, `canceled`, `skipped` — rolls up from the states of its jobs. These endpoints trigger a build, read it, cancel a running one, list its artifacts, and mint the short-lived token the browser uses to stream live logs. The jobs that make up a build live under [Jobs](/api/reference/jobs). {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Reference (/api/reference) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Jobs (/api/reference/jobs) A job is the unit of execution within a build — one node in the build's DAG, corresponding to a single `command` step. Jobs carry their own state, `step_key`, `command`, `exit_code`, and `depends_on` edges. These endpoints read a single job within a build and list a job's artifacts. Jobs are planned by the executor in topological order; you cannot create or cancel a job directly — operate on its [Build](/api/reference/builds) instead. {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Organizations (/api/reference/organizations) Organizations are the top-level container in Harmont. Every pipeline, build, and job lives under exactly one organization, addressed by an immutable `org_slug`. The endpoints below cover the full hierarchy: org → pipeline → build → job. URLs nest deeply on purpose. {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Pipelines (/api/reference/pipelines) A pipeline is a named CI definition inside an organization — the thing you push code against. Each pipeline owns its builds; its `pipeline_slug` is unique within the org. These endpoints list and create pipelines and fetch a single pipeline's record (including its `build_count`). To run one, create a build under it — see [Builds](/api/reference/builds). {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # User (/api/reference/user) User-scoped endpoints return information about the caller — currently the bound user record plus the primary organization. Future endpoints (token list, preferences, notification settings) will land here. {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Auth (/sdk/reference/auth) {/* Generated by docs-site/scripts/generate-sdk-docs.ts — do not edit. */} ### `cliClaim` [#cliclaim] `POST /api/v0/auth/cli/claim` Claim a transferred session token (CLI loopback poll) The CLI polls with the nonce it generated; on a match within the 60s window it receives the raw session token (single-use). ```ts import { cliClaim } from "@harmont/cloud"; ``` ```ts cliClaim(options): RequestResult ``` **Body** `CliClaimRequest` (optional) **Returns** `CliClaimResponse` See [`POST /api/v0/auth/cli/claim`](/api/reference/auth) for the full request and response schema. ### `cliCode` [#clicode] `POST /api/v0/auth/cli/code` Mint a human-typeable CLI paste code Mints a fresh session token for the current user and a short paste code (valid 5 minutes) the user re-types into the CLI to redeem it. ```ts import { cliCode } from "@harmont/cloud"; ``` ```ts cliCode(options): RequestResult ``` **Returns** `CliCodeResponse` See [`POST /api/v0/auth/cli/code`](/api/reference/auth) for the full request and response schema. ### `cliRedeem` [#cliredeem] `POST /api/v0/auth/cli/redeem` Redeem a CLI paste code for a session token The CLI submits the paste code the user typed in; on a match within the 5m window it receives the raw session token (single-use). ```ts import { cliRedeem } from "@harmont/cloud"; ``` ```ts cliRedeem(options): RequestResult ``` **Body** `CliRedeemRequest` (optional) **Returns** `CliRedeemResponse` See [`POST /api/v0/auth/cli/redeem`](/api/reference/auth) for the full request and response schema. ### `cliTransfer` [#clitransfer] `POST /api/v0/auth/cli/transfer` Hand a session token to a locally-running CLI (loopback) Mints a fresh session token for the current user and parks it under the CLI-supplied nonce for 60 seconds. The CLI claims it via the claim endpoint. ```ts import { cliTransfer } from "@harmont/cloud"; ``` ```ts cliTransfer(options): RequestResult ``` **Body** `CliTransferRequest` (optional) **Returns** `CliTransferResponse` See [`POST /api/v0/auth/cli/transfer`](/api/reference/auth) for the full request and response schema. ### `logout` [#logout] `POST /api/v0/auth/logout` Log out (revoke the current bearer token) Revokes the bearer token used for this request. The token can no longer be used to authenticate. Idempotent. ```ts import { logout } from "@harmont/cloud"; ``` ```ts logout(options): RequestResult ``` **Returns** `LogoutResponse` See [`POST /api/v0/auth/logout`](/api/reference/auth) for the full request and response schema. # Billing (/sdk/reference/billing) {/* Generated by docs-site/scripts/generate-sdk-docs.ts — do not edit. */} ### `getBillingBalance` [#getbillingbalance] `GET /api/v0/billing/balance/{org}` Get an organization's balance Returns the organization's current balance in cents — the sum of every ledger entry (credits positive, debits negative). May be negative. ```ts import { getBillingBalance } from "@harmont/cloud"; ``` ```ts getBillingBalance(options): RequestResult ``` | Parameter | In | Type | Description | | --------- | ---- | -------- | ---------------------- | | `org` | path | `string` | The organization slug. | **Returns** `GetBillingBalanceResponse` See [`GET /api/v0/billing/balance/{org}`](/api/reference/billing) for the full request and response schema. ### `getBillingUsage` [#getbillingusage] `GET /api/v0/billing/usage/{org}` Get an organization's VM usage Aggregates the organization's VM-lease usage over the half-open window `[from, to)` (both ISO-8601 timestamps): resource-seconds per dimension and the total billed cost in cents. Both `from` and `to` are required. ```ts import { getBillingUsage } from "@harmont/cloud"; ``` ```ts getBillingUsage(options): RequestResult ``` | Parameter | In | Type | Description | | --------- | ----- | -------- | ----------------------------------- | | `org` | path | `string` | The organization slug. | | `from` | query | `string` | Window start (inclusive), ISO-8601. | | `to` | query | `string` | Window end (exclusive), ISO-8601. | **Returns** `GetBillingUsageResponse` See [`GET /api/v0/billing/usage/{org}`](/api/reference/billing) for the full request and response schema. ### `getBillingUsageBreakdown` [#getbillingusagebreakdown] `GET /api/v0/billing/usage/{org}/breakdown` Per-build VM usage breakdown Returns the organization's VM usage over the half-open `[from, to)` window (both ISO-8601), grouped by build (newest first) and broken down per job lease — pipeline, build number, job, VM handle, resource shape, duration and cost — so a charge can be traced to its source. ```ts import { getBillingUsageBreakdown } from "@harmont/cloud"; ``` ```ts getBillingUsageBreakdown(options): RequestResult ``` | Parameter | In | Type | Description | | --------- | ----- | -------- | ---------------------------------- | | `org` | path | `string` | Organization slug. | | `from` | query | `string` | ISO-8601 window start (inclusive). | | `to` | query | `string` | ISO-8601 window end (exclusive). | **Returns** `GetBillingUsageBreakdownResponse` See [`GET /api/v0/billing/usage/{org}/breakdown`](/api/reference/billing) for the full request and response schema. ### `getBillingUsageSeries` [#getbillingusageseries] `GET /api/v0/billing/usage/{org}/series` Per-day usage time-series ```ts import { getBillingUsageSeries } from "@harmont/cloud"; ``` ```ts getBillingUsageSeries(options): RequestResult ``` | Parameter | In | Type | Description | | --------- | ----- | -------- | ---------------------------------- | | `org` | path | `string` | Organization slug. | | `from` | query | `string` | ISO-8601 window start (inclusive). | | `to` | query | `string` | ISO-8601 window end (exclusive). | **Returns** `GetBillingUsageSeriesResponse` See [`GET /api/v0/billing/usage/{org}/series`](/api/reference/billing) for the full request and response schema. ### `listBillingTransactions` [#listbillingtransactions] `GET /api/v0/billing/transactions/{org}` List an organization's ledger entries Returns the organization's ledger entries, newest first, cursor-paginated. ```ts import { listBillingTransactions } from "@harmont/cloud"; ``` ```ts listBillingTransactions(options): RequestResult ``` | Parameter | In | Type | Description | | --------- | ----- | -------- | --------------------------------------------------- | | `org` | path | `string` | The organization slug. | | `limit` | query | `number` | Page size (1–100, default 50). | | `cursor` | query | `string` | Opaque cursor from a previous page's `next_cursor`. | **Returns** `ListBillingTransactionsResponse` See [`GET /api/v0/billing/transactions/{org}`](/api/reference/billing) for the full request and response schema. # Builds (/sdk/reference/builds) {/* Generated by docs-site/scripts/generate-sdk-docs.ts — do not edit. */} ### `cancelBuild` [#cancelbuild] `PUT /api/v0/organizations/{org}/pipelines/{pipeline}/builds/{number}/cancel` Cancel a build Cancels an in-flight build in-process (transitions non-terminal jobs and tears down their sandboxes). Idempotent: cancelling an already-terminal build is a no-op. Returns the reloaded build with its updated state. ```ts import { cancelBuild } from "@harmont/cloud"; ``` ```ts cancelBuild(options): RequestResult ``` | Parameter | In | Type | Description | | ---------- | ---- | -------- | ---------------------- | | `org` | path | `string` | The organization slug. | | `pipeline` | path | `string` | The pipeline slug. | | `number` | path | `number` | The build number. | **Returns** `CancelBuildResponse` See [`PUT /api/v0/organizations/{org}/pipelines/{pipeline}/builds/{number}/cancel`](/api/reference/builds) for the full request and response schema. ### `createBuild` [#createbuild] `POST /api/v0/organizations/{org}/pipelines/{pipeline}/builds` Create a build Creates a build for the pipeline and starts execution in-process. When `pipeline_ir` is supplied the IR is materialised directly; when it is absent the engine renders the pipeline's IR in a sandbox VM first (rendering never happens on the API host). A manual build against a pipeline that disallows manual builds yields 403; an IR that fails to render/parse/plan yields 422 (the build row is created with its error fields set). ```ts import { createBuild } from "@harmont/cloud"; ``` ```ts createBuild(options): RequestResult ``` | Parameter | In | Type | Description | | ---------- | ---- | -------- | ---------------------- | | `org` | path | `string` | The organization slug. | | `pipeline` | path | `string` | The pipeline slug. | **Body** `CreateBuildRequest` (optional) **Returns** `CreateBuildResponse` See [`POST /api/v0/organizations/{org}/pipelines/{pipeline}/builds`](/api/reference/builds) for the full request and response schema. ### `createBuildBySource` [#createbuildbysource] `POST /api/v0/organizations/{org}/builds` Create a build by repo + source slug Creates a build by addressing the pipeline through its repo-natural identity (`repo_name` + `source_slug`) rather than the org-global slug. This is the `hm run` path. Resolution, manual-build gating, billing, and IR handling are otherwise identical to `createBuild`. A repo/source slug that matches no pipeline yields 404. ```ts import { createBuildBySource } from "@harmont/cloud"; ``` ```ts createBuildBySource(options): RequestResult ``` | Parameter | In | Type | Description | | --------- | ---- | -------- | ---------------------- | | `org` | path | `string` | The organization slug. | **Body** `CreateRepoBuildRequest` (optional) **Returns** `CreateBuildBySourceResponse` See [`POST /api/v0/organizations/{org}/builds`](/api/reference/builds) for the full request and response schema. ### `getBuild` [#getbuild] `GET /api/v0/organizations/{org}/pipelines/{pipeline}/builds/{number}` Get a build Returns the build identified by its pipeline-scoped number. An unknown number (or one in another pipeline) is reported as 404. ```ts import { getBuild } from "@harmont/cloud"; ``` ```ts getBuild(options): RequestResult ``` | Parameter | In | Type | Description | | ---------- | ---- | -------- | ---------------------- | | `org` | path | `string` | The organization slug. | | `pipeline` | path | `string` | The pipeline slug. | | `number` | path | `number` | The build number. | **Returns** `GetBuildResponse` See [`GET /api/v0/organizations/{org}/pipelines/{pipeline}/builds/{number}`](/api/reference/builds) for the full request and response schema. ### `getBuildLogToken` [#getbuildlogtoken] `GET /api/v0/organizations/{org}/pipelines/{pipeline}/builds/{number}/log-token` Mint a build-scoped log token Returns a short-lived (\~1 hour) HMAC token the SSE log stream accepts, scoped to this build. Pass it as the stream's `token` query parameter. ```ts import { getBuildLogToken } from "@harmont/cloud"; ``` ```ts getBuildLogToken(options): RequestResult ``` | Parameter | In | Type | Description | | ---------- | ---- | -------- | ---------------------- | | `org` | path | `string` | The organization slug. | | `pipeline` | path | `string` | The pipeline slug. | | `number` | path | `number` | The build number. | **Returns** `GetBuildLogTokenResponse` See [`GET /api/v0/organizations/{org}/pipelines/{pipeline}/builds/{number}/log-token`](/api/reference/builds) for the full request and response schema. ### `listBuilds` [#listbuilds] `GET /api/v0/organizations/{org}/pipelines/{pipeline}/builds` List a pipeline's builds Returns the pipeline's builds, newest first, paginated. ```ts import { listBuilds } from "@harmont/cloud"; ``` ```ts listBuilds(options): RequestResult ``` | Parameter | In | Type | Description | | ---------- | ----- | -------- | --------------------------------------------------- | | `org` | path | `string` | The organization slug. | | `pipeline` | path | `string` | The pipeline slug. | | `limit` | query | `number` | Page size (1–100, default 50). | | `cursor` | query | `string` | Opaque cursor from a previous page's `next_cursor`. | **Returns** `ListBuildsResponse` See [`GET /api/v0/organizations/{org}/pipelines/{pipeline}/builds`](/api/reference/builds) for the full request and response schema. # Reference (/sdk/reference) {/* Generated by docs-site/scripts/generate-sdk-docs.ts — do not edit. */} One function per public endpoint, grouped by tag. Each shows the import, the call signature, parameters, and a link to the full schema in the [API reference](/api/reference). * [Auth](/sdk/reference/auth) * [Billing](/sdk/reference/billing) * [Builds](/sdk/reference/builds) * [Jobs](/sdk/reference/jobs) * [Organizations](/sdk/reference/organizations) * [Pipelines](/sdk/reference/pipelines) * [User](/sdk/reference/user) # Jobs (/sdk/reference/jobs) {/* Generated by docs-site/scripts/generate-sdk-docs.ts — do not edit. */} ### `getJob` [#getjob] `GET /api/v0/organizations/{org}/pipelines/{pipeline}/builds/{number}/jobs/{job_id}` Get a job Returns a single job within the build. A `job_id` that belongs to another build is reported as 404. ```ts import { getJob } from "@harmont/cloud"; ``` ```ts getJob(options): RequestResult ``` | Parameter | In | Type | Description | | ---------- | ---- | -------- | ---------------------- | | `org` | path | `string` | The organization slug. | | `pipeline` | path | `string` | The pipeline slug. | | `number` | path | `number` | The build number. | | `job_id` | path | `string` | The job id. | **Returns** `GetJobResponse` See [`GET /api/v0/organizations/{org}/pipelines/{pipeline}/builds/{number}/jobs/{job_id}`](/api/reference/jobs) for the full request and response schema. ### `listJobs` [#listjobs] `GET /api/v0/organizations/{org}/pipelines/{pipeline}/builds/{number}/jobs` List a build's jobs Returns the build's jobs in DAG creation order. ```ts import { listJobs } from "@harmont/cloud"; ``` ```ts listJobs(options): RequestResult ``` | Parameter | In | Type | Description | | ---------- | ---- | -------- | ---------------------- | | `org` | path | `string` | The organization slug. | | `pipeline` | path | `string` | The pipeline slug. | | `number` | path | `number` | The build number. | **Returns** `ListJobsResponse` See [`GET /api/v0/organizations/{org}/pipelines/{pipeline}/builds/{number}/jobs`](/api/reference/jobs) for the full request and response schema. # Organizations (/sdk/reference/organizations) {/* Generated by docs-site/scripts/generate-sdk-docs.ts — do not edit. */} ### `acceptInvite` [#acceptinvite] `POST /api/v0/invites/accept` Accept an invite ```ts import { acceptInvite } from "@harmont/cloud"; ``` ```ts acceptInvite(options): RequestResult ``` **Body** `AcceptInviteRequest` (optional) **Returns** `AcceptInviteResponse` See [`POST /api/v0/invites/accept`](/api/reference/organizations) for the full request and response schema. ### `createInvite` [#createinvite] `POST /api/v0/organizations/{org}/invites` Invite an email to the organization ```ts import { createInvite } from "@harmont/cloud"; ``` ```ts createInvite(options): RequestResult ``` | Parameter | In | Type | Description | | --------- | ---- | -------- | ----------- | | `org` | path | `string` | — | **Body** `CreateInviteRequest` (optional) **Returns** `CreateInviteResponse` See [`POST /api/v0/organizations/{org}/invites`](/api/reference/organizations) for the full request and response schema. ### `createOrganization` [#createorganization] `POST /api/v0/organizations` Create an organization Creates a new organization with the authenticated user as its owner. ```ts import { createOrganization } from "@harmont/cloud"; ``` ```ts createOrganization(options): RequestResult ``` **Body** `CreateOrganizationRequest` (optional) **Returns** `CreateOrganizationResponse` See [`POST /api/v0/organizations`](/api/reference/organizations) for the full request and response schema. ### `listInvites` [#listinvites] `GET /api/v0/organizations/{org}/invites` List pending invites ```ts import { listInvites } from "@harmont/cloud"; ``` ```ts listInvites(options): RequestResult ``` | Parameter | In | Type | Description | | --------- | ---- | -------- | ----------- | | `org` | path | `string` | — | **Returns** `ListInvitesResponse` See [`GET /api/v0/organizations/{org}/invites`](/api/reference/organizations) for the full request and response schema. ### `listOrganizations` [#listorganizations] `GET /api/v0/organizations` List the current user's organizations Returns the organizations the authenticated user is a member of, paginated. ```ts import { listOrganizations } from "@harmont/cloud"; ``` ```ts listOrganizations(options): RequestResult ``` | Parameter | In | Type | Description | | --------- | ----- | -------- | --------------------------------------------------- | | `limit` | query | `number` | Page size (1–100, default 50). | | `cursor` | query | `string` | Opaque cursor from a previous page's `next_cursor`. | **Returns** `ListOrganizationsResponse` See [`GET /api/v0/organizations`](/api/reference/organizations) for the full request and response schema. ### `listOrgMembers` [#listorgmembers] `GET /api/v0/organizations/{org}/members` List organization members ```ts import { listOrgMembers } from "@harmont/cloud"; ``` ```ts listOrgMembers(options): RequestResult ``` | Parameter | In | Type | Description | | --------- | ---- | -------- | ----------- | | `org` | path | `string` | — | **Returns** `ListOrgMembersResponse` See [`GET /api/v0/organizations/{org}/members`](/api/reference/organizations) for the full request and response schema. ### `removeOrgMember` [#removeorgmember] `DELETE /api/v0/organizations/{org}/members/{user_id}` Remove a member ```ts import { removeOrgMember } from "@harmont/cloud"; ``` ```ts removeOrgMember(options): RequestResult ``` | Parameter | In | Type | Description | | --------- | ---- | -------- | ----------- | | `org` | path | `string` | — | | `user_id` | path | `string` | — | **Returns** `RemoveOrgMemberResponse` See [`DELETE /api/v0/organizations/{org}/members/{user_id}`](/api/reference/organizations) for the full request and response schema. ### `revokeInvite` [#revokeinvite] `DELETE /api/v0/organizations/{org}/invites/{id}` Revoke a pending invite ```ts import { revokeInvite } from "@harmont/cloud"; ``` ```ts revokeInvite(options): RequestResult ``` | Parameter | In | Type | Description | | --------- | ---- | -------- | ----------- | | `org` | path | `string` | — | | `id` | path | `string` | — | **Returns** `RevokeInviteResponse` See [`DELETE /api/v0/organizations/{org}/invites/{id}`](/api/reference/organizations) for the full request and response schema. ### `updateOrgMember` [#updateorgmember] `PATCH /api/v0/organizations/{org}/members/{user_id}` Change a member's role ```ts import { updateOrgMember } from "@harmont/cloud"; ``` ```ts updateOrgMember(options): RequestResult ``` | Parameter | In | Type | Description | | --------- | ---- | -------- | ----------- | | `org` | path | `string` | — | | `user_id` | path | `string` | — | **Body** `UpdateMemberRoleRequest` (optional) **Returns** `UpdateOrgMemberResponse` See [`PATCH /api/v0/organizations/{org}/members/{user_id}`](/api/reference/organizations) for the full request and response schema. # Pipelines (/sdk/reference/pipelines) {/* Generated by docs-site/scripts/generate-sdk-docs.ts — do not edit. */} ### `createPipeline` [#createpipeline] `POST /api/v0/organizations/{org}/pipelines` Create a pipeline Creates a pipeline in the organization. The slug is derived from the name; a colliding slug within the organization yields 422. ```ts import { createPipeline } from "@harmont/cloud"; ``` ```ts createPipeline(options): RequestResult ``` | Parameter | In | Type | Description | | --------- | ---- | -------- | ---------------------- | | `org` | path | `string` | The organization slug. | **Body** `CreatePipelineRequest` (optional) **Returns** `CreatePipelineResponse` See [`POST /api/v0/organizations/{org}/pipelines`](/api/reference/pipelines) for the full request and response schema. ### `getPipeline` [#getpipeline] `GET /api/v0/organizations/{org}/pipelines/{pipeline}` Get a pipeline Returns the pipeline identified by the path slug within the organization. An unknown slug (or one in another organization) is reported as 404. ```ts import { getPipeline } from "@harmont/cloud"; ``` ```ts getPipeline(options): RequestResult ``` | Parameter | In | Type | Description | | ---------- | ---- | -------- | ---------------------- | | `org` | path | `string` | The organization slug. | | `pipeline` | path | `string` | The pipeline slug. | **Returns** `GetPipelineResponse` See [`GET /api/v0/organizations/{org}/pipelines/{pipeline}`](/api/reference/pipelines) for the full request and response schema. ### `listPipelines` [#listpipelines] `GET /api/v0/organizations/{org}/pipelines` List an organization's pipelines Returns the organization's non-archived pipelines, paginated. A slug the user cannot access is reported as 404. ```ts import { listPipelines } from "@harmont/cloud"; ``` ```ts listPipelines(options): RequestResult ``` | Parameter | In | Type | Description | | --------- | ----- | -------- | --------------------------------------------------- | | `org` | path | `string` | The organization slug. | | `limit` | query | `number` | Page size (1–100, default 50). | | `cursor` | query | `string` | Opaque cursor from a previous page's `next_cursor`. | **Returns** `ListPipelinesResponse` See [`GET /api/v0/organizations/{org}/pipelines`](/api/reference/pipelines) for the full request and response schema. # User (/sdk/reference/user) {/* Generated by docs-site/scripts/generate-sdk-docs.ts — do not edit. */} ### `createApiToken` [#createapitoken] `POST /api/v0/user/api-tokens` Create a personal API key Returns the raw secret in the response body. It is shown only once and cannot be retrieved later. ```ts import { createApiToken } from "@harmont/cloud"; ``` ```ts createApiToken(options): RequestResult ``` **Body** `ApiTokenCreateRequest` (optional) **Returns** `CreateApiTokenResponse` See [`POST /api/v0/user/api-tokens`](/api/reference/user) for the full request and response schema. ### `deleteCurrentUser` [#deletecurrentuser] `DELETE /api/v0/user` Delete the current user's account ```ts import { deleteCurrentUser } from "@harmont/cloud"; ``` ```ts deleteCurrentUser(options): RequestResult ``` **Returns** `DeleteCurrentUserResponse` See [`DELETE /api/v0/user`](/api/reference/user) for the full request and response schema. ### `getCurrentUser` [#getcurrentuser] `GET /api/v0/user` Get the current authenticated user Returns the bearer-authenticated user and their personal-organization slug. ```ts import { getCurrentUser } from "@harmont/cloud"; ``` ```ts getCurrentUser(options): RequestResult ``` **Returns** `GetCurrentUserResponse` See [`GET /api/v0/user`](/api/reference/user) for the full request and response schema. ### `listApiTokens` [#listapitokens] `GET /api/v0/user/api-tokens` List the current user's API keys ```ts import { listApiTokens } from "@harmont/cloud"; ``` ```ts listApiTokens(options): RequestResult ``` **Returns** `ListApiTokensResponse` See [`GET /api/v0/user/api-tokens`](/api/reference/user) for the full request and response schema. ### `revokeApiToken` [#revokeapitoken] `DELETE /api/v0/user/api-tokens/{id}` Revoke one of the current user's API keys ```ts import { revokeApiToken } from "@harmont/cloud"; ``` ```ts revokeApiToken(options): RequestResult ``` | Parameter | In | Type | Description | | --------- | ---- | -------- | --------------- | | `id` | path | `string` | The API key id. | **Returns** `RevokeApiTokenResponse` See [`DELETE /api/v0/user/api-tokens/{id}`](/api/reference/user) for the full request and response schema. ### `updateCurrentUser` [#updatecurrentuser] `PATCH /api/v0/user` Update the current user's display name ```ts import { updateCurrentUser } from "@harmont/cloud"; ``` ```ts updateCurrentUser(options): RequestResult ``` **Body** `UserUpdateRequest` (optional) **Returns** `UpdateCurrentUserResponse` See [`PATCH /api/v0/user`](/api/reference/user) for the full request and response schema. # Cache policies (/pipeline-sdk/reference/cache) {/* Generated by docs-site/scripts/generate-dsl-docs.ts — do not edit. */} ## `CacheCompose` [#cachecompose] Combine multiple policies. Cache hits ONLY when every sub-policy hits. Useful for "rebuild daily OR when these files change": CacheCompose(policies=( CacheTTL(duration=timedelta(days=1)), CacheOnChange(paths=("api/cabal.project",)), )) ### Fields [#fields] | Field | Type | Default | | ---------- | ------------------------- | ---------- | | `policies` | `tuple[CachePolicy, ...]` | *required* | ## `CacheForever` [#cacheforever] Cache forever, keyed only on (command, parent, env\_keys). Use for pure computations whose only inputs are visible to the planner. DO NOT use for installs that fetch the public internet — package repos drift; manual cache busts will be needed. ### Fields [#fields-1] | Field | Type | Default | | ---------- | ----------------- | ------- | | `env_keys` | `tuple[str, ...]` | `()` | ## `CacheNone` [#cachenone] Always run the step; never cache its snapshot. Equivalent to today's behavior. Default for command steps. ## `CacheOnChange` [#cacheonchange] Rebuild whenever any file under `paths` changes. Paths are relative to the source-archive root. File hashes are computed at render time by `harmont.keygen` (paths are read from the source archive's checkout root). No `env_keys` field — file content already covers the invalidation surface. ### Fields [#fields-2] | Field | Type | Default | | ------- | ----------------- | ---------- | | `paths` | `tuple[str, ...]` | *required* | ## `CachePolicy` [#cachepolicy] Base — never instantiate directly. Use the helpers below. ## `CacheTTL` [#cachettl] Cache for `duration`; refresh once per window (UTC-midnight floored). Two builds within the same UTC day share a key; a build at 00:30 UTC the next day rebuilds. ### Fields [#fields-3] | Field | Type | Default | | ---------- | ----------------- | ---------- | | `duration` | `timedelta` | *required* | | `env_keys` | `tuple[str, ...]` | `()` | ## `compose` [#compose] Combine multiple cache policies: hit only when every sub-policy hits. Use to express compound invalidation conditions such as "rebuild daily OR when these files change". ```python compose(*policies) -> CacheCompose ``` | Parameter | Type | Default | Description | | ---------- | ------------- | ------- | ----------- | | `policies` | `CachePolicy` | `()` | — | **Returns** `CacheCompose` — A `CacheCompose` policy for use in `.sh(cache=...)`. **Examples** ```python >>> from datetime import timedelta >>> import harmont as hm >>> policy = hm.compose( ... hm.ttl(timedelta(days=1)), ... hm.on_change("api/cabal.project"), ... ) ``` ## `forever` [#forever] Create a permanent cache policy. The step's snapshot is reused indefinitely, keyed on (command, parent, env\_keys). Suitable for deterministic installs where the command string itself encodes the version (e.g. downloading a pinned binary). Do not use for steps that fetch mutable remote resources. ```python forever(env_keys=()) -> CacheForever ``` | Parameter | Type | Default | Description | | ------------------------------------------------------------- | ----------------- | ------- | ------------------------------------------------------- | | `env_keys` | `tuple[str, ...]` | `()` | Environment variable names whose values are folded into | | the cache key. Use this when the command's behavior varies by | | | | | environment (e.g. `GOARCH`). | | | | **Returns** `CacheForever` — A `CacheForever` policy for use in `.sh(cache=...)`. **Examples** ```python >>> import harmont as hm >>> step = hm.sh("curl .../go1.23.tar.gz | tar ...", cache=hm.forever()) ``` ## `on_change` [#on_change] Create a content-addressed cache policy keyed on file hashes. The step's snapshot is reused until any file under `paths` changes. Paths are relative to the source-archive root and resolved at render time by the key generator. ```python on_change(*paths) -> CacheOnChange ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `paths` | `str` | `()` | — | **Returns** `CacheOnChange` — A `CacheOnChange` policy for use in `.sh(cache=...)`. **Examples** ```python >>> import harmont as hm >>> step = hm.sh("pip install -r requirements.txt", ... cache=hm.on_change("requirements.txt")) ``` ## `ttl` [#ttl] Create a time-to-live cache policy. The step's snapshot is reused until `duration` has elapsed since the last successful run, floored to UTC midnight. Two builds within the same UTC day share a cache key; a build the following day rebuilds. ```python ttl(duration) -> CacheTTL ``` | Parameter | Type | Default | Description | | ---------- | ----------- | ---------- | ----------------------------------------- | | `duration` | `timedelta` | *required* | How long the cached result remains valid. | **Returns** `CacheTTL` — A `CacheTTL` policy for use in `.sh(cache=...)`. **Examples** ```python >>> from datetime import timedelta >>> import harmont as hm >>> step = hm.sh("apt-get update", cache=hm.ttl(timedelta(days=1))) ``` # Chains & steps (/pipeline-sdk/reference/chains) {/* Generated by docs-site/scripts/generate-dsl-docs.ts — do not edit. */} ## `group` [#group] Collect a list of steps into a tuple for use as a target return value. `pipeline()` and `@pipeline` both accept a tuple of leaves. `group()` converts a list to that tuple for convenience. ```python group(steps) -> tuple[Step, ...] ``` | Parameter | Type | Default | Description | | --------- | -------------------------------- | ---------- | -------------------------- | | `steps` | `list[Step] \| tuple[Step, ...]` | *required* | The leaf steps to collect. | **Returns** `tuple[Step, ...]` — A tuple of the input steps. **Examples** ```python >>> import harmont as hm >>> proj = hm.rust.project() >>> leaves = hm.group([proj.test(), proj.clippy(), proj.fmt()]) ``` ## `scratch` [#scratch] Create a new root step with no command. Use as the starting point for a chain, or call `sh()` at the module level to combine `scratch()` and `.sh()` in one call. ```python scratch() -> Step ``` **Returns** `Step` — A new root `Step` with no command or parent. **Examples** ```python >>> import harmont as hm >>> step = hm.scratch().sh("echo hello") ``` ## `sh` [#sh] Start a chain with a single shell command. Shorthand for `scratch().sh(cmd, ...)`. All keyword arguments are forwarded to `Step.sh`. ```python sh(cmd, *, cwd=None, label=None, cache=None, env=None, timeout_seconds=None, image=None, key=None) -> Step ``` | Parameter | Type | Default | Description | | ----------------- | ------------------------ | ---------- | ------------------------------------------------------------------- | | `cmd` | `str` | *required* | Shell command to run. | | `cwd` | `str \| None` | `None` | Directory to run in, relative to the workspace root. Omit to | | run in the root. | | | | | `label` | `str \| None` | `None` | Human-facing label shown in the UI. Defaults to the command. | | `cache` | `CachePolicy \| None` | `None` | Cache policy controlling result reuse across builds. | | `env` | `dict[str, str] \| None` | `None` | Per-step environment variables merged on top of pipeline-level env. | | `timeout_seconds` | `int \| None` | `None` | Hard wall-clock timeout in seconds. | | `image` | `str \| None` | `None` | Local-mode Docker base image override for this step. | | `key` | `str \| None` | `None` | Manual key override for this step in the v0 IR. | **Returns** `Step` — A new root `Step` with the command set. **Examples** ```python >>> import harmont as hm >>> step = hm.sh("cargo build") ``` ## `Step` [#step] Immutable chain node — the primitive the pipeline SDK is built on. Steps are constructed via `scratch()` or `wait()` and extended by calling `.sh()` or `.fork()` on the result. Every mutating method returns a new `Step`; the receiver is unchanged. ### Fields [#fields] | Field | Type | Default | | --------------------- | ------------------------ | ------- | | `cmd` | `str \| None` | `None` | | `parent` | `Step \| None` | `None` | | `is_wait` | `bool` | `False` | | `continue_on_failure` | `bool` | `False` | | `label` | `str \| None` | `None` | | `cache` | `CachePolicy \| None` | `None` | | `env` | `dict[str, str] \| None` | `None` | | `timeout_seconds` | `int \| None` | `None` | | `image` | `str \| None` | `None` | | `runner` | `str \| None` | `None` | | `runner_args` | `dict[str, Any] \| None` | `None` | | `key_override` | `str \| None` | `None` | ### `Step.fork()` [#stepfork] ```python fork(label=None) -> Step ``` Create a branch point from this step. Returns a new scratch-rooted `Step` whose parent is `self`. Downstream `.sh()` calls on the fork produce independent leaves that all share `self` as their nearest emitted ancestor. | Parameter | Type | Default | Description | | --------- | ------------- | ------- | ------------------------------------------- | | `label` | `str \| None` | `None` | Optional label for the fork node in the UI. | **Returns** `Step` — A new `Step` branching from this one. ### `Step.sh()` [#stepsh] ```python sh(cmd, *, cwd=None, label=None, cache=None, env=None, timeout_seconds=None, image=None, runner=None, runner_args=None, key=None) -> Step ``` Append a shell command to this chain. Returns a new `Step`; the receiver is unchanged (steps are immutable). | Parameter | Type | Default | Description | | ----------------------------------------------------------------- | ------------------------ | ---------- | --------------------------------------------------------------- | | `cmd` | `str` | *required* | Shell command to run. | | `cwd` | `str \| None` | `None` | Directory to run in, relative to the workspace root. Omit to | | run in the root; pass a non-empty path to change directory first. | | | | | `label` | `str \| None` | `None` | Human-facing label shown in the UI. Defaults to the command. | | `cache` | `CachePolicy \| None` | `None` | Cache policy controlling result reuse across builds. | | `env` | `dict[str, str] \| None` | `None` | Per-step environment variables, merged on top of pipeline-level | | env at render time. | | | | | `timeout_seconds` | `int \| None` | `None` | Hard wall-clock timeout for the step. The executor | | kills the process after this many seconds. | | | | | `image` | `str \| None` | `None` | Local-mode Docker base image for this step. Ignored when the | | step has a `builds_in` parent (the parent's snapshot wins). | | | | | `runner` | `str \| None` | `None` | Executor plugin runner name. `None` selects the default | | Docker runner. | | | | | `runner_args` | `dict[str, Any] \| None` | `None` | Plugin-specific arguments validated by the runner's | | schema. | | | | | `key` | `str \| None` | `None` | Manual key override for this step in the v0 IR. Auto-derived | | from the command when omitted. | | | | **Returns** `Step` — A new `Step` with this command appended to the chain. ## `target` [#target] Mark a function as a reusable, memoized pipeline building block. The wrapped function may declare dependencies as parameters; each parameter name is resolved against the global target registry (pytest-fixture style). The return value is memoized per render so targets calling other targets dedup correctly. ```python target(*, name=None) -> Callable[[Callable[..., Any]], Callable[[], Any]] ``` | Parameter | Type | Default | Description | | ------------------------------------------------------------- | ------------- | ------- | ------------------------------------------------------- | | `name` | `str \| None` | `None` | Registry key for this target. Defaults to the decorated | | function's name. Override when the name collides with another | | | | | target or a more human-readable key is preferred. | | | | **Returns** `Callable[[Callable[..., Any]], Callable[[], Any]]` — A decorator that registers and memoizes the wrapped function. **Examples** ```python >>> import harmont as hm >>> @hm.target() ... def apt_base() -> hm.Step: ... return hm.sh("apt-get update") ``` ## `wait` [#wait] Insert a synchronization barrier between pipeline stages. All steps emitted before the barrier must finish before any step emitted after it starts. Equivalent to Buildkite's `wait` step. ```python wait(*, continue_on_failure=False) -> Step ``` | Parameter | Type | Default | Description | | ------------------------------------------------------------ | ------ | ------- | --------------------------------------- | | `continue_on_failure` | `bool` | `False` | When `True`, the barrier passes even if | | upstream steps have failed, allowing cleanup or notification | | | | | steps to run. | | | | **Returns** `Step` — A `Step` that lowers to a wait barrier in the v0 IR. **Examples** ```python >>> import harmont as hm >>> p = hm.pipeline(hm.sh("make build"), hm.wait(), hm.sh("make deploy")) ``` # Reference (/pipeline-sdk/reference) {/* Generated by docs-site/scripts/generate-dsl-docs.ts — do not edit. */} The complete public surface of the `harmont` package, generated from the source. * [Cache policies](/pipeline-sdk/reference/cache) * [Chains & steps](/pipeline-sdk/reference/chains) * [Pipeline](/pipeline-sdk/reference/pipeline) * [Triggers](/pipeline-sdk/reference/triggers) * [Toolchains](/pipeline-sdk/reference/toolchains) # Pipeline (/pipeline-sdk/reference/pipeline) {/* Generated by docs-site/scripts/generate-dsl-docs.ts — do not edit. */} ## `dump_registry_json` [#dump_registry_json] Emit the schema\_version=1 envelope JSON. Defaults mirror `pipeline_to_json`: `pipeline_org` \<- `env["HARMONT_PIPELINE_ORG"]` or `"default"` `now` \<- `int(time.time())` `base_path` \<- `Path.cwd()` (resolves `on_change` cache paths) `env` \<- `os.environ` Per-pipeline slug is read from each registration. The target memoization cache is cleared at the start of each render so per-pipeline target invocations dedup within a single render but don't leak across renders. The named-target registry is left intact so pipeline fixture-style params can resolve their dependencies. ```python dump_registry_json(*, pipeline_org=None, now=None, base_path=None, env=None) -> str ``` | Parameter | Type | Default | Description | | -------------- | --------------------------- | ------- | ----------- | | `pipeline_org` | `str \| None` | `None` | — | | `now` | `int \| None` | `None` | — | | `base_path` | `Path \| None` | `None` | — | | `env` | `Mapping[str, str] \| None` | `None` | — | **Returns** `str` ## `pipeline` [#pipeline] Build a v0 IR dict or register a pipeline function. This function is polymorphic based on the type of its positional arguments. Factory form — every positional is a `Step`: pipeline(\*leaves, env=None, default\_image=None) -> dict Decorator form — no positionals or a string slug: @pipeline(slug=None, \*, name=None, triggers=(), allow\_manual=True, env=None, default\_image=None) def my\_pipeline() -> Step: ... The decorator registers the wrapped function in the module-level pipeline registry (HAR-9). The discriminant is the type of the positional arguments: any non-`Step` positional (including a string slug, or no positional at all) routes to the decorator path. ```python pipeline(*args, **kwargs) -> Any ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `args` | `Any` | `()` | — | | `kwargs` | `Any` | `{}` | — | **Returns** `Any` — A v0 IR `dict` in factory form, or a decorator in decorator form. ## `pipeline_to_json` [#pipeline_to_json] Convenience re-export so callers can do `harmont.pipeline_to_json(pipeline(...))` without importing `json_emit` directly. See `json_emit.pipeline_to_json` for kwargs. ```python pipeline_to_json(p, **kw) -> str ``` | Parameter | Type | Default | Description | | --------- | ---------------- | ---------- | ----------- | | `p` | `dict[str, Any]` | *required* | — | | `kw` | `Any` | `{}` | — | **Returns** `str` # Triggers (/pipeline-sdk/reference/triggers) {/* Generated by docs-site/scripts/generate-dsl-docs.ts — do not edit. */} ## `pr` [#pr] Trigger on a GitHub pull\_request event. `branches` filters by the PR's *target* branch. `types` selects PR-action keywords; defaults to opened/synchronize/reopened (mirrors GHA). ```python pr(branches=None, types=None) -> PullRequestTrigger ``` | Parameter | Type | Default | Description | | ---------- | --------------------------------------------- | ------- | ----------- | | `branches` | `str \| list[str] \| tuple[str, ...] \| None` | `None` | — | | `types` | `list[str] \| tuple[str, ...] \| None` | `None` | — | **Returns** `PullRequestTrigger` ## `pull_request` [#pull_request] Trigger on a GitHub pull\_request event. `branches` filters by the PR's *target* branch. `types` selects PR-action keywords; defaults to opened/synchronize/reopened (mirrors GHA). ```python pull_request(branches=None, types=None) -> PullRequestTrigger ``` | Parameter | Type | Default | Description | | ---------- | --------------------------------------------- | ------- | ----------- | | `branches` | `str \| list[str] \| tuple[str, ...] \| None` | `None` | — | | `types` | `list[str] \| tuple[str, ...] \| None` | `None` | — | **Returns** `PullRequestTrigger` ## `push` [#push] Trigger on a git push. Pass exactly one of `branch` or `tag`. Each is a glob or list of globs (`*` matches any chars including `/`; `?` matches one char). ```python push(branch=None, tag=None) -> PushTrigger ``` | Parameter | Type | Default | Description | | --------- | --------------------------------------------- | ------- | ----------- | | `branch` | `str \| list[str] \| tuple[str, ...] \| None` | `None` | — | | `tag` | `str \| list[str] \| tuple[str, ...] \| None` | `None` | — | **Returns** `PushTrigger` ## `schedule` [#schedule] Trigger on a UTC cron schedule. `cron` is a five-field crontab expression (minute hour day month dow). Always interpreted as UTC. ```python schedule(cron) -> ScheduleTrigger ``` | Parameter | Type | Default | Description | | --------- | ----- | ---------- | ----------- | | `cron` | `str` | *required* | — | **Returns** `ScheduleTrigger` # Base images (/pipeline-sdk/reference/toolchains/base) {/* Generated by docs-site/scripts/generate-dsl-docs.ts — do not edit. */} ## `apt_base` [#apt_base] Create a standalone apt-base step sharable across toolchains. Emits `apt-get update && apt-get install -y \` with a daily TTL cache. Pass the returned step as `base=` to any toolchain constructor to share one apt-base across multiple toolchains. ```python apt_base(*, packages, image=None, label=':apt: base') -> Step ``` | Parameter | Type | Default | Description | | ---------- | ----------------- | -------------- | ---------------------------------------------------- | | `packages` | `tuple[str, ...]` | *required* | apt package names to install. | | `image` | `str \| None` | `None` | Local-mode Docker base image override for this step. | | `label` | `str` | `':apt: base'` | Human-facing label shown in the UI. | **Returns** `Step` — A `Step` that installs the given apt packages. **Examples** ```python >>> import harmont as hm >>> base = hm.apt_base(packages=("git", "curl")) >>> tc = hm.rust.toolchain(base=base) ``` ## `BaseImage` [#baseimage] Create a `BaseImage` annotation marker for a target parameter. Use as `Annotated[Step, BaseImage("ubuntu-24.04")]` on a parameter of a `@hm.target()` function. The runtime decorator injects a scratch-rooted `Step` with the given image set as the parameter value. The first `.sh()` call on that step inherits the image, so the first emitted IR step carries `image` in the v0 wire format. ```python BaseImage(image) -> _BaseImageMarker ``` | Parameter | Type | Default | Description | | --------- | ----- | ---------- | ------------------------------------------------------ | | `image` | `str` | *required* | Non-empty Docker image string (e.g. `"ubuntu-24.04"`). | **Returns** `_BaseImageMarker` — A `_BaseImageMarker` for use in `Annotated[Step, ...]`. **Examples** ```python >>> import harmont as hm >>> from typing import Annotated >>> @hm.target() ... def my_target(base: Annotated[hm.Step, hm.BaseImage("ubuntu-24.04")]) -> hm.Step: ... return base.sh("apt-get update") ``` # CMake (/pipeline-sdk/reference/toolchains/cmake) {/* Generated by docs-site/scripts/generate-dsl-docs.ts — do not edit. */} ## `cmake` [#cmake] Callable singleton for the CMake toolchain — access as `hm.cmake`. Call directly to construct a `CMakeProject`, or use the bare-form action methods (`cmake.build()`, `cmake.test()`, etc.) for a one-shot leaf. ```python cmake(*, path='.', lang='c', image=None, base=None) -> CMakeProject ``` | Parameter | Type | Default | Description | | ------------------------------------------------ | -------------- | ------- | -------------------------------------------------------- | | `path` | `str` | `'.'` | Path to the project root (where `CMakeLists.txt` lives). | | `lang` | `str` | `'c'` | Language tag, either `"c"` or `"cpp"`. Affects label | | prefixes only; the cmake commands are identical. | | | | | `image` | `str \| None` | `None` | Local-mode Docker base image override. | | `base` | `Step \| None` | `None` | Existing `Step` to attach to instead of emitting a fresh | | apt-base step. | | | | **Returns** `CMakeProject` — A `CMakeProject` ready for action methods. ### `cmake.build()` [#cmakebuild] ```python build(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `cmake.configure()` [#cmakeconfigure] ```python configure(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `cmake.fmt()` [#cmakefmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `cmake.test()` [#cmaketest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `CMakeEntry` [#cmakeentry] Callable singleton for the CMake toolchain — access as `hm.cmake`. Call directly to construct a `CMakeProject`, or use the bare-form action methods (`cmake.build()`, `cmake.test()`, etc.) for a one-shot leaf. ### `CMakeEntry.build()` [#cmakeentrybuild] ```python build(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `CMakeEntry.configure()` [#cmakeentryconfigure] ```python configure(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `CMakeEntry.fmt()` [#cmakeentryfmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `CMakeEntry.test()` [#cmakeentrytest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `CMakeProject` [#cmakeproject] CMake (C/C++) project install chain — constructed via `hm.cmake()`. `installed` is the cmake-verify step. Action methods (`configure`, `build`, `test`, `fmt`) attach leaves to `installed`. ### Fields [#fields] | Field | Type | Default | | ----------- | ------ | ---------- | | `path` | `str` | *required* | | `installed` | `Step` | *required* | ### `CMakeProject.build()` [#cmakeprojectbuild] ```python build(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `CMakeProject.configure()` [#cmakeprojectconfigure] ```python configure(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `CMakeProject.fmt()` [#cmakeprojectfmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `CMakeProject.test()` [#cmakeprojecttest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` # Composer (/pipeline-sdk/reference/toolchains/composer) {/* Generated by docs-site/scripts/generate-dsl-docs.ts — do not edit. */} ## `composer` [#composer] Callable singleton for the Composer toolchain — access as `hm.composer`. Call directly to construct a `ComposerProject`, or use the bare-form action methods (`composer.test()`, `composer.lint()`) for a one-shot leaf. ```python composer(*, path='.', laravel=False, image=None, base=None) -> ComposerProject ``` | Parameter | Type | Default | Description | | --------------------------------------------------- | -------------- | ------- | -------------------------------------------------------- | | `path` | `str` | `'.'` | Path to the PHP project root (must contain a | | `composer.lock`). | | | | | `laravel` | `bool` | `False` | When `True`, uses `php artisan test` for `.test()` | | and sets the label prefix to `:laravel:` instead of | | | | | `:php:`. | | | | | `image` | `str \| None` | `None` | Local-mode Docker base image override. | | `base` | `Step \| None` | `None` | Existing `Step` to attach to instead of emitting a fresh | | apt-base step. | | | | **Returns** `ComposerProject` — A `ComposerProject` whose `installed` step is `composer install`. ### `composer.lint()` [#composerlint] ```python lint(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `composer.test()` [#composertest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `ComposerEntry` [#composerentry] Callable singleton for the Composer toolchain — access as `hm.composer`. Call directly to construct a `ComposerProject`, or use the bare-form action methods (`composer.test()`, `composer.lint()`) for a one-shot leaf. ### `ComposerEntry.lint()` [#composerentrylint] ```python lint(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `ComposerEntry.test()` [#composerentrytest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `ComposerProject` [#composerproject] Composer (PHP/Laravel) project install chain — constructed via `hm.composer()`. `installed` is the `composer install` step. Action methods (`test`, `lint`) attach leaves to `installed`. ### Fields [#fields] | Field | Type | Default | | ----------- | ------ | ---------- | | `path` | `str` | *required* | | `installed` | `Step` | *required* | ### `ComposerProject.lint()` [#composerprojectlint] ```python lint(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `ComposerProject.test()` [#composerprojecttest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` # Dotnet (/pipeline-sdk/reference/toolchains/dotnet) {/* Generated by docs-site/scripts/generate-dsl-docs.ts — do not edit. */} ## `dotnet` [#dotnet] Callable singleton for the dotnet toolchain — access as `hm.dotnet`. Call directly to construct a `DotnetProject`, or use the bare-form action methods (`dotnet.build()`, `dotnet.test()`, etc.) for a one-shot leaf. ```python dotnet(*, path='.', channel='8.0', image=None, base=None) -> DotnetProject ``` | Parameter | Type | Default | Description | | --------------------------------------------------- | -------------- | ------- | -------------------------------------------------------- | | `path` | `str` | `'.'` | Path to the .NET project root. | | `channel` | `str` | `'8.0'` | .NET SDK channel to install. Use a version like | | `"8.0"`, or a release band like `"LTS"` or `"STS"`. | | | | | `image` | `str \| None` | `None` | Local-mode Docker base image override. | | `base` | `Step \| None` | `None` | Existing `Step` to attach to instead of emitting a fresh | | apt-base step. | | | | **Returns** `DotnetProject` — A `DotnetProject` ready for action methods. ### `dotnet.build()` [#dotnetbuild] ```python build(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `dotnet.fmt()` [#dotnetfmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `dotnet.test()` [#dotnettest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `DotnetEntry` [#dotnetentry] Callable singleton for the dotnet toolchain — access as `hm.dotnet`. Call directly to construct a `DotnetProject`, or use the bare-form action methods (`dotnet.build()`, `dotnet.test()`, etc.) for a one-shot leaf. ### `DotnetEntry.build()` [#dotnetentrybuild] ```python build(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `DotnetEntry.fmt()` [#dotnetentryfmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `DotnetEntry.test()` [#dotnetentrytest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `DotnetProject` [#dotnetproject] dotnet (C#) project install chain — constructed via `hm.dotnet()`. `installed` is the dotnet-install step. Action methods (`build`, `test`, `fmt`) attach leaves to `installed`. ### Fields [#fields] | Field | Type | Default | | ----------- | ------ | ---------- | | `path` | `str` | *required* | | `installed` | `Step` | *required* | ### `DotnetProject.build()` [#dotnetprojectbuild] ```python build(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `DotnetProject.fmt()` [#dotnetprojectfmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `DotnetProject.test()` [#dotnetprojecttest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` # Elm (/pipeline-sdk/reference/toolchains/elm) {/* Generated by docs-site/scripts/generate-dsl-docs.ts — do not edit. */} ## `elm` [#elm] Callable singleton for the Elm toolchain — access as `hm.elm`. Supports both object form (`hm.elm()`) and bare form (`hm.elm.make(target)`, `hm.elm.test()`, etc.). ```python elm(*, path='.', elm_version='0.19.1', node_version='20', image=None, base=None) -> ElmProject ``` | Parameter | Type | Default | Description | | ------------------------------------------------------- | -------------- | ---------- | -------------------------------------------------------- | | `path` | `str` | `'.'` | Path to the Elm project root. | | `elm_version` | `str` | `'0.19.1'` | Elm compiler version to download from GitHub releases | | (e.g. `"0.19.1"`). | | | | | `node_version` | `str` | `'20'` | Node.js major version for npx-based tools | | (elm-test, elm-review, elm-format). Defaults to `"20"`. | | | | | `image` | `str \| None` | `None` | Local-mode Docker base image override. | | `base` | `Step \| None` | `None` | Existing `Step` to attach to instead of emitting a fresh | | apt-base step. | | | | **Returns** `ElmProject` — An `ElmProject` whose `installed` step is the elm-install step. ### `elm.fmt()` [#elmfmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `elm.make()` [#elmmake] ```python make(target, *, output=None, **kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ------------- | ---------- | ----------- | | `target` | `str` | *required* | — | | `output` | `str \| None` | `None` | — | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `elm.review()` [#elmreview] ```python review(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `elm.test()` [#elmtest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `ElmEntry` [#elmentry] Callable singleton for the Elm toolchain — access as `hm.elm`. Supports both object form (`hm.elm()`) and bare form (`hm.elm.make(target)`, `hm.elm.test()`, etc.). ### `ElmEntry.fmt()` [#elmentryfmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `ElmEntry.make()` [#elmentrymake] ```python make(target, *, output=None, **kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ------------- | ---------- | ----------- | | `target` | `str` | *required* | — | | `output` | `str \| None` | `None` | — | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `ElmEntry.review()` [#elmentryreview] ```python review(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `ElmEntry.test()` [#elmentrytest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `ElmProject` [#elmproject] Elm project install chain — constructed via `hm.elm()`. `installed` is the elm binary download step. Action methods (`make`, `test`, `review`, `fmt`) attach leaves to `installed`. ### Fields [#fields] | Field | Type | Default | | ----------- | ------ | ---------- | | `path` | `str` | *required* | | `installed` | `Step` | *required* | ### `ElmProject.fmt()` [#elmprojectfmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `ElmProject.make()` [#elmprojectmake] ```python make(target, *, output=None, **kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ------------- | ---------- | ----------- | | `target` | `str` | *required* | — | | `output` | `str \| None` | `None` | — | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `ElmProject.review()` [#elmprojectreview] ```python review(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `ElmProject.test()` [#elmprojecttest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` # Go (/pipeline-sdk/reference/toolchains/go) {/* Generated by docs-site/scripts/generate-dsl-docs.ts — do not edit. */} ## `go` [#go] Callable singleton for the Go toolchain — access as `hm.go`. Call directly to construct a `GoToolchain`, or use the bare-form action methods (`go.build()`, `go.test()`, etc.) for a one-shot leaf. ```python go(*, path='.', version='1.23.2', image=None, base=None) -> GoToolchain ``` | Parameter | Type | Default | Description | | ---------------------------------------- | -------------- | ---------- | -------------------------------------------------------- | | `path` | `str` | `'.'` | Path to the Go module root. | | `version` | `str` | `'1.23.2'` | Go version to install (e.g. `"1.23.2"`). Must be a | | full `MAJOR.MINOR.PATCH` version string. | | | | | `image` | `str \| None` | `None` | Local-mode Docker base image override. | | `base` | `Step \| None` | `None` | Existing `Step` to attach to instead of emitting a fresh | | apt-base step. | | | | **Returns** `GoToolchain` — A `GoToolchain` ready for action methods. ### `go.build()` [#gobuild] ```python build(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `go.fmt()` [#gofmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `go.test()` [#gotest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `go.vet()` [#govet] ```python vet(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `GoEntry` [#goentry] Callable singleton for the Go toolchain — access as `hm.go`. Call directly to construct a `GoToolchain`, or use the bare-form action methods (`go.build()`, `go.test()`, etc.) for a one-shot leaf. ### `GoEntry.build()` [#goentrybuild] ```python build(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `GoEntry.fmt()` [#goentryfmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `GoEntry.test()` [#goentrytest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `GoEntry.vet()` [#goentryvet] ```python vet(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `GoToolchain` [#gotoolchain] Go toolchain install chain — constructed via `hm.go()`. Holds the go-install step. Action methods (`build`, `test`, `vet`, `fmt`) attach leaves to `installed`. ### Fields [#fields] | Field | Type | Default | | ----------- | ------ | ---------- | | `path` | `str` | *required* | | `installed` | `Step` | *required* | ### `GoToolchain.build()` [#gotoolchainbuild] ```python build(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `GoToolchain.fmt()` [#gotoolchainfmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `GoToolchain.test()` [#gotoolchaintest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `GoToolchain.vet()` [#gotoolchainvet] ```python vet(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` # Gradle (/pipeline-sdk/reference/toolchains/gradle) {/* Generated by docs-site/scripts/generate-dsl-docs.ts — do not edit. */} ## `gradle` [#gradle] Callable singleton for the Gradle toolchain — access as `hm.gradle`. Call directly to construct a `GradleProject`, or use the bare-form action methods (`gradle.build()`, `gradle.test()`, etc.) for a one-shot leaf. ```python gradle(*, path='.', jdk='21', kotlin=False, image=None, base=None) -> GradleProject ``` | Parameter | Type | Default | Description | | ------------------------------------------------------- | -------------- | ------- | -------------------------------------------------------- | | `path` | `str` | `'.'` | Path to the project root (where `build.gradle` lives). | | `jdk` | `str` | `'21'` | JDK major version to install via apt. Must be one of | | `"11"`, `"17"`, or `"21"`. | | | | | `kotlin` | `bool` | `False` | When `True`, sets the label prefix to `:kotlin:` | | instead of `:java:`. The Gradle commands are identical. | | | | | `image` | `str \| None` | `None` | Local-mode Docker base image override. | | `base` | `Step \| None` | `None` | Existing `Step` to attach to instead of emitting a fresh | | apt-base step. | | | | **Returns** `GradleProject` — A `GradleProject` ready for action methods. ### `gradle.build()` [#gradlebuild] ```python build(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `gradle.lint()` [#gradlelint] ```python lint(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `gradle.test()` [#gradletest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `GradleEntry` [#gradleentry] Callable singleton for the Gradle toolchain — access as `hm.gradle`. Call directly to construct a `GradleProject`, or use the bare-form action methods (`gradle.build()`, `gradle.test()`, etc.) for a one-shot leaf. ### `GradleEntry.build()` [#gradleentrybuild] ```python build(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `GradleEntry.lint()` [#gradleentrylint] ```python lint(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `GradleEntry.test()` [#gradleentrytest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `GradleProject` [#gradleproject] Gradle (Java/Kotlin) project install chain — constructed via `hm.gradle()`. `installed` is the JDK-verify step. Action methods (`build`, `test`, `lint`) attach leaves to `installed`. ### Fields [#fields] | Field | Type | Default | | ----------- | ------ | ---------- | | `path` | `str` | *required* | | `installed` | `Step` | *required* | ### `GradleProject.build()` [#gradleprojectbuild] ```python build(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `GradleProject.lint()` [#gradleprojectlint] ```python lint(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `GradleProject.test()` [#gradleprojecttest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` # Haskell (/pipeline-sdk/reference/toolchains/haskell) {/* Generated by docs-site/scripts/generate-dsl-docs.ts — do not edit. */} ## `haskell` [#haskell] Callable singleton for the Haskell toolchain — access as `hm.haskell`. Supports both object form (`hm.haskell(ghc="9.6.7")`) and bare form (`hm.haskell.build(ghc="9.6.7", path="api")`, etc.). ```python haskell(*, ghc=None, cabal='latest', image=None, base=None, path=None, cache_paths=None) -> HaskellToolchain | HaskellPackage ``` | Parameter | Type | Default | Description | | ------------------------------------------------------ | ------------------------- | ---------- | -------------------------------------------------------- | | `ghc` | `str \| None` | `None` | GHC version to install (e.g. `"9.6.7"`). Required. | | `cabal` | `str` | `'latest'` | cabal-install version. Defaults to `"latest"`. | | `image` | `str \| None` | `None` | Local-mode Docker base image override. | | `base` | `Step \| None` | `None` | Existing `Step` to attach to instead of emitting a fresh | | apt-base step. | | | | | `path` | `str \| None` | `None` | Cabal package root. When provided, the call returns a | | `HaskellPackage` directly rather than a toolchain. | | | | | `cache_paths` | `tuple[str, ...] \| None` | `None` | Override the cabal-file paths for deps-step cache | | invalidation. Only meaningful when `path` is also set. | | | | **Returns** `HaskellToolchain | HaskellPackage` — A `HaskellToolchain` when `path` is omitted, or a ### `haskell.build()` [#haskellbuild] ```python build(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `haskell.fmt()` [#haskellfmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `haskell.hlint()` [#haskellhlint] ```python hlint(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `haskell.lint()` [#haskelllint] ```python lint(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `haskell.test()` [#haskelltest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `HaskellEntry` [#haskellentry] Callable singleton for the Haskell toolchain — access as `hm.haskell`. Supports both object form (`hm.haskell(ghc="9.6.7")`) and bare form (`hm.haskell.build(ghc="9.6.7", path="api")`, etc.). ### `HaskellEntry.build()` [#haskellentrybuild] ```python build(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `HaskellEntry.fmt()` [#haskellentryfmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `HaskellEntry.hlint()` [#haskellentryhlint] ```python hlint(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `HaskellEntry.lint()` [#haskellentrylint] ```python lint(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `HaskellEntry.test()` [#haskellentrytest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `HaskellPackage` [#haskellpackage] One cabal package — returned by `HaskellToolchain.package()`. `installed` is the package's `deps` step (the chain ancestor every action leaf attaches to). Exposed so callers can chain custom commands onto the deps-installed snapshot via `pkg.installed.sh(...)`. ### Fields [#fields] | Field | Type | Default | | ----------- | ------ | ---------- | | `path` | `str` | *required* | | `installed` | `Step` | *required* | ### `HaskellPackage.build()` [#haskellpackagebuild] ```python build(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `HaskellPackage.fmt()` [#haskellpackagefmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `HaskellPackage.hlint()` [#haskellpackagehlint] ```python hlint(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `HaskellPackage.lint()` [#haskellpackagelint] ```python lint(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `HaskellPackage.test()` [#haskellpackagetest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `HaskellToolchain` [#haskelltoolchain] Haskell toolchain install chain — constructed via `hm.haskell()`. Holds the shared `ghcup` install step. Spawn one `HaskellPackage` per cabal package via `.package(path)`. All packages from one toolchain share the same ghcup-install step. ### Fields [#fields-1] | Field | Type | Default | | --------------- | ------ | ---------- | | `ghc` | `str` | *required* | | `cabal_version` | `str` | *required* | | `installed` | `Step` | *required* | ### `HaskellToolchain.cabal()` [#haskelltoolchaincabal] ```python cabal(path, *, cache_paths=None) -> HaskellPackage ``` Create a `HaskellPackage` for the cabal package at `path`. Alias for `.package()`; reads more naturally for cabal projects. | Parameter | Type | Default | Description | | ------------- | ------------------------- | ---------- | ------------------------------------------------------ | | `path` | `str` | *required* | Path to the cabal package root. | | `cache_paths` | `tuple[str, ...] \| None` | `None` | Override the set of paths used for cache invalidation. | **Returns** `HaskellPackage` — A `HaskellPackage` ready for action methods. ### `HaskellToolchain.package()` [#haskelltoolchainpackage] ```python package(path, *, cache_paths=None) -> HaskellPackage ``` Create a `HaskellPackage` for the cabal package at `path`. Emits a `cabal build all --only-dependencies` step cached on the package's cabal files. Action methods on the returned package attach to that deps step. | Parameter | Type | Default | Description | | --------------------------------------------------------------- | ------------------------- | ---------- | -------------------------------------------------------- | | `path` | `str` | *required* | Path to the cabal package root. Must contain a `*.cabal` | | file and optionally a `cabal.project`. | | | | | `cache_paths` | `tuple[str, ...] \| None` | `None` | Override the set of paths used for cache invalidation. | | Defaults to `(f"\{path\}/*.cabal", f"\{path\}/cabal.project")`. | | | | **Returns** `HaskellPackage` — A `HaskellPackage` ready for action methods. **Examples** ```python >>> import harmont as hm >>> tc = hm.haskell(ghc="9.6.7") >>> pkg = tc.package("api") >>> hm.pipeline(pkg.build(), pkg.test()) ``` # Npm (/pipeline-sdk/reference/toolchains/npm) {/* Generated by docs-site/scripts/generate-dsl-docs.ts — do not edit. */} ## `npm` [#npm] Callable singleton for the npm toolchain — access as `hm.npm`. Call directly to construct an `NpmProject`, or use the bare-form action methods (`npm.test()`, `npm.run(script)`, etc.) for a one-shot leaf. ```python npm(*, path='.', version='20', image=None, base=None) -> NpmProject ``` | Parameter | Type | Default | Description | | --------------------- | -------------- | ------- | -------------------------------------------------------- | | `path` | `str` | `'.'` | Path to the npm project root (must contain a | | `package-lock.json`). | | | | | `version` | `str` | `'20'` | Node.js major version to install (e.g. `"20"` or | | `"20.x"`). | | | | | `image` | `str \| None` | `None` | Local-mode Docker base image override. | | `base` | `Step \| None` | `None` | Existing `Step` to attach to instead of emitting a fresh | | apt-base step. | | | | **Returns** `NpmProject` — An `NpmProject` whose `installed` step is `npm ci`. ### `npm.fmt()` [#npmfmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `npm.install()` [#npminstall] ```python install(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `npm.lint()` [#npmlint] ```python lint(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `npm.run()` [#npmrun] ```python run(script, **kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ---------- | ----------- | | `script` | `str` | *required* | — | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `npm.test()` [#npmtest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `NpmEntry` [#npmentry] Callable singleton for the npm toolchain — access as `hm.npm`. Call directly to construct an `NpmProject`, or use the bare-form action methods (`npm.test()`, `npm.run(script)`, etc.) for a one-shot leaf. ### `NpmEntry.fmt()` [#npmentryfmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `NpmEntry.install()` [#npmentryinstall] ```python install(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `NpmEntry.lint()` [#npmentrylint] ```python lint(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `NpmEntry.run()` [#npmentryrun] ```python run(script, **kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ---------- | ----------- | | `script` | `str` | *required* | — | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `NpmEntry.test()` [#npmentrytest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `NpmProject` [#npmproject] npm project install chain — constructed via `hm.npm()`. `installed` is the `npm ci` step. Action methods (`run`, `test`, `lint`, `fmt`) attach leaves to `installed` so dependency installation is shared across CI actions. ### Fields [#fields] | Field | Type | Default | | ----------- | ------ | ---------- | | `path` | `str` | *required* | | `installed` | `Step` | *required* | ### `NpmProject.fmt()` [#npmprojectfmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `NpmProject.install()` [#npmprojectinstall] ```python install() -> Step ``` **Returns** `Step` ### `NpmProject.lint()` [#npmprojectlint] ```python lint(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `NpmProject.run()` [#npmprojectrun] ```python run(script, **kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ---------- | ----------- | | `script` | `str` | *required* | — | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `NpmProject.test()` [#npmprojecttest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` # Ocaml (/pipeline-sdk/reference/toolchains/ocaml) {/* Generated by docs-site/scripts/generate-dsl-docs.ts — do not edit. */} ## `ocaml` [#ocaml] Callable singleton for the OCaml toolchain — access as `hm.ocaml`. Call directly to construct an `OCamlProject`, or use the bare-form action methods (`ocaml.build()`, `ocaml.test()`, etc.) for a one-shot leaf. ```python ocaml(*, path='.', compiler='5.1.1', image=None, base=None) -> OCamlProject ``` | Parameter | Type | Default | Description | | ---------------------------------------------------------- | -------------- | --------- | -------------------------------------------------------- | | `path` | `str` | `'.'` | Path to the OCaml project root. If `*.opam` files are | | present, `opam install . --deps-only` is run and cached on | | | | | those files. | | | | | `compiler` | `str` | `'5.1.1'` | OCaml compiler version to install via opam | | (e.g. `"5.1.1"`). | | | | | `image` | `str \| None` | `None` | Local-mode Docker base image override. | | `base` | `Step \| None` | `None` | Existing `Step` to attach to instead of emitting a fresh | | apt-base step. | | | | **Returns** `OCamlProject` — An `OCamlProject` whose `installed` step is the opam-deps step. ### `ocaml.build()` [#ocamlbuild] ```python build(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `ocaml.fmt()` [#ocamlfmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `ocaml.test()` [#ocamltest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `OCamlEntry` [#ocamlentry] Callable singleton for the OCaml toolchain — access as `hm.ocaml`. Call directly to construct an `OCamlProject`, or use the bare-form action methods (`ocaml.build()`, `ocaml.test()`, etc.) for a one-shot leaf. ### `OCamlEntry.build()` [#ocamlentrybuild] ```python build(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `OCamlEntry.fmt()` [#ocamlentryfmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `OCamlEntry.test()` [#ocamlentrytest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `OCamlProject` [#ocamlproject] OCaml project install chain — constructed via `hm.ocaml()`. `installed` is the opam-deps step. Action methods (`build`, `test`, `fmt`) attach leaves to `installed`. ### Fields [#fields] | Field | Type | Default | | ----------- | ------ | ---------- | | `path` | `str` | *required* | | `installed` | `Step` | *required* | ### `OCamlProject.build()` [#ocamlprojectbuild] ```python build(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `OCamlProject.fmt()` [#ocamlprojectfmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `OCamlProject.test()` [#ocamlprojecttest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` # Perl (/pipeline-sdk/reference/toolchains/perl) {/* Generated by docs-site/scripts/generate-dsl-docs.ts — do not edit. */} ## `perl` [#perl] Callable singleton for the Perl toolchain — access as `hm.perl`. Call directly to construct a `PerlProject`, or use the bare-form action methods (`perl.test()`, `perl.lint()`) for a one-shot leaf. ```python perl(*, path='.', image=None, base=None) -> PerlProject ``` | Parameter | Type | Default | Description | | -------------- | -------------- | ------- | ---------------------------------------------------------- | | `path` | `str` | `'.'` | Path to the Perl project root (must contain a `cpanfile`). | | `image` | `str \| None` | `None` | Local-mode Docker base image override. | | `base` | `Step \| None` | `None` | Existing `Step` to attach to instead of emitting a fresh | | apt-base step. | | | | **Returns** `PerlProject` — A `PerlProject` whose `installed` step is the cpanm-deps step. ### `perl.lint()` [#perllint] ```python lint(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `perl.test()` [#perltest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `PerlEntry` [#perlentry] Callable singleton for the Perl toolchain — access as `hm.perl`. Call directly to construct a `PerlProject`, or use the bare-form action methods (`perl.test()`, `perl.lint()`) for a one-shot leaf. ### `PerlEntry.lint()` [#perlentrylint] ```python lint(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `PerlEntry.test()` [#perlentrytest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `PerlProject` [#perlproject] Perl project install chain — constructed via `hm.perl()`. `installed` is the cpanm-deps step. Action methods (`test`, `lint`) attach leaves to `installed`. ### Fields [#fields] | Field | Type | Default | | ----------- | ------ | ---------- | | `path` | `str` | *required* | | `installed` | `Step` | *required* | ### `PerlProject.lint()` [#perlprojectlint] ```python lint(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `PerlProject.test()` [#perlprojecttest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` # Python (/pipeline-sdk/reference/toolchains/python) {/* Generated by docs-site/scripts/generate-dsl-docs.ts — do not edit. */} ## `python` [#python] Callable singleton for the Python (uv) toolchain — access as `hm.python`. Call directly to construct a `PythonToolchain`, or use the bare-form action methods (`python.test()`, `python.lint()`, etc.) for a one-shot leaf. ```python python(*, path='.', uv_version='latest', image=None, base=None) -> PythonToolchain ``` | Parameter | Type | Default | Description | | --------------------------------------------------- | -------------- | ---------- | -------------------------------------------------------- | | `path` | `str` | `'.'` | Path to the Python project root (must contain a | | `pyproject.toml`). | | | | | `uv_version` | `str` | `'latest'` | uv version to install. Use `"latest"` for the | | latest release or a pinned version like `"0.4.18"`. | | | | | `image` | `str \| None` | `None` | Local-mode Docker base image override. | | `base` | `Step \| None` | `None` | Existing `Step` to attach to instead of emitting a fresh | | apt-base step. | | | | **Returns** `PythonToolchain` — A `PythonToolchain` whose `installed` step is `uv sync`. ### `python.fmt()` [#pythonfmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `python.lint()` [#pythonlint] ```python lint(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `python.test()` [#pythontest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `python.typecheck()` [#pythontypecheck] ```python typecheck(*, paths=None, **kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | -------------------------- | ------- | ----------- | | `paths` | `str \| list[str] \| None` | `None` | — | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `PythonEntry` [#pythonentry] Callable singleton for the Python (uv) toolchain — access as `hm.python`. Call directly to construct a `PythonToolchain`, or use the bare-form action methods (`python.test()`, `python.lint()`, etc.) for a one-shot leaf. ### `PythonEntry.fmt()` [#pythonentryfmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `PythonEntry.lint()` [#pythonentrylint] ```python lint(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `PythonEntry.test()` [#pythonentrytest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `PythonEntry.typecheck()` [#pythonentrytypecheck] ```python typecheck(*, paths=None, **kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | -------------------------- | ------- | ----------- | | `paths` | `str \| list[str] \| None` | `None` | — | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `PythonToolchain` [#pythontoolchain] Python (uv) toolchain install chain — constructed via `hm.python()`. `installed` is the `uv sync` step. Action methods (`test`, `lint`, `fmt`, `typecheck`) attach leaves to `installed` so dependency installation is shared across CI actions. ### Fields [#fields] | Field | Type | Default | | ----------- | ------ | ---------- | | `path` | `str` | *required* | | `installed` | `Step` | *required* | ### `PythonToolchain.fmt()` [#pythontoolchainfmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `PythonToolchain.lint()` [#pythontoolchainlint] ```python lint(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `PythonToolchain.test()` [#pythontoolchaintest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `PythonToolchain.typecheck()` [#pythontoolchaintypecheck] ```python typecheck(*, paths=None, **kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | -------------------------- | ------- | ----------- | | `paths` | `str \| list[str] \| None` | `None` | — | | `kw` | `Any` | `{}` | — | **Returns** `Step` # Ruby (/pipeline-sdk/reference/toolchains/ruby) {/* Generated by docs-site/scripts/generate-dsl-docs.ts — do not edit. */} ## `ruby` [#ruby] Callable singleton for the Ruby toolchain — access as `hm.ruby`. Call directly to construct a `RubyProject`, or use the bare-form action methods (`ruby.test()`, `ruby.lint()`) for a one-shot leaf. ```python ruby(*, path='.', version='default', image=None, base=None) -> RubyProject ``` | Parameter | Type | Default | Description | | ------------------------------------------------------------- | -------------- | ----------- | -------------------------------------------------------- | | `path` | `str` | `'.'` | Path to the Ruby project root (must contain a | | `Gemfile.lock`). | | | | | `version` | `str` | `'default'` | Ruby version. Currently only `"default"` is supported | | (installs whichever `ruby-full` ships in the apt repository). | | | | | Pinned versions require rbenv/asdf support, which is not yet | | | | | implemented. | | | | | `image` | `str \| None` | `None` | Local-mode Docker base image override. | | `base` | `Step \| None` | `None` | Existing `Step` to attach to instead of emitting a fresh | | apt-base step. | | | | **Returns** `RubyProject` — A `RubyProject` whose `installed` step is `bundle install`. ### `ruby.lint()` [#rubylint] ```python lint(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `ruby.test()` [#rubytest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `RubyEntry` [#rubyentry] Callable singleton for the Ruby toolchain — access as `hm.ruby`. Call directly to construct a `RubyProject`, or use the bare-form action methods (`ruby.test()`, `ruby.lint()`) for a one-shot leaf. ### `RubyEntry.lint()` [#rubyentrylint] ```python lint(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `RubyEntry.test()` [#rubyentrytest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `RubyProject` [#rubyproject] Ruby project install chain — constructed via `hm.ruby()`. `installed` is the `bundle install` step. Action methods (`test`, `lint`) attach leaves to `installed`. ### Fields [#fields] | Field | Type | Default | | ----------- | ------ | ---------- | | `path` | `str` | *required* | | `installed` | `Step` | *required* | ### `RubyProject.lint()` [#rubyprojectlint] ```python lint(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `RubyProject.test()` [#rubyprojecttest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` # Rust (/pipeline-sdk/reference/toolchains/rust) {/* Generated by docs-site/scripts/generate-dsl-docs.ts — do not edit. */} ## `rust` [#rust] Namespace for `hm.rust.toolchain()` and `hm.rust.project()`. ### `rust.project()` [#rustproject] ```python project(*, path='.', version='stable', image=None, components=('clippy', 'rustfmt'), base=None, cache=None) -> RustProject ``` Build a high-level Rust CI DAG. Installs the toolchain via rustup, warms a dependency cache keyed on `Cargo.lock`, and returns a `RustProject` whose `.test()`, `.clippy()`, and `.fmt()` methods build on that warmup step so dependency compilation is shared. | Parameter | Type | Default | Description | | -------------------------------------- | --------------------- | ----------------------- | -------------------------------------------------------- | | `path` | `str` | `'.'` | Path to the crate or workspace root. | | `version` | `str` | `'stable'` | rustup channel name (`"stable"`) or a pinned version | | (`"1.81.0"`). | | | | | `image` | `str \| None` | `None` | Local-mode Docker base image override. | | `components` | `tuple[str, ...]` | `('clippy', 'rustfmt')` | rustup components to install alongside the toolchain. | | Defaults to `("clippy", "rustfmt")`. | | | | | `base` | `Step \| None` | `None` | Existing `Step` to attach to instead of emitting a fresh | | apt-base step. | | | | | `cache` | `CachePolicy \| None` | `None` | Override the warmup step's cache policy. Defaults to | | `CacheOnChange` keyed on `Cargo.lock`. | | | | **Returns** `RustProject` — A `RustProject` exposing the common CI steps. **Examples** ```python >>> import harmont as hm >>> proj = hm.rust.project() >>> hm.group([proj.test(), proj.clippy(), proj.fmt()]) ``` ### `rust.toolchain()` [#rusttoolchain] ```python toolchain(*, path='.', version='stable', image=None, components=('clippy', 'rustfmt'), base=None) -> RustToolchain ``` Install the Rust toolchain via rustup. Produces a `RustToolchain` whose `installed` step is the rustup-install step. Action methods on the toolchain attach leaves to `installed`. Use `project()` instead when you want a pre-built warmup step shared across test/clippy/fmt. | Parameter | Type | Default | Description | | ------------------------------------------------------------ | ----------------- | ----------------------- | ---------------------------------------------------------- | | `path` | `str` | `'.'` | Path to the crate or workspace root. | | `version` | `str` | `'stable'` | rustup channel name (`"stable"`) or a pinned version | | (`"1.81.0"`). | | | | | `image` | `str \| None` | `None` | Local-mode Docker base image override. | | `components` | `tuple[str, ...]` | `('clippy', 'rustfmt')` | rustup components to install alongside the toolchain. | | Defaults to `("clippy", "rustfmt")`. | | | | | `base` | `Step \| None` | `None` | Existing `Step` to attach the toolchain install to instead | | of emitting a fresh apt-base step. Use to share one apt-base | | | | | across multiple toolchains. | | | | **Returns** `RustToolchain` — A `RustToolchain` ready for action methods. **Examples** ```python >>> import harmont as hm >>> tc = hm.rust.toolchain(version="1.81.0") >>> hm.pipeline(tc.test(), tc.clippy()) ``` ## `RustEntry` [#rustentry] Namespace for `hm.rust.toolchain()` and `hm.rust.project()`. ### `RustEntry.project()` [#rustentryproject] ```python project(*, path='.', version='stable', image=None, components=('clippy', 'rustfmt'), base=None, cache=None) -> RustProject ``` Build a high-level Rust CI DAG. Installs the toolchain via rustup, warms a dependency cache keyed on `Cargo.lock`, and returns a `RustProject` whose `.test()`, `.clippy()`, and `.fmt()` methods build on that warmup step so dependency compilation is shared. | Parameter | Type | Default | Description | | -------------------------------------- | --------------------- | ----------------------- | -------------------------------------------------------- | | `path` | `str` | `'.'` | Path to the crate or workspace root. | | `version` | `str` | `'stable'` | rustup channel name (`"stable"`) or a pinned version | | (`"1.81.0"`). | | | | | `image` | `str \| None` | `None` | Local-mode Docker base image override. | | `components` | `tuple[str, ...]` | `('clippy', 'rustfmt')` | rustup components to install alongside the toolchain. | | Defaults to `("clippy", "rustfmt")`. | | | | | `base` | `Step \| None` | `None` | Existing `Step` to attach to instead of emitting a fresh | | apt-base step. | | | | | `cache` | `CachePolicy \| None` | `None` | Override the warmup step's cache policy. Defaults to | | `CacheOnChange` keyed on `Cargo.lock`. | | | | **Returns** `RustProject` — A `RustProject` exposing the common CI steps. **Examples** ```python >>> import harmont as hm >>> proj = hm.rust.project() >>> hm.group([proj.test(), proj.clippy(), proj.fmt()]) ``` ### `RustEntry.toolchain()` [#rustentrytoolchain] ```python toolchain(*, path='.', version='stable', image=None, components=('clippy', 'rustfmt'), base=None) -> RustToolchain ``` Install the Rust toolchain via rustup. Produces a `RustToolchain` whose `installed` step is the rustup-install step. Action methods on the toolchain attach leaves to `installed`. Use `project()` instead when you want a pre-built warmup step shared across test/clippy/fmt. | Parameter | Type | Default | Description | | ------------------------------------------------------------ | ----------------- | ----------------------- | ---------------------------------------------------------- | | `path` | `str` | `'.'` | Path to the crate or workspace root. | | `version` | `str` | `'stable'` | rustup channel name (`"stable"`) or a pinned version | | (`"1.81.0"`). | | | | | `image` | `str \| None` | `None` | Local-mode Docker base image override. | | `components` | `tuple[str, ...]` | `('clippy', 'rustfmt')` | rustup components to install alongside the toolchain. | | Defaults to `("clippy", "rustfmt")`. | | | | | `base` | `Step \| None` | `None` | Existing `Step` to attach the toolchain install to instead | | of emitting a fresh apt-base step. Use to share one apt-base | | | | | across multiple toolchains. | | | | **Returns** `RustToolchain` — A `RustToolchain` ready for action methods. **Examples** ```python >>> import harmont as hm >>> tc = hm.rust.toolchain(version="1.81.0") >>> hm.pipeline(tc.test(), tc.clippy()) ``` ## `RustProject` [#rustproject-1] High-level Rust CI DAG — constructed via `hm.rust.project()`. Wraps a `RustToolchain` and a pre-built warmup step. Action methods (`test`, `clippy`, `fmt`) attach leaves to the warmup so dependency compilation is shared across CI actions. ### Fields [#fields] | Field | Type | Default | | ----------- | --------------- | ---------- | | `toolchain` | `RustToolchain` | *required* | | `warmup` | `Step` | *required* | ### `RustProject.clippy()` [#rustprojectclippy] ```python clippy(*, flags=(), **kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----------------- | ------- | ----------- | | `flags` | `tuple[str, ...]` | `()` | — | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `RustProject.fmt()` [#rustprojectfmt] ```python fmt(*, flags=(), **kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----------------- | ------- | ----------- | | `flags` | `tuple[str, ...]` | `()` | — | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `RustProject.test()` [#rustprojecttest] ```python test(*, flags=(), packages=(), **kw) -> Step ``` | Parameter | Type | Default | Description | | ---------- | ----------------- | ------- | ----------- | | `flags` | `tuple[str, ...]` | `()` | — | | `packages` | `tuple[str, ...]` | `()` | — | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `RustToolchain` [#rusttoolchain-1] Rust toolchain install chain — constructed via `hm.rust.toolchain()`. Holds the install step produced by rustup. Action methods (`build`, `test`, `clippy`, `fmt`, `doc`) attach leaves to `installed`. ### Fields [#fields-1] | Field | Type | Default | | ----------- | ------ | ---------- | | `path` | `str` | *required* | | `installed` | `Step` | *required* | ### `RustToolchain.build()` [#rusttoolchainbuild] ```python build(*, release=False, **kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ------ | ------- | ----------- | | `release` | `bool` | `False` | — | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `RustToolchain.clippy()` [#rusttoolchainclippy] ```python clippy(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `RustToolchain.doc()` [#rusttoolchaindoc] ```python doc(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `RustToolchain.fmt()` [#rusttoolchainfmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `RustToolchain.test()` [#rusttoolchaintest] ```python test(*, release=False, **kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ------ | ------- | ----------- | | `release` | `bool` | `False` | — | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `RustToolchain.warmup()` [#rusttoolchainwarmup] ```python warmup(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` # Zig (/pipeline-sdk/reference/toolchains/zig) {/* Generated by docs-site/scripts/generate-dsl-docs.ts — do not edit. */} ## `zig` [#zig] Callable singleton for the Zig toolchain — access as `hm.zig`. Supports three usage forms: * Toolchain form: `hm.zig(version="0.13.0")` returns a `ZigToolchain` shared across multiple projects. * Project form: `hm.zig(path=".")` returns a `ZigProject` directly. * Bare form: `hm.zig.build()`, `hm.zig.test()`, etc. for one-shot leaves. ```python zig(*, path=None, version='0.13.0', image=None, base=None) -> ZigToolchain | ZigProject ``` | Parameter | Type | Default | Description | | -------------------------------------------- | -------------- | ---------- | -------------------------------------------------------- | | `path` | `str \| None` | `None` | Zig project root. Omit to get a reusable `ZigToolchain` | | from which multiple projects can be spawned. | | | | | `version` | `str` | `'0.13.0'` | Zig release version (e.g. `"0.13.0"`). Must be a | | full `MAJOR.MINOR.PATCH` string. | | | | | `image` | `str \| None` | `None` | Local-mode Docker base image override. | | `base` | `Step \| None` | `None` | Existing `Step` to attach to instead of emitting a fresh | | apt-base step. | | | | **Returns** `ZigToolchain | ZigProject` — A `ZigToolchain` when `path` is omitted, or a `ZigProject` ### `zig.build()` [#zigbuild] ```python build(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `zig.fmt()` [#zigfmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `zig.test()` [#zigtest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `ZigEntry` [#zigentry] Callable singleton for the Zig toolchain — access as `hm.zig`. Supports three usage forms: * Toolchain form: `hm.zig(version="0.13.0")` returns a `ZigToolchain` shared across multiple projects. * Project form: `hm.zig(path=".")` returns a `ZigProject` directly. * Bare form: `hm.zig.build()`, `hm.zig.test()`, etc. for one-shot leaves. ### `ZigEntry.build()` [#zigentrybuild] ```python build(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `ZigEntry.fmt()` [#zigentryfmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `ZigEntry.test()` [#zigentrytest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `ZigProject` [#zigproject] Zig project rooted on a specific path — constructed via `hm.zig(path=...)`. `installed` is the zig-install step. Action methods (`build`, `test`, `fmt`) attach leaves to `installed`. ### Fields [#fields] | Field | Type | Default | | ----------- | ------ | ---------- | | `path` | `str` | *required* | | `installed` | `Step` | *required* | ### `ZigProject.build()` [#zigprojectbuild] ```python build(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `ZigProject.fmt()` [#zigprojectfmt] ```python fmt(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ### `ZigProject.test()` [#zigprojecttest] ```python test(**kw) -> Step ``` | Parameter | Type | Default | Description | | --------- | ----- | ------- | ----------- | | `kw` | `Any` | `{}` | — | **Returns** `Step` ## `ZigToolchain` [#zigtoolchain] Zig toolchain install chain — constructed via `hm.zig()` with no `path`. Holds the shared zig-install step. Spawn one `ZigProject` per subdirectory via `.project(path)`; all projects from one toolchain share the same install step, so the emitted IR contains a single `:zig: install` node fanned out to N project chains. ### Fields [#fields-1] | Field | Type | Default | | ----------- | ------ | ---------- | | `version` | `str` | *required* | | `installed` | `Step` | *required* | ### `ZigToolchain.project()` [#zigtoolchainproject] ```python project(path='.') -> ZigProject ``` Create a `ZigProject` rooted at `path` from this toolchain. | Parameter | Type | Default | Description | | --------- | ----- | ------- | ------------------------------------------------------- | | `path` | `str` | `'.'` | Path to the Zig project root relative to the workspace. | **Returns** `ZigProject` — A `ZigProject` whose `installed` step is shared with this **Examples** ```python >>> import harmont as hm >>> tc = hm.zig(version="0.13.0") >>> lib = tc.project("lib-a") >>> app = tc.project("app") >>> hm.pipeline(lib.test(), app.test()) ```