diff options
Diffstat (limited to 'Omni/Dev')
| -rwxr-xr-x | Omni/Dev/Beryllium.nix | 5 | ||||
| -rw-r--r-- | Omni/Dev/Beryllium/AVA.md | 111 | ||||
| -rw-r--r-- | Omni/Dev/Beryllium/Ava.nix | 81 | ||||
| -rw-r--r-- | Omni/Dev/Beryllium/Configuration.nix | 28 | ||||
| -rw-r--r-- | Omni/Dev/Beryllium/Hardware.nix | 1 | ||||
| -rw-r--r-- | Omni/Dev/Beryllium/Live.nix | 135 | ||||
| -rwxr-xr-x | Omni/Dev/Beryllium/migrate-ava.sh | 102 | ||||
| -rwxr-xr-x | Omni/Dev/Lithium.nix | 2 | ||||
| -rw-r--r-- | Omni/Dev/Lithium/Configuration.nix | 10 | ||||
| -rw-r--r-- | Omni/Dev/Vpn.nix | 3 |
10 files changed, 449 insertions, 29 deletions
diff --git a/Omni/Dev/Beryllium.nix b/Omni/Dev/Beryllium.nix index 9a72353..4d9ed09 100755 --- a/Omni/Dev/Beryllium.nix +++ b/Omni/Dev/Beryllium.nix @@ -5,13 +5,16 @@ bild.os { ../Os/Base.nix ../Packages.nix ../Users.nix + ./Beryllium/Ava.nix ./Beryllium/Configuration.nix ./Beryllium/Hardware.nix ./Beryllium/Ollama.nix ./Docker.nix ./Vpn.nix ./Beryllium/OpenWebui.nix + ./Beryllium/Live.nix + ../Syncthing.nix ]; networking.hostName = "beryllium"; - networking.domain = "beryl.simatime.com"; + networking.domain = "beryl.bensima.com"; } diff --git a/Omni/Dev/Beryllium/AVA.md b/Omni/Dev/Beryllium/AVA.md new file mode 100644 index 0000000..620592b --- /dev/null +++ b/Omni/Dev/Beryllium/AVA.md @@ -0,0 +1,111 @@ +# Ava Deployment on Beryllium + +Ava runs as a systemd service under the `ava` user. + +## Architecture + +``` +/home/ava/ # Ava's home directory (AVA_DATA_ROOT) +├── omni/ # Clone of the omni repo +├── skills/ # Ava's skills directory +│ ├── shared/ # Skills available to all users +│ └── <username>/ # User-specific skills +├── outreach/ # Outreach approval queue +│ ├── pending/ +│ ├── approved/ +│ ├── rejected/ +│ └── sent/ +├── users/ # Per-user scratch space +│ └── <username>/ +└── .local/share/omni/ + └── memory.db # SQLite memory database +``` + +## Configuration + +The service is configured in `Ava.nix` and requires these environment variables in `/run/secrets/ava.env`: + +```bash +TELEGRAM_BOT_TOKEN=xxx +OPENROUTER_API_KEY=xxx +KAGI_API_KEY=xxx # optional +ALLOWED_TELEGRAM_USER_IDS=xxx,yyy # or * for all +``` + +## Commands + +```bash +# View logs +journalctl -u ava -f + +# Restart service +sudo systemctl restart ava + +# Check status +sudo systemctl status ava + +# Stop/Start +sudo systemctl stop ava +sudo systemctl start ava +``` + +## SSH Access + +The Ava private key is at `~/.ssh/ava_ed25519`. Use it to SSH as ava: + +```bash +ssh -i ~/.ssh/ava_ed25519 ava@beryl.bensima.com +``` + +Ben can also access ava's workspace via his own SSH key since ava is in the git group. + +## Git Setup + +Ava has its own clone of the omni repo at `/home/ava/omni`. To fetch changes from ben: + +```bash +# As ava: +cd /home/ava/omni +git fetch origin +git pull origin main +``` + +Ben can also push directly to ava's repo if needed: + +```bash +# From /home/ben/omni: +git remote add ava /home/ava/omni +git push ava main +``` + +## Redeploy + +To redeploy Ava with code changes: + +```bash +# 1. Rebuild the NixOS config +push.sh Omni/Dev/Beryllium.nix + +# 2. Or just restart the service if only env changes +sudo systemctl restart ava +``` + +## Migration from tmux + +If migrating from the old tmux-based deployment: + +1. Deploy the NixOS config with the new ava user +2. Run the migration script: `sudo ./Omni/Dev/Beryllium/migrate-ava.sh` +3. Create `/run/secrets/ava.env` with the required secrets +4. Stop the tmux ava process +5. Start the systemd service: `sudo systemctl start ava` +6. Enable on boot: `sudo systemctl enable ava` + +## Environment Variable: AVA_DATA_ROOT + +The `AVA_DATA_ROOT` environment variable controls where Ava stores its data: + +- **Development** (unset): Uses `_/var/ava/` (relative to repo) +- **Production**: Set to `/home/ava` via the systemd service + +This allows the same codebase to run in both environments without changes. diff --git a/Omni/Dev/Beryllium/Ava.nix b/Omni/Dev/Beryllium/Ava.nix new file mode 100644 index 0000000..f0765cd --- /dev/null +++ b/Omni/Dev/Beryllium/Ava.nix @@ -0,0 +1,81 @@ +{...}: let + bild = import ../../Bild.nix {}; + avaPkg = bild.run ../../Ava.hs; + + # Python environment for Ava's python_exec tool + avaPython = bild.python.pythonWith (p: [ + p.requests # HTTP requests + p.beautifulsoup4 # HTML/XML parsing + p.lxml # Fast XML/HTML parser + p.pandas # Data analysis + p.numpy # Numerical computing + p.pyyaml # YAML parsing + p.python-dateutil # Date utilities + ]); + + # Wrap ava binary with tools in PATH + avaWithTools = bild.stdenv.mkDerivation { + name = "ava-wrapped"; + buildInputs = [bild.makeWrapper]; + phases = ["installPhase"]; + installPhase = '' + mkdir -p $out/bin + makeWrapper ${avaPkg}/bin/ava $out/bin/ava \ + --prefix PATH : ${bild.lib.makeBinPath [ + avaPython + bild.pkgs.jq + bild.pkgs.ripgrep + bild.pkgs.coreutils + bild.pkgs.git + bild.pkgs.sqlite + ]} + ''; + }; +in { + systemd.services.ava = { + description = "Ava Telegram assistant"; + after = ["network-online.target" "ollama.service"]; + wants = ["network-online.target" "ollama.service"]; + wantedBy = ["multi-user.target"]; + + serviceConfig = { + Type = "simple"; + User = "ava"; + Group = "users"; + WorkingDirectory = "/home/ava/omni"; + + Environment = [ + "AVA_DATA_ROOT=/home/ava" + "HOME=/home/ava" + "OLLAMA_URL=http://localhost:11434" + ]; + + EnvironmentFile = "/run/secrets/ava.env"; + + ExecStart = "${avaWithTools}/bin/ava"; + + StandardOutput = "journal"; + StandardError = "journal"; + + Restart = "on-failure"; + RestartSec = 5; + + TimeoutStopSec = 90; + KillMode = "mixed"; + KillSignal = "SIGTERM"; + }; + }; + + systemd.tmpfiles.rules = [ + "d /home/ava 0755 ava users -" + "d /home/ava/omni 0755 ava users -" + "d /home/ava/skills 0755 ava users -" + "d /home/ava/outreach 0755 ava users -" + "d /home/ava/outreach/pending 0755 ava users -" + "d /home/ava/outreach/approved 0755 ava users -" + "d /home/ava/outreach/rejected 0755 ava users -" + "d /home/ava/outreach/sent 0755 ava users -" + "d /home/ava/users 0755 ava users -" + "d /home/ava/.local/share/omni 0755 ava users -" + ]; +} diff --git a/Omni/Dev/Beryllium/Configuration.nix b/Omni/Dev/Beryllium/Configuration.nix index 8fa783b..3e39fe4 100644 --- a/Omni/Dev/Beryllium/Configuration.nix +++ b/Omni/Dev/Beryllium/Configuration.nix @@ -14,9 +14,6 @@ in { boot.loader.systemd-boot.enable = true; boot.loader.efi.canTouchEfiVariables = true; - boot.kernelModules = ["v4l2loopback"]; - boot.extraModulePackages = [pkgs.linuxPackages.v4l2loopback]; - # Enable networking networking.networkmanager.enable = true; @@ -52,24 +49,21 @@ in { services.xserver = { layout = "us"; xkbVariant = ""; + extraConfig = '' + Section "InputClass" + Identifier "Kensington Expert Mouse" + MatchProduct "Kensington Expert Mouse" + Option "ButtonMapping" "1 8 2 4 5 6 7 3 9" + Option "NaturalScrolling" "true" + Option "ScrollMethod" "button" + Option "ScrollButton" "3" + EndSection + ''; }; # Enable CUPS to print documents. services.printing.enable = true; - # Enable sound with pipewire. - hardware.pulseaudio.enable = false; - security.rtkit.enable = true; - services.pipewire = { - enable = true; - alsa.enable = true; - alsa.support32Bit = true; - pulse.enable = true; - # If you want to use JACK applications, uncomment this - jack.enable = true; - wireplumber.enable = true; - }; - hardware.opengl.enable = true; hardware.opengl.driSupport32Bit = true; services.xserver.videoDrivers = ["nvidia"]; @@ -100,6 +94,8 @@ in { services.eternal-terminal.enable = true; + services.pcscd.enable = true; + environment.systemPackages = with pkgs; [ v4l-utils linuxPackages.v4l2loopback diff --git a/Omni/Dev/Beryllium/Hardware.nix b/Omni/Dev/Beryllium/Hardware.nix index 5a8b583..c9632f5 100644 --- a/Omni/Dev/Beryllium/Hardware.nix +++ b/Omni/Dev/Beryllium/Hardware.nix @@ -12,7 +12,6 @@ boot.initrd.availableKernelModules = ["xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "sd_mod"]; boot.initrd.kernelModules = []; boot.kernelModules = ["kvm-amd"]; - boot.extraModulePackages = []; fileSystems."/" = { device = "/dev/disk/by-uuid/f96eaa16-d0e2-4230-aece-131ce7b630da"; diff --git a/Omni/Dev/Beryllium/Live.nix b/Omni/Dev/Beryllium/Live.nix new file mode 100644 index 0000000..a44452f --- /dev/null +++ b/Omni/Dev/Beryllium/Live.nix @@ -0,0 +1,135 @@ +{pkgs, ...}: { + programs.obs-studio = { + enable = true; + enableVirtualCamera = true; + plugins = with pkgs.obs-studio-plugins; [ + obs-pipewire-audio-capture + ]; + }; + + # Enable sound with pipewire. + hardware.pulseaudio.enable = false; + security.rtkit.enable = true; + + # Latency optimization + boot.kernelParams = ["threadirqs"]; + boot.kernel.sysctl."vm.swappiness" = 10; + + environment.systemPackages = with pkgs; [ + obs-do # cli for controlling obs + pamixer # cli volume control + patchage # another connection manager + pwvucontrol # gui for quick adjustments + qpwgraph # better than helvum + supercollider-with-plugins + ]; + + # Virtual sinks for routing audio + services.pipewire = { + enable = true; + alsa.enable = true; + alsa.support32Bit = true; + pulse.enable = true; + jack.enable = true; + wireplumber.enable = true; + + extraConfig.pipewire = { + "10-loopback" = { + # loopback my mic into my headphones so i can hear myself, this creates + # an auditory space that encourages focus and thinking + + "context.properties" = { + "default.clock.rate" = 48000; + "default.clock.quantum" = 128; # lower for less latency + "default.clock.min-quantum" = 32; + "default.clock.max-quantum" = 8192; + }; + + "context.exec" = [ + { + "path" = "${pkgs.writeShellScript "setup-mic-monitor" '' + sleep 1 + ${pkgs.pipewire}/bin/pw-link \ + "alsa_input.usb-Antlion_Audio_Antlion_USB_Microphone-00.pro-input-0:capture_AUX0" \ + "input.mic-monitor:input_FL" + + ${pkgs.pipewire}/bin/pw-link \ + "alsa_input.usb-Antlion_Audio_Antlion_USB_Microphone-00.pro-input-0:capture_AUX0" \ + "input.mic-monitor:input_FR" + ''}"; + } + ]; + + "context.modules" = [ + { + name = "libpipewire-module-loopback"; + args = { + "node.name" = "mic-monitor"; + "node.description" = "Microphone Monitor"; + "capture.props" = { + "target.object" = "alsa_input.usb-Antlion_Audio_Antlion_USB_Microphone-00.pro-input-0"; + "channelmix.normalize" = true; + "audio.channels" = 1; + "audio.position" = ["FR" "FL"]; + }; + "playback.props" = { + "target.object" = "alsa_output.usb-Focusrite_Scarlett_Solo_USB-00.HiFi__Line1__sink"; + "node.passive" = true; + "channelmix.normalize" = true; + "audio.channels" = 2; + "audio.position" = ["FR" "FL"]; + }; + }; + } + ]; + }; + + "10-combined" = { + "context.modules" = [ + { + name = "libpipewire-module-loopback"; + args = { + "node.name" = "combined-audio"; + "node.description" = "Combined Mic+Desktop Audio"; + "capture.props" = { + "media.class" = "Audio/Sink"; + "audio.class" = 2; + "audio.position" = ["FL" "FR"]; + "channelmix.normalize" = true; + }; + "playback.props" = { + "media.class" = "Audio/Source"; + "audio.channels" = 2; + "audio.position" = ["FL" "FR"]; + "channelmix.normalize" = true; + }; + }; + } + ]; + + "context.exec" = [ + { + "path" = "${pkgs.writeShellScript "setup-audio-routing" '' + sleep 1 + ${pkgs.pipewire}/bin/pw-link \ + "alsa_input.usb-Antlion_Audio_Antlion_USB_Microphone-00.pro-input-0:capture_AUX0" \ + "input.combined-audio:playback_FL" + + ${pkgs.pipewire}/bin/pw-link \ + "alsa_input.usb-Antlion_Audio_Antlion_USB_Microphone-00.pro-input-0:capture_AUX0" \ + "input.combined-audio:playback_FR" + + ${pkgs.pipewire}/bin/pw-link \ + "input.combined-audio:monitor_FL" \ + "alsa_output.usb-Focusrite_Scarlett_Solo_USB-00.HiFi__Line1__sink:playback_FL" + + ${pkgs.pipewire}/bin/pw-link \ + "input.combined-audio:monitor_FR" \ + "alsa_output.usb-Focusrite_Scarlett_Solo_USB-00.HiFi__Line1__sink:playback_FR" + ''}"; + } + ]; + }; + }; + }; +} diff --git a/Omni/Dev/Beryllium/migrate-ava.sh b/Omni/Dev/Beryllium/migrate-ava.sh new file mode 100755 index 0000000..91d2740 --- /dev/null +++ b/Omni/Dev/Beryllium/migrate-ava.sh @@ -0,0 +1,102 @@ +#!/usr/bin/env bash +# Migration script: move Ava data from _/var/ava to /home/ava +# +# Run this ONCE after deploying the NixOS config with the new ava user. +# +# Usage: +# sudo ./migrate-ava.sh +# +# This script: +# 1. Copies existing data from _/var/ava to /home/ava +# 2. Copies memory.db from ben's .local to ava's .local +# 3. Clones the omni repo into /home/ava/omni +# 4. Sets proper ownership + +set -euo pipefail + +GRN='\033[0;32m' +YLW='\033[0;33m' +RED='\033[0;31m' +NC='\033[0m' + +OMNI_REPO="/home/ben/omni" +AVA_HOME="/home/ava" +OLD_DATA_ROOT="$OMNI_REPO/_/var/ava" + +echo -e "${YLW}=== Ava Migration Script ===${NC}" + +# Check we're running as root +if [[ $EUID -ne 0 ]]; then + echo -e "${RED}Error: This script must be run as root${NC}" + exit 1 +fi + +# Check ava user exists +if ! id ava &>/dev/null; then + echo -e "${RED}Error: ava user does not exist. Deploy the NixOS config first.${NC}" + exit 1 +fi + +# Create directory structure (tmpfiles should handle this, but just in case) +echo -e "${YLW}Creating directory structure...${NC}" +mkdir -p "$AVA_HOME"/{skills,outreach,users,omni,.local/share/omni} +mkdir -p "$AVA_HOME"/outreach/{pending,approved,rejected,sent} + +# Copy skills +if [[ -d "$OLD_DATA_ROOT/skills" ]]; then + echo -e "${YLW}Copying skills...${NC}" + rsync -av --progress "$OLD_DATA_ROOT/skills/" "$AVA_HOME/skills/" +else + echo -e "${YLW}No skills to migrate${NC}" +fi + +# Copy outreach +if [[ -d "$OLD_DATA_ROOT/outreach" ]]; then + echo -e "${YLW}Copying outreach data...${NC}" + rsync -av --progress "$OLD_DATA_ROOT/outreach/" "$AVA_HOME/outreach/" +else + echo -e "${YLW}No outreach data to migrate${NC}" +fi + +# Copy memory.db if it exists +BEN_MEMORY="/home/ben/.local/share/omni/memory.db" +AVA_MEMORY="$AVA_HOME/.local/share/omni/memory.db" +if [[ -f "$BEN_MEMORY" ]]; then + echo -e "${YLW}Copying memory database...${NC}" + cp -v "$BEN_MEMORY" "$AVA_MEMORY" +else + echo -e "${YLW}No memory.db found at $BEN_MEMORY${NC}" +fi + +# Clone or update the omni repo +if [[ -d "$AVA_HOME/omni/.git" ]]; then + echo -e "${YLW}Omni repo already exists, updating...${NC}" + cd "$AVA_HOME/omni" + sudo -u ava git fetch origin +else + echo -e "${YLW}Cloning omni repo...${NC}" + sudo -u ava git clone "$OMNI_REPO" "$AVA_HOME/omni" +fi + +# Set ownership +echo -e "${YLW}Setting ownership...${NC}" +chown -R ava:users "$AVA_HOME" + +# Show summary +echo "" +echo -e "${GRN}=== Migration Complete ===${NC}" +echo "" +echo "Directory structure:" +ls -la "$AVA_HOME" +echo "" +echo "Next steps:" +echo "1. Create /run/secrets/ava.env with:" +echo " TELEGRAM_BOT_TOKEN=xxx" +echo " OPENROUTER_API_KEY=xxx" +echo " KAGI_API_KEY=xxx (optional)" +echo " ALLOWED_TELEGRAM_USER_IDS=xxx (or * for all)" +echo "" +echo "2. Stop the tmux Ava process" +echo "3. Start the systemd service: sudo systemctl start ava" +echo "4. Watch logs: journalctl -u ava -f" +echo "5. Enable on boot: sudo systemctl enable ava" diff --git a/Omni/Dev/Lithium.nix b/Omni/Dev/Lithium.nix index 7befc7d..6b7b9a4 100755 --- a/Omni/Dev/Lithium.nix +++ b/Omni/Dev/Lithium.nix @@ -16,5 +16,5 @@ bild.os { ./Vpn.nix ]; networking.hostName = "lithium"; - networking.domain = "dev.simatime.com"; + networking.domain = "dev.bensima.com"; } diff --git a/Omni/Dev/Lithium/Configuration.nix b/Omni/Dev/Lithium/Configuration.nix index 92290f4..a439ec4 100644 --- a/Omni/Dev/Lithium/Configuration.nix +++ b/Omni/Dev/Lithium/Configuration.nix @@ -38,7 +38,7 @@ in { services.my-hoogle.enable = true; services.my-hoogle.port = ports.hoogle; - services.my-hoogle.home = "//hoogle.simatime.com"; + services.my-hoogle.home = "//hoogle.bensima.com"; services.my-hoogle.packages = pkgset: lib.attrsets.attrVals (import ../../Bild/Deps/Haskell.nix) pkgset; services.my-hoogle.haskellPackages = pkgs.haskell.packages.${ghcCompiler}; @@ -49,11 +49,6 @@ in { services.k3s.enable = false; services.k3s.role = "server"; - services.syncthing.enable = true; - services.syncthing.guiAddress = "127.0.0.1:${toString ports.syncthing-gui}"; - services.syncthing.openDefaultPorts = true; - services.syncthing.systemService = true; - services.tor.enable = true; services.tor.client.enable = true; services.tor.relay.role = "bridge"; @@ -66,7 +61,6 @@ in { services.bitcoind.mainnet.enable = true; services.bitcoind.mainnet.dataDir = "/mnt/campbell/bitcoind-mainnet/data"; services.bitcoind.mainnet.configFile = "/mnt/campbell/bitcoind-mainnet/bitcoin.conf"; - services.bitcoind.mainnet.prune = 10000; services.pcscd.enable = true; services.logind.lidSwitch = "ignore"; @@ -107,7 +101,7 @@ in { services.xserver.modules = [pkgs.xf86_input_wacom]; services.xserver.wacom.enable = true; - services.jupyter.enable = true; + services.jupyter.enable = false; services.jupyter.port = ports.jupyter; services.jupyter.ip = "*"; users.users.jupyter.group = "jupyter"; diff --git a/Omni/Dev/Vpn.nix b/Omni/Dev/Vpn.nix index 7172d84..996b22c 100644 --- a/Omni/Dev/Vpn.nix +++ b/Omni/Dev/Vpn.nix @@ -6,13 +6,12 @@ inappropriate sites, as well as a ton of ads. */ let ports = import ../Cloud/Ports.nix; - domain = "headscale.simatime.com"; in { services.headscale = { enable = false; # don't use headscale rn, just use tailscale.com address = "0.0.0.0"; port = ports.headscale; - settings = {dns.base_domain = "simatime.com";}; + settings = {dns.base_domain = "bensima.com";}; }; environment.systemPackages = [config.services.headscale.package]; |
