swarm containers: run the claude-code the hive pins for agents
This commit is contained in:
parent
1302288474
commit
a169947f15
6 changed files with 65 additions and 2 deletions
|
|
@ -7,6 +7,9 @@ agent's harness installs them from there.
|
|||
|
||||
Where it runs and how it's enabled: [`services.md`](services.md#claude-login-minter).
|
||||
|
||||
The service runs the `claude-code` that `services.hyperhive.c0re.claudeCodePackage`
|
||||
pins for agents, and its container's own nixpkgs' where the hive pins none.
|
||||
|
||||
## What happens on a login
|
||||
|
||||
1. The agent publishes `needs_login` in its turn-state header, and its card
|
||||
|
|
|
|||
|
|
@ -135,6 +135,9 @@ config) and an empty directory of its own. The prompt reaches it on stdin as
|
|||
one user message in `--input-format stream-json`, so that it can carry content
|
||||
blocks (see [Shared context](#shared-context)).
|
||||
|
||||
The `claude` is the one `services.hyperhive.c0re.claudeCodePackage` pins for
|
||||
agents, or its container's own nixpkgs' where the hive pins none.
|
||||
|
||||
On the ACP runtime, each classification is one prompt on a new `opencode acp`
|
||||
session. Its config and opencode's state live in a directory of its own,
|
||||
removed after it. Its working directory is one empty directory that every
|
||||
|
|
|
|||
|
|
@ -158,6 +158,12 @@
|
|||
`nix-collect-garbage` cannot reclaim an old `claude-code` until
|
||||
every agent has been rebuilt past it and the old generations
|
||||
are gone.
|
||||
|
||||
The swarm's `swarm-claude-login` and `swarm-review-classifier`
|
||||
containers, where this host runs them, follow the same pin and
|
||||
keep their own nixpkgs' `claude-code` when it is `null`. They are
|
||||
not agents, so pinning an older build for an agent-side
|
||||
regression pins them too.
|
||||
'';
|
||||
};
|
||||
dashboardPort = lib.mkOption {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,16 @@
|
|||
}:
|
||||
let
|
||||
hyperhiveCfg = config.services.hyperhive;
|
||||
|
||||
# The `claude-code` the agents run, so this container does not trail them on
|
||||
# the CLI; `fallback`, the container's own nixpkgs', only where the hive pins
|
||||
# none.
|
||||
claudeCode =
|
||||
fallback:
|
||||
if hyperhiveCfg.c0re.claudeCodePackage != null then
|
||||
hyperhiveCfg.c0re.claudeCodePackage
|
||||
else
|
||||
fallback;
|
||||
cfg = hyperhiveCfg.deploy.claude-login;
|
||||
baoCfg = hyperhiveCfg.swarm.bao;
|
||||
baoDeploy = hyperhiveCfg.deploy.bao;
|
||||
|
|
@ -175,7 +185,7 @@ in
|
|||
SWARM_CLAUDE_LOGIN_NATS_URL = "tls://${natsCfg.domain}:${toString natsCfg.port}";
|
||||
SWARM_CLAUDE_LOGIN_OIDC_TOKEN_ENDPOINT = "${autheliaCfg.url}/api/oidc/token";
|
||||
SWARM_CLAUDE_LOGIN_OIDC_CLIENT_ID = clientId;
|
||||
SWARM_CLAUDE_LOGIN_CLAUDE = "${pkgs.claude-code}/bin/claude";
|
||||
SWARM_CLAUDE_LOGIN_CLAUDE = "${claudeCode pkgs.claude-code}/bin/claude";
|
||||
}
|
||||
// lib.optionalAttrs (storeFiles ? claude-login-bao-server-ca) {
|
||||
BAO_CACERT = credential "claude-login-bao-server-ca";
|
||||
|
|
|
|||
|
|
@ -22,6 +22,16 @@
|
|||
}:
|
||||
let
|
||||
hyperhiveCfg = config.services.hyperhive;
|
||||
|
||||
# The `claude-code` the agents run, so this container does not trail them on
|
||||
# the CLI; `fallback`, the container's own nixpkgs', only where the hive pins
|
||||
# none.
|
||||
claudeCode =
|
||||
fallback:
|
||||
if hyperhiveCfg.c0re.claudeCodePackage != null then
|
||||
hyperhiveCfg.c0re.claudeCodePackage
|
||||
else
|
||||
fallback;
|
||||
cfg = hyperhiveCfg.deploy.review-classifier;
|
||||
baoCfg = hyperhiveCfg.swarm.bao;
|
||||
baoDeploy = hyperhiveCfg.deploy.bao;
|
||||
|
|
@ -195,7 +205,7 @@ in
|
|||
SWARM_REVIEW_CLASSIFIER_NATS_URL = "tls://${natsCfg.domain}:${toString natsCfg.port}";
|
||||
SWARM_REVIEW_CLASSIFIER_OIDC_TOKEN_ENDPOINT = "${autheliaCfg.url}/api/oidc/token";
|
||||
SWARM_REVIEW_CLASSIFIER_OIDC_CLIENT_ID = clientId;
|
||||
SWARM_REVIEW_CLASSIFIER_CLAUDE = "${pkgs.claude-code}/bin/claude";
|
||||
SWARM_REVIEW_CLASSIFIER_CLAUDE = "${claudeCode pkgs.claude-code}/bin/claude";
|
||||
SWARM_REVIEW_CLASSIFIER_OPENCODE = "${pkgs.opencode}/bin/opencode";
|
||||
}
|
||||
// lib.optionalAttrs (storeFiles ? review-classifier-bao-server-ca) {
|
||||
|
|
|
|||
|
|
@ -99,6 +99,13 @@ let
|
|||
deploy.builder.enable = false;
|
||||
};
|
||||
|
||||
# Same, with the claude-code build the agents run pinned on the hive. Any
|
||||
# package serves: only the path the containers are pointed at is read.
|
||||
swarmServicesPinnedClaude = hiveWithController {
|
||||
deploy.allSwarmServices = true;
|
||||
c0re.claudeCodePackage = pkgs.hello;
|
||||
};
|
||||
|
||||
# Same, with one of those services placed on another host. Every derivation
|
||||
# in that module is `mkDefault` so this stays expressible.
|
||||
swarmServicesBaoElsewhere = hive {
|
||||
|
|
@ -273,6 +280,30 @@ let
|
|||
&& !(swarmServicesBaoElsewhere.containers ? swarm-claude-login)
|
||||
&& swarmServicesBaoElsewhere.services.hyperhive.deploy.nats.enable;
|
||||
}
|
||||
{
|
||||
# The CLI is the one the agents run, not the container's own nixpkgs'.
|
||||
# Unpinned is the control: it falls back to the container's own `claude-code`.
|
||||
name = "the claude login minter and the review classifier run the claude-code the hive pins";
|
||||
ok =
|
||||
let
|
||||
claudeOf =
|
||||
host: container: unit: var:
|
||||
host.containers.${container}.config.systemd.services.${unit}.environment.${var};
|
||||
pinned = "${pkgs.hello}/bin/claude";
|
||||
in
|
||||
claudeOf swarmServicesPinnedClaude "swarm-claude-login" "swarm-claude-login"
|
||||
"SWARM_CLAUDE_LOGIN_CLAUDE" == pinned
|
||||
&&
|
||||
claudeOf swarmServicesPinnedClaude "swarm-review-classifier" "swarm-review-classifier"
|
||||
"SWARM_REVIEW_CLASSIFIER_CLAUDE" == pinned
|
||||
&& lib.hasInfix "claude-code" (
|
||||
claudeOf swarmServicesHere "swarm-claude-login" "swarm-claude-login" "SWARM_CLAUDE_LOGIN_CLAUDE"
|
||||
)
|
||||
&& lib.hasInfix "claude-code" (
|
||||
claudeOf swarmServicesHere "swarm-review-classifier" "swarm-review-classifier"
|
||||
"SWARM_REVIEW_CLASSIFIER_CLAUDE"
|
||||
);
|
||||
}
|
||||
{
|
||||
# The switch fills in for an operator who has not spoken and yields to
|
||||
# one who has — that is what keeps a shared service placeable on a host
|
||||
|
|
|
|||
Loading…
Reference in a new issue