From da8c45534c5c33912e5982f5955b1741af777c1d Mon Sep 17 00:00:00 2001 From: Harivansh Rathi Date: Fri, 3 Apr 2026 15:14:50 +0000 Subject: [PATCH] replace pi with openclaw --- README.md | 2 +- config/codex/config.toml | 3 -- config/{pi/SYSTEM.md => openclaw/SOUL.md} | 0 config/openclaw/env.example | 3 ++ config/openclaw/openclaw.json | 49 ++++++++++++++++++ home/common.nix | 2 +- home/openclaw.nix | 35 +++++++++++++ home/pi.nix | 53 -------------------- hosts/netty/configuration.nix | 3 +- hosts/netty/nginx.nix | 13 +++-- hosts/netty/openclaw-gateway.nix | 61 +++++++++++++++++++++++ hosts/netty/pi-agent.nix | 50 ------------------- 12 files changed, 160 insertions(+), 114 deletions(-) rename config/{pi/SYSTEM.md => openclaw/SOUL.md} (100%) create mode 100644 config/openclaw/env.example create mode 100644 config/openclaw/openclaw.json create mode 100644 home/openclaw.nix delete mode 100644 home/pi.nix create mode 100644 hosts/netty/openclaw-gateway.nix delete mode 100644 hosts/netty/pi-agent.nix diff --git a/README.md b/README.md index e839bc0..7d8b9a1 100644 --- a/README.md +++ b/README.md @@ -35,4 +35,4 @@ The KVM has a declarative service bundle: - Self hosts Forgejo mirroring to GitHub (git.harivan.sh) - Self hosts VaultWarden - betterNAS control-plane and node agent (api.betternas.com) -- pi-coding-agent in dtach (`pa` alias for attaching) +- OpenClaw gateway behind nginx (netty.harivan.sh) diff --git a/config/codex/config.toml b/config/codex/config.toml index 0e7391b..197b4f2 100644 --- a/config/codex/config.toml +++ b/config/codex/config.toml @@ -85,9 +85,6 @@ trust_level = "trusted" [projects."/Users/rathi/Documents/GitHub/agentikube"] trust_level = "trusted" -[projects."/Users/rathi/Documents/GitHub/companion/pi-mono"] -trust_level = "trusted" - [projects."/Users/rathi/.humanlayer/riptide/artifacts/019cc50f-02a6-75fe-9279-3cdc300448a4"] trust_level = "trusted" diff --git a/config/pi/SYSTEM.md b/config/openclaw/SOUL.md similarity index 100% rename from config/pi/SYSTEM.md rename to config/openclaw/SOUL.md diff --git a/config/openclaw/env.example b/config/openclaw/env.example new file mode 100644 index 0000000..605e80c --- /dev/null +++ b/config/openclaw/env.example @@ -0,0 +1,3 @@ +OPENCLAW_GATEWAY_TOKEN=replace-me-with-a-long-random-token +TELEGRAM_BOT_TOKEN=123456:replace-me +ANTHROPIC_API_KEY=sk-ant-replace-me diff --git a/config/openclaw/openclaw.json b/config/openclaw/openclaw.json new file mode 100644 index 0000000..0a664b0 --- /dev/null +++ b/config/openclaw/openclaw.json @@ -0,0 +1,49 @@ +{ + gateway: { + mode: "local", + bind: "loopback", + port: 2470, + trustedProxies: ["127.0.0.1", "::1"], + controlUi: { + enabled: true, + allowedOrigins: ["https://netty.harivan.sh"], + }, + auth: { + mode: "token", + token: "${OPENCLAW_GATEWAY_TOKEN}", + }, + }, + + channels: { + telegram: { + enabled: true, + botToken: "${TELEGRAM_BOT_TOKEN}", + dmPolicy: "pairing", + }, + }, + + agents: { + defaults: { + workspace: "~/.openclaw/workspace", + model: { + primary: "anthropic/claude-sonnet-4-6", + }, + sandbox: { + mode: "non-main", + }, + }, + }, + + tools: { + profile: "coding", + deny: [ + "browser", + "canvas", + "cron", + "gateway", + "nodes", + "sessions_send", + "sessions_spawn", + ], + }, +} diff --git a/home/common.nix b/home/common.nix index 1f93c52..cf8b8c5 100644 --- a/home/common.nix +++ b/home/common.nix @@ -21,7 +21,7 @@ ./mise.nix ./migration.nix ./nvim.nix - ./pi.nix + ./openclaw.nix ./prompt.nix ./skills.nix ./scripts.nix diff --git a/home/openclaw.nix b/home/openclaw.nix new file mode 100644 index 0000000..300395d --- /dev/null +++ b/home/openclaw.nix @@ -0,0 +1,35 @@ +{ + config, + lib, + pkgs, + hostConfig, + ... +}: +let + openClawStateDir = "${config.home.homeDirectory}/.openclaw"; + openClawWorkspaceDir = "${openClawStateDir}/workspace"; + npmDir = "${config.xdg.dataHome}/npm"; +in +lib.mkIf hostConfig.isLinux { + home.activation.installOpenClaw = lib.hm.dag.entryAfter [ "writeBoundary" ] '' + export PATH="${ + lib.makeBinPath [ + pkgs.nodejs_22 + pkgs.coreutils + ] + }:$PATH" + export NPM_CONFIG_USERCONFIG="${config.xdg.configHome}/npm/npmrc" + export XDG_DATA_HOME="${config.xdg.dataHome}" + export XDG_CACHE_HOME="${config.xdg.cacheHome}" + + if [ ! -d "${npmDir}/lib/node_modules/openclaw" ]; then + npm install -g openclaw@latest 2>/dev/null || true + fi + ''; + + home.activation.syncOpenClawState = lib.hm.dag.entryAfter [ "writeBoundary" ] '' + install -d -m 700 "${openClawStateDir}" "${openClawWorkspaceDir}" + install -m 600 ${../config/openclaw/openclaw.json} "${openClawStateDir}/openclaw.json" + install -m 644 ${../config/openclaw/SOUL.md} "${openClawWorkspaceDir}/SOUL.md" + ''; +} diff --git a/home/pi.nix b/home/pi.nix deleted file mode 100644 index a0d798c..0000000 --- a/home/pi.nix +++ /dev/null @@ -1,53 +0,0 @@ -{ - config, - lib, - pkgs, - hostConfig, - ... -}: -let - npmDir = "${config.xdg.dataHome}/npm"; - piBin = "${npmDir}/bin/pi"; -in -lib.mkIf hostConfig.isLinux { - home.file.".pi/agent/SYSTEM.md".source = ../config/pi/SYSTEM.md; - # Install pi-coding-agent globally via npm at activation time. - home.activation.installPiAgent = lib.hm.dag.entryAfter [ "writeBoundary" ] '' - export PATH="${ - lib.makeBinPath [ - pkgs.nodejs_22 - pkgs.coreutils - ] - }:$PATH" - export NPM_CONFIG_USERCONFIG="${config.xdg.configHome}/npm/npmrc" - export XDG_DATA_HOME="${config.xdg.dataHome}" - export XDG_CACHE_HOME="${config.xdg.cacheHome}" - - if [ ! -d "${npmDir}/lib/node_modules/@mariozechner/pi-coding-agent" ]; then - npm install -g @mariozechner/pi-coding-agent 2>/dev/null || true - fi - ''; - - # Install Pi extensions at activation time: - # - @e9n/pi-channels: Telegram/Slack bridge with RPC-based persistent sessions - # - pi-schedule-prompt: cron/interval scheduled prompts - # - pi-subagents: background task delegation with async execution - home.activation.installPiExtensions = lib.hm.dag.entryAfter [ "installPiAgent" ] '' - export PATH="${ - lib.makeBinPath [ - pkgs.nodejs_22 - pkgs.coreutils - pkgs.git - ] - }:$PATH" - export NPM_CONFIG_USERCONFIG="${config.xdg.configHome}/npm/npmrc" - export XDG_DATA_HOME="${config.xdg.dataHome}" - export XDG_CACHE_HOME="${config.xdg.cacheHome}" - - if [ -x "${piBin}" ]; then - for pkg in "@e9n/pi-channels" "pi-schedule-prompt" "pi-subagents"; do - "${piBin}" install "npm:$pkg" 2>/dev/null || true - done - fi - ''; -} diff --git a/hosts/netty/configuration.nix b/hosts/netty/configuration.nix index 5a6cd8f..d3560f9 100644 --- a/hosts/netty/configuration.nix +++ b/hosts/netty/configuration.nix @@ -18,7 +18,7 @@ in ./vaultwarden.nix ./forgejo.nix ./betternas.nix - ./pi-agent.nix + ./openclaw-gateway.nix ../../modules/base.nix (modulesPath + "/profiles/minimal.nix") (modulesPath + "/profiles/headless.nix") @@ -114,7 +114,6 @@ in environment.systemPackages = packageSets.extras ++ [ pkgs.chromium - pkgs.dtach pkgs.php ]; diff --git a/hosts/netty/nginx.nix b/hosts/netty/nginx.nix index 73da49c..274ecc7 100644 --- a/hosts/netty/nginx.nix +++ b/hosts/netty/nginx.nix @@ -2,7 +2,7 @@ ... }: let - sandboxDomain = "netty.harivan.sh"; + openClawDomain = "netty.harivan.sh"; forgejoDomain = "git.harivan.sh"; vaultDomain = "vault.harivan.sh"; betternasDomain = "api.betternas.com"; @@ -19,11 +19,16 @@ in recommendedTlsSettings = true; clientMaxBodySize = "512m"; - # Reserved for future use - nothing listening on this port yet - virtualHosts.${sandboxDomain} = { + virtualHosts.${openClawDomain} = { enableACME = true; forceSSL = true; - locations."/".proxyPass = "http://127.0.0.1:2470"; + locations."/" = { + proxyPass = "http://127.0.0.1:2470"; + proxyWebsockets = true; + extraConfig = '' + proxy_set_header X-Forwarded-For $remote_addr; + ''; + }; }; virtualHosts.${forgejoDomain} = { diff --git a/hosts/netty/openclaw-gateway.nix b/hosts/netty/openclaw-gateway.nix new file mode 100644 index 0000000..82df270 --- /dev/null +++ b/hosts/netty/openclaw-gateway.nix @@ -0,0 +1,61 @@ +{ + pkgs, + username, + ... +}: +let + homeDir = "/home/${username}"; + openClawStateDir = "${homeDir}/.openclaw"; + openClawConfigPath = "${openClawStateDir}/openclaw.json"; + openClawEnvFile = "${openClawStateDir}/.env"; + openClawBin = "${homeDir}/.local/share/npm/bin/openclaw"; + openClawCheck = pkgs.writeShellScript "openclaw-gateway-check" '' + [ -x "${openClawBin}" ] && [ -f "${openClawConfigPath}" ] && [ -s "${openClawEnvFile}" ] + ''; +in +{ + systemd.tmpfiles.rules = [ + "d ${openClawStateDir} 0700 ${username} users -" + "d ${openClawStateDir}/workspace 0700 ${username} users -" + "z ${openClawEnvFile} 0600 ${username} users -" + "z ${openClawConfigPath} 0600 ${username} users -" + ]; + + systemd.services.openclaw-gateway = { + description = "OpenClaw Gateway"; + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + path = with pkgs; [ + nodejs_22 + git + coreutils + findutils + gnugrep + gawk + docker + ]; + environment = { + HOME = homeDir; + NODE_NO_WARNINGS = "1"; + OPENCLAW_NIX_MODE = "1"; + OPENCLAW_STATE_DIR = openClawStateDir; + OPENCLAW_CONFIG_PATH = openClawConfigPath; + NPM_CONFIG_USERCONFIG = "${homeDir}/.config/npm/npmrc"; + XDG_CACHE_HOME = "${homeDir}/.cache"; + XDG_CONFIG_HOME = "${homeDir}/.config"; + XDG_DATA_HOME = "${homeDir}/.local/share"; + }; + serviceConfig = { + Type = "simple"; + User = username; + Group = "users"; + WorkingDirectory = openClawStateDir; + ExecCondition = openClawCheck; + EnvironmentFile = "-${openClawEnvFile}"; + ExecStart = "${openClawBin} gateway run"; + Restart = "on-failure"; + RestartSec = 5; + }; + }; +} diff --git a/hosts/netty/pi-agent.nix b/hosts/netty/pi-agent.nix deleted file mode 100644 index 3873cd6..0000000 --- a/hosts/netty/pi-agent.nix +++ /dev/null @@ -1,50 +0,0 @@ -{ - pkgs, - username, - ... -}: -let - piAgentEnvFile = "/var/lib/pi-agent/pi-agent.env"; - piBin = "/home/${username}/.local/share/npm/bin/pi"; - - # Start pi inside an interactive login shell so it inherits the full user - # environment (PATH, XDG dirs, etc). dtach provides the PTY that pi needs. - piAgentStart = pkgs.writeShellScript "start-pi-agent" '' - exec ${pkgs.dtach}/bin/dtach -N /run/pi-agent/pi-agent.sock \ - /run/current-system/sw/bin/zsh -lic 'exec ${piBin} --chat-bridge' - ''; -in -{ - systemd.tmpfiles.rules = [ - "d /var/lib/pi-agent 0750 ${username} users -" - "z ${piAgentEnvFile} 0600 ${username} users -" - "d /run/pi-agent 0750 ${username} users -" - ]; - - # Pi coding agent running as a Telegram bridge gateway. - # The main process hosts extensions (pi-channels, pi-schedule-prompt, - # pi-subagents) and polls Telegram. Actual prompts run in separate - # pi --mode rpc subprocesses spawned on demand. - # - # Runs as a login shell so the agent has the full user environment - # - # Config: ~/.pi/agent/settings.json (bot token, bridge settings) - # API key: /var/lib/pi-agent/pi-agent.env - systemd.services.pi-agent = { - description = "Pi Telegram Bridge"; - after = [ "network-online.target" ]; - wants = [ "network-online.target" ]; - wantedBy = [ "multi-user.target" ]; - path = [ pkgs.dtach ]; - serviceConfig = { - Type = "simple"; - User = username; - Group = "users"; - WorkingDirectory = "/home/${username}"; - EnvironmentFile = piAgentEnvFile; - ExecStart = piAgentStart; - Restart = "on-failure"; - RestartSec = 10; - }; - }; -}