Skip to content

Scripts your agents would actually write.

Three short Husk scripts that demonstrate the core primitives — typed paths, pipelines, parallel, checkpoint, plan-before-apply. Each is runnable.

§ fs · git

Rename docker-compose.yml across a portfolio

The case study from the home page, shown in full. One script. Idempotent. Resumable.

§ rename-compose.husk husk plan
# Rename docker-compose.{yml,yaml} to compose.yml across the
# portfolio. Update references. Commit per repo.

let root: path = param("root", default: path("~/mataki"))
let exclude = list("node_modules", ".git", ".terraform", ".worktrees")

let files =
    fs.walk(root, exclude: exclude)
    | where .name in list("docker-compose.yml", "docker-compose.yaml")

let by_repo = files | group_by { f => git.repo_root(f.path) }

by_repo | parallel(max: 4) { repo, files =>
    checkpoint("repo:${repo}") {
        for f in files {
            fs.ensure(file: f.path.parent / "compose.yml",
                      contents: fs.read(f.path)?)
            fs.ensure(file: f.path, absent: true)
        }
        git.commit(repo: repo,
                   paths: files.map(.path.parent / "compose.yml"),
                   message: "chore: rename to compose.yml")
    }
}
§ http · json

Cache GitHub release metadata

Fetch releases for a set of repos, typed response, resumable across transient HTTP failures.

§ fetch-releases.husk husk plan
let repos = list("husk-sh/husk", "husk-sh/registry")

let releases = repos | parallel(max: 6) { repo =>
    let url = "https://api.github.com/repos/${repo}/releases/latest"
    let resp = http.get(url, retry: 3)?

    {
        repo: repo,
        tag: resp.body.tag_name,
        published: resp.body.published_at,
        assets: resp.body.assets | map { a =>
            { name: a.name, size_kb: a.size / 1024 }
        }
    }
}

fs.ensure(file: path("./releases.json"),
          contents: json.stringify(releases, pretty: true))
§ git · checkpoint

Run a migration across every repo in a workspace

Checkpoint per repo. If step 14 of 18 fails, resume at 14 — no double-applied migrations.

§ port-migrate.husk husk plan
let workspace = param("workspace", default: path("~/src"))

let repos = fs.walk(workspace, max_depth: 2)
          | where .name == ".git"
          | map .path.parent

repos | parallel(max: 4) { repo =>
    checkpoint("migrate:${repo.name}") {
        let status = git.status(repo)?
        assert status.clean, "repo not clean: ${repo}"

        git.pull(repo, rebase: true)?

        let pkg = fs.read_json(repo / "package.json")?
        let updated = pkg | merge({ engines: { node: ">=22" } })

        fs.ensure(file: repo / "package.json",
                  contents: json.stringify(updated, pretty: true))

        git.commit(repo: repo,
                   paths: list("package.json"),
                   message: "chore: require node >=22")
    }
}

Give your agents a language they'll love.

Install Husk. Wire it into your harness. Watch the first script rehearse itself before it runs.