#+TITLE: Setup & Onboarding (setup.org) #+AUTHOR: Amr #+FILETAGS: :harness:setup:onboarding: #+STARTUP: content * Overview: The Zero-to-One Experience The *Setup & Onboarding* process ensures that users can boot the ~org-agent~ Lisp Machine with zero friction. We follow the *Appliance Paradigm* for standard users (Docker-first) and provide a *Power User Path* (Baremetal) for those wanting deep native integration. This file is a Literate Devops document. Tangling it generates the Docker configuration, the one-liner installation script, and the baremetal onboarding script. * 1. The Appliance Paradigm (Docker First) The easiest way to run the agent is via Docker. This prevents the user from having to manually manage SBCL, Quicklisp, Python virtual environments, Playwright binaries, and Java (for Signal). ** The Dockerfile The container wraps all messy OS dependencies and pre-caches the Lisp environment for rapid booting. #+begin_src dockerfile :tangle ../Dockerfile # ORG-AGENT v1.0 Production Environment FROM debian:bookworm-slim # Prevent interactive prompts during build ENV DEBIAN_FRONTEND=noninteractive # 1. Install System Dependencies # - sbcl: The Lisp Runtime # - curl/git/unzip: Standard tools for Quicklisp and binaries # - default-jre: Required by signal-cli # - python3/pip: Required for Playwright bridge RUN apt-get update && apt-get install -y \ sbcl \ curl \ git \ unzip \ default-jre \ libsqlite3-0 \ python3 \ python3-pip \ python3-venv \ && rm -rf /var/lib/apt/lists/* # 2. Setup Playwright (High-Fidelity Browsing) RUN python3 -m venv /opt/venv ENV PATH="/opt/venv/bin:$PATH" RUN pip install playwright \ && playwright install --with-deps chromium # 3. Install signal-cli (v0.14.0) ENV SIGNAL_CLI_VERSION=0.14.0 RUN curl -L https://github.com/AsamK/signal-cli/releases/download/v${SIGNAL_CLI_VERSION}/signal-cli-${SIGNAL_CLI_VERSION}-Linux.tar.gz | tar xz -C /opt \ && ln -s /opt/signal-cli-${SIGNAL_CLI_VERSION}/bin/signal-cli /usr/local/bin/signal-cli # 4. Install Quicklisp & Pin Distribution # Pinned to 2026-04-01 for bit-rot resistance. WORKDIR /root RUN curl -O https://beta.quicklisp.org/quicklisp.lisp \ && sbcl --non-interactive \ --load quicklisp.lisp \ --eval '(quicklisp-quickstart:install)' \ --eval '(ql-dist:install-dist "http://beta.quicklisp.org/dist/quicklisp/2026-04-01/distinfo.txt" :prompt nil :replace t)' # 5. Configure SBCL to load Quicklisp on startup RUN echo '(let ((quicklisp-init (merge-pathnames "quicklisp/setup.lisp" (user-homedir-pathname)))) (when (probe-file quicklisp-init) (load quicklisp-init)))' > /root/.sbclrc # 6. Setup Application Directory WORKDIR /app COPY . /app/projects/org-agent # 7. Pre-cache Lisp Dependencies RUN sbcl --non-interactive \ --eval '(push #p"/app/projects/org-agent/" asdf:*central-registry*)' \ --eval '(ql:quickload :org-agent)' # 8. Environment & Volumes # The host's memex root should be mounted to /memex ENV MEMEX_DIR=/memex VOLUME ["/memex"] # Default Ports EXPOSE 9105 8080 # Entrypoint CMD ["sbcl", "--non-interactive", \ "--eval", "(push #p\"/app/projects/org-agent/\" asdf:*central-registry*)", \ "--eval", "(ql:quickload :org-agent)", \ "--eval", "(org-agent:main)"] #+end_src ** Docker Compose #+begin_src yaml :tangle ../docker-compose.yml services: org-agent: build: context: . dockerfile: Dockerfile container_name: org-agent env_file: .env volumes: # Mount the entire memex directory (2 levels up from projects/org-agent) - ../..:/memex # Ensure signal-cli state is preserved - signal-state:/root/.local/share/signal-cli ports: - "${ORG_AGENT_DAEMON_PORT:-9105}:9105" - "${ORG_AGENT_WEB_PORT:-8080}:8080" restart: unless-stopped volumes: signal-state: #+end_src * 2. The Interactive One-Liner (install.sh) This script is what the user pipes to ~bash~ from curl. It detects the OS, installs Docker if missing (after asking permission), clones the repo, interactively generates the ~.env~, and launches the container. #+begin_src bash :tangle ../scripts/install.sh :shebang "#!/bin/bash" set -e RED='\033[0;31m' GREEN='\033[0;32m' BLUE='\033[0;34m' YELLOW='\033[0;33m' NC='\033[0m' # No Color echo -e "${BLUE}==================================================${NC}" echo -e "${BLUE} org-agent: Sovereign Intelligence Onboarding ${NC}" echo -e "${BLUE}==================================================${NC}" # --- OS & Docker Detection --- echo -e "\n${BLUE}[1/4] Verifying Environment...${NC}" command_exists() { command -v "$1" >/dev/null 2>&1; } install_docker() { echo -e "${YELLOW}Docker is required to run org-agent natively without messy dependencies.${NC}" read -p "Would you like me to attempt to install Docker? [Y/n]: " install_choice install_choice=${install_choice:-Y} if [[ "$install_choice" =~ ^[Yy]$ ]]; then if [[ "$OSTYPE" == "linux-gnu"* ]]; then if command_exists apt-get; then echo "Installing Docker via apt..." sudo apt-get update sudo apt-get install -y docker.io docker-compose elif command_exists dnf; then echo "Installing Docker via dnf..." sudo dnf install -y docker docker-compose sudo systemctl start docker sudo systemctl enable docker else echo -e "${RED}Unsupported package manager. Please install Docker manually.${NC}" exit 1 fi elif [[ "$OSTYPE" == "darwin"* ]]; then if command_exists brew; then echo "Installing Docker Desktop via Homebrew..." brew install --cask docker echo -e "${YELLOW}Please start Docker Desktop from your Applications folder, then re-run this script.${NC}" exit 0 else echo -e "${RED}Homebrew not found. Please install Docker Desktop for Mac manually.${NC}" exit 1 fi else echo -e "${RED}Unsupported OS for automated Docker installation. Please install manually.${NC}" exit 1 fi else echo -e "${RED}Docker is required. Aborting.${NC}" exit 1 fi } if ! command_exists docker || ! command_exists docker-compose; then install_docker else echo -e "${GREEN}✓ Docker and docker-compose detected.${NC}" fi # --- Repository Setup --- echo -e "\n${BLUE}[2/4] Downloading Kernel...${NC}" MEMEX_DEFAULT="$HOME/memex" read -p "Where is your Memex located? (default: $MEMEX_DEFAULT): " MEMEX_TARGET MEMEX_TARGET=${MEMEX_TARGET:-$MEMEX_DEFAULT} mkdir -p "$MEMEX_TARGET/projects" cd "$MEMEX_TARGET/projects" if [ ! -d "org-agent" ]; then echo "Cloning org-agent..." git clone https://github.com/gharbeia/org-agent.git cd org-agent else echo -e "${GREEN}✓ Repository already exists.${NC}" cd org-agent git pull origin main fi # --- Interactive Configuration --- echo -e "\n${BLUE}[3/4] Neural & Identity Calibration...${NC}" if [ ! -f .env ]; then cp .env.example .env fi # Ask for Name read -p "What is your name? (default: User): " USER_NAME USER_NAME=${USER_NAME:-User} sed -i "s/MEMEX_USER=.*/MEMEX_USER=\"$USER_NAME\"/g" .env # Ask for Assistant Name read -p "What shall we name your Assistant? (default: Agent): " AGENT_NAME AGENT_NAME=${AGENT_NAME:-Agent} sed -i "s/MEMEX_ASSISTANT=.*/MEMEX_ASSISTANT=\"$AGENT_NAME\"/g" .env # Ask for LLM echo -e "\nSelect your primary neural provider:" echo "1) Google Gemini (Free Tier / Official)" echo "2) OpenRouter (Unified / Paid)" echo "3) Anthropic (Claude / API Key)" echo "4) OpenAI (GPT / API Key)" read -p "Choice [1-4]: " LLM_CHOICE case $LLM_CHOICE in 2) read -p "Enter OpenRouter API Key: " INPUT; sed -i "s/OPENROUTER_API_KEY=.*/OPENROUTER_API_KEY=\"$INPUT\"/g" .env ;; 3) read -p "Enter Anthropic API Key: " INPUT; sed -i "s/ANTHROPIC_API_KEY=.*/ANTHROPIC_API_KEY=\"$INPUT\"/g" .env ;; 4) read -p "Enter OpenAI API Key: " INPUT; sed -i "s/OPENAI_API_KEY=.*/OPENAI_API_KEY=\"$INPUT\"/g" .env ;; *) read -p "Enter Gemini API Key: " INPUT; sed -i "s/GEMINI_API_KEY=.*/GEMINI_API_KEY=\"$INPUT\"/g" .env ;; esac # Seed Core Skills echo -e "\n${BLUE}[4/4] Seeding Skills...${NC}" # In Docker, the host's memex maps to /memex. The skills should be saved in the host's memex notes folder. SKILLS_DIR="$MEMEX_TARGET/notes" mkdir -p "$SKILLS_DIR" cp -n skills/*.org "$SKILLS_DIR/" 2>/dev/null || true echo -e "${GREEN}✓ Core skills seeded to $SKILLS_DIR.${NC}" # Ensure proper ownership if sudo was used for apt if [ -n "$SUDO_USER" ]; then chown -R "$SUDO_USER" "$MEMEX_TARGET/projects/org-agent" fi echo -e "\n${GREEN}==================================================${NC}" echo -e "${GREEN} Onboarding Complete! ${NC}" echo -e "${GREEN} Booting your sovereign brain in the background...${NC}" echo -e "${GREEN}==================================================${NC}" # Launch docker-compose up -d --build echo -e "\n${YELLOW}To view logs, run: cd $MEMEX_TARGET/projects/org-agent && docker-compose logs -f${NC}" #+end_src * 3. The Power-User Path (Baremetal Onboarding) For users who want to run the Lisp Machine natively on their host OS (typically Emacs users who want the agent to directly manipulate their local =.emacs.d=), we provide the baremetal setup script. This script verifies the host has SBCL and Quicklisp installed, and configures the paths natively. #+begin_src bash :tangle ../scripts/onboard-baremetal.sh :shebang "#!/bin/bash" set -e RED='\033[0;31m'; GREEN='\033[0;32m'; BLUE='\033[0;34m'; NC='\033[0m' echo -e "${BLUE}=== org-agent: Baremetal Power-User Setup ===${NC}" if ! command -v sbcl >/dev/null 2>&1; then echo -e "${RED}✗ SBCL not found. Please install it first.${NC}" exit 1 fi if [ ! -d "$HOME/quicklisp" ] && [ ! -d "$HOME/.quicklisp" ]; then echo -e "${RED}✗ Quicklisp not found. Please install Quicklisp.${NC}" exit 1 fi if [ ! -f .env ]; then cp .env.example .env; fi read -p "What is your name? (default: User): " USER_NAME USER_NAME=${USER_NAME:-User} sed -i "s/MEMEX_USER=.*/MEMEX_USER=\"$USER_NAME\"/g" .env read -p "What shall we name your Assistant? (default: Agent): " AGENT_NAME AGENT_NAME=${AGENT_NAME:-Agent} sed -i "s/MEMEX_ASSISTANT=.*/MEMEX_ASSISTANT=\"$AGENT_NAME\"/g" .env echo "Select primary neural provider:" echo "1) Gemini"; echo "2) OpenRouter"; echo "3) Anthropic"; echo "4) OpenAI" read -p "Choice [1-4]: " LLM_CHOICE case $LLM_CHOICE in 2) read -p "Enter OpenRouter Key: " INPUT; sed -i "s/OPENROUTER_API_KEY=.*/OPENROUTER_API_KEY=\"$INPUT\"/g" .env ;; 3) read -p "Enter Anthropic Key: " INPUT; sed -i "s/ANTHROPIC_API_KEY=.*/ANTHROPIC_API_KEY=\"$INPUT\"/g" .env ;; 4) read -p "Enter OpenAI Key: " INPUT; sed -i "s/OPENAI_API_KEY=.*/OPENAI_API_KEY=\"$INPUT\"/g" .env ;; *) read -p "Enter Gemini Key: " INPUT; sed -i "s/GEMINI_API_KEY=.*/GEMINI_API_KEY=\"$INPUT\"/g" .env ;; esac # Update baremetal paths based on current directory structure PROJECT_ROOT=$(pwd) PARENT_DIR=$(dirname "$PROJECT_ROOT") sed -i "s|MEMEX_DIR=.*|MEMEX_DIR=\"$PARENT_DIR\"|g" .env sed -i "s|ZETTELKASTEN_DIR=.*|ZETTELKASTEN_DIR=\"$PARENT_DIR/notes\"|g" .env sed -i "s|SKILLS_DIR=.*|SKILLS_DIR=\"$PARENT_DIR/notes\"|g" .env mkdir -p "$PARENT_DIR/notes" cp -n skills/*.org "$PARENT_DIR/notes/" 2>/dev/null || true echo -e "${GREEN}Baremetal setup complete. Run 'make run' to start.${NC}" #+end_src