# nixbuild Operator surface for the [nixbuild.net](https://nixbuild.net) remote build service. A Haiku **ops** agent fronts three tools and two skills for reading the metered account's usage and managing its settings — built from the hard-won knowledge of how nixbuild's two control surfaces actually behave. ## Install ``` claude plugin install nixbuild@oleks-local ``` ## Why this exists nixbuild has two completely separate control surfaces, and using the wrong one is the main failure mode: - **HTTP API** (`https://api.nixbuild.net`, Bearer token) is **read-only** — usage, builds, summary. No settings endpoints. - **Admin shell** (`ssh eu.nixbuild.net shell`) is the **only** place settings, SSH keys, tokens, and billing live, and it is interactive-only and fussy: - `ssh -T … shell` + piped stdin → **silent** (needs a PTY). - `ssh -tt … shell` → rejected: *"pty not supported"*. - `ssh … shell ` (command as args) → hits the build-runner channel, needs `run:write`, fails *"Authorization failed"*. The only thing that works is a **real local PTY** wrapping `ssh -T … shell`, fed one command at a time, synchronised on the `nixbuild.net>` prompt. The `nbshell` tool does exactly that via `expect`. ## Agent - **ops** (Haiku) — answers account questions and applies settings changes safely. Read-mostly; confirms every mutation. Routes deeper workflows to the two skills. ## Tools (`bin/`) - **`nbshell '' ['' …]`** — drive the admin shell non-interactively (expect+PTY). Output cleaned of banner/prompt noise. The foundation for all settings work. - **`nbapi `** — read-only HTTP API client. Token from `$NIXBUILD_API_TOKEN` or `pass show infra/nixbuild/api-token`. - **`nb-substituters `** — guarded substituter/key manager that catches nixbuild's path-style-URL rejection before it reaches the shell. ## Skills - **nixbuild-settings** — manage substituters, trusted public keys, SSH keys, and any `settings ` via the shell. Carries the path-style-URL guard and the path-less-cache recipe. - **nixbuild-usage** — metered-account cost posture: free time left, billable CPU-seconds, build history, output/stored size. ## Hard-won facts encoded here - **nixbuild rejects path-style substituter URLs** (`https://host/cache-name` → *"invalid substituter"*, trailing slash doesn't help). Only host-root HTTPS, `s3://bucket/prefix`, or `cachix://name` are accepted. Reach a sub-path cache (Attic, nix-serve) **path-less** — front it at a host root with a reverse-proxy rewrite of `/.narinfo` and `/nar/*`. The oleks fleet does this for Attic at `https://nix-cache-custom.oleks.space` (Caddy root-rewrite); NCPS is `https://nix-cache-mirror.oleks.space`. - **`builders-use-substitutes = true` on the client does NOT forward the client's substituters to nixbuild** — the remote uses its OWN (account-side) substituters. Caches only help remote builds when registered account-side (what `nb-substituters add-cache` does). - **The account is metered.** Free tier resets monthly (`Free build time left: 25:00:00` on the 1st); when spent the banner reads *"You have no free build time left"* and builds are billed. Cache hits on registered substituters are the cost lever. ## Requirements - `expect` on PATH, or `nix` (the tools fetch `expect` ephemerally via `nix run nixpkgs#expect` — no profile install). - An SSH key registered on the nixbuild account **with admin permissions** for settings changes (configured via `~/.ssh/config` / system `ssh_config` for the `ssh_host`, default `eu.nixbuild.net`). - `curl`, and `jq` (optional, for pretty JSON). `pass` for the API token unless `$NIXBUILD_API_TOKEN` is set. ## Configuration | Key | Default | Purpose | |-----|---------|---------| | `ssh_host` | `eu.nixbuild.net` | SSH host alias for the admin/build endpoint | | `api_token_pass_entry` | `infra/nixbuild/api-token` | `pass` path for the HTTP API token (overridden by `$NIXBUILD_API_TOKEN`) | ## License MIT