mirror of
https://github.com/harivansh-afk/nix.git
synced 2026-04-15 07:04:47 +00:00
replace pi with openclaw (#60)
This commit is contained in:
parent
be2370f406
commit
630ec774ce
12 changed files with 160 additions and 114 deletions
|
|
@ -35,4 +35,4 @@ The KVM has a declarative service bundle:
|
||||||
- Self hosts Forgejo mirroring to GitHub (git.harivan.sh)
|
- Self hosts Forgejo mirroring to GitHub (git.harivan.sh)
|
||||||
- Self hosts VaultWarden
|
- Self hosts VaultWarden
|
||||||
- betterNAS control-plane and node agent (api.betternas.com)
|
- 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)
|
||||||
|
|
|
||||||
|
|
@ -85,9 +85,6 @@ trust_level = "trusted"
|
||||||
[projects."/Users/rathi/Documents/GitHub/agentikube"]
|
[projects."/Users/rathi/Documents/GitHub/agentikube"]
|
||||||
trust_level = "trusted"
|
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"]
|
[projects."/Users/rathi/.humanlayer/riptide/artifacts/019cc50f-02a6-75fe-9279-3cdc300448a4"]
|
||||||
trust_level = "trusted"
|
trust_level = "trusted"
|
||||||
|
|
||||||
|
|
|
||||||
3
config/openclaw/env.example
Normal file
3
config/openclaw/env.example
Normal file
|
|
@ -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
|
||||||
49
config/openclaw/openclaw.json
Normal file
49
config/openclaw/openclaw.json
Normal file
|
|
@ -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",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
./mise.nix
|
./mise.nix
|
||||||
./migration.nix
|
./migration.nix
|
||||||
./nvim.nix
|
./nvim.nix
|
||||||
./pi.nix
|
./openclaw.nix
|
||||||
./prompt.nix
|
./prompt.nix
|
||||||
./skills.nix
|
./skills.nix
|
||||||
./scripts.nix
|
./scripts.nix
|
||||||
|
|
|
||||||
35
home/openclaw.nix
Normal file
35
home/openclaw.nix
Normal file
|
|
@ -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"
|
||||||
|
'';
|
||||||
|
}
|
||||||
53
home/pi.nix
53
home/pi.nix
|
|
@ -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
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
|
|
@ -18,7 +18,7 @@ in
|
||||||
./vaultwarden.nix
|
./vaultwarden.nix
|
||||||
./forgejo.nix
|
./forgejo.nix
|
||||||
./betternas.nix
|
./betternas.nix
|
||||||
./pi-agent.nix
|
./openclaw-gateway.nix
|
||||||
../../modules/base.nix
|
../../modules/base.nix
|
||||||
(modulesPath + "/profiles/minimal.nix")
|
(modulesPath + "/profiles/minimal.nix")
|
||||||
(modulesPath + "/profiles/headless.nix")
|
(modulesPath + "/profiles/headless.nix")
|
||||||
|
|
@ -114,7 +114,6 @@ in
|
||||||
|
|
||||||
environment.systemPackages = packageSets.extras ++ [
|
environment.systemPackages = packageSets.extras ++ [
|
||||||
pkgs.chromium
|
pkgs.chromium
|
||||||
pkgs.dtach
|
|
||||||
pkgs.php
|
pkgs.php
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
sandboxDomain = "netty.harivan.sh";
|
openClawDomain = "netty.harivan.sh";
|
||||||
forgejoDomain = "git.harivan.sh";
|
forgejoDomain = "git.harivan.sh";
|
||||||
vaultDomain = "vault.harivan.sh";
|
vaultDomain = "vault.harivan.sh";
|
||||||
betternasDomain = "api.betternas.com";
|
betternasDomain = "api.betternas.com";
|
||||||
|
|
@ -19,11 +19,16 @@ in
|
||||||
recommendedTlsSettings = true;
|
recommendedTlsSettings = true;
|
||||||
clientMaxBodySize = "512m";
|
clientMaxBodySize = "512m";
|
||||||
|
|
||||||
# Reserved for future use - nothing listening on this port yet
|
virtualHosts.${openClawDomain} = {
|
||||||
virtualHosts.${sandboxDomain} = {
|
|
||||||
enableACME = true;
|
enableACME = true;
|
||||||
forceSSL = 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} = {
|
virtualHosts.${forgejoDomain} = {
|
||||||
|
|
|
||||||
61
hosts/netty/openclaw-gateway.nix
Normal file
61
hosts/netty/openclaw-gateway.nix
Normal file
|
|
@ -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;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -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;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue