Initial commit: nixbuild.net operator plugin
Haiku ops agent + 3 tools (nbshell expect+PTY admin-shell driver, nbapi read-only HTTP client, nb-substituters guarded cache manager) + 2 skills (nixbuild-settings, nixbuild-usage). Encodes the two-control-surface model and the path-style-substituter-URL gotcha.
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
---
|
||||
name: nixbuild-settings
|
||||
description: |
|
||||
Manage nixbuild.net account settings over the interactive admin shell —
|
||||
binary-cache substituters, trusted public keys, SSH keys, and other
|
||||
account/SSH-key settings. Carries the guard rails for nixbuild's quirks:
|
||||
path-style substituter URLs are rejected (reach sub-path caches like Attic
|
||||
path-less instead), and the admin shell needs a real PTY (driven by the
|
||||
nbshell tool). Use when registering/removing a cache on nixbuild, adding a
|
||||
trusted public key, managing SSH keys, or reading/changing any
|
||||
`settings <SETTING>`. Trigger on "add a substituter to nixbuild", "register
|
||||
a cache on nixbuild", "nixbuild trusted key", "nixbuild ssh key", "change
|
||||
nixbuild settings", "nixbuild substituters".
|
||||
disable-model-invocation: false
|
||||
allowed-tools: Bash, Read, AskUserQuestion
|
||||
---
|
||||
|
||||
# nixbuild-settings — account settings via the admin shell
|
||||
|
||||
Owning agent: `nixbuild:ops`. Account administration lives ONLY behind
|
||||
nixbuild's interactive admin shell; the HTTP API cannot touch it. Drive the
|
||||
shell through the **`nbshell`** tool (real PTY via `expect`) — never hand-roll
|
||||
ssh (see the plugin's `ops` agent for why the obvious invocations all fail).
|
||||
|
||||
Tools live under `${CLAUDE_PLUGIN_ROOT}/bin`.
|
||||
|
||||
## Read current settings
|
||||
|
||||
```bash
|
||||
nb-substituters list # substituters + trusted keys
|
||||
nbshell 'settings substituters --show'
|
||||
nbshell 'settings trusted-public-keys --show'
|
||||
nbshell 'ssh-keys' # registered SSH keys + permissions
|
||||
nbshell 'settings --help' # list every available SETTING
|
||||
```
|
||||
|
||||
The full SETTING list includes: `substituters`, `trusted-public-keys`,
|
||||
`caches`, `access-tokens`, `always-substitute`, `max-cpu`, `max-mem`,
|
||||
`default-permissions`, `signing-key-for-builds`, `timeout`, and more. Read any
|
||||
with `settings <SETTING> --show`.
|
||||
|
||||
## Register a binary cache (the common task)
|
||||
|
||||
```bash
|
||||
nb-substituters add-cache <url> <public-key>
|
||||
```
|
||||
|
||||
`add-cache` adds the substituter AND its trusted key, then re-shows both. It
|
||||
**refuses path-style URLs before they reach the shell**.
|
||||
|
||||
### The path-style gotcha (apply, do not re-derive)
|
||||
|
||||
nixbuild's `settings substituters --add` accepts ONLY:
|
||||
|
||||
- host-root HTTPS: `https://host` (NO path, no trailing slash)
|
||||
- `s3://bucket/prefix`
|
||||
- `cachix://name`
|
||||
|
||||
A path-style URL like `https://host/cache-name` (Attic, nix-serve) is rejected
|
||||
as "invalid substituter". To use such a cache you must expose it **path-less**:
|
||||
front it at a host root with a reverse proxy that rewrites `/<hash>.narinfo`
|
||||
and `/nar/*` into the cache namespace, then register that bare host.
|
||||
|
||||
Worked example (oleks fleet): Attic's native URL is
|
||||
`https://nix-cache-custom.oleks.space/attic-infra-cache-k3s-1` (rejected). But
|
||||
`oci-caddy.nix` already serves it path-less at the root of
|
||||
`nix-cache-custom.oleks.space`, so register:
|
||||
|
||||
```bash
|
||||
nb-substituters add-cache https://nix-cache-custom.oleks.space \
|
||||
attic-infra-cache-k3s-1:qYSNK3DmttQXCFqn1t50qoWGtQNPRFWq9mgQjD05DeU=
|
||||
```
|
||||
|
||||
NCPS is plain host-root and just works:
|
||||
`nb-substituters add-cache https://nix-cache-mirror.oleks.space nix-cache-mirror.oleks.space:v8rbmAnk5MrEunNCC0BxYUh21UALvCuR2lnuZrr0hHY=`.
|
||||
|
||||
### Why register account-side at all
|
||||
|
||||
`builders-use-substitutes = true` on the *client* does NOT forward the client's
|
||||
substituters to nixbuild — the remote uses ITS OWN substituters. So a cache only
|
||||
speeds up / cheapens remote builds when registered here, account-side.
|
||||
|
||||
## Add only a key, or remove things
|
||||
|
||||
```bash
|
||||
nb-substituters add-key <public-key>
|
||||
nb-substituters remove <url>
|
||||
nb-substituters remove-key <public-key>
|
||||
nbshell 'settings substituters --reset' # back to default (cache.nixos.org)
|
||||
```
|
||||
|
||||
## SSH keys and other raw settings
|
||||
|
||||
```bash
|
||||
nbshell 'ssh-keys' # list keys + permission sets
|
||||
nbshell 'settings <SETTING> --add <value>' # generic add
|
||||
nbshell 'settings <SETTING> --reset' # generic reset
|
||||
```
|
||||
|
||||
Per-key overrides: most settings take `--ssh-key <SSH_KEY_ID>` to scope to one
|
||||
key instead of the whole account.
|
||||
|
||||
## Procedure (mutations)
|
||||
|
||||
1. **Read** the current value first (`--show`) so you can show a before/after.
|
||||
2. **State the exact command(s)** you will run and **confirm via
|
||||
`AskUserQuestion`** — settings changes affect every build on the account.
|
||||
3. **Apply** through `nb-substituters` (preferred, guarded) or `nbshell`.
|
||||
4. **Verify**: re-show the setting and report the after-state. A successful add
|
||||
is silent; the proof is the `--show` afterwards.
|
||||
|
||||
## Failure signals
|
||||
|
||||
- `invalid substituter` → path-style URL; expose path-less (above).
|
||||
- `Authorization failed … run:write` → the SSH key in use lacks admin
|
||||
permission for the shell (or the command was sent as ssh args, not via
|
||||
`nbshell`). Use a full-access key.
|
||||
- `nbshell` prints nothing but errors → `expect` missing and no `nix` to fetch
|
||||
it; install `expect` or run where `nix` is available.
|
||||
@@ -0,0 +1,91 @@
|
||||
---
|
||||
name: nixbuild-usage
|
||||
description: |
|
||||
Report nixbuild.net account usage and cost posture — remaining free build
|
||||
time, billable CPU-seconds over a date range, build history (success/fail/
|
||||
discarded), output NAR size, and stored size. The account is metered, so
|
||||
this is the cost-visibility skill. Reads come from the HTTP API (nbapi tool,
|
||||
no PTY needed) plus the shell's `usage` command for the live free-time
|
||||
counter. Trigger on "nixbuild usage", "how much build time left", "nixbuild
|
||||
billing", "nixbuild storage", "nixbuild build history", "am I out of free
|
||||
build time", "nixbuild cost".
|
||||
disable-model-invocation: false
|
||||
allowed-tools: Bash, Read
|
||||
---
|
||||
|
||||
# nixbuild-usage — metered account usage & cost
|
||||
|
||||
Owning agent: `nixbuild:ops`. nixbuild bills CPU-time beyond a monthly free
|
||||
tier; this skill answers "where do I stand" without touching settings. Most of
|
||||
it is the read-only HTTP API via **`nbapi`** (`${CLAUDE_PLUGIN_ROOT}/bin`), which
|
||||
needs no PTY. The live free-time counter comes from the shell banner / `usage`.
|
||||
|
||||
## Quick posture
|
||||
|
||||
```bash
|
||||
nbapi summary
|
||||
```
|
||||
|
||||
Returns (example shape):
|
||||
|
||||
```json
|
||||
{
|
||||
"build_count": 19, "running_build_count": 0,
|
||||
"discarded_build_count": 1, "failed_build_count": 1,
|
||||
"successful_build_count": 17,
|
||||
"total_cpu_seconds": 27401, "billable_cpu_seconds": 20963,
|
||||
"total_duration_seconds": 2708.06, "wall_time_seconds": 48398.44,
|
||||
"total_output_nar_size_kilobytes": 786691
|
||||
}
|
||||
```
|
||||
|
||||
Key fields: `billable_cpu_seconds` (what you pay for), `successful/failed/
|
||||
discarded_build_count`, `total_output_nar_size_kilobytes`.
|
||||
|
||||
## Remaining free build time (live)
|
||||
|
||||
The free-tier counter is only in the shell, not the HTTP API:
|
||||
|
||||
```bash
|
||||
nbshell 'usage'
|
||||
```
|
||||
|
||||
The shell login banner also prints it, e.g. `Free build time left: 25:00:00
|
||||
(hh:mm:ss)` — it resets at the start of each month. When spent, the banner
|
||||
reads `You have no free build time left` and further builds are billed.
|
||||
|
||||
## Billable CPU over a date range
|
||||
|
||||
```bash
|
||||
nbapi usage --from 2026-06-01 --to 2026-06-30
|
||||
```
|
||||
|
||||
## Recent build history
|
||||
|
||||
```bash
|
||||
nbapi builds --limit 20
|
||||
```
|
||||
|
||||
Each entry carries id, status, drv path, timing — useful to spot a runaway or
|
||||
repeatedly-failing build burning CPU. For one build's detail: `nbapi raw
|
||||
/builds/<id>`; for a shareable web link: `nbapi raw /builds/<id>/url`.
|
||||
|
||||
## Stored size
|
||||
|
||||
`Storage used:` appears in the shell banner (`nbshell 'usage'`), and
|
||||
`total_output_nar_size_kilobytes` in `nbapi summary` approximates output volume.
|
||||
|
||||
## Reporting
|
||||
|
||||
Lead with the two numbers that matter: **free time left** and **billable
|
||||
CPU-seconds** (this month). Add fail/discard counts only if non-trivial (a high
|
||||
`failed`/`discarded` ratio means wasted spend — flag it). Convert CPU-seconds to
|
||||
hours for readability (`/3600`). Keep it to a few lines unless asked for the
|
||||
full history.
|
||||
|
||||
## Token
|
||||
|
||||
`nbapi` reads the bearer token from `$NIXBUILD_API_TOKEN`, else `pass show
|
||||
infra/nixbuild/api-token` (override the entry with
|
||||
`$NIXBUILD_API_TOKEN_PASS_ENTRY`). The read-only API needs only the `:read`
|
||||
scopes; a broad token works but is more than required.
|
||||
Reference in New Issue
Block a user