# Omnara ## Full Omnara setup with `happy` for machine management 2026-01-13 ### System (root) setup (Local) Copy `lexe-agent` SSH keys into root account ```bash $ scp ~/.ssh/lexe-agent-2026-ed25519 root@<IP>:~/.ssh/ $ scp ~/.ssh/lexe-agent-2026-ed25519.pub root@<IP>:~/.ssh/ ``` (Local) SSH into the VM as root ```bash ssh root@<IP> ``` (Root) Set up 16 GB of swap ```bash fallocate -l 16G /mnt/swap chmod 600 /mnt/swap mkswap /mnt/swap swapon /mnt/swap echo '/mnt/swap none swap sw 0 0' >> /etc/fstab ``` (Root) Install `gh` ```bash # https://github.com/cli/cli/blob/trunk/docs/install_linux.md#debian $ (type -p wget >/dev/null || (sudo apt update && sudo apt install wget -y)) \ && sudo mkdir -p -m 755 /etc/apt/keyrings \ && out=$(mktemp) && wget -nv -O$out https://cli.github.com/packages/githubcli-archive-keyring.gpg \ && cat $out | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null \ && sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \ && sudo mkdir -p -m 755 /etc/apt/sources.list.d \ && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \ && sudo apt update \ && sudo apt install gh -y ``` (Root) Install Rust dependencies ```bash sudo apt-get update && sudo apt-get install -y build-essential sudo apt-get install -y protobuf-compiler ``` (Root) Install happy ```bash # Install nvm, npm curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash \. "$HOME/.nvm/nvm.sh" nvm install 24 node -v # Should print "v24.12.0". npm -v # Should print "11.6.2". # Install happy $ npm install -g happy-coder ``` (Root) Daemonize happy as `happy-root` - TODO(dev): Can remove this step; it seems that giving the user passwordless `sudo` access still allows Omnara to work ```bash cat > /etc/systemd/system/happy-root.service << 'EOF' [Unit] Description=Happy Claude Code Instance (root) After=network.target [Service] Type=oneshot RemainAfterExit=yes WorkingDirectory=/root Environment=TERM=xterm-256color ExecStart=/usr/bin/tmux new-session -d -s happy-root "bash -lc 'source ~/.nvm/nvm.sh && happy --yolo'" ExecStop=-/usr/bin/tmux kill-session -t happy-root [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl enable happy-root.service systemctl start happy-root.service systemctl status happy-root.service ``` (Root) Create non-root user ```bash sudo useradd -m -s /bin/bash dev # Allow passwordless sudo echo 'dev ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/dev chmod 440 /etc/sudoers.d/dev # Create .ssh directory and copy authorized_keys sudo mkdir -p /home/dev/.ssh sudo cp /root/.ssh/authorized_keys /home/dev/.ssh/ # Copy the lexe-agent SSH key sudo cp /root/.ssh/lexe-agent-2026-ed25519 /home/dev/.ssh/ sudo cp /root/.ssh/lexe-agent-2026-ed25519.pub /home/dev/.ssh/ # Set ownership sudo chown -R dev:dev /home/dev/.ssh # Set permissions sudo chmod 700 /home/dev/.ssh sudo chmod 600 /home/dev/.ssh/authorized_keys sudo chmod 600 /home/dev/.ssh/lexe-agent-2026-ed25519 # Enable lingering so systemd services can run without login: # TODO(dev): Confirm if this is actually required sudo loginctl enable-linger dev ``` ### User setup (Local) SSH into the VM as non-root user ```bash ssh dev@<IP> ``` (User) Set up SSH config ```bash # SSH setup cat > ~/.ssh/config << 'EOF' Host github.com HostName github.com User git IdentityFile ~/.ssh/lexe-agent-2026-ed25519 IdentitiesOnly yes EOF chmod 600 ~/.ssh/config ``` (User) Install Claude Code ```bash $ curl -fsSL https://claude.ai/install.sh | bash $ echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc && source ~/.bashrc # Log in to Claude $ claude ``` (User) Complete `gh` auth ``` gh auth login ``` (User) Install happy ```bash # Install nvm, npm curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash \. "$HOME/.nvm/nvm.sh" nvm install 24 node -v # Should print "v24.12.0". npm -v # Should print "11.6.2". # Install happy npm install -g happy-coder # Authenticate happy happy ``` (User) Daemonize happy as `happy-dev` user service ```bash mkdir -p ~/.config/systemd/user cat > ~/.config/systemd/user/happy-dev.service << 'EOF' [Unit] Description=Happy Claude Code Instance (dev) After=default.target [Service] Type=oneshot RemainAfterExit=yes WorkingDirectory=%h Environment=TERM=xterm-256color ExecStart=/usr/bin/tmux new-session -d -s happy-dev "bash -lc 'source ~/.nvm/nvm.sh && happy --yolo'" ExecStop=-/usr/bin/tmux kill-session -t happy-dev [Install] WantedBy=default.target EOF systemctl --user daemon-reload systemctl --user enable happy-dev.service systemctl --user start happy-dev.service systemctl --user status happy-dev.service ``` (User) Setup repo ```bash mkdir -p ~/lexe-agent git clone [email protected]:lexe-agent/lexe.git ~/lexe-agent/lexe cd ~/lexe-agent/lexe git remote add upstream [email protected]:lexe-app/lexe.git ``` (User) Install omnara, and daemonize as `com.omnara.daemon.service` user service ```bash curl -fsSL https://omnara.com/install/install.sh | bash source ~/.bashrc # Ensure systemctl service is OK systemctl --user status com.omnara.daemon ``` (User) Init Omnara session and set up auth ```bash cd ~/lexe-agent/lexe omnara ``` (Optional, User) Uninstall Omnara ```bash systemctl --user stop com.omnara.daemon systemctl --user disable com.omnara.daemon rm ~/.config/systemd/user/com.omnara.daemon.service systemctl --user daemon-reload # Optionally also delete all local data rm -rf ~/.omnara # Optionally remove from .bashrc sed -i '/^# omnara$/d; /^export OMNARA_INSTALL=/d' ~/.bashrc ```