Deployment Guide
Deployment Guide
Section titled “Deployment Guide”Overview
Section titled “Overview”Construct can be deployed via Docker (recommended) or as a bare-metal systemd service. Code changes made by the agent via the edit and shell tools must be deployed manually.
Key Files
Section titled “Key Files”| File | Role |
|---|---|
deploy/Dockerfile | Multi-stage Docker build |
deploy/docker-compose.yml | Compose configuration with volume mounts and env |
.dockerignore | Excludes build artifacts, secrets, and dev files |
deploy/ | Docker build context and compose files |
src/main.ts | Application entry point |
Docker Deployment (Primary)
Section titled “Docker Deployment (Primary)”Prerequisites
Section titled “Prerequisites”- Docker and Docker Compose installed on the host
- A
~/.construct/directory for persistent data - A
~/.construct/.envfile with required environment variables
1. Configure Environment
Section titled “1. Configure Environment”Create the data directory and environment file:
mkdir -p ~/.construct/extensions/skills ~/.construct/extensions/toolsCreate ~/.construct/.env with at minimum:
OPENROUTER_API_KEY=sk-or-v1-...TELEGRAM_BOT_TOKEN=123456:ABC-DEF...See the Environment Variables section in CLAUDE.md for all available variables. Note that DATABASE_URL, LOG_FILE, and EXTENSIONS_DIR are pre-set in the Dockerfile to point to /data/ paths, so you do not need to set them in your .env file.
2. Build and Run
Section titled “2. Build and Run”From the project root:
docker compose -f deploy/docker-compose.yml up -d --buildThis will:
- Build a multi-stage image using
node:22-alpine - Install dependencies in a builder stage, then copy only
node_modulesto the runtime stage - Install
gitin the runtime stage (optional, for version control) - Mount
~/.constructon the host to/datain the container - Load environment variables from
~/.construct/.env - Start the application with
restart: unless-stopped
3. Verify
Section titled “3. Verify”docker compose -f deploy/docker-compose.yml logs -fLook for Construct is running in the output.
Volume Layout
Section titled “Volume Layout”The host directory ~/.construct/ maps to /data inside the container:
~/.construct/ (host) --> /data/ (container) .env (env_file, not mounted inside /data) construct.db construct.db (SQLite database) construct.log construct.log (log file) extensions/ extensions/ (EXTENSIONS_DIR) SOUL.md SOUL.md IDENTITY.md IDENTITY.md USER.md USER.md skills/ skills/ tools/ tools/The .env file is read by Docker Compose via env_file: — it is injected as environment variables into the container, not mounted as a file inside /data.
Dockerfile Details
Section titled “Dockerfile Details”The Dockerfile (deploy/Dockerfile) uses a two-stage build:
Builder stage — installs dependencies:
FROM node:22-alpine AS builderWORKDIR /appCOPY package.json pnpm-lock.yaml ./RUN pnpm install --frozen-lockfileRuntime stage — copies dependencies and source:
FROM node:22-alpineWORKDIR /appRUN apk add --no-cache gitCOPY --from=builder /app/node_modules ./node_modulesCOPY package.json tsconfig.json ./COPY src/ ./src/COPY cli/ ./cli/Environment defaults baked into the image:
DATABASE_URL=/data/construct.dbLOG_FILE=/data/construct.logEXTENSIONS_DIR=/data/extensions
Entry point: node --import=tsx src/main.ts
Docker Compose Configuration
Section titled “Docker Compose Configuration”The compose file (deploy/docker-compose.yml) is minimal:
services: construct: build: context: .. dockerfile: deploy/Dockerfile volumes: - ~/.construct:/data env_file: - ~/.construct/.env restart: unless-stoppedKey points:
- Build context is
..(project root), since the compose file lives indeploy/ restart: unless-stoppedensures the container restarts if the process exits
Updating the Agent
Section titled “Updating the Agent”After the agent edits its own source code via the edit and shell tools, changes must be deployed manually. There is no automatic self-deploy mechanism.
Docker Update
Section titled “Docker Update”After code changes are committed inside the container:
docker compose -f deploy/docker-compose.yml up -d --buildThe --build flag rebuilds the image with the latest source. The container restarts with the new code.
Systemd Update
Section titled “Systemd Update”On bare-metal deployments:
cd /opt/constructgit pullpnpm install --frozen-lockfilesudo systemctl restart constructWait 5 seconds and verify: sudo systemctl is-active construct
Non-Docker Deployment (systemd)
Section titled “Non-Docker Deployment (systemd)”For bare-metal deployment without Docker:
1. Install Dependencies
Section titled “1. Install Dependencies”git clone <repo> /opt/constructcd /opt/constructpnpm install --frozen-lockfile2. Create Environment File
Section titled “2. Create Environment File”cp .env.example .env# Edit .env with your API keys and configuration3. Create systemd Service
Section titled “3. Create systemd Service”[Unit]Description=Construct Telegram BotAfter=network.target
[Service]Type=simpleWorkingDirectory=/opt/constructExecStart=/usr/bin/node --env-file=.env --import=tsx src/main.tsRestart=on-failureUser=construct
[Install]WantedBy=multi-user.target4. Enable and Start
Section titled “4. Enable and Start”sudo systemctl enable constructsudo systemctl start constructThe systemd unit is named construct by default. The agent process needs passwordless sudo for systemctl restart construct and systemctl is-active construct if you want the agent to restart itself via the shell tool.