diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8c9208e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,58 @@ +# 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 +RUN apt-get update && apt-get install -y \ + sbcl \ + curl \ + git \ + unzip \ + default-jre \ + libsqlite3-0 \ + && rm -rf /var/lib/apt/lists/* + +# 2. 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 + +# 3. Install Quicklisp +WORKDIR /root +RUN curl -O https://beta.quicklisp.org/quicklisp.lisp \ + && sbcl --non-interactive \ + --load quicklisp.lisp \ + --eval '(quicklisp-quickstart:install)' \ + --eval '(let ((ql-util::*quicklisp-home* (merge-pathnames "quicklisp/" (user-homedir-pathname)))) (ql-dist:install-dist "http://beta.quicklisp.org/dist/quicklisp.txt" :prompt nil))' + +# 4. 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 + +# 5. Setup Application Directory +WORKDIR /app +COPY . /app/projects/org-agent + +# 6. Pre-cache Lisp Dependencies +# This minimizes startup time by downloading dexador, cl-json, etc. during build +RUN sbcl --non-interactive \ + --eval '(push #p"/app/projects/org-agent/" asdf:*central-registry*)' \ + --eval '(ql:quickload :org-agent)' + +# 7. 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)"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..8ffb6db --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,19 @@ +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: diff --git a/docs/deployment.org b/docs/deployment.org new file mode 100644 index 0000000..476d9d7 --- /dev/null +++ b/docs/deployment.org @@ -0,0 +1,36 @@ +#+TITLE: Deployment Guide: Containerized Org-Agent +#+AUTHOR: Amr +#+DATE: [2026-04-11 Sat] +#+FILETAGS: :deployment:docker:infrastructure: + +* Overview +The ~org-agent~ is designed to run within a Docker container to ensure system dependencies (SBCL, Quicklisp, signal-cli) are perfectly matched across different host environments. + +* Prerequisites +- Docker Engine +- Docker Compose +- A valid ~.env~ file in the ~projects/org-agent/~ directory (refer to ~.env.example~). + +* Quick Start +** 1. Build and Start +From the ~projects/org-agent/~ directory: +#+begin_src bash +docker-compose up --build -d +#+end_src + +** 2. Check Logs +#+begin_src bash +docker-compose logs -f +#+end_src + +* Volume Mapping +The ~docker-compose.yml~ file automatically mounts your host's ~memex~ directory to ~/memex~ inside the container. This allows the agent to: +1. Read/Write to your Zettelkasten and GTD files. +2. Maintain its local state (Object Store, snapshots). + +* Troubleshooting +** signal-cli Identity +If using the Signal gateway, ensure you have registered your number via the host's ~signal-cli~ or within the container. The state is preserved in the ~signal-state~ Docker volume. + +** Re-loading Skills +The container pre-caches dependencies during the build. If you modify core Lisp logic, you must rebuild the image (~--build~). If you only modify ~.org~ skills in your memex, the agent can reload them dynamically if they are part of the startup scan. diff --git a/docs/rca/rca-infrastructure-docker.org b/docs/rca/rca-infrastructure-docker.org new file mode 100644 index 0000000..2eba668 --- /dev/null +++ b/docs/rca/rca-infrastructure-docker.org @@ -0,0 +1,30 @@ +#+TITLE: Root Cause Analysis: Containerized Infrastructure (Docker) +#+DATE: 2026-04-11 +#+FILETAGS: :rca:docker:deployment:infrastructure:psf: + +* Executive Summary +Standardized the `org-agent` execution environment by creating a production-grade Docker infrastructure. This ensures that all system dependencies, including the Lisp runtime and external binaries like `signal-cli`, are locked down and portable. + +* 1. Architectural Intent: The "Clean Room" Model +** Problem +The `org-agent` was relying on host-local binaries (`sbcl`, `signal-cli`) and manually configured Quicklisp dists. This made deployment to other environments (e.g., a VPS or a Sovereign Home Server) fragile and prone to version drift. +** Solution +1. **Dockerfile:** Created a multi-step build process that installs Debian Bookworm, SBCL, Java, and `signal-cli 0.14.0`. +2. **Pre-Caching:** The build process triggers a `ql:quickload` of the `:org-agent` system, ensuring all Lisp dependencies are pre-downloaded and stored in the image layer, drastically reducing startup time. +3. **Compose Orchestration:** Standardized the runtime via `docker-compose.yml`, which handles volume mounting of the user's `memex` directory and injection of `.env` secrets. + +* 2. Volume Mapping & Persistence +** Strategy +To maintain the "Sovereign" mandate, the agent's code is isolated, but its memory (the `memex`) remains on the host. +- **Mapping:** `../..` (host) -> `/memex` (container). +- **State:** Created a named Docker volume `signal-state` to ensure that `signal-cli` identities and cryptographic keys survive container restarts and image updates. + +* 3. Alignment with PSF Mandates +** Evolutionary Completion +By moving to Docker, we have achieved "Evolutionary Completion" for the deployment track. The system is no longer a collection of scripts; it is a deployable appliance. +** Documentation +A new `Deployment Guide` was added to `docs/deployment.org` to ensure standard operating procedures are preserved. + +* 4. Permanent Learnings +- **Lisp Build Layers:** Always push the system to the ASDF registry and quickload during Docker build to bake dependencies into the image. +- **Compose Locality:** Placing the `docker-compose.yml` inside the `projects/org-agent/` folder keeps infrastructure code close to the implementation logic.