main
nixbuild
Operator surface for the 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 <cmd>(command as args) → hits the build-runner channel, needsrun: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 '<cmd>' ['<cmd>' …]— drive the admin shell non-interactively (expect+PTY). Output cleaned of banner/prompt noise. The foundation for all settings work.nbapi <usage|summary|builds|raw>— read-only HTTP API client. Token from$NIXBUILD_API_TOKENorpass show infra/nixbuild/api-token.nb-substituters <list|add-cache|add-key|remove|remove-key|reset>— 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 <SETTING>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, orcachix://nameare accepted. Reach a sub-path cache (Attic, nix-serve) path-less — front it at a host root with a reverse-proxy rewrite of/<hash>.narinfoand/nar/*. The oleks fleet does this for Attic athttps://nix-cache-custom.oleks.space(Caddy root-rewrite); NCPS ishttps://nix-cache-mirror.oleks.space. builders-use-substitutes = trueon 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 (whatnb-substituters add-cachedoes).- The account is metered. Free tier resets monthly (
Free build time left: 25:00:00on 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
expecton PATH, ornix(the tools fetchexpectephemerally vianix run nixpkgs#expect— no profile install).- An SSH key registered on the nixbuild account with admin permissions for settings changes (configured via
~/.ssh/config/ systemssh_configfor thessh_host, defaulteu.nixbuild.net). curl, andjq(optional, for pretty JSON).passfor the API token unless$NIXBUILD_API_TOKENis 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
Languages
Shell
100%