# 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())
```