From 621ee66133831158329981b498b50b4342ed4339 Mon Sep 17 00:00:00 2001 From: damocles Date: Mon, 29 Jun 2026 18:38:40 +0200 Subject: [PATCH] fix(#2022): seed claude onboarding+trust via a boot-time oneshot --- docs/tools/hivectl.md | 6 +++++ nix/templates/harness-base.nix | 47 ++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/docs/tools/hivectl.md b/docs/tools/hivectl.md index 9195899c..51f3ec47 100644 --- a/docs/tools/hivectl.md +++ b/docs/tools/hivectl.md @@ -155,6 +155,12 @@ lands in a faithful copy of the agent's environment: harness writes each turn — so the operator gets the agent's settings, the hyperhive/matrix MCP tools, and the role prompt. Each flag is included only when its file exists. +- **without the onboarding walkthrough**: a boot-time oneshot + (`hive-claude-onboarding`) seeds `hasCompletedOnboarding` and the + project trust flags into `~/.claude.json` once before the harness + starts, so the first interactive choom lands straight in a session + instead of the onboarding/trust dialog the headless harness never + completes. It's the single place hyperhive touches that file. ## Open diff --git a/nix/templates/harness-base.nix b/nix/templates/harness-base.nix index 7a2c2473..f6c7c01a 100644 --- a/nix/templates/harness-base.nix +++ b/nix/templates/harness-base.nix @@ -1200,6 +1200,53 @@ in }; }; + # Seed claude's onboarding + per-project trust state once. claude only + # marks `hasCompletedOnboarding` (global) and the project trust dialog + # as accepted when run *interactively*; the harness only ever runs it + # headless (`--print`) and `claude auth login` doesn't set them either. + # So the first interactive launch (`hivectl choom`) would drop the + # operator into the onboarding/trust walkthrough despite valid OAuth + # creds. This oneshot is the single place hyperhive touches + # `~/.claude.json`: it runs before the harness (so nothing races it), + # is idempotent (skips when the flags are already set), and is + # best-effort (`before`, not a hard dep — a failed seed leaves the file + # untouched and the harness still starts). Credentials live in the + # separate `~/.claude/.credentials.json`, so this never touches secrets. + systemd.services.hive-claude-onboarding = { + description = "Seed claude onboarding + project-trust so choom skips the walkthrough"; + wantedBy = [ "multi-user.target" ]; + before = [ "hive-ag3nt.service" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + User = userName; + Group = userName; + ExecStart = pkgs.writeShellScript "hive-claude-onboarding" '' + set -eu + umask 077 + cfg=${homeDir}/.claude.json + dir=/agents/${userName}/state + base='{}' + [ -s "$cfg" ] && base="$(cat "$cfg")" + # Idempotent: nothing to do when already onboarded + trusted. + if printf '%s' "$base" | ${pkgs.jq}/bin/jq -e \ + --arg d "$dir" \ + '.hasCompletedOnboarding == true and (.projects[$d].hasTrustDialogAccepted == true)' \ + >/dev/null 2>&1; then + exit 0 + fi + printf '%s' "$base" | ${pkgs.jq}/bin/jq \ + --arg d "$dir" \ + '.hasCompletedOnboarding = true + | .projects[$d].hasTrustDialogAccepted = true + | .projects[$d].hasCompletedProjectOnboarding = true' \ + > "$cfg.tmp" + mv "$cfg.tmp" "$cfg" + chmod 0600 "$cfg" + ''; + }; + }; + # Merged frontend static tree. Base = `${frontend.dist}/agent/`, # then each `extraFiles` entry is laid on top at its `target` # path. The runCommand derivation aborts on overwrite so a