forked from lukas/nixos-config
201 lines
7 KiB
Nix
201 lines
7 KiB
Nix
{ config, pkgs, ... }:
|
|
let
|
|
stateDir = "/var/lib/agent-codex";
|
|
roleDir = "/home/drone/nixos-config/agents";
|
|
runtimeXmppConfig = "${stateDir}/sendxmpp.conf";
|
|
runtimeBuilderXmppConfig = "${stateDir}/builder-sendxmpp.conf";
|
|
listenerScript = ./agent-codex/listener.py;
|
|
workerScript = ./agent-codex/worker.py;
|
|
builderScript = ./agent-codex/builder.py;
|
|
codexHome = "${stateDir}/codex-home";
|
|
agentHome = "${stateDir}/home";
|
|
xmppConfig = pkgs.writeText "agent-sendxmpp.conf" ''
|
|
username: agent
|
|
jserver: bot.${config.domain}
|
|
eval_password: ${pkgs.coreutils}/bin/cat ${config.age.secrets.agentXmpp.path}
|
|
'';
|
|
builderXmppConfig = pkgs.writeText "builder-sendxmpp.conf" ''
|
|
username: builder
|
|
jserver: bot.${config.domain}
|
|
eval_password: ${pkgs.coreutils}/bin/cat ${config.age.secrets.builderXmpp.path}
|
|
'';
|
|
prepareCodexHome = pkgs.writeShellScript "prepare-agent-codex-home" ''
|
|
set -eu
|
|
${pkgs.coreutils}/bin/install -d -m 700 ${codexHome} ${agentHome}
|
|
if [ ! -s ${codexHome}/auth.json ]; then
|
|
${pkgs.coreutils}/bin/install \
|
|
-m 600 \
|
|
/home/drone/.codex/auth.json \
|
|
${codexHome}/auth.json
|
|
fi
|
|
'';
|
|
commonEnvironment = {
|
|
AGENT_ALLOWED_SENDERS = "lukas@${config.domain}";
|
|
AGENT_CODEX_BIN = "${pkgs.codex}/bin/codex";
|
|
AGENT_CODEX_HOME = codexHome;
|
|
AGENT_DEBOUNCE_SECONDS = "3";
|
|
AGENT_DOMAIN = config.domain;
|
|
AGENT_FAILED_DIR = "${stateDir}/failed";
|
|
AGENT_HOME = agentHome;
|
|
AGENT_MAX_INPUT_CHARS = "20000";
|
|
AGENT_MAX_RESPONSE_CHARS = "12000";
|
|
AGENT_PROCESSING_DIR = "${stateDir}/processing";
|
|
AGENT_QUEUE_DIR = "${stateDir}/inbox";
|
|
AGENT_BUILDER_QUEUE_DIR = "${stateDir}/builder-inbox";
|
|
AGENT_BUILDER_PROCESSING_DIR = "${stateDir}/builder-processing";
|
|
AGENT_BUILDER_FAILED_DIR = "${stateDir}/builder-failed";
|
|
AGENT_ROLE_DIR = roleDir;
|
|
AGENT_BUILDER_WRITABLE_DIR = "/home/drone/nixos-config";
|
|
AGENT_SENDER_STATE_DIR = "${stateDir}/senders";
|
|
AGENT_SESSION_DIR = "${stateDir}/sessions";
|
|
AGENT_BUILDER_SENDER_STATE_DIR = "${stateDir}/builder-senders";
|
|
AGENT_BUILDER_SESSION_DIR = "${stateDir}/builder-sessions";
|
|
AGENT_SESSION_IDLE_SECONDS = "1800";
|
|
AGENT_SENDXMPP_BIN = "${pkgs.go-sendxmpp}/bin/go-sendxmpp";
|
|
AGENT_XMPP_CONFIG = runtimeXmppConfig;
|
|
AGENT_BUILDER_XMPP_CONFIG = runtimeBuilderXmppConfig;
|
|
XDG_CACHE_HOME = "${stateDir}/xdg-cache";
|
|
XDG_DATA_HOME = "${stateDir}/xdg-data";
|
|
};
|
|
in
|
|
{
|
|
systemd.services.agent-xmpp-listener = {
|
|
description = "Queue allowlisted XMPP messages for the Codex platform agent";
|
|
after = [ "network-online.target" ];
|
|
wants = [ "network-online.target" ];
|
|
wantedBy = [ "multi-user.target" ];
|
|
environment = commonEnvironment;
|
|
|
|
serviceConfig = {
|
|
User = "drone";
|
|
Group = "users";
|
|
StateDirectory = "agent-codex";
|
|
StateDirectoryMode = "0700";
|
|
UMask = "0077";
|
|
ExecStartPre = "${pkgs.coreutils}/bin/install -m 600 ${xmppConfig} ${runtimeXmppConfig}";
|
|
ExecStart = pkgs.writeShellScript "agent-xmpp-listener" ''
|
|
set -o pipefail
|
|
${pkgs.go-sendxmpp}/bin/go-sendxmpp \
|
|
--file ${runtimeXmppConfig} \
|
|
--listen \
|
|
| ${pkgs.python3}/bin/python3 ${listenerScript}
|
|
'';
|
|
Restart = "always";
|
|
RestartSec = "10s";
|
|
NoNewPrivileges = true;
|
|
PrivateTmp = true;
|
|
ProtectSystem = "strict";
|
|
ProtectHome = "read-only";
|
|
};
|
|
};
|
|
|
|
systemd.services.agent-codex-worker = {
|
|
description = "Process queued XMPP messages with the read-only Codex platform agent";
|
|
after = [ "network-online.target" ];
|
|
wants = [ "network-online.target" ];
|
|
environment = commonEnvironment;
|
|
path = [ pkgs.git pkgs.openssh ];
|
|
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
User = "drone";
|
|
Group = "users";
|
|
WorkingDirectory = roleDir;
|
|
StateDirectory = "agent-codex";
|
|
StateDirectoryMode = "0700";
|
|
UMask = "0077";
|
|
ExecStartPre = prepareCodexHome;
|
|
ExecStart = "${pkgs.python3}/bin/python3 ${workerScript}";
|
|
TimeoutStartSec = "20min";
|
|
NoNewPrivileges = true;
|
|
PrivateTmp = true;
|
|
ProtectSystem = "strict";
|
|
ProtectHome = "read-only";
|
|
};
|
|
};
|
|
|
|
systemd.paths.agent-codex-worker = {
|
|
description = "Watch the XMPP Codex inbox";
|
|
wantedBy = [ "multi-user.target" ];
|
|
pathConfig = {
|
|
PathExistsGlob = "${stateDir}/inbox/*.json";
|
|
Unit = "agent-codex-worker.service";
|
|
};
|
|
};
|
|
|
|
# Direct messages to builder@ queue the same way agent@ does, into
|
|
# builder-inbox instead of inbox.
|
|
systemd.services.agent-codex-builder-listener = {
|
|
description = "Queue allowlisted XMPP messages for the Codex Builder";
|
|
after = [ "network-online.target" ];
|
|
wants = [ "network-online.target" ];
|
|
wantedBy = [ "multi-user.target" ];
|
|
environment = commonEnvironment // {
|
|
AGENT_QUEUE_DIR = "${stateDir}/builder-inbox";
|
|
};
|
|
|
|
serviceConfig = {
|
|
User = "drone";
|
|
Group = "users";
|
|
StateDirectory = "agent-codex";
|
|
StateDirectoryMode = "0700";
|
|
UMask = "0077";
|
|
ExecStartPre = "${pkgs.coreutils}/bin/install -m 600 ${builderXmppConfig} ${runtimeBuilderXmppConfig}";
|
|
ExecStart = pkgs.writeShellScript "agent-codex-builder-listener" ''
|
|
set -o pipefail
|
|
${pkgs.go-sendxmpp}/bin/go-sendxmpp \
|
|
--file ${runtimeBuilderXmppConfig} \
|
|
--listen \
|
|
| ${pkgs.python3}/bin/python3 ${listenerScript}
|
|
'';
|
|
Restart = "always";
|
|
RestartSec = "10s";
|
|
NoNewPrivileges = true;
|
|
PrivateTmp = true;
|
|
ProtectSystem = "strict";
|
|
ProtectHome = "read-only";
|
|
};
|
|
};
|
|
|
|
# Builder converses, plans, and can now implement changes: workspace-write
|
|
# sandbox over the full nixos-config checkout (AGENT_BUILDER_WRITABLE_DIR),
|
|
# git/openssh on PATH to commit and push to dev. Deliberately no deploy
|
|
# capability -- see builder.py and agents/builder.md.
|
|
systemd.services.agent-codex-builder = {
|
|
description = "Process queued XMPP messages with the write-capable Codex Builder";
|
|
after = [ "network-online.target" ];
|
|
wants = [ "network-online.target" ];
|
|
environment = commonEnvironment;
|
|
path = [ pkgs.git pkgs.openssh pkgs.nix ];
|
|
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
User = "drone";
|
|
Group = "users";
|
|
WorkingDirectory = roleDir;
|
|
StateDirectory = "agent-codex";
|
|
StateDirectoryMode = "0700";
|
|
UMask = "0077";
|
|
ExecStartPre = [
|
|
prepareCodexHome
|
|
"${pkgs.coreutils}/bin/install -m 600 ${builderXmppConfig} ${runtimeBuilderXmppConfig}"
|
|
];
|
|
ExecStart = "${pkgs.python3}/bin/python3 ${builderScript}";
|
|
TimeoutStartSec = "20min";
|
|
NoNewPrivileges = true;
|
|
PrivateTmp = true;
|
|
ProtectSystem = "strict";
|
|
ProtectHome = "read-only";
|
|
ReadWritePaths = [ "/home/drone/nixos-config" ];
|
|
};
|
|
};
|
|
|
|
systemd.paths.agent-codex-builder = {
|
|
description = "Watch the Builder handoff inbox";
|
|
wantedBy = [ "multi-user.target" ];
|
|
pathConfig = {
|
|
PathExistsGlob = "${stateDir}/builder-inbox/*.json";
|
|
Unit = "agent-codex-builder.service";
|
|
};
|
|
};
|
|
}
|